1 | // |
2 | // TCPServer.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: TCPServer |
6 | // Module: TCPServer |
7 | // |
8 | // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/TCPServer.h" |
16 | #include "Poco/Net/TCPServerDispatcher.h" |
17 | #include "Poco/Net/TCPServerConnection.h" |
18 | #include "Poco/Net/TCPServerConnectionFactory.h" |
19 | #include "Poco/Timespan.h" |
20 | #include "Poco/Exception.h" |
21 | #include "Poco/ErrorHandler.h" |
22 | |
23 | |
24 | using Poco::ErrorHandler; |
25 | |
26 | |
27 | namespace Poco { |
28 | namespace Net { |
29 | |
30 | |
31 | // |
32 | // TCPServerConnectionFilter |
33 | // |
34 | |
35 | |
36 | TCPServerConnectionFilter::~TCPServerConnectionFilter() |
37 | { |
38 | } |
39 | |
40 | |
41 | // |
42 | // TCPServer |
43 | // |
44 | |
45 | |
46 | TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, Poco::UInt16 portNumber, TCPServerParams::Ptr pParams): |
47 | _socket(ServerSocket(portNumber)), |
48 | _thread(threadName(_socket)), |
49 | _stopped(true) |
50 | { |
51 | Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool(); |
52 | if (pParams) |
53 | { |
54 | int toAdd = pParams->getMaxThreads() - pool.capacity(); |
55 | if (toAdd > 0) pool.addCapacity(toAdd); |
56 | } |
57 | _pDispatcher = new TCPServerDispatcher(pFactory, pool, pParams); |
58 | |
59 | } |
60 | |
61 | |
62 | TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, const ServerSocket& socket, TCPServerParams::Ptr pParams): |
63 | _socket(socket), |
64 | _thread(threadName(socket)), |
65 | _stopped(true) |
66 | { |
67 | Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool(); |
68 | if (pParams) |
69 | { |
70 | int toAdd = pParams->getMaxThreads() - pool.capacity(); |
71 | if (toAdd > 0) pool.addCapacity(toAdd); |
72 | } |
73 | _pDispatcher = new TCPServerDispatcher(pFactory, pool, pParams); |
74 | } |
75 | |
76 | |
77 | TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, Poco::ThreadPool& threadPool, const ServerSocket& socket, TCPServerParams::Ptr pParams): |
78 | _socket(socket), |
79 | _pDispatcher(new TCPServerDispatcher(pFactory, threadPool, pParams)), |
80 | _thread(threadName(socket)), |
81 | _stopped(true) |
82 | { |
83 | } |
84 | |
85 | |
86 | TCPServer::~TCPServer() |
87 | { |
88 | try |
89 | { |
90 | stop(); |
91 | _pDispatcher->release(); |
92 | } |
93 | catch (...) |
94 | { |
95 | poco_unexpected(); |
96 | } |
97 | } |
98 | |
99 | |
100 | const TCPServerParams& TCPServer::params() const |
101 | { |
102 | return _pDispatcher->params(); |
103 | } |
104 | |
105 | |
106 | void TCPServer::start() |
107 | { |
108 | poco_assert (_stopped); |
109 | |
110 | _stopped = false; |
111 | _thread.start(*this); |
112 | } |
113 | |
114 | |
115 | void TCPServer::stop() |
116 | { |
117 | if (!_stopped) |
118 | { |
119 | _stopped = true; |
120 | _thread.join(); |
121 | _pDispatcher->stop(); |
122 | } |
123 | } |
124 | |
125 | |
126 | void TCPServer::run() |
127 | { |
128 | while (!_stopped) |
129 | { |
130 | Poco::Timespan timeout(250000); |
131 | try |
132 | { |
133 | if (_socket.poll(timeout, Socket::SELECT_READ)) |
134 | { |
135 | try |
136 | { |
137 | StreamSocket ss = _socket.acceptConnection(); |
138 | |
139 | if (!_pConnectionFilter || _pConnectionFilter->accept(ss)) |
140 | { |
141 | // enable nodelay per default: OSX really needs that |
142 | #if defined(POCO_OS_FAMILY_UNIX) |
143 | if (ss.address().family() != AddressFamily::UNIX_LOCAL) |
144 | #endif |
145 | { |
146 | ss.setNoDelay(true); |
147 | } |
148 | _pDispatcher->enqueue(ss); |
149 | } |
150 | } |
151 | catch (Poco::Exception& exc) |
152 | { |
153 | ErrorHandler::handle(exc); |
154 | } |
155 | catch (std::exception& exc) |
156 | { |
157 | ErrorHandler::handle(exc); |
158 | } |
159 | catch (...) |
160 | { |
161 | ErrorHandler::handle(); |
162 | } |
163 | } |
164 | } |
165 | catch (Poco::Exception& exc) |
166 | { |
167 | ErrorHandler::handle(exc); |
168 | // possibly a resource issue since poll() failed; |
169 | // give some time to recover before trying again |
170 | Poco::Thread::sleep(50); |
171 | } |
172 | } |
173 | } |
174 | |
175 | |
176 | int TCPServer::currentThreads() const |
177 | { |
178 | return _pDispatcher->currentThreads(); |
179 | } |
180 | |
181 | |
182 | int TCPServer::maxThreads() const |
183 | { |
184 | return _pDispatcher->maxThreads(); |
185 | } |
186 | |
187 | |
188 | int TCPServer::totalConnections() const |
189 | { |
190 | return _pDispatcher->totalConnections(); |
191 | } |
192 | |
193 | |
194 | int TCPServer::currentConnections() const |
195 | { |
196 | return _pDispatcher->currentConnections(); |
197 | } |
198 | |
199 | |
200 | int TCPServer::maxConcurrentConnections() const |
201 | { |
202 | return _pDispatcher->maxConcurrentConnections(); |
203 | } |
204 | |
205 | |
206 | int TCPServer::queuedConnections() const |
207 | { |
208 | return _pDispatcher->queuedConnections(); |
209 | } |
210 | |
211 | |
212 | int TCPServer::refusedConnections() const |
213 | { |
214 | return _pDispatcher->refusedConnections(); |
215 | } |
216 | |
217 | |
218 | void TCPServer::setConnectionFilter(const TCPServerConnectionFilter::Ptr& pConnectionFilter) |
219 | { |
220 | poco_assert (_stopped); |
221 | |
222 | _pConnectionFilter = pConnectionFilter; |
223 | } |
224 | |
225 | |
226 | std::string TCPServer::threadName(const ServerSocket& socket) |
227 | { |
228 | #if _WIN32_WCE == 0x0800 |
229 | // Workaround for WEC2013: only the first call to getsockname() |
230 | // succeeds. To mitigate the impact of this bug, do not call |
231 | // socket.address(), which calls getsockname(), here. |
232 | std::string name("TCPServer" ); |
233 | #pragma message("Using WEC2013 getsockname() workaround in TCPServer::threadName(). Remove when no longer needed.") |
234 | #else |
235 | std::string name("TCPServer: " ); |
236 | name.append(socket.address().toString()); |
237 | #endif |
238 | return name; |
239 | |
240 | } |
241 | |
242 | |
243 | } } // namespace Poco::Net |
244 | |