2 Copyright (C) 2006 by Intra2net AG - Gerd v. Egidy
4 The software in this package is distributed under the GNU General
5 Public License version 2 (with a special exception described below).
7 A copy of GNU General Public License (GPL) is included in this distribution,
8 in the file COPYING.GPL.
10 As a special exception, if other files instantiate templates or use macros
11 or inline functions from this file, or you compile this file and link it
12 with other works to produce a work based on this file, this file
13 does not by itself cause the resulting work to be covered
14 by the GNU General Public License.
16 However the source code for this file must still be made available
17 in accordance with section (3) of the GNU General Public License.
19 This exception does not invalidate any other reasons why a work based
20 on this file might be covered by the GNU General Public License.
26 #include <boost/archive/binary_oarchive.hpp>
27 #include <boost/archive/binary_iarchive.hpp>
28 #include <boost/archive/xml_oarchive.hpp>
29 #include <boost/archive/xml_iarchive.hpp>
30 #include <boost/serialization/serialization.hpp>
32 #include <boost/bind.hpp>
34 #include "command_client.hxx"
47 * @param _c connection for this command. Ownership of the pointer is outside.
48 * @param _command_timeout_usec timeout until the command has to be completed
49 * @param _hello_timeout_usec timeout until hello has to be received
51 command_client::command_client(client_connection* _c, long long _command_timeout_usec, long long _hello_timeout_usec)
53 , constructorException(NULL)
55 command_timeout_usec=_command_timeout_usec;
56 hello_timeout_usec=_hello_timeout_usec;
59 c->add_callback(new_connection,bind(&command_client::read_hello, boost::ref(*this)));
61 // don't expect hello from an always closed connection (like dummy_client_connection)
62 if (!is_connection_closed())
68 catch (t2n_communication_error &e)
72 // store a copy of the exception that you can find out details about the error later
73 constructorException = e.clone();
85 command_client::~command_client()
87 if (constructorException)
89 delete constructorException;
90 constructorException = NULL;
94 /** @brief replace the connection currently in use with a new one
95 @param _c pointer to the new connection
97 @note the old connection must still be valid when this method is called,
98 it can safely be deleted after this method returned
100 @note all callbacks registered on the old connection will be copied over
103 void command_client::replace_connection(client_connection* _c)
105 // copy all callbacks registered on the old connection
106 for(callback_event_type e=static_cast<callback_event_type>(0);
108 e=static_cast<callback_event_type>(static_cast<int>(e)+1))
110 list<boost::function<void ()> > evcb=c->get_callback_list(e);
112 for (list<boost::function<void ()> >::iterator i=evcb.begin(); i != evcb.end(); i++)
113 _c->add_callback(e,*i);
116 // replace the connection
122 /** @brief return a complete packet
123 @param usec_timeout maximum microseconds to wait until the packet is complete
124 @retval packet data as std::string
126 @note throws a t2n_transfer_error if the timeout is exceeded
128 std::string command_client::read_packet(const long long &usec_timeout)
131 bool got_packet=false;
132 long long my_timeout=usec_timeout;
133 while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed())
134 c->fill_buffer(my_timeout,&my_timeout);
137 throw t2n_transfer_error("timeout exceeded");
142 /** @brief read and check the hello message at the beginning of a connection
144 @note throws exceptions if something went wrong
146 void command_client::read_hello()
149 bool got_packet=false;
150 long long my_timeout=hello_timeout_usec;
151 while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed())
153 c->fill_buffer(my_timeout,&my_timeout);
155 c->peek_packet(resultpacket);
156 check_hello(resultpacket); // will throw before timeout if wrong data received
160 throw t2n_transfer_error("timeout exceeded");
162 if (!check_hello(resultpacket))
163 throw t2n_version_mismatch("illegal hello received (incomplete): "+resultpacket);
166 /** @brief check if a hello message is valid
167 @param hellostr std::string with the message to check
168 @retval true if the hello is good and complete
170 @note you can check incomplete hellos. you will get a false return value
171 but no exception. throws exceptions as soon as something is wrong.
173 bool command_client::check_hello(const std::string& hellostr)
175 istringstream hello(hellostr);
179 if (hello.read(&chk,1))
182 throw t2n_version_mismatch("illegal hello received (T2N)");
187 if (hello.read(&chk,1))
190 throw t2n_version_mismatch("illegal hello received (T2N)");
195 if (hello.read(&chk,1))
198 throw t2n_version_mismatch("illegal hello received (T2N)");
203 if (hello.read(&chk,1))
206 throw t2n_version_mismatch("illegal hello received (T2N)");
212 if (hello >> prot_version)
214 if (prot_version != PROTOCOL_VERSION)
215 throw t2n_version_mismatch("not compatible with the server protocol version");
220 if (hello.read(&chk,1))
223 throw t2n_version_mismatch("illegal hello received (1. ;)");
229 if (hello.read((char*)&hbo,sizeof(hbo)))
232 throw t2n_version_mismatch("host byte order not matching");
237 if (hello.read(&chk,1))
240 throw t2n_version_mismatch("illegal hello received (2. ;)");
248 /** @brief send a command to the server and store the result
249 @param cmd pointer to a command-object
250 @param[out] res result container to store the result in
252 @note you can check incomplete hellos. you will get a false return value
253 but no exception. throws exceptions as soon as something is wrong.
255 void command_client::send_command(command* cmd, result_container &res)
258 command_container cc(cmd);
259 boost::archive::binary_oarchive oa(ofs);
261 if (is_connection_closed())
262 throw t2n_transfer_error("connection to server is closed");
268 catch(boost::archive::archive_exception &e)
271 msg << "archive_exception while serializing on client-side, code " << e.code << " (" << e.what() << ")";
272 throw t2n_serialization_error(msg.str());
278 if ((ostr=c->get_logstream(fulldebug))!=NULL)
280 (*ostr) << "sending command, decoded data: " << std::endl;
281 boost::archive::xml_oarchive xo(*ostr);
282 xo << BOOST_SERIALIZATION_NVP(cc);
287 istringstream ifs(read_packet(command_timeout_usec));
288 boost::archive::binary_iarchive ia(ifs);
294 catch(boost::archive::archive_exception &e)
297 msg << "archive_exception while deserializing on client-side, code " << e.code << " (" << e.what() << ")";
298 throw t2n_serialization_error(msg.str());
303 if ((ostr=c->get_logstream(fulldebug))!=NULL)
305 (*ostr) << "received result, decoded data: " << std::endl;
306 boost::archive::xml_oarchive xo(*ostr);
307 xo << BOOST_SERIALIZATION_NVP(res);