libt2n: (gerd) socket reconnect added (incl. unit tests)
[libt2n] / test / reconnect.cpp
CommitLineData
af84dfb5
GE
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
29using namespace std;
30using namespace libt2n;
31using namespace CppUnit;
32
33// this is an evil hack to get access to real_write, don't ever do this in an app!!!
34class real_write_connection: public socket_server_connection
35{
36 public:
37 void real_write(const std::string& data)
38 { socket_write(data); }
39};
40
41class 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
549CPPUNIT_TEST_SUITE_REGISTRATION(test_reconnect);