1//
2// detail/impl/socket_ops.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
12#define BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#include <cctype>
21#include <cstdio>
22#include <cstdlib>
23#include <cstring>
24#include <cerrno>
25#include <new>
26#include <boost/asio/detail/assert.hpp>
27#include <boost/asio/detail/socket_ops.hpp>
28#include <boost/asio/error.hpp>
29
30#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
31# include <codecvt>
32# include <locale>
33# include <string>
34#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
35
36#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) \
37 || defined(__MACH__) && defined(__APPLE__)
38# if defined(BOOST_ASIO_HAS_PTHREADS)
39# include <pthread.h>
40# endif // defined(BOOST_ASIO_HAS_PTHREADS)
41#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
42 // || defined(__MACH__) && defined(__APPLE__)
43
44#include <boost/asio/detail/push_options.hpp>
45
46namespace boost {
47namespace asio {
48namespace detail {
49namespace socket_ops {
50
51#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
52
53#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
54struct msghdr { int msg_namelen; };
55#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
56
57#if defined(__hpux)
58// HP-UX doesn't declare these functions extern "C", so they are declared again
59// here to avoid linker errors about undefined symbols.
60extern "C" char* if_indextoname(unsigned int, char*);
61extern "C" unsigned int if_nametoindex(const char*);
62#endif // defined(__hpux)
63
64#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
65
66inline void clear_last_error()
67{
68#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
69 WSASetLastError(0);
70#else
71 errno = 0;
72#endif
73}
74
75#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
76
77inline void get_last_error(
78 boost::system::error_code& ec, bool is_error_condition)
79{
80 if (!is_error_condition)
81 {
82 boost::asio::error::clear(ec);
83 }
84 else
85 {
86#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
87 ec = boost::system::error_code(WSAGetLastError(),
88 boost::asio::error::get_system_category());
89#else
90 ec = boost::system::error_code(errno,
91 boost::asio::error::get_system_category());
92#endif
93 }
94}
95
96template <typename SockLenType>
97inline socket_type call_accept(SockLenType msghdr::*,
98 socket_type s, void* addr, std::size_t* addrlen)
99{
100 SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
101 socket_type result = ::accept(fd: s,
102 addr: static_cast<socket_addr_type*>(addr),
103 addr_len: addrlen ? &tmp_addrlen : 0);
104 if (addrlen)
105 *addrlen = (std::size_t)tmp_addrlen;
106 return result;
107}
108
109socket_type accept(socket_type s, void* addr,
110 std::size_t* addrlen, boost::system::error_code& ec)
111{
112 if (s == invalid_socket)
113 {
114 ec = boost::asio::error::bad_descriptor;
115 return invalid_socket;
116 }
117
118 socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen);
119 get_last_error(ec, is_error_condition: new_s == invalid_socket);
120 if (new_s == invalid_socket)
121 return new_s;
122
123#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
124 int optval = 1;
125 int result = ::setsockopt(new_s, SOL_SOCKET,
126 SO_NOSIGPIPE, &optval, sizeof(optval));
127 get_last_error(ec, result != 0);
128 if (result != 0)
129 {
130 ::close(new_s);
131 return invalid_socket;
132 }
133#endif
134
135 boost::asio::error::clear(ec);
136 return new_s;
137}
138
139socket_type sync_accept(socket_type s, state_type state,
140 void* addr, std::size_t* addrlen, boost::system::error_code& ec)
141{
142 // Accept a socket.
143 for (;;)
144 {
145 // Try to complete the operation without blocking.
146 socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
147
148 // Check if operation succeeded.
149 if (new_socket != invalid_socket)
150 return new_socket;
151
152 // Operation failed.
153 if (ec == boost::asio::error::would_block
154 || ec == boost::asio::error::try_again)
155 {
156 if (state & user_set_non_blocking)
157 return invalid_socket;
158 // Fall through to retry operation.
159 }
160 else if (ec == boost::asio::error::connection_aborted)
161 {
162 if (state & enable_connection_aborted)
163 return invalid_socket;
164 // Fall through to retry operation.
165 }
166#if defined(EPROTO)
167 else if (ec.value() == EPROTO)
168 {
169 if (state & enable_connection_aborted)
170 return invalid_socket;
171 // Fall through to retry operation.
172 }
173#endif // defined(EPROTO)
174 else
175 return invalid_socket;
176
177 // Wait for socket to become ready.
178 if (socket_ops::poll_read(s, state: 0, msec: -1, ec) < 0)
179 return invalid_socket;
180 }
181}
182
183#if defined(BOOST_ASIO_HAS_IOCP)
184
185void complete_iocp_accept(socket_type s, void* output_buffer,
186 DWORD address_length, void* addr, std::size_t* addrlen,
187 socket_type new_socket, boost::system::error_code& ec)
188{
189 // Map non-portable errors to their portable counterparts.
190 if (ec.value() == ERROR_NETNAME_DELETED)
191 ec = boost::asio::error::connection_aborted;
192
193 if (!ec)
194 {
195 // Get the address of the peer.
196 if (addr && addrlen)
197 {
198 LPSOCKADDR local_addr = 0;
199 int local_addr_length = 0;
200 LPSOCKADDR remote_addr = 0;
201 int remote_addr_length = 0;
202 GetAcceptExSockaddrs(output_buffer, 0, address_length,
203 address_length, &local_addr, &local_addr_length,
204 &remote_addr, &remote_addr_length);
205 if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
206 {
207 ec = boost::asio::error::invalid_argument;
208 }
209 else
210 {
211 using namespace std; // For memcpy.
212 memcpy(addr, remote_addr, remote_addr_length);
213 *addrlen = static_cast<std::size_t>(remote_addr_length);
214 }
215 }
216
217 // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
218 // and getpeername will work on the accepted socket.
219 SOCKET update_ctx_param = s;
220 socket_ops::state_type state = 0;
221 socket_ops::setsockopt(new_socket, state,
222 SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
223 &update_ctx_param, sizeof(SOCKET), ec);
224 }
225}
226
227#else // defined(BOOST_ASIO_HAS_IOCP)
228
229bool non_blocking_accept(socket_type s,
230 state_type state, void* addr, std::size_t* addrlen,
231 boost::system::error_code& ec, socket_type& new_socket)
232{
233 for (;;)
234 {
235 // Accept the waiting connection.
236 new_socket = socket_ops::accept(s, addr, addrlen, ec);
237
238 // Check if operation succeeded.
239 if (new_socket != invalid_socket)
240 return true;
241
242 // Retry operation if interrupted by signal.
243 if (ec == boost::asio::error::interrupted)
244 continue;
245
246 // Operation failed.
247 if (ec == boost::asio::error::would_block
248 || ec == boost::asio::error::try_again)
249 {
250 // Fall through to retry operation.
251 }
252 else if (ec == boost::asio::error::connection_aborted)
253 {
254 if (state & enable_connection_aborted)
255 return true;
256 // Fall through to retry operation.
257 }
258#if defined(EPROTO)
259 else if (ec.value() == EPROTO)
260 {
261 if (state & enable_connection_aborted)
262 return true;
263 // Fall through to retry operation.
264 }
265#endif // defined(EPROTO)
266 else
267 return true;
268
269 return false;
270 }
271}
272
273#endif // defined(BOOST_ASIO_HAS_IOCP)
274
275template <typename SockLenType>
276inline int call_bind(SockLenType msghdr::*,
277 socket_type s, const void* addr, std::size_t addrlen)
278{
279 return ::bind(fd: s, addr: static_cast<const socket_addr_type*>(addr),
280 len: (SockLenType)addrlen);
281}
282
283int bind(socket_type s, const void* addr,
284 std::size_t addrlen, boost::system::error_code& ec)
285{
286 if (s == invalid_socket)
287 {
288 ec = boost::asio::error::bad_descriptor;
289 return socket_error_retval;
290 }
291
292 int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen);
293 get_last_error(ec, is_error_condition: result != 0);
294 return result;
295}
296
297int close(socket_type s, state_type& state,
298 bool destruction, boost::system::error_code& ec)
299{
300 int result = 0;
301 if (s != invalid_socket)
302 {
303 // We don't want the destructor to block, so set the socket to linger in
304 // the background. If the user doesn't like this behaviour then they need
305 // to explicitly close the socket.
306 if (destruction && (state & user_set_linger))
307 {
308 ::linger opt;
309 opt.l_onoff = 0;
310 opt.l_linger = 0;
311 boost::system::error_code ignored_ec;
312 socket_ops::setsockopt(s, state, SOL_SOCKET,
313 SO_LINGER, optval: &opt, optlen: sizeof(opt), ec&: ignored_ec);
314 }
315
316#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
317 result = ::closesocket(s);
318#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
319 result = ::close(fd: s);
320#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
321 get_last_error(ec, is_error_condition: result != 0);
322
323 if (result != 0
324 && (ec == boost::asio::error::would_block
325 || ec == boost::asio::error::try_again))
326 {
327 // According to UNIX Network Programming Vol. 1, it is possible for
328 // close() to fail with EWOULDBLOCK under certain circumstances. What
329 // isn't clear is the state of the descriptor after this error. The one
330 // current OS where this behaviour is seen, Windows, says that the socket
331 // remains open. Therefore we'll put the descriptor back into blocking
332 // mode and have another attempt at closing it.
333#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
334 ioctl_arg_type arg = 0;
335 ::ioctlsocket(s, FIONBIO, &arg);
336#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
337# if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
338 int flags = ::fcntl(s, F_GETFL, 0);
339 if (flags >= 0)
340 ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
341# else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
342 ioctl_arg_type arg = 0;
343# if defined(ENOTTY) || defined(ENOTCAPABLE)
344 result = ::ioctl(fd: s, FIONBIO, &arg);
345 get_last_error(ec, is_error_condition: result < 0);
346 if (false
347# if defined(ENOTTY)
348 || ec.value() == ENOTTY
349# endif // defined(ENOTTY)
350# if defined(ENOTCAPABLE)
351 || ec.value() == ENOTCAPABLE
352# endif // defined(ENOTCAPABLE)
353 )
354 {
355 int flags = ::fcntl(fd: s, F_GETFL, 0);
356 if (flags >= 0)
357 ::fcntl(fd: s, F_SETFL, flags & ~O_NONBLOCK);
358 }
359# else // defined(ENOTTY) || defined(ENOTCAPABLE)
360 ::ioctl(s, FIONBIO, &arg);
361# endif // defined(ENOTTY) || defined(ENOTCAPABLE)
362# endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
363#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
364 state &= ~non_blocking;
365
366#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
367 result = ::closesocket(s);
368#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
369 result = ::close(fd: s);
370#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
371 get_last_error(ec, is_error_condition: result != 0);
372 }
373 }
374
375 return result;
376}
377
378bool set_user_non_blocking(socket_type s,
379 state_type& state, bool value, boost::system::error_code& ec)
380{
381 if (s == invalid_socket)
382 {
383 ec = boost::asio::error::bad_descriptor;
384 return false;
385 }
386
387#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
388 ioctl_arg_type arg = (value ? 1 : 0);
389 int result = ::ioctlsocket(s, FIONBIO, &arg);
390 get_last_error(ec, result < 0);
391#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
392 int result = ::fcntl(s, F_GETFL, 0);
393 get_last_error(ec, result < 0);
394 if (result >= 0)
395 {
396 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
397 result = ::fcntl(s, F_SETFL, flag);
398 get_last_error(ec, result < 0);
399 }
400#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
401 ioctl_arg_type arg = (value ? 1 : 0);
402 int result = ::ioctl(fd: s, FIONBIO, &arg);
403 get_last_error(ec, is_error_condition: result < 0);
404# if defined(ENOTTY) || defined(ENOTCAPABLE)
405 if (false
406# if defined(ENOTTY)
407 || ec.value() == ENOTTY
408# endif // defined(ENOTTY)
409# if defined(ENOTCAPABLE)
410 || ec.value() == ENOTCAPABLE
411# endif // defined(ENOTCAPABLE)
412 )
413 {
414 result = ::fcntl(fd: s, F_GETFL, 0);
415 get_last_error(ec, is_error_condition: result < 0);
416 if (result >= 0)
417 {
418 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
419 result = ::fcntl(fd: s, F_SETFL, flag);
420 get_last_error(ec, is_error_condition: result < 0);
421 }
422 }
423# endif // defined(ENOTTY) || defined(ENOTCAPABLE)
424#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
425
426 if (result >= 0)
427 {
428 if (value)
429 state |= user_set_non_blocking;
430 else
431 {
432 // Clearing the user-set non-blocking mode always overrides any
433 // internally-set non-blocking flag. Any subsequent asynchronous
434 // operations will need to re-enable non-blocking I/O.
435 state &= ~(user_set_non_blocking | internal_non_blocking);
436 }
437 return true;
438 }
439
440 return false;
441}
442
443bool set_internal_non_blocking(socket_type s,
444 state_type& state, bool value, boost::system::error_code& ec)
445{
446 if (s == invalid_socket)
447 {
448 ec = boost::asio::error::bad_descriptor;
449 return false;
450 }
451
452 if (!value && (state & user_set_non_blocking))
453 {
454 // It does not make sense to clear the internal non-blocking flag if the
455 // user still wants non-blocking behaviour. Return an error and let the
456 // caller figure out whether to update the user-set non-blocking flag.
457 ec = boost::asio::error::invalid_argument;
458 return false;
459 }
460
461#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
462 ioctl_arg_type arg = (value ? 1 : 0);
463 int result = ::ioctlsocket(s, FIONBIO, &arg);
464 get_last_error(ec, result < 0);
465#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
466 int result = ::fcntl(s, F_GETFL, 0);
467 get_last_error(ec, result < 0);
468 if (result >= 0)
469 {
470 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
471 result = ::fcntl(s, F_SETFL, flag);
472 get_last_error(ec, result < 0);
473 }
474#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
475 ioctl_arg_type arg = (value ? 1 : 0);
476 int result = ::ioctl(fd: s, FIONBIO, &arg);
477 get_last_error(ec, is_error_condition: result < 0);
478# if defined(ENOTTY) || defined(ENOTCAPABLE)
479 if (false
480# if defined(ENOTTY)
481 || ec.value() == ENOTTY
482# endif // defined(ENOTTY)
483# if defined(ENOTCAPABLE)
484 || ec.value() == ENOTCAPABLE
485# endif // defined(ENOTCAPABLE)
486 )
487 {
488 result = ::fcntl(fd: s, F_GETFL, 0);
489 get_last_error(ec, is_error_condition: result < 0);
490 if (result >= 0)
491 {
492 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
493 result = ::fcntl(fd: s, F_SETFL, flag);
494 get_last_error(ec, is_error_condition: result < 0);
495 }
496 }
497# endif // defined(ENOTTY) || defined(ENOTCAPABLE)
498#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
499
500 if (result >= 0)
501 {
502 if (value)
503 state |= internal_non_blocking;
504 else
505 state &= ~internal_non_blocking;
506 return true;
507 }
508
509 return false;
510}
511
512int shutdown(socket_type s, int what, boost::system::error_code& ec)
513{
514 if (s == invalid_socket)
515 {
516 ec = boost::asio::error::bad_descriptor;
517 return socket_error_retval;
518 }
519
520 int result = ::shutdown(fd: s, how: what);
521 get_last_error(ec, is_error_condition: result != 0);
522 return result;
523}
524
525template <typename SockLenType>
526inline int call_connect(SockLenType msghdr::*,
527 socket_type s, const void* addr, std::size_t addrlen)
528{
529 return ::connect(fd: s, addr: static_cast<const socket_addr_type*>(addr),
530 len: (SockLenType)addrlen);
531}
532
533int connect(socket_type s, const void* addr,
534 std::size_t addrlen, boost::system::error_code& ec)
535{
536 if (s == invalid_socket)
537 {
538 ec = boost::asio::error::bad_descriptor;
539 return socket_error_retval;
540 }
541
542 int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen);
543 get_last_error(ec, is_error_condition: result != 0);
544#if defined(__linux__)
545 if (result != 0 && ec == boost::asio::error::try_again)
546 {
547 if (static_cast<const socket_addr_type*>(addr)->sa_family == AF_UNIX)
548 ec = boost::asio::error::in_progress;
549 else
550 ec = boost::asio::error::no_buffer_space;
551 }
552#endif // defined(__linux__)
553 return result;
554}
555
556void sync_connect(socket_type s, const void* addr,
557 std::size_t addrlen, boost::system::error_code& ec)
558{
559 // Perform the connect operation.
560 socket_ops::connect(s, addr, addrlen, ec);
561 if (ec != boost::asio::error::in_progress
562 && ec != boost::asio::error::would_block)
563 {
564 // The connect operation finished immediately.
565 return;
566 }
567
568 // Wait for socket to become ready.
569 if (socket_ops::poll_connect(s, msec: -1, ec) < 0)
570 return;
571
572 // Get the error code from the connect operation.
573 int connect_error = 0;
574 size_t connect_error_len = sizeof(connect_error);
575 if (socket_ops::getsockopt(s, state: 0, SOL_SOCKET, SO_ERROR,
576 optval: &connect_error, optlen: &connect_error_len, ec) == socket_error_retval)
577 return;
578
579 // Return the result of the connect operation.
580 ec = boost::system::error_code(connect_error,
581 boost::asio::error::get_system_category());
582}
583
584#if defined(BOOST_ASIO_HAS_IOCP)
585
586void complete_iocp_connect(socket_type s, boost::system::error_code& ec)
587{
588 // Map non-portable errors to their portable counterparts.
589 switch (ec.value())
590 {
591 case ERROR_CONNECTION_REFUSED:
592 ec = boost::asio::error::connection_refused;
593 break;
594 case ERROR_NETWORK_UNREACHABLE:
595 ec = boost::asio::error::network_unreachable;
596 break;
597 case ERROR_HOST_UNREACHABLE:
598 ec = boost::asio::error::host_unreachable;
599 break;
600 case ERROR_SEM_TIMEOUT:
601 ec = boost::asio::error::timed_out;
602 break;
603 default:
604 break;
605 }
606
607 if (!ec)
608 {
609 // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname
610 // and getpeername will work on the connected socket.
611 socket_ops::state_type state = 0;
612 const int so_update_connect_context = 0x7010;
613 socket_ops::setsockopt(s, state, SOL_SOCKET,
614 so_update_connect_context, 0, 0, ec);
615 }
616}
617
618#endif // defined(BOOST_ASIO_HAS_IOCP)
619
620bool non_blocking_connect(socket_type s, boost::system::error_code& ec)
621{
622 // Check if the connect operation has finished. This is required since we may
623 // get spurious readiness notifications from the reactor.
624#if defined(BOOST_ASIO_WINDOWS) \
625 || defined(__CYGWIN__) \
626 || defined(__SYMBIAN32__)
627 fd_set write_fds;
628 FD_ZERO(&write_fds);
629 FD_SET(s, &write_fds);
630 fd_set except_fds;
631 FD_ZERO(&except_fds);
632 FD_SET(s, &except_fds);
633 timeval zero_timeout;
634 zero_timeout.tv_sec = 0;
635 zero_timeout.tv_usec = 0;
636 int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout);
637#else // defined(BOOST_ASIO_WINDOWS)
638 // || defined(__CYGWIN__)
639 // || defined(__SYMBIAN32__)
640 pollfd fds;
641 fds.fd = s;
642 fds.events = POLLOUT;
643 fds.revents = 0;
644 int ready = ::poll(fds: &fds, nfds: 1, timeout: 0);
645#endif // defined(BOOST_ASIO_WINDOWS)
646 // || defined(__CYGWIN__)
647 // || defined(__SYMBIAN32__)
648 if (ready == 0)
649 {
650 // The asynchronous connect operation is still in progress.
651 return false;
652 }
653
654 // Get the error code from the connect operation.
655 int connect_error = 0;
656 size_t connect_error_len = sizeof(connect_error);
657 if (socket_ops::getsockopt(s, state: 0, SOL_SOCKET, SO_ERROR,
658 optval: &connect_error, optlen: &connect_error_len, ec) == 0)
659 {
660 if (connect_error)
661 {
662 ec = boost::system::error_code(connect_error,
663 boost::asio::error::get_system_category());
664 }
665 else
666 boost::asio::error::clear(ec);
667 }
668
669 return true;
670}
671
672int socketpair(int af, int type, int protocol,
673 socket_type sv[2], boost::system::error_code& ec)
674{
675#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
676 (void)(af);
677 (void)(type);
678 (void)(protocol);
679 (void)(sv);
680 ec = boost::asio::error::operation_not_supported;
681 return socket_error_retval;
682#else
683 int result = ::socketpair(domain: af, type: type, protocol: protocol, fds: sv);
684 get_last_error(ec, is_error_condition: result != 0);
685 return result;
686#endif
687}
688
689bool sockatmark(socket_type s, boost::system::error_code& ec)
690{
691 if (s == invalid_socket)
692 {
693 ec = boost::asio::error::bad_descriptor;
694 return false;
695 }
696
697#if defined(SIOCATMARK)
698 ioctl_arg_type value = 0;
699# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
700 int result = ::ioctlsocket(s, SIOCATMARK, &value);
701# else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
702 int result = ::ioctl(fd: s, SIOCATMARK, &value);
703# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
704 get_last_error(ec, is_error_condition: result < 0);
705# if defined(ENOTTY)
706 if (ec.value() == ENOTTY)
707 ec = boost::asio::error::not_socket;
708# endif // defined(ENOTTY)
709#else // defined(SIOCATMARK)
710 int value = ::sockatmark(s);
711 get_last_error(ec, value < 0);
712#endif // defined(SIOCATMARK)
713
714 return ec ? false : value != 0;
715}
716
717size_t available(socket_type s, boost::system::error_code& ec)
718{
719 if (s == invalid_socket)
720 {
721 ec = boost::asio::error::bad_descriptor;
722 return 0;
723 }
724
725 ioctl_arg_type value = 0;
726#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
727 int result = ::ioctlsocket(s, FIONREAD, &value);
728#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
729 int result = ::ioctl(fd: s, FIONREAD, &value);
730#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
731 get_last_error(ec, is_error_condition: result < 0);
732#if defined(ENOTTY)
733 if (ec.value() == ENOTTY)
734 ec = boost::asio::error::not_socket;
735#endif // defined(ENOTTY)
736
737 return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
738}
739
740int listen(socket_type s, int backlog, boost::system::error_code& ec)
741{
742 if (s == invalid_socket)
743 {
744 ec = boost::asio::error::bad_descriptor;
745 return socket_error_retval;
746 }
747
748 int result = ::listen(fd: s, n: backlog);
749 get_last_error(ec, is_error_condition: result != 0);
750 return result;
751}
752
753inline void init_buf_iov_base(void*& base, void* addr)
754{
755 base = addr;
756}
757
758template <typename T>
759inline void init_buf_iov_base(T& base, void* addr)
760{
761 base = static_cast<T>(addr);
762}
763
764#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
765typedef WSABUF buf;
766#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
767typedef iovec buf;
768#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
769
770void init_buf(buf& b, void* data, size_t size)
771{
772#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
773 b.buf = static_cast<char*>(data);
774 b.len = static_cast<u_long>(size);
775#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
776 init_buf_iov_base(base&: b.iov_base, addr: data);
777 b.iov_len = size;
778#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
779}
780
781void init_buf(buf& b, const void* data, size_t size)
782{
783#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
784 b.buf = static_cast<char*>(const_cast<void*>(data));
785 b.len = static_cast<u_long>(size);
786#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
787 init_buf_iov_base(base&: b.iov_base, addr: const_cast<void*>(data));
788 b.iov_len = size;
789#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
790}
791
792inline void init_msghdr_msg_name(void*& name, void* addr)
793{
794 name = static_cast<socket_addr_type*>(addr);
795}
796
797inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
798{
799 name = const_cast<socket_addr_type*>(addr);
800}
801
802template <typename T>
803inline void init_msghdr_msg_name(T& name, void* addr)
804{
805 name = static_cast<T>(addr);
806}
807
808template <typename T>
809inline void init_msghdr_msg_name(T& name, const void* addr)
810{
811 name = static_cast<T>(const_cast<void*>(addr));
812}
813
814signed_size_type recv(socket_type s, buf* bufs, size_t count,
815 int flags, boost::system::error_code& ec)
816{
817#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
818 // Receive some data.
819 DWORD recv_buf_count = static_cast<DWORD>(count);
820 DWORD bytes_transferred = 0;
821 DWORD recv_flags = flags;
822 int result = ::WSARecv(s, bufs, recv_buf_count,
823 &bytes_transferred, &recv_flags, 0, 0);
824 get_last_error(ec, true);
825 if (ec.value() == ERROR_NETNAME_DELETED)
826 ec = boost::asio::error::connection_reset;
827 else if (ec.value() == ERROR_PORT_UNREACHABLE)
828 ec = boost::asio::error::connection_refused;
829 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
830 result = 0;
831 if (result != 0)
832 return socket_error_retval;
833 boost::asio::error::clear(ec);
834 return bytes_transferred;
835#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
836 msghdr msg = msghdr();
837 msg.msg_iov = bufs;
838 msg.msg_iovlen = static_cast<int>(count);
839 signed_size_type result = ::recvmsg(fd: s, message: &msg, flags: flags);
840 get_last_error(ec, is_error_condition: result < 0);
841 return result;
842#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
843}
844
845signed_size_type recv1(socket_type s, void* data, size_t size,
846 int flags, boost::system::error_code& ec)
847{
848#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
849 // Receive some data.
850 WSABUF buf;
851 buf.buf = const_cast<char*>(static_cast<const char*>(data));
852 buf.len = static_cast<ULONG>(size);
853 DWORD bytes_transferred = 0;
854 DWORD recv_flags = flags;
855 int result = ::WSARecv(s, &buf, 1,
856 &bytes_transferred, &recv_flags, 0, 0);
857 get_last_error(ec, true);
858 if (ec.value() == ERROR_NETNAME_DELETED)
859 ec = boost::asio::error::connection_reset;
860 else if (ec.value() == ERROR_PORT_UNREACHABLE)
861 ec = boost::asio::error::connection_refused;
862 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
863 result = 0;
864 if (result != 0)
865 return socket_error_retval;
866 boost::asio::error::clear(ec);
867 return bytes_transferred;
868#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
869 signed_size_type result = ::recv(fd: s, buf: static_cast<char*>(data), n: size, flags: flags);
870 get_last_error(ec, is_error_condition: result < 0);
871 return result;
872#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
873}
874
875size_t sync_recv(socket_type s, state_type state, buf* bufs,
876 size_t count, int flags, bool all_empty, boost::system::error_code& ec)
877{
878 if (s == invalid_socket)
879 {
880 ec = boost::asio::error::bad_descriptor;
881 return 0;
882 }
883
884 // A request to read 0 bytes on a stream is a no-op.
885 if (all_empty && (state & stream_oriented))
886 {
887 boost::asio::error::clear(ec);
888 return 0;
889 }
890
891 // Read some data.
892 for (;;)
893 {
894 // Try to complete the operation without blocking.
895 signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
896
897 // Check for EOF.
898 if ((state & stream_oriented) && bytes == 0)
899 {
900 ec = boost::asio::error::eof;
901 return 0;
902 }
903
904 // Check if operation succeeded.
905 if (bytes >= 0)
906 return bytes;
907
908 // Operation failed.
909 if ((state & user_set_non_blocking)
910 || (ec != boost::asio::error::would_block
911 && ec != boost::asio::error::try_again))
912 return 0;
913
914 // Wait for socket to become ready.
915 if (socket_ops::poll_read(s, state: 0, msec: -1, ec) < 0)
916 return 0;
917 }
918}
919
920size_t sync_recv1(socket_type s, state_type state, void* data,
921 size_t size, int flags, boost::system::error_code& ec)
922{
923 if (s == invalid_socket)
924 {
925 ec = boost::asio::error::bad_descriptor;
926 return 0;
927 }
928
929 // A request to read 0 bytes on a stream is a no-op.
930 if (size == 0 && (state & stream_oriented))
931 {
932 boost::asio::error::clear(ec);
933 return 0;
934 }
935
936 // Read some data.
937 for (;;)
938 {
939 // Try to complete the operation without blocking.
940 signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);
941
942 // Check for EOF.
943 if ((state & stream_oriented) && bytes == 0)
944 {
945 ec = boost::asio::error::eof;
946 return 0;
947 }
948
949 // Check if operation succeeded.
950 if (bytes >= 0)
951 return bytes;
952
953 // Operation failed.
954 if ((state & user_set_non_blocking)
955 || (ec != boost::asio::error::would_block
956 && ec != boost::asio::error::try_again))
957 return 0;
958
959 // Wait for socket to become ready.
960 if (socket_ops::poll_read(s, state: 0, msec: -1, ec) < 0)
961 return 0;
962 }
963}
964
965#if defined(BOOST_ASIO_HAS_IOCP)
966
967void complete_iocp_recv(state_type state,
968 const weak_cancel_token_type& cancel_token, bool all_empty,
969 boost::system::error_code& ec, size_t bytes_transferred)
970{
971 // Map non-portable errors to their portable counterparts.
972 if (ec.value() == ERROR_NETNAME_DELETED)
973 {
974 if (cancel_token.expired())
975 ec = boost::asio::error::operation_aborted;
976 else
977 ec = boost::asio::error::connection_reset;
978 }
979 else if (ec.value() == ERROR_PORT_UNREACHABLE)
980 {
981 ec = boost::asio::error::connection_refused;
982 }
983 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
984 {
985 boost::asio::error::clear(ec);
986 }
987
988 // Check for connection closed.
989 else if (!ec && bytes_transferred == 0
990 && (state & stream_oriented) != 0
991 && !all_empty)
992 {
993 ec = boost::asio::error::eof;
994 }
995}
996
997#else // defined(BOOST_ASIO_HAS_IOCP)
998
999bool non_blocking_recv(socket_type s,
1000 buf* bufs, size_t count, int flags, bool is_stream,
1001 boost::system::error_code& ec, size_t& bytes_transferred)
1002{
1003 for (;;)
1004 {
1005 // Read some data.
1006 signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
1007
1008 // Check for end of stream.
1009 if (is_stream && bytes == 0)
1010 {
1011 ec = boost::asio::error::eof;
1012 return true;
1013 }
1014
1015 // Check if operation succeeded.
1016 if (bytes >= 0)
1017 {
1018 bytes_transferred = bytes;
1019 return true;
1020 }
1021
1022 // Retry operation if interrupted by signal.
1023 if (ec == boost::asio::error::interrupted)
1024 continue;
1025
1026 // Check if we need to run the operation again.
1027 if (ec == boost::asio::error::would_block
1028 || ec == boost::asio::error::try_again)
1029 return false;
1030
1031 // Operation failed.
1032 bytes_transferred = 0;
1033 return true;
1034 }
1035}
1036
1037bool non_blocking_recv1(socket_type s,
1038 void* data, size_t size, int flags, bool is_stream,
1039 boost::system::error_code& ec, size_t& bytes_transferred)
1040{
1041 for (;;)
1042 {
1043 // Read some data.
1044 signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);
1045
1046 // Check for end of stream.
1047 if (is_stream && bytes == 0)
1048 {
1049 ec = boost::asio::error::eof;
1050 return true;
1051 }
1052
1053 // Check if operation succeeded.
1054 if (bytes >= 0)
1055 {
1056 bytes_transferred = bytes;
1057 return true;
1058 }
1059
1060 // Retry operation if interrupted by signal.
1061 if (ec == boost::asio::error::interrupted)
1062 continue;
1063
1064 // Check if we need to run the operation again.
1065 if (ec == boost::asio::error::would_block
1066 || ec == boost::asio::error::try_again)
1067 return false;
1068
1069 // Operation failed.
1070 bytes_transferred = 0;
1071 return true;
1072 }
1073}
1074
1075#endif // defined(BOOST_ASIO_HAS_IOCP)
1076
1077signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
1078 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1079{
1080#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1081 // Receive some data.
1082 DWORD recv_buf_count = static_cast<DWORD>(count);
1083 DWORD bytes_transferred = 0;
1084 DWORD recv_flags = flags;
1085 int tmp_addrlen = (int)*addrlen;
1086 int result = ::WSARecvFrom(s, bufs, recv_buf_count, &bytes_transferred,
1087 &recv_flags, static_cast<socket_addr_type*>(addr), &tmp_addrlen, 0, 0);
1088 get_last_error(ec, true);
1089 *addrlen = (std::size_t)tmp_addrlen;
1090 if (ec.value() == ERROR_NETNAME_DELETED)
1091 ec = boost::asio::error::connection_reset;
1092 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1093 ec = boost::asio::error::connection_refused;
1094 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1095 result = 0;
1096 if (result != 0)
1097 return socket_error_retval;
1098 boost::asio::error::clear(ec);
1099 return bytes_transferred;
1100#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1101 msghdr msg = msghdr();
1102 init_msghdr_msg_name(name&: msg.msg_name, addr);
1103 msg.msg_namelen = static_cast<int>(*addrlen);
1104 msg.msg_iov = bufs;
1105 msg.msg_iovlen = static_cast<int>(count);
1106 signed_size_type result = ::recvmsg(fd: s, message: &msg, flags: flags);
1107 get_last_error(ec, is_error_condition: result < 0);
1108 *addrlen = msg.msg_namelen;
1109 return result;
1110#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1111}
1112
1113template <typename SockLenType>
1114inline signed_size_type call_recvfrom(SockLenType msghdr::*, socket_type s,
1115 void* data, size_t size, int flags, void* addr, std::size_t* addrlen)
1116{
1117 SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
1118 signed_size_type result = ::recvfrom(fd: s, buf: static_cast<char*>(data), n: size,
1119 flags: flags, addr: static_cast<socket_addr_type*>(addr), addr_len: addrlen ? &tmp_addrlen : 0);
1120 if (addrlen)
1121 *addrlen = (std::size_t)tmp_addrlen;
1122 return result;
1123}
1124
1125signed_size_type recvfrom1(socket_type s, void* data, size_t size,
1126 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1127{
1128#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1129 // Receive some data.
1130 WSABUF buf;
1131 buf.buf = static_cast<char*>(data);
1132 buf.len = static_cast<ULONG>(size);
1133 DWORD bytes_transferred = 0;
1134 DWORD recv_flags = flags;
1135 int tmp_addrlen = (int)*addrlen;
1136 int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred, &recv_flags,
1137 static_cast<socket_addr_type*>(addr), &tmp_addrlen, 0, 0);
1138 get_last_error(ec, true);
1139 *addrlen = (std::size_t)tmp_addrlen;
1140 if (ec.value() == ERROR_NETNAME_DELETED)
1141 ec = boost::asio::error::connection_reset;
1142 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1143 ec = boost::asio::error::connection_refused;
1144 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1145 result = 0;
1146 if (result != 0)
1147 return socket_error_retval;
1148 boost::asio::error::clear(ec);
1149 return bytes_transferred;
1150#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1151 signed_size_type result = call_recvfrom(&msghdr::msg_namelen,
1152 s, data, size, flags, addr, addrlen);
1153 get_last_error(ec, is_error_condition: result < 0);
1154 return result;
1155#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1156}
1157
1158size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, size_t count,
1159 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1160{
1161 if (s == invalid_socket)
1162 {
1163 ec = boost::asio::error::bad_descriptor;
1164 return 0;
1165 }
1166
1167 // Read some data.
1168 for (;;)
1169 {
1170 // Try to complete the operation without blocking.
1171 signed_size_type bytes = socket_ops::recvfrom(
1172 s, bufs, count, flags, addr, addrlen, ec);
1173
1174 // Check if operation succeeded.
1175 if (bytes >= 0)
1176 return bytes;
1177
1178 // Operation failed.
1179 if ((state & user_set_non_blocking)
1180 || (ec != boost::asio::error::would_block
1181 && ec != boost::asio::error::try_again))
1182 return 0;
1183
1184 // Wait for socket to become ready.
1185 if (socket_ops::poll_read(s, state: 0, msec: -1, ec) < 0)
1186 return 0;
1187 }
1188}
1189
1190size_t sync_recvfrom1(socket_type s, state_type state, void* data, size_t size,
1191 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1192{
1193 if (s == invalid_socket)
1194 {
1195 ec = boost::asio::error::bad_descriptor;
1196 return 0;
1197 }
1198
1199 // Read some data.
1200 for (;;)
1201 {
1202 // Try to complete the operation without blocking.
1203 signed_size_type bytes = socket_ops::recvfrom1(
1204 s, data, size, flags, addr, addrlen, ec);
1205
1206 // Check if operation succeeded.
1207 if (bytes >= 0)
1208 return bytes;
1209
1210 // Operation failed.
1211 if ((state & user_set_non_blocking)
1212 || (ec != boost::asio::error::would_block
1213 && ec != boost::asio::error::try_again))
1214 return 0;
1215
1216 // Wait for socket to become ready.
1217 if (socket_ops::poll_read(s, state: 0, msec: -1, ec) < 0)
1218 return 0;
1219 }
1220}
1221
1222#if defined(BOOST_ASIO_HAS_IOCP)
1223
1224void complete_iocp_recvfrom(
1225 const weak_cancel_token_type& cancel_token,
1226 boost::system::error_code& ec)
1227{
1228 // Map non-portable errors to their portable counterparts.
1229 if (ec.value() == ERROR_NETNAME_DELETED)
1230 {
1231 if (cancel_token.expired())
1232 ec = boost::asio::error::operation_aborted;
1233 else
1234 ec = boost::asio::error::connection_reset;
1235 }
1236 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1237 {
1238 ec = boost::asio::error::connection_refused;
1239 }
1240 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1241 {
1242 boost::asio::error::clear(ec);
1243 }
1244}
1245
1246#else // defined(BOOST_ASIO_HAS_IOCP)
1247
1248bool non_blocking_recvfrom(socket_type s, buf* bufs,
1249 size_t count, int flags, void* addr, std::size_t* addrlen,
1250 boost::system::error_code& ec, size_t& bytes_transferred)
1251{
1252 for (;;)
1253 {
1254 // Read some data.
1255 signed_size_type bytes = socket_ops::recvfrom(
1256 s, bufs, count, flags, addr, addrlen, ec);
1257
1258 // Check if operation succeeded.
1259 if (bytes >= 0)
1260 {
1261 bytes_transferred = bytes;
1262 return true;
1263 }
1264
1265 // Retry operation if interrupted by signal.
1266 if (ec == boost::asio::error::interrupted)
1267 continue;
1268
1269 // Check if we need to run the operation again.
1270 if (ec == boost::asio::error::would_block
1271 || ec == boost::asio::error::try_again)
1272 return false;
1273
1274 // Operation failed.
1275 bytes_transferred = 0;
1276 return true;
1277 }
1278}
1279
1280bool non_blocking_recvfrom1(socket_type s, void* data,
1281 size_t size, int flags, void* addr, std::size_t* addrlen,
1282 boost::system::error_code& ec, size_t& bytes_transferred)
1283{
1284 for (;;)
1285 {
1286 // Read some data.
1287 signed_size_type bytes = socket_ops::recvfrom1(
1288 s, data, size, flags, addr, addrlen, ec);
1289
1290 // Check if operation succeeded.
1291 if (bytes >= 0)
1292 {
1293 bytes_transferred = bytes;
1294 return true;
1295 }
1296
1297 // Retry operation if interrupted by signal.
1298 if (ec == boost::asio::error::interrupted)
1299 continue;
1300
1301 // Check if we need to run the operation again.
1302 if (ec == boost::asio::error::would_block
1303 || ec == boost::asio::error::try_again)
1304 return false;
1305
1306 // Operation failed.
1307 bytes_transferred = 0;
1308 return true;
1309 }
1310}
1311
1312#endif // defined(BOOST_ASIO_HAS_IOCP)
1313
1314signed_size_type recvmsg(socket_type s, buf* bufs, size_t count,
1315 int in_flags, int& out_flags, boost::system::error_code& ec)
1316{
1317#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1318 out_flags = 0;
1319 return socket_ops::recv(s, bufs, count, in_flags, ec);
1320#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1321 msghdr msg = msghdr();
1322 msg.msg_iov = bufs;
1323 msg.msg_iovlen = static_cast<int>(count);
1324 signed_size_type result = ::recvmsg(fd: s, message: &msg, flags: in_flags);
1325 get_last_error(ec, is_error_condition: result < 0);
1326 if (result >= 0)
1327 out_flags = msg.msg_flags;
1328 else
1329 out_flags = 0;
1330 return result;
1331#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1332}
1333
1334size_t sync_recvmsg(socket_type s, state_type state,
1335 buf* bufs, size_t count, int in_flags, int& out_flags,
1336 boost::system::error_code& ec)
1337{
1338 if (s == invalid_socket)
1339 {
1340 ec = boost::asio::error::bad_descriptor;
1341 return 0;
1342 }
1343
1344 // Read some data.
1345 for (;;)
1346 {
1347 // Try to complete the operation without blocking.
1348 signed_size_type bytes = socket_ops::recvmsg(
1349 s, bufs, count, in_flags, out_flags, ec);
1350
1351 // Check if operation succeeded.
1352 if (bytes >= 0)
1353 return bytes;
1354
1355 // Operation failed.
1356 if ((state & user_set_non_blocking)
1357 || (ec != boost::asio::error::would_block
1358 && ec != boost::asio::error::try_again))
1359 return 0;
1360
1361 // Wait for socket to become ready.
1362 if (socket_ops::poll_read(s, state: 0, msec: -1, ec) < 0)
1363 return 0;
1364 }
1365}
1366
1367#if defined(BOOST_ASIO_HAS_IOCP)
1368
1369void complete_iocp_recvmsg(
1370 const weak_cancel_token_type& cancel_token,
1371 boost::system::error_code& ec)
1372{
1373 // Map non-portable errors to their portable counterparts.
1374 if (ec.value() == ERROR_NETNAME_DELETED)
1375 {
1376 if (cancel_token.expired())
1377 ec = boost::asio::error::operation_aborted;
1378 else
1379 ec = boost::asio::error::connection_reset;
1380 }
1381 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1382 {
1383 ec = boost::asio::error::connection_refused;
1384 }
1385 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1386 {
1387 boost::asio::error::clear(ec);
1388 }
1389}
1390
1391#else // defined(BOOST_ASIO_HAS_IOCP)
1392
1393bool non_blocking_recvmsg(socket_type s,
1394 buf* bufs, size_t count, int in_flags, int& out_flags,
1395 boost::system::error_code& ec, size_t& bytes_transferred)
1396{
1397 for (;;)
1398 {
1399 // Read some data.
1400 signed_size_type bytes = socket_ops::recvmsg(
1401 s, bufs, count, in_flags, out_flags, ec);
1402
1403 // Check if operation succeeded.
1404 if (bytes >= 0)
1405 {
1406 bytes_transferred = bytes;
1407 return true;
1408 }
1409
1410 // Retry operation if interrupted by signal.
1411 if (ec == boost::asio::error::interrupted)
1412 continue;
1413
1414 // Check if we need to run the operation again.
1415 if (ec == boost::asio::error::would_block
1416 || ec == boost::asio::error::try_again)
1417 return false;
1418
1419 // Operation failed.
1420 bytes_transferred = 0;
1421 return true;
1422 }
1423}
1424
1425#endif // defined(BOOST_ASIO_HAS_IOCP)
1426
1427signed_size_type send(socket_type s, const buf* bufs, size_t count,
1428 int flags, boost::system::error_code& ec)
1429{
1430#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1431 // Send the data.
1432 DWORD send_buf_count = static_cast<DWORD>(count);
1433 DWORD bytes_transferred = 0;
1434 DWORD send_flags = flags;
1435 int result = ::WSASend(s, const_cast<buf*>(bufs),
1436 send_buf_count, &bytes_transferred, send_flags, 0, 0);
1437 get_last_error(ec, true);
1438 if (ec.value() == ERROR_NETNAME_DELETED)
1439 ec = boost::asio::error::connection_reset;
1440 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1441 ec = boost::asio::error::connection_refused;
1442 if (result != 0)
1443 return socket_error_retval;
1444 boost::asio::error::clear(ec);
1445 return bytes_transferred;
1446#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1447 msghdr msg = msghdr();
1448 msg.msg_iov = const_cast<buf*>(bufs);
1449 msg.msg_iovlen = static_cast<int>(count);
1450#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1451 flags |= MSG_NOSIGNAL;
1452#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1453 signed_size_type result = ::sendmsg(fd: s, message: &msg, flags: flags);
1454 get_last_error(ec, is_error_condition: result < 0);
1455 return result;
1456#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1457}
1458
1459signed_size_type send1(socket_type s, const void* data, size_t size,
1460 int flags, boost::system::error_code& ec)
1461{
1462#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1463 // Send the data.
1464 WSABUF buf;
1465 buf.buf = const_cast<char*>(static_cast<const char*>(data));
1466 buf.len = static_cast<ULONG>(size);
1467 DWORD bytes_transferred = 0;
1468 DWORD send_flags = flags;
1469 int result = ::WSASend(s, &buf, 1,
1470 &bytes_transferred, send_flags, 0, 0);
1471 get_last_error(ec, true);
1472 if (ec.value() == ERROR_NETNAME_DELETED)
1473 ec = boost::asio::error::connection_reset;
1474 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1475 ec = boost::asio::error::connection_refused;
1476 if (result != 0)
1477 return socket_error_retval;
1478 boost::asio::error::clear(ec);
1479 return bytes_transferred;
1480#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1481#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1482 flags |= MSG_NOSIGNAL;
1483#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1484 signed_size_type result = ::send(fd: s,
1485 buf: static_cast<const char*>(data), n: size, flags: flags);
1486 get_last_error(ec, is_error_condition: result < 0);
1487 return result;
1488#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1489}
1490
1491size_t sync_send(socket_type s, state_type state, const buf* bufs,
1492 size_t count, int flags, bool all_empty, boost::system::error_code& ec)
1493{
1494 if (s == invalid_socket)
1495 {
1496 ec = boost::asio::error::bad_descriptor;
1497 return 0;
1498 }
1499
1500 // A request to write 0 bytes to a stream is a no-op.
1501 if (all_empty && (state & stream_oriented))
1502 {
1503 boost::asio::error::clear(ec);
1504 return 0;
1505 }
1506
1507 // Read some data.
1508 for (;;)
1509 {
1510 // Try to complete the operation without blocking.
1511 signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
1512
1513 // Check if operation succeeded.
1514 if (bytes >= 0)
1515 return bytes;
1516
1517 // Operation failed.
1518 if ((state & user_set_non_blocking)
1519 || (ec != boost::asio::error::would_block
1520 && ec != boost::asio::error::try_again))
1521 return 0;
1522
1523 // Wait for socket to become ready.
1524 if (socket_ops::poll_write(s, state: 0, msec: -1, ec) < 0)
1525 return 0;
1526 }
1527}
1528
1529size_t sync_send1(socket_type s, state_type state, const void* data,
1530 size_t size, int flags, boost::system::error_code& ec)
1531{
1532 if (s == invalid_socket)
1533 {
1534 ec = boost::asio::error::bad_descriptor;
1535 return 0;
1536 }
1537
1538 // A request to write 0 bytes to a stream is a no-op.
1539 if (size == 0 && (state & stream_oriented))
1540 {
1541 boost::asio::error::clear(ec);
1542 return 0;
1543 }
1544
1545 // Read some data.
1546 for (;;)
1547 {
1548 // Try to complete the operation without blocking.
1549 signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);
1550
1551 // Check if operation succeeded.
1552 if (bytes >= 0)
1553 return bytes;
1554
1555 // Operation failed.
1556 if ((state & user_set_non_blocking)
1557 || (ec != boost::asio::error::would_block
1558 && ec != boost::asio::error::try_again))
1559 return 0;
1560
1561 // Wait for socket to become ready.
1562 if (socket_ops::poll_write(s, state: 0, msec: -1, ec) < 0)
1563 return 0;
1564 }
1565}
1566
1567#if defined(BOOST_ASIO_HAS_IOCP)
1568
1569void complete_iocp_send(
1570 const weak_cancel_token_type& cancel_token,
1571 boost::system::error_code& ec)
1572{
1573 // Map non-portable errors to their portable counterparts.
1574 if (ec.value() == ERROR_NETNAME_DELETED)
1575 {
1576 if (cancel_token.expired())
1577 ec = boost::asio::error::operation_aborted;
1578 else
1579 ec = boost::asio::error::connection_reset;
1580 }
1581 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1582 {
1583 ec = boost::asio::error::connection_refused;
1584 }
1585}
1586
1587#else // defined(BOOST_ASIO_HAS_IOCP)
1588
1589bool non_blocking_send(socket_type s,
1590 const buf* bufs, size_t count, int flags,
1591 boost::system::error_code& ec, size_t& bytes_transferred)
1592{
1593 for (;;)
1594 {
1595 // Write some data.
1596 signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
1597
1598 // Check if operation succeeded.
1599 if (bytes >= 0)
1600 {
1601 bytes_transferred = bytes;
1602 return true;
1603 }
1604
1605 // Retry operation if interrupted by signal.
1606 if (ec == boost::asio::error::interrupted)
1607 continue;
1608
1609 // Check if we need to run the operation again.
1610 if (ec == boost::asio::error::would_block
1611 || ec == boost::asio::error::try_again)
1612 return false;
1613
1614 // Operation failed.
1615 bytes_transferred = 0;
1616 return true;
1617 }
1618}
1619
1620bool non_blocking_send1(socket_type s,
1621 const void* data, size_t size, int flags,
1622 boost::system::error_code& ec, size_t& bytes_transferred)
1623{
1624 for (;;)
1625 {
1626 // Write some data.
1627 signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);
1628
1629 // Check if operation succeeded.
1630 if (bytes >= 0)
1631 {
1632 bytes_transferred = bytes;
1633 return true;
1634 }
1635
1636 // Retry operation if interrupted by signal.
1637 if (ec == boost::asio::error::interrupted)
1638 continue;
1639
1640 // Check if we need to run the operation again.
1641 if (ec == boost::asio::error::would_block
1642 || ec == boost::asio::error::try_again)
1643 return false;
1644
1645 // Operation failed.
1646 bytes_transferred = 0;
1647 return true;
1648 }
1649}
1650
1651#endif // defined(BOOST_ASIO_HAS_IOCP)
1652
1653signed_size_type sendto(socket_type s, const buf* bufs,
1654 size_t count, int flags, const void* addr,
1655 std::size_t addrlen, boost::system::error_code& ec)
1656{
1657#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1658 // Send the data.
1659 DWORD send_buf_count = static_cast<DWORD>(count);
1660 DWORD bytes_transferred = 0;
1661 int result = ::WSASendTo(s, const_cast<buf*>(bufs),
1662 send_buf_count, &bytes_transferred, flags,
1663 static_cast<const socket_addr_type*>(addr),
1664 static_cast<int>(addrlen), 0, 0);
1665 get_last_error(ec, true);
1666 if (ec.value() == ERROR_NETNAME_DELETED)
1667 ec = boost::asio::error::connection_reset;
1668 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1669 ec = boost::asio::error::connection_refused;
1670 if (result != 0)
1671 return socket_error_retval;
1672 boost::asio::error::clear(ec);
1673 return bytes_transferred;
1674#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1675 msghdr msg = msghdr();
1676 init_msghdr_msg_name(name&: msg.msg_name, addr);
1677 msg.msg_namelen = static_cast<int>(addrlen);
1678 msg.msg_iov = const_cast<buf*>(bufs);
1679 msg.msg_iovlen = static_cast<int>(count);
1680#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1681 flags |= MSG_NOSIGNAL;
1682#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1683 signed_size_type result = ::sendmsg(fd: s, message: &msg, flags: flags);
1684 get_last_error(ec, is_error_condition: result < 0);
1685 return result;
1686#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1687}
1688
1689template <typename SockLenType>
1690inline signed_size_type call_sendto(SockLenType msghdr::*,
1691 socket_type s, const void* data, size_t size, int flags,
1692 const void* addr, std::size_t addrlen)
1693{
1694 return ::sendto(fd: s, buf: static_cast<char*>(const_cast<void*>(data)), n: size, flags: flags,
1695 addr: static_cast<const socket_addr_type*>(addr), addr_len: (SockLenType)addrlen);
1696}
1697
1698signed_size_type sendto1(socket_type s, const void* data,
1699 size_t size, int flags, const void* addr,
1700 std::size_t addrlen, boost::system::error_code& ec)
1701{
1702#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1703 // Send the data.
1704 WSABUF buf;
1705 buf.buf = const_cast<char*>(static_cast<const char*>(data));
1706 buf.len = static_cast<ULONG>(size);
1707 DWORD bytes_transferred = 0;
1708 int result = ::WSASendTo(s, &buf, 1, &bytes_transferred, flags,
1709 static_cast<const socket_addr_type*>(addr),
1710 static_cast<int>(addrlen), 0, 0);
1711 get_last_error(ec, true);
1712 if (ec.value() == ERROR_NETNAME_DELETED)
1713 ec = boost::asio::error::connection_reset;
1714 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1715 ec = boost::asio::error::connection_refused;
1716 if (result != 0)
1717 return socket_error_retval;
1718 boost::asio::error::clear(ec);
1719 return bytes_transferred;
1720#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1721#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1722 flags |= MSG_NOSIGNAL;
1723#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1724 signed_size_type result = call_sendto(&msghdr::msg_namelen,
1725 s, data, size, flags, addr, addrlen);
1726 get_last_error(ec, is_error_condition: result < 0);
1727 return result;
1728#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1729}
1730
1731size_t sync_sendto(socket_type s, state_type state,
1732 const buf* bufs, size_t count, int flags, const void* addr,
1733 std::size_t addrlen, boost::system::error_code& ec)
1734{
1735 if (s == invalid_socket)
1736 {
1737 ec = boost::asio::error::bad_descriptor;
1738 return 0;
1739 }
1740
1741 // Write some data.
1742 for (;;)
1743 {
1744 // Try to complete the operation without blocking.
1745 signed_size_type bytes = socket_ops::sendto(
1746 s, bufs, count, flags, addr, addrlen, ec);
1747
1748 // Check if operation succeeded.
1749 if (bytes >= 0)
1750 return bytes;
1751
1752 // Operation failed.
1753 if ((state & user_set_non_blocking)
1754 || (ec != boost::asio::error::would_block
1755 && ec != boost::asio::error::try_again))
1756 return 0;
1757
1758 // Wait for socket to become ready.
1759 if (socket_ops::poll_write(s, state: 0, msec: -1, ec) < 0)
1760 return 0;
1761 }
1762}
1763
1764size_t sync_sendto1(socket_type s, state_type state,
1765 const void* data, size_t size, int flags, const void* addr,
1766 std::size_t addrlen, boost::system::error_code& ec)
1767{
1768 if (s == invalid_socket)
1769 {
1770 ec = boost::asio::error::bad_descriptor;
1771 return 0;
1772 }
1773
1774 // Write some data.
1775 for (;;)
1776 {
1777 // Try to complete the operation without blocking.
1778 signed_size_type bytes = socket_ops::sendto1(
1779 s, data, size, flags, addr, addrlen, ec);
1780
1781 // Check if operation succeeded.
1782 if (bytes >= 0)
1783 return bytes;
1784
1785 // Operation failed.
1786 if ((state & user_set_non_blocking)
1787 || (ec != boost::asio::error::would_block
1788 && ec != boost::asio::error::try_again))
1789 return 0;
1790
1791 // Wait for socket to become ready.
1792 if (socket_ops::poll_write(s, state: 0, msec: -1, ec) < 0)
1793 return 0;
1794 }
1795}
1796
1797#if !defined(BOOST_ASIO_HAS_IOCP)
1798
1799bool non_blocking_sendto(socket_type s,
1800 const buf* bufs, size_t count, int flags,
1801 const void* addr, std::size_t addrlen,
1802 boost::system::error_code& ec, size_t& bytes_transferred)
1803{
1804 for (;;)
1805 {
1806 // Write some data.
1807 signed_size_type bytes = socket_ops::sendto(
1808 s, bufs, count, flags, addr, addrlen, ec);
1809
1810 // Check if operation succeeded.
1811 if (bytes >= 0)
1812 {
1813 bytes_transferred = bytes;
1814 return true;
1815 }
1816
1817 // Retry operation if interrupted by signal.
1818 if (ec == boost::asio::error::interrupted)
1819 continue;
1820
1821 // Check if we need to run the operation again.
1822 if (ec == boost::asio::error::would_block
1823 || ec == boost::asio::error::try_again)
1824 return false;
1825
1826 // Operation failed.
1827 bytes_transferred = 0;
1828 return true;
1829 }
1830}
1831
1832bool non_blocking_sendto1(socket_type s,
1833 const void* data, size_t size, int flags,
1834 const void* addr, std::size_t addrlen,
1835 boost::system::error_code& ec, size_t& bytes_transferred)
1836{
1837 for (;;)
1838 {
1839 // Write some data.
1840 signed_size_type bytes = socket_ops::sendto1(
1841 s, data, size, flags, addr, addrlen, ec);
1842
1843 // Check if operation succeeded.
1844 if (bytes >= 0)
1845 {
1846 bytes_transferred = bytes;
1847 return true;
1848 }
1849
1850 // Retry operation if interrupted by signal.
1851 if (ec == boost::asio::error::interrupted)
1852 continue;
1853
1854 // Check if we need to run the operation again.
1855 if (ec == boost::asio::error::would_block
1856 || ec == boost::asio::error::try_again)
1857 return false;
1858
1859 // Operation failed.
1860 bytes_transferred = 0;
1861 return true;
1862 }
1863}
1864
1865#endif // !defined(BOOST_ASIO_HAS_IOCP)
1866
1867socket_type socket(int af, int type, int protocol,
1868 boost::system::error_code& ec)
1869{
1870#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1871 socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED);
1872 get_last_error(ec, s == invalid_socket);
1873 if (s == invalid_socket)
1874 return s;
1875
1876 if (af == BOOST_ASIO_OS_DEF(AF_INET6))
1877 {
1878 // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
1879 // false. This will only succeed on Windows Vista and later versions of
1880 // Windows, where a dual-stack IPv4/v6 implementation is available.
1881 DWORD optval = 0;
1882 ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
1883 reinterpret_cast<const char*>(&optval), sizeof(optval));
1884 }
1885
1886 return s;
1887#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
1888 socket_type s = ::socket(af, type, protocol);
1889 get_last_error(ec, s == invalid_socket);
1890 if (s == invalid_socket)
1891 return s;
1892
1893 int optval = 1;
1894 int result = ::setsockopt(s, SOL_SOCKET,
1895 SO_NOSIGPIPE, &optval, sizeof(optval));
1896 get_last_error(ec, result != 0);
1897 if (result != 0)
1898 {
1899 ::close(s);
1900 return invalid_socket;
1901 }
1902
1903 return s;
1904#else
1905 int s = ::socket(domain: af, type: type, protocol: protocol);
1906 get_last_error(ec, is_error_condition: s < 0);
1907 return s;
1908#endif
1909}
1910
1911template <typename SockLenType>
1912inline int call_setsockopt(SockLenType msghdr::*,
1913 socket_type s, int level, int optname,
1914 const void* optval, std::size_t optlen)
1915{
1916 return ::setsockopt(fd: s, level: level, optname: optname,
1917 optval: (const char*)optval, optlen: (SockLenType)optlen);
1918}
1919
1920int setsockopt(socket_type s, state_type& state, int level, int optname,
1921 const void* optval, std::size_t optlen, boost::system::error_code& ec)
1922{
1923 if (s == invalid_socket)
1924 {
1925 ec = boost::asio::error::bad_descriptor;
1926 return socket_error_retval;
1927 }
1928
1929 if (level == custom_socket_option_level && optname == always_fail_option)
1930 {
1931 ec = boost::asio::error::invalid_argument;
1932 return socket_error_retval;
1933 }
1934
1935 if (level == custom_socket_option_level
1936 && optname == enable_connection_aborted_option)
1937 {
1938 if (optlen != sizeof(int))
1939 {
1940 ec = boost::asio::error::invalid_argument;
1941 return socket_error_retval;
1942 }
1943
1944 if (*static_cast<const int*>(optval))
1945 state |= enable_connection_aborted;
1946 else
1947 state &= ~enable_connection_aborted;
1948 boost::asio::error::clear(ec);
1949 return 0;
1950 }
1951
1952 if (level == SOL_SOCKET && optname == SO_LINGER)
1953 state |= user_set_linger;
1954
1955#if defined(__BORLANDC__)
1956 // Mysteriously, using the getsockopt and setsockopt functions directly with
1957 // Borland C++ results in incorrect values being set and read. The bug can be
1958 // worked around by using function addresses resolved with GetProcAddress.
1959 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
1960 {
1961 typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
1962 if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
1963 {
1964 int result = sso(s, level, optname,
1965 reinterpret_cast<const char*>(optval),
1966 static_cast<int>(optlen));
1967 get_last_error(ec, result != 0);
1968 return result;
1969 }
1970 }
1971 ec = boost::asio::error::fault;
1972 return socket_error_retval;
1973#else // defined(__BORLANDC__)
1974 int result = call_setsockopt(&msghdr::msg_namelen,
1975 s, level, optname, optval, optlen);
1976 get_last_error(ec, is_error_condition: result != 0);
1977 if (result == 0)
1978 {
1979#if defined(__MACH__) && defined(__APPLE__) \
1980 || defined(__NetBSD__) || defined(__FreeBSD__) \
1981 || defined(__OpenBSD__) || defined(__QNX__)
1982 // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
1983 // need to also set SO_REUSEPORT on BSD-based platforms.
1984 if ((state & datagram_oriented)
1985 && level == SOL_SOCKET && optname == SO_REUSEADDR)
1986 {
1987 call_setsockopt(&msghdr::msg_namelen, s,
1988 SOL_SOCKET, SO_REUSEPORT, optval, optlen);
1989 }
1990#endif
1991 }
1992
1993 return result;
1994#endif // defined(__BORLANDC__)
1995}
1996
1997template <typename SockLenType>
1998inline int call_getsockopt(SockLenType msghdr::*,
1999 socket_type s, int level, int optname,
2000 void* optval, std::size_t* optlen)
2001{
2002 SockLenType tmp_optlen = (SockLenType)*optlen;
2003 int result = ::getsockopt(fd: s, level: level, optname: optname, optval: (char*)optval, optlen: &tmp_optlen);
2004 *optlen = (std::size_t)tmp_optlen;
2005 return result;
2006}
2007
2008int getsockopt(socket_type s, state_type state, int level, int optname,
2009 void* optval, size_t* optlen, boost::system::error_code& ec)
2010{
2011 if (s == invalid_socket)
2012 {
2013 ec = boost::asio::error::bad_descriptor;
2014 return socket_error_retval;
2015 }
2016
2017 if (level == custom_socket_option_level && optname == always_fail_option)
2018 {
2019 ec = boost::asio::error::invalid_argument;
2020 return socket_error_retval;
2021 }
2022
2023 if (level == custom_socket_option_level
2024 && optname == enable_connection_aborted_option)
2025 {
2026 if (*optlen != sizeof(int))
2027 {
2028 ec = boost::asio::error::invalid_argument;
2029 return socket_error_retval;
2030 }
2031
2032 *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
2033 boost::asio::error::clear(ec);
2034 return 0;
2035 }
2036
2037#if defined(__BORLANDC__)
2038 // Mysteriously, using the getsockopt and setsockopt functions directly with
2039 // Borland C++ results in incorrect values being set and read. The bug can be
2040 // worked around by using function addresses resolved with GetProcAddress.
2041 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
2042 {
2043 typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
2044 if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
2045 {
2046 int tmp_optlen = static_cast<int>(*optlen);
2047 int result = gso(s, level, optname,
2048 reinterpret_cast<char*>(optval), &tmp_optlen);
2049 get_last_error(ec, result != 0);
2050 *optlen = static_cast<size_t>(tmp_optlen);
2051 if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
2052 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
2053 {
2054 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
2055 // only supported on Windows Vista and later. To simplify program logic
2056 // we will fake success of getting this option and specify that the
2057 // value is non-zero (i.e. true). This corresponds to the behavior of
2058 // IPv6 sockets on Windows platforms pre-Vista.
2059 *static_cast<DWORD*>(optval) = 1;
2060 boost::asio::error::clear(ec);
2061 }
2062 return result;
2063 }
2064 }
2065 ec = boost::asio::error::fault;
2066 return socket_error_retval;
2067#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2068 int result = call_getsockopt(&msghdr::msg_namelen,
2069 s, level, optname, optval, optlen);
2070 get_last_error(ec, result != 0);
2071 if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
2072 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
2073 {
2074 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
2075 // supported on Windows Vista and later. To simplify program logic we will
2076 // fake success of getting this option and specify that the value is
2077 // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
2078 // on Windows platforms pre-Vista.
2079 *static_cast<DWORD*>(optval) = 1;
2080 boost::asio::error::clear(ec);
2081 }
2082 return result;
2083#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2084 int result = call_getsockopt(&msghdr::msg_namelen,
2085 s, level, optname, optval, optlen);
2086 get_last_error(ec, is_error_condition: result != 0);
2087#if defined(__linux__)
2088 if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
2089 && (optname == SO_SNDBUF || optname == SO_RCVBUF))
2090 {
2091 // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
2092 // to set the buffer size to N*2. Linux puts additional stuff into the
2093 // buffers so that only about half is actually available to the application.
2094 // The retrieved value is divided by 2 here to make it appear as though the
2095 // correct value has been set.
2096 *static_cast<int*>(optval) /= 2;
2097 }
2098#endif // defined(__linux__)
2099 return result;
2100#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2101}
2102
2103template <typename SockLenType>
2104inline int call_getpeername(SockLenType msghdr::*,
2105 socket_type s, void* addr, std::size_t* addrlen)
2106{
2107 SockLenType tmp_addrlen = (SockLenType)*addrlen;
2108 int result = ::getpeername(fd: s,
2109 addr: static_cast<socket_addr_type*>(addr), len: &tmp_addrlen);
2110 *addrlen = (std::size_t)tmp_addrlen;
2111 return result;
2112}
2113
2114int getpeername(socket_type s, void* addr, std::size_t* addrlen,
2115 bool cached, boost::system::error_code& ec)
2116{
2117 if (s == invalid_socket)
2118 {
2119 ec = boost::asio::error::bad_descriptor;
2120 return socket_error_retval;
2121 }
2122
2123#if defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP) \
2124 || defined(__CYGWIN__)
2125 if (cached)
2126 {
2127 // Check if socket is still connected.
2128 DWORD connect_time = 0;
2129 size_t connect_time_len = sizeof(connect_time);
2130 if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,
2131 &connect_time, &connect_time_len, ec) == socket_error_retval)
2132 {
2133 return socket_error_retval;
2134 }
2135 if (connect_time == 0xFFFFFFFF)
2136 {
2137 ec = boost::asio::error::not_connected;
2138 return socket_error_retval;
2139 }
2140
2141 // The cached value is still valid.
2142 boost::asio::error::clear(ec);
2143 return 0;
2144 }
2145#else // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP)
2146 // || defined(__CYGWIN__)
2147 (void)cached;
2148#endif // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP)
2149 // || defined(__CYGWIN__)
2150
2151 int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen);
2152 get_last_error(ec, is_error_condition: result != 0);
2153 return result;
2154}
2155
2156template <typename SockLenType>
2157inline int call_getsockname(SockLenType msghdr::*,
2158 socket_type s, void* addr, std::size_t* addrlen)
2159{
2160 SockLenType tmp_addrlen = (SockLenType)*addrlen;
2161 int result = ::getsockname(fd: s,
2162 addr: static_cast<socket_addr_type*>(addr), len: &tmp_addrlen);
2163 *addrlen = (std::size_t)tmp_addrlen;
2164 return result;
2165}
2166
2167int getsockname(socket_type s, void* addr,
2168 std::size_t* addrlen, boost::system::error_code& ec)
2169{
2170 if (s == invalid_socket)
2171 {
2172 ec = boost::asio::error::bad_descriptor;
2173 return socket_error_retval;
2174 }
2175
2176 int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen);
2177 get_last_error(ec, is_error_condition: result != 0);
2178 return result;
2179}
2180
2181int ioctl(socket_type s, state_type& state, int cmd,
2182 ioctl_arg_type* arg, boost::system::error_code& ec)
2183{
2184 if (s == invalid_socket)
2185 {
2186 ec = boost::asio::error::bad_descriptor;
2187 return socket_error_retval;
2188 }
2189
2190#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2191 int result = ::ioctlsocket(s, cmd, arg);
2192#elif defined(__MACH__) && defined(__APPLE__) \
2193 || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
2194 int result = ::ioctl(s, static_cast<unsigned int>(cmd), arg);
2195#else
2196 int result = ::ioctl(fd: s, request: cmd, arg);
2197#endif
2198 get_last_error(ec, is_error_condition: result < 0);
2199 if (result >= 0)
2200 {
2201 // When updating the non-blocking mode we always perform the ioctl syscall,
2202 // even if the flags would otherwise indicate that the socket is already in
2203 // the correct state. This ensures that the underlying socket is put into
2204 // the state that has been requested by the user. If the ioctl syscall was
2205 // successful then we need to update the flags to match.
2206 if (cmd == static_cast<int>(FIONBIO))
2207 {
2208 if (*arg)
2209 {
2210 state |= user_set_non_blocking;
2211 }
2212 else
2213 {
2214 // Clearing the non-blocking mode always overrides any internally-set
2215 // non-blocking flag. Any subsequent asynchronous operations will need
2216 // to re-enable non-blocking I/O.
2217 state &= ~(user_set_non_blocking | internal_non_blocking);
2218 }
2219 }
2220 }
2221
2222 return result;
2223}
2224
2225int select(int nfds, fd_set* readfds, fd_set* writefds,
2226 fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec)
2227{
2228#if defined(__EMSCRIPTEN__)
2229 exceptfds = 0;
2230#endif // defined(__EMSCRIPTEN__)
2231#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2232 if (!readfds && !writefds && !exceptfds && timeout)
2233 {
2234 DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
2235 if (milliseconds == 0)
2236 milliseconds = 1; // Force context switch.
2237 ::Sleep(milliseconds);
2238 boost::asio::error::clear(ec);
2239 return 0;
2240 }
2241
2242 // The select() call allows timeout values measured in microseconds, but the
2243 // system clock (as wrapped by boost::posix_time::microsec_clock) typically
2244 // has a resolution of 10 milliseconds. This can lead to a spinning select
2245 // reactor, meaning increased CPU usage, when waiting for the earliest
2246 // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
2247 // spin we'll use a minimum timeout of 1 millisecond.
2248 if (timeout && timeout->tv_sec == 0
2249 && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
2250 timeout->tv_usec = 1000;
2251#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2252
2253#if defined(__hpux) && defined(__SELECT)
2254 timespec ts;
2255 ts.tv_sec = timeout ? timeout->tv_sec : 0;
2256 ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
2257 int result = ::pselect(nfds, readfds,
2258 writefds, exceptfds, timeout ? &ts : 0, 0);
2259#else
2260 int result = ::select(nfds: nfds, readfds: readfds, writefds: writefds, exceptfds: exceptfds, timeout: timeout);
2261#endif
2262 get_last_error(ec, is_error_condition: result < 0);
2263 return result;
2264}
2265
2266int poll_read(socket_type s, state_type state,
2267 int msec, boost::system::error_code& ec)
2268{
2269 if (s == invalid_socket)
2270 {
2271 ec = boost::asio::error::bad_descriptor;
2272 return socket_error_retval;
2273 }
2274
2275#if defined(BOOST_ASIO_WINDOWS) \
2276 || defined(__CYGWIN__) \
2277 || defined(__SYMBIAN32__)
2278 fd_set fds;
2279 FD_ZERO(&fds);
2280 FD_SET(s, &fds);
2281 timeval timeout_obj;
2282 timeval* timeout;
2283 if (state & user_set_non_blocking)
2284 {
2285 timeout_obj.tv_sec = 0;
2286 timeout_obj.tv_usec = 0;
2287 timeout = &timeout_obj;
2288 }
2289 else if (msec >= 0)
2290 {
2291 timeout_obj.tv_sec = msec / 1000;
2292 timeout_obj.tv_usec = (msec % 1000) * 1000;
2293 timeout = &timeout_obj;
2294 }
2295 else
2296 timeout = 0;
2297 int result = ::select(s + 1, &fds, 0, 0, timeout);
2298 get_last_error(ec, result < 0);
2299#else // defined(BOOST_ASIO_WINDOWS)
2300 // || defined(__CYGWIN__)
2301 // || defined(__SYMBIAN32__)
2302 pollfd fds;
2303 fds.fd = s;
2304 fds.events = POLLIN;
2305 fds.revents = 0;
2306 int timeout = (state & user_set_non_blocking) ? 0 : msec;
2307 int result = ::poll(fds: &fds, nfds: 1, timeout: timeout);
2308 get_last_error(ec, is_error_condition: result < 0);
2309#endif // defined(BOOST_ASIO_WINDOWS)
2310 // || defined(__CYGWIN__)
2311 // || defined(__SYMBIAN32__)
2312 if (result == 0)
2313 if (state & user_set_non_blocking)
2314 ec = boost::asio::error::would_block;
2315 return result;
2316}
2317
2318int poll_write(socket_type s, state_type state,
2319 int msec, boost::system::error_code& ec)
2320{
2321 if (s == invalid_socket)
2322 {
2323 ec = boost::asio::error::bad_descriptor;
2324 return socket_error_retval;
2325 }
2326
2327#if defined(BOOST_ASIO_WINDOWS) \
2328 || defined(__CYGWIN__) \
2329 || defined(__SYMBIAN32__)
2330 fd_set fds;
2331 FD_ZERO(&fds);
2332 FD_SET(s, &fds);
2333 timeval timeout_obj;
2334 timeval* timeout;
2335 if (state & user_set_non_blocking)
2336 {
2337 timeout_obj.tv_sec = 0;
2338 timeout_obj.tv_usec = 0;
2339 timeout = &timeout_obj;
2340 }
2341 else if (msec >= 0)
2342 {
2343 timeout_obj.tv_sec = msec / 1000;
2344 timeout_obj.tv_usec = (msec % 1000) * 1000;
2345 timeout = &timeout_obj;
2346 }
2347 else
2348 timeout = 0;
2349 int result = ::select(s + 1, 0, &fds, 0, timeout);
2350 get_last_error(ec, result < 0);
2351#else // defined(BOOST_ASIO_WINDOWS)
2352 // || defined(__CYGWIN__)
2353 // || defined(__SYMBIAN32__)
2354 pollfd fds;
2355 fds.fd = s;
2356 fds.events = POLLOUT;
2357 fds.revents = 0;
2358 int timeout = (state & user_set_non_blocking) ? 0 : msec;
2359 int result = ::poll(fds: &fds, nfds: 1, timeout: timeout);
2360 get_last_error(ec, is_error_condition: result < 0);
2361#endif // defined(BOOST_ASIO_WINDOWS)
2362 // || defined(__CYGWIN__)
2363 // || defined(__SYMBIAN32__)
2364 if (result == 0)
2365 if (state & user_set_non_blocking)
2366 ec = boost::asio::error::would_block;
2367 return result;
2368}
2369
2370int poll_error(socket_type s, state_type state,
2371 int msec, boost::system::error_code& ec)
2372{
2373 if (s == invalid_socket)
2374 {
2375 ec = boost::asio::error::bad_descriptor;
2376 return socket_error_retval;
2377 }
2378
2379#if defined(BOOST_ASIO_WINDOWS) \
2380 || defined(__CYGWIN__) \
2381 || defined(__SYMBIAN32__)
2382 fd_set fds;
2383 FD_ZERO(&fds);
2384 FD_SET(s, &fds);
2385 timeval timeout_obj;
2386 timeval* timeout;
2387 if (state & user_set_non_blocking)
2388 {
2389 timeout_obj.tv_sec = 0;
2390 timeout_obj.tv_usec = 0;
2391 timeout = &timeout_obj;
2392 }
2393 else if (msec >= 0)
2394 {
2395 timeout_obj.tv_sec = msec / 1000;
2396 timeout_obj.tv_usec = (msec % 1000) * 1000;
2397 timeout = &timeout_obj;
2398 }
2399 else
2400 timeout = 0;
2401 int result = ::select(s + 1, 0, 0, &fds, timeout);
2402 get_last_error(ec, result < 0);
2403#else // defined(BOOST_ASIO_WINDOWS)
2404 // || defined(__CYGWIN__)
2405 // || defined(__SYMBIAN32__)
2406 pollfd fds;
2407 fds.fd = s;
2408 fds.events = POLLPRI | POLLERR | POLLHUP;
2409 fds.revents = 0;
2410 int timeout = (state & user_set_non_blocking) ? 0 : msec;
2411 int result = ::poll(fds: &fds, nfds: 1, timeout: timeout);
2412 get_last_error(ec, is_error_condition: result < 0);
2413#endif // defined(BOOST_ASIO_WINDOWS)
2414 // || defined(__CYGWIN__)
2415 // || defined(__SYMBIAN32__)
2416 if (result == 0)
2417 if (state & user_set_non_blocking)
2418 ec = boost::asio::error::would_block;
2419 return result;
2420}
2421
2422int poll_connect(socket_type s, int msec, boost::system::error_code& ec)
2423{
2424 if (s == invalid_socket)
2425 {
2426 ec = boost::asio::error::bad_descriptor;
2427 return socket_error_retval;
2428 }
2429
2430#if defined(BOOST_ASIO_WINDOWS) \
2431 || defined(__CYGWIN__) \
2432 || defined(__SYMBIAN32__)
2433 fd_set write_fds;
2434 FD_ZERO(&write_fds);
2435 FD_SET(s, &write_fds);
2436 fd_set except_fds;
2437 FD_ZERO(&except_fds);
2438 FD_SET(s, &except_fds);
2439 timeval timeout_obj;
2440 timeval* timeout;
2441 if (msec >= 0)
2442 {
2443 timeout_obj.tv_sec = msec / 1000;
2444 timeout_obj.tv_usec = (msec % 1000) * 1000;
2445 timeout = &timeout_obj;
2446 }
2447 else
2448 timeout = 0;
2449 int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout);
2450 get_last_error(ec, result < 0);
2451 return result;
2452#else // defined(BOOST_ASIO_WINDOWS)
2453 // || defined(__CYGWIN__)
2454 // || defined(__SYMBIAN32__)
2455 pollfd fds;
2456 fds.fd = s;
2457 fds.events = POLLOUT;
2458 fds.revents = 0;
2459 int result = ::poll(fds: &fds, nfds: 1, timeout: msec);
2460 get_last_error(ec, is_error_condition: result < 0);
2461 return result;
2462#endif // defined(BOOST_ASIO_WINDOWS)
2463 // || defined(__CYGWIN__)
2464 // || defined(__SYMBIAN32__)
2465}
2466
2467#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
2468
2469const char* inet_ntop(int af, const void* src, char* dest, size_t length,
2470 unsigned long scope_id, boost::system::error_code& ec)
2471{
2472 clear_last_error();
2473#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
2474 using namespace std; // For sprintf.
2475 const unsigned char* bytes = static_cast<const unsigned char*>(src);
2476 if (af == BOOST_ASIO_OS_DEF(AF_INET))
2477 {
2478 sprintf_s(dest, length, "%u.%u.%u.%u",
2479 bytes[0], bytes[1], bytes[2], bytes[3]);
2480 return dest;
2481 }
2482 else if (af == BOOST_ASIO_OS_DEF(AF_INET6))
2483 {
2484 size_t n = 0, b = 0, z = 0;
2485 while (n < length && b < 16)
2486 {
2487 if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0)
2488 {
2489 do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0);
2490 n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z;
2491 }
2492 else
2493 {
2494 n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "",
2495 (static_cast<u_long_type>(bytes[b]) << 8) | bytes[b + 1]);
2496 b += 2;
2497 }
2498 }
2499 if (scope_id)
2500 n += sprintf_s(dest + n, length - n, "%%%lu", scope_id);
2501 return dest;
2502 }
2503 else
2504 {
2505 ec = boost::asio::error::address_family_not_supported;
2506 return 0;
2507 }
2508#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2509 using namespace std; // For memcpy.
2510
2511 if (af != BOOST_ASIO_OS_DEF(AF_INET) && af != BOOST_ASIO_OS_DEF(AF_INET6))
2512 {
2513 ec = boost::asio::error::address_family_not_supported;
2514 return 0;
2515 }
2516
2517 union
2518 {
2519 socket_addr_type base;
2520 sockaddr_storage_type storage;
2521 sockaddr_in4_type v4;
2522 sockaddr_in6_type v6;
2523 } address;
2524 DWORD address_length;
2525 if (af == BOOST_ASIO_OS_DEF(AF_INET))
2526 {
2527 address_length = sizeof(sockaddr_in4_type);
2528 address.v4.sin_family = BOOST_ASIO_OS_DEF(AF_INET);
2529 address.v4.sin_port = 0;
2530 memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
2531 }
2532 else // AF_INET6
2533 {
2534 address_length = sizeof(sockaddr_in6_type);
2535 address.v6.sin6_family = BOOST_ASIO_OS_DEF(AF_INET6);
2536 address.v6.sin6_port = 0;
2537 address.v6.sin6_flowinfo = 0;
2538 address.v6.sin6_scope_id = scope_id;
2539 memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
2540 }
2541
2542 DWORD string_length = static_cast<DWORD>(length);
2543#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
2544 LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
2545 int result = ::WSAAddressToStringW(&address.base,
2546 address_length, 0, string_buffer, &string_length);
2547 get_last_error(ec, true);
2548 ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1,
2549 dest, static_cast<int>(length), 0, 0);
2550#else
2551 int result = ::WSAAddressToStringA(&address.base,
2552 address_length, 0, dest, &string_length);
2553 get_last_error(ec, true);
2554#endif
2555
2556 // Windows may set error code on success.
2557 if (result != socket_error_retval)
2558 boost::asio::error::clear(ec);
2559
2560 // Windows may not set an error code on failure.
2561 else if (result == socket_error_retval && !ec)
2562 ec = boost::asio::error::invalid_argument;
2563
2564 return result == socket_error_retval ? 0 : dest;
2565#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2566 const char* result = ::inet_ntop(af: af, cp: src, buf: dest, len: static_cast<int>(length));
2567 get_last_error(ec, is_error_condition: true);
2568 if (result == 0 && !ec)
2569 ec = boost::asio::error::invalid_argument;
2570 if (result != 0 && af == BOOST_ASIO_OS_DEF(AF_INET6) && scope_id != 0)
2571 {
2572 using namespace std; // For strcat and sprintf.
2573 char if_name[(IF_NAMESIZE > 21 ? IF_NAMESIZE : 21) + 1] = "%";
2574 const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
2575 bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
2576 && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
2577 bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)
2578 && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));
2579 if ((!is_link_local && !is_multicast_link_local)
2580 || if_indextoname(ifindex: static_cast<unsigned>(scope_id), ifname: if_name + 1) == 0)
2581#if defined(BOOST_ASIO_HAS_SNPRINTF)
2582 snprintf(if_name + 1, sizeof(if_name) - 1, "%lu", scope_id);
2583#else // defined(BOOST_ASIO_HAS_SNPRINTF)
2584 sprintf(s: if_name + 1, format: "%lu", scope_id);
2585#endif // defined(BOOST_ASIO_HAS_SNPRINTF)
2586 strcat(dest: dest, src: if_name);
2587 }
2588 return result;
2589#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2590}
2591
2592int inet_pton(int af, const char* src, void* dest,
2593 unsigned long* scope_id, boost::system::error_code& ec)
2594{
2595 clear_last_error();
2596#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
2597 using namespace std; // For sscanf.
2598 unsigned char* bytes = static_cast<unsigned char*>(dest);
2599 if (af == BOOST_ASIO_OS_DEF(AF_INET))
2600 {
2601 unsigned int b0, b1, b2, b3;
2602 if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4)
2603 {
2604 ec = boost::asio::error::invalid_argument;
2605 return -1;
2606 }
2607 if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255)
2608 {
2609 ec = boost::asio::error::invalid_argument;
2610 return -1;
2611 }
2612 bytes[0] = static_cast<unsigned char>(b0);
2613 bytes[1] = static_cast<unsigned char>(b1);
2614 bytes[2] = static_cast<unsigned char>(b2);
2615 bytes[3] = static_cast<unsigned char>(b3);
2616 boost::asio::error::clear(ec);
2617 return 1;
2618 }
2619 else if (af == BOOST_ASIO_OS_DEF(AF_INET6))
2620 {
2621 unsigned char* bytes = static_cast<unsigned char*>(dest);
2622 std::memset(bytes, 0, 16);
2623 unsigned char back_bytes[16] = { 0 };
2624 int num_front_bytes = 0, num_back_bytes = 0;
2625 const char* p = src;
2626
2627 enum { fword, fcolon, bword, scope, done } state = fword;
2628 unsigned long current_word = 0;
2629 while (state != done)
2630 {
2631 if (current_word > 0xFFFF)
2632 {
2633 ec = boost::asio::error::invalid_argument;
2634 return -1;
2635 }
2636
2637 switch (state)
2638 {
2639 case fword:
2640 if (*p >= '0' && *p <= '9')
2641 current_word = current_word * 16 + *p++ - '0';
2642 else if (*p >= 'a' && *p <= 'f')
2643 current_word = current_word * 16 + *p++ - 'a' + 10;
2644 else if (*p >= 'A' && *p <= 'F')
2645 current_word = current_word * 16 + *p++ - 'A' + 10;
2646 else
2647 {
2648 if (num_front_bytes == 16)
2649 {
2650 ec = boost::asio::error::invalid_argument;
2651 return -1;
2652 }
2653
2654 bytes[num_front_bytes++] = (current_word >> 8) & 0xFF;
2655 bytes[num_front_bytes++] = current_word & 0xFF;
2656 current_word = 0;
2657
2658 if (*p == ':')
2659 state = fcolon, ++p;
2660 else if (*p == '%')
2661 state = scope, ++p;
2662 else if (*p == 0)
2663 state = done;
2664 else
2665 {
2666 ec = boost::asio::error::invalid_argument;
2667 return -1;
2668 }
2669 }
2670 break;
2671
2672 case fcolon:
2673 if (*p == ':')
2674 state = bword, ++p;
2675 else
2676 state = fword;
2677 break;
2678
2679 case bword:
2680 if (*p >= '0' && *p <= '9')
2681 current_word = current_word * 16 + *p++ - '0';
2682 else if (*p >= 'a' && *p <= 'f')
2683 current_word = current_word * 16 + *p++ - 'a' + 10;
2684 else if (*p >= 'A' && *p <= 'F')
2685 current_word = current_word * 16 + *p++ - 'A' + 10;
2686 else
2687 {
2688 if (num_front_bytes + num_back_bytes == 16)
2689 {
2690 ec = boost::asio::error::invalid_argument;
2691 return -1;
2692 }
2693
2694 back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF;
2695 back_bytes[num_back_bytes++] = current_word & 0xFF;
2696 current_word = 0;
2697
2698 if (*p == ':')
2699 state = bword, ++p;
2700 else if (*p == '%')
2701 state = scope, ++p;
2702 else if (*p == 0)
2703 state = done;
2704 else
2705 {
2706 ec = boost::asio::error::invalid_argument;
2707 return -1;
2708 }
2709 }
2710 break;
2711
2712 case scope:
2713 if (*p >= '0' && *p <= '9')
2714 current_word = current_word * 10 + *p++ - '0';
2715 else if (*p == 0)
2716 *scope_id = current_word, state = done;
2717 else
2718 {
2719 ec = boost::asio::error::invalid_argument;
2720 return -1;
2721 }
2722 break;
2723
2724 default:
2725 break;
2726 }
2727 }
2728
2729 for (int i = 0; i < num_back_bytes; ++i)
2730 bytes[16 - num_back_bytes + i] = back_bytes[i];
2731
2732 boost::asio::error::clear(ec);
2733 return 1;
2734 }
2735 else
2736 {
2737 ec = boost::asio::error::address_family_not_supported;
2738 return -1;
2739 }
2740#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2741 using namespace std; // For memcpy and strcmp.
2742
2743 if (af != BOOST_ASIO_OS_DEF(AF_INET) && af != BOOST_ASIO_OS_DEF(AF_INET6))
2744 {
2745 ec = boost::asio::error::address_family_not_supported;
2746 return -1;
2747 }
2748
2749 union
2750 {
2751 socket_addr_type base;
2752 sockaddr_storage_type storage;
2753 sockaddr_in4_type v4;
2754 sockaddr_in6_type v6;
2755 } address;
2756 int address_length = sizeof(sockaddr_storage_type);
2757#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
2758 int num_wide_chars = static_cast<int>(strlen(src)) + 1;
2759 LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
2760 ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
2761 int result = ::WSAStringToAddressW(wide_buffer,
2762 af, 0, &address.base, &address_length);
2763 get_last_error(ec, true);
2764#else
2765 int result = ::WSAStringToAddressA(const_cast<char*>(src),
2766 af, 0, &address.base, &address_length);
2767 get_last_error(ec, true);
2768#endif
2769
2770 if (af == BOOST_ASIO_OS_DEF(AF_INET))
2771 {
2772 if (result != socket_error_retval)
2773 {
2774 memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
2775 boost::asio::error::clear(ec);
2776 }
2777 else if (strcmp(src, "255.255.255.255") == 0)
2778 {
2779 static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
2780 boost::asio::error::clear(ec);
2781 }
2782 }
2783 else // AF_INET6
2784 {
2785 if (result != socket_error_retval)
2786 {
2787 memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
2788 if (scope_id)
2789 *scope_id = address.v6.sin6_scope_id;
2790 boost::asio::error::clear(ec);
2791 }
2792 }
2793
2794 // Windows may not set an error code on failure.
2795 if (result == socket_error_retval && !ec)
2796 ec = boost::asio::error::invalid_argument;
2797
2798 if (result != socket_error_retval)
2799 boost::asio::error::clear(ec);
2800
2801 return result == socket_error_retval ? -1 : 1;
2802#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2803 using namespace std; // For strchr, memcpy and atoi.
2804
2805 // On some platforms, inet_pton fails if an address string contains a scope
2806 // id. Detect and remove the scope id before passing the string to inet_pton.
2807 const bool is_v6 = (af == BOOST_ASIO_OS_DEF(AF_INET6));
2808 const char* if_name = is_v6 ? strchr(s: src, c: '%') : 0;
2809 char src_buf[max_addr_v6_str_len + 1];
2810 const char* src_ptr = src;
2811 if (if_name != 0)
2812 {
2813 if (if_name - src > max_addr_v6_str_len)
2814 {
2815 ec = boost::asio::error::invalid_argument;
2816 return 0;
2817 }
2818 memcpy(dest: src_buf, src: src, n: if_name - src);
2819 src_buf[if_name - src] = 0;
2820 src_ptr = src_buf;
2821 }
2822
2823 int result = ::inet_pton(af: af, cp: src_ptr, buf: dest);
2824 get_last_error(ec, is_error_condition: true);
2825 if (result <= 0 && !ec)
2826 ec = boost::asio::error::invalid_argument;
2827 if (result > 0 && is_v6 && scope_id)
2828 {
2829 using namespace std; // For strchr and atoi.
2830 *scope_id = 0;
2831 if (if_name != 0)
2832 {
2833 in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
2834 bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
2835 && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
2836 bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)
2837 && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));
2838 if (is_link_local || is_multicast_link_local)
2839 *scope_id = if_nametoindex(ifname: if_name + 1);
2840 if (*scope_id == 0)
2841 *scope_id = atoi(nptr: if_name + 1);
2842 }
2843 }
2844 return result;
2845#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2846}
2847
2848int gethostname(char* name, int namelen, boost::system::error_code& ec)
2849{
2850#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
2851 try
2852 {
2853 using namespace Windows::Foundation::Collections;
2854 using namespace Windows::Networking;
2855 using namespace Windows::Networking::Connectivity;
2856 IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames();
2857 for (unsigned i = 0; i < hostnames->Size; ++i)
2858 {
2859 HostName^ hostname = hostnames->GetAt(i);
2860 if (hostname->Type == HostNameType::DomainName)
2861 {
2862 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
2863 std::string raw_name = converter.to_bytes(hostname->RawName->Data());
2864 if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(namelen))
2865 {
2866 strcpy_s(name, namelen, raw_name.c_str());
2867 return 0;
2868 }
2869 }
2870 }
2871 return -1;
2872 }
2873 catch (Platform::Exception^ e)
2874 {
2875 ec = boost::system::error_code(e->HResult,
2876 boost::system::system_category());
2877 return -1;
2878 }
2879#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
2880 int result = ::gethostname(name: name, len: namelen);
2881 get_last_error(ec, is_error_condition: result != 0);
2882 return result;
2883#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
2884}
2885
2886#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
2887
2888#if !defined(BOOST_ASIO_HAS_GETADDRINFO)
2889
2890// The following functions are only needed for emulation of getaddrinfo and
2891// getnameinfo.
2892
2893inline boost::system::error_code translate_netdb_error(int error)
2894{
2895 switch (error)
2896 {
2897 case 0:
2898 return boost::system::error_code();
2899 case HOST_NOT_FOUND:
2900 return boost::asio::error::host_not_found;
2901 case TRY_AGAIN:
2902 return boost::asio::error::host_not_found_try_again;
2903 case NO_RECOVERY:
2904 return boost::asio::error::no_recovery;
2905 case NO_DATA:
2906 return boost::asio::error::no_data;
2907 default:
2908 BOOST_ASIO_ASSERT(false);
2909 return boost::asio::error::invalid_argument;
2910 }
2911}
2912
2913inline hostent* gethostbyaddr(const char* addr, int length, int af,
2914 hostent* result, char* buffer, int buflength, boost::system::error_code& ec)
2915{
2916#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2917 (void)(buffer);
2918 (void)(buflength);
2919 hostent* retval = ::gethostbyaddr(addr, length, af);
2920 get_last_error(ec, !retval);
2921 if (!retval)
2922 return 0;
2923 *result = *retval;
2924 return retval;
2925#elif defined(__sun) || defined(__QNX__)
2926 int error = 0;
2927 hostent* retval = ::gethostbyaddr_r(addr, length,
2928 af, result, buffer, buflength, &error);
2929 get_last_error(ec, !retval);
2930 if (error)
2931 ec = translate_netdb_error(error);
2932 return retval;
2933#elif defined(__MACH__) && defined(__APPLE__)
2934 (void)(buffer);
2935 (void)(buflength);
2936 int error = 0;
2937 hostent* retval = ::getipnodebyaddr(addr, length, af, &error);
2938 get_last_error(ec, !retval);
2939 if (error)
2940 ec = translate_netdb_error(error);
2941 if (!retval)
2942 return 0;
2943 *result = *retval;
2944 return retval;
2945#else
2946 hostent* retval = 0;
2947 int error = 0;
2948 clear_last_error();
2949 ::gethostbyaddr_r(addr, length, af, result,
2950 buffer, buflength, &retval, &error);
2951 get_last_error(ec, true);
2952 if (error)
2953 ec = translate_netdb_error(error);
2954 return retval;
2955#endif
2956}
2957
2958inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
2959 char* buffer, int buflength, int ai_flags, boost::system::error_code& ec)
2960{
2961#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2962 (void)(buffer);
2963 (void)(buflength);
2964 (void)(ai_flags);
2965 if (af != BOOST_ASIO_OS_DEF(AF_INET))
2966 {
2967 ec = boost::asio::error::address_family_not_supported;
2968 return 0;
2969 }
2970 hostent* retval = ::gethostbyname(name);
2971 get_last_error(ec, !retval);
2972 if (!retval)
2973 return 0;
2974 *result = *retval;
2975 return result;
2976#elif defined(__sun) || defined(__QNX__)
2977 (void)(ai_flags);
2978 if (af != BOOST_ASIO_OS_DEF(AF_INET))
2979 {
2980 ec = boost::asio::error::address_family_not_supported;
2981 return 0;
2982 }
2983 int error = 0;
2984 hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error);
2985 get_last_error(ec, !retval);
2986 if (error)
2987 ec = translate_netdb_error(error);
2988 return retval;
2989#elif defined(__MACH__) && defined(__APPLE__)
2990 (void)(buffer);
2991 (void)(buflength);
2992 int error = 0;
2993 hostent* retval = ::getipnodebyname(name, af, ai_flags, &error);
2994 get_last_error(ec, !retval);
2995 if (error)
2996 ec = translate_netdb_error(error);
2997 if (!retval)
2998 return 0;
2999 *result = *retval;
3000 return retval;
3001#else
3002 (void)(ai_flags);
3003 if (af != BOOST_ASIO_OS_DEF(AF_INET))
3004 {
3005 ec = boost::asio::error::address_family_not_supported;
3006 return 0;
3007 }
3008 hostent* retval = 0;
3009 int error = 0;
3010 clear_last_error();
3011 ::gethostbyname_r(name, result, buffer, buflength, &retval, &error);
3012 get_last_error(ec, true);
3013 if (error)
3014 ec = translate_netdb_error(error);
3015 return retval;
3016#endif
3017}
3018
3019inline void freehostent(hostent* h)
3020{
3021#if defined(__MACH__) && defined(__APPLE__)
3022 if (h)
3023 ::freehostent(h);
3024#else
3025 (void)(h);
3026#endif
3027}
3028
3029// Emulation of getaddrinfo based on implementation in:
3030// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
3031
3032struct gai_search
3033{
3034 const char* host;
3035 int family;
3036};
3037
3038inline int gai_nsearch(const char* host,
3039 const addrinfo_type* hints, gai_search (&search)[2])
3040{
3041 int search_count = 0;
3042 if (host == 0 || host[0] == '\0')
3043 {
3044 if (hints->ai_flags & AI_PASSIVE)
3045 {
3046 // No host and AI_PASSIVE implies wildcard bind.
3047 switch (hints->ai_family)
3048 {
3049 case BOOST_ASIO_OS_DEF(AF_INET):
3050 search[search_count].host = "0.0.0.0";
3051 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
3052 ++search_count;
3053 break;
3054 case BOOST_ASIO_OS_DEF(AF_INET6):
3055 search[search_count].host = "0::0";
3056 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
3057 ++search_count;
3058 break;
3059 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
3060 search[search_count].host = "0::0";
3061 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
3062 ++search_count;
3063 search[search_count].host = "0.0.0.0";
3064 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
3065 ++search_count;
3066 break;
3067 default:
3068 break;
3069 }
3070 }
3071 else
3072 {
3073 // No host and not AI_PASSIVE means connect to local host.
3074 switch (hints->ai_family)
3075 {
3076 case BOOST_ASIO_OS_DEF(AF_INET):
3077 search[search_count].host = "localhost";
3078 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
3079 ++search_count;
3080 break;
3081 case BOOST_ASIO_OS_DEF(AF_INET6):
3082 search[search_count].host = "localhost";
3083 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
3084 ++search_count;
3085 break;
3086 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
3087 search[search_count].host = "localhost";
3088 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
3089 ++search_count;
3090 search[search_count].host = "localhost";
3091 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
3092 ++search_count;
3093 break;
3094 default:
3095 break;
3096 }
3097 }
3098 }
3099 else
3100 {
3101 // Host is specified.
3102 switch (hints->ai_family)
3103 {
3104 case BOOST_ASIO_OS_DEF(AF_INET):
3105 search[search_count].host = host;
3106 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
3107 ++search_count;
3108 break;
3109 case BOOST_ASIO_OS_DEF(AF_INET6):
3110 search[search_count].host = host;
3111 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
3112 ++search_count;
3113 break;
3114 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
3115 search[search_count].host = host;
3116 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
3117 ++search_count;
3118 search[search_count].host = host;
3119 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
3120 ++search_count;
3121 break;
3122 default:
3123 break;
3124 }
3125 }
3126 return search_count;
3127}
3128
3129template <typename T>
3130inline T* gai_alloc(std::size_t size = sizeof(T))
3131{
3132 using namespace std;
3133 T* p = static_cast<T*>(::operator new(size, std::nothrow));
3134 if (p)
3135 memset(p, 0, size);
3136 return p;
3137}
3138
3139inline void gai_free(void* p)
3140{
3141 ::operator delete(p);
3142}
3143
3144inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
3145{
3146 using namespace std;
3147#if defined(BOOST_ASIO_HAS_SECURE_RTL)
3148 strcpy_s(target, max_size, source);
3149#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
3150 *target = 0;
3151 if (max_size > 0)
3152 strncat(target, source, max_size - 1);
3153#endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
3154}
3155
3156enum { gai_clone_flag = 1 << 30 };
3157
3158inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
3159 const void* addr, int family)
3160{
3161 using namespace std;
3162
3163 addrinfo_type* ai = gai_alloc<addrinfo_type>();
3164 if (ai == 0)
3165 return EAI_MEMORY;
3166
3167 ai->ai_next = 0;
3168 **next = ai;
3169 *next = &ai->ai_next;
3170
3171 ai->ai_canonname = 0;
3172 ai->ai_socktype = hints->ai_socktype;
3173 if (ai->ai_socktype == 0)
3174 ai->ai_flags |= gai_clone_flag;
3175 ai->ai_protocol = hints->ai_protocol;
3176 ai->ai_family = family;
3177
3178 switch (ai->ai_family)
3179 {
3180 case BOOST_ASIO_OS_DEF(AF_INET):
3181 {
3182 sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
3183 if (sinptr == 0)
3184 return EAI_MEMORY;
3185 sinptr->sin_family = BOOST_ASIO_OS_DEF(AF_INET);
3186 memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
3187 ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
3188 ai->ai_addrlen = sizeof(sockaddr_in4_type);
3189 break;
3190 }
3191 case BOOST_ASIO_OS_DEF(AF_INET6):
3192 {
3193 sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
3194 if (sin6ptr == 0)
3195 return EAI_MEMORY;
3196 sin6ptr->sin6_family = BOOST_ASIO_OS_DEF(AF_INET6);
3197 memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
3198 ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
3199 ai->ai_addrlen = sizeof(sockaddr_in6_type);
3200 break;
3201 }
3202 default:
3203 break;
3204 }
3205
3206 return 0;
3207}
3208
3209inline addrinfo_type* gai_clone(addrinfo_type* ai)
3210{
3211 using namespace std;
3212
3213 addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
3214 if (new_ai == 0)
3215 return new_ai;
3216
3217 new_ai->ai_next = ai->ai_next;
3218 ai->ai_next = new_ai;
3219
3220 new_ai->ai_flags = 0;
3221 new_ai->ai_family = ai->ai_family;
3222 new_ai->ai_socktype = ai->ai_socktype;
3223 new_ai->ai_protocol = ai->ai_protocol;
3224 new_ai->ai_canonname = 0;
3225 new_ai->ai_addrlen = ai->ai_addrlen;
3226 new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
3227 memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
3228
3229 return new_ai;
3230}
3231
3232inline int gai_port(addrinfo_type* aihead, int port, int socktype)
3233{
3234 int num_found = 0;
3235
3236 for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
3237 {
3238 if (ai->ai_flags & gai_clone_flag)
3239 {
3240 if (ai->ai_socktype != 0)
3241 {
3242 ai = gai_clone(ai);
3243 if (ai == 0)
3244 return -1;
3245 // ai now points to newly cloned entry.
3246 }
3247 }
3248 else if (ai->ai_socktype != socktype)
3249 {
3250 // Ignore if mismatch on socket type.
3251 continue;
3252 }
3253
3254 ai->ai_socktype = socktype;
3255
3256 switch (ai->ai_family)
3257 {
3258 case BOOST_ASIO_OS_DEF(AF_INET):
3259 {
3260 sockaddr_in4_type* sinptr =
3261 reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
3262 sinptr->sin_port = port;
3263 ++num_found;
3264 break;
3265 }
3266 case BOOST_ASIO_OS_DEF(AF_INET6):
3267 {
3268 sockaddr_in6_type* sin6ptr =
3269 reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
3270 sin6ptr->sin6_port = port;
3271 ++num_found;
3272 break;
3273 }
3274 default:
3275 break;
3276 }
3277 }
3278
3279 return num_found;
3280}
3281
3282inline int gai_serv(addrinfo_type* aihead,
3283 const addrinfo_type* hints, const char* serv)
3284{
3285 using namespace std;
3286
3287 int num_found = 0;
3288
3289 if (
3290#if defined(AI_NUMERICSERV)
3291 (hints->ai_flags & AI_NUMERICSERV) ||
3292#endif
3293 isdigit(static_cast<unsigned char>(serv[0])))
3294 {
3295 int port = htons(atoi(serv));
3296 if (hints->ai_socktype)
3297 {
3298 // Caller specifies socket type.
3299 int rc = gai_port(aihead, port, hints->ai_socktype);
3300 if (rc < 0)
3301 return EAI_MEMORY;
3302 num_found += rc;
3303 }
3304 else
3305 {
3306 // Caller does not specify socket type.
3307 int rc = gai_port(aihead, port, SOCK_STREAM);
3308 if (rc < 0)
3309 return EAI_MEMORY;
3310 num_found += rc;
3311 rc = gai_port(aihead, port, SOCK_DGRAM);
3312 if (rc < 0)
3313 return EAI_MEMORY;
3314 num_found += rc;
3315 }
3316 }
3317 else
3318 {
3319 // Try service name with TCP first, then UDP.
3320 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
3321 {
3322 servent* sptr = getservbyname(serv, "tcp");
3323 if (sptr != 0)
3324 {
3325 int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
3326 if (rc < 0)
3327 return EAI_MEMORY;
3328 num_found += rc;
3329 }
3330 }
3331 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
3332 {
3333 servent* sptr = getservbyname(serv, "udp");
3334 if (sptr != 0)
3335 {
3336 int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
3337 if (rc < 0)
3338 return EAI_MEMORY;
3339 num_found += rc;
3340 }
3341 }
3342 }
3343
3344 if (num_found == 0)
3345 {
3346 if (hints->ai_socktype == 0)
3347 {
3348 // All calls to getservbyname() failed.
3349 return EAI_NONAME;
3350 }
3351 else
3352 {
3353 // Service not supported for socket type.
3354 return EAI_SERVICE;
3355 }
3356 }
3357
3358 return 0;
3359}
3360
3361inline int gai_echeck(const char* host, const char* service,
3362 int flags, int family, int socktype, int protocol)
3363{
3364 (void)(flags);
3365 (void)(protocol);
3366
3367 // Host or service must be specified.
3368 if (host == 0 || host[0] == '\0')
3369 if (service == 0 || service[0] == '\0')
3370 return EAI_NONAME;
3371
3372 // Check combination of family and socket type.
3373 switch (family)
3374 {
3375 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
3376 break;
3377 case BOOST_ASIO_OS_DEF(AF_INET):
3378 case BOOST_ASIO_OS_DEF(AF_INET6):
3379 if (service != 0 && service[0] != '\0')
3380 if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
3381 return EAI_SOCKTYPE;
3382 break;
3383 default:
3384 return EAI_FAMILY;
3385 }
3386
3387 return 0;
3388}
3389
3390inline void freeaddrinfo_emulation(addrinfo_type* aihead)
3391{
3392 addrinfo_type* ai = aihead;
3393 while (ai)
3394 {
3395 gai_free(ai->ai_addr);
3396 gai_free(ai->ai_canonname);
3397 addrinfo_type* ainext = ai->ai_next;
3398 gai_free(ai);
3399 ai = ainext;
3400 }
3401}
3402
3403inline int getaddrinfo_emulation(const char* host, const char* service,
3404 const addrinfo_type* hintsp, addrinfo_type** result)
3405{
3406 // Set up linked list of addrinfo structures.
3407 addrinfo_type* aihead = 0;
3408 addrinfo_type** ainext = &aihead;
3409 char* canon = 0;
3410
3411 // Supply default hints if not specified by caller.
3412 addrinfo_type hints = addrinfo_type();
3413 hints.ai_family = BOOST_ASIO_OS_DEF(AF_UNSPEC);
3414 if (hintsp)
3415 hints = *hintsp;
3416
3417 // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
3418 // and AI_ALL flags.
3419#if defined(AI_V4MAPPED)
3420 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6))
3421 hints.ai_flags &= ~AI_V4MAPPED;
3422#endif
3423#if defined(AI_ALL)
3424 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6))
3425 hints.ai_flags &= ~AI_ALL;
3426#endif
3427
3428 // Basic error checking.
3429 int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
3430 hints.ai_socktype, hints.ai_protocol);
3431 if (rc != 0)
3432 {
3433 freeaddrinfo_emulation(aihead);
3434 return rc;
3435 }
3436
3437 gai_search search[2];
3438 int search_count = gai_nsearch(host, &hints, search);
3439 for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
3440 {
3441 // Check for IPv4 dotted decimal string.
3442 in4_addr_type inaddr;
3443 boost::system::error_code ec;
3444 if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET),
3445 sptr->host, &inaddr, 0, ec) == 1)
3446 {
3447 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)
3448 && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET))
3449 {
3450 freeaddrinfo_emulation(aihead);
3451 gai_free(canon);
3452 return EAI_FAMILY;
3453 }
3454 if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET))
3455 {
3456 rc = gai_aistruct(&ainext, &hints, &inaddr, BOOST_ASIO_OS_DEF(AF_INET));
3457 if (rc != 0)
3458 {
3459 freeaddrinfo_emulation(aihead);
3460 gai_free(canon);
3461 return rc;
3462 }
3463 }
3464 continue;
3465 }
3466
3467 // Check for IPv6 hex string.
3468 in6_addr_type in6addr;
3469 if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6),
3470 sptr->host, &in6addr, 0, ec) == 1)
3471 {
3472 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)
3473 && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6))
3474 {
3475 freeaddrinfo_emulation(aihead);
3476 gai_free(canon);
3477 return EAI_FAMILY;
3478 }
3479 if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET6))
3480 {
3481 rc = gai_aistruct(&ainext, &hints, &in6addr,
3482 BOOST_ASIO_OS_DEF(AF_INET6));
3483 if (rc != 0)
3484 {
3485 freeaddrinfo_emulation(aihead);
3486 gai_free(canon);
3487 return rc;
3488 }
3489 }
3490 continue;
3491 }
3492
3493 // Look up hostname.
3494 hostent hent;
3495 char hbuf[8192] = "";
3496 hostent* hptr = socket_ops::gethostbyname(sptr->host,
3497 sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
3498 if (hptr == 0)
3499 {
3500 if (search_count == 2)
3501 {
3502 // Failure is OK if there are multiple searches.
3503 continue;
3504 }
3505 freeaddrinfo_emulation(aihead);
3506 gai_free(canon);
3507 if (ec == boost::asio::error::host_not_found)
3508 return EAI_NONAME;
3509 if (ec == boost::asio::error::host_not_found_try_again)
3510 return EAI_AGAIN;
3511 if (ec == boost::asio::error::no_recovery)
3512 return EAI_FAIL;
3513 if (ec == boost::asio::error::no_data)
3514 return EAI_NONAME;
3515 return EAI_NONAME;
3516 }
3517
3518 // Check for address family mismatch if one was specified.
3519 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)
3520 && hints.ai_family != hptr->h_addrtype)
3521 {
3522 freeaddrinfo_emulation(aihead);
3523 gai_free(canon);
3524 socket_ops::freehostent(hptr);
3525 return EAI_FAMILY;
3526 }
3527
3528 // Save canonical name first time.
3529 if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
3530 && (hints.ai_flags & AI_CANONNAME) && canon == 0)
3531 {
3532 std::size_t canon_len = strlen(hptr->h_name) + 1;
3533 canon = gai_alloc<char>(canon_len);
3534 if (canon == 0)
3535 {
3536 freeaddrinfo_emulation(aihead);
3537 socket_ops::freehostent(hptr);
3538 return EAI_MEMORY;
3539 }
3540 gai_strcpy(canon, hptr->h_name, canon_len);
3541 }
3542
3543 // Create an addrinfo structure for each returned address.
3544 for (char** ap = hptr->h_addr_list; *ap; ++ap)
3545 {
3546 rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
3547 if (rc != 0)
3548 {
3549 freeaddrinfo_emulation(aihead);
3550 gai_free(canon);
3551 socket_ops::freehostent(hptr);
3552 return EAI_FAMILY;
3553 }
3554 }
3555
3556 socket_ops::freehostent(hptr);
3557 }
3558
3559 // Check if we found anything.
3560 if (aihead == 0)
3561 {
3562 gai_free(canon);
3563 return EAI_NONAME;
3564 }
3565
3566 // Return canonical name in first entry.
3567 if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
3568 {
3569 if (canon)
3570 {
3571 aihead->ai_canonname = canon;
3572 canon = 0;
3573 }
3574 else
3575 {
3576 std::size_t canonname_len = strlen(search[0].host) + 1;
3577 aihead->ai_canonname = gai_alloc<char>(canonname_len);
3578 if (aihead->ai_canonname == 0)
3579 {
3580 freeaddrinfo_emulation(aihead);
3581 return EAI_MEMORY;
3582 }
3583 gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
3584 }
3585 }
3586 gai_free(canon);
3587
3588 // Process the service name.
3589 if (service != 0 && service[0] != '\0')
3590 {
3591 rc = gai_serv(aihead, &hints, service);
3592 if (rc != 0)
3593 {
3594 freeaddrinfo_emulation(aihead);
3595 return rc;
3596 }
3597 }
3598
3599 // Return result to caller.
3600 *result = aihead;
3601 return 0;
3602}
3603
3604inline boost::system::error_code getnameinfo_emulation(
3605 const socket_addr_type* sa, std::size_t salen, char* host,
3606 std::size_t hostlen, char* serv, std::size_t servlen, int flags,
3607 boost::system::error_code& ec)
3608{
3609 using namespace std;
3610
3611 const char* addr;
3612 size_t addr_len;
3613 unsigned short port;
3614 switch (sa->sa_family)
3615 {
3616 case BOOST_ASIO_OS_DEF(AF_INET):
3617 if (salen != sizeof(sockaddr_in4_type))
3618 {
3619 return ec = boost::asio::error::invalid_argument;
3620 }
3621 addr = reinterpret_cast<const char*>(
3622 &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
3623 addr_len = sizeof(in4_addr_type);
3624 port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
3625 break;
3626 case BOOST_ASIO_OS_DEF(AF_INET6):
3627 if (salen != sizeof(sockaddr_in6_type))
3628 {
3629 return ec = boost::asio::error::invalid_argument;
3630 }
3631 addr = reinterpret_cast<const char*>(
3632 &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
3633 addr_len = sizeof(in6_addr_type);
3634 port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
3635 break;
3636 default:
3637 return ec = boost::asio::error::address_family_not_supported;
3638 }
3639
3640 if (host && hostlen > 0)
3641 {
3642 if (flags & NI_NUMERICHOST)
3643 {
3644 if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
3645 {
3646 return ec;
3647 }
3648 }
3649 else
3650 {
3651 hostent hent;
3652 char hbuf[8192] = "";
3653 hostent* hptr = socket_ops::gethostbyaddr(addr,
3654 static_cast<int>(addr_len), sa->sa_family,
3655 &hent, hbuf, sizeof(hbuf), ec);
3656 if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
3657 {
3658 if (flags & NI_NOFQDN)
3659 {
3660 char* dot = strchr(hptr->h_name, '.');
3661 if (dot)
3662 {
3663 *dot = 0;
3664 }
3665 }
3666 gai_strcpy(host, hptr->h_name, hostlen);
3667 socket_ops::freehostent(hptr);
3668 }
3669 else
3670 {
3671 socket_ops::freehostent(hptr);
3672 if (flags & NI_NAMEREQD)
3673 {
3674 return ec = boost::asio::error::host_not_found;
3675 }
3676 if (socket_ops::inet_ntop(sa->sa_family,
3677 addr, host, hostlen, 0, ec) == 0)
3678 {
3679 return ec;
3680 }
3681 }
3682 }
3683 }
3684
3685 if (serv && servlen > 0)
3686 {
3687 if (flags & NI_NUMERICSERV)
3688 {
3689 if (servlen < 6)
3690 {
3691 return ec = boost::asio::error::no_buffer_space;
3692 }
3693#if defined(BOOST_ASIO_HAS_SNPRINTF)
3694 snprintf(serv, servlen, "%u", ntohs(port));
3695#elif defined(BOOST_ASIO_HAS_SECURE_RTL)
3696 sprintf_s(serv, servlen, "%u", ntohs(port));
3697#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
3698 sprintf(serv, "%u", ntohs(port));
3699#endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
3700 }
3701 else
3702 {
3703#if defined(BOOST_ASIO_HAS_PTHREADS)
3704 static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
3705 ::pthread_mutex_lock(&mutex);
3706#endif // defined(BOOST_ASIO_HAS_PTHREADS)
3707 servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
3708 if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
3709 {
3710 gai_strcpy(serv, sptr->s_name, servlen);
3711 }
3712 else
3713 {
3714 if (servlen < 6)
3715 {
3716 return ec = boost::asio::error::no_buffer_space;
3717 }
3718#if defined(BOOST_ASIO_HAS_SNPRINTF)
3719 snprintf(serv, servlen, "%u", ntohs(port));
3720#elif defined(BOOST_ASIO_HAS_SECURE_RTL)
3721 sprintf_s(serv, servlen, "%u", ntohs(port));
3722#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
3723 sprintf(serv, "%u", ntohs(port));
3724#endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
3725 }
3726#if defined(BOOST_ASIO_HAS_PTHREADS)
3727 ::pthread_mutex_unlock(&mutex);
3728#endif // defined(BOOST_ASIO_HAS_PTHREADS)
3729 }
3730 }
3731
3732 boost::asio::error::clear(ec);
3733 return ec;
3734}
3735
3736#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO)
3737
3738inline boost::system::error_code translate_addrinfo_error(int error)
3739{
3740 switch (error)
3741 {
3742 case 0:
3743 return boost::system::error_code();
3744 case EAI_AGAIN:
3745 return boost::asio::error::host_not_found_try_again;
3746 case EAI_BADFLAGS:
3747 return boost::asio::error::invalid_argument;
3748 case EAI_FAIL:
3749 return boost::asio::error::no_recovery;
3750 case EAI_FAMILY:
3751 return boost::asio::error::address_family_not_supported;
3752 case EAI_MEMORY:
3753 return boost::asio::error::no_memory;
3754 case EAI_NONAME:
3755#if defined(EAI_ADDRFAMILY)
3756 case EAI_ADDRFAMILY:
3757#endif
3758#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
3759 case EAI_NODATA:
3760#endif
3761 return boost::asio::error::host_not_found;
3762 case EAI_SERVICE:
3763 return boost::asio::error::service_not_found;
3764 case EAI_SOCKTYPE:
3765 return boost::asio::error::socket_type_not_supported;
3766 default: // Possibly the non-portable EAI_SYSTEM.
3767#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3768 return boost::system::error_code(
3769 WSAGetLastError(), boost::asio::error::get_system_category());
3770#else
3771 return boost::system::error_code(
3772 errno, boost::asio::error::get_system_category());
3773#endif
3774 }
3775}
3776
3777boost::system::error_code getaddrinfo(const char* host,
3778 const char* service, const addrinfo_type& hints,
3779 addrinfo_type** result, boost::system::error_code& ec)
3780{
3781 host = (host && *host) ? host : 0;
3782 service = (service && *service) ? service : 0;
3783 clear_last_error();
3784#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3785# if defined(BOOST_ASIO_HAS_GETADDRINFO)
3786 // Building for Windows XP, Windows Server 2003, or later.
3787 int error = ::getaddrinfo(host, service, &hints, result);
3788 return ec = translate_addrinfo_error(error);
3789# else
3790 // Building for Windows 2000 or earlier.
3791 typedef int (WSAAPI *gai_t)(const char*,
3792 const char*, const addrinfo_type*, addrinfo_type**);
3793 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
3794 {
3795 if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
3796 {
3797 int error = gai(host, service, &hints, result);
3798 return ec = translate_addrinfo_error(error);
3799 }
3800 }
3801 int error = getaddrinfo_emulation(host, service, &hints, result);
3802 return ec = translate_addrinfo_error(error);
3803# endif
3804#elif !defined(BOOST_ASIO_HAS_GETADDRINFO)
3805 int error = getaddrinfo_emulation(host, service, &hints, result);
3806 return ec = translate_addrinfo_error(error);
3807#else
3808 int error = ::getaddrinfo(name: host, service: service, req: &hints, pai: result);
3809#if defined(__MACH__) && defined(__APPLE__)
3810 using namespace std; // For isdigit and atoi.
3811 if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0])))
3812 {
3813 u_short_type port = host_to_network_short(atoi(service));
3814 for (addrinfo_type* ai = *result; ai; ai = ai->ai_next)
3815 {
3816 switch (ai->ai_family)
3817 {
3818 case BOOST_ASIO_OS_DEF(AF_INET):
3819 {
3820 sockaddr_in4_type* sinptr =
3821 reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
3822 if (sinptr->sin_port == 0)
3823 sinptr->sin_port = port;
3824 break;
3825 }
3826 case BOOST_ASIO_OS_DEF(AF_INET6):
3827 {
3828 sockaddr_in6_type* sin6ptr =
3829 reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
3830 if (sin6ptr->sin6_port == 0)
3831 sin6ptr->sin6_port = port;
3832 break;
3833 }
3834 default:
3835 break;
3836 }
3837 }
3838 }
3839#endif
3840 return ec = translate_addrinfo_error(error);
3841#endif
3842}
3843
3844boost::system::error_code background_getaddrinfo(
3845 const weak_cancel_token_type& cancel_token, const char* host,
3846 const char* service, const addrinfo_type& hints,
3847 addrinfo_type** result, boost::system::error_code& ec)
3848{
3849 if (cancel_token.expired())
3850 ec = boost::asio::error::operation_aborted;
3851 else
3852 socket_ops::getaddrinfo(host, service, hints, result, ec);
3853 return ec;
3854}
3855
3856void freeaddrinfo(addrinfo_type* ai)
3857{
3858#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3859# if defined(BOOST_ASIO_HAS_GETADDRINFO)
3860 // Building for Windows XP, Windows Server 2003, or later.
3861 ::freeaddrinfo(ai);
3862# else
3863 // Building for Windows 2000 or earlier.
3864 typedef int (WSAAPI *fai_t)(addrinfo_type*);
3865 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
3866 {
3867 if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
3868 {
3869 fai(ai);
3870 return;
3871 }
3872 }
3873 freeaddrinfo_emulation(ai);
3874# endif
3875#elif !defined(BOOST_ASIO_HAS_GETADDRINFO)
3876 freeaddrinfo_emulation(ai);
3877#else
3878 ::freeaddrinfo(ai: ai);
3879#endif
3880}
3881
3882boost::system::error_code getnameinfo(const void* addr,
3883 std::size_t addrlen, char* host, std::size_t hostlen,
3884 char* serv, std::size_t servlen, int flags, boost::system::error_code& ec)
3885{
3886#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3887# if defined(BOOST_ASIO_HAS_GETADDRINFO)
3888 // Building for Windows XP, Windows Server 2003, or later.
3889 clear_last_error();
3890 int error = ::getnameinfo(static_cast<const socket_addr_type*>(addr),
3891 static_cast<socklen_t>(addrlen), host, static_cast<DWORD>(hostlen),
3892 serv, static_cast<DWORD>(servlen), flags);
3893 return ec = translate_addrinfo_error(error);
3894# else
3895 // Building for Windows 2000 or earlier.
3896 typedef int (WSAAPI *gni_t)(const socket_addr_type*,
3897 int, char*, DWORD, char*, DWORD, int);
3898 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
3899 {
3900 if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
3901 {
3902 clear_last_error();
3903 int error = gni(static_cast<const socket_addr_type*>(addr),
3904 static_cast<int>(addrlen), host, static_cast<DWORD>(hostlen),
3905 serv, static_cast<DWORD>(servlen), flags);
3906 return ec = translate_addrinfo_error(error);
3907 }
3908 }
3909 clear_last_error();
3910 return getnameinfo_emulation(static_cast<const socket_addr_type*>(addr),
3911 addrlen, host, hostlen, serv, servlen, flags, ec);
3912# endif
3913#elif !defined(BOOST_ASIO_HAS_GETADDRINFO)
3914 using namespace std; // For memcpy.
3915 sockaddr_storage_type tmp_addr;
3916 memcpy(&tmp_addr, addr, addrlen);
3917 addr = &tmp_addr;
3918 clear_last_error();
3919 return getnameinfo_emulation(static_cast<const socket_addr_type*>(addr),
3920 addrlen, host, hostlen, serv, servlen, flags, ec);
3921#else
3922 clear_last_error();
3923 int error = ::getnameinfo(sa: static_cast<const socket_addr_type*>(addr),
3924 salen: addrlen, host: host, hostlen: hostlen, serv: serv, servlen: servlen, flags: flags);
3925 return ec = translate_addrinfo_error(error);
3926#endif
3927}
3928
3929boost::system::error_code sync_getnameinfo(const void* addr,
3930 std::size_t addrlen, char* host, std::size_t hostlen, char* serv,
3931 std::size_t servlen, int sock_type, boost::system::error_code& ec)
3932{
3933 // First try resolving with the service name. If that fails try resolving
3934 // but allow the service to be returned as a number.
3935 int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
3936 socket_ops::getnameinfo(addr, addrlen, host,
3937 hostlen, serv, servlen, flags, ec);
3938 if (ec)
3939 {
3940 socket_ops::getnameinfo(addr, addrlen, host, hostlen,
3941 serv, servlen, flags: flags | NI_NUMERICSERV, ec);
3942 }
3943
3944 return ec;
3945}
3946
3947boost::system::error_code background_getnameinfo(
3948 const weak_cancel_token_type& cancel_token,
3949 const void* addr, std::size_t addrlen,
3950 char* host, std::size_t hostlen, char* serv,
3951 std::size_t servlen, int sock_type, boost::system::error_code& ec)
3952{
3953 if (cancel_token.expired())
3954 {
3955 ec = boost::asio::error::operation_aborted;
3956 }
3957 else
3958 {
3959 // First try resolving with the service name. If that fails try resolving
3960 // but allow the service to be returned as a number.
3961 int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
3962 socket_ops::getnameinfo(addr, addrlen, host,
3963 hostlen, serv, servlen, flags, ec);
3964 if (ec)
3965 {
3966 socket_ops::getnameinfo(addr, addrlen, host, hostlen,
3967 serv, servlen, flags: flags | NI_NUMERICSERV, ec);
3968 }
3969 }
3970
3971 return ec;
3972}
3973
3974#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
3975
3976u_long_type network_to_host_long(u_long_type value)
3977{
3978#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
3979 unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
3980 u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24)
3981 | (static_cast<u_long_type>(value_p[1]) << 16)
3982 | (static_cast<u_long_type>(value_p[2]) << 8)
3983 | static_cast<u_long_type>(value_p[3]);
3984 return result;
3985#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
3986 return ntohl(value);
3987#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
3988}
3989
3990u_long_type host_to_network_long(u_long_type value)
3991{
3992#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
3993 u_long_type result;
3994 unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
3995 result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF);
3996 result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF);
3997 result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF);
3998 result_p[3] = static_cast<unsigned char>(value & 0xFF);
3999 return result;
4000#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4001 return htonl(value);
4002#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4003}
4004
4005u_short_type network_to_host_short(u_short_type value)
4006{
4007#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
4008 unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
4009 u_short_type result = (static_cast<u_short_type>(value_p[0]) << 8)
4010 | static_cast<u_short_type>(value_p[1]);
4011 return result;
4012#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4013 return ntohs(value);
4014#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4015}
4016
4017u_short_type host_to_network_short(u_short_type value)
4018{
4019#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
4020 u_short_type result;
4021 unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
4022 result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF);
4023 result_p[1] = static_cast<unsigned char>(value & 0xFF);
4024 return result;
4025#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4026 return htons(value);
4027#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4028}
4029
4030} // namespace socket_ops
4031} // namespace detail
4032} // namespace asio
4033} // namespace boost
4034
4035#include <boost/asio/detail/pop_options.hpp>
4036
4037#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
4038

source code of boost/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp