09c5f5f084c1051221d1ca43ea9c180e070f7970
[libt2n] / test / reconnect.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 <cppunit/extensions/TestFactoryRegistry.h>
19 #include <cppunit/ui/text/TestRunner.h>
20 #include <cppunit/extensions/HelperMacros.h>
21
22 #include <socket_client.hxx>
23 #include <socket_server.hxx>
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 using namespace std;
30 using namespace libt2n;
31 using namespace CppUnit;
32
33 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
34 class real_write_connection: public socket_server_connection
35 {
36     public:
37         void real_write(const std::string& data)
38             { socket_write(data); }
39 };
40
41 class test_reconnect : public TestFixture
42 {
43     CPPUNIT_TEST_SUITE(test_reconnect);
44
45     CPPUNIT_TEST(simple_reconnect);
46     CPPUNIT_TEST(reconnect_with_close);
47     CPPUNIT_TEST(reconnect_buffer_complete);
48     CPPUNIT_TEST(reconnect_buffer_several_complete);
49     CPPUNIT_TEST(reconnect_buffer_no_incomplete1);
50     CPPUNIT_TEST(reconnect_buffer_no_incomplete2);
51
52     CPPUNIT_TEST_SUITE_END();
53
54     public:
55
56     void setUp()
57     { }
58
59     void tearDown()
60     { }
61
62     void send_raw_socket(string hello_string, socket_server* ss, int conn_id)
63     {
64         socket_server_connection *ssc=dynamic_cast<socket_server_connection*>(ss->get_connection(conn_id));
65
66         // this is an evil hack to get access to real_write, don't ever do this in an app!!!
67         real_write_connection *rwc=(real_write_connection*)ssc;
68         rwc->real_write(hello_string);
69     }
70
71     void simple_reconnect()
72     {
73         pid_t pid;
74
75         switch(pid=fork())
76         {
77             case -1:
78             {
79                 CPPUNIT_FAIL("fork error");
80                 break;
81             }
82             case 0:
83             // child
84             {
85                 socket_server ss("./socket");
86
87                 time_t t0 = time(NULL);
88
89                 // max 10 sec
90                 while (time(NULL) < t0 + 10 )
91                 {
92                     ss.fill_buffer(1000000);
93
94                     string data;
95                     unsigned int cid;
96
97                     if(ss.get_packet(data,cid))
98                     {
99                         server_connection* con=ss.get_connection(cid);
100
101                         if (data=="QUIT")
102                             break;
103
104                         if (data=="x")
105                             con->write(string().insert(0,100,'X'));
106                         else
107                             con->write(string().insert(0,100,'Y'));
108                     }
109                 }
110
111                 // don't call atexit and stuff
112                 _exit(0);
113             }
114
115             default:
116             // parent
117             {
118                 // don't kill us on broken pipe
119                 signal(SIGPIPE, SIG_IGN);
120
121                 // wait till server is up
122                 sleep(1);
123                 socket_client_connection sc("./socket");
124
125                 sc.write("abc");
126
127                 string data;
128
129                 while (!sc.get_packet(data))
130                     sc.fill_buffer(1000000);
131
132                 sc.reconnect();
133
134                 sc.write("x");
135
136                 while (!sc.get_packet(data))
137                     sc.fill_buffer(1000000);
138
139                 CPPUNIT_ASSERT_EQUAL(string().insert(0,100,'X'),data);
140             }
141         }
142     }
143
144     void reconnect_with_close()
145     {
146         pid_t pid;
147
148         switch(pid=fork())
149         {
150             case -1:
151             {
152                 CPPUNIT_FAIL("fork error");
153                 break;
154             }
155             case 0:
156             // child
157             {
158                 socket_server ss("./socket");
159
160                 time_t t0 = time(NULL);
161
162                 // max 10 sec
163                 while (time(NULL) < t0 + 10 )
164                 {
165                     ss.fill_buffer(1000000);
166
167                     string data;
168                     unsigned int cid;
169
170                     if(ss.get_packet(data,cid))
171                     {
172                         server_connection* con=ss.get_connection(cid);
173
174                         if (data=="QUIT")
175                             break;
176
177                         if (data=="x")
178                             con->write(string().insert(0,100,'X'));
179                         else
180                             con->write(string().insert(0,100,'Y'));
181                     }
182                 }
183
184                 // don't call atexit and stuff
185                 _exit(0);
186             }
187
188             default:
189             // parent
190             {
191                 // don't kill us on broken pipe
192                 signal(SIGPIPE, SIG_IGN);
193
194                 // wait till server is up
195                 sleep(1);
196                 socket_client_connection sc("./socket");
197
198                 sc.write("abc");
199
200                 string data;
201
202                 while (!sc.get_packet(data))
203                     sc.fill_buffer(1000000);
204
205                 sc.close();
206
207                 // empty buffer
208                 sc.get_packet(data);
209
210                 sc.reconnect();
211
212                 sc.write("x");
213
214                 while (!sc.get_packet(data))
215                     sc.fill_buffer(1000000);
216
217                 CPPUNIT_ASSERT_EQUAL(string().insert(0,100,'X'),data);
218             }
219         }
220     }
221
222     void reconnect_buffer_complete()
223     {
224         pid_t pid;
225
226         switch(pid=fork())
227         {
228             case -1:
229             {
230                 CPPUNIT_FAIL("fork error");
231                 break;
232             }
233             case 0:
234             // child
235             {
236                 socket_server ss("./socket");
237
238                 time_t t0 = time(NULL);
239
240                 // max 10 sec
241                 while (time(NULL) < t0 + 10 )
242                 {
243                     ss.fill_buffer(1000000);
244
245                     string data;
246                     unsigned int cid;
247
248                     if(ss.get_packet(data,cid))
249                     {
250                         server_connection* con=ss.get_connection(cid);
251
252                         if (data=="QUIT")
253                             break;
254
255                         if (data=="x")
256                             con->write(string().insert(0,100,'X'));
257                     }
258                 }
259
260                 // don't call atexit and stuff
261                 _exit(0);
262             }
263
264             default:
265             // parent
266             {
267                 // don't kill us on broken pipe
268                 signal(SIGPIPE, SIG_IGN);
269
270                 // wait till server is up
271                 sleep(1);
272                 socket_client_connection sc("./socket");
273
274                 sc.write("x");
275
276                 string data;
277
278                 while (!sc.packet_available())
279                     sc.fill_buffer(1000000);
280
281                 sc.reconnect();
282
283                 CPPUNIT_ASSERT_EQUAL_MESSAGE("packet not there",true,sc.get_packet(data));
284
285                 CPPUNIT_ASSERT_EQUAL_MESSAGE("data incorrect",string().insert(0,100,'X'),data);
286             }
287         }
288     }
289
290     void reconnect_buffer_several_complete()
291     {
292         pid_t pid;
293
294         const int packets=3;
295
296         switch(pid=fork())
297         {
298             case -1:
299             {
300                 CPPUNIT_FAIL("fork error");
301                 break;
302             }
303             case 0:
304             // child
305             {
306                 socket_server ss("./socket");
307
308                 time_t t0 = time(NULL);
309
310                 // max 10 sec
311                 while (time(NULL) < t0 + 10 )
312                 {
313                     ss.fill_buffer(1000000);
314
315                     string data;
316                     unsigned int cid;
317
318                     if(ss.get_packet(data,cid))
319                     {
320                         server_connection* con=ss.get_connection(cid);
321
322                         if (data=="QUIT")
323                             break;
324
325                         if (data=="x")
326                         {
327                             for (int i=0; i<packets; i++)
328                                 con->write(string().insert(0,100,'X'));
329                         }
330                     }
331                 }
332
333                 // don't call atexit and stuff
334                 _exit(0);
335             }
336
337             default:
338             // parent
339             {
340                 // don't kill us on broken pipe
341                 signal(SIGPIPE, SIG_IGN);
342
343                 // wait till server is up
344                 sleep(1);
345                 socket_client_connection sc("./socket");
346
347                 sc.write("x");
348
349                 // retrieve packets for 3 seconds
350                 time_t t0 = time(NULL);
351
352                 // max 3 sec
353                 while (time(NULL) < t0 + 3 )
354                     sc.fill_buffer(1000000);
355
356                 // we now should have packets complete packets in the buffer
357
358                 sc.reconnect();
359
360                 // are these packets still there?
361
362                 for (int i=0; i < packets; i++)
363                 {
364                     string data;
365
366                     ostringstream os;
367                     os << "packet " << i << " not there";
368
369                     CPPUNIT_ASSERT_EQUAL_MESSAGE(os.str(),true,sc.get_packet(data));
370
371                     os.str("");
372                     os << "packet " << i << " incorrect";
373
374                     CPPUNIT_ASSERT_EQUAL_MESSAGE(os.str(),string().insert(0,100,'X'),data);
375                 }
376             }
377         }
378     }
379
380     void reconnect_buffer_no_incomplete1()
381     {
382         pid_t pid;
383
384         switch(pid=fork())
385         {
386             case -1:
387             {
388                 CPPUNIT_FAIL("fork error");
389                 break;
390             }
391             case 0:
392             // child
393             {
394                 socket_server ss("./socket");
395
396                 time_t t0 = time(NULL);
397
398                 // max 10 sec
399                 while (time(NULL) < t0 + 10 )
400                 {
401                     ss.fill_buffer(1000000);
402
403                     string data;
404                     unsigned int cid;
405
406                     if(ss.get_packet(data,cid))
407                     {
408                         server_connection* con=ss.get_connection(cid);
409
410                         if (data=="QUIT")
411                             break;
412
413                         if (data=="x")
414                         {
415                             con->write(string().insert(0,100,'X'));
416                             send_raw_socket("aaaab",&ss,cid);
417                         }
418                     }
419                 }
420
421                 // don't call atexit and stuff
422                 _exit(0);
423             }
424
425             default:
426             // parent
427             {
428                 // don't kill us on broken pipe
429                 signal(SIGPIPE, SIG_IGN);
430
431                 // wait till server is up
432                 sleep(1);
433                 socket_client_connection sc("./socket");
434
435                 sc.write("x");
436
437                 // retrieve packets for 3 seconds
438                 time_t t0 = time(NULL);
439
440                 // max 3 sec
441                 while (time(NULL) < t0 + 3 )
442                     sc.fill_buffer(1000000);
443
444                 // we now should have one complete packet and some stuff in the buffer
445
446                 string data;
447                 sc.get_packet(data);
448
449                 CPPUNIT_ASSERT_EQUAL_MESSAGE("no incomplete packet",true,(sc.peek_packet(data))>0);
450
451                 sc.reconnect();
452
453                 CPPUNIT_ASSERT_EQUAL_MESSAGE("incomplete packet not removed",0,(int)sc.peek_packet(data));
454             }
455         }
456     }
457
458     void reconnect_buffer_no_incomplete2()
459     {
460         pid_t pid;
461
462         switch(pid=fork())
463         {
464             case -1:
465             {
466                 CPPUNIT_FAIL("fork error");
467                 break;
468             }
469             case 0:
470             // child
471             {
472                 socket_server ss("./socket");
473
474                 time_t t0 = time(NULL);
475
476                 // max 10 sec
477                 while (time(NULL) < t0 + 10 )
478                 {
479                     ss.fill_buffer(1000000);
480
481                     string data;
482                     unsigned int cid;
483
484                     if(ss.get_packet(data,cid))
485                     {
486                         server_connection* con=ss.get_connection(cid);
487
488                         if (data=="QUIT")
489                             break;
490
491                         if (data=="x")
492                         {
493                             con->write(string().insert(0,100,'X'));
494
495                             string blob=string().insert(0,100,'Y');
496
497                             // one byte will be missing...
498                             int size=blob.size()+1;
499                             char sizetransfer[sizeof(int)+1];
500                             memcpy(sizetransfer,(void*)&size,sizeof(int));
501                             sizetransfer[sizeof(int)+1]=0;
502
503                             string packet=string(sizetransfer)+blob;
504
505                             send_raw_socket(packet,&ss,cid);
506                         }
507                     }
508                 }
509
510                 // don't call atexit and stuff
511                 _exit(0);
512             }
513
514             default:
515             // parent
516             {
517                 // don't kill us on broken pipe
518                 signal(SIGPIPE, SIG_IGN);
519
520                 // wait till server is up
521                 sleep(1);
522                 socket_client_connection sc("./socket");
523
524                 sc.write("x");
525
526                 // retrieve packets for 3 seconds
527                 time_t t0 = time(NULL);
528
529                 // max 3 sec
530                 while (time(NULL) < t0 + 3 )
531                     sc.fill_buffer(1000000);
532
533                 // we now should have one complete packet and some stuff in the buffer
534
535                 sc.reconnect();
536
537                 string data;
538
539                 CPPUNIT_ASSERT_EQUAL_MESSAGE("packet not there",true,sc.get_packet(data));
540                 CPPUNIT_ASSERT_EQUAL_MESSAGE("data incorrect",string().insert(0,100,'X'),data);
541
542                 CPPUNIT_ASSERT_EQUAL_MESSAGE("incomplete packet not removed",0,(int)sc.peek_packet(data));
543             }
544         }
545     }
546
547 };
548
549 CPPUNIT_TEST_SUITE_REGISTRATION(test_reconnect);