Change license from LGPL to GPL version 2 + linking exception. This fixes C++ templat...
[libt2n] / test / reentrant.cpp
... / ...
CommitLineData
1/*
2Copyright (C) 2004 by Intra2net AG
3
4The software in this package is distributed under the GNU General
5Public License version 2 (with a special exception described below).
6
7A copy of GNU General Public License (GPL) is included in this distribution,
8in the file COPYING.GPL.
9
10As a special exception, if other files instantiate templates or use macros
11or inline functions from this file, or you compile this file and link it
12with other works to produce a work based on this file, this file
13does not by itself cause the resulting work to be covered
14by the GNU General Public License.
15
16However the source code for this file must still be made available
17in accordance with section (3) of the GNU General Public License.
18
19This exception does not invalidate any other reasons why a work based
20on 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
33#include <cppunit/extensions/TestFactoryRegistry.h>
34#include <cppunit/ui/text/TestRunner.h>
35#include <cppunit/extensions/HelperMacros.h>
36
37#include <boost/archive/binary_oarchive.hpp>
38#include <boost/archive/binary_iarchive.hpp>
39#include <boost/archive/xml_oarchive.hpp>
40#include <boost/archive/xml_iarchive.hpp>
41#include <boost/serialization/serialization.hpp>
42
43#include <container.hxx>
44#include <socket_client.hxx>
45#include <socket_server.hxx>
46#include <command_client.hxx>
47#include <command_server.hxx>
48
49using namespace std;
50using namespace CppUnit;
51using namespace libt2n;
52
53namespace reentrant
54{
55
56command_server *global_server = NULL;
57
58int fork_count = 3;
59int requests_per_child = 100;
60int all_requests = (2 << (fork_count-1)) * requests_per_child;
61
62int seen_client_requests = 0;
63
64string testfunc(const string& str)
65{
66 string ret;
67 ret=str+", testfunc() was here";
68
69 // call handle, eventually reentrant
70 if (global_server)
71 global_server->handle(10000);
72
73 ++seen_client_requests;
74
75 return ret;
76}
77
78class testfunc_res : public libt2n::result
79{
80 private:
81 string res;
82
83 friend class boost::serialization::access;
84 template<class Archive>
85 void serialize(Archive & ar, const unsigned int version)
86 {
87 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::result);
88 ar & BOOST_SERIALIZATION_NVP(res);
89 }
90
91 public:
92 testfunc_res()
93 {
94 }
95
96 testfunc_res(const string& str)
97 {
98 res=str;
99 }
100
101 string get_data()
102 {
103 return res;
104 }
105};
106
107
108class testfunc_cmd : public libt2n::command
109{
110 private:
111 string param;
112
113 friend class boost::serialization::access;
114 template<class Archive>
115 void serialize(Archive & ar, const unsigned int version)
116 {
117 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(libt2n::command);
118 ar & BOOST_SERIALIZATION_NVP(param);
119 }
120
121 public:
122 testfunc_cmd()
123 {
124 }
125
126 testfunc_cmd(const string& str)
127 {
128 param=str;
129 }
130
131 libt2n::result* operator()()
132 {
133 return new testfunc_res(testfunc(param));
134 }
135};
136
137}
138
139
140#include <boost/serialization/export.hpp>
141
142BOOST_CLASS_EXPORT(reentrant::testfunc_cmd)
143BOOST_CLASS_EXPORT(reentrant::testfunc_res)
144
145using namespace reentrant;
146
147class test_reentrant : public TestFixture
148{
149 CPPUNIT_TEST_SUITE(test_reentrant);
150
151 CPPUNIT_TEST(ReentrantServer);
152
153 CPPUNIT_TEST_SUITE_END();
154
155 public:
156
157 void setUp()
158 { }
159
160 void tearDown()
161 { }
162
163 void ReentrantServer()
164 {
165 switch(fork())
166 {
167 case -1:
168 {
169 CPPUNIT_FAIL("fork error");
170 break;
171 }
172 case 0:
173 // child
174 {
175 // wait till server is up
176 sleep(2);
177
178 // hammer the server
179 for (int i = 0; i < fork_count; i++)
180 fork();
181
182 try
183 {
184 for (int i=0; i < requests_per_child; i++)
185 {
186 socket_client_connection sc("./socket");
187 // sc.set_logging(&cerr,debug);
188 command_client cc(&sc);
189
190 result_container rc;
191 cc.send_command(new testfunc_cmd("hello"),rc);
192
193 testfunc_res *res = dynamic_cast<testfunc_res*>(rc.get_result());
194 if (res)
195 {
196 string ret = res->get_data();
197 if (ret != "hello, testfunc() was here")
198 std::cout << "ERROR reentrant server testfunc_res failed, res: \"" << ret << "\"\n";
199 }
200 else
201 {
202 std::cout << "ERROR result from reentrant server empty (" << rc.get_result() << ")\n";
203 }
204 }
205 } catch (exception &e)
206 {
207 cerr << "caught exception: " << e.what() << endl;
208 } catch(...)
209 {
210 std::cerr << "exception in child. ignoring\n";
211 }
212
213 // don't call atexit and stuff
214 _exit(0);
215 }
216
217 default:
218 // parent
219 {
220 // don't kill us on broken pipe
221 signal(SIGPIPE, SIG_IGN);
222
223 socket_server ss("./socket");
224 command_server cs(ss);
225
226 global_server=&cs;
227
228 // Wait until all requests have successed
229 int safety_check = 0;
230 while (seen_client_requests < all_requests)
231 {
232 ++safety_check;
233 if (safety_check > 10) {
234 std::cerr << "reached safety check, aborting.\n";
235 break;
236 }
237
238 long long maxtime=1000000;
239 while(maxtime > 0)
240 cs.handle(maxtime,&maxtime);
241 }
242
243 global_server = NULL;
244 }
245
246 // we are still alive, everything is ok
247 CPPUNIT_ASSERT_EQUAL(all_requests, seen_client_requests);
248 }
249 }
250
251};
252
253
254CPPUNIT_TEST_SUITE_REGISTRATION(test_reentrant);