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