1//
2// Socket.cpp
3//
4// Library: Net
5// Package: Sockets
6// Module: Socket
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/Socket.h"
16#include "Poco/Net/StreamSocketImpl.h"
17#include "Poco/Timestamp.h"
18#include <algorithm>
19#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
20#if defined(POCO_HAVE_FD_EPOLL)
21#include <sys/epoll.h>
22#elif defined(POCO_HAVE_FD_POLL)
23#include <poll.h>
24#endif
25
26
27namespace Poco {
28namespace Net {
29
30
31Socket::Socket():
32 _pImpl(new StreamSocketImpl)
33{
34}
35
36
37Socket::Socket(SocketImpl* pImpl):
38 _pImpl(pImpl)
39{
40 poco_check_ptr (_pImpl);
41}
42
43
44Socket::Socket(const Socket& socket):
45 _pImpl(socket._pImpl)
46{
47 poco_check_ptr (_pImpl);
48
49 _pImpl->duplicate();
50}
51
52
53Socket& Socket::operator = (const Socket& socket)
54{
55 if (&socket != this)
56 {
57 if (_pImpl) _pImpl->release();
58 _pImpl = socket._pImpl;
59 if (_pImpl) _pImpl->duplicate();
60 }
61 return *this;
62}
63
64
65Socket::~Socket()
66{
67 _pImpl->release();
68}
69
70
71int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exceptList, const Poco::Timespan& timeout)
72{
73#if defined(POCO_HAVE_FD_EPOLL)
74
75 int epollSize = readList.size() + writeList.size() + exceptList.size();
76 if (epollSize == 0) return 0;
77
78 int epollfd = -1;
79 {
80 struct epoll_event eventsIn[epollSize];
81 memset(eventsIn, 0, sizeof(epoll_event) * epollSize );
82
83 struct epoll_event* eventLast = eventsIn;
84 for (SocketList::iterator it = readList.begin(); it != readList.end(); ++it)
85 {
86 poco_socket_t sockfd = it->sockfd();
87 if (sockfd != POCO_INVALID_SOCKET)
88 {
89 struct epoll_event* e = eventsIn;
90 for (; e != eventLast; ++e)
91 {
92 if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
93 break;
94 }
95 if (e == eventLast)
96 {
97 e->data.ptr = &(*it);
98 ++eventLast;
99 }
100 e->events |= EPOLLIN;
101 }
102 }
103
104 for (SocketList::iterator it = writeList.begin(); it != writeList.end(); ++it)
105 {
106 poco_socket_t sockfd = it->sockfd();
107 if (sockfd != POCO_INVALID_SOCKET)
108 {
109 struct epoll_event* e = eventsIn;
110 for (; e != eventLast; ++e)
111 {
112 if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
113 break;
114 }
115 if (e == eventLast)
116 {
117 e->data.ptr = &(*it);
118 ++eventLast;
119 }
120 e->events |= EPOLLOUT;
121 }
122 }
123
124 for (SocketList::iterator it = exceptList.begin(); it != exceptList.end(); ++it)
125 {
126 poco_socket_t sockfd = it->sockfd();
127 if (sockfd != POCO_INVALID_SOCKET)
128 {
129 struct epoll_event* e = eventsIn;
130 for (; e != eventLast; ++e)
131 {
132 if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
133 break;
134 }
135 if (e == eventLast)
136 {
137 e->data.ptr = &(*it);
138 ++eventLast;
139 }
140 e->events |= EPOLLERR;
141 }
142 }
143
144 epollSize = eventLast - eventsIn;
145 if (epollSize == 0) return 0;
146
147 epollfd = epoll_create(1);
148 if (epollfd < 0)
149 {
150 SocketImpl::error("Can't create epoll queue");
151 }
152
153 for (struct epoll_event* e = eventsIn; e != eventLast; ++e)
154 {
155 poco_socket_t sockfd = reinterpret_cast<Socket*>(e->data.ptr)->sockfd();
156 if (sockfd != POCO_INVALID_SOCKET)
157 {
158 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, e) < 0)
159 {
160 ::close(epollfd);
161 SocketImpl::error("Can't insert socket to epoll queue");
162 }
163 }
164 }
165 }
166
167 struct epoll_event eventsOut[epollSize];
168 memset(eventsOut, 0, sizeof(epoll_event) * epollSize );
169
170 Poco::Timespan remainingTime(timeout);
171 int rc;
172 do
173 {
174 Poco::Timestamp start;
175 rc = epoll_wait(epollfd, eventsOut, epollSize, remainingTime.totalMilliseconds());
176 if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
177 {
178 Poco::Timestamp end;
179 Poco::Timespan waited = end - start;
180 if (waited < remainingTime)
181 remainingTime -= waited;
182 else
183 remainingTime = 0;
184 }
185 }
186 while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
187
188 ::close(epollfd);
189 if (rc < 0) SocketImpl::error();
190
191 SocketList readyReadList;
192 SocketList readyWriteList;
193 SocketList readyExceptList;
194 for (int n = 0; n < rc; ++n)
195 {
196 if (eventsOut[n].events & EPOLLERR)
197 readyExceptList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
198 if (eventsOut[n].events & EPOLLIN)
199 readyReadList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
200 if (eventsOut[n].events & EPOLLOUT)
201 readyWriteList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
202 }
203 std::swap(readList, readyReadList);
204 std::swap(writeList, readyWriteList);
205 std::swap(exceptList, readyExceptList);
206 return readList.size() + writeList.size() + exceptList.size();
207
208#elif defined(POCO_HAVE_FD_POLL)
209 nfds_t nfd = readList.size() + writeList.size() + exceptList.size();
210 if (0 == nfd) return 0;
211
212 std::unique_ptr<pollfd[]> pPollArr(new pollfd[nfd]());
213
214 int idx = 0;
215 for (SocketList::iterator it = readList.begin(); it != readList.end(); ++it)
216 {
217 pPollArr[idx].fd = int(it->sockfd());
218 pPollArr[idx++].events |= POLLIN;
219 }
220
221 SocketList::iterator begR = readList.begin();
222 SocketList::iterator endR = readList.end();
223 for (SocketList::iterator it = writeList.begin(); it != writeList.end(); ++it)
224 {
225 SocketList::iterator pos = std::find(begR, endR, *it);
226 if (pos != endR)
227 {
228 pPollArr[pos-begR].events |= POLLOUT;
229 --nfd;
230 }
231 else
232 {
233 pPollArr[idx].fd = int(it->sockfd());
234 pPollArr[idx++].events |= POLLOUT;
235 }
236 }
237
238 SocketList::iterator begW = writeList.begin();
239 SocketList::iterator endW = writeList.end();
240 for (SocketList::iterator it = exceptList.begin(); it != exceptList.end(); ++it)
241 {
242 SocketList::iterator pos = std::find(begR, endR, *it);
243 if (pos != endR) --nfd;
244 else
245 {
246 SocketList::iterator pos = std::find(begW, endW, *it);
247 if (pos != endW) --nfd;
248 else pPollArr[idx++].fd = int(it->sockfd());
249 }
250 }
251
252 Poco::Timespan remainingTime(timeout);
253 int rc;
254 do
255 {
256 Poco::Timestamp start;
257 rc = ::poll(pPollArr.get(), nfd, remainingTime.totalMilliseconds());
258 if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
259 {
260 Poco::Timestamp end;
261 Poco::Timespan waited = end - start;
262 if (waited < remainingTime) remainingTime -= waited;
263 else remainingTime = 0;
264 }
265 }
266 while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
267 if (rc < 0) SocketImpl::error();
268
269 SocketList readyReadList;
270 SocketList readyWriteList;
271 SocketList readyExceptList;
272
273 SocketList::iterator begE = exceptList.begin();
274 SocketList::iterator endE = exceptList.end();
275 for (int idx = 0; idx < nfd; ++idx)
276 {
277 SocketList::iterator slIt = std::find_if(begR, endR, Socket::FDCompare(pPollArr[idx].fd));
278 if (POLLIN & pPollArr[idx].revents && slIt != endR) readyReadList.push_back(*slIt);
279 slIt = std::find_if(begW, endW, Socket::FDCompare(pPollArr[idx].fd));
280 if (POLLOUT & pPollArr[idx].revents && slIt != endW) readyWriteList.push_back(*slIt);
281 slIt = std::find_if(begE, endE, Socket::FDCompare(pPollArr[idx].fd));
282 if (POLLERR & pPollArr[idx].revents && slIt != endE) readyExceptList.push_back(*slIt);
283 }
284 std::swap(readList, readyReadList);
285 std::swap(writeList, readyWriteList);
286 std::swap(exceptList, readyExceptList);
287 return readList.size() + writeList.size() + exceptList.size();
288
289#else
290
291 fd_set fdRead;
292 fd_set fdWrite;
293 fd_set fdExcept;
294 int nfd = 0;
295 FD_ZERO(&fdRead);
296 for (SocketList::const_iterator it = readList.begin(); it != readList.end(); ++it)
297 {
298 poco_socket_t fd = it->sockfd();
299 if (fd != POCO_INVALID_SOCKET)
300 {
301 if (int(fd) > nfd)
302 nfd = int(fd);
303 FD_SET(fd, &fdRead);
304 }
305 }
306 FD_ZERO(&fdWrite);
307 for (SocketList::const_iterator it = writeList.begin(); it != writeList.end(); ++it)
308 {
309 poco_socket_t fd = it->sockfd();
310 if (fd != POCO_INVALID_SOCKET)
311 {
312 if (int(fd) > nfd)
313 nfd = int(fd);
314 FD_SET(fd, &fdWrite);
315 }
316 }
317 FD_ZERO(&fdExcept);
318 for (SocketList::const_iterator it = exceptList.begin(); it != exceptList.end(); ++it)
319 {
320 poco_socket_t fd = it->sockfd();
321 if (fd != POCO_INVALID_SOCKET)
322 {
323 if (int(fd) > nfd)
324 nfd = int(fd);
325 FD_SET(fd, &fdExcept);
326 }
327 }
328 if (nfd == 0) return 0;
329 Poco::Timespan remainingTime(timeout);
330 int rc;
331 do
332 {
333 struct timeval tv;
334 tv.tv_sec = (long) remainingTime.totalSeconds();
335 tv.tv_usec = (long) remainingTime.useconds();
336 Poco::Timestamp start;
337 rc = ::select(nfd + 1, &fdRead, &fdWrite, &fdExcept, &tv);
338 if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
339 {
340 Poco::Timestamp end;
341 Poco::Timespan waited = end - start;
342 if (waited < remainingTime)
343 remainingTime -= waited;
344 else
345 remainingTime = 0;
346 }
347 }
348 while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
349 if (rc < 0) SocketImpl::error();
350
351 SocketList readyReadList;
352 for (SocketList::const_iterator it = readList.begin(); it != readList.end(); ++it)
353 {
354 poco_socket_t fd = it->sockfd();
355 if (fd != POCO_INVALID_SOCKET)
356 {
357 if (FD_ISSET(fd, &fdRead))
358 readyReadList.push_back(*it);
359 }
360 }
361 std::swap(readList, readyReadList);
362 SocketList readyWriteList;
363 for (SocketList::const_iterator it = writeList.begin(); it != writeList.end(); ++it)
364 {
365 poco_socket_t fd = it->sockfd();
366 if (fd != POCO_INVALID_SOCKET)
367 {
368 if (FD_ISSET(fd, &fdWrite))
369 readyWriteList.push_back(*it);
370 }
371 }
372 std::swap(writeList, readyWriteList);
373 SocketList readyExceptList;
374 for (SocketList::const_iterator it = exceptList.begin(); it != exceptList.end(); ++it)
375 {
376 poco_socket_t fd = it->sockfd();
377 if (fd != POCO_INVALID_SOCKET)
378 {
379 if (FD_ISSET(fd, &fdExcept))
380 readyExceptList.push_back(*it);
381 }
382 }
383 std::swap(exceptList, readyExceptList);
384 return rc;
385
386#endif // POCO_HAVE_FD_EPOLL
387}
388
389
390SocketBufVec Socket::makeBufVec(std::size_t size, std::size_t bufLen)
391{
392 SocketBufVec buf(size);
393 SocketBufVec::iterator it = buf.begin();
394 SocketBufVec::iterator end = buf.end();
395 for (; it != end; ++it)
396 {
397 // TODO: use memory pool
398 *it = makeBuffer(malloc(bufLen), bufLen);
399 }
400 return buf;
401}
402
403
404void Socket::destroyBufVec(SocketBufVec& buf)
405{
406 SocketBufVec::iterator it = buf.begin();
407 SocketBufVec::iterator end = buf.end();
408 for (; it != end; ++it)
409 {
410#if defined(POCO_OS_FAMILY_WINDOWS)
411 free(it->buf);
412#elif defined(POCO_OS_FAMILY_UNIX)
413 free(it->iov_base);
414#endif
415 }
416 SocketBufVec().swap(buf);
417}
418
419
420SocketBuf Socket::makeBuffer(void* buffer, std::size_t length)
421{
422 SocketBuf ret;
423#if defined(POCO_OS_FAMILY_WINDOWS)
424 ret.buf = reinterpret_cast<char*>(buffer);
425 ret.len = static_cast<ULONG>(length);
426#elif defined(POCO_OS_FAMILY_UNIX)
427 ret.iov_base = buffer;
428 ret.iov_len = length;
429#else
430 throw NotImplementedException("Socket::makeBuffer(void*, size_t)");
431#endif
432 return ret;
433}
434
435
436SocketBufVec Socket::makeBufVec(const std::vector<char*>& vec)
437{
438 SocketBufVec buf(vec.size());
439 SocketBufVec::iterator it = buf.begin();
440 SocketBufVec::iterator end = buf.end();
441 std::vector<char*>::const_iterator vIt = vec.begin();
442 for (; it != end; ++it, ++vIt)
443 {
444 *it = makeBuffer(*vIt, strlen(*vIt));
445 }
446 return buf;
447}
448
449
450SocketBufVec Socket::makeBufVec(const std::vector<std::string>& vec)
451{
452 SocketBufVec buf(vec.size());
453 SocketBufVec::iterator it = buf.begin();
454 SocketBufVec::iterator end = buf.end();
455 std::vector<std::string>::const_iterator vIt = vec.begin();
456 for (; it != end; ++it, ++vIt)
457 {
458 char* c = const_cast<char*>(vIt->data());
459 *it = makeBuffer(reinterpret_cast<void*>(c), vIt->size());
460 }
461 return buf;
462}
463
464
465} } // namespace Poco::Net
466