1 | // |
2 | // TCPServerTest.cpp |
3 | // |
4 | // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. |
5 | // and Contributors. |
6 | // |
7 | // SPDX-License-Identifier: BSL-1.0 |
8 | // |
9 | |
10 | |
11 | #include "TCPServerTest.h" |
12 | #include "Poco/CppUnit/TestCaller.h" |
13 | #include "Poco/CppUnit/TestSuite.h" |
14 | #include "Poco/Net/TCPServer.h" |
15 | #include "Poco/Net/TCPServerConnection.h" |
16 | #include "Poco/Net/TCPServerConnectionFactory.h" |
17 | #include "Poco/Net/TCPServerParams.h" |
18 | #include "Poco/Net/SecureStreamSocket.h" |
19 | #include "Poco/Net/SecureServerSocket.h" |
20 | #include "Poco/Net/Context.h" |
21 | #include "Poco/Net/Session.h" |
22 | #include "Poco/Net/SSLManager.h" |
23 | #include "Poco/Util/Application.h" |
24 | #include "Poco/Util/AbstractConfiguration.h" |
25 | #include "Poco/Thread.h" |
26 | #include <iostream> |
27 | |
28 | |
29 | using Poco::Net::TCPServer; |
30 | using Poco::Net::TCPServerConnection; |
31 | using Poco::Net::TCPServerConnectionFactory; |
32 | using Poco::Net::TCPServerConnectionFactoryImpl; |
33 | using Poco::Net::TCPServerParams; |
34 | using Poco::Net::StreamSocket; |
35 | using Poco::Net::SecureStreamSocket; |
36 | using Poco::Net::SecureServerSocket; |
37 | using Poco::Net::SocketAddress; |
38 | using Poco::Net::Context; |
39 | using Poco::Net::Session; |
40 | using Poco::Net::SSLManager; |
41 | using Poco::Thread; |
42 | using Poco::Util::Application; |
43 | |
44 | static const int closeSleepTime = 3000; |
45 | |
46 | namespace |
47 | { |
48 | class EchoConnection: public TCPServerConnection |
49 | { |
50 | public: |
51 | EchoConnection(const StreamSocket& s): TCPServerConnection(s) |
52 | { |
53 | } |
54 | |
55 | void run() |
56 | { |
57 | StreamSocket& ss = socket(); |
58 | try |
59 | { |
60 | char buffer[256]; |
61 | int n = ss.receiveBytes(buffer, sizeof(buffer)); |
62 | while (n > 0) |
63 | { |
64 | ss.sendBytes(buffer, n); |
65 | n = ss.receiveBytes(buffer, sizeof(buffer)); |
66 | } |
67 | } |
68 | catch (Poco::Exception& exc) |
69 | { |
70 | std::cerr << "EchoConnection: " << exc.displayText() << std::endl; |
71 | } |
72 | } |
73 | }; |
74 | } |
75 | |
76 | |
77 | TCPServerTest::TCPServerTest(const std::string& name): CppUnit::TestCase(name) |
78 | { |
79 | } |
80 | |
81 | |
82 | TCPServerTest::~TCPServerTest() |
83 | { |
84 | } |
85 | |
86 | |
87 | void TCPServerTest::testOneConnection() |
88 | { |
89 | SecureServerSocket svs(0); |
90 | TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs); |
91 | srv.start(); |
92 | assertTrue (srv.currentConnections() == 0); |
93 | assertTrue (srv.currentThreads() == 0); |
94 | assertTrue (srv.queuedConnections() == 0); |
95 | assertTrue (srv.totalConnections() == 0); |
96 | |
97 | SocketAddress sa("127.0.0.1" , svs.address().port()); |
98 | SecureStreamSocket ss1(sa); |
99 | std::string data("hello, world" ); |
100 | ss1.sendBytes(data.data(), (int) data.size()); |
101 | char buffer[256]; |
102 | int n = ss1.receiveBytes(buffer, sizeof(buffer)); |
103 | assertTrue (n > 0); |
104 | assertTrue (std::string(buffer, n) == data); |
105 | assertTrue (srv.currentConnections() == 1); |
106 | assertTrue (srv.currentThreads() == 1); |
107 | assertTrue (srv.queuedConnections() == 0); |
108 | assertTrue (srv.totalConnections() == 1); |
109 | ss1.close(); |
110 | Thread::sleep(closeSleepTime); |
111 | assertTrue (srv.currentConnections() == 0); |
112 | } |
113 | |
114 | |
115 | void TCPServerTest::testTwoConnections() |
116 | { |
117 | SecureServerSocket svs(0); |
118 | TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs); |
119 | srv.start(); |
120 | assertTrue (srv.currentConnections() == 0); |
121 | assertTrue (srv.currentThreads() == 0); |
122 | assertTrue (srv.queuedConnections() == 0); |
123 | assertTrue (srv.totalConnections() == 0); |
124 | |
125 | SocketAddress sa("127.0.0.1" , svs.address().port()); |
126 | SecureStreamSocket ss1(sa); |
127 | SecureStreamSocket ss2(sa); |
128 | std::string data("hello, world" ); |
129 | ss1.sendBytes(data.data(), (int) data.size()); |
130 | ss2.sendBytes(data.data(), (int) data.size()); |
131 | |
132 | char buffer[256]; |
133 | int n = ss1.receiveBytes(buffer, sizeof(buffer)); |
134 | assertTrue (n > 0); |
135 | assertTrue (std::string(buffer, n) == data); |
136 | |
137 | n = ss2.receiveBytes(buffer, sizeof(buffer)); |
138 | assertTrue (n > 0); |
139 | assertTrue (std::string(buffer, n) == data); |
140 | |
141 | assertTrue (srv.currentConnections() == 2); |
142 | assertTrue (srv.currentThreads() == 2); |
143 | assertTrue (srv.queuedConnections() == 0); |
144 | assertTrue (srv.totalConnections() == 2); |
145 | ss1.close(); |
146 | Thread::sleep(300); |
147 | assertTrue (srv.currentConnections() == 1); |
148 | assertTrue (srv.currentThreads() == 1); |
149 | assertTrue (srv.queuedConnections() == 0); |
150 | assertTrue (srv.totalConnections() == 2); |
151 | ss2.close(); |
152 | |
153 | Thread::sleep(closeSleepTime); |
154 | assertTrue (srv.currentConnections() == 0); |
155 | } |
156 | |
157 | |
158 | void TCPServerTest::testMultiConnections() |
159 | { |
160 | SecureServerSocket svs(0); |
161 | TCPServerParams* pParams = new TCPServerParams; |
162 | pParams->setMaxThreads(4); |
163 | pParams->setMaxQueued(4); |
164 | pParams->setThreadIdleTime(100); |
165 | TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs, pParams); |
166 | srv.start(); |
167 | assertTrue (srv.currentConnections() == 0); |
168 | assertTrue (srv.currentThreads() == 0); |
169 | assertTrue (srv.queuedConnections() == 0); |
170 | assertTrue (srv.totalConnections() == 0); |
171 | |
172 | SocketAddress sa("127.0.0.1" , svs.address().port()); |
173 | SecureStreamSocket ss1(sa); |
174 | SecureStreamSocket ss2(sa); |
175 | SecureStreamSocket ss3(sa); |
176 | SecureStreamSocket ss4(sa); |
177 | std::string data("hello, world" ); |
178 | ss1.sendBytes(data.data(), (int) data.size()); |
179 | ss2.sendBytes(data.data(), (int) data.size()); |
180 | ss3.sendBytes(data.data(), (int) data.size()); |
181 | ss4.sendBytes(data.data(), (int) data.size()); |
182 | |
183 | char buffer[256]; |
184 | int n = ss1.receiveBytes(buffer, sizeof(buffer)); |
185 | assertTrue (n > 0); |
186 | assertTrue (std::string(buffer, n) == data); |
187 | |
188 | n = ss2.receiveBytes(buffer, sizeof(buffer)); |
189 | assertTrue (n > 0); |
190 | assertTrue (std::string(buffer, n) == data); |
191 | |
192 | n = ss3.receiveBytes(buffer, sizeof(buffer)); |
193 | assertTrue (n > 0); |
194 | assertTrue (std::string(buffer, n) == data); |
195 | |
196 | n = ss4.receiveBytes(buffer, sizeof(buffer)); |
197 | assertTrue (n > 0); |
198 | assertTrue (std::string(buffer, n) == data); |
199 | |
200 | assertTrue (srv.currentConnections() == 4); |
201 | assertTrue (srv.currentThreads() == 4); |
202 | assertTrue (srv.queuedConnections() == 0); |
203 | assertTrue (srv.totalConnections() == 4); |
204 | |
205 | SecureStreamSocket ss5; |
206 | ss5.setLazyHandshake(); |
207 | ss5.connect(sa); |
208 | Thread::sleep(200); |
209 | assertTrue (srv.queuedConnections() == 1); |
210 | SecureStreamSocket ss6; |
211 | ss6.setLazyHandshake(); |
212 | ss6.connect(sa); |
213 | Thread::sleep(200); |
214 | assertTrue (srv.queuedConnections() == 2); |
215 | |
216 | ss1.close(); |
217 | Thread::sleep(300); |
218 | assertTrue (srv.currentConnections() == 4); |
219 | assertTrue (srv.currentThreads() == 4); |
220 | assertTrue (srv.queuedConnections() == 1); |
221 | assertTrue (srv.totalConnections() == 5); |
222 | |
223 | ss2.close(); |
224 | Thread::sleep(300); |
225 | assertTrue (srv.currentConnections() == 4); |
226 | assertTrue (srv.currentThreads() == 4); |
227 | assertTrue (srv.queuedConnections() == 0); |
228 | assertTrue (srv.totalConnections() == 6); |
229 | |
230 | ss3.close(); |
231 | Thread::sleep(300); |
232 | assertTrue (srv.currentConnections() == 3); |
233 | assertTrue (srv.currentThreads() == 3); |
234 | assertTrue (srv.queuedConnections() == 0); |
235 | assertTrue (srv.totalConnections() == 6); |
236 | |
237 | ss4.close(); |
238 | Thread::sleep(300); |
239 | assertTrue (srv.currentConnections() == 2); |
240 | assertTrue (srv.currentThreads() == 2); |
241 | assertTrue (srv.queuedConnections() == 0); |
242 | assertTrue (srv.totalConnections() == 6); |
243 | |
244 | ss5.close(); |
245 | ss6.close(); |
246 | Thread::sleep(closeSleepTime); |
247 | assertTrue (srv.currentConnections() == 0); |
248 | } |
249 | |
250 | |
251 | void TCPServerTest::testReuseSocket() |
252 | { |
253 | SecureServerSocket svs(0); |
254 | TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs); |
255 | srv.start(); |
256 | assertTrue (srv.currentConnections() == 0); |
257 | assertTrue (srv.currentThreads() == 0); |
258 | assertTrue (srv.queuedConnections() == 0); |
259 | assertTrue (srv.totalConnections() == 0); |
260 | |
261 | SocketAddress sa("127.0.0.1" , svs.address().port()); |
262 | SecureStreamSocket ss1(sa); |
263 | std::string data("hello, world" ); |
264 | ss1.sendBytes(data.data(), (int) data.size()); |
265 | char buffer[256]; |
266 | int n = ss1.receiveBytes(buffer, sizeof(buffer)); |
267 | assertTrue (n > 0); |
268 | assertTrue (std::string(buffer, n) == data); |
269 | assertTrue (srv.currentConnections() == 1); |
270 | assertTrue (srv.currentThreads() == 1); |
271 | assertTrue (srv.queuedConnections() == 0); |
272 | assertTrue (srv.totalConnections() == 1); |
273 | ss1.close(); |
274 | Thread::sleep(300); |
275 | assertTrue (srv.currentConnections() == 0); |
276 | |
277 | ss1.connect(sa); |
278 | ss1.sendBytes(data.data(), (int) data.size()); |
279 | n = ss1.receiveBytes(buffer, sizeof(buffer)); |
280 | assertTrue (n > 0); |
281 | assertTrue (std::string(buffer, n) == data); |
282 | assertTrue (srv.currentConnections() == 1); |
283 | assertTrue (srv.queuedConnections() == 0); |
284 | assertTrue (srv.totalConnections() == 2); |
285 | ss1.close(); |
286 | Thread::sleep(closeSleepTime); |
287 | assertTrue (srv.currentConnections() == 0); |
288 | } |
289 | |
290 | |
291 | void TCPServerTest::testReuseSession() |
292 | { |
293 | // ensure OpenSSL machinery is fully setup |
294 | Context::Ptr pDefaultServerContext = SSLManager::instance().defaultServerContext(); |
295 | Context::Ptr pDefaultClientContext = SSLManager::instance().defaultClientContext(); |
296 | |
297 | Context::Ptr pServerContext = new Context( |
298 | Context::SERVER_USE, |
299 | Application::instance().config().getString("openSSL.server.privateKeyFile" ), |
300 | Application::instance().config().getString("openSSL.server.privateKeyFile" ), |
301 | Application::instance().config().getString("openSSL.server.caConfig" ), |
302 | Context::VERIFY_NONE, |
303 | 9, |
304 | true, |
305 | "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" ); |
306 | pServerContext->enableSessionCache(true, "TestSuite" ); |
307 | pServerContext->setSessionTimeout(10); |
308 | pServerContext->setSessionCacheSize(1000); |
309 | pServerContext->disableStatelessSessionResumption(); |
310 | |
311 | SecureServerSocket svs(0, 64, pServerContext); |
312 | TCPServer srv(new TCPServerConnectionFactoryImpl<EchoConnection>(), svs); |
313 | srv.start(); |
314 | assertTrue (srv.currentConnections() == 0); |
315 | assertTrue (srv.currentThreads() == 0); |
316 | assertTrue (srv.queuedConnections() == 0); |
317 | assertTrue (srv.totalConnections() == 0); |
318 | |
319 | Context::Ptr pClientContext = new Context( |
320 | Context::CLIENT_USE, |
321 | Application::instance().config().getString("openSSL.client.privateKeyFile" ), |
322 | Application::instance().config().getString("openSSL.client.privateKeyFile" ), |
323 | Application::instance().config().getString("openSSL.client.caConfig" ), |
324 | Context::VERIFY_RELAXED, |
325 | 9, |
326 | true, |
327 | "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" ); |
328 | pClientContext->enableSessionCache(true); |
329 | |
330 | SocketAddress sa("127.0.0.1" , svs.address().port()); |
331 | SecureStreamSocket ss1(sa, pClientContext); |
332 | assertTrue (!ss1.sessionWasReused()); |
333 | std::string data("hello, world" ); |
334 | ss1.sendBytes(data.data(), (int) data.size()); |
335 | char buffer[256]; |
336 | int n = ss1.receiveBytes(buffer, sizeof(buffer)); |
337 | assertTrue (n > 0); |
338 | assertTrue (std::string(buffer, n) == data); |
339 | assertTrue (srv.currentConnections() == 1); |
340 | assertTrue (srv.currentThreads() == 1); |
341 | assertTrue (srv.queuedConnections() == 0); |
342 | assertTrue (srv.totalConnections() == 1); |
343 | |
344 | Session::Ptr pSession = ss1.currentSession(); |
345 | |
346 | ss1.close(); |
347 | Thread::sleep(300); |
348 | assertTrue (srv.currentConnections() == 0); |
349 | |
350 | ss1.useSession(pSession); |
351 | ss1.connect(sa); |
352 | assertTrue (ss1.sessionWasReused()); |
353 | assertTrue (ss1.currentSession() == pSession); |
354 | ss1.sendBytes(data.data(), (int) data.size()); |
355 | n = ss1.receiveBytes(buffer, sizeof(buffer)); |
356 | assertTrue (n > 0); |
357 | assertTrue (std::string(buffer, n) == data); |
358 | assertTrue (srv.currentConnections() == 1); |
359 | assertTrue (srv.queuedConnections() == 0); |
360 | assertTrue (srv.totalConnections() == 2); |
361 | ss1.close(); |
362 | Thread::sleep(300); |
363 | assertTrue (srv.currentConnections() == 0); |
364 | |
365 | Thread::sleep(15000); // wait for session to expire |
366 | pServerContext->flushSessionCache(); |
367 | |
368 | ss1.useSession(pSession); |
369 | ss1.connect(sa); |
370 | assertTrue (!ss1.sessionWasReused()); |
371 | assertTrue (ss1.currentSession() != pSession); |
372 | ss1.sendBytes(data.data(), (int) data.size()); |
373 | n = ss1.receiveBytes(buffer, sizeof(buffer)); |
374 | assertTrue (n > 0); |
375 | assertTrue (std::string(buffer, n) == data); |
376 | assertTrue (srv.currentConnections() == 1); |
377 | assertTrue (srv.queuedConnections() == 0); |
378 | assertTrue (srv.totalConnections() == 3); |
379 | ss1.close(); |
380 | Thread::sleep(closeSleepTime); |
381 | assertTrue (srv.currentConnections() == 0); |
382 | } |
383 | |
384 | |
385 | void TCPServerTest::setUp() |
386 | { |
387 | } |
388 | |
389 | |
390 | void TCPServerTest::tearDown() |
391 | { |
392 | } |
393 | |
394 | |
395 | CppUnit::Test* TCPServerTest::suite() |
396 | { |
397 | CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("TCPServerTest" ); |
398 | |
399 | CppUnit_addTest(pSuite, TCPServerTest, testOneConnection); |
400 | CppUnit_addTest(pSuite, TCPServerTest, testTwoConnections); |
401 | CppUnit_addTest(pSuite, TCPServerTest, testMultiConnections); |
402 | CppUnit_addTest(pSuite, TCPServerTest, testReuseSocket); |
403 | CppUnit_addTest(pSuite, TCPServerTest, testReuseSession); |
404 | |
405 | return pSuite; |
406 | } |
407 | |