1 | // |
2 | // UDPServerTest.cpp |
3 | // |
4 | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. |
5 | // and Contributors. |
6 | // |
7 | // SPDX-License-Identifier: BSL-1.0 |
8 | // |
9 | |
10 | |
11 | #include "UDPServerTest.h" |
12 | #include "Poco/CppUnit/TestCaller.h" |
13 | #include "Poco/CppUnit/TestSuite.h" |
14 | #include "Poco/Net/UDPServer.h" |
15 | #include "Poco/Net/UDPClient.h" |
16 | #include "Poco/Net/UDPHandler.h" |
17 | #include "Poco/Net/DatagramSocket.h" |
18 | #include "Poco/Net/SocketAddress.h" |
19 | #include "Poco/Net/NetworkInterface.h" |
20 | #include "Poco/Net/NetException.h" |
21 | #include "Poco/Timespan.h" |
22 | #include "Poco/AtomicCounter.h" |
23 | #include "Poco/StringTokenizer.h" |
24 | #include <cstring> |
25 | |
26 | |
27 | using Poco::Net::DatagramSocket; |
28 | using Poco::Net::UDPServer; |
29 | using Poco::Net::UDPClient; |
30 | using Poco::Net::UDPMultiServer; |
31 | using Poco::Net::UDPHandler; |
32 | using Poco::Net::Socket; |
33 | using Poco::Net::SocketBufVec; |
34 | using Poco::Net::SocketAddress; |
35 | using Poco::Timespan; |
36 | using Poco::Thread; |
37 | using Poco::TimeoutException; |
38 | using Poco::InvalidArgumentException; |
39 | using Poco::AtomicCounter; |
40 | using Poco::StringTokenizer; |
41 | |
42 | |
43 | namespace |
44 | { |
45 | struct TestUDPHandler : public Poco::Net::UDPHandler |
46 | { |
47 | TestUDPHandler() : counter(0), errCounter(0) {} |
48 | |
49 | void processData(char *buf) |
50 | { |
51 | if (!addr.empty() && addr != address(buf).toString()) ++errors; |
52 | addr = address(buf).toString(); |
53 | counter = counter.value() + static_cast<AtomicCounter::ValueType>(payload(buf, '\n').count()); |
54 | if (counter % 10) |
55 | { |
56 | if (payload(buf, '\n').count() == 0) ++errors; |
57 | std::memset(buf, 0, blockSize()); |
58 | } |
59 | else // fake error |
60 | { |
61 | errCounter = errCounter.value() + static_cast<AtomicCounter::ValueType>(payload(buf, '\n').count()); |
62 | setError(buf, "error" ); |
63 | processError(buf); |
64 | } |
65 | } |
66 | |
67 | void processError(char *buf) |
68 | { |
69 | if (std::string(error(buf)) != "error" ) ++errors; |
70 | std::memset(buf, 0, blockSize()); |
71 | } |
72 | |
73 | AtomicCounter counter; |
74 | AtomicCounter errCounter; |
75 | static AtomicCounter errors; |
76 | std::string addr; |
77 | }; |
78 | |
79 | AtomicCounter TestUDPHandler::errors; |
80 | |
81 | template<typename S> |
82 | bool server(int handlerCount, int reps, int port = 0) |
83 | { |
84 | Poco::Net::UDPHandler::List handlers; |
85 | for (int i = 0; i < handlerCount; ++i) |
86 | handlers.push_back(new TestUDPHandler()); |
87 | |
88 | S server(handlers, Poco::Net::SocketAddress("127.0.0.1" , port)); |
89 | Poco::Thread::sleep(100); |
90 | |
91 | Poco::Net::UDPClient client("127.0.0.1" , server.port(), true); |
92 | Poco::Thread::sleep(10); |
93 | |
94 | std::vector<std::string> data; |
95 | int i = 0; |
96 | const char *str = "hello\n" ; |
97 | for (; i < reps; ++i) |
98 | { |
99 | data.push_back(str); |
100 | if (data.size() == 230 || i == reps - 1) |
101 | { |
102 | data.back().append(1, '\0'); |
103 | std::size_t sz = (data.size() * strlen(str)) + 1; |
104 | if (sz != client.send(Poco::Net::Socket::makeBufVec(data))) |
105 | return false; |
106 | //Poco::Thread::sleep(10); |
107 | data.clear(); |
108 | } |
109 | } |
110 | |
111 | int count = 0; |
112 | int errCount = 0; |
113 | do |
114 | { |
115 | count = 0; |
116 | errCount = 0; |
117 | Poco::Thread::sleep(10); |
118 | Poco::Net::UDPHandler::Iterator it = handlers.begin(); |
119 | Poco::Net::UDPHandler::Iterator end = handlers.end(); |
120 | for (; it != end; ++it) |
121 | { |
122 | count += dynamic_cast<TestUDPHandler &>(*(*it)).counter.value(); |
123 | errCount += count / 10; |
124 | } |
125 | } while (count < i); |
126 | if (reps != count) return false; |
127 | Poco::Net::UDPHandler::Iterator it = handlers.begin(); |
128 | Poco::Net::UDPHandler::Iterator end = handlers.end(); |
129 | for (; it != end; ++it) |
130 | { |
131 | TestUDPHandler &h = dynamic_cast<TestUDPHandler &>(*(*it)); |
132 | count = h.counter.value(); |
133 | errCount = h.errCounter.value(); |
134 | if (errCount < count / 10) return false; |
135 | if (h.addr.empty() && h.addr != client.address().toString()) |
136 | return false; |
137 | } |
138 | return true; |
139 | } |
140 | } |
141 | |
142 | |
143 | UDPServerTest::UDPServerTest(const std::string& name): CppUnit::TestCase(name) |
144 | { |
145 | } |
146 | |
147 | |
148 | UDPServerTest::~UDPServerTest() |
149 | { |
150 | } |
151 | |
152 | |
153 | void UDPServerTest::testServer() |
154 | { |
155 | int msgs = 10000; |
156 | assertTrue (server<Poco::Net::UDPServer>(1, msgs)); |
157 | assertTrue (server<Poco::Net::UDPMultiServer>(10, msgs, 22080)); |
158 | assertTrue (TestUDPHandler::errors == 0); |
159 | } |
160 | |
161 | |
162 | void UDPServerTest::setUp() |
163 | { |
164 | } |
165 | |
166 | |
167 | void UDPServerTest::tearDown() |
168 | { |
169 | } |
170 | |
171 | |
172 | CppUnit::Test* UDPServerTest::suite() |
173 | { |
174 | CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("UDPServerTest" ); |
175 | |
176 | CppUnit_addTest(pSuite, UDPServerTest, testServer); |
177 | |
178 | return pSuite; |
179 | } |
180 | |