Change license from LGPL to GPL version 2 + linking exception. This fixes C++ templat...
[libt2n] / test / hello.cpp
1 /*
2 Copyright (C) 2004 by Intra2net AG
3
4 The software in this package is distributed under the GNU General
5 Public License version 2 (with a special exception described below).
6
7 A copy of GNU General Public License (GPL) is included in this distribution,
8 in the file COPYING.GPL.
9
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.
15
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.
18
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.
21 */
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <stdio.h>
27
28 #include <iostream>
29 #include <string>
30 #include <sstream>
31 #include <stdexcept>
32
33 #include <boost/bind.hpp>
34
35 #include <cppunit/extensions/TestFactoryRegistry.h>
36 #include <cppunit/ui/text/TestRunner.h>
37 #include <cppunit/extensions/HelperMacros.h>
38
39 #include <t2n_exception.hxx>
40 #include <socket_client.hxx>
41 #include <socket_server.hxx>
42 #include <command_client.hxx>
43
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 using namespace std;
49 using namespace libt2n;
50 using namespace CppUnit;
51
52 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
53 class real_write_connection: public socket_server_connection
54 {
55     public:
56         void real_write(const std::string& data)
57             { socket_write(data); }
58 };
59
60 class test_hello : public TestFixture
61 {
62     CPPUNIT_TEST_SUITE(test_hello);
63
64     CPPUNIT_TEST(HelloOk);
65     CPPUNIT_TEST(BadTag);
66     CPPUNIT_TEST(BadVersion);
67     CPPUNIT_TEST(SeparatorMissing);
68     CPPUNIT_TEST(WrongByteOrder);
69     CPPUNIT_TEST(OtherServerBig);
70     CPPUNIT_TEST(OtherServerSmall);
71
72     CPPUNIT_TEST_SUITE_END();
73
74     pid_t child_pid;
75
76     public:
77
78     void setUp()
79     { }
80
81     void tearDown()
82     {
83         // make sure the server-child is dead before the next test runs
84         kill(child_pid,SIGKILL);
85         sleep(1);
86     }
87
88     void send_hello(string hello_string, socket_server* ss, int conn_id)
89     {
90         server_connection *sc=ss->get_connection(conn_id);
91         sc->write(hello_string);
92     }
93
94     void send_raw_socket(string hello_string, socket_server* ss, int conn_id)
95     {
96         socket_server_connection *ssc=dynamic_cast<socket_server_connection*>(ss->get_connection(conn_id));
97
98         // this is an evil hack to get access to real_write, don't ever do this in an app!!!
99         real_write_connection *rwc=(real_write_connection*)ssc;
100         rwc->real_write(hello_string);
101     }
102
103     void HelloOk()
104     {
105         switch(child_pid=fork())
106         {
107             case -1:
108             {
109                 CPPUNIT_FAIL("fork error");
110                 break;
111             }
112             case 0:
113             // child
114             {
115                 try
116                 {
117                     socket_server ss("./socket");
118
119                     ostringstream hello;
120                     hello << "T2Nv" << PROTOCOL_VERSION << ';';
121                     int byteordercheck=1;
122                     hello.write((char*)&byteordercheck,sizeof(byteordercheck));
123                     hello << ';';
124
125                     ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
126
127                     // max 10 sec
128                     for (int i=0; i < 10; i++)
129                         ss.fill_buffer(1000000);
130                 } catch(...)
131                 {
132                     std::cerr << "exception in child. ignoring\n";
133                 }
134
135                 // don't call atexit and stuff
136                 _exit(0);
137             }
138
139             default:
140             // parent
141             {
142                 string data;
143
144                 // wait till server is up
145                 sleep(1);
146                 socket_client_connection sc("./socket");
147                 command_client cc(&sc);
148             }
149         }
150     }
151
152     void BadTag()
153     {
154         switch(child_pid=fork())
155         {
156             case -1:
157             {
158                 CPPUNIT_FAIL("fork error");
159                 break;
160             }
161             case 0:
162             // child
163             {
164                 try
165                 {
166                     socket_server ss("./socket");
167
168                     ostringstream hello;
169                     hello << "XYZ 123";
170
171                     ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
172
173                     // max 10 sec
174                     for (int i=0; i < 10; i++)
175                         ss.fill_buffer(1000000);
176                 } catch(...)
177                 {
178                     std::cerr << "exception in child. ignoring\n";
179                 }
180
181                 // don't call atexit and stuff
182                 _exit(0);
183             }
184
185             default:
186             // parent
187             {
188                 string data;
189
190                 // wait till server is up
191                 sleep(1);
192                 socket_client_connection sc("./socket");
193
194                 command_client cc(&sc);
195
196                 t2n_exception* ep=cc.get_constuctor_exception();
197
198                 string errormsg;
199                 if (ep)
200                     errormsg=ep->what();
201
202                 CPPUNIT_ASSERT_EQUAL(string("illegal hello received (T2N)"),errormsg);
203             }
204         }
205     }
206
207     void BadVersion()
208     {
209         switch(child_pid=fork())
210         {
211             case -1:
212             {
213                 CPPUNIT_FAIL("fork error");
214                 break;
215             }
216             case 0:
217             // child
218             {
219                 try
220                 {
221                     socket_server ss("./socket");
222
223                     ostringstream hello;
224                     // lets hope we don't ever get near such a version number...
225                     hello << "T2Nv" << 4982271 << ';';
226                     int byteordercheck=1;
227                     hello.write((char*)&byteordercheck,sizeof(byteordercheck));
228                     hello << ';';
229
230                     ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
231
232                     // max 10 sec
233                     for (int i=0; i < 10; i++)
234                         ss.fill_buffer(1000000);
235                 } catch(...)
236                 {
237                     std::cerr << "exception in child. ignoring\n";
238                 }
239
240                 // don't call atexit and stuff
241                 _exit(0);
242             }
243
244             default:
245             // parent
246             {
247                 string data;
248
249                 // wait till server is up
250                 sleep(1);
251                 socket_client_connection sc("./socket");
252
253                 command_client cc(&sc);
254
255                 t2n_exception* ep=cc.get_constuctor_exception();
256
257                 string errormsg;
258                 if (ep)
259                     errormsg=ep->what();
260
261                 CPPUNIT_ASSERT_EQUAL(string("not compatible with the server protocol version"),errormsg);
262             }
263         }
264     }
265
266     void SeparatorMissing()
267     {
268         switch(child_pid=fork())
269         {
270             case -1:
271             {
272                 CPPUNIT_FAIL("fork error");
273                 break;
274             }
275             case 0:
276             // child
277             {
278                 try
279                 {
280                     socket_server ss("./socket");
281
282                     ostringstream hello;
283                     hello << "T2Nv" << PROTOCOL_VERSION;
284                     int byteordercheck=1;
285                     hello.write((char*)&byteordercheck,sizeof(byteordercheck));
286                     hello << ';';
287
288                     ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
289
290                     // max 10 sec
291                     for (int i=0; i < 10; i++)
292                         ss.fill_buffer(1000000);
293                 } catch(...)
294                 {
295                     std::cerr << "exception in child. ignoring\n";
296                 }
297
298                 // don't call atexit and stuff
299                 _exit(0);
300             }
301
302             default:
303             // parent
304             {
305                 string data;
306
307                 // wait till server is up
308                 sleep(1);
309                 socket_client_connection sc("./socket");
310
311                 command_client cc(&sc);
312
313                 t2n_exception* ep=cc.get_constuctor_exception();
314
315                 string errormsg;
316                 if (ep)
317                     errormsg=ep->what();
318
319                 CPPUNIT_ASSERT_EQUAL(string("illegal hello received (1. ;)"),errormsg);
320             }
321         }
322     }
323
324     void WrongByteOrder()
325     {
326         switch(child_pid=fork())
327         {
328             case -1:
329             {
330                 CPPUNIT_FAIL("fork error");
331                 break;
332             }
333             case 0:
334             // child
335             {
336                 try
337                 {
338                     socket_server ss("./socket");
339
340                     ostringstream hello;
341                     hello << "T2Nv" << PROTOCOL_VERSION << ';';
342                     int byteordercheck=1;
343                     int dst;
344                     char* si=(char*)&byteordercheck;
345                     char* di=(char*)&dst;
346
347                     di[0]=si[3];
348                     di[1]=si[2];
349                     di[2]=si[1];
350                     di[3]=si[0];
351
352                     hello.write((char*)&dst,sizeof(dst));
353                     hello << ';';
354
355                     ss.add_callback(new_connection,bind(&test_hello::send_hello, boost::ref(*this), hello.str(),&ss, _1));
356
357                     // max 10 sec
358                     for (int i=0; i < 10; i++)
359                         ss.fill_buffer(1000000);
360                 } catch(...)
361                 {
362                     std::cerr << "exception in child. ignoring\n";
363                 }
364
365                 // don't call atexit and stuff
366                 _exit(0);
367             }
368
369             default:
370             // parent
371             {
372                 string data;
373
374                 // wait till server is up
375                 sleep(1);
376                 socket_client_connection sc("./socket");
377
378                 command_client cc(&sc);
379
380                 t2n_exception* ep=cc.get_constuctor_exception();
381
382                 string errormsg;
383                 if (ep)
384                     errormsg=ep->what();
385
386                 CPPUNIT_ASSERT_EQUAL(string("host byte order not matching"),errormsg);
387             }
388         }
389     }
390
391     void OtherServerBig()
392     {
393         switch(child_pid=fork())
394         {
395             case -1:
396             {
397                 CPPUNIT_FAIL("fork error");
398                 break;
399             }
400             case 0:
401             // child
402             {
403                 try
404                 {
405                     socket_server ss("./socket");
406
407                     ostringstream hello;
408                     // hmm, we got the wrong socket
409                     hello << "* OK intradev.net.lan Cyrus IMAP4 v2.2.13 server ready";
410
411                     ss.add_callback(new_connection,bind(&test_hello::send_raw_socket, boost::ref(*this), hello.str(),&ss, _1));
412
413                     // max 3 sec
414                     for (int i=0; i < 3; i++)
415                         ss.fill_buffer(1000000);
416                 } catch(...)
417                 {
418                     std::cerr << "exception in child. ignoring\n";
419                 }
420
421                 // don't call atexit and stuff
422                 _exit(0);
423             }
424
425             default:
426             // parent
427             {
428                 string data;
429
430                 // wait till server is up
431                 sleep(1);
432                 socket_client_connection sc("./socket");
433
434                 command_client cc(&sc);
435
436                 t2n_exception* ep=cc.get_constuctor_exception();
437
438                 string errormsg;
439                 if (ep)
440                     errormsg=ep->what();
441
442                 CPPUNIT_ASSERT_EQUAL(string("illegal hello received (T2N)"),errormsg);
443             }
444         }
445     }
446
447     void OtherServerSmall()
448     {
449         switch(child_pid=fork())
450         {
451             case -1:
452             {
453                 CPPUNIT_FAIL("fork error");
454                 break;
455             }
456             case 0:
457             // child
458             {
459                 try
460                 {
461                     socket_server ss("./socket");
462
463                     ostringstream hello;
464                     // hmm, we got the wrong socket
465                     hello << "READY";
466
467                     ss.add_callback(new_connection,bind(&test_hello::send_raw_socket, boost::ref(*this), hello.str(),&ss, _1));
468
469                     // max 3 sec
470                     for (int i=0; i < 3; i++)
471                         ss.fill_buffer(1000000);
472                 } catch(...)
473                 {
474                     std::cerr << "exception in child. ignoring\n";
475                 }
476
477                 // don't call atexit and stuff
478                 _exit(0);
479             }
480
481             default:
482             // parent
483             {
484                 string data;
485
486                 // wait till server is up
487                 sleep(1);
488                 socket_client_connection sc("./socket");
489
490                 command_client cc(&sc);
491
492                 t2n_exception* ep=cc.get_constuctor_exception();
493
494                 string errormsg;
495                 if (ep)
496                     errormsg=ep->what();
497
498                 CPPUNIT_ASSERT_EQUAL(string("illegal hello received (T2N)"),errormsg);
499             }
500         }
501     }
502
503 };
504
505 CPPUNIT_TEST_SUITE_REGISTRATION(test_hello);