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