Fix 'occurred' typo
[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 40#include <config.h>
8104c8f7 41
7087e187
GE
42using namespace std;
43
44namespace libt2n
45{
46
28cb45a5 47command_server::command_server(server& _s)
3b2543e7 48 : s(_s), guard_handle(0)
28cb45a5
GE
49{
50 // register callback
8104c8f7 51 s.add_callback(new_connection,bind(&command_server::send_hello, boost::ref(*this), _1));
28cb45a5
GE
52}
53
56f3994d
TJ
54/**
55 * Destructor
56 */
57command_server::~command_server()
58{
59}
60
487afb79 61/// send a hello message to a new connection
8104c8f7 62void command_server::send_hello(unsigned int conn_id)
28cb45a5 63{
8104c8f7 64 server_connection* sc=s.get_connection(conn_id);
1bdd13c0
GE
65
66 if (!sc)
67 return; // connection not existing, so no hello
8104c8f7 68
539b09c0 69 std::ostringstream hello;
8104c8f7
GE
70
71 hello << "T2Nv" << PROTOCOL_VERSION << ';';
72
73 int byteordercheck=1;
74 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
75
76 hello << ';';
77
78 sc->write(hello.str());
28cb45a5
GE
79}
80
7087e187
GE
81/// handle a command including deserialization and answering
82void command_server::handle_packet(const std::string& packet, server_connection* conn)
83{
a7170401
GE
84 OBJLOGSTREAM(s,debug,"handling packet from connection " << conn->get_id());
85
7087e187 86 // deserialize packet
539b09c0 87 std::istringstream ifs(packet);
7087e187
GE
88 boost::archive::binary_iarchive ia(ifs);
89 command_container ccont;
01a46463 90 result_container res;
7087e187 91
01a46463 92 try
d535333f 93 {
01a46463 94 ia >> ccont;
d535333f 95 }
01a46463
GE
96 catch(boost::archive::archive_exception &e)
97 {
539b09c0 98 std::ostringstream msg;
01a46463
GE
99 msg << "archive_exception while deserializing on server-side, "
100 "code " << e.code << " (" << e.what() << ")";
101 res.set_exception(new t2n_serialization_error(msg.str()));
102 }
d535333f 103
01a46463
GE
104 if (!res.has_exception())
105 {
106 std::ostream* ostr;
107 if ((ostr=s.get_logstream(fulldebug))!=NULL)
108 {
109 (*ostr) << "decoded packet data: " << std::endl;
110 boost::archive::xml_oarchive xo(*ostr);
111 xo << BOOST_SERIALIZATION_NVP(ccont);
112 }
7087e187 113
539b09c0 114 command* cmd=cast_command(ccont.get_command());
7087e187 115
01a46463 116 if (cmd)
7087e187 117 {
01a46463
GE
118 try
119 {
120 res.set_result((*cmd)());
121 }
122 catch (t2n_exception &e)
123 { res.set_exception(e.clone()); }
7087e187 124 }
01a46463 125 else
539b09c0
GE
126 {
127 std::ostringstream msg;
128 if (ccont.get_command()!=NULL)
129 msg << "illegal command of type " << typeid(ccont.get_command()).name() << " called";
130 else
131 msg << "NULL command called";
132 res.set_exception(new t2n_command_error(msg.str()));
133 }
7087e187 134 }
7087e187 135
539b09c0 136 std::ostringstream ofs;
7087e187
GE
137 boost::archive::binary_oarchive oa(ofs);
138
01a46463
GE
139 try
140 {
141 oa << res;
142 }
143 catch(boost::archive::archive_exception &e)
144 {
539b09c0 145 std::ostringstream msg;
01a46463
GE
146 msg << "archive_exception while serializing on server-side, "
147 "code " << e.code << " (" << e.what() << ")";
148 res.set_exception(new t2n_serialization_error(msg.str()));
149 oa << res;
150 }
7087e187 151
01a46463 152 std::ostream* ostr;
d535333f
GE
153 if ((ostr=s.get_logstream(fulldebug))!=NULL)
154 {
155 (*ostr) << "returning result, decoded data: " << std::endl;
156 boost::archive::xml_oarchive xo(*ostr);
157 xo << BOOST_SERIALIZATION_NVP(res);
158 }
159
7087e187
GE
160 conn->write(ofs.str());
161}
162
163/** @brief handle incoming commands
45a2ebc9
GE
164 @param[in,out] usec_timeout wait until new data is found, max timeout usecs.
165 -1: wait endless, 0: instant return
9a5d7790 166 @param[out] usec_timeout_remaining microseconds from the timeout that were not used
7087e187 167*/
45a2ebc9 168void command_server::handle(long long usec_timeout, long long* usec_timeout_remaining)
7087e187 169{
3b2543e7 170 guard_handle++;
56f3994d 171
3b2543e7 172 try
7087e187 173 {
3b2543e7 174 if (s.fill_buffer(usec_timeout,usec_timeout_remaining))
c7857475 175 {
3b2543e7 176 std::string packet;
56f3994d 177 unsigned int conn_id = 0;
c7857475 178
3b2543e7 179 while (s.get_packet(packet,conn_id))
c7857475 180 {
3b2543e7
GE
181 server_connection* conn=s.get_connection(conn_id);
182 if (!conn)
183 EXCEPTIONSTREAM(error,logic_error,"illegal connection id " << conn_id << " received");
3b2543e7
GE
184 try
185 { handle_packet(packet,conn); }
186 catch (t2n_transfer_error &e)
187 {
188 // shut down a connection with transfer errors (usually write errors)
189 conn->close();
190 }
c7857475 191 }
c7857475 192 }
7087e187 193 }
3b2543e7
GE
194 catch(...)
195 {
196 guard_handle--;
197 throw;
198 }
199 guard_handle--;
200
201 // don't call cleanup on re-entered handle-calls
202 if (guard_handle == 0)
203 s.cleanup();
7087e187
GE
204}
205
206}