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