libt2n: (gerd) add hello peek
[libt2n] / test / hello.cpp
1 /***************************************************************************
2  *   Copyright (C) 2004 by Intra2net AG                                    *
3  *   info@intra2net.com                                                    *
4  *                                                                         *
5  ***************************************************************************/
6
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <stdio.h>
12
13 #include <iostream>
14 #include <string>
15 #include <sstream>
16 #include <stdexcept>
17
18 #include <boost/bind.hpp>
19
20 #include <cppunit/extensions/TestFactoryRegistry.h>
21 #include <cppunit/ui/text/TestRunner.h>
22 #include <cppunit/extensions/HelperMacros.h>
23
24 #include <t2n_exception.hxx>
25 #include <socket_client.hxx>
26 #include <socket_server.hxx>
27 #include <command_client.hxx>
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 using namespace std;
34 using namespace libt2n;
35 using namespace CppUnit;
36
37 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
38 class real_write_connection: public socket_server_connection
39 {
40     public:
41         void real_write(const std::string& data)
42             { socket_write(data); }
43 };
44
45 class test_hello : public TestFixture
46 {
47     CPPUNIT_TEST_SUITE(test_hello);
48
49     CPPUNIT_TEST(HelloOk);
50     CPPUNIT_TEST(BadTag);
51     CPPUNIT_TEST(BadVersion);
52     CPPUNIT_TEST(SeparatorMissing);
53     CPPUNIT_TEST(WrongByteOrder);
54     CPPUNIT_TEST(OtherServer);
55
56     CPPUNIT_TEST_SUITE_END();
57
58     public:
59
60     void setUp()
61     { }
62
63     void tearDown()
64     { }
65
66     void send_hello(string hello_string, socket_server* ss, int conn_id)
67     {
68         server_connection *sc=ss->get_connection(conn_id);
69         sc->write(hello_string);
70     }
71
72     void send_raw_socket(string hello_string, socket_server* ss, int conn_id)
73     {
74         socket_server_connection *ssc=dynamic_cast<socket_server_connection*>(ss->get_connection(conn_id));
75
76         // this is an evil hack to get access to real_write, don't ever do this in an app!!!
77         real_write_connection *rwc=(real_write_connection*)ssc;
78         rwc->real_write(hello_string);
79     }
80
81     void HelloOk()
82     {
83         pid_t pid;
84
85         switch(pid=fork())
86         {
87             case -1:
88             {
89                 CPPUNIT_FAIL("fork error");
90                 break;
91             }
92             case 0:
93             // child
94             {
95                 socket_server ss("./socket");
96
97                 ostringstream hello;
98                 hello << "T2Nv" << PROTOCOL_VERSION << ';';
99                 int byteordercheck=1;
100                 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
101                 hello << ';';
102
103                 ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
104
105                 // max 10 sec
106                 for (int i=0; i < 10; i++)
107                     ss.fill_buffer(1000000);
108                 // don't call atexit and stuff
109                 _exit(0);
110             }
111
112             default:
113             // parent
114             {
115                 string data;
116
117                 // wait till server is up
118                 sleep(1);
119                 socket_client_connection sc("./socket");
120                 command_client cc(sc);
121             }
122         }
123     }
124
125     void BadTag()
126     {
127         pid_t pid;
128
129         switch(pid=fork())
130         {
131             case -1:
132             {
133                 CPPUNIT_FAIL("fork error");
134                 break;
135             }
136             case 0:
137             // child
138             {
139                 socket_server ss("./socket");
140
141                 ostringstream hello;
142                 hello << "XYZ 123";
143
144                 ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
145
146                 // max 10 sec
147                 for (int i=0; i < 10; i++)
148                     ss.fill_buffer(1000000);
149                 // don't call atexit and stuff
150                 _exit(0);
151             }
152
153             default:
154             // parent
155             {
156                 string data;
157
158                 // wait till server is up
159                 sleep(1);
160                 socket_client_connection sc("./socket");
161
162                 string errormsg;
163
164                 try
165                 {
166                     command_client cc(sc);
167                 }
168                 catch(t2n_version_mismatch &e)
169                 { errormsg=e.what(); }
170                 catch(...)
171                 { throw; }
172
173                 CPPUNIT_ASSERT_EQUAL(string("illegal hello received (T2N)"),errormsg);
174             }
175         }
176     }
177
178     void BadVersion()
179     {
180         pid_t pid;
181
182         switch(pid=fork())
183         {
184             case -1:
185             {
186                 CPPUNIT_FAIL("fork error");
187                 break;
188             }
189             case 0:
190             // child
191             {
192                 socket_server ss("./socket");
193
194                 ostringstream hello;
195                 // lets hope we don't ever get near such a version number...
196                 hello << "T2Nv" << 4982271 << ';';
197                 int byteordercheck=1;
198                 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
199                 hello << ';';
200
201                 ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
202
203                 // max 10 sec
204                 for (int i=0; i < 10; i++)
205                     ss.fill_buffer(1000000);
206                 // don't call atexit and stuff
207                 _exit(0);
208             }
209
210             default:
211             // parent
212             {
213                 string data;
214
215                 // wait till server is up
216                 sleep(1);
217                 socket_client_connection sc("./socket");
218
219                 string errormsg;
220
221                 try
222                 {
223                     command_client cc(sc);
224                 }
225                 catch(t2n_version_mismatch &e)
226                 { errormsg=e.what(); }
227                 catch(...)
228                 { throw; }
229
230                 CPPUNIT_ASSERT_EQUAL(string("not compatible with the server protocol version"),errormsg);
231             }
232         }
233     }
234
235     void SeparatorMissing()
236     {
237         pid_t pid;
238
239         switch(pid=fork())
240         {
241             case -1:
242             {
243                 CPPUNIT_FAIL("fork error");
244                 break;
245             }
246             case 0:
247             // child
248             {
249                 socket_server ss("./socket");
250
251                 ostringstream hello;
252                 hello << "T2Nv" << PROTOCOL_VERSION;
253                 int byteordercheck=1;
254                 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
255                 hello << ';';
256
257                 ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
258
259                 // max 10 sec
260                 for (int i=0; i < 10; i++)
261                     ss.fill_buffer(1000000);
262                 // don't call atexit and stuff
263                 _exit(0);
264             }
265
266             default:
267             // parent
268             {
269                 string data;
270
271                 // wait till server is up
272                 sleep(1);
273                 socket_client_connection sc("./socket");
274
275                 string errormsg;
276
277                 try
278                 {
279                     command_client cc(sc);
280                 }
281                 catch(t2n_version_mismatch &e)
282                 { errormsg=e.what(); }
283                 catch(...)
284                 { throw; }
285
286                 CPPUNIT_ASSERT_EQUAL(string("illegal hello received (1. ;)"),errormsg);
287             }
288         }
289     }
290
291     void WrongByteOrder()
292     {
293         pid_t pid;
294
295         switch(pid=fork())
296         {
297             case -1:
298             {
299                 CPPUNIT_FAIL("fork error");
300                 break;
301             }
302             case 0:
303             // child
304             {
305                 socket_server ss("./socket");
306
307                 ostringstream hello;
308                 hello << "T2Nv" << PROTOCOL_VERSION << ';';
309                 int byteordercheck=1;
310                 int dst;
311                 char* si=(char*)&byteordercheck;
312                 char* di=(char*)&dst;
313
314                 di[0]=si[3];
315                 di[1]=si[2];
316                 di[2]=si[1];
317                 di[3]=si[0];
318
319                 hello.write((char*)&dst,sizeof(dst));
320                 hello << ';';
321
322                 ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
323
324                 // max 10 sec
325                 for (int i=0; i < 10; i++)
326                     ss.fill_buffer(1000000);
327                 // don't call atexit and stuff
328                 _exit(0);
329             }
330
331             default:
332             // parent
333             {
334                 string data;
335
336                 // wait till server is up
337                 sleep(1);
338                 socket_client_connection sc("./socket");
339
340                 string errormsg;
341
342                 try
343                 {
344                     command_client cc(sc);
345                 }
346                 catch(t2n_version_mismatch &e)
347                 { errormsg=e.what(); }
348                 catch(...)
349                 { throw; }
350
351                 CPPUNIT_ASSERT_EQUAL(string("host byte order not matching"),errormsg);
352             }
353         }
354     }
355
356     void OtherServer()
357     {
358         pid_t pid;
359
360         switch(pid=fork())
361         {
362             case -1:
363             {
364                 CPPUNIT_FAIL("fork error");
365                 break;
366             }
367             case 0:
368             // child
369             {
370                 socket_server ss("./socket");
371
372                 ostringstream hello;
373                 // hmm, we got the wrong socket
374                 hello << "* OK intradev.net.lan Cyrus IMAP4 v2.2.13 server ready";
375
376                 ss.add_callback(new_connection,bind(&test_hello::send_raw_socket, boost::ref(*this), hello.str(),&ss, _1));
377
378                 // max 3 sec
379                 for (int i=0; i < 3; i++)
380                     ss.fill_buffer(1000000);
381                 // don't call atexit and stuff
382                 _exit(0);
383             }
384
385             default:
386             // parent
387             {
388                 string data;
389
390                 // wait till server is up
391                 sleep(1);
392                 socket_client_connection sc("./socket");
393
394                 string errormsg;
395
396                 try
397                 {
398                     command_client cc(sc);
399                 }
400                 catch(t2n_version_mismatch &e)
401                 { errormsg=e.what(); }
402                 catch(...)
403                 { throw; }
404
405                 CPPUNIT_ASSERT_EQUAL(string("illegal hello received (T2N)"),errormsg);
406             }
407         }
408     }
409
410 };
411
412 CPPUNIT_TEST_SUITE_REGISTRATION(test_hello);