Prepare libt2n 0.7 release
[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#define BOOST_TEST_DYN_LINK
34#include <boost/test/unit_test.hpp>
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;
49using namespace libt2n;
50
51namespace reentrant
52{
53
54command_server *global_server = NULL;
55
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
62string testfunc(const string& str)
63{
64 string ret;
65 ret=str+", testfunc() was here";
66
67 // call handle, eventually reentrant
68 if (global_server)
69 global_server->handle(10000);
70
71 ++seen_client_requests;
72
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()
91 {
92 }
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()
121 {
122 }
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
137
138#include <boost/serialization/export.hpp>
139
140BOOST_CLASS_EXPORT(reentrant::testfunc_cmd)
141BOOST_CLASS_EXPORT(reentrant::testfunc_res)
142
143using namespace reentrant;
144
145BOOST_AUTO_TEST_SUITE(test_reentrant)
146
147BOOST_AUTO_TEST_CASE(ReentrantServer)
148{
149 switch(fork())
150 {
151 case -1:
152 {
153 BOOST_FAIL("fork error");
154 break;
155 }
156 case 0:
157 // child
158 {
159 // wait till server is up
160 sleep(2);
161
162 // hammer the server
163 for (int i = 0; i < fork_count; i++)
164 fork();
165
166 try
167 {
168 for (int i=0; i < requests_per_child; i++)
169 {
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)
179 {
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";
187 }
188 }
189 } catch (exception &e)
190 {
191 cerr << "caught exception: " << e.what() << endl;
192 } catch(...)
193 {
194 std::cerr << "exception in child. ignoring\n";
195 }
196
197 // don't call atexit and stuff
198 _exit(0);
199 }
200
201 default:
202 // parent
203 {
204 // don't kill us on broken pipe
205 signal(SIGPIPE, SIG_IGN);
206
207 socket_server ss("./socket");
208 command_server cs(ss);
209
210 global_server=&cs;
211
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;
220 }
221
222 long long maxtime=1000000;
223 while(maxtime > 0)
224 cs.handle(maxtime,&maxtime);
225 }
226
227 global_server = NULL;
228 }
229
230 // we are still alive, everything is ok
231 BOOST_CHECK_EQUAL(all_requests, seen_client_requests);
232 }
233}
234
235BOOST_AUTO_TEST_SUITE_END()