Don't catch unknown exceptions if we are only going to rethrow them.
[libt2n] / src / command_server.cpp
... / ...
CommitLineData
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*/
22
23#include <string>
24#include <sstream>
25#include <stdexcept>
26#include <iostream>
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>
33
34#include <boost/bind.hpp>
35
36#include "command_server.hxx"
37#include "container.hxx"
38#include "log.hxx"
39
40#ifdef HAVE_CONFIG_H
41#include <config.h>
42#endif
43
44using namespace std;
45
46namespace libt2n
47{
48
49command_server::command_server(server& _s)
50 : s(_s), guard_handle(0)
51{
52 // register callback
53 s.add_callback(new_connection,bind(&command_server::send_hello, boost::ref(*this), _1));
54}
55
56/**
57 * Destructor
58 */
59command_server::~command_server()
60{
61}
62
63/// send a hello message to a new connection
64void command_server::send_hello(unsigned int conn_id)
65{
66 server_connection* sc=s.get_connection(conn_id);
67
68 if (!sc)
69 return; // connection not existing, so no hello
70
71 std::ostringstream hello;
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());
81}
82
83/// handle a command including deserialization and answering
84void command_server::handle_packet(const std::string& packet, server_connection* conn)
85{
86 OBJLOGSTREAM(s,debug,"handling packet from connection " << conn->get_id());
87
88 // deserialize packet
89 std::istringstream ifs(packet);
90 boost::archive::binary_iarchive ia(ifs);
91 command_container ccont;
92 result_container res;
93
94 try
95 {
96 ia >> ccont;
97 }
98 catch(boost::archive::archive_exception &e)
99 {
100 std::ostringstream msg;
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 }
105
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 }
115
116 command* cmd=cast_command(ccont.get_command());
117
118 if (cmd)
119 {
120 try
121 {
122 res.set_result((*cmd)());
123 }
124 catch (t2n_exception &e)
125 { res.set_exception(e.clone()); }
126 }
127 else
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 }
136 }
137
138 std::ostringstream ofs;
139 boost::archive::binary_oarchive oa(ofs);
140
141 try
142 {
143 oa << res;
144 }
145 catch(boost::archive::archive_exception &e)
146 {
147 std::ostringstream msg;
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 }
153
154 std::ostream* ostr;
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
162 conn->write(ofs.str());
163}
164
165/** @brief handle incoming commands
166 @param[in,out] usec_timeout wait until new data is found, max timeout usecs.
167 -1: wait endless, 0: instant return
168 @param[out] usec_timeout_remaining microseconds from the timeout that were not used
169*/
170void command_server::handle(long long usec_timeout, long long* usec_timeout_remaining)
171{
172 guard_handle++;
173
174 try
175 {
176 if (s.fill_buffer(usec_timeout,usec_timeout_remaining))
177 {
178 std::string packet;
179 unsigned int conn_id = 0;
180
181 while (s.get_packet(packet,conn_id))
182 {
183 server_connection* conn=s.get_connection(conn_id);
184 if (!conn)
185 EXCEPTIONSTREAM(error,logic_error,"illegal connection id " << conn_id << " received");
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 }
193 }
194 }
195 }
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();
206}
207
208}