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 | |
54 | using Poco::IOException; |
55 | using Poco::TimeoutException; |
56 | using Poco::InvalidArgumentException; |
57 | using Poco::NumberFormatter; |
58 | using Poco::Timespan; |
59 | |
60 | |
61 | namespace Poco { |
62 | namespace Net { |
63 | |
64 | |
65 | bool 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 | |
82 | SocketImpl::SocketImpl(): |
83 | _sockfd(POCO_INVALID_SOCKET), |
84 | _blocking(true), |
85 | _isBrokenTimeout(checkIsBrokenTimeout()) |
86 | { |
87 | } |
88 | |
89 | |
90 | SocketImpl::SocketImpl(poco_socket_t sockfd): |
91 | _sockfd(sockfd), |
92 | _blocking(true), |
93 | _isBrokenTimeout(checkIsBrokenTimeout()) |
94 | { |
95 | } |
96 | |
97 | |
98 | SocketImpl::~SocketImpl() |
99 | { |
100 | close(); |
101 | } |
102 | |
103 | |
104 | SocketImpl* 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 | |
127 | void 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 | |
151 | void 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 | |
185 | void 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 | |
206 | void SocketImpl::bind(const SocketAddress& address, bool reuseAddress) |
207 | { |
208 | bind(address, reuseAddress, true); |
209 | } |
210 | |
211 | |
212 | void 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 | |
231 | void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) |
232 | { |
233 | bind6(address, reuseAddress, true, ipV6Only); |
234 | } |
235 | |
236 | |
237 | void 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 | |
264 | void 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 | |
273 | void SocketImpl::close() |
274 | { |
275 | if (_sockfd != POCO_INVALID_SOCKET) |
276 | { |
277 | poco_closesocket(_sockfd); |
278 | _sockfd = POCO_INVALID_SOCKET; |
279 | } |
280 | } |
281 | |
282 | |
283 | void 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 | |
292 | void 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 | |
301 | void 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 | |
310 | void 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 | |
324 | int 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 | |
340 | int 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 | |
365 | int 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 | |
390 | int 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 | |
424 | int 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 | |
454 | int 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 | |
472 | int 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 | |
504 | int 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 | |
519 | int 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 | |
543 | int 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 | |
558 | int 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 | |
600 | void 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 | |
609 | int SocketImpl::available() |
610 | { |
611 | int result = 0; |
612 | ioctl(FIONREAD, result); |
613 | return result; |
614 | } |
615 | |
616 | |
617 | bool SocketImpl::secure() const |
618 | { |
619 | return false; |
620 | } |
621 | |
622 | |
623 | bool 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 | |
758 | void SocketImpl::setSendBufferSize(int size) |
759 | { |
760 | setOption(SOL_SOCKET, SO_SNDBUF, size); |
761 | } |
762 | |
763 | |
764 | int SocketImpl::getSendBufferSize() |
765 | { |
766 | int result; |
767 | getOption(SOL_SOCKET, SO_SNDBUF, result); |
768 | return result; |
769 | } |
770 | |
771 | |
772 | void SocketImpl::setReceiveBufferSize(int size) |
773 | { |
774 | setOption(SOL_SOCKET, SO_RCVBUF, size); |
775 | } |
776 | |
777 | |
778 | int SocketImpl::getReceiveBufferSize() |
779 | { |
780 | int result; |
781 | getOption(SOL_SOCKET, SO_RCVBUF, result); |
782 | return result; |
783 | } |
784 | |
785 | |
786 | void 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 | |
799 | Poco::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 | |
815 | void 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 | |
830 | Poco::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 | |
846 | SocketAddress 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 | |
862 | SocketAddress 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 | |
878 | void SocketImpl::setOption(int level, int option, int value) |
879 | { |
880 | setRawOption(level, option, &value, sizeof(value)); |
881 | } |
882 | |
883 | |
884 | void SocketImpl::setOption(int level, int option, unsigned value) |
885 | { |
886 | setRawOption(level, option, &value, sizeof(value)); |
887 | } |
888 | |
889 | |
890 | void SocketImpl::setOption(int level, int option, unsigned char value) |
891 | { |
892 | setRawOption(level, option, &value, sizeof(value)); |
893 | } |
894 | |
895 | |
896 | void SocketImpl::setOption(int level, int option, const IPAddress& value) |
897 | { |
898 | setRawOption(level, option, value.addr(), value.length()); |
899 | } |
900 | |
901 | |
902 | void 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 | |
912 | void 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 | |
925 | void 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 | |
932 | void 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 | |
939 | void 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 | |
946 | void 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 | |
955 | void 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 | |
964 | void 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 | |
973 | void 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 | |
982 | void 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 | |
992 | void SocketImpl::setNoDelay(bool flag) |
993 | { |
994 | int value = flag ? 1 : 0; |
995 | setOption(IPPROTO_TCP, TCP_NODELAY, value); |
996 | } |
997 | |
998 | |
999 | bool SocketImpl::getNoDelay() |
1000 | { |
1001 | int value(0); |
1002 | getOption(IPPROTO_TCP, TCP_NODELAY, value); |
1003 | return value != 0; |
1004 | } |
1005 | |
1006 | |
1007 | void SocketImpl::setKeepAlive(bool flag) |
1008 | { |
1009 | int value = flag ? 1 : 0; |
1010 | setOption(SOL_SOCKET, SO_KEEPALIVE, value); |
1011 | } |
1012 | |
1013 | |
1014 | bool SocketImpl::getKeepAlive() |
1015 | { |
1016 | int value(0); |
1017 | getOption(SOL_SOCKET, SO_KEEPALIVE, value); |
1018 | return value != 0; |
1019 | } |
1020 | |
1021 | |
1022 | void SocketImpl::setReuseAddress(bool flag) |
1023 | { |
1024 | int value = flag ? 1 : 0; |
1025 | setOption(SOL_SOCKET, SO_REUSEADDR, value); |
1026 | } |
1027 | |
1028 | |
1029 | bool SocketImpl::getReuseAddress() |
1030 | { |
1031 | int value(0); |
1032 | getOption(SOL_SOCKET, SO_REUSEADDR, value); |
1033 | return value != 0; |
1034 | } |
1035 | |
1036 | |
1037 | void 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 | |
1057 | bool 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 | |
1069 | void SocketImpl::setOOBInline(bool flag) |
1070 | { |
1071 | int value = flag ? 1 : 0; |
1072 | setOption(SOL_SOCKET, SO_OOBINLINE, value); |
1073 | } |
1074 | |
1075 | |
1076 | bool SocketImpl::getOOBInline() |
1077 | { |
1078 | int value(0); |
1079 | getOption(SOL_SOCKET, SO_OOBINLINE, value); |
1080 | return value != 0; |
1081 | } |
1082 | |
1083 | |
1084 | void SocketImpl::setBroadcast(bool flag) |
1085 | { |
1086 | int value = flag ? 1 : 0; |
1087 | setOption(SOL_SOCKET, SO_BROADCAST, value); |
1088 | } |
1089 | |
1090 | |
1091 | bool SocketImpl::getBroadcast() |
1092 | { |
1093 | int value(0); |
1094 | getOption(SOL_SOCKET, SO_BROADCAST, value); |
1095 | return value != 0; |
1096 | } |
1097 | |
1098 | |
1099 | void 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 | |
1114 | int SocketImpl::socketError() |
1115 | { |
1116 | int result(0); |
1117 | getOption(SOL_SOCKET, SO_ERROR, result); |
1118 | return result; |
1119 | } |
1120 | |
1121 | |
1122 | void SocketImpl::init(int af) |
1123 | { |
1124 | initSocket(af, SOCK_STREAM); |
1125 | } |
1126 | |
1127 | |
1128 | void 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 | |
1147 | void 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 | |
1160 | void 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) |
1174 | int 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 | |
1182 | int 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 | |
1191 | void SocketImpl::reset(poco_socket_t aSocket) |
1192 | { |
1193 | _sockfd = aSocket; |
1194 | } |
1195 | |
1196 | |
1197 | void SocketImpl::error() |
1198 | { |
1199 | int err = lastError(); |
1200 | std::string empty; |
1201 | error(err, empty); |
1202 | } |
1203 | |
1204 | |
1205 | void SocketImpl::error(const std::string& arg) |
1206 | { |
1207 | error(lastError(), arg); |
1208 | } |
1209 | |
1210 | |
1211 | void SocketImpl::error(int code) |
1212 | { |
1213 | std::string arg; |
1214 | error(code, arg); |
1215 | } |
1216 | |
1217 | |
1218 | void 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 | |