libt2n: (tomj) added exception handling to every child after fork(). This is needed...
[libt2n] / test / callback.cpp
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 #include <vector>
18
19 #include <boost/bind.hpp>
20
21 #include <cppunit/extensions/TestFactoryRegistry.h>
22 #include <cppunit/ui/text/TestRunner.h>
23 #include <cppunit/extensions/HelperMacros.h>
24
25 #include <socket_client.hxx>
26 #include <socket_server.hxx>
27
28 using namespace std;
29 using namespace libt2n;
30 using namespace CppUnit;
31
32 class test_callback : public TestFixture
33 {
34     CPPUNIT_TEST_SUITE(test_callback);
35
36     CPPUNIT_TEST(ServerNewConnCallback);
37     CPPUNIT_TEST(ServerConnClosedCallback);
38     CPPUNIT_TEST(ServerConnDeletedCallback);
39     CPPUNIT_TEST(ServerCallbackOrder);
40     CPPUNIT_TEST(ClientConnClosedCallback);
41     CPPUNIT_TEST(ClientConnDeletedCallback);
42
43     CPPUNIT_TEST_SUITE_END();
44
45     std::vector<bool> callback_done;
46
47     pid_t child_pid;
48
49     public:
50
51     void setUp()
52     {
53         callback_done.resize(__events_end);
54     }
55
56     void tearDown()
57     {
58         callback_done.clear();
59
60         // make sure the server-child is dead before the next test runs
61         kill(child_pid,SIGKILL);
62         sleep(1);
63     }
64
65     void callback_func(callback_event_type ev, int conn_id)
66     {
67         // we don't care for the conn_id, we just mark the callback as done
68         if (callback_done[ev])
69             throw runtime_error("callback already done for this event");
70
71         callback_done[ev]=true;
72     }
73
74     void ServerNewConnCallback()
75     {
76         switch(child_pid=fork())
77         {
78             case -1:
79             {
80                 CPPUNIT_FAIL("fork error");
81                 break;
82             }
83             case 0:
84             // child
85             {
86                 try
87                 {
88                     string data;
89                     // wait till server is up
90                     sleep(1);
91
92                     {
93                         socket_client_connection sc("./socket");
94
95                         sc.write("ABC");
96
97                         // wait half a sec
98                         sc.fill_buffer(500000);
99                         sc.get_packet(data);
100
101                         // close the connection
102                     }
103                 } catch(...)
104                 {
105                     std::cerr << "exception in child. ignoring\n";
106                 }
107
108                 // don't call atexit and stuff
109                 _exit(0);
110             }
111
112             default:
113             // parent
114             {
115                 socket_server ss("./socket");
116
117                 ss.add_callback(new_connection,bind(&test_callback::callback_func, boost::ref(*this), new_connection, _1));
118
119                 // max 3 sec
120                 for (int i=0; i < 3; i++)
121                 {
122                     ss.fill_buffer(1000000);
123
124                     string data;
125                     unsigned int cid;
126                     if(ss.get_packet(data,cid))
127                     {
128                         server_connection* con=ss.get_connection(cid);
129                         con->write("XYZ");
130                     }
131                 }
132                 CPPUNIT_ASSERT_EQUAL(true,static_cast<bool>(callback_done[new_connection]));
133                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[connection_closed]));
134                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[connection_deleted]));
135             }
136         }
137     }
138
139     void ServerConnClosedCallback()
140     {
141         switch(child_pid=fork())
142         {
143             case -1:
144             {
145                 CPPUNIT_FAIL("fork error");
146                 break;
147             }
148             case 0:
149             // child
150             {
151                 try
152                 {
153                     string data;
154                     // wait till server is up
155                     sleep(1);
156
157                     {
158                         socket_client_connection sc("./socket");
159
160                         sc.write("ABC");
161
162                         // wait half a sec
163                         sc.fill_buffer(500000);
164                         sc.get_packet(data);
165
166                         // close the connection
167                     }
168                 } catch(...)
169                 {
170                     std::cerr << "exception in child. ignoring\n";
171                 }
172
173                 // don't call atexit and stuff
174                 _exit(0);
175             }
176
177             default:
178             // parent
179             {
180                 socket_server ss("./socket");
181
182                 ss.add_callback(connection_closed,bind(&test_callback::callback_func, boost::ref(*this), connection_closed, _1));
183
184                 // max 3 sec
185                 for (int i=0; i < 3; i++)
186                 {
187                     ss.fill_buffer(1000000);
188
189                     string data;
190                     unsigned int cid;
191                     if(ss.get_packet(data,cid))
192                     {
193                         server_connection* con=ss.get_connection(cid);
194                         con->write("XYZ");
195                     }
196                 }
197                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[new_connection]));
198                 CPPUNIT_ASSERT_EQUAL(true,static_cast<bool>(callback_done[connection_closed]));
199                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[connection_deleted]));
200             }
201         }
202     }
203
204     void ServerConnDeletedCallback()
205     {
206         switch(child_pid=fork())
207         {
208             case -1:
209             {
210                 CPPUNIT_FAIL("fork error");
211                 break;
212             }
213             case 0:
214             // child
215             {
216                 try
217                 {
218                     string data;
219                     // wait till server is up
220                     sleep(1);
221
222                     {
223                         socket_client_connection sc("./socket");
224
225                         sc.write("ABC");
226
227                         // wait half a sec
228                         sc.fill_buffer(500000);
229                         sc.get_packet(data);
230
231                         // close the connection
232                     }
233                 } catch(...)
234                 {
235                     std::cerr << "exception in child. ignoring\n";
236                 }
237
238                 // don't call atexit and stuff
239                 _exit(0);
240             }
241
242             default:
243             // parent
244             {
245                 socket_server ss("./socket");
246
247                 ss.add_callback(connection_deleted,bind(&test_callback::callback_func, boost::ref(*this), connection_deleted, _1));
248
249                 // max 3 sec
250                 for (int i=0; i < 3; i++)
251                 {
252                     ss.fill_buffer(1000000);
253
254                     string data;
255                     unsigned int cid;
256                     if(ss.get_packet(data,cid))
257                     {
258                         server_connection* con=ss.get_connection(cid);
259                         con->write("XYZ");
260                     }
261                     ss.cleanup();
262                 }
263                 ss.cleanup();
264
265                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[new_connection]));
266                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[connection_closed]));
267                 CPPUNIT_ASSERT_EQUAL(true,static_cast<bool>(callback_done[connection_deleted]));
268             }
269         }
270     }
271
272     void ServerCallbackOrder()
273     {
274         switch(child_pid=fork())
275         {
276             case -1:
277             {
278                 CPPUNIT_FAIL("fork error");
279                 break;
280             }
281             case 0:
282             // child
283             {
284                 try
285                 {
286                     string data;
287                     // wait till server is up
288                     sleep(1);
289
290                     {
291                         socket_client_connection sc("./socket");
292
293                         sc.write("1");
294
295                         // wait half a sec
296                         sc.fill_buffer(500000);
297                         sc.get_packet(data);
298
299                         sc.write("2");
300
301                         // close the connection
302                     }
303                 } catch(...)
304                 {
305                     std::cerr << "exception in child. ignoring\n";
306                 }
307
308                 // don't call atexit and stuff
309                 _exit(0);
310             }
311
312             default:
313             // parent
314             {
315                 socket_server ss("./socket");
316
317                 ss.add_callback(connection_closed,bind(&test_callback::callback_func, boost::ref(*this), connection_closed, _1));
318                 ss.add_callback(connection_deleted,bind(&test_callback::callback_func, boost::ref(*this), connection_deleted, _1));
319
320                 bool got_1=false;
321
322                 for (int i=0; i < 5; i++)
323                 {
324                     ss.fill_buffer(500000);
325
326                     string data;
327                     unsigned int cid;
328                     if(!got_1 && ss.get_packet(data,cid))
329                     {
330                         server_connection* con=ss.get_connection(cid);
331                         con->write("XYZ");
332                         got_1=true;
333                         // don't call get_packet anymore
334                     }
335                     ss.cleanup();
336                 }
337                 ss.cleanup();
338
339                 CPPUNIT_ASSERT_EQUAL_MESSAGE("closed done",true,static_cast<bool>(callback_done[connection_closed]));
340                 CPPUNIT_ASSERT_EQUAL_MESSAGE("not deleted yet",false,static_cast<bool>(callback_done[connection_deleted]));
341
342                 for (int i=0; i < 4; i++)
343                 {
344                     ss.fill_buffer(500000);
345
346                     string data;
347                     unsigned int cid;
348                     ss.get_packet(data,cid);
349                     ss.cleanup();
350                 }
351                 ss.cleanup();
352
353                 CPPUNIT_ASSERT_EQUAL_MESSAGE("closed done (2)",true,static_cast<bool>(callback_done[connection_closed]));
354                 CPPUNIT_ASSERT_EQUAL_MESSAGE("deleted done",true,static_cast<bool>(callback_done[connection_deleted]));
355             }
356         }
357     }
358
359     void ClientConnClosedCallback()
360     {
361         switch(child_pid=fork())
362         {
363             case -1:
364             {
365                 CPPUNIT_FAIL("fork error");
366                 break;
367             }
368             case 0:
369             // child
370             {
371                 try
372                 {
373                     socket_server ss("./socket");
374
375                     // max 3 sec
376                     for (int i=0; i < 3; i++)
377                     {
378                         ss.fill_buffer(1000000);
379
380                         string data;
381                         unsigned int cid;
382                         if(ss.get_packet(data,cid))
383                             break;
384                     }
385                 } catch(...)
386                 {
387                     std::cerr << "exception in child. ignoring\n";
388                 }
389
390                 // don't call atexit and stuff
391                 _exit(0);
392             }
393
394             default:
395             // parent
396             {
397                 string data;
398                 // wait till server is up
399                 sleep(1);
400
401                 socket_client_connection sc("./socket");
402
403                 sc.add_callback(connection_closed,bind(&test_callback::callback_func, boost::ref(*this), connection_closed, 0));
404
405                 sc.write("ABC");
406
407                 // wait half a sec
408                 sc.fill_buffer(500000);
409                 sc.get_packet(data);
410
411                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[new_connection]));
412                 CPPUNIT_ASSERT_EQUAL(true,static_cast<bool>(callback_done[connection_closed]));
413                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[connection_deleted]));
414             }
415         }
416     }
417
418     void ClientConnDeletedCallback()
419     {
420         switch(child_pid=fork())
421         {
422             case -1:
423             {
424                 CPPUNIT_FAIL("fork error");
425                 break;
426             }
427             case 0:
428             // child
429             {
430                 try
431                 {
432                     socket_server ss("./socket");
433
434                     // max 3 sec
435                     for (int i=0; i < 3; i++)
436                     {
437                         ss.fill_buffer(1000000);
438
439                         string data;
440                         unsigned int cid;
441                         if(ss.get_packet(data,cid))
442                             break;
443                     }
444                 } catch(...)
445                 {
446                     std::cerr << "exception in child. ignoring\n";
447                 }
448
449                 // don't call atexit and stuff
450                 _exit(0);
451             }
452
453             default:
454             // parent
455             {
456                 string data;
457                 // wait till server is up
458                 sleep(1);
459
460                 {
461                     socket_client_connection sc("./socket");
462
463                     sc.add_callback(connection_deleted,bind(&test_callback::callback_func, boost::ref(*this), connection_deleted, 0));
464
465                     sc.write("ABC");
466
467                     // wait half a sec
468                     sc.fill_buffer(500000);
469                     sc.get_packet(data);
470                 }
471
472                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[new_connection]));
473                 CPPUNIT_ASSERT_EQUAL(false,static_cast<bool>(callback_done[connection_closed]));
474                 CPPUNIT_ASSERT_EQUAL(true,static_cast<bool>(callback_done[connection_deleted]));
475             }
476         }
477     }
478 };
479
480 CPPUNIT_TEST_SUITE_REGISTRATION(test_callback);