libt2n: (tomj) fix mysterious crashes in test::ReentrantServer: boost serialization...
[libt2n] / test / reentrant.cpp
CommitLineData
3b2543e7
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 <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
34using namespace std;
35using namespace CppUnit;
36using namespace libt2n;
37
276fd052 38namespace reentrant
3b2543e7
GE
39{
40
d55e0d0f 41command_server *global_server = NULL;
3b2543e7 42
696c95c2
TJ
43int fork_count = 3;
44int requests_per_child = 100;
45int all_requests = (2 << (fork_count-1)) * requests_per_child;
46
47int seen_client_requests = 0;
48
3b2543e7
GE
49string testfunc(const string& str)
50{
51 string ret;
52 ret=str+", testfunc() was here";
53
54 // call handle, eventually reentrant
d55e0d0f 55 if (global_server)
56f3994d 56 global_server->handle(10000);
3b2543e7 57
696c95c2
TJ
58 ++seen_client_requests;
59
3b2543e7
GE
60 return ret;
61}
62
63class testfunc_res : public libt2n::result
64{
65 private:
66 string res;
67
68 friend class boost::serialization::access;
69 template<class Archive>
70 void serialize(Archive & ar, const unsigned int version)
71 {
72 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
73 ar & BOOST_SERIALIZATION_NVP(res);
74 }
75
76 public:
77 testfunc_res()
696c95c2
TJ
78 {
79 }
3b2543e7
GE
80
81 testfunc_res(const string& str)
82 {
83 res=str;
84 }
85
86 string get_data()
87 {
88 return res;
89 }
90};
91
92
93class testfunc_cmd : public libt2n::command
94{
95 private:
96 string param;
97
98 friend class boost::serialization::access;
99 template<class Archive>
100 void serialize(Archive & ar, const unsigned int version)
101 {
102 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
103 ar & BOOST_SERIALIZATION_NVP(param);
104 }
105
106 public:
107 testfunc_cmd()
696c95c2
TJ
108 {
109 }
3b2543e7
GE
110
111 testfunc_cmd(const string& str)
112 {
113 param=str;
114 }
115
116 libt2n::result* operator()()
117 {
118 return new testfunc_res(testfunc(param));
119 }
120};
121
122}
123
696c95c2 124
3b2543e7
GE
125#include <boost/serialization/export.hpp>
126
276fd052
TJ
127BOOST_CLASS_EXPORT(reentrant::testfunc_cmd)
128BOOST_CLASS_EXPORT(reentrant::testfunc_res)
129
130using namespace reentrant;
3b2543e7
GE
131
132class test_reentrant : public TestFixture
133{
134 CPPUNIT_TEST_SUITE(test_reentrant);
135
136 CPPUNIT_TEST(ReentrantServer);
137
138 CPPUNIT_TEST_SUITE_END();
139
3b2543e7
GE
140 public:
141
142 void setUp()
143 { }
144
145 void tearDown()
146 { }
147
148 void ReentrantServer()
149 {
56f3994d 150 switch(fork())
3b2543e7
GE
151 {
152 case -1:
153 {
154 CPPUNIT_FAIL("fork error");
155 break;
156 }
157 case 0:
158 // child
159 {
160 // wait till server is up
696c95c2 161 sleep(2);
3b2543e7 162
696c95c2
TJ
163 // hammer the server
164 for (int i = 0; i < fork_count; i++)
165 fork();
3b2543e7 166
56f3994d 167 try
3b2543e7 168 {
696c95c2 169 for (int i=0; i < requests_per_child; i++)
56f3994d
TJ
170 {
171 socket_client_connection sc("./socket");
696c95c2 172 // sc.set_logging(&cerr,debug);
56f3994d
TJ
173 command_client cc(&sc);
174
175 result_container rc;
176 cc.send_command(new testfunc_cmd("hello"),rc);
177
178 testfunc_res *res = dynamic_cast<testfunc_res*>(rc.get_result());
179 if (res)
180 {
181 string ret = res->get_data();
182 if (ret != "hello, testfunc() was here")
696c95c2 183 std::cout << "ERROR reentrant server testfunc_res failed, res: \"" << ret << "\"\n";
56f3994d
TJ
184 }
185 else
186 {
696c95c2 187 std::cout << "ERROR result from reentrant server empty (" << rc.get_result() << ")\n";
56f3994d
TJ
188 }
189 }
190 } catch (exception &e)
191 {
192 cerr << "caught exception: " << e.what() << endl;
441d41fe
TJ
193 } catch(...)
194 {
195 std::cerr << "exception in child. ignoring\n";
3b2543e7
GE
196 }
197
198 // don't call atexit and stuff
199 _exit(0);
200 }
201
202 default:
203 // parent
204 {
56f3994d
TJ
205 // don't kill us on broken pipe
206 signal(SIGPIPE, SIG_IGN);
207
3b2543e7
GE
208 socket_server ss("./socket");
209 command_server cs(ss);
210
211 global_server=&cs;
212
696c95c2
TJ
213 // Wait until all requests have successed
214 int safety_check = 0;
215 while (seen_client_requests < all_requests)
216 {
217 ++safety_check;
218 if (safety_check > 10) {
219 std::cerr << "reached safety check, aborting.\n";
220 break;
221 }
56f3994d 222
696c95c2
TJ
223 long long maxtime=1000000;
224 while(maxtime > 0)
225 cs.handle(maxtime,&maxtime);
226 }
56f3994d 227
d55e0d0f 228 global_server = NULL;
3b2543e7
GE
229 }
230
231 // we are still alive, everything is ok
696c95c2 232 CPPUNIT_ASSERT_EQUAL(all_requests, seen_client_requests);
3b2543e7
GE
233 }
234 }
235
236};
237
238
239CPPUNIT_TEST_SUITE_REGISTRATION(test_reentrant);