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