commit changes to build
[libt2n] / src / command_client.cpp
1 /***************************************************************************
2  *   Copyright (C) 2006 by Gerd v. Egidy                                   *
3  *   gve@intra2net.com                                                     *
4  *                                                                         *
5  *   This library is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Lesser General Public License version   *
7  *   2.1 as published by the Free Software Foundation.                     *
8  *                                                                         *
9  *   This library is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU Lesser General Public License for more details.                   *
13  *                                                                         *
14  *   You should have received a copy of the GNU Lesser General Public      *
15  *   License along with this program; if not, write to the                 *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19
20 #include <string>
21 #include <sstream>
22
23 #include <boost/archive/binary_oarchive.hpp>
24 #include <boost/archive/binary_iarchive.hpp>
25 #include <boost/archive/xml_oarchive.hpp>
26 #include <boost/archive/xml_iarchive.hpp>
27 #include <boost/serialization/serialization.hpp>
28
29 #include <boost/bind.hpp>
30
31 #include "command_client.hxx"
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 using namespace std;
38
39 namespace libt2n
40 {
41
42 command_client::command_client(client_connection& _c, long long _command_timeout_usec, long long _hello_timeout_usec)
43     : c(_c)
44 {
45     command_timeout_usec=_command_timeout_usec;
46     hello_timeout_usec=_hello_timeout_usec;
47
48     // for reconnects
49     c.add_callback(new_connection,bind(&command_client::read_hello, boost::ref(*this)));
50
51     read_hello();
52 }
53
54 std::string command_client::read_packet(const long long &usec_timeout)
55 {
56     string resultpacket;
57     bool got_packet=false;
58     long long my_timeout=usec_timeout;
59     while(!(got_packet=c.get_packet(resultpacket)) && my_timeout > 0  && !c.is_closed())
60         c.fill_buffer(my_timeout,&my_timeout);
61
62     if (!got_packet)
63         throw t2n_transfer_error("timeout exceeded");
64
65     return resultpacket;
66 }
67
68 void command_client::read_hello()
69 {
70     string resultpacket;
71     bool got_packet=false;
72     long long my_timeout=hello_timeout_usec;
73     while(!(got_packet=c.get_packet(resultpacket)) && my_timeout > 0  && !c.is_closed())
74     {
75         c.fill_buffer(my_timeout,&my_timeout);
76
77         c.peek_packet(resultpacket);
78         check_hello(resultpacket);           // will throw before timeout if wrong data received
79     }
80
81     if (!got_packet)
82         throw t2n_transfer_error("timeout exceeded");
83
84     if (!check_hello(resultpacket))
85         throw t2n_version_mismatch("illegal hello received (incomplete): "+resultpacket);
86 }
87
88 bool command_client::check_hello(const string& hellostr)
89 {
90     istringstream hello(hellostr);
91
92     char chk;
93
94     if (hello.read(&chk,1))
95     {
96         if (chk != 'T')
97             throw t2n_version_mismatch("illegal hello received (T2N)");
98     }
99     else
100         return false;
101
102     if (hello.read(&chk,1))
103     {
104         if (chk != '2')
105             throw t2n_version_mismatch("illegal hello received (T2N)");
106     }
107     else
108         return false;
109
110     if (hello.read(&chk,1))
111     {
112         if (chk != 'N')
113             throw t2n_version_mismatch("illegal hello received (T2N)");
114     }
115     else
116         return false;
117
118     if (hello.read(&chk,1))
119     {
120         if (chk != 'v')
121             throw t2n_version_mismatch("illegal hello received (T2N)");
122     }
123     else
124         return false;
125
126     int prot_version;
127     if (hello >> prot_version)
128     {
129         if (prot_version != PROTOCOL_VERSION)
130             throw t2n_version_mismatch("not compatible with the server protocol version");
131     }
132     else
133         return false;
134
135     if (hello.read(&chk,1))
136     {
137         if (chk != ';')
138             throw t2n_version_mismatch("illegal hello received (1. ;)");
139     }
140     else
141         return false;
142
143     unsigned int hbo;
144     if (hello.read((char*)&hbo,sizeof(hbo)))
145     {
146         if (hbo != 1)
147             throw t2n_version_mismatch("host byte order not matching");
148     }
149     else
150         return false;
151
152     if (hello.read(&chk,1))
153     {
154         if (chk != ';')
155             throw t2n_version_mismatch("illegal hello received (2. ;)");
156     }
157     else
158         return false;
159
160     return true;
161 }
162
163 void command_client::send_command(command* cmd, result_container &res)
164 {
165     ostringstream ofs;
166     command_container cc(cmd);
167     boost::archive::binary_oarchive oa(ofs);
168
169     try
170     {
171         oa << cc;
172     }
173     catch(boost::archive::archive_exception &e)
174     {
175         ostringstream msg;
176         msg << "archive_exception while serializing on client-side, code " << e.code << " (" << e.what() << ")";
177         throw t2n_serialization_error(msg.str());
178     }
179     catch(...)
180         { throw; }
181
182     std::ostream* ostr;
183     if ((ostr=c.get_logstream(fulldebug))!=NULL)
184     {
185         (*ostr) << "sending command, decoded data: " << std::endl;
186         boost::archive::xml_oarchive xo(*ostr);
187         xo << BOOST_SERIALIZATION_NVP(cc);
188     }
189
190     c.write(ofs.str());
191
192     istringstream ifs(read_packet(command_timeout_usec));
193     boost::archive::binary_iarchive ia(ifs);
194
195     try
196     {
197         ia >> res;
198     }
199     catch(boost::archive::archive_exception &e)
200     {
201         ostringstream msg;
202         msg << "archive_exception while deserializing on client-side, code " << e.code << " (" << e.what() << ")";
203         throw t2n_serialization_error(msg.str());
204     }
205     catch(...)
206         { throw; }
207
208     if ((ostr=c.get_logstream(fulldebug))!=NULL)
209     {
210         (*ostr) << "received result, decoded data: " << std::endl;
211         boost::archive::xml_oarchive xo(*ostr);
212         xo << BOOST_SERIALIZATION_NVP(res);
213     }
214 }
215
216 }