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