Don't catch unknown exceptions if we are only going to rethrow them.
[libt2n] / src / command_server.cpp
CommitLineData
19facd85
TJ
1/*
2Copyright (C) 2006 by Intra2net AG - Gerd v. Egidy
3
4The software in this package is distributed under the GNU General
5Public License version 2 (with a special exception described below).
6
7A copy of GNU General Public License (GPL) is included in this distribution,
8in the file COPYING.GPL.
9
10As a special exception, if other files instantiate templates or use macros
11or inline functions from this file, or you compile this file and link it
12with other works to produce a work based on this file, this file
13does not by itself cause the resulting work to be covered
14by the GNU General Public License.
15
16However the source code for this file must still be made available
17in accordance with section (3) of the GNU General Public License.
18
19This exception does not invalidate any other reasons why a work based
20on this file might be covered by the GNU General Public License.
21*/
7087e187
GE
22
23#include <string>
24#include <sstream>
25#include <stdexcept>
28cb45a5 26#include <iostream>
7087e187
GE
27
28#include <boost/archive/binary_oarchive.hpp>
29#include <boost/archive/binary_iarchive.hpp>
30#include <boost/archive/xml_oarchive.hpp>
31#include <boost/archive/xml_iarchive.hpp>
32#include <boost/serialization/serialization.hpp>
7087e187 33
28cb45a5
GE
34#include <boost/bind.hpp>
35
7087e187
GE
36#include "command_server.hxx"
37#include "container.hxx"
a7170401 38#include "log.hxx"
7087e187 39
8104c8f7
GE
40#ifdef HAVE_CONFIG_H
41#include <config.h>
42#endif
43
7087e187
GE
44using namespace std;
45
46namespace libt2n
47{
48
28cb45a5 49command_server::command_server(server& _s)
3b2543e7 50 : s(_s), guard_handle(0)
28cb45a5
GE
51{
52 // register callback
8104c8f7 53 s.add_callback(new_connection,bind(&command_server::send_hello, boost::ref(*this), _1));
28cb45a5
GE
54}
55
56f3994d
TJ
56/**
57 * Destructor
58 */
59command_server::~command_server()
60{
61}
62
487afb79 63/// send a hello message to a new connection
8104c8f7 64void command_server::send_hello(unsigned int conn_id)
28cb45a5 65{
8104c8f7 66 server_connection* sc=s.get_connection(conn_id);
1bdd13c0
GE
67
68 if (!sc)
69 return; // connection not existing, so no hello
8104c8f7 70
539b09c0 71 std::ostringstream hello;
8104c8f7
GE
72
73 hello << "T2Nv" << PROTOCOL_VERSION << ';';
74
75 int byteordercheck=1;
76 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
77
78 hello << ';';
79
80 sc->write(hello.str());
28cb45a5
GE
81}
82
7087e187
GE
83/// handle a command including deserialization and answering
84void command_server::handle_packet(const std::string& packet, server_connection* conn)
85{
a7170401
GE
86 OBJLOGSTREAM(s,debug,"handling packet from connection " << conn->get_id());
87
7087e187 88 // deserialize packet
539b09c0 89 std::istringstream ifs(packet);
7087e187
GE
90 boost::archive::binary_iarchive ia(ifs);
91 command_container ccont;
01a46463 92 result_container res;
7087e187 93
01a46463 94 try
d535333f 95 {
01a46463 96 ia >> ccont;
d535333f 97 }
01a46463
GE
98 catch(boost::archive::archive_exception &e)
99 {
539b09c0 100 std::ostringstream msg;
01a46463
GE
101 msg << "archive_exception while deserializing on server-side, "
102 "code " << e.code << " (" << e.what() << ")";
103 res.set_exception(new t2n_serialization_error(msg.str()));
104 }
d535333f 105
01a46463
GE
106 if (!res.has_exception())
107 {
108 std::ostream* ostr;
109 if ((ostr=s.get_logstream(fulldebug))!=NULL)
110 {
111 (*ostr) << "decoded packet data: " << std::endl;
112 boost::archive::xml_oarchive xo(*ostr);
113 xo << BOOST_SERIALIZATION_NVP(ccont);
114 }
7087e187 115
539b09c0 116 command* cmd=cast_command(ccont.get_command());
7087e187 117
01a46463 118 if (cmd)
7087e187 119 {
01a46463
GE
120 try
121 {
122 res.set_result((*cmd)());
123 }
124 catch (t2n_exception &e)
125 { res.set_exception(e.clone()); }
7087e187 126 }
01a46463 127 else
539b09c0
GE
128 {
129 std::ostringstream msg;
130 if (ccont.get_command()!=NULL)
131 msg << "illegal command of type " << typeid(ccont.get_command()).name() << " called";
132 else
133 msg << "NULL command called";
134 res.set_exception(new t2n_command_error(msg.str()));
135 }
7087e187 136 }
7087e187 137
539b09c0 138 std::ostringstream ofs;
7087e187
GE
139 boost::archive::binary_oarchive oa(ofs);
140
01a46463
GE
141 try
142 {
143 oa << res;
144 }
145 catch(boost::archive::archive_exception &e)
146 {
539b09c0 147 std::ostringstream msg;
01a46463
GE
148 msg << "archive_exception while serializing on server-side, "
149 "code " << e.code << " (" << e.what() << ")";
150 res.set_exception(new t2n_serialization_error(msg.str()));
151 oa << res;
152 }
7087e187 153
01a46463 154 std::ostream* ostr;
d535333f
GE
155 if ((ostr=s.get_logstream(fulldebug))!=NULL)
156 {
157 (*ostr) << "returning result, decoded data: " << std::endl;
158 boost::archive::xml_oarchive xo(*ostr);
159 xo << BOOST_SERIALIZATION_NVP(res);
160 }
161
7087e187
GE
162 conn->write(ofs.str());
163}
164
165/** @brief handle incoming commands
45a2ebc9
GE
166 @param[in,out] usec_timeout wait until new data is found, max timeout usecs.
167 -1: wait endless, 0: instant return
9a5d7790 168 @param[out] usec_timeout_remaining microseconds from the timeout that were not used
7087e187 169*/
45a2ebc9 170void command_server::handle(long long usec_timeout, long long* usec_timeout_remaining)
7087e187 171{
3b2543e7 172 guard_handle++;
56f3994d 173
3b2543e7 174 try
7087e187 175 {
3b2543e7 176 if (s.fill_buffer(usec_timeout,usec_timeout_remaining))
c7857475 177 {
3b2543e7 178 std::string packet;
56f3994d 179 unsigned int conn_id = 0;
c7857475 180
3b2543e7 181 while (s.get_packet(packet,conn_id))
c7857475 182 {
3b2543e7
GE
183 server_connection* conn=s.get_connection(conn_id);
184 if (!conn)
185 EXCEPTIONSTREAM(error,logic_error,"illegal connection id " << conn_id << " received");
3b2543e7
GE
186 try
187 { handle_packet(packet,conn); }
188 catch (t2n_transfer_error &e)
189 {
190 // shut down a connection with transfer errors (usually write errors)
191 conn->close();
192 }
c7857475 193 }
c7857475 194 }
7087e187 195 }
3b2543e7
GE
196 catch(...)
197 {
198 guard_handle--;
199 throw;
200 }
201 guard_handle--;
202
203 // don't call cleanup on re-entered handle-calls
204 if (guard_handle == 0)
205 s.cleanup();
7087e187
GE
206}
207
208}