libt2n: (gerd) add client timeouts & tests, hello peek missing
[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     istringstream hello(read_packet(hello_timeout_usec));
71
72     char chk[5];
73     hello.read(chk,4);
74     chk[4]=0;
75     if (hello.fail() || hello.eof() || string("T2Nv") != chk)
76         throw t2n_version_mismatch("illegal hello received (T2N)");
77
78     int prot_version;
79     hello >> prot_version;
80     if (hello.fail() || hello.eof() || prot_version != PROTOCOL_VERSION)
81         throw t2n_version_mismatch("not compatible with the server protocol version");
82
83     hello.read(chk,1);
84     if (hello.fail() || hello.eof() || chk[0] != ';')
85         throw t2n_version_mismatch("illegal hello received (1. ;)");
86
87     hello.read(chk,4);
88     if (hello.fail() || hello.eof() || *((int*)chk) != 1)
89         throw t2n_version_mismatch("host byte order not matching");
90
91     hello.read(chk,1);
92     if (hello.fail() || hello.eof() || chk[0] != ';')
93         throw t2n_version_mismatch("illegal hello received (2. ;)");
94 }
95
96 void command_client::send_command(command* cmd, result_container &res)
97 {
98     ostringstream ofs;
99     command_container cc(cmd);
100     boost::archive::binary_oarchive oa(ofs);
101
102     try
103     {
104         oa << cc;
105     }
106     catch(boost::archive::archive_exception &e)
107     {
108         ostringstream msg;
109         msg << "archive_exception while serializing on client-side, code " << e.code << " (" << e.what() << ")";
110         throw t2n_serialization_error(msg.str());
111     }
112     catch(...)
113         { throw; }
114
115     std::ostream* ostr;
116     if ((ostr=c.get_logstream(fulldebug))!=NULL)
117     {
118         (*ostr) << "sending command, decoded data: " << std::endl;
119         boost::archive::xml_oarchive xo(*ostr);
120         xo << BOOST_SERIALIZATION_NVP(cc);
121     }
122
123     c.write(ofs.str());
124
125     istringstream ifs(read_packet(command_timeout_usec));
126     boost::archive::binary_iarchive ia(ifs);
127
128     try
129     {
130         ia >> res;
131     }
132     catch(boost::archive::archive_exception &e)
133     {
134         ostringstream msg;
135         msg << "archive_exception while deserializing on client-side, code " << e.code << " (" << e.what() << ")";
136         throw t2n_serialization_error(msg.str());
137     }
138     catch(...)
139         { throw; }
140
141     if ((ostr=c.get_logstream(fulldebug))!=NULL)
142     {
143         (*ostr) << "received result, decoded data: " << std::endl;
144         boost::archive::xml_oarchive xo(*ostr);
145         xo << BOOST_SERIALIZATION_NVP(res);
146     }
147 }
148
149 }