diff options
Diffstat (limited to '3rdparty/asio/include/asio/detail/impl/socket_ops.ipp')
-rw-r--r-- | 3rdparty/asio/include/asio/detail/impl/socket_ops.ipp | 1011 |
1 files changed, 724 insertions, 287 deletions
diff --git a/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp b/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp index d9cc1c95722..3403f1c0a85 100644 --- a/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp +++ b/3rdparty/asio/include/asio/detail/impl/socket_ops.ipp @@ -2,7 +2,7 @@ // detail/impl/socket_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -73,18 +73,23 @@ inline void clear_last_error() #if !defined(ASIO_WINDOWS_RUNTIME) -template <typename ReturnType> -inline ReturnType error_wrapper(ReturnType return_value, - asio::error_code& ec) +inline void get_last_error( + asio::error_code& ec, bool is_error_condition) { + if (!is_error_condition) + { + ec.assign(0, ec.category()); + } + else + { #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - ec = asio::error_code(WSAGetLastError(), - asio::error::get_system_category()); + ec = asio::error_code(WSAGetLastError(), + asio::error::get_system_category()); #else - ec = asio::error_code(errno, - asio::error::get_system_category()); + ec = asio::error_code(errno, + asio::error::get_system_category()); #endif - return return_value; + } } template <typename SockLenType> @@ -107,17 +112,16 @@ socket_type accept(socket_type s, socket_addr_type* addr, return invalid_socket; } - clear_last_error(); - - socket_type new_s = error_wrapper(call_accept( - &msghdr::msg_namelen, s, addr, addrlen), ec); + socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, new_s == invalid_socket); if (new_s == invalid_socket) return new_s; #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) int optval = 1; - int result = error_wrapper(::setsockopt(new_s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + int result = ::setsockopt(new_s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); if (result != 0) { ::close(new_s); @@ -125,7 +129,7 @@ socket_type accept(socket_type s, socket_addr_type* addr, } #endif - ec = asio::error_code(); + ec.assign(0, ec.category()); return new_s; } @@ -241,8 +245,6 @@ bool non_blocking_accept(socket_type s, if (ec == asio::error::would_block || ec == asio::error::try_again) { - if (state & user_set_non_blocking) - return true; // Fall through to retry operation. } else if (ec == asio::error::connection_aborted) @@ -284,11 +286,8 @@ int bind(socket_type s, const socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_bind( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -311,12 +310,12 @@ int close(socket_type s, state_type& state, SO_LINGER, &opt, sizeof(opt), ignored_ec); } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::closesocket(s), ec); + result = ::closesocket(s); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::close(s), ec); + result = ::close(s); #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); if (result != 0 && (ec == asio::error::would_block @@ -332,28 +331,26 @@ int close(socket_type s, state_type& state, ioctl_arg_type arg = 0; ::ioctlsocket(s, FIONBIO, &arg); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) -# if defined(__SYMBIAN32__) +# if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int flags = ::fcntl(s, F_GETFL, 0); if (flags >= 0) ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); -# else // defined(__SYMBIAN32__) +# else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = 0; ::ioctl(s, FIONBIO, &arg); -# endif // defined(__SYMBIAN32__) +# endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) state &= ~non_blocking; - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::closesocket(s), ec); + result = ::closesocket(s); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::close(s), ec); + result = ::close(s); #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); } } - if (result == 0) - ec = asio::error_code(); return result; } @@ -366,26 +363,27 @@ bool set_user_non_blocking(socket_type s, return false; } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); -#elif defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - clear_last_error(); int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); } #else ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); #endif if (result >= 0) { - ec = asio::error_code(); if (value) state |= user_set_non_blocking; else @@ -419,26 +417,27 @@ bool set_internal_non_blocking(socket_type s, return false; } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); -#elif defined(__SYMBIAN32__) - int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); +#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - clear_last_error(); int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); } #else ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); #endif if (result >= 0) { - ec = asio::error_code(); if (value) state |= internal_non_blocking; else @@ -457,10 +456,8 @@ int shutdown(socket_type s, int what, asio::error_code& ec) return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(::shutdown(s, what), ec); - if (result == 0) - ec = asio::error_code(); + int result = ::shutdown(s, what); + get_last_error(ec, result != 0); return result; } @@ -480,13 +477,10 @@ int connect(socket_type s, const socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_connect( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); #if defined(__linux__) - else if (ec == asio::error::try_again) + if (result != 0 && ec == asio::error::try_again) ec = asio::error::no_buffer_space; #endif // defined(__linux__) return result; @@ -602,7 +596,7 @@ bool non_blocking_connect(socket_type s, asio::error_code& ec) asio::error::get_system_category()); } else - ec = asio::error_code(); + ec.assign(0, ec.category()); } return true; @@ -619,10 +613,8 @@ int socketpair(int af, int type, int protocol, ec = asio::error::operation_not_supported; return socket_error_retval; #else - clear_last_error(); - int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); - if (result == 0) - ec = asio::error_code(); + int result = ::socketpair(af, type, protocol, sv); + get_last_error(ec, result != 0); return result; #endif } @@ -638,20 +630,18 @@ bool sockatmark(socket_type s, asio::error_code& ec) #if defined(SIOCATMARK) ioctl_arg_type value = 0; # if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); + int result = ::ioctlsocket(s, SIOCATMARK, &value); # else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); + int result = ::ioctl(s, SIOCATMARK, &value); # endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - ec = asio::error_code(); + get_last_error(ec, result < 0); # if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket; # endif // defined(ENOTTY) #else // defined(SIOCATMARK) - int value = error_wrapper(::sockatmark(s), ec); - if (value != -1) - ec = asio::error_code(); + int value = ::sockatmark(s); + get_last_error(ec, value < 0); #endif // defined(SIOCATMARK) return ec ? false : value != 0; @@ -667,12 +657,11 @@ size_t available(socket_type s, asio::error_code& ec) ioctl_arg_type value = 0; #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); + int result = ::ioctlsocket(s, FIONREAD, &value); #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); + int result = ::ioctl(s, FIONREAD, &value); #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - ec = asio::error_code(); + get_last_error(ec, result < 0); #if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket; @@ -689,10 +678,8 @@ int listen(socket_type s, int backlog, asio::error_code& ec) return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(::listen(s, backlog), ec); - if (result == 0) - ec = asio::error_code(); + int result = ::listen(s, backlog); + get_last_error(ec, result != 0); return result; } @@ -760,29 +747,60 @@ inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) signed_size_type recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int result = error_wrapper(::WSARecv(s, bufs, - recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + int result = ::WSARecv(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); - if (result >= 0) - ec = asio::error_code(); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +signed_size_type recv1(socket_type s, void* data, size_t size, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = const_cast<char*>(static_cast<const char*>(data)); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(s, &buf, 1, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = ::recv(s, static_cast<char*>(data), size, flags); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -799,7 +817,7 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, // A request to read 0 bytes on a stream is a no-op. if (all_empty && (state & stream_oriented)) { - ec = asio::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -809,10 +827,51 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, // Try to complete the operation without blocking. signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = asio::error::eof; + return 0; + } + // Check if operation succeeded. - if (bytes > 0) + if (bytes >= 0) return bytes; + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +size_t sync_recv1(socket_type s, state_type state, void* data, + size_t size, int flags, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + // Check for EOF. if ((state & stream_oriented) && bytes == 0) { @@ -820,6 +879,10 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, return 0; } + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block @@ -850,6 +913,10 @@ void complete_iocp_recv(state_type state, { ec = asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } // Check for connection closed. else if (!ec && bytes_transferred == 0 @@ -878,6 +945,13 @@ bool non_blocking_recv(socket_type s, return true; } + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -887,15 +961,46 @@ bool non_blocking_recv(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_recv1(socket_type s, + void* data, size_t size, int flags, bool is_stream, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = asio::error::eof; + return true; + } + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -906,23 +1011,25 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int tmp_addrlen = (int)*addrlen; - int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + int result = ::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0); + get_last_error(ec, true); *addrlen = (std::size_t)tmp_addrlen; if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -930,10 +1037,56 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, msg.msg_namelen = static_cast<int>(*addrlen); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); *addrlen = msg.msg_namelen; - if (result >= 0) - ec = asio::error_code(); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template <typename SockLenType> +inline signed_size_type call_recvfrom(SockLenType msghdr::*, + socket_type s, void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + signed_size_type result = ::recvfrom(s, static_cast<char*>(data), + size, flags, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +signed_size_type recvfrom1(socket_type s, void* data, size_t size, + int flags, socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = static_cast<char*>(data); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred, + &recv_flags, addr, &tmp_addrlen, 0, 0); + get_last_error(ec, true); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = call_recvfrom(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -971,6 +1124,39 @@ size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, } } +size_t sync_recvfrom1(socket_type s, state_type state, void* data, + size_t size, int flags, socket_addr_type* addr, + std::size_t* addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + #if defined(ASIO_HAS_IOCP) void complete_iocp_recvfrom( @@ -989,6 +1175,10 @@ void complete_iocp_recvfrom( { ec = asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } } #else // defined(ASIO_HAS_IOCP) @@ -1004,6 +1194,13 @@ bool non_blocking_recvfrom(socket_type s, signed_size_type bytes = socket_ops::recvfrom( s, bufs, count, flags, addr, addrlen, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1013,15 +1210,41 @@ bool non_blocking_recvfrom(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_recvfrom1(socket_type s, + void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1031,7 +1254,6 @@ bool non_blocking_recvfrom(socket_type s, signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, int in_flags, int& out_flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) out_flags = 0; return socket_ops::recv(s, bufs, count, in_flags, ec); @@ -1039,12 +1261,10 @@ signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, in_flags), ec); + signed_size_type result = ::recvmsg(s, &msg, in_flags); + get_last_error(ec, result < 0); if (result >= 0) - { - ec = asio::error_code(); out_flags = msg.msg_flags; - } else out_flags = 0; return result; @@ -1102,6 +1322,10 @@ void complete_iocp_recvmsg( { ec = asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } } #else // defined(ASIO_HAS_IOCP) @@ -1116,6 +1340,13 @@ bool non_blocking_recvmsg(socket_type s, signed_size_type bytes = socket_ops::recvmsg( s, bufs, count, in_flags, out_flags, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1125,15 +1356,8 @@ bool non_blocking_recvmsg(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = asio::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1143,32 +1367,63 @@ bool non_blocking_recvmsg(socket_type s, signed_size_type send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD send_flags = flags; - int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs), - send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + int result = ::WSASend(s, const_cast<buf*>(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = const_cast<buf*>(bufs); msg.msg_iovlen = static_cast<int>(count); -#if defined(__linux__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - ec = asio::error_code(); +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +signed_size_type send1(socket_type s, const void* data, size_t size, + int flags, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast<char*>(static_cast<const char*>(data)); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = ::WSASend(s, &buf, 1, + &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::send(s, + static_cast<const char*>(data), size, flags); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1185,7 +1440,7 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs, // A request to write 0 bytes to a stream is a no-op. if (all_empty && (state & stream_oriented)) { - ec = asio::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1211,6 +1466,44 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs, } } +size_t sync_send1(socket_type s, state_type state, const void* data, + size_t size, int flags, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + #if defined(ASIO_HAS_IOCP) void complete_iocp_send( @@ -1242,6 +1535,13 @@ bool non_blocking_send(socket_type s, // Write some data. signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1251,15 +1551,39 @@ bool non_blocking_send(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_send1(socket_type s, + const void* data, size_t size, int flags, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1270,21 +1594,21 @@ signed_size_type sendto(socket_type s, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; - int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs), + int result = ::WSASendTo(s, const_cast<buf*>(bufs), send_buf_count, &bytes_transferred, flags, addr, - static_cast<int>(addrlen), 0, 0), ec); + static_cast<int>(addrlen), 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; - ec = asio::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -1292,12 +1616,52 @@ signed_size_type sendto(socket_type s, const buf* bufs, size_t count, msg.msg_namelen = static_cast<int>(addrlen); msg.msg_iov = const_cast<buf*>(bufs); msg.msg_iovlen = static_cast<int>(count); -#if defined(__linux__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - ec = asio::error_code(); +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); + return result; +#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template <typename SockLenType> +inline signed_size_type call_sendto(SockLenType msghdr::*, + socket_type s, const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen) +{ + return ::sendto(s, static_cast<char*>(const_cast<void*>(data)), + size, flags, addr, (SockLenType)addrlen); +} + +signed_size_type sendto1(socket_type s, const void* data, size_t size, + int flags, const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast<char*>(static_cast<const char*>(data)); + buf.len = static_cast<ULONG>(size); + DWORD bytes_transferred = 0; + int result = ::WSASendTo(s, &buf, 1, &bytes_transferred, + flags, addr, static_cast<int>(addrlen), 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(ASIO_HAS_MSG_NOSIGNAL) + flags |= MSG_NOSIGNAL; +#endif // defined(ASIO_HAS_MSG_NOSIGNAL) + signed_size_type result = call_sendto(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1335,6 +1699,39 @@ size_t sync_sendto(socket_type s, state_type state, const buf* bufs, } } +size_t sync_sendto1(socket_type s, state_type state, const void* data, + size_t size, int flags, const socket_addr_type* addr, + std::size_t addrlen, asio::error_code& ec) +{ + if (s == invalid_socket) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + #if !defined(ASIO_HAS_IOCP) bool non_blocking_sendto(socket_type s, @@ -1348,6 +1745,13 @@ bool non_blocking_sendto(socket_type s, signed_size_type bytes = socket_ops::sendto( s, bufs, count, flags, addr, addrlen, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; @@ -1357,15 +1761,41 @@ bool non_blocking_sendto(socket_type s, || ec == asio::error::try_again) return false; - // Operation is complete. + // Operation failed. + bytes_transferred = 0; + return true; + } +} + +bool non_blocking_sendto1(socket_type s, + const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. if (bytes >= 0) { - ec = asio::error_code(); bytes_transferred = bytes; + return true; } - else - bytes_transferred = 0; + // Retry operation if interrupted by signal. + if (ec == asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1375,10 +1805,9 @@ bool non_blocking_sendto(socket_type s, socket_type socket(int af, int type, int protocol, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - socket_type s = error_wrapper(::WSASocketW(af, type, protocol, 0, 0, - WSA_FLAG_OVERLAPPED), ec); + socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED); + get_last_error(ec, s == invalid_socket); if (s == invalid_socket) return s; @@ -1392,17 +1821,17 @@ socket_type socket(int af, int type, int protocol, reinterpret_cast<const char*>(&optval), sizeof(optval)); } - ec = asio::error_code(); - return s; #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type s = error_wrapper(::socket(af, type, protocol), ec); + socket_type s = ::socket(af, type, protocol); + get_last_error(ec, s == invalid_socket); if (s == invalid_socket) return s; int optval = 1; - int result = error_wrapper(::setsockopt(s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + int result = ::setsockopt(s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); if (result != 0) { ::close(s); @@ -1411,9 +1840,8 @@ socket_type socket(int af, int type, int protocol, return s; #else - int s = error_wrapper(::socket(af, type, protocol), ec); - if (s >= 0) - ec = asio::error_code(); + int s = ::socket(af, type, protocol); + get_last_error(ec, s < 0); return s; #endif } @@ -1455,7 +1883,7 @@ int setsockopt(socket_type s, state_type& state, int level, int optname, state |= enable_connection_aborted; else state &= ~enable_connection_aborted; - ec = asio::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1471,24 +1899,24 @@ int setsockopt(socket_type s, state_type& state, int level, int optname, typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) { - clear_last_error(); - return error_wrapper(sso(s, level, optname, + int result = sso(s, level, optname, reinterpret_cast<const char*>(optval), - static_cast<int>(optlen)), ec); + static_cast<int>(optlen)); + get_last_error(ec, result != 0); + return result; } } ec = asio::error::fault; return socket_error_retval; #else // defined(__BORLANDC__) - clear_last_error(); - int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); if (result == 0) { - ec = asio::error_code(); - #if defined(__MACH__) && defined(__APPLE__) \ - || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + || defined(__NetBSD__) || defined(__FreeBSD__) \ + || defined(__OpenBSD__) || defined(__QNX__) // To implement portable behaviour for SO_REUSEADDR with UDP sockets we // need to also set SO_REUSEPORT on BSD-based platforms. if ((state & datagram_oriented) @@ -1540,7 +1968,7 @@ int getsockopt(socket_type s, state_type state, int level, int optname, } *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0; - ec = asio::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1553,10 +1981,10 @@ int getsockopt(socket_type s, state_type state, int level, int optname, typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) { - clear_last_error(); int tmp_optlen = static_cast<int>(*optlen); - int result = error_wrapper(gso(s, level, optname, - reinterpret_cast<char*>(optval), &tmp_optlen), ec); + int result = gso(s, level, optname, + reinterpret_cast<char*>(optval), &tmp_optlen); + get_last_error(ec, result != 0); *optlen = static_cast<size_t>(tmp_optlen); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) @@ -1567,7 +1995,7 @@ int getsockopt(socket_type s, state_type state, int level, int optname, // value is non-zero (i.e. true). This corresponds to the behavior of // IPv6 sockets on Windows platforms pre-Vista. *static_cast<DWORD*>(optval) = 1; - ec = asio::error_code(); + ec.assign(0, ec.category()); } return result; } @@ -1575,9 +2003,9 @@ int getsockopt(socket_type s, state_type state, int level, int optname, ec = asio::error::fault; return socket_error_retval; #elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) { @@ -1587,15 +2015,13 @@ int getsockopt(socket_type s, state_type state, int level, int optname, // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets // on Windows platforms pre-Vista. *static_cast<DWORD*>(optval) = 1; - ec = asio::error_code(); + ec.assign(0, ec.category()); } - if (result == 0) - ec = asio::error_code(); return result; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); #if defined(__linux__) if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) && (optname == SO_SNDBUF || optname == SO_RCVBUF)) @@ -1608,8 +2034,6 @@ int getsockopt(socket_type s, state_type state, int level, int optname, *static_cast<int*>(optval) /= 2; } #endif // defined(__linux__) - if (result == 0) - ec = asio::error_code(); return result; #endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1652,7 +2076,7 @@ int getpeername(socket_type s, socket_addr_type* addr, } // The cached value is still valid. - ec = asio::error_code(); + ec.assign(0, ec.category()); return 0; } #else // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) @@ -1661,11 +2085,8 @@ int getpeername(socket_type s, socket_addr_type* addr, #endif // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) // || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getpeername( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -1688,11 +2109,8 @@ int getsockname(socket_type s, socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_getsockname( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = asio::error_code(); + int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -1705,20 +2123,17 @@ int ioctl(socket_type s, state_type& state, int cmd, return socket_error_retval; } - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); + int result = ::ioctlsocket(s, cmd, arg); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - int result = error_wrapper(::ioctl(s, - static_cast<unsigned int>(cmd), arg), ec); + int result = ::ioctl(s, static_cast<unsigned int>(cmd), arg); #else - int result = error_wrapper(::ioctl(s, cmd, arg), ec); + int result = ::ioctl(s, cmd, arg); #endif + get_last_error(ec, result < 0); if (result >= 0) { - ec = asio::error_code(); - // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the socket is already in // the correct state. This ensures that the underlying socket is put into @@ -1746,7 +2161,9 @@ int ioctl(socket_type s, state_type& state, int cmd, int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout, asio::error_code& ec) { - clear_last_error(); +#if defined(__EMSCRIPTEN__) + exceptfds = 0; +#endif // defined(__EMSCRIPTEN__) #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) if (!readfds && !writefds && !exceptfds && timeout) { @@ -1754,7 +2171,7 @@ int select(int nfds, fd_set* readfds, fd_set* writefds, if (milliseconds == 0) milliseconds = 1; // Force context switch. ::Sleep(milliseconds); - ec = asio::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1773,15 +2190,13 @@ int select(int nfds, fd_set* readfds, fd_set* writefds, timespec ts; ts.tv_sec = timeout ? timeout->tv_sec : 0; ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; - return error_wrapper(::pselect(nfds, readfds, - writefds, exceptfds, timeout ? &ts : 0, 0), ec); + int result = ::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0); #else - int result = error_wrapper(::select(nfds, readfds, - writefds, exceptfds, timeout), ec); - if (result >= 0) - ec = asio::error_code(); - return result; + int result = ::select(nfds, readfds, writefds, exceptfds, timeout); #endif + get_last_error(ec, result < 0); + return result; } int poll_read(socket_type s, state_type state, @@ -1815,8 +2230,8 @@ int poll_read(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec); + int result = ::select(s + 1, &fds, 0, 0, timeout); + get_last_error(ec, result < 0); #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -1825,16 +2240,14 @@ int poll_read(socket_type s, state_type state, fds.events = POLLIN; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -1869,8 +2282,8 @@ int poll_write(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec); + int result = ::select(s + 1, 0, &fds, 0, timeout); + get_last_error(ec, result < 0); #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -1879,16 +2292,14 @@ int poll_write(socket_type s, state_type state, fds.events = POLLOUT; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -1923,8 +2334,8 @@ int poll_error(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec); + int result = ::select(s + 1, 0, 0, &fds, timeout); + get_last_error(ec, result < 0); #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -1933,16 +2344,14 @@ int poll_error(socket_type s, state_type state, fds.events = POLLPRI | POLLERR | POLLHUP; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? asio::error::would_block : asio::error_code(); - else if (result > 0) - ec = asio::error_code(); + if (state & user_set_non_blocking) + ec = asio::error::would_block; return result; } @@ -1973,11 +2382,8 @@ int poll_connect(socket_type s, int msec, asio::error_code& ec) } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select( - s + 1, 0, &write_fds, &except_fds, timeout), ec); - if (result >= 0) - ec = asio::error_code(); + int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout); + get_last_error(ec, result < 0); return result; #else // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) @@ -1986,10 +2392,8 @@ int poll_connect(socket_type s, int msec, asio::error_code& ec) fds.fd = s; fds.events = POLLOUT; fds.revents = 0; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, msec), ec); - if (result >= 0) - ec = asio::error_code(); + int result = ::poll(&fds, 1, msec); + get_last_error(ec, result < 0); return result; #endif // defined(ASIO_WINDOWS) // || defined(__CYGWIN__) @@ -2074,18 +2478,20 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, DWORD string_length = static_cast<DWORD>(length); #if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); - int result = error_wrapper(::WSAAddressToStringW(&address.base, - address_length, 0, string_buffer, &string_length), ec); + int result = ::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length); + get_last_error(ec, true); ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, static_cast<int>(length), 0, 0); #else - int result = error_wrapper(::WSAAddressToStringA( - &address.base, address_length, 0, dest, &string_length), ec); + int result = ::WSAAddressToStringA(&address.base, + address_length, 0, dest, &string_length); + get_last_error(ec, true); #endif // Windows may set error code on success. if (result != socket_error_retval) - ec = asio::error_code(); + ec.assign(0, ec.category()); // Windows may not set an error code on failure. else if (result == socket_error_retval && !ec) @@ -2093,14 +2499,14 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, return result == socket_error_retval ? 0 : dest; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) - const char* result = error_wrapper(::inet_ntop( - af, src, dest, static_cast<int>(length)), ec); + const char* result = ::inet_ntop(af, src, dest, static_cast<int>(length)); + get_last_error(ec, true); if (result == 0 && !ec) ec = asio::error::invalid_argument; if (result != 0 && af == ASIO_OS_DEF(AF_INET6) && scope_id != 0) { using namespace std; // For strcat and sprintf. - char if_name[IF_NAMESIZE + 1] = "%"; + char if_name[(IF_NAMESIZE > 21 ? IF_NAMESIZE : 21) + 1] = "%"; const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src); bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); @@ -2139,7 +2545,7 @@ int inet_pton(int af, const char* src, void* dest, bytes[1] = static_cast<unsigned char>(b1); bytes[2] = static_cast<unsigned char>(b2); bytes[3] = static_cast<unsigned char>(b3); - ec = asio::error_code(); + ec.assign(0, ec.category()); return 1; } else if (af == ASIO_OS_DEF(AF_INET6)) @@ -2255,7 +2661,7 @@ int inet_pton(int af, const char* src, void* dest, for (int i = 0; i < num_back_bytes; ++i) bytes[16 - num_back_bytes + i] = back_bytes[i]; - ec = asio::error_code(); + ec.assign(0, ec.category()); return 1; } else @@ -2284,11 +2690,13 @@ int inet_pton(int af, const char* src, void* dest, int num_wide_chars = static_cast<int>(strlen(src)) + 1; LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); - int result = error_wrapper(::WSAStringToAddressW( - wide_buffer, af, 0, &address.base, &address_length), ec); + int result = ::WSAStringToAddressW(wide_buffer, + af, 0, &address.base, &address_length); + get_last_error(ec, true); #else - int result = error_wrapper(::WSAStringToAddressA( - const_cast<char*>(src), af, 0, &address.base, &address_length), ec); + int result = ::WSAStringToAddressA(const_cast<char*>(src), + af, 0, &address.base, &address_length); + get_last_error(ec, true); #endif if (af == ASIO_OS_DEF(AF_INET)) @@ -2296,12 +2704,12 @@ int inet_pton(int af, const char* src, void* dest, if (result != socket_error_retval) { memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); - ec = asio::error_code(); + ec.assign(0, ec.category()); } else if (strcmp(src, "255.255.255.255") == 0) { static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; - ec = asio::error_code(); + ec.assign(0, ec.category()); } } else // AF_INET6 @@ -2311,7 +2719,7 @@ int inet_pton(int af, const char* src, void* dest, memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); if (scope_id) *scope_id = address.v6.sin6_scope_id; - ec = asio::error_code(); + ec.assign(0, ec.category()); } } @@ -2320,7 +2728,7 @@ int inet_pton(int af, const char* src, void* dest, ec = asio::error::invalid_argument; if (result != socket_error_retval) - ec = asio::error_code(); + ec.assign(0, ec.category()); return result == socket_error_retval ? -1 : 1; #else // defined(ASIO_WINDOWS) || defined(__CYGWIN__) @@ -2344,7 +2752,8 @@ int inet_pton(int af, const char* src, void* dest, src_ptr = src_buf; } - int result = error_wrapper(::inet_pton(af, src_ptr, dest), ec); + int result = ::inet_pton(af, src_ptr, dest); + get_last_error(ec, true); if (result <= 0 && !ec) ec = asio::error::invalid_argument; if (result > 0 && is_v6 && scope_id) @@ -2370,7 +2779,6 @@ int inet_pton(int af, const char* src, void* dest, int gethostname(char* name, int namelen, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS_RUNTIME) try { @@ -2401,11 +2809,8 @@ int gethostname(char* name, int namelen, asio::error_code& ec) return -1; } #else // defined(ASIO_WINDOWS_RUNTIME) - int result = error_wrapper(::gethostname(name, namelen), ec); -# if defined(ASIO_WINDOWS) - if (result == 0) - ec = asio::error_code(); -# endif // defined(ASIO_WINDOWS) + int result = ::gethostname(name, namelen); + get_last_error(ec, result != 0); return result; #endif // defined(ASIO_WINDOWS_RUNTIME) } @@ -2440,20 +2845,20 @@ inline asio::error_code translate_netdb_error(int error) inline hostent* gethostbyaddr(const char* addr, int length, int af, hostent* result, char* buffer, int buflength, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); - hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + hostent* retval = ::gethostbyaddr(addr, length, af); + get_last_error(ec, !retval); if (!retval) return 0; - ec = asio::error_code(); *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) int error = 0; - hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, - buffer, buflength, &error), ec); + hostent* retval = ::gethostbyaddr_r(addr, length, + af, result, buffer, buflength, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; @@ -2461,8 +2866,8 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, (void)(buffer); (void)(buflength); int error = 0; - hostent* retval = error_wrapper(::getipnodebyaddr( - addr, length, af, &error), ec); + hostent* retval = ::getipnodebyaddr(addr, length, af, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); if (!retval) @@ -2472,8 +2877,10 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, #else hostent* retval = 0; int error = 0; - error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, - buflength, &retval, &error), ec); + clear_last_error(); + ::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &retval, &error); + get_last_error(ec, true); if (error) ec = translate_netdb_error(error); return retval; @@ -2483,7 +2890,6 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, inline hostent* gethostbyname(const char* name, int af, struct hostent* result, char* buffer, int buflength, int ai_flags, asio::error_code& ec) { - clear_last_error(); #if defined(ASIO_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); @@ -2493,10 +2899,10 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, ec = asio::error::address_family_not_supported; return 0; } - hostent* retval = error_wrapper(::gethostbyname(name), ec); + hostent* retval = ::gethostbyname(name); + get_last_error(ec, !retval); if (!retval) return 0; - ec = asio::error_code(); *result = *retval; return result; #elif defined(__sun) || defined(__QNX__) @@ -2507,8 +2913,8 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, return 0; } int error = 0; - hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, - buflength, &error), ec); + hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; @@ -2516,8 +2922,8 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, (void)(buffer); (void)(buflength); int error = 0; - hostent* retval = error_wrapper(::getipnodebyname( - name, af, ai_flags, &error), ec); + hostent* retval = ::getipnodebyname(name, af, ai_flags, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); if (!retval) @@ -2533,8 +2939,9 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, } hostent* retval = 0; int error = 0; - error_wrapper(::gethostbyname_r(name, result, - buffer, buflength, &retval, &error), ec); + clear_last_error(); + ::gethostbyname_r(name, result, buffer, buflength, &retval, &error); + get_last_error(ec, true); if (error) ec = translate_netdb_error(error); return retval; @@ -3250,7 +3657,7 @@ inline asio::error_code getnameinfo_emulation( } } - ec = asio::error_code(); + ec.assign(0, ec.category()); return ec; } @@ -3327,6 +3734,37 @@ asio::error_code getaddrinfo(const char* host, return ec = translate_addrinfo_error(error); #else int error = ::getaddrinfo(host, service, &hints, result); +#if defined(__MACH__) && defined(__APPLE__) + using namespace std; // For isdigit and atoi. + if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0]))) + { + u_short_type port = host_to_network_short(atoi(service)); + for (addrinfo_type* ai = *result; ai; ai = ai->ai_next) + { + switch (ai->ai_family) + { + case ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr); + if (sinptr->sin_port == 0) + sinptr->sin_port = port; + break; + } + case ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr); + if (sin6ptr->sin6_port == 0) + sin6ptr->sin6_port = port; + break; + } + default: + break; + } + } + } +#endif return ec = translate_addrinfo_error(error); #endif } @@ -3404,7 +3842,6 @@ asio::error_code getnameinfo(const socket_addr_type* addr, using namespace std; // For memcpy. sockaddr_storage_type tmp_addr; memcpy(&tmp_addr, addr, addrlen); - tmp_addr.ss_len = addrlen; addr = reinterpret_cast<socket_addr_type*>(&tmp_addr); clear_last_error(); return getnameinfo_emulation(addr, addrlen, |