Commit | Line | Data |
---|---|---|
19facd85 TJ |
1 | /* |
2 | Copyright (C) 2004 by Intra2net AG | |
af84dfb5 | 3 | |
19facd85 TJ |
4 | The software in this package is distributed under the GNU General |
5 | Public License version 2 (with a special exception described below). | |
6 | ||
7 | A copy of GNU General Public License (GPL) is included in this distribution, | |
8 | in the file COPYING.GPL. | |
9 | ||
10 | As a special exception, if other files instantiate templates or use macros | |
11 | or inline functions from this file, or you compile this file and link it | |
12 | with other works to produce a work based on this file, this file | |
13 | does not by itself cause the resulting work to be covered | |
14 | by the GNU General Public License. | |
15 | ||
16 | However the source code for this file must still be made available | |
17 | in accordance with section (3) of the GNU General Public License. | |
18 | ||
19 | This exception does not invalidate any other reasons why a work based | |
20 | on this file might be covered by the GNU General Public License. | |
21 | */ | |
af84dfb5 GE |
22 | #include <sys/types.h> |
23 | #include <unistd.h> | |
24 | #include <errno.h> | |
25 | #include <signal.h> | |
26 | #include <stdio.h> | |
4c3662a0 | 27 | #include <time.h> |
af84dfb5 GE |
28 | |
29 | #include <iostream> | |
30 | #include <string> | |
31 | #include <sstream> | |
32 | #include <stdexcept> | |
33 | ||
307b5e74 TJ |
34 | #define BOOST_TEST_DYN_LINK |
35 | #include <boost/test/unit_test.hpp> | |
af84dfb5 GE |
36 | |
37 | #include <socket_client.hxx> | |
38 | #include <socket_server.hxx> | |
39 | ||
307b5e74 TJ |
40 | #include "test_fixtures.hxx" |
41 | ||
af84dfb5 | 42 | #include <config.h> |
af84dfb5 GE |
43 | |
44 | using namespace std; | |
45 | using namespace libt2n; | |
af84dfb5 | 46 | |
df94ded3 | 47 | BOOST_FIXTURE_TEST_SUITE(test_reconnect, KillChildOnShutdownFixture) |
307b5e74 TJ |
48 | |
49 | BOOST_AUTO_TEST_CASE(simple_reconnect) | |
50 | { | |
51 | switch(child_pid=fork()) | |
52 | { | |
53 | case -1: | |
af84dfb5 | 54 | { |
307b5e74 TJ |
55 | BOOST_FAIL("fork error"); |
56 | break; | |
57 | } | |
58 | case 0: | |
59 | // child | |
60 | { | |
61 | try | |
af84dfb5 | 62 | { |
307b5e74 | 63 | socket_server ss("./socket"); |
af84dfb5 | 64 | |
307b5e74 | 65 | time_t t0 = time(NULL); |
af84dfb5 | 66 | |
307b5e74 TJ |
67 | // max 10 sec |
68 | while (time(NULL) < t0 + 10 ) | |
69 | { | |
70 | ss.fill_buffer(1000000); | |
441d41fe | 71 | |
307b5e74 TJ |
72 | string data; |
73 | unsigned int cid; | |
441d41fe | 74 | |
307b5e74 TJ |
75 | if(ss.get_packet(data,cid)) |
76 | { | |
77 | server_connection* con=ss.get_connection(cid); | |
af84dfb5 | 78 | |
307b5e74 TJ |
79 | if (data=="QUIT") |
80 | break; | |
af84dfb5 | 81 | |
307b5e74 TJ |
82 | if (data=="x") |
83 | con->write(string().insert(0,100,'X')); | |
84 | else | |
85 | con->write(string().insert(0,100,'Y')); | |
af84dfb5 GE |
86 | } |
87 | } | |
307b5e74 TJ |
88 | } catch(...) |
89 | { | |
90 | std::cerr << "exception in child. ignoring\n"; | |
af84dfb5 GE |
91 | } |
92 | ||
307b5e74 TJ |
93 | // don't call atexit and stuff |
94 | _exit(0); | |
95 | } | |
af84dfb5 | 96 | |
307b5e74 TJ |
97 | default: |
98 | // parent | |
99 | { | |
100 | // don't kill us on broken pipe | |
101 | signal(SIGPIPE, SIG_IGN); | |
af84dfb5 | 102 | |
307b5e74 TJ |
103 | // wait till server is up |
104 | sleep(1); | |
105 | socket_client_connection sc("./socket"); | |
af84dfb5 | 106 | |
307b5e74 | 107 | sc.write("abc"); |
af84dfb5 | 108 | |
307b5e74 | 109 | string data; |
af84dfb5 | 110 | |
307b5e74 TJ |
111 | while (!sc.get_packet(data)) |
112 | sc.fill_buffer(1000000); | |
af84dfb5 | 113 | |
307b5e74 | 114 | sc.reconnect(); |
af84dfb5 | 115 | |
307b5e74 | 116 | sc.write("x"); |
af84dfb5 | 117 | |
307b5e74 TJ |
118 | while (!sc.get_packet(data)) |
119 | sc.fill_buffer(1000000); | |
120 | ||
121 | BOOST_CHECK_EQUAL(string().insert(0,100,'X'),data); | |
af84dfb5 GE |
122 | } |
123 | } | |
307b5e74 | 124 | } |
af84dfb5 | 125 | |
307b5e74 TJ |
126 | BOOST_AUTO_TEST_CASE(reconnect_with_close) |
127 | { | |
128 | switch(child_pid=fork()) | |
af84dfb5 | 129 | { |
307b5e74 | 130 | case -1: |
af84dfb5 | 131 | { |
307b5e74 TJ |
132 | BOOST_FAIL("fork error"); |
133 | break; | |
134 | } | |
135 | case 0: | |
136 | // child | |
137 | { | |
138 | try | |
af84dfb5 | 139 | { |
307b5e74 | 140 | socket_server ss("./socket"); |
af84dfb5 | 141 | |
307b5e74 | 142 | time_t t0 = time(NULL); |
af84dfb5 | 143 | |
307b5e74 TJ |
144 | // max 10 sec |
145 | while (time(NULL) < t0 + 10 ) | |
146 | { | |
147 | ss.fill_buffer(1000000); | |
af84dfb5 | 148 | |
307b5e74 TJ |
149 | string data; |
150 | unsigned int cid; | |
af84dfb5 | 151 | |
307b5e74 TJ |
152 | if(ss.get_packet(data,cid)) |
153 | { | |
154 | server_connection* con=ss.get_connection(cid); | |
441d41fe | 155 | |
307b5e74 TJ |
156 | if (data=="QUIT") |
157 | break; | |
441d41fe | 158 | |
307b5e74 TJ |
159 | if (data=="x") |
160 | con->write(string().insert(0,100,'X')); | |
161 | else | |
162 | con->write(string().insert(0,100,'Y')); | |
af84dfb5 GE |
163 | } |
164 | } | |
307b5e74 TJ |
165 | } catch(...) |
166 | { | |
167 | std::cerr << "exception in child. ignoring\n"; | |
af84dfb5 GE |
168 | } |
169 | ||
307b5e74 TJ |
170 | // don't call atexit and stuff |
171 | _exit(0); | |
172 | } | |
af84dfb5 | 173 | |
307b5e74 TJ |
174 | default: |
175 | // parent | |
176 | { | |
177 | // don't kill us on broken pipe | |
178 | signal(SIGPIPE, SIG_IGN); | |
af84dfb5 | 179 | |
307b5e74 TJ |
180 | // wait till server is up |
181 | sleep(1); | |
182 | socket_client_connection sc("./socket"); | |
af84dfb5 | 183 | |
307b5e74 | 184 | sc.write("abc"); |
af84dfb5 | 185 | |
307b5e74 | 186 | string data; |
af84dfb5 | 187 | |
307b5e74 TJ |
188 | while (!sc.get_packet(data)) |
189 | sc.fill_buffer(1000000); | |
af84dfb5 | 190 | |
307b5e74 | 191 | sc.close(); |
af84dfb5 | 192 | |
307b5e74 TJ |
193 | // empty buffer |
194 | sc.get_packet(data); | |
af84dfb5 | 195 | |
307b5e74 | 196 | sc.reconnect(); |
af84dfb5 | 197 | |
307b5e74 | 198 | sc.write("x"); |
af84dfb5 | 199 | |
307b5e74 TJ |
200 | while (!sc.get_packet(data)) |
201 | sc.fill_buffer(1000000); | |
202 | ||
203 | BOOST_CHECK_EQUAL(string().insert(0,100,'X'),data); | |
af84dfb5 GE |
204 | } |
205 | } | |
307b5e74 | 206 | } |
af84dfb5 | 207 | |
307b5e74 TJ |
208 | BOOST_AUTO_TEST_CASE(reconnect_buffer_complete) |
209 | { | |
210 | switch(child_pid=fork()) | |
af84dfb5 | 211 | { |
307b5e74 | 212 | case -1: |
af84dfb5 | 213 | { |
307b5e74 TJ |
214 | BOOST_FAIL("fork error"); |
215 | break; | |
216 | } | |
217 | case 0: | |
218 | // child | |
219 | { | |
220 | try | |
af84dfb5 | 221 | { |
307b5e74 | 222 | socket_server ss("./socket"); |
af84dfb5 | 223 | |
307b5e74 | 224 | time_t t0 = time(NULL); |
af84dfb5 | 225 | |
307b5e74 TJ |
226 | // max 10 sec |
227 | while (time(NULL) < t0 + 10 ) | |
228 | { | |
229 | ss.fill_buffer(1000000); | |
441d41fe | 230 | |
307b5e74 TJ |
231 | string data; |
232 | unsigned int cid; | |
441d41fe | 233 | |
307b5e74 TJ |
234 | if(ss.get_packet(data,cid)) |
235 | { | |
236 | server_connection* con=ss.get_connection(cid); | |
af84dfb5 | 237 | |
307b5e74 TJ |
238 | if (data=="QUIT") |
239 | break; | |
af84dfb5 | 240 | |
307b5e74 TJ |
241 | if (data=="x") |
242 | con->write(string().insert(0,100,'X')); | |
af84dfb5 GE |
243 | } |
244 | } | |
307b5e74 TJ |
245 | } catch(...) |
246 | { | |
247 | std::cerr << "exception in child. ignoring\n"; | |
af84dfb5 GE |
248 | } |
249 | ||
307b5e74 TJ |
250 | // don't call atexit and stuff |
251 | _exit(0); | |
252 | } | |
af84dfb5 | 253 | |
307b5e74 TJ |
254 | default: |
255 | // parent | |
256 | { | |
257 | // don't kill us on broken pipe | |
258 | signal(SIGPIPE, SIG_IGN); | |
af84dfb5 | 259 | |
307b5e74 TJ |
260 | // wait till server is up |
261 | sleep(1); | |
262 | socket_client_connection sc("./socket"); | |
af84dfb5 | 263 | |
307b5e74 | 264 | sc.write("x"); |
af84dfb5 | 265 | |
307b5e74 | 266 | string data; |
af84dfb5 | 267 | |
307b5e74 TJ |
268 | while (!sc.packet_available()) |
269 | sc.fill_buffer(1000000); | |
af84dfb5 | 270 | |
307b5e74 | 271 | sc.reconnect(); |
af84dfb5 | 272 | |
307b5e74 TJ |
273 | BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, "packet not there"); |
274 | ||
275 | BOOST_CHECK_MESSAGE(data == string().insert(0,100,'X'), "data incorrect"); | |
af84dfb5 GE |
276 | } |
277 | } | |
307b5e74 | 278 | } |
af84dfb5 | 279 | |
307b5e74 TJ |
280 | BOOST_AUTO_TEST_CASE(reconnect_buffer_several_complete) |
281 | { | |
282 | const int packets=3; | |
af84dfb5 | 283 | |
307b5e74 TJ |
284 | switch(child_pid=fork()) |
285 | { | |
286 | case -1: | |
af84dfb5 | 287 | { |
307b5e74 TJ |
288 | BOOST_FAIL("fork error"); |
289 | break; | |
290 | } | |
291 | case 0: | |
292 | // child | |
293 | { | |
294 | try | |
af84dfb5 | 295 | { |
307b5e74 TJ |
296 | socket_server ss("./socket"); |
297 | ||
298 | time_t t0 = time(NULL); | |
299 | ||
300 | // max 10 sec | |
301 | while (time(NULL) < t0 + 10 ) | |
af84dfb5 | 302 | { |
307b5e74 | 303 | ss.fill_buffer(1000000); |
af84dfb5 | 304 | |
307b5e74 TJ |
305 | string data; |
306 | unsigned int cid; | |
af84dfb5 | 307 | |
307b5e74 | 308 | if(ss.get_packet(data,cid)) |
af84dfb5 | 309 | { |
307b5e74 | 310 | server_connection* con=ss.get_connection(cid); |
af84dfb5 | 311 | |
307b5e74 TJ |
312 | if (data=="QUIT") |
313 | break; | |
af84dfb5 | 314 | |
307b5e74 | 315 | if (data=="x") |
af84dfb5 | 316 | { |
307b5e74 TJ |
317 | for (int i=0; i<packets; i++) |
318 | con->write(string().insert(0,100,'X')); | |
af84dfb5 GE |
319 | } |
320 | } | |
321 | } | |
307b5e74 TJ |
322 | } catch(...) |
323 | { | |
324 | std::cerr << "exception in child. ignoring\n"; | |
af84dfb5 GE |
325 | } |
326 | ||
307b5e74 TJ |
327 | // don't call atexit and stuff |
328 | _exit(0); | |
329 | } | |
af84dfb5 | 330 | |
307b5e74 TJ |
331 | default: |
332 | // parent | |
333 | { | |
334 | // don't kill us on broken pipe | |
335 | signal(SIGPIPE, SIG_IGN); | |
af84dfb5 | 336 | |
307b5e74 TJ |
337 | // wait till server is up |
338 | sleep(1); | |
339 | socket_client_connection sc("./socket"); | |
af84dfb5 | 340 | |
307b5e74 | 341 | sc.write("x"); |
af84dfb5 | 342 | |
307b5e74 TJ |
343 | // retrieve packets for 3 seconds |
344 | time_t t0 = time(NULL); | |
af84dfb5 | 345 | |
307b5e74 TJ |
346 | // max 3 sec |
347 | while (time(NULL) < t0 + 3 ) | |
348 | sc.fill_buffer(1000000); | |
af84dfb5 | 349 | |
307b5e74 | 350 | // we now should have packets complete packets in the buffer |
af84dfb5 | 351 | |
307b5e74 | 352 | sc.reconnect(); |
af84dfb5 | 353 | |
307b5e74 | 354 | // are these packets still there? |
af84dfb5 | 355 | |
307b5e74 TJ |
356 | for (int i=0; i < packets; i++) |
357 | { | |
358 | string data; | |
af84dfb5 | 359 | |
307b5e74 TJ |
360 | ostringstream os; |
361 | os << "packet " << i << " not there"; | |
af84dfb5 | 362 | |
307b5e74 | 363 | BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, os.str()); |
af84dfb5 | 364 | |
307b5e74 TJ |
365 | os.str(""); |
366 | os << "packet " << i << " incorrect"; | |
367 | ||
368 | BOOST_CHECK_MESSAGE(string().insert(0,100,'X') == data, os.str()); | |
af84dfb5 GE |
369 | } |
370 | } | |
371 | } | |
307b5e74 | 372 | } |
af84dfb5 | 373 | |
307b5e74 TJ |
374 | BOOST_AUTO_TEST_CASE(reconnect_buffer_no_incomplete1) |
375 | { | |
376 | switch(child_pid=fork()) | |
af84dfb5 | 377 | { |
307b5e74 | 378 | case -1: |
af84dfb5 | 379 | { |
307b5e74 TJ |
380 | BOOST_FAIL("fork error"); |
381 | break; | |
382 | } | |
383 | case 0: | |
384 | // child | |
385 | { | |
386 | try | |
af84dfb5 | 387 | { |
307b5e74 TJ |
388 | socket_server ss("./socket"); |
389 | ||
390 | time_t t0 = time(NULL); | |
391 | ||
392 | // max 10 sec | |
393 | while (time(NULL) < t0 + 10 ) | |
af84dfb5 | 394 | { |
307b5e74 | 395 | ss.fill_buffer(1000000); |
af84dfb5 | 396 | |
307b5e74 TJ |
397 | string data; |
398 | unsigned int cid; | |
af84dfb5 | 399 | |
307b5e74 | 400 | if(ss.get_packet(data,cid)) |
af84dfb5 | 401 | { |
307b5e74 | 402 | server_connection* con=ss.get_connection(cid); |
af84dfb5 | 403 | |
307b5e74 TJ |
404 | if (data=="QUIT") |
405 | break; | |
af84dfb5 | 406 | |
307b5e74 | 407 | if (data=="x") |
af84dfb5 | 408 | { |
307b5e74 TJ |
409 | con->write(string().insert(0,100,'X')); |
410 | send_raw_socket("aaaab",&ss,cid); | |
af84dfb5 GE |
411 | } |
412 | } | |
413 | } | |
307b5e74 TJ |
414 | } catch(...) |
415 | { | |
416 | std::cerr << "exception in child. ignoring\n"; | |
af84dfb5 GE |
417 | } |
418 | ||
307b5e74 TJ |
419 | // don't call atexit and stuff |
420 | _exit(0); | |
421 | } | |
af84dfb5 | 422 | |
307b5e74 TJ |
423 | default: |
424 | // parent | |
425 | { | |
426 | // don't kill us on broken pipe | |
427 | signal(SIGPIPE, SIG_IGN); | |
af84dfb5 | 428 | |
307b5e74 TJ |
429 | // wait till server is up |
430 | sleep(1); | |
431 | socket_client_connection sc("./socket"); | |
af84dfb5 | 432 | |
307b5e74 | 433 | sc.write("x"); |
af84dfb5 | 434 | |
307b5e74 TJ |
435 | // retrieve packets for 3 seconds |
436 | time_t t0 = time(NULL); | |
af84dfb5 | 437 | |
307b5e74 TJ |
438 | // max 3 sec |
439 | while (time(NULL) < t0 + 3 ) | |
440 | sc.fill_buffer(1000000); | |
af84dfb5 | 441 | |
307b5e74 | 442 | // we now should have one complete packet and some stuff in the buffer |
af84dfb5 | 443 | |
307b5e74 TJ |
444 | string data; |
445 | sc.get_packet(data); | |
af84dfb5 | 446 | |
307b5e74 | 447 | BOOST_CHECK_MESSAGE((sc.peek_packet(data))>0, "no incomplete packet"); |
af84dfb5 | 448 | |
307b5e74 TJ |
449 | sc.reconnect(); |
450 | ||
451 | BOOST_CHECK_MESSAGE((int)sc.peek_packet(data) == 0, "incomplete packet not removed"); | |
af84dfb5 GE |
452 | } |
453 | } | |
307b5e74 | 454 | } |
af84dfb5 | 455 | |
307b5e74 TJ |
456 | BOOST_AUTO_TEST_CASE(reconnect_buffer_no_incomplete2) |
457 | { | |
458 | switch(child_pid=fork()) | |
af84dfb5 | 459 | { |
307b5e74 | 460 | case -1: |
af84dfb5 | 461 | { |
307b5e74 TJ |
462 | BOOST_FAIL("fork error"); |
463 | break; | |
464 | } | |
465 | case 0: | |
466 | // child | |
467 | { | |
468 | try | |
af84dfb5 | 469 | { |
307b5e74 TJ |
470 | socket_server ss("./socket"); |
471 | ||
472 | time_t t0 = time(NULL); | |
473 | ||
474 | // max 10 sec | |
475 | while (time(NULL) < t0 + 10 ) | |
af84dfb5 | 476 | { |
307b5e74 | 477 | ss.fill_buffer(1000000); |
af84dfb5 | 478 | |
307b5e74 TJ |
479 | string data; |
480 | unsigned int cid; | |
af84dfb5 | 481 | |
307b5e74 | 482 | if(ss.get_packet(data,cid)) |
af84dfb5 | 483 | { |
307b5e74 | 484 | server_connection* con=ss.get_connection(cid); |
af84dfb5 | 485 | |
307b5e74 TJ |
486 | if (data=="QUIT") |
487 | break; | |
af84dfb5 | 488 | |
307b5e74 | 489 | if (data=="x") |
af84dfb5 | 490 | { |
307b5e74 | 491 | con->write(string().insert(0,100,'X')); |
441d41fe | 492 | |
307b5e74 | 493 | string blob=string().insert(0,100,'Y'); |
af84dfb5 | 494 | |
307b5e74 TJ |
495 | // one byte will be missing... |
496 | int size=blob.size()+1; | |
497 | char sizetransfer[sizeof(int)+1]; | |
498 | memcpy(sizetransfer,(void*)&size,sizeof(int)); | |
4c31749b | 499 | sizetransfer[sizeof(int)]=0; |
af84dfb5 | 500 | |
307b5e74 | 501 | string packet=string(sizetransfer)+blob; |
af84dfb5 | 502 | |
307b5e74 | 503 | send_raw_socket(packet,&ss,cid); |
af84dfb5 GE |
504 | } |
505 | } | |
506 | } | |
307b5e74 TJ |
507 | } catch(...) |
508 | { | |
509 | std::cerr << "exception in child. ignoring\n"; | |
af84dfb5 GE |
510 | } |
511 | ||
307b5e74 TJ |
512 | // don't call atexit and stuff |
513 | _exit(0); | |
514 | } | |
af84dfb5 | 515 | |
307b5e74 TJ |
516 | default: |
517 | // parent | |
518 | { | |
519 | // don't kill us on broken pipe | |
520 | signal(SIGPIPE, SIG_IGN); | |
af84dfb5 | 521 | |
307b5e74 TJ |
522 | // wait till server is up |
523 | sleep(1); | |
524 | socket_client_connection sc("./socket"); | |
af84dfb5 | 525 | |
307b5e74 | 526 | sc.write("x"); |
af84dfb5 | 527 | |
307b5e74 TJ |
528 | // retrieve packets for 3 seconds |
529 | time_t t0 = time(NULL); | |
af84dfb5 | 530 | |
307b5e74 TJ |
531 | // max 3 sec |
532 | while (time(NULL) < t0 + 3 ) | |
533 | sc.fill_buffer(1000000); | |
af84dfb5 | 534 | |
307b5e74 | 535 | // we now should have one complete packet and some stuff in the buffer |
af84dfb5 | 536 | |
307b5e74 | 537 | sc.reconnect(); |
af84dfb5 | 538 | |
307b5e74 | 539 | string data; |
af84dfb5 | 540 | |
307b5e74 TJ |
541 | BOOST_CHECK_MESSAGE(sc.get_packet(data) == true, "packet not there"); |
542 | BOOST_CHECK_MESSAGE(string().insert(0,100,'X') == data, "data incorrect"); | |
543 | ||
544 | BOOST_CHECK_MESSAGE((int)sc.peek_packet(data) == 0, "incomplete packet not removed"); | |
af84dfb5 GE |
545 | } |
546 | } | |
307b5e74 | 547 | } |
af84dfb5 | 548 | |
307b5e74 | 549 | BOOST_AUTO_TEST_SUITE_END() |