Change license from LGPL to GPL version 2 + linking exception. This fixes C++ templat...
[libt2n] / test / reconnect.cpp
CommitLineData
19facd85
TJ
1/*
2Copyright (C) 2004 by Intra2net AG
af84dfb5 3
19facd85
TJ
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*/
af84dfb5
GE
22#include <sys/types.h>
23#include <unistd.h>
24#include <errno.h>
25#include <signal.h>
26#include <stdio.h>
4c3662a0 27#include <time.h>
af84dfb5
GE
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
b5922184
GE
70 pid_t child_pid;
71
af84dfb5
GE
72 public:
73
74 void setUp()
75 { }
76
77 void tearDown()
b5922184
GE
78 {
79 // make sure the server-child is dead before the next test runs
80 kill(child_pid,SIGKILL);
81 sleep(1);
82 }
af84dfb5
GE
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 {
b5922184 95 switch(child_pid=fork())
af84dfb5
GE
96 {
97 case -1:
98 {
99 CPPUNIT_FAIL("fork error");
100 break;
101 }
102 case 0:
103 // child
104 {
441d41fe 105 try
af84dfb5 106 {
441d41fe 107 socket_server ss("./socket");
af84dfb5 108
441d41fe 109 time_t t0 = time(NULL);
af84dfb5 110
441d41fe
TJ
111 // max 10 sec
112 while (time(NULL) < t0 + 10 )
af84dfb5 113 {
441d41fe
TJ
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);
af84dfb5 122
441d41fe
TJ
123 if (data=="QUIT")
124 break;
af84dfb5 125
441d41fe
TJ
126 if (data=="x")
127 con->write(string().insert(0,100,'X'));
128 else
129 con->write(string().insert(0,100,'Y'));
130 }
af84dfb5 131 }
441d41fe
TJ
132 } catch(...)
133 {
134 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
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 {
b5922184 172 switch(child_pid=fork())
af84dfb5
GE
173 {
174 case -1:
175 {
176 CPPUNIT_FAIL("fork error");
177 break;
178 }
179 case 0:
180 // child
181 {
441d41fe 182 try
af84dfb5 183 {
441d41fe 184 socket_server ss("./socket");
af84dfb5 185
441d41fe 186 time_t t0 = time(NULL);
af84dfb5 187
441d41fe
TJ
188 // max 10 sec
189 while (time(NULL) < t0 + 10 )
af84dfb5 190 {
441d41fe 191 ss.fill_buffer(1000000);
af84dfb5 192
441d41fe
TJ
193 string data;
194 unsigned int cid;
af84dfb5 195
441d41fe
TJ
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 }
af84dfb5 208 }
441d41fe
TJ
209 } catch(...)
210 {
211 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
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 {
b5922184 254 switch(child_pid=fork())
af84dfb5
GE
255 {
256 case -1:
257 {
258 CPPUNIT_FAIL("fork error");
259 break;
260 }
261 case 0:
262 // child
263 {
441d41fe 264 try
af84dfb5 265 {
441d41fe 266 socket_server ss("./socket");
af84dfb5 267
441d41fe 268 time_t t0 = time(NULL);
af84dfb5 269
441d41fe
TJ
270 // max 10 sec
271 while (time(NULL) < t0 + 10 )
af84dfb5 272 {
441d41fe
TJ
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);
af84dfb5 281
441d41fe
TJ
282 if (data=="QUIT")
283 break;
af84dfb5 284
441d41fe
TJ
285 if (data=="x")
286 con->write(string().insert(0,100,'X'));
287 }
af84dfb5 288 }
441d41fe
TJ
289 } catch(...)
290 {
291 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
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 {
af84dfb5
GE
326 const int packets=3;
327
b5922184 328 switch(child_pid=fork())
af84dfb5
GE
329 {
330 case -1:
331 {
332 CPPUNIT_FAIL("fork error");
333 break;
334 }
335 case 0:
336 // child
337 {
441d41fe 338 try
af84dfb5 339 {
441d41fe 340 socket_server ss("./socket");
af84dfb5 341
441d41fe 342 time_t t0 = time(NULL);
af84dfb5 343
441d41fe
TJ
344 // max 10 sec
345 while (time(NULL) < t0 + 10 )
af84dfb5 346 {
441d41fe 347 ss.fill_buffer(1000000);
af84dfb5 348
441d41fe
TJ
349 string data;
350 unsigned int cid;
af84dfb5 351
441d41fe 352 if(ss.get_packet(data,cid))
af84dfb5 353 {
441d41fe
TJ
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 }
af84dfb5
GE
364 }
365 }
441d41fe
TJ
366 } catch(...)
367 {
368 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
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 {
b5922184 420 switch(child_pid=fork())
af84dfb5
GE
421 {
422 case -1:
423 {
424 CPPUNIT_FAIL("fork error");
425 break;
426 }
427 case 0:
428 // child
429 {
441d41fe 430 try
af84dfb5 431 {
441d41fe 432 socket_server ss("./socket");
af84dfb5 433
441d41fe 434 time_t t0 = time(NULL);
af84dfb5 435
441d41fe
TJ
436 // max 10 sec
437 while (time(NULL) < t0 + 10 )
af84dfb5 438 {
441d41fe 439 ss.fill_buffer(1000000);
af84dfb5 440
441d41fe
TJ
441 string data;
442 unsigned int cid;
af84dfb5 443
441d41fe 444 if(ss.get_packet(data,cid))
af84dfb5 445 {
441d41fe
TJ
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 }
af84dfb5
GE
456 }
457 }
441d41fe
TJ
458 } catch(...)
459 {
460 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
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 {
b5922184 502 switch(child_pid=fork())
af84dfb5
GE
503 {
504 case -1:
505 {
506 CPPUNIT_FAIL("fork error");
507 break;
508 }
509 case 0:
510 // child
511 {
441d41fe 512 try
af84dfb5 513 {
441d41fe 514 socket_server ss("./socket");
af84dfb5 515
441d41fe 516 time_t t0 = time(NULL);
af84dfb5 517
441d41fe
TJ
518 // max 10 sec
519 while (time(NULL) < t0 + 10 )
af84dfb5 520 {
441d41fe 521 ss.fill_buffer(1000000);
af84dfb5 522
441d41fe
TJ
523 string data;
524 unsigned int cid;
af84dfb5 525
441d41fe 526 if(ss.get_packet(data,cid))
af84dfb5 527 {
441d41fe
TJ
528 server_connection* con=ss.get_connection(cid);
529
530 if (data=="QUIT")
531 break;
af84dfb5 532
441d41fe
TJ
533 if (data=="x")
534 {
535 con->write(string().insert(0,100,'X'));
536
537 string blob=string().insert(0,100,'Y');
af84dfb5 538
441d41fe
TJ
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;
af84dfb5 544
441d41fe 545 string packet=string(sizetransfer)+blob;
af84dfb5 546
441d41fe
TJ
547 send_raw_socket(packet,&ss,cid);
548 }
af84dfb5
GE
549 }
550 }
441d41fe
TJ
551 } catch(...)
552 {
553 std::cerr << "exception in child. ignoring\n";
af84dfb5
GE
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);