Change license from LGPL to GPL version 2 + linking exception. This fixes C++ templat...
[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 }
105 catch(...)
106 { throw; }
d535333f 107
01a46463
GE
108 if (!res.has_exception())
109 {
110 std::ostream* ostr;
111 if ((ostr=s.get_logstream(fulldebug))!=NULL)
112 {
113 (*ostr) << "decoded packet data: " << std::endl;
114 boost::archive::xml_oarchive xo(*ostr);
115 xo << BOOST_SERIALIZATION_NVP(ccont);
116 }
7087e187 117
539b09c0 118 command* cmd=cast_command(ccont.get_command());
7087e187 119
01a46463 120 if (cmd)
7087e187 121 {
01a46463
GE
122 try
123 {
124 res.set_result((*cmd)());
125 }
126 catch (t2n_exception &e)
127 { res.set_exception(e.clone()); }
128 catch (...)
129 { throw; }
7087e187 130 }
01a46463 131 else
539b09c0
GE
132 {
133 std::ostringstream msg;
134 if (ccont.get_command()!=NULL)
135 msg << "illegal command of type " << typeid(ccont.get_command()).name() << " called";
136 else
137 msg << "NULL command called";
138 res.set_exception(new t2n_command_error(msg.str()));
139 }
7087e187 140 }
7087e187 141
539b09c0 142 std::ostringstream ofs;
7087e187
GE
143 boost::archive::binary_oarchive oa(ofs);
144
01a46463
GE
145 try
146 {
147 oa << res;
148 }
149 catch(boost::archive::archive_exception &e)
150 {
539b09c0 151 std::ostringstream msg;
01a46463
GE
152 msg << "archive_exception while serializing on server-side, "
153 "code " << e.code << " (" << e.what() << ")";
154 res.set_exception(new t2n_serialization_error(msg.str()));
155 oa << res;
156 }
157 catch(...)
158 { throw; }
7087e187 159
01a46463 160 std::ostream* ostr;
d535333f
GE
161 if ((ostr=s.get_logstream(fulldebug))!=NULL)
162 {
163 (*ostr) << "returning result, decoded data: " << std::endl;
164 boost::archive::xml_oarchive xo(*ostr);
165 xo << BOOST_SERIALIZATION_NVP(res);
166 }
167
7087e187
GE
168 conn->write(ofs.str());
169}
170
171/** @brief handle incoming commands
45a2ebc9
GE
172 @param[in,out] usec_timeout wait until new data is found, max timeout usecs.
173 -1: wait endless, 0: instant return
9a5d7790 174 @param[out] usec_timeout_remaining microseconds from the timeout that were not used
7087e187 175*/
45a2ebc9 176void command_server::handle(long long usec_timeout, long long* usec_timeout_remaining)
7087e187 177{
3b2543e7 178 guard_handle++;
56f3994d 179
3b2543e7 180 try
7087e187 181 {
3b2543e7 182 if (s.fill_buffer(usec_timeout,usec_timeout_remaining))
c7857475 183 {
3b2543e7 184 std::string packet;
56f3994d 185 unsigned int conn_id = 0;
c7857475 186
3b2543e7 187 while (s.get_packet(packet,conn_id))
c7857475 188 {
3b2543e7
GE
189 server_connection* conn=s.get_connection(conn_id);
190 if (!conn)
191 EXCEPTIONSTREAM(error,logic_error,"illegal connection id " << conn_id << " received");
3b2543e7
GE
192 try
193 { handle_packet(packet,conn); }
194 catch (t2n_transfer_error &e)
195 {
196 // shut down a connection with transfer errors (usually write errors)
197 conn->close();
198 }
199 catch(...)
200 { throw; }
c7857475 201 }
c7857475 202 }
7087e187 203 }
3b2543e7
GE
204 catch(...)
205 {
206 guard_handle--;
207 throw;
208 }
209 guard_handle--;
210
211 // don't call cleanup on re-entered handle-calls
212 if (guard_handle == 0)
213 s.cleanup();
7087e187
GE
214}
215
216}