1//
2// SocketImpl.cpp
3//
4// Library: Net
5// Package: Sockets
6// Module: SocketImpl
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/SocketImpl.h"
16#include "Poco/Net/NetException.h"
17#include "Poco/Net/StreamSocketImpl.h"
18#include "Poco/NumberFormatter.h"
19#include "Poco/Timestamp.h"
20#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
21
22
23#if defined(_WIN32) && _WIN32_WINNT >= 0x0600
24#ifndef POCO_HAVE_FD_POLL
25#define POCO_HAVE_FD_POLL 1
26#endif
27#elif defined(POCO_OS_FAMILY_BSD)
28#ifndef POCO_HAVE_FD_POLL
29#define POCO_HAVE_FD_POLL 1
30#endif
31#endif
32
33
34#if defined(POCO_HAVE_FD_EPOLL)
35#include <sys/epoll.h>
36#elif defined(POCO_HAVE_FD_POLL)
37#ifndef _WIN32
38#include <poll.h>
39#endif
40#endif
41
42
43#if defined(sun) || defined(__sun) || defined(__sun__)
44#include <unistd.h>
45#include <stropts.h>
46#endif
47
48
49#ifdef POCO_OS_FAMILY_WINDOWS
50#include <windows.h>
51#endif
52
53
54using Poco::IOException;
55using Poco::TimeoutException;
56using Poco::InvalidArgumentException;
57using Poco::NumberFormatter;
58using Poco::Timespan;
59
60
61namespace Poco {
62namespace Net {
63
64
65bool checkIsBrokenTimeout()
66{
67#if defined(POCO_BROKEN_TIMEOUTS)
68 return true;
69#elif defined(POCO_OS_FAMILY_WINDOWS)
70 // on Windows 7 and lower, socket timeouts have a minimum of 500ms, use poll for timeouts on this case
71 // https://social.msdn.microsoft.com/Forums/en-US/76620f6d-22b1-4872-aaf0-833204f3f867/minimum-timeout-value-for-sorcvtimeo
72 OSVERSIONINFO vi;
73 vi.dwOSVersionInfoSize = sizeof(vi);
74 if (GetVersionEx(&vi) == 0) return true;
75 return vi.dwMajorVersion < 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion < 2);
76#else
77 return false;
78#endif
79}
80
81
82SocketImpl::SocketImpl():
83 _sockfd(POCO_INVALID_SOCKET),
84 _blocking(true),
85 _isBrokenTimeout(checkIsBrokenTimeout())
86{
87}
88
89
90SocketImpl::SocketImpl(poco_socket_t sockfd):
91 _sockfd(sockfd),
92 _blocking(true),
93 _isBrokenTimeout(checkIsBrokenTimeout())
94{
95}
96
97
98SocketImpl::~SocketImpl()
99{
100 close();
101}
102
103
104SocketImpl* SocketImpl::acceptConnection(SocketAddress& clientAddr)
105{
106 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
107
108 sockaddr_storage buffer;
109 struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(&buffer);
110 poco_socklen_t saLen = sizeof(buffer);
111 poco_socket_t sd;
112 do
113 {
114 sd = ::accept(_sockfd, pSA, &saLen);
115 }
116 while (sd == POCO_INVALID_SOCKET && lastError() == POCO_EINTR);
117 if (sd != POCO_INVALID_SOCKET)
118 {
119 clientAddr = SocketAddress(pSA, saLen);
120 return new StreamSocketImpl(sd);
121 }
122 error(); // will throw
123 return 0;
124}
125
126
127void SocketImpl::connect(const SocketAddress& address)
128{
129 if (_sockfd == POCO_INVALID_SOCKET)
130 {
131 init(address.af());
132 }
133 int rc;
134 do
135 {
136#if defined(POCO_VXWORKS)
137 rc = ::connect(_sockfd, (sockaddr*) address.addr(), address.length());
138#else
139 rc = ::connect(_sockfd, address.addr(), address.length());
140#endif
141 }
142 while (rc != 0 && lastError() == POCO_EINTR);
143 if (rc != 0)
144 {
145 int err = lastError();
146 error(err, address.toString());
147 }
148}
149
150
151void SocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
152{
153 if (_sockfd == POCO_INVALID_SOCKET)
154 {
155 init(address.af());
156 }
157 setBlocking(false);
158 try
159 {
160#if defined(POCO_VXWORKS)
161 int rc = ::connect(_sockfd, (sockaddr*) address.addr(), address.length());
162#else
163 int rc = ::connect(_sockfd, address.addr(), address.length());
164#endif
165 if (rc != 0)
166 {
167 int err = lastError();
168 if (err != POCO_EINPROGRESS && err != POCO_EWOULDBLOCK)
169 error(err, address.toString());
170 if (!poll(timeout, SELECT_READ | SELECT_WRITE | SELECT_ERROR))
171 throw Poco::TimeoutException("connect timed out", address.toString());
172 err = socketError();
173 if (err != 0) error(err);
174 }
175 }
176 catch (Poco::Exception&)
177 {
178 setBlocking(true);
179 throw;
180 }
181 setBlocking(true);
182}
183
184
185void SocketImpl::connectNB(const SocketAddress& address)
186{
187 if (_sockfd == POCO_INVALID_SOCKET)
188 {
189 init(address.af());
190 }
191 setBlocking(false);
192#if defined(POCO_VXWORKS)
193 int rc = ::connect(_sockfd, (sockaddr*) address.addr(), address.length());
194#else
195 int rc = ::connect(_sockfd, address.addr(), address.length());
196#endif
197 if (rc != 0)
198 {
199 int err = lastError();
200 if (err != POCO_EINPROGRESS && err != POCO_EWOULDBLOCK)
201 error(err, address.toString());
202 }
203}
204
205
206void SocketImpl::bind(const SocketAddress& address, bool reuseAddress)
207{
208 bind(address, reuseAddress, true);
209}
210
211
212void SocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
213{
214 if (_sockfd == POCO_INVALID_SOCKET)
215 {
216 init(address.af());
217 }
218 if (reuseAddress)
219 setReuseAddress(true);
220 if (reusePort)
221 setReusePort(true);
222#if defined(POCO_VXWORKS)
223 int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length());
224#else
225 int rc = ::bind(_sockfd, address.addr(), address.length());
226#endif
227 if (rc != 0) error(address.toString());
228}
229
230
231void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
232{
233 bind6(address, reuseAddress, true, ipV6Only);
234}
235
236
237void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
238{
239#if defined(POCO_HAVE_IPv6)
240 if (address.family() != SocketAddress::IPv6)
241 throw Poco::InvalidArgumentException("SocketAddress must be an IPv6 address");
242
243 if (_sockfd == POCO_INVALID_SOCKET)
244 {
245 init(address.af());
246 }
247#ifdef IPV6_V6ONLY
248 setOption(IPPROTO_IPV6, IPV6_V6ONLY, ipV6Only ? 1 : 0);
249#else
250 if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined.");
251#endif
252 if (reuseAddress)
253 setReuseAddress(true);
254 if (reusePort)
255 setReusePort(true);
256 int rc = ::bind(_sockfd, address.addr(), address.length());
257 if (rc != 0) error(address.toString());
258#else
259 throw Poco::NotImplementedException("No IPv6 support available");
260#endif
261}
262
263
264void SocketImpl::listen(int backlog)
265{
266 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
267
268 int rc = ::listen(_sockfd, backlog);
269 if (rc != 0) error();
270}
271
272
273void SocketImpl::close()
274{
275 if (_sockfd != POCO_INVALID_SOCKET)
276 {
277 poco_closesocket(_sockfd);
278 _sockfd = POCO_INVALID_SOCKET;
279 }
280}
281
282
283void SocketImpl::shutdownReceive()
284{
285 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
286
287 int rc = ::shutdown(_sockfd, 0);
288 if (rc != 0) error();
289}
290
291
292void SocketImpl::shutdownSend()
293{
294 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
295
296 int rc = ::shutdown(_sockfd, 1);
297 if (rc != 0) error();
298}
299
300
301void SocketImpl::shutdown()
302{
303 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
304
305 int rc = ::shutdown(_sockfd, 2);
306 if (rc != 0) error();
307}
308
309
310void SocketImpl::checkBrokenTimeout(const SelectMode& mode)
311{
312 if (_isBrokenTimeout)
313 {
314 Poco::Timespan timeout = (mode == SelectMode::SELECT_READ) ? _recvTimeout : _sndTimeout;
315 if (timeout.totalMicroseconds() != 0)
316 {
317 if (!poll(timeout, mode))
318 throw TimeoutException();
319 }
320 }
321}
322
323
324int SocketImpl::sendBytes(const void* buffer, int length, int flags)
325{
326 checkBrokenTimeout(SELECT_WRITE);
327
328 int rc;
329 do
330 {
331 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
332 rc = ::send(_sockfd, reinterpret_cast<const char*>(buffer), length, flags);
333 }
334 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
335 if (rc < 0) error();
336 return rc;
337}
338
339
340int SocketImpl::sendBytes(const SocketBufVec& buffers, int flags)
341{
342 checkBrokenTimeout(SELECT_WRITE);
343
344 int rc = 0;
345 do
346 {
347 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
348#if defined(POCO_OS_FAMILY_WINDOWS)
349 DWORD sent = 0;
350 rc = WSASend(_sockfd, const_cast<LPWSABUF>(&buffers[0]),
351 static_cast<DWORD>(buffers.size()), &sent,
352 static_cast<DWORD>(flags), 0, 0);
353 if (rc == SOCKET_ERROR) error();
354 rc = sent;
355#elif defined(POCO_OS_FAMILY_UNIX)
356 rc = writev(_sockfd, &buffers[0], static_cast<int>(buffers.size()));
357#endif
358 }
359 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
360 if (rc < 0) error();
361 return rc;
362}
363
364
365int SocketImpl::receiveBytes(void* buffer, int length, int flags)
366{
367 checkBrokenTimeout(SELECT_READ);
368
369 int rc;
370 do
371 {
372 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
373 rc = ::recv(_sockfd, reinterpret_cast<char*>(buffer), length, flags);
374 }
375 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
376 if (rc < 0)
377 {
378 int err = lastError();
379 if (err == POCO_EAGAIN && !_blocking)
380 ;
381 else if (err == POCO_EAGAIN || err == POCO_ETIMEDOUT)
382 throw TimeoutException(err);
383 else
384 error(err);
385 }
386 return rc;
387}
388
389
390int SocketImpl::receiveBytes(SocketBufVec& buffers, int flags)
391{
392 checkBrokenTimeout(SELECT_READ);
393
394 int rc = 0;
395 do
396 {
397 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
398#if defined(POCO_OS_FAMILY_WINDOWS)
399 DWORD recvd = 0;
400 DWORD dwFlags = static_cast<DWORD>(flags);
401 rc = WSARecv(_sockfd, &buffers[0], static_cast<DWORD>(buffers.size()),
402 &recvd, &dwFlags, 0, 0);
403 if (rc == SOCKET_ERROR) error();
404 rc = recvd;
405#elif defined(POCO_OS_FAMILY_UNIX)
406 rc = readv(_sockfd, &buffers[0], static_cast<int>(buffers.size()));
407#endif
408 }
409 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
410 if (rc < 0)
411 {
412 int err = lastError();
413 if (err == POCO_EAGAIN && !_blocking)
414 ;
415 else if (err == POCO_EAGAIN || err == POCO_ETIMEDOUT)
416 throw TimeoutException(err);
417 else
418 error(err);
419 }
420 return rc;
421}
422
423
424int SocketImpl::receiveBytes(Poco::Buffer<char>& buffer, int flags, const Poco::Timespan& timeout)
425{
426 int rc = 0;
427 if (poll(timeout, SELECT_READ))
428 {
429 int avail = available();
430 if (buffer.size() < avail) buffer.resize(avail);
431
432 do
433 {
434 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
435 rc = ::recv(_sockfd, buffer.begin(), static_cast<int>(buffer.size()), flags);
436 }
437 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
438 if (rc < 0)
439 {
440 int err = lastError();
441 if (err == POCO_EAGAIN && !_blocking)
442 ;
443 else if (err == POCO_EAGAIN || err == POCO_ETIMEDOUT)
444 throw TimeoutException(err);
445 else
446 error(err);
447 }
448 if (rc < buffer.size()) buffer.resize(rc);
449 }
450 return rc;
451}
452
453
454int SocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
455{
456 int rc;
457 do
458 {
459 if (_sockfd == POCO_INVALID_SOCKET) init(address.af());
460#if defined(POCO_VXWORKS)
461 rc = ::sendto(_sockfd, (char*) buffer, length, flags, (sockaddr*) address.addr(), address.length());
462#else
463 rc = ::sendto(_sockfd, reinterpret_cast<const char*>(buffer), length, flags, address.addr(), address.length());
464#endif
465 }
466 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
467 if (rc < 0) error();
468 return rc;
469}
470
471
472int SocketImpl::sendTo(const SocketBufVec& buffers, const SocketAddress& address, int flags)
473{
474 int rc = 0;
475 do
476 {
477 if (_sockfd == POCO_INVALID_SOCKET) init(address.af());
478#if defined(POCO_OS_FAMILY_WINDOWS)
479 DWORD sent = 0;
480 rc = WSASendTo(_sockfd, const_cast<LPWSABUF>(&buffers[0]),
481 static_cast<DWORD>(buffers.size()), &sent,
482 static_cast<DWORD>(flags),
483 address.addr(), address.length(), 0, 0);
484 if (rc == SOCKET_ERROR) error();
485 rc = sent;
486#elif defined(POCO_OS_FAMILY_UNIX)
487 struct msghdr msgHdr;
488 msgHdr.msg_name = const_cast<sockaddr*>(address.addr());
489 msgHdr.msg_namelen = address.length();
490 msgHdr.msg_iov = const_cast<iovec*>(&buffers[0]);
491 msgHdr.msg_iovlen = buffers.size();
492 msgHdr.msg_control = 0;
493 msgHdr.msg_controllen = 0;
494 msgHdr.msg_flags = flags;
495 rc = sendmsg(_sockfd, &msgHdr, flags);
496#endif
497 }
498 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
499 if (rc < 0) error();
500 return rc;
501}
502
503
504int SocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
505{
506 sockaddr_storage abuffer;
507 struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(&abuffer);
508 poco_socklen_t saLen = sizeof(abuffer);
509 poco_socklen_t* pSALen = &saLen;
510 int rc = receiveFrom(buffer, length, &pSA, &pSALen, flags);
511 if (rc >= 0)
512 {
513 address = SocketAddress(pSA, saLen);
514 }
515 return rc;
516}
517
518
519int SocketImpl::receiveFrom(void* buffer, int length, struct sockaddr** ppSA, poco_socklen_t** ppSALen, int flags)
520{
521 checkBrokenTimeout(SELECT_READ);
522 int rc;
523 do
524 {
525 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
526 rc = ::recvfrom(_sockfd, reinterpret_cast<char*>(buffer), length, flags, *ppSA, *ppSALen);
527 }
528 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
529 if (rc < 0)
530 {
531 int err = lastError();
532 if (err == POCO_EAGAIN && !_blocking)
533 ;
534 else if (err == POCO_EAGAIN || err == POCO_ETIMEDOUT)
535 throw TimeoutException(err);
536 else
537 error(err);
538 }
539 return rc;
540}
541
542
543int SocketImpl::receiveFrom(SocketBufVec& buffers, SocketAddress& address, int flags)
544{
545 sockaddr_storage abuffer;
546 struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(&abuffer);
547 poco_socklen_t saLen = sizeof(abuffer);
548 poco_socklen_t* pSALen = &saLen;
549 int rc = receiveFrom(buffers, &pSA, &pSALen, flags);
550 if(rc >= 0)
551 {
552 address = SocketAddress(pSA, saLen);
553 }
554 return rc;
555}
556
557
558int SocketImpl::receiveFrom(SocketBufVec& buffers, struct sockaddr** pSA, poco_socklen_t** ppSALen, int flags)
559{
560 checkBrokenTimeout(SELECT_READ);
561 int rc = 0;
562 do
563 {
564 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
565#if defined(POCO_OS_FAMILY_WINDOWS)
566 DWORD recvd = 0;
567 DWORD dwFlags = static_cast<DWORD>(flags);
568 rc = WSARecvFrom(_sockfd, &buffers[0], static_cast<DWORD>(buffers.size()),
569 &recvd, &dwFlags, *pSA, *ppSALen, 0, 0);
570 if (rc == SOCKET_ERROR) error();
571 rc = recvd;
572#elif defined(POCO_OS_FAMILY_UNIX)
573 struct msghdr msgHdr;
574 msgHdr.msg_name = *pSA;
575 msgHdr.msg_namelen = **ppSALen;
576 msgHdr.msg_iov = &buffers[0];
577 msgHdr.msg_iovlen = buffers.size();
578 msgHdr.msg_control = 0;
579 msgHdr.msg_controllen = 0;
580 msgHdr.msg_flags = flags;
581 rc = recvmsg(_sockfd, &msgHdr, flags);
582 if (rc >= 0) **ppSALen = msgHdr.msg_namelen;
583#endif
584 }
585 while (_blocking && rc < 0 && lastError() == POCO_EINTR);
586 if (rc < 0)
587 {
588 int err = lastError();
589 if (err == POCO_EAGAIN && !_blocking)
590 ;
591 else if (err == POCO_EAGAIN || err == POCO_ETIMEDOUT)
592 throw TimeoutException(err);
593 else
594 error(err);
595 }
596 return rc;
597}
598
599
600void SocketImpl::sendUrgent(unsigned char data)
601{
602 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
603
604 int rc = ::send(_sockfd, reinterpret_cast<const char*>(&data), sizeof(data), MSG_OOB);
605 if (rc < 0) error();
606}
607
608
609int SocketImpl::available()
610{
611 int result = 0;
612 ioctl(FIONREAD, result);
613 return result;
614}
615
616
617bool SocketImpl::secure() const
618{
619 return false;
620}
621
622
623bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
624{
625 poco_socket_t sockfd = _sockfd;
626 if (sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
627
628#if defined(POCO_HAVE_FD_EPOLL)
629
630 int epollfd = epoll_create(1);
631 if (epollfd < 0)
632 {
633 error("Can't create epoll queue");
634 }
635
636 struct epoll_event evin;
637 memset(&evin, 0, sizeof(evin));
638
639 if (mode & SELECT_READ)
640 evin.events |= EPOLLIN;
641 if (mode & SELECT_WRITE)
642 evin.events |= EPOLLOUT;
643 if (mode & SELECT_ERROR)
644 evin.events |= EPOLLERR;
645
646 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &evin) < 0)
647 {
648 ::close(epollfd);
649 error("Can't insert socket to epoll queue");
650 }
651
652 Poco::Timespan remainingTime(timeout);
653 int rc;
654 do
655 {
656 struct epoll_event evout;
657 memset(&evout, 0, sizeof(evout));
658
659 Poco::Timestamp start;
660 rc = epoll_wait(epollfd, &evout, 1, remainingTime.totalMilliseconds());
661 if (rc < 0 && lastError() == POCO_EINTR)
662 {
663 Poco::Timestamp end;
664 Poco::Timespan waited = end - start;
665 if (waited < remainingTime)
666 remainingTime -= waited;
667 else
668 remainingTime = 0;
669 }
670 }
671 while (rc < 0 && lastError() == POCO_EINTR);
672
673 ::close(epollfd);
674 if (rc < 0) error();
675 return rc > 0;
676
677#elif defined(POCO_HAVE_FD_POLL)
678
679 pollfd pollBuf;
680
681 memset(&pollBuf, 0, sizeof(pollfd));
682 pollBuf.fd = _sockfd;
683 if (mode & SELECT_READ) pollBuf.events |= POLLIN;
684 if (mode & SELECT_WRITE) pollBuf.events |= POLLOUT;
685
686 Poco::Timespan remainingTime(timeout);
687 int rc;
688 do
689 {
690 Poco::Timestamp start;
691#ifdef _WIN32
692 rc = WSAPoll(&pollBuf, 1, static_cast<INT>(timeout.totalMilliseconds()));
693#else
694 rc = ::poll(&pollBuf, 1, remainingTime.totalMilliseconds());
695#endif
696 if (rc < 0 && lastError() == POCO_EINTR)
697 {
698 Poco::Timestamp end;
699 Poco::Timespan waited = end - start;
700 if (waited < remainingTime)
701 remainingTime -= waited;
702 else
703 remainingTime = 0;
704 }
705 }
706 while (rc < 0 && lastError() == POCO_EINTR);
707 if (rc < 0) error();
708 return rc > 0;
709
710#else
711
712 fd_set fdRead;
713 fd_set fdWrite;
714 fd_set fdExcept;
715 FD_ZERO(&fdRead);
716 FD_ZERO(&fdWrite);
717 FD_ZERO(&fdExcept);
718 if (mode & SELECT_READ)
719 {
720 FD_SET(sockfd, &fdRead);
721 }
722 if (mode & SELECT_WRITE)
723 {
724 FD_SET(sockfd, &fdWrite);
725 }
726 if (mode & SELECT_ERROR)
727 {
728 FD_SET(sockfd, &fdExcept);
729 }
730 Poco::Timespan remainingTime(timeout);
731 int errorCode = POCO_ENOERR;
732 int rc;
733 do
734 {
735 struct timeval tv;
736 tv.tv_sec = (long) remainingTime.totalSeconds();
737 tv.tv_usec = (long) remainingTime.useconds();
738 Poco::Timestamp start;
739 rc = ::select(int(sockfd) + 1, &fdRead, &fdWrite, &fdExcept, &tv);
740 if (rc < 0 && (errorCode = lastError()) == POCO_EINTR)
741 {
742 Poco::Timestamp end;
743 Poco::Timespan waited = end - start;
744 if (waited < remainingTime)
745 remainingTime -= waited;
746 else
747 remainingTime = 0;
748 }
749 }
750 while (rc < 0 && errorCode == POCO_EINTR);
751 if (rc < 0) error(errorCode);
752 return rc > 0;
753
754#endif // POCO_HAVE_FD_EPOLL
755}
756
757
758void SocketImpl::setSendBufferSize(int size)
759{
760 setOption(SOL_SOCKET, SO_SNDBUF, size);
761}
762
763
764int SocketImpl::getSendBufferSize()
765{
766 int result;
767 getOption(SOL_SOCKET, SO_SNDBUF, result);
768 return result;
769}
770
771
772void SocketImpl::setReceiveBufferSize(int size)
773{
774 setOption(SOL_SOCKET, SO_RCVBUF, size);
775}
776
777
778int SocketImpl::getReceiveBufferSize()
779{
780 int result;
781 getOption(SOL_SOCKET, SO_RCVBUF, result);
782 return result;
783}
784
785
786void SocketImpl::setSendTimeout(const Poco::Timespan& timeout)
787{
788#if defined(_WIN32) && !defined(POCO_BROKEN_TIMEOUTS)
789 int value = (int) timeout.totalMilliseconds();
790 setOption(SOL_SOCKET, SO_SNDTIMEO, value);
791#elif !defined(POCO_BROKEN_TIMEOUTS)
792 setOption(SOL_SOCKET, SO_SNDTIMEO, timeout);
793#endif
794 if (_isBrokenTimeout)
795 _sndTimeout = timeout;
796}
797
798
799Poco::Timespan SocketImpl::getSendTimeout()
800{
801 Timespan result;
802#if defined(_WIN32) && !defined(POCO_BROKEN_TIMEOUTS)
803 int value;
804 getOption(SOL_SOCKET, SO_SNDTIMEO, value);
805 result = Timespan::TimeDiff(value)*1000;
806#elif !defined(POCO_BROKEN_TIMEOUTS)
807 getOption(SOL_SOCKET, SO_SNDTIMEO, result);
808#endif
809 if (_isBrokenTimeout)
810 result = _sndTimeout;
811 return result;
812}
813
814
815void SocketImpl::setReceiveTimeout(const Poco::Timespan& timeout)
816{
817#ifndef POCO_BROKEN_TIMEOUTS
818#if defined(_WIN32)
819 int value = (int) timeout.totalMilliseconds();
820 setOption(SOL_SOCKET, SO_RCVTIMEO, value);
821#else
822 setOption(SOL_SOCKET, SO_RCVTIMEO, timeout);
823#endif
824#endif
825 if (_isBrokenTimeout)
826 _recvTimeout = timeout;
827}
828
829
830Poco::Timespan SocketImpl::getReceiveTimeout()
831{
832 Timespan result;
833#if defined(_WIN32) && !defined(POCO_BROKEN_TIMEOUTS)
834 int value;
835 getOption(SOL_SOCKET, SO_RCVTIMEO, value);
836 result = Timespan::TimeDiff(value)*1000;
837#elif !defined(POCO_BROKEN_TIMEOUTS)
838 getOption(SOL_SOCKET, SO_RCVTIMEO, result);
839#endif
840 if (_isBrokenTimeout)
841 result = _recvTimeout;
842 return result;
843}
844
845
846SocketAddress SocketImpl::address()
847{
848 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
849
850 sockaddr_storage buffer;
851 struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(&buffer);
852 poco_socklen_t saLen = sizeof(buffer);
853 int rc = ::getsockname(_sockfd, pSA, &saLen);
854 if (rc == 0)
855 return SocketAddress(pSA, saLen);
856 else
857 error();
858 return SocketAddress();
859}
860
861
862SocketAddress SocketImpl::peerAddress()
863{
864 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
865
866 sockaddr_storage buffer;
867 struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(&buffer);
868 poco_socklen_t saLen = sizeof(buffer);
869 int rc = ::getpeername(_sockfd, pSA, &saLen);
870 if (rc == 0)
871 return SocketAddress(pSA, saLen);
872 else
873 error();
874 return SocketAddress();
875}
876
877
878void SocketImpl::setOption(int level, int option, int value)
879{
880 setRawOption(level, option, &value, sizeof(value));
881}
882
883
884void SocketImpl::setOption(int level, int option, unsigned value)
885{
886 setRawOption(level, option, &value, sizeof(value));
887}
888
889
890void SocketImpl::setOption(int level, int option, unsigned char value)
891{
892 setRawOption(level, option, &value, sizeof(value));
893}
894
895
896void SocketImpl::setOption(int level, int option, const IPAddress& value)
897{
898 setRawOption(level, option, value.addr(), value.length());
899}
900
901
902void SocketImpl::setOption(int level, int option, const Poco::Timespan& value)
903{
904 struct timeval tv;
905 tv.tv_sec = (long) value.totalSeconds();
906 tv.tv_usec = (long) value.useconds();
907
908 setRawOption(level, option, &tv, sizeof(tv));
909}
910
911
912void SocketImpl::setRawOption(int level, int option, const void* value, poco_socklen_t length)
913{
914 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
915
916#if defined(POCO_VXWORKS)
917 int rc = ::setsockopt(_sockfd, level, option, (char*) value, length);
918#else
919 int rc = ::setsockopt(_sockfd, level, option, reinterpret_cast<const char*>(value), length);
920#endif
921 if (rc == -1) error();
922}
923
924
925void SocketImpl::getOption(int level, int option, int& value)
926{
927 poco_socklen_t len = sizeof(value);
928 getRawOption(level, option, &value, len);
929}
930
931
932void SocketImpl::getOption(int level, int option, unsigned& value)
933{
934 poco_socklen_t len = sizeof(value);
935 getRawOption(level, option, &value, len);
936}
937
938
939void SocketImpl::getOption(int level, int option, unsigned char& value)
940{
941 poco_socklen_t len = sizeof(value);
942 getRawOption(level, option, &value, len);
943}
944
945
946void SocketImpl::getOption(int level, int option, Poco::Timespan& value)
947{
948 struct timeval tv;
949 poco_socklen_t len = sizeof(tv);
950 getRawOption(level, option, &tv, len);
951 value.assign(tv.tv_sec, tv.tv_usec);
952}
953
954
955void SocketImpl::getOption(int level, int option, IPAddress& value)
956{
957 char buffer[IPAddress::MAX_ADDRESS_LENGTH];
958 poco_socklen_t len = sizeof(buffer);
959 getRawOption(level, option, buffer, len);
960 value = IPAddress(buffer, len);
961}
962
963
964void SocketImpl::getRawOption(int level, int option, void* value, poco_socklen_t& length)
965{
966 if (_sockfd == POCO_INVALID_SOCKET) throw InvalidSocketException();
967
968 int rc = ::getsockopt(_sockfd, level, option, reinterpret_cast<char*>(value), &length);
969 if (rc == -1) error();
970}
971
972
973void SocketImpl::setLinger(bool on, int seconds)
974{
975 struct linger l;
976 l.l_onoff = on ? 1 : 0;
977 l.l_linger = static_cast<u_short>(seconds);
978 setRawOption(SOL_SOCKET, SO_LINGER, &l, sizeof(l));
979}
980
981
982void SocketImpl::getLinger(bool& on, int& seconds)
983{
984 struct linger l;
985 poco_socklen_t len = sizeof(l);
986 getRawOption(SOL_SOCKET, SO_LINGER, &l, len);
987 on = l.l_onoff != 0;
988 seconds = l.l_linger;
989}
990
991
992void SocketImpl::setNoDelay(bool flag)
993{
994 int value = flag ? 1 : 0;
995 setOption(IPPROTO_TCP, TCP_NODELAY, value);
996}
997
998
999bool SocketImpl::getNoDelay()
1000{
1001 int value(0);
1002 getOption(IPPROTO_TCP, TCP_NODELAY, value);
1003 return value != 0;
1004}
1005
1006
1007void SocketImpl::setKeepAlive(bool flag)
1008{
1009 int value = flag ? 1 : 0;
1010 setOption(SOL_SOCKET, SO_KEEPALIVE, value);
1011}
1012
1013
1014bool SocketImpl::getKeepAlive()
1015{
1016 int value(0);
1017 getOption(SOL_SOCKET, SO_KEEPALIVE, value);
1018 return value != 0;
1019}
1020
1021
1022void SocketImpl::setReuseAddress(bool flag)
1023{
1024 int value = flag ? 1 : 0;
1025 setOption(SOL_SOCKET, SO_REUSEADDR, value);
1026}
1027
1028
1029bool SocketImpl::getReuseAddress()
1030{
1031 int value(0);
1032 getOption(SOL_SOCKET, SO_REUSEADDR, value);
1033 return value != 0;
1034}
1035
1036
1037void SocketImpl::setReusePort(bool flag)
1038{
1039#ifdef SO_REUSEPORT
1040 try
1041 {
1042 int value = flag ? 1 : 0;
1043 setOption(SOL_SOCKET, SO_REUSEPORT, value);
1044 }
1045 catch (IOException&)
1046 {
1047 // ignore error, since not all implementations
1048 // support SO_REUSEPORT, even if the macro
1049 // is defined.
1050 }
1051#else
1052 (void)flag;
1053#endif
1054}
1055
1056
1057bool SocketImpl::getReusePort()
1058{
1059#ifdef SO_REUSEPORT
1060 int value(0);
1061 getOption(SOL_SOCKET, SO_REUSEPORT, value);
1062 return value != 0;
1063#else
1064 return false;
1065#endif
1066}
1067
1068
1069void SocketImpl::setOOBInline(bool flag)
1070{
1071 int value = flag ? 1 : 0;
1072 setOption(SOL_SOCKET, SO_OOBINLINE, value);
1073}
1074
1075
1076bool SocketImpl::getOOBInline()
1077{
1078 int value(0);
1079 getOption(SOL_SOCKET, SO_OOBINLINE, value);
1080 return value != 0;
1081}
1082
1083
1084void SocketImpl::setBroadcast(bool flag)
1085{
1086 int value = flag ? 1 : 0;
1087 setOption(SOL_SOCKET, SO_BROADCAST, value);
1088}
1089
1090
1091bool SocketImpl::getBroadcast()
1092{
1093 int value(0);
1094 getOption(SOL_SOCKET, SO_BROADCAST, value);
1095 return value != 0;
1096}
1097
1098
1099void SocketImpl::setBlocking(bool flag)
1100{
1101#if !defined(POCO_OS_FAMILY_UNIX)
1102 int arg = flag ? 0 : 1;
1103 ioctl(FIONBIO, arg);
1104#else
1105 int arg = fcntl(F_GETFL);
1106 long flags = arg & ~O_NONBLOCK;
1107 if (!flag) flags |= O_NONBLOCK;
1108 (void) fcntl(F_SETFL, flags);
1109#endif
1110 _blocking = flag;
1111}
1112
1113
1114int SocketImpl::socketError()
1115{
1116 int result(0);
1117 getOption(SOL_SOCKET, SO_ERROR, result);
1118 return result;
1119}
1120
1121
1122void SocketImpl::init(int af)
1123{
1124 initSocket(af, SOCK_STREAM);
1125}
1126
1127
1128void SocketImpl::initSocket(int af, int type, int proto)
1129{
1130 poco_assert (_sockfd == POCO_INVALID_SOCKET);
1131
1132 _sockfd = ::socket(af, type, proto);
1133 if (_sockfd == POCO_INVALID_SOCKET)
1134 error();
1135
1136#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
1137 // SIGPIPE sends a signal that if unhandled (which is the default)
1138 // will crash the process. This only happens on UNIX, and not Linux.
1139 //
1140 // In order to have POCO sockets behave the same across platforms, it is
1141 // best to just ignore SIGPIPE altogether.
1142 setOption(SOL_SOCKET, SO_NOSIGPIPE, 1);
1143#endif
1144}
1145
1146
1147void SocketImpl::ioctl(poco_ioctl_request_t request, int& arg)
1148{
1149#if defined(_WIN32)
1150 int rc = ioctlsocket(_sockfd, request, reinterpret_cast<u_long*>(&arg));
1151#elif defined(POCO_VXWORKS)
1152 int rc = ::ioctl(_sockfd, request, (int) &arg);
1153#else
1154 int rc = ::ioctl(_sockfd, request, &arg);
1155#endif
1156 if (rc != 0) error();
1157}
1158
1159
1160void SocketImpl::ioctl(poco_ioctl_request_t request, void* arg)
1161{
1162#if defined(_WIN32)
1163 int rc = ioctlsocket(_sockfd, request, reinterpret_cast<u_long*>(arg));
1164#elif defined(POCO_VXWORKS)
1165 int rc = ::ioctl(_sockfd, request, (int) arg);
1166#else
1167 int rc = ::ioctl(_sockfd, request, arg);
1168#endif
1169 if (rc != 0) error();
1170}
1171
1172
1173#if defined(POCO_OS_FAMILY_UNIX)
1174int SocketImpl::fcntl(poco_fcntl_request_t request)
1175{
1176 int rc = ::fcntl(_sockfd, request);
1177 if (rc == -1) error();
1178 return rc;
1179}
1180
1181
1182int SocketImpl::fcntl(poco_fcntl_request_t request, long arg)
1183{
1184 int rc = ::fcntl(_sockfd, request, arg);
1185 if (rc == -1) error();
1186 return rc;
1187}
1188#endif
1189
1190
1191void SocketImpl::reset(poco_socket_t aSocket)
1192{
1193 _sockfd = aSocket;
1194}
1195
1196
1197void SocketImpl::error()
1198{
1199 int err = lastError();
1200 std::string empty;
1201 error(err, empty);
1202}
1203
1204
1205void SocketImpl::error(const std::string& arg)
1206{
1207 error(lastError(), arg);
1208}
1209
1210
1211void SocketImpl::error(int code)
1212{
1213 std::string arg;
1214 error(code, arg);
1215}
1216
1217
1218void SocketImpl::error(int code, const std::string& arg)
1219{
1220 switch (code)
1221 {
1222 case POCO_ENOERR: return;
1223 case POCO_ESYSNOTREADY:
1224 throw NetException("Net subsystem not ready", code);
1225 case POCO_ENOTINIT:
1226 throw NetException("Net subsystem not initialized", code);
1227 case POCO_EINTR:
1228 throw IOException("Interrupted", code);
1229 case POCO_EACCES:
1230 throw IOException("Permission denied", code);
1231 case POCO_EFAULT:
1232 throw IOException("Bad address", code);
1233 case POCO_EINVAL:
1234 throw InvalidArgumentException(code);
1235 case POCO_EMFILE:
1236 throw IOException("Too many open files", code);
1237 case POCO_EWOULDBLOCK:
1238 throw IOException("Operation would block", code);
1239 case POCO_EINPROGRESS:
1240 throw IOException("Operation now in progress", code);
1241 case POCO_EALREADY:
1242 throw IOException("Operation already in progress", code);
1243 case POCO_ENOTSOCK:
1244 throw IOException("Socket operation attempted on non-socket", code);
1245 case POCO_EDESTADDRREQ:
1246 throw NetException("Destination address required", code);
1247 case POCO_EMSGSIZE:
1248 throw NetException("Message too long", code);
1249 case POCO_EPROTOTYPE:
1250 throw NetException("Wrong protocol type", code);
1251 case POCO_ENOPROTOOPT:
1252 throw NetException("Protocol not available", code);
1253 case POCO_EPROTONOSUPPORT:
1254 throw NetException("Protocol not supported", code);
1255 case POCO_ESOCKTNOSUPPORT:
1256 throw NetException("Socket type not supported", code);
1257 case POCO_ENOTSUP:
1258 throw NetException("Operation not supported", code);
1259 case POCO_EPFNOSUPPORT:
1260 throw NetException("Protocol family not supported", code);
1261 case POCO_EAFNOSUPPORT:
1262 throw NetException("Address family not supported", code);
1263 case POCO_EADDRINUSE:
1264 throw NetException("Address already in use", arg, code);
1265 case POCO_EADDRNOTAVAIL:
1266 throw NetException("Cannot assign requested address", arg, code);
1267 case POCO_ENETDOWN:
1268 throw NetException("Network is down", code);
1269 case POCO_ENETUNREACH:
1270 throw NetException("Network is unreachable", code);
1271 case POCO_ENETRESET:
1272 throw NetException("Network dropped connection on reset", code);
1273 case POCO_ECONNABORTED:
1274 throw ConnectionAbortedException(code);
1275 case POCO_ECONNRESET:
1276 throw ConnectionResetException(code);
1277 case POCO_ENOBUFS:
1278 throw IOException("No buffer space available", code);
1279 case POCO_EISCONN:
1280 throw NetException("Socket is already connected", code);
1281 case POCO_ENOTCONN:
1282 throw NetException("Socket is not connected", code);
1283 case POCO_ESHUTDOWN:
1284 throw NetException("Cannot send after socket shutdown", code);
1285 case POCO_ETIMEDOUT:
1286 throw TimeoutException(code);
1287 case POCO_ECONNREFUSED:
1288 throw ConnectionRefusedException(arg, code);
1289 case POCO_EHOSTDOWN:
1290 throw NetException("Host is down", arg, code);
1291 case POCO_EHOSTUNREACH:
1292 throw NetException("No route to host", arg, code);
1293#if defined(POCO_OS_FAMILY_UNIX)
1294 case EPIPE:
1295 throw IOException("Broken pipe", code);
1296 case EBADF:
1297 throw IOException("Bad socket descriptor", code);
1298 case ENOENT:
1299 throw IOException("Not found", arg, code);
1300#endif
1301 default:
1302 throw IOException(NumberFormatter::format(code), arg, code);
1303 }
1304}
1305
1306
1307} } // namespace Poco::Net
1308