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();
81 command_client::~command_client()
83 if (constructorException)
85 delete constructorException;
86 constructorException = NULL;
90 /** @brief replace the connection currently in use with a new one
91 @param _c pointer to the new connection
93 @note the old connection must still be valid when this method is called,
94 it can safely be deleted after this method returned
96 @note all callbacks registered on the old connection will be copied over
99 void command_client::replace_connection(client_connection* _c)
101 // copy all callbacks registered on the old connection
102 for(callback_event_type e=static_cast<callback_event_type>(0);
104 e=static_cast<callback_event_type>(static_cast<int>(e)+1))
106 list<boost::function<void ()> > evcb=c->get_callback_list(e);
108 for (list<boost::function<void ()> >::iterator i=evcb.begin(); i != evcb.end(); i++)
109 _c->add_callback(e,*i);
112 // replace the connection
118 /** @brief return a complete packet
119 @param usec_timeout maximum microseconds to wait until the packet is complete
120 @retval packet data as std::string
122 @note throws a t2n_transfer_error if the timeout is exceeded
124 std::string command_client::read_packet(const long long &usec_timeout)
127 bool got_packet=false;
128 long long my_timeout=usec_timeout;
129 while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed())
130 c->fill_buffer(my_timeout,&my_timeout);
133 throw t2n_transfer_error("timeout exceeded");
138 /** @brief read and check the hello message at the beginning of a connection
140 @note throws exceptions if something went wrong
142 void command_client::read_hello()
145 bool got_packet=false;
146 long long my_timeout=hello_timeout_usec;
147 while(!(got_packet=c->get_packet(resultpacket)) && my_timeout > 0 && !c->is_closed())
149 c->fill_buffer(my_timeout,&my_timeout);
151 c->peek_packet(resultpacket);
152 check_hello(resultpacket); // will throw before timeout if wrong data received
156 throw t2n_transfer_error("timeout exceeded");
158 if (!check_hello(resultpacket))
159 throw t2n_version_mismatch("illegal hello received (incomplete): "+resultpacket);
162 /** @brief check if a hello message is valid
163 @param hellostr std::string with the message to check
164 @retval true if the hello is good and complete
166 @note you can check incomplete hellos. you will get a false return value
167 but no exception. throws exceptions as soon as something is wrong.
169 bool command_client::check_hello(const std::string& hellostr)
171 istringstream hello(hellostr);
175 if (hello.read(&chk,1))
178 throw t2n_version_mismatch("illegal hello received (T2N)");
183 if (hello.read(&chk,1))
186 throw t2n_version_mismatch("illegal hello received (T2N)");
191 if (hello.read(&chk,1))
194 throw t2n_version_mismatch("illegal hello received (T2N)");
199 if (hello.read(&chk,1))
202 throw t2n_version_mismatch("illegal hello received (T2N)");
208 if (hello >> prot_version)
210 if (prot_version != PROTOCOL_VERSION)
211 throw t2n_version_mismatch("not compatible with the server protocol version");
216 if (hello.read(&chk,1))
219 throw t2n_version_mismatch("illegal hello received (1. ;)");
225 if (hello.read((char*)&hbo,sizeof(hbo)))
228 throw t2n_version_mismatch("host byte order not matching");
233 if (hello.read(&chk,1))
236 throw t2n_version_mismatch("illegal hello received (2. ;)");
244 /** @brief send a command to the server and store the result
245 @param cmd pointer to a command-object
246 @param[out] res result container to store the result in
248 @note you can check incomplete hellos. you will get a false return value
249 but no exception. throws exceptions as soon as something is wrong.
251 void command_client::send_command(command* cmd, result_container &res)
254 command_container cc(cmd);
255 boost::archive::binary_oarchive oa(ofs);
257 if (is_connection_closed())
258 throw t2n_transfer_error("connection to server is closed");
264 catch(boost::archive::archive_exception &e)
267 msg << "archive_exception while serializing on client-side, code " << e.code << " (" << e.what() << ")";
268 throw t2n_serialization_error(msg.str());
272 if ((ostr=c->get_logstream(fulldebug))!=NULL)
274 (*ostr) << "sending command, decoded data: " << std::endl;
275 boost::archive::xml_oarchive xo(*ostr);
276 xo << BOOST_SERIALIZATION_NVP(cc);
281 istringstream ifs(read_packet(command_timeout_usec));
282 boost::archive::binary_iarchive ia(ifs);
288 catch(boost::archive::archive_exception &e)
291 msg << "archive_exception while deserializing on client-side, code " << e.code << " (" << e.what() << ")";
292 throw t2n_serialization_error(msg.str());
295 if ((ostr=c->get_logstream(fulldebug))!=NULL)
297 (*ostr) << "received result, decoded data: " << std::endl;
298 boost::archive::xml_oarchive xo(*ostr);
299 xo << BOOST_SERIALIZATION_NVP(res);