Adding DOCUMENTATION flag to the CMakeLists.txt
[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#include <config.h>
41
42using namespace std;
43
44namespace libt2n
45{
46
47command_server::command_server(server& _s)
48 : s(_s), guard_handle(0)
49{
50 // register callback
51 s.add_callback(new_connection,bind(&command_server::send_hello, boost::ref(*this), _1));
52}
53
54/**
55 * Destructor
56 */
57command_server::~command_server()
58{
59}
60
61/// send a hello message to a new connection
62void command_server::send_hello(unsigned int conn_id)
63{
64 server_connection* sc=s.get_connection(conn_id);
65
66 if (!sc)
67 return; // connection not existing, so no hello
68
69 std::ostringstream hello;
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());
79}
80
81/// handle a command including deserialization and answering
82void command_server::handle_packet(const std::string& packet, server_connection* conn)
83{
84 OBJLOGSTREAM(s,debug,"handling packet from connection " << conn->get_id());
85
86 // deserialize packet
87 std::istringstream ifs(packet);
88 boost::archive::binary_iarchive ia(ifs);
89 command_container ccont;
90 result_container res;
91
92 try
93 {
94 ia >> ccont;
95 }
96 catch(boost::archive::archive_exception &e)
97 {
98 std::ostringstream msg;
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 }
103
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 }
113
114 command* cmd=cast_command(ccont.get_command());
115
116 if (cmd)
117 {
118 try
119 {
120 res.set_result((*cmd)());
121 }
122 catch (t2n_exception &e)
123 { res.set_exception(e.clone()); }
124 }
125 else
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 }
134 }
135
136 std::ostringstream ofs;
137 boost::archive::binary_oarchive oa(ofs);
138
139 try
140 {
141 oa << res;
142 }
143 catch(boost::archive::archive_exception &e)
144 {
145 std::ostringstream msg;
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 }
151
152 std::ostream* ostr;
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
160 conn->write(ofs.str());
161}
162
163/** @brief handle incoming commands
164 @param[in,out] usec_timeout wait until new data is found, max timeout usecs.
165 -1: wait endless, 0: instant return
166 @param[out] usec_timeout_remaining microseconds from the timeout that were not used
167*/
168void command_server::handle(long long usec_timeout, long long* usec_timeout_remaining)
169{
170 guard_handle++;
171
172 try
173 {
174 if (s.fill_buffer(usec_timeout,usec_timeout_remaining))
175 {
176 std::string packet;
177 unsigned int conn_id = 0;
178
179 while (s.get_packet(packet,conn_id))
180 {
181 server_connection* conn=s.get_connection(conn_id);
182 if (!conn)
183 EXCEPTIONSTREAM(error,logic_error,"illegal connection id " << conn_id << " received");
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 }
191 }
192 }
193 }
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();
204}
205
206}