libt2n: (tomj) fixed call of virtual function close() from destructor, fixed return...
[libt2n] / test / reentrant.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
18 #include <cppunit/extensions/TestFactoryRegistry.h>
19 #include <cppunit/ui/text/TestRunner.h>
20 #include <cppunit/extensions/HelperMacros.h>
21
22 #include <boost/archive/binary_oarchive.hpp>
23 #include <boost/archive/binary_iarchive.hpp>
24 #include <boost/archive/xml_oarchive.hpp>
25 #include <boost/archive/xml_iarchive.hpp>
26 #include <boost/serialization/serialization.hpp>
27
28 #include <container.hxx>
29 #include <socket_client.hxx>
30 #include <socket_server.hxx>
31 #include <command_client.hxx>
32 #include <command_server.hxx>
33
34 using namespace std;
35 using namespace CppUnit;
36 using namespace libt2n;
37
38 namespace
39 {
40
41 command_server *global_server = NULL;
42
43 string testfunc(const string& str)
44 {
45     string ret;
46     ret=str+", testfunc() was here";
47
48     // call handle, eventually reentrant
49     if (global_server)
50         global_server->handle(10000);
51
52     return ret;
53 }
54
55 class testfunc_res : public libt2n::result
56 {
57     private:
58         string res;
59
60         friend class boost::serialization::access;
61         template<class Archive>
62         void serialize(Archive & ar, const unsigned int version)
63         {
64             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
65             ar & BOOST_SERIALIZATION_NVP(res);
66         }
67
68     public:
69         testfunc_res()
70             { }
71
72         testfunc_res(const string& str)
73         {
74             res=str;
75         }
76
77         string get_data()
78         {
79             return res;
80         }
81 };
82
83
84 class testfunc_cmd : public libt2n::command
85 {
86     private:
87         string param;
88
89         friend class boost::serialization::access;
90         template<class Archive>
91         void serialize(Archive & ar, const unsigned int version)
92         {
93             ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
94             ar & BOOST_SERIALIZATION_NVP(param);
95         }
96
97     public:
98         testfunc_cmd()
99             { }
100
101         testfunc_cmd(const string& str)
102         {
103             param=str;
104         }
105
106         libt2n::result* operator()()
107         {
108             return new testfunc_res(testfunc(param));
109         }
110 };
111
112 }
113
114 #include <boost/serialization/export.hpp>
115
116 BOOST_CLASS_EXPORT(testfunc_cmd)
117 BOOST_CLASS_EXPORT(testfunc_res)
118
119 class test_reentrant : public TestFixture
120 {
121     CPPUNIT_TEST_SUITE(test_reentrant);
122
123     CPPUNIT_TEST(ReentrantServer);
124
125     CPPUNIT_TEST_SUITE_END();
126
127     public:
128
129     void setUp()
130     { }
131
132     void tearDown()
133     { }
134
135     void ReentrantServer()
136     {
137         switch(fork())
138         {
139             case -1:
140             {
141                 CPPUNIT_FAIL("fork error");
142                 break;
143             }
144             case 0:
145             // child
146             {
147                 // wait till server is up
148                 sleep(3);
149
150                 // we want 8 identical childs hammering the server
151                 fork();
152                 fork();
153                 fork();
154
155                 try
156                 {
157                     for (int i=0; i < 100; i++)
158                     {
159                         socket_client_connection sc("./socket");
160                         command_client cc(&sc);
161
162                         result_container rc;
163                         cc.send_command(new testfunc_cmd("hello"),rc);
164
165                         testfunc_res *res = dynamic_cast<testfunc_res*>(rc.get_result());
166                         if (res)
167                         {
168                             string ret = res->get_data();
169                             if (ret != "hello, testfunc() was here")
170                                 std::cout << "ERROR reentrant server testfunc_res failed, res: " << ret << "\n";
171                         }
172                         else
173                         {
174                             std::cout << "ERROR result from reentrant server empty\n";
175                         }
176                     }
177                 } catch (exception &e)
178                 {
179                     cerr << "caught exception: " << e.what() << endl;
180                 }
181
182                 // don't call atexit and stuff
183                 _exit(0);
184             }
185
186             default:
187             // parent
188             {
189                 // don't kill us on broken pipe
190                 signal(SIGPIPE, SIG_IGN);
191
192                 socket_server ss("./socket");
193                 command_server cs(ss);
194
195                 global_server=&cs;
196
197                 // max 10 sec
198                 long long maxtime=1000000;
199                 while(maxtime > 0)
200                     cs.handle(maxtime,&maxtime);
201
202                 // max 10 sec
203                 maxtime=1000000;
204                 while(maxtime > 0)
205                     cs.handle(maxtime,&maxtime);
206
207                 // max 10 sec
208                 maxtime=1000000;
209                 while(maxtime > 0)
210                     cs.handle(maxtime,&maxtime);
211
212                 global_server = NULL;
213             }
214
215             // we are still alive, everything is ok
216             CPPUNIT_ASSERT_EQUAL(1,1);
217         }
218     }
219
220 };
221
222
223 CPPUNIT_TEST_SUITE_REGISTRATION(test_reentrant);