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"
45 * @param _c connection for this command. Ownership of the pointer is outside.
46 * @param _command_timeout_usec timeout until the command has to be completed
47 * @param _hello_timeout_usec timeout until hello has to be received
49 command_client::command_client(client_connection* _c, long long _command_timeout_usec, long long _hello_timeout_usec)
51 , constructorException(NULL)
53 command_timeout_usec=_command_timeout_usec;
54 hello_timeout_usec=_hello_timeout_usec;
57 c->add_callback(new_connection,bind(&command_client::read_hello, boost::ref(*this)));
59 // don't expect hello from an always closed connection (like dummy_client_connection)
60 if (!is_connection_closed())
66 catch (t2n_communication_error &e)
70 // store a copy of the exception that you can find out details about the error later
71 constructorException = e.clone();
79 command_client::~command_client()
81 if (constructorException)
83 delete constructorException;
84 constructorException = NULL;
88 /** @brief replace the connection currently in use with a new one
89 @param _c pointer to the new connection
91 @note the old connection must still be valid when this method is called,
92 it can safely be deleted after this method returned
94 @note all callbacks registered on the old connection will be copied over
97 void command_client::replace_connection(client_connection* _c)
99 // copy all callbacks registered on the old connection
100 for(callback_event_type e=static_cast<callback_event_type>(0);
102 e=static_cast<callback_event_type>(static_cast<int>(e)+1))
104 list<boost::function<void ()> > evcb=c->get_callback_list(e);
106 for (list<boost::function<void ()> >::iterator i=evcb.begin(); i != evcb.end(); i++)
107 _c->add_callback(e,*i);
110 // replace the connection
116 /** @brief return a complete packet
117 @param usec_timeout maximum microseconds to wait until the packet is complete
118 @retval packet data as std::string
120 @note throws a t2n_transfer_error if the timeout is exceeded
122 std::string command_client::read_packet(const long long &usec_timeout)
125 bool got_packet=false;
126 long long my_timeout=usec_timeout;
127 while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed())
128 c->fill_buffer(my_timeout,&my_timeout);
131 throw t2n_transfer_error("timeout exceeded");
136 /** @brief read and check the hello message at the beginning of a connection
138 @note throws exceptions if something went wrong
140 void command_client::read_hello()
143 bool got_packet=false;
144 long long my_timeout=hello_timeout_usec;
145 while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed())
147 c->fill_buffer(my_timeout,&my_timeout);
149 c->peek_packet(resultpacket);
150 check_hello(resultpacket); // will throw before timeout if wrong data received
154 throw t2n_transfer_error("timeout exceeded");
156 if (!check_hello(resultpacket))
157 throw t2n_version_mismatch("illegal hello received (incomplete): "+resultpacket);
160 /** @brief check if a hello message is valid
161 @param hellostr std::string with the message to check
162 @retval true if the hello is good and complete
164 @note you can check incomplete hellos. you will get a false return value
165 but no exception. throws exceptions as soon as something is wrong.
167 bool command_client::check_hello(const std::string& hellostr)
169 istringstream hello(hellostr);
173 if (hello.read(&chk,1))
176 throw t2n_version_mismatch("illegal hello received (T2N)");
181 if (hello.read(&chk,1))
184 throw t2n_version_mismatch("illegal hello received (T2N)");
189 if (hello.read(&chk,1))
192 throw t2n_version_mismatch("illegal hello received (T2N)");
197 if (hello.read(&chk,1))
200 throw t2n_version_mismatch("illegal hello received (T2N)");
206 if (hello >> prot_version)
208 if (prot_version != PROTOCOL_VERSION)
209 throw t2n_version_mismatch("not compatible with the server protocol version");
214 if (hello.read(&chk,1))
217 throw t2n_version_mismatch("illegal hello received (1. ;)");
223 if (hello.read((char*)&hbo,sizeof(hbo)))
226 throw t2n_version_mismatch("host byte order not matching");
231 if (hello.read(&chk,1))
234 throw t2n_version_mismatch("illegal hello received (2. ;)");
242 /** @brief send a command to the server and store the result
243 @param cmd pointer to a command-object
244 @param[out] res result container to store the result in
246 @note you can check incomplete hellos. you will get a false return value
247 but no exception. throws exceptions as soon as something is wrong.
249 void command_client::send_command(command* cmd, result_container &res)
252 command_container cc(cmd);
253 boost::archive::binary_oarchive oa(ofs);
255 if (is_connection_closed())
256 throw t2n_transfer_error("connection to server is closed");
262 catch(boost::archive::archive_exception &e)
265 msg << "archive_exception while serializing on client-side, code " << e.code << " (" << e.what() << ")";
266 throw t2n_serialization_error(msg.str());
270 if ((ostr=c->get_logstream(fulldebug))!=NULL)
272 (*ostr) << "sending command, decoded data: " << std::endl;
273 boost::archive::xml_oarchive xo(*ostr);
274 xo << BOOST_SERIALIZATION_NVP(cc);
279 istringstream ifs(read_packet(command_timeout_usec));
280 boost::archive::binary_iarchive ia(ifs);
286 catch(boost::archive::archive_exception &e)
289 msg << "archive_exception while deserializing on client-side, code " << e.code << " (" << e.what() << ")";
290 throw t2n_serialization_error(msg.str());
293 if ((ostr=c->get_logstream(fulldebug))!=NULL)
295 (*ostr) << "received result, decoded data: " << std::endl;
296 boost::archive::xml_oarchive xo(*ostr);
297 xo << BOOST_SERIALIZATION_NVP(res);