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