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