libt2n: (reinhard) more compile fixes.
[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
146 public:
147
148 typedef uint32_t packet_size_indicator;
149
150 void setUp()
151 { }
152
153 void tearDown()
154 { }
155
156 void send_hello(string hello_string, socket_server* ss, unsigned int conn_id)
157 {
158 server_connection *sc=ss->get_connection(conn_id);
159 sc->write(hello_string);
160 }
161
162 void send_slow_raw_socket(string data, socket_server* ss, unsigned int conn_id)
163 {
164 socket_server_connection *ssc=dynamic_cast<socket_server_connection*>(ss->get_connection(conn_id));
165
166 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
167 real_write_connection *rwc=(real_write_connection*)ssc;
168
169 // we write one char each 0.2 sec
170 for (int pos=0; pos < data.size(); pos++)
171 {
172 string onebyte;
173 onebyte+=data[pos];
174 rwc->real_write(onebyte);
175 usleep(200000);
176 }
177 }
178
c7857475
GE
179 void ConnectTimeout()
180 {
181 pid_t pid;
182
183 switch(pid=fork())
184 {
185 case -1:
186 {
187 CPPUNIT_FAIL("fork error");
188 break;
189 }
190 case 0:
191 // child
192 {
193 socket_server ss("./socket");
194
195 // don't call atexit and stuff
196 _exit(0);
197 }
198
199 default:
200 // parent
201 {
202 string data;
203
204 // wait till server is up
205 sleep(1);
206
207 string errormsg;
208
209 try
210 {
211 socket_client_connection sc("./socket");
212 command_client cc(sc,1000000,1000000);
213 }
214 catch(t2n_transfer_error &e)
215 { errormsg=e.what(); }
216 catch(...)
217 { throw; }
218
219 CPPUNIT_ASSERT_EQUAL(string("error reading from socket : Invalid argument"),errormsg);
220 }
221 }
222 }
223
45a2ebc9
GE
224 void HelloTimeoutNothing()
225 {
226 pid_t pid;
227
228 switch(pid=fork())
229 {
230 case -1:
231 {
232 CPPUNIT_FAIL("fork error");
233 break;
234 }
235 case 0:
236 // child
237 {
238 socket_server ss("./socket");
239
240 // max 10 sec
241 for (int i=0; i < 10; i++)
242 ss.fill_buffer(1000000);
243 // don't call atexit and stuff
244 _exit(0);
245 }
246
247 default:
248 // parent
249 {
250 string data;
251
252 // wait till server is up
253 sleep(1);
254 socket_client_connection sc("./socket");
255
256 string errormsg;
257
258 try
259 {
260 command_client cc(sc,1000000,1000000);
261 }
262 catch(t2n_transfer_error &e)
263 { errormsg=e.what(); }
264 catch(...)
265 { throw; }
266
267 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
268 }
269 }
270 }
271
272 void HelloTimeoutSlowData()
273 {
274 pid_t pid;
275
276 switch(pid=fork())
277 {
278 case -1:
279 {
280 CPPUNIT_FAIL("fork error");
281 break;
282 }
283 case 0:
284 // child
285 {
286 socket_server ss("./socket");
287
288 // create a valid packet
289 ostringstream hello;
290 hello << "T2Nv" << PROTOCOL_VERSION << ';';
291 int byteordercheck=1;
292 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
293 hello << ';';
294
295 packet_size_indicator psize=htonl(hello.str().size());
296 std::string send_data(hello.str());
297 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
298
299 ss.add_callback(new_connection,bind(&test_timeout::send_slow_raw_socket, boost::ref(*this), send_data,&ss, _1));
300
301 // max 10 sec
302 for (int i=0; i < 10; i++)
303 ss.fill_buffer(1000000);
304 // don't call atexit and stuff
305 _exit(0);
306 }
307
308 default:
309 // parent
310 {
311 string data;
312
313 // wait till server is up
314 sleep(1);
315 socket_client_connection sc("./socket");
316
317 string errormsg;
318
319 try
320 {
321 command_client cc(sc,1000000,1000000);
322 }
323 catch(t2n_transfer_error &e)
324 { errormsg=e.what(); }
325 catch(...)
326 { throw; }
327
328 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
329 }
330 }
331 }
332
333 void CommandTimeout()
334 {
335 pid_t pid;
336
337 switch(pid=fork())
338 {
339 case -1:
340 {
341 CPPUNIT_FAIL("fork error");
342 break;
343 }
344 case 0:
345 // child
346 {
347 socket_server ss("./socket");
348
349 ostringstream hello;
350 hello << "T2Nv" << PROTOCOL_VERSION << ';';
351 int byteordercheck=1;
352 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
353 hello << ';';
354
355 ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1));
356
357 // max 10 sec
358 for (int i=0; i < 10; i++)
359 ss.fill_buffer(1000000);
360 // don't call atexit and stuff
361 _exit(0);
362 }
363
364 default:
365 // parent
366 {
367 string data;
368
369 // wait till server is up
370 sleep(1);
371 socket_client_connection sc("./socket");
372
373 command_client cc(sc,1000000,1000000);
374 result_container rc;
375
376 string errormsg;
377
378 try
379 {
380 cc.send_command(new testfunc2_cmd("hello"),rc);
381 }
382 catch(t2n_transfer_error &e)
383 { errormsg=e.what(); }
384 catch(...)
385 { throw; }
386
387 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
388 }
389 }
390 }
391
392 void CommandSlowResponse()
393 {
394 pid_t pid;
395
396 switch(pid=fork())
397 {
398 case -1:
399 {
400 CPPUNIT_FAIL("fork error");
401 break;
402 }
403 case 0:
404 // child
405 {
406 socket_server ss("./socket");
407
408 ostringstream hello;
409 hello << "T2Nv" << PROTOCOL_VERSION << ';';
410 int byteordercheck=1;
411 hello.write((char*)&byteordercheck,sizeof(byteordercheck));
412 hello << ';';
413
414 ss.add_callback(new_connection,bind(&test_timeout::send_hello, boost::ref(*this), hello.str(),&ss, _1));
415
416 // max 10 sec
417 for (int i=0; i < 10; i++)
418 {
419 ss.fill_buffer(1000000);
420
421 string data;
422 unsigned int cid;
423
424 if(ss.get_packet(data,cid))
425 {
426 // create a valid packet & send
427 string response="abcdefghijklmnopqrstuvwxyz";
428 packet_size_indicator psize=htonl(response.size());
429 std::string send_data(response);
430 send_data.insert(0,(char*)&psize,sizeof(packet_size_indicator));
431 send_slow_raw_socket(send_data,&ss,cid);
432 }
433 }
434 // don't call atexit and stuff
435 _exit(0);
436 }
437
438 default:
439 // parent
440 {
441 string data;
442
443 // wait till server is up
444 sleep(1);
445 socket_client_connection sc("./socket");
446
447 command_client cc(sc,1000000,1000000);
448 result_container rc;
449
450 string errormsg;
451
452 try
453 {
454 cc.send_command(new testfunc2_cmd("hello"),rc);
455 }
456 catch(t2n_transfer_error &e)
457 { errormsg=e.what(); }
458 catch(...)
459 { throw; }
460
461 CPPUNIT_ASSERT_EQUAL(string("timeout exceeded"),errormsg);
462 }
463 }
464 }
465
c7857475
GE
466 void DisconnectOnWrite()
467 {
468 pid_t pid;
469
470 switch(pid=fork())
471 {
472 case -1:
473 {
474 CPPUNIT_FAIL("fork error");
475 break;
476 }
477 case 0:
478 // child
479 {
480 socket_server ss("./socket");
481
482 // bail out as soon as we get something
483 ss.fill_buffer(-1);
484 // don't call atexit and stuff
485 _exit(0);
486 }
487
488 default:
489 // parent
490 {
491 string data;
492
493 // don't kill us on broken pipe
494 signal(SIGPIPE, SIG_IGN);
495
496 // wait till server is up
497 sleep(1);
498 socket_client_connection sc("./socket");
499
500 string errormsg;
501
502 string huge(1000000,'x');
503
504 try
505 {
506 sc.write(huge);
507 }
508 catch(t2n_transfer_error &e)
509 { errormsg=e.what(); }
510 catch(...)
511 { throw; }
512
513 CPPUNIT_ASSERT_EQUAL(string("write() returned Broken pipe"),errormsg);
514 }
515 }
516 }
517
518 void DisconnectOnRead()
519 {
520 pid_t pid;
521
522 switch(pid=fork())
523 {
524 case -1:
525 {
526 CPPUNIT_FAIL("fork error");
527 break;
528 }
529 case 0:
530 // child
531 {
532 // wait till server is up
533 sleep(1);
534
535 socket_client_connection sc("./socket");
536
537 // this is an evil hack to get access to real_write, don't ever do this in an app!!!
538 real_write_client_connection *rwc=(real_write_client_connection*)&sc;
539 rwc->real_write(string(10000,'x'));
540
541 // don't call atexit and stuff
542 _exit(0);
543 }
544
545 default:
546 // parent
547 {
548 // don't kill us on broken pipe
549 signal(SIGPIPE, SIG_IGN);
550
551 socket_server ss("./socket");
552
553 time_t t0 = time(NULL);
554
555 // max 5 sec
556 while (time(NULL) < t0 + 5 )
557 {
558 ss.fill_buffer(1000000);
559
560 string data;
561 ss.get_packet(data);
562 }
563
564 // are we still alive and able to process data?
565
566 switch(pid=fork())
567 {
568 case -1:
569 {
570 CPPUNIT_FAIL("fork error");
571 break;
572 }
573 case 0:
574 // child
575 {
576 socket_client_connection *sc=new socket_client_connection("./socket");
577 sc->write(string(10000,'x'));
578 delete sc;
579 // socket is closed regularly
580
581 // don't run regular cleanup, otherwise cppunit stuff gets called
582 _exit(0);
583 }
584
585 default:
586 // parent
587 {
588 string received;
589
590 t0 = time(NULL);
591
592 // max 10 sec
593 while (time(NULL) < t0 + 10 )
594 {
595 ss.fill_buffer(1000000);
596
597 if (ss.get_packet(received))
598 break;
599 }
600
601 CPPUNIT_ASSERT_EQUAL(string(10000,'x'),received);
602 }
603 }
604 }
605 }
606 }
607
608 void BreakAccept()
609 {
610 pid_t pid;
611
612 switch(pid=fork())
613 {
614 case -1:
615 {
616 CPPUNIT_FAIL("fork error");
617 break;
618 }
619 case 0:
620 // child
621 {
622 // wait till server is really up and waiting
623 sleep(2);
624
625 // connect with very tight timeout and only 1 retry
626 socket_client_connection sc("./socket",50,1);
627
628 // don't call atexit and stuff
629 _exit(0);
630 }
631
632 default:
633 // parent
634 {
635 // don't kill us on broken pipe
636 signal(SIGPIPE, SIG_IGN);
637
638 socket_server ss("./socket");
639
640 // server is "working" while client wants to connect
641 sleep(5);
642
643 time_t t0 = time(NULL);
644
645 // max 5 sec
646 while (time(NULL) < t0 + 5 )
647 {
648 ss.fill_buffer(1000000);
649
650 string data;
651 ss.get_packet(data);
652 }
653
654 // are we still alive and able to process data?
655
656 switch(pid=fork())
657 {
658 case -1:
659 {
660 CPPUNIT_FAIL("fork error");
661 break;
662 }
663 case 0:
664 // child
665 {
666 socket_client_connection *sc=new socket_client_connection("./socket");
667 sc->write(string(10000,'x'));
668 delete sc;
669 // socket is closed regularly
670
671 // don't run regular cleanup, otherwise cppunit stuff gets called
672 _exit(0);
673 }
674
675 default:
676 // parent
677 {
678 string received;
679
680 t0 = time(NULL);
681
682 // max 10 sec
683 while (time(NULL) < t0 + 10 )
684 {
685 ss.fill_buffer(1000000);
686
687 if (ss.get_packet(received))
688 break;
689 }
690
691 CPPUNIT_ASSERT_EQUAL(string(10000,'x'),received);
692 }
693 }
694 }
695 }
696 }
45a2ebc9
GE
697};
698
699CPPUNIT_TEST_SUITE_REGISTRATION(test_timeout);