libt2n, arnied: (gerd) set logging on existing connections too, show t2n-debugging...
[libt2n] / test / timeout.cpp
CommitLineData
45a2ebc9
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 <boost/bind.hpp>
19
20#include <cppunit/extensions/TestFactoryRegistry.h>
21#include <cppunit/ui/text/TestRunner.h>
22#include <cppunit/extensions/HelperMacros.h>
23
24#include <boost/archive/binary_oarchive.hpp>
25#include <boost/archive/binary_iarchive.hpp>
26#include <boost/archive/xml_oarchive.hpp>
27#include <boost/archive/xml_iarchive.hpp>
28#include <boost/serialization/serialization.hpp>
29
30#include <container.hxx>
31#include <socket_client.hxx>
32#include <socket_server.hxx>
33#include <command_client.hxx>
34#include <command_server.hxx>
35
36#ifdef HAVE_CONFIG_H
37#include <config.h>
38#endif
39
40using namespace std;
41using namespace libt2n;
42using namespace CppUnit;
43
44string testfunc2(const string& str)
45{
46 if (str=="throw")
47 throw libt2n::t2n_runtime_error("throw me around");
48 string ret(str);
49 ret+=", testfunc() was here";
50 return ret;
51}
52
53class testfunc2_res : public libt2n::result
54{
55 private:
56 string res;
57
58 friend class boost::serialization::access;
59 template<class Archive>
60 void serialize(Archive & ar, const unsigned int version)
61 {
62 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
63 ar & BOOST_SERIALIZATION_NVP(res);
64 }
65
66 public:
67 testfunc2_res()
68 { }
69
70 testfunc2_res(const string& str)
71 {
72 res=str;
73 }
74
75 string get_data()
76 {
77 return res;
78 }
79};
80
81
82class testfunc2_cmd : public libt2n::command
83{
84 private:
85 string param;
86
87 friend class boost::serialization::access;
88 template<class Archive>
89 void serialize(Archive & ar, const unsigned int version)
90 {
91 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
92 ar & BOOST_SERIALIZATION_NVP(param);
93 }
94
95 public:
96 testfunc2_cmd()
97 { }
98
99 testfunc2_cmd(const string& str)
100 {
101 param=str;
102 }
103
104 libt2n::result* operator()()
105 {
106 return new testfunc2_res(testfunc2(param));
107 }
108};
109
110#include <boost/serialization/export.hpp>
111
112BOOST_CLASS_EXPORT(testfunc2_cmd)
113BOOST_CLASS_EXPORT(testfunc2_res)
114
115// this is an evil hack to get access to real_write, don't ever do this in an app!!!
116class real_write_connection: public socket_server_connection
117{
118 public:
119 void real_write(const std::string& data)
120 { socket_write(data); }
121};
122
c7857475
GE
123// this is an evil hack to get access to real_write, don't ever do this in an app!!!
124class real_write_client_connection: public socket_client_connection
125{
126 public:
127 void real_write(const std::string& data)
128 { socket_write(data); }
129};
130
45a2ebc9
GE
131class test_timeout : public TestFixture
132{
133 CPPUNIT_TEST_SUITE(test_timeout);
134
c7857475 135 CPPUNIT_TEST(ConnectTimeout);
45a2ebc9
GE
136 CPPUNIT_TEST(HelloTimeoutNothing);
137 CPPUNIT_TEST(HelloTimeoutSlowData);
138 CPPUNIT_TEST(CommandTimeout);
139 CPPUNIT_TEST(CommandSlowResponse);
c7857475
GE
140 CPPUNIT_TEST(DisconnectOnWrite);
141 CPPUNIT_TEST(DisconnectOnRead);
142 CPPUNIT_TEST(BreakAccept);
45a2ebc9
GE
143
144 CPPUNIT_TEST_SUITE_END();
145
b5922184
GE
146 pid_t child_pid;
147
45a2ebc9
GE
148 public:
149
150 typedef uint32_t packet_size_indicator;
151
152 void setUp()
153 { }
154
155 void tearDown()
b5922184
GE
156 {
157 // make sure the server-child is dead before the next test runs
158 kill(child_pid,SIGKILL);
159 sleep(1);
160 }
45a2ebc9
GE
161
162 void send_hello(string hello_string, socket_server* ss, unsigned int conn_id)
163 {
164 server_connection *sc=ss->get_connection(conn_id);
165 sc->write(hello_string);
166 }
167
168 void send_slow_raw_socket(string data, socket_server* ss, unsigned int conn_id)
169 {
170 socket_server_connection *ssc=dynamic_cast<socket_server_connection*>(ss->get_connection(conn_id));
171
172 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
173 real_write_connection *rwc=(real_write_connection*)ssc;
174
175 // we write one char each 0.2 sec
176 for (int pos=0; pos < data.size(); pos++)
177 {
178 string onebyte;
179 onebyte+=data[pos];
180 rwc->real_write(onebyte);
181 usleep(200000);
182 }
183 }
184
c7857475
GE
185 void ConnectTimeout()
186 {
b5922184 187 switch(child_pid=fork())
c7857475
GE
188 {
189 case -1:
190 {
191 CPPUNIT_FAIL("fork error");
192 break;
193 }
194 case 0:
195 // child
196 {
197 socket_server ss("./socket");
198
199 // don't call atexit and stuff
200 _exit(0);
201 }
202
203 default:
204 // parent
205 {
206 string data;
207
208 // wait till server is up
209 sleep(1);
210
211 string errormsg;
212
fb3345ad 213 socket_client_connection sc("./socket");
c7857475 214
b5922184
GE
215 CPPUNIT_ASSERT_EQUAL_MESSAGE("connection not closed",true,sc.connection::is_closed());
216
217 CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong errormessage",string("no more retries left after connect error"),sc.get_last_error_msg());
c7857475
GE
218 }
219 }
220 }
221
45a2ebc9
GE
222 void HelloTimeoutNothing()
223 {
b5922184 224 switch(child_pid=fork())
45a2ebc9
GE
225 {
226 case -1:
227 {
228 CPPUNIT_FAIL("fork error");
229 break;
230 }
231 case 0:
232 // child
233 {
234 socket_server ss("./socket");
235
236 // max 10 sec
237 for (int i=0; i < 10; i++)
238 ss.fill_buffer(1000000);
239 // don't call atexit and stuff
240 _exit(0);
241 }
242
243 default:
244 // parent
245 {
246 string data;
247
248 // wait till server is up
249 sleep(1);
250 socket_client_connection sc("./socket");
b5922184 251 command_client cc(&sc,1000000,1000000);
45a2ebc9 252
b5922184 253 t2n_exception* ep=cc.get_constuctor_exception();
45a2ebc9 254
b5922184
GE
255 string errormsg;
256 if (ep)
257 errormsg=ep->what();
45a2ebc9
GE
258
259 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
260 }
261 }
262 }
263
264 void HelloTimeoutSlowData()
265 {
b5922184 266 switch(child_pid=fork())
45a2ebc9
GE
267 {
268 case -1:
269 {
270 CPPUNIT_FAIL("fork error");
271 break;
272 }
273 case 0:
274 // child
275 {
276 socket_server ss("./socket");
277
278 // create a valid packet
279 ostringstream hello;
280 hello << "T2Nv" << PROTOCOL_VERSION << ';';
281 int byteordercheck=1;
282 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
283 hello << ';';
284
285 packet_size_indicator psize=htonl(hello.str().size());
286 std::string send_data(hello.str());
287 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
288
289 ss.add_callback(new_connection,bind(&test_timeout::send_slow_raw_socket, boost::ref(*this), send_data,&ss, _1));
290
291 // max 10 sec
292 for (int i=0; i < 10; i++)
293 ss.fill_buffer(1000000);
294 // don't call atexit and stuff
295 _exit(0);
296 }
297
298 default:
299 // parent
300 {
301 string data;
302
303 // wait till server is up
304 sleep(1);
305 socket_client_connection sc("./socket");
b5922184 306 command_client cc(&sc,1000000,1000000);
45a2ebc9 307
b5922184 308 t2n_exception* ep=cc.get_constuctor_exception();
45a2ebc9 309
b5922184
GE
310 string errormsg;
311 if (ep)
312 errormsg=ep->what();
45a2ebc9
GE
313
314 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
315 }
316 }
317 }
318
319 void CommandTimeout()
320 {
b5922184 321 switch(child_pid=fork())
45a2ebc9
GE
322 {
323 case -1:
324 {
325 CPPUNIT_FAIL("fork error");
326 break;
327 }
328 case 0:
329 // child
330 {
331 socket_server ss("./socket");
332
333 ostringstream hello;
334 hello << "T2Nv" << PROTOCOL_VERSION << ';';
335 int byteordercheck=1;
336 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
337 hello << ';';
338
339 ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1));
340
341 // max 10 sec
342 for (int i=0; i < 10; i++)
343 ss.fill_buffer(1000000);
344 // don't call atexit and stuff
345 _exit(0);
346 }
347
348 default:
349 // parent
350 {
351 string data;
352
353 // wait till server is up
354 sleep(1);
355 socket_client_connection sc("./socket");
356
fb3345ad 357 command_client cc(&sc,1000000,1000000);
45a2ebc9
GE
358 result_container rc;
359
360 string errormsg;
361
362 try
363 {
364 cc.send_command(new testfunc2_cmd("hello"),rc);
365 }
366 catch(t2n_transfer_error &e)
367 { errormsg=e.what(); }
368 catch(...)
369 { throw; }
370
371 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
372 }
373 }
374 }
375
376 void CommandSlowResponse()
377 {
b5922184 378 switch(child_pid=fork())
45a2ebc9
GE
379 {
380 case -1:
381 {
382 CPPUNIT_FAIL("fork error");
383 break;
384 }
385 case 0:
386 // child
387 {
388 socket_server ss("./socket");
389
390 ostringstream hello;
391 hello << "T2Nv" << PROTOCOL_VERSION << ';';
392 int byteordercheck=1;
393 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
394 hello << ';';
395
396 ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1));
397
398 // max 10 sec
399 for (int i=0; i < 10; i++)
400 {
401 ss.fill_buffer(1000000);
402
403 string data;
404 unsigned int cid;
405
406 if(ss.get_packet(data,cid))
407 {
408 // create a valid packet & send
409 string response="abcdefghijklmnopqrstuvwxyz";
410 packet_size_indicator psize=htonl(response.size());
411 std::string send_data(response);
412 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
413 send_slow_raw_socket(send_data,&ss,cid);
414 }
415 }
416 // don't call atexit and stuff
417 _exit(0);
418 }
419
420 default:
421 // parent
422 {
423 string data;
424
425 // wait till server is up
426 sleep(1);
427 socket_client_connection sc("./socket");
428
fb3345ad 429 command_client cc(&sc,1000000,1000000);
45a2ebc9
GE
430 result_container rc;
431
432 string errormsg;
433
434 try
435 {
436 cc.send_command(new testfunc2_cmd("hello"),rc);
437 }
438 catch(t2n_transfer_error &e)
439 { errormsg=e.what(); }
440 catch(...)
441 { throw; }
442
443 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
444 }
445 }
446 }
447
c7857475
GE
448 void DisconnectOnWrite()
449 {
b5922184 450 switch(child_pid=fork())
c7857475
GE
451 {
452 case -1:
453 {
454 CPPUNIT_FAIL("fork error");
455 break;
456 }
457 case 0:
458 // child
459 {
460 socket_server ss("./socket");
461
462 // bail out as soon as we get something
463 ss.fill_buffer(-1);
464 // don't call atexit and stuff
465 _exit(0);
466 }
467
468 default:
469 // parent
470 {
471 string data;
472
473 // don't kill us on broken pipe
474 signal(SIGPIPE, SIG_IGN);
475
476 // wait till server is up
477 sleep(1);
478 socket_client_connection sc("./socket");
479
480 string errormsg;
481
482 string huge(1000000,'x');
483
484 try
485 {
486 sc.write(huge);
487 }
488 catch(t2n_transfer_error &e)
489 { errormsg=e.what(); }
490 catch(...)
491 { throw; }
492
493 CPPUNIT_ASSERT_EQUAL(string("write() returned Broken pipe"),errormsg);
494 }
495 }
496 }
497
498 void DisconnectOnRead()
499 {
b5922184 500 pid_t pid2;
c7857475 501
b5922184 502 switch(child_pid=fork())
c7857475
GE
503 {
504 case -1:
505 {
506 CPPUNIT_FAIL("fork error");
507 break;
508 }
509 case 0:
510 // child
511 {
512 // wait till server is up
513 sleep(1);
514
515 socket_client_connection sc("./socket");
516
517 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
518 real_write_client_connection *rwc=(real_write_client_connection*)&sc;
519 rwc->real_write(string(10000,'x'));
520
521 // don't call atexit and stuff
522 _exit(0);
523 }
524
525 default:
526 // parent
527 {
528 // don't kill us on broken pipe
529 signal(SIGPIPE, SIG_IGN);
530
531 socket_server ss("./socket");
532
533 time_t t0 = time(NULL);
534
535 // max 5 sec
536 while (time(NULL) < t0 + 5 )
537 {
538 ss.fill_buffer(1000000);
539
540 string data;
541 ss.get_packet(data);
542 }
543
544 // are we still alive and able to process data?
545
fb3345ad 546 switch(pid2=fork())
c7857475
GE
547 {
548 case -1:
549 {
550 CPPUNIT_FAIL("fork error");
551 break;
552 }
553 case 0:
554 // child
555 {
556 socket_client_connection *sc=new socket_client_connection("./socket");
557 sc->write(string(10000,'x'));
558 delete sc;
559 // socket is closed regularly
560
561 // don't run regular cleanup, otherwise cppunit stuff gets called
562 _exit(0);
563 }
564
565 default:
566 // parent
567 {
568 string received;
569
570 t0 = time(NULL);
571
572 // max 10 sec
573 while (time(NULL) < t0 + 10 )
574 {
575 ss.fill_buffer(1000000);
576
577 if (ss.get_packet(received))
578 break;
579 }
580
581 CPPUNIT_ASSERT_EQUAL(string(10000,'x'),received);
582 }
583 }
584 }
585 }
fb3345ad 586 kill(pid2,SIGKILL);
c7857475
GE
587 }
588
589 void BreakAccept()
590 {
b5922184 591 pid_t pid2;
c7857475 592
b5922184 593 switch(child_pid=fork())
c7857475
GE
594 {
595 case -1:
596 {
597 CPPUNIT_FAIL("fork error");
598 break;
599 }
600 case 0:
601 // child
602 {
603 // wait till server is really up and waiting
604 sleep(2);
605
606 // connect with very tight timeout and only 1 retry
607 socket_client_connection sc("./socket",50,1);
608
609 // don't call atexit and stuff
610 _exit(0);
611 }
612
613 default:
614 // parent
615 {
616 // don't kill us on broken pipe
617 signal(SIGPIPE, SIG_IGN);
618
619 socket_server ss("./socket");
620
621 // server is "working" while client wants to connect
622 sleep(5);
623
624 time_t t0 = time(NULL);
625
626 // max 5 sec
627 while (time(NULL) < t0 + 5 )
628 {
629 ss.fill_buffer(1000000);
630
631 string data;
632 ss.get_packet(data);
633 }
634
635 // are we still alive and able to process data?
636
fb3345ad 637 switch(pid2=fork())
c7857475
GE
638 {
639 case -1:
640 {
641 CPPUNIT_FAIL("fork error");
642 break;
643 }
644 case 0:
645 // child
646 {
647 socket_client_connection *sc=new socket_client_connection("./socket");
648 sc->write(string(10000,'x'));
649 delete sc;
650 // socket is closed regularly
651
652 // don't run regular cleanup, otherwise cppunit stuff gets called
653 _exit(0);
654 }
655
656 default:
657 // parent
658 {
659 string received;
660
661 t0 = time(NULL);
662
663 // max 10 sec
664 while (time(NULL) < t0 + 10 )
665 {
666 ss.fill_buffer(1000000);
667
668 if (ss.get_packet(received))
669 break;
670 }
671
672 CPPUNIT_ASSERT_EQUAL(string(10000,'x'),received);
673 }
674 }
675 }
676 }
fb3345ad 677 kill(pid2,SIGKILL);
c7857475 678 }
45a2ebc9
GE
679};
680
681CPPUNIT_TEST_SUITE_REGISTRATION(test_timeout);