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