/Src/Dependencies/Boost/boost/asio/detail/impl/socket_ops.ipp
http://hadesmem.googlecode.com/ · C++ Header · 3048 lines · 2550 code · 287 blank · 211 comment · 765 complexity · a110c3cf3a01d0363e2dff13e1d4da07 MD5 · raw file
Large files are truncated click here to view the full file
- //
- // detail/impl/socket_ops.ipp
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~
- //
- // Copyright (c) 2003-2011 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)
- //
- #ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
- #define BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- # pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include <boost/asio/detail/config.hpp>
- #include <boost/assert.hpp>
- #include <boost/detail/workaround.hpp>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <cerrno>
- #include <new>
- #include <boost/asio/detail/socket_ops.hpp>
- #include <boost/asio/error.hpp>
- #include <boost/asio/detail/push_options.hpp>
- namespace boost {
- namespace asio {
- namespace detail {
- namespace socket_ops {
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- struct msghdr { int msg_namelen; };
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- #if defined(__hpux)
- // HP-UX doesn't declare these functions extern "C", so they are declared again
- // here to avoid linker errors about undefined symbols.
- extern "C" char* if_indextoname(unsigned int, char*);
- extern "C" unsigned int if_nametoindex(const char*);
- #endif // defined(__hpux)
- inline void clear_last_error()
- {
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- WSASetLastError(0);
- #else
- errno = 0;
- #endif
- }
- template <typename ReturnType>
- inline ReturnType error_wrapper(ReturnType return_value,
- boost::system::error_code& ec)
- {
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- ec = boost::system::error_code(WSAGetLastError(),
- boost::asio::error::get_system_category());
- #else
- ec = boost::system::error_code(errno,
- boost::asio::error::get_system_category());
- #endif
- return return_value;
- }
- template <typename SockLenType>
- inline socket_type call_accept(SockLenType msghdr::*,
- socket_type s, socket_addr_type* addr, std::size_t* addrlen)
- {
- SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
- socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
- if (addrlen)
- *addrlen = (std::size_t)tmp_addrlen;
- return result;
- }
- socket_type accept(socket_type s, socket_addr_type* addr,
- std::size_t* addrlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return invalid_socket;
- }
- clear_last_error();
- socket_type new_s = error_wrapper(call_accept(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- 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);
- if (result != 0)
- {
- ::close(new_s);
- return invalid_socket;
- }
- #endif
- ec = boost::system::error_code();
- return new_s;
- }
- socket_type sync_accept(socket_type s, state_type state,
- socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec)
- {
- // Accept a socket.
- for (;;)
- {
- // Try to complete the operation without blocking.
- socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
- // Check if operation succeeded.
- if (new_socket != invalid_socket)
- return new_socket;
- // Operation failed.
- if (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again)
- {
- if (state & user_set_non_blocking)
- return invalid_socket;
- // Fall through to retry operation.
- }
- else if (ec == boost::asio::error::connection_aborted)
- {
- if (state & enable_connection_aborted)
- return invalid_socket;
- // Fall through to retry operation.
- }
- #if defined(EPROTO)
- else if (ec.value() == EPROTO)
- {
- if (state & enable_connection_aborted)
- return invalid_socket;
- // Fall through to retry operation.
- }
- #endif // defined(EPROTO)
- else
- return invalid_socket;
- // Wait for socket to become ready.
- if (socket_ops::poll_read(s, ec) < 0)
- return invalid_socket;
- }
- }
- #if defined(BOOST_ASIO_HAS_IOCP)
- void complete_iocp_accept(socket_type s,
- void* output_buffer, DWORD address_length,
- socket_addr_type* addr, std::size_t* addrlen,
- socket_type new_socket, boost::system::error_code& ec)
- {
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_NETNAME_DELETED)
- ec = boost::asio::error::connection_aborted;
- if (!ec)
- {
- // Get the address of the peer.
- if (addr && addrlen)
- {
- LPSOCKADDR local_addr = 0;
- int local_addr_length = 0;
- LPSOCKADDR remote_addr = 0;
- int remote_addr_length = 0;
- GetAcceptExSockaddrs(output_buffer, 0, address_length,
- address_length, &local_addr, &local_addr_length,
- &remote_addr, &remote_addr_length);
- if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
- {
- ec = boost::asio::error::invalid_argument;
- }
- else
- {
- using namespace std; // For memcpy.
- memcpy(addr, remote_addr, remote_addr_length);
- *addrlen = static_cast<std::size_t>(remote_addr_length);
- }
- }
- // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
- // and getpeername will work on the accepted socket.
- SOCKET update_ctx_param = s;
- socket_ops::state_type state = 0;
- socket_ops::setsockopt(new_socket, state,
- SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
- &update_ctx_param, sizeof(SOCKET), ec);
- }
- }
- #else // defined(BOOST_ASIO_HAS_IOCP)
- bool non_blocking_accept(socket_type s,
- state_type state, socket_addr_type* addr, std::size_t* addrlen,
- boost::system::error_code& ec, socket_type& new_socket)
- {
- for (;;)
- {
- // Accept the waiting connection.
- new_socket = socket_ops::accept(s, addr, addrlen, ec);
- // Check if operation succeeded.
- if (new_socket != invalid_socket)
- return true;
- // Retry operation if interrupted by signal.
- if (ec == boost::asio::error::interrupted)
- continue;
- // Operation failed.
- if (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again)
- {
- if (state & user_set_non_blocking)
- return true;
- // Fall through to retry operation.
- }
- else if (ec == boost::asio::error::connection_aborted)
- {
- if (state & enable_connection_aborted)
- return true;
- // Fall through to retry operation.
- }
- #if defined(EPROTO)
- else if (ec.value() == EPROTO)
- {
- if (state & enable_connection_aborted)
- return true;
- // Fall through to retry operation.
- }
- #endif // defined(EPROTO)
- else
- return true;
- return false;
- }
- }
- #endif // defined(BOOST_ASIO_HAS_IOCP)
- template <typename SockLenType>
- inline int call_bind(SockLenType msghdr::*,
- socket_type s, const socket_addr_type* addr, std::size_t addrlen)
- {
- return ::bind(s, addr, (SockLenType)addrlen);
- }
- int bind(socket_type s, const socket_addr_type* addr,
- std::size_t addrlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- clear_last_error();
- int result = error_wrapper(call_bind(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- }
- int close(socket_type s, state_type& state,
- bool destruction, boost::system::error_code& ec)
- {
- int result = 0;
- if (s != invalid_socket)
- {
- // We don't want the destructor to block, so set the socket to linger in
- // the background. If the user doesn't like this behaviour then they need
- // to explicitly close the socket.
- if (destruction && (state & user_set_linger))
- {
- ::linger opt;
- opt.l_onoff = 0;
- opt.l_linger = 0;
- boost::system::error_code ignored_ec;
- socket_ops::setsockopt(s, state, SOL_SOCKET,
- SO_LINGER, &opt, sizeof(opt), ignored_ec);
- }
- clear_last_error();
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- result = error_wrapper(::closesocket(s), ec);
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- result = error_wrapper(::close(s), ec);
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (result != 0
- && (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again))
- {
- // According to UNIX Network Programming Vol. 1, it is possible for
- // close() to fail with EWOULDBLOCK under certain circumstances. What
- // isn't clear is the state of the descriptor after this error. The one
- // current OS where this behaviour is seen, Windows, says that the socket
- // remains open. Therefore we'll put the descriptor back into blocking
- // mode and have another attempt at closing it.
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- ioctl_arg_type arg = 0;
- ::ioctlsocket(s, FIONBIO, &arg);
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- # if defined(__SYMBIAN32__)
- int flags = ::fcntl(s, F_GETFL, 0);
- if (flags >= 0)
- ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
- # else // defined(__SYMBIAN32__)
- ioctl_arg_type arg = 0;
- ::ioctl(s, FIONBIO, &arg);
- # endif // defined(__SYMBIAN32__)
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- state &= ~non_blocking;
- clear_last_error();
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- result = error_wrapper(::closesocket(s), ec);
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- result = error_wrapper(::close(s), ec);
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- }
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- }
- bool set_user_non_blocking(socket_type s,
- state_type& state, bool value, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return false;
- }
- clear_last_error();
- #if defined(BOOST_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);
- if (result >= 0)
- {
- clear_last_error();
- int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
- result = error_wrapper(::fcntl(s, F_SETFL, flag), ec);
- }
- #else
- ioctl_arg_type arg = (value ? 1 : 0);
- int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
- #endif
- if (result >= 0)
- {
- ec = boost::system::error_code();
- if (value)
- state |= user_set_non_blocking;
- else
- {
- // Clearing the user-set non-blocking mode always overrides any
- // internally-set non-blocking flag. Any subsequent asynchronous
- // operations will need to re-enable non-blocking I/O.
- state &= ~(user_set_non_blocking | internal_non_blocking);
- }
- return true;
- }
- return false;
- }
- bool set_internal_non_blocking(socket_type s,
- state_type& state, bool value, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return false;
- }
- if (!value && (state & user_set_non_blocking))
- {
- // It does not make sense to clear the internal non-blocking flag if the
- // user still wants non-blocking behaviour. Return an error and let the
- // caller figure out whether to update the user-set non-blocking flag.
- ec = boost::asio::error::invalid_argument;
- return false;
- }
- clear_last_error();
- #if defined(BOOST_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);
- if (result >= 0)
- {
- clear_last_error();
- int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
- result = error_wrapper(::fcntl(s, F_SETFL, flag), ec);
- }
- #else
- ioctl_arg_type arg = (value ? 1 : 0);
- int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
- #endif
- if (result >= 0)
- {
- ec = boost::system::error_code();
- if (value)
- state |= internal_non_blocking;
- else
- state &= ~internal_non_blocking;
- return true;
- }
- return false;
- }
- int shutdown(socket_type s, int what, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- clear_last_error();
- int result = error_wrapper(::shutdown(s, what), ec);
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- }
- template <typename SockLenType>
- inline int call_connect(SockLenType msghdr::*,
- socket_type s, const socket_addr_type* addr, std::size_t addrlen)
- {
- return ::connect(s, addr, (SockLenType)addrlen);
- }
- int connect(socket_type s, const socket_addr_type* addr,
- std::size_t addrlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- clear_last_error();
- int result = error_wrapper(call_connect(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- }
- void sync_connect(socket_type s, const socket_addr_type* addr,
- std::size_t addrlen, boost::system::error_code& ec)
- {
- // Perform the connect operation.
- socket_ops::connect(s, addr, addrlen, ec);
- if (ec != boost::asio::error::in_progress
- && ec != boost::asio::error::would_block)
- {
- // The connect operation finished immediately.
- return;
- }
- // Wait for socket to become ready.
- if (socket_ops::poll_connect(s, ec) < 0)
- return;
- // Get the error code from the connect operation.
- int connect_error = 0;
- size_t connect_error_len = sizeof(connect_error);
- if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
- &connect_error, &connect_error_len, ec) == socket_error_retval)
- return;
- // Return the result of the connect operation.
- ec = boost::system::error_code(connect_error,
- boost::asio::error::get_system_category());
- }
- bool non_blocking_connect(socket_type s, boost::system::error_code& ec)
- {
- // Get the error code from the connect operation.
- int connect_error = 0;
- size_t connect_error_len = sizeof(connect_error);
- if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
- &connect_error, &connect_error_len, ec) == 0)
- {
- if (connect_error)
- {
- ec = boost::system::error_code(connect_error,
- boost::asio::error::get_system_category());
- }
- else
- ec = boost::system::error_code();
- }
- return true;
- }
- int socketpair(int af, int type, int protocol,
- socket_type sv[2], boost::system::error_code& ec)
- {
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- (void)(af);
- (void)(type);
- (void)(protocol);
- (void)(sv);
- ec = boost::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 = boost::system::error_code();
- return result;
- #endif
- }
- bool sockatmark(socket_type s, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return false;
- }
- #if defined(SIOCATMARK)
- ioctl_arg_type value = 0;
- # if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec);
- # else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec);
- # endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (result == 0)
- ec = boost::system::error_code();
- # if defined(ENOTTY)
- if (ec.value() == ENOTTY)
- ec = boost::asio::error::not_socket;
- # endif // defined(ENOTTY)
- #else // defined(SIOCATMARK)
- int value = error_wrapper(::sockatmark(s), ec);
- if (value != -1)
- ec = boost::system::error_code();
- #endif // defined(SIOCATMARK)
- return ec ? false : value != 0;
- }
- size_t available(socket_type s, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return 0;
- }
- ioctl_arg_type value = 0;
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec);
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec);
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (result == 0)
- ec = boost::system::error_code();
- #if defined(ENOTTY)
- if (ec.value() == ENOTTY)
- ec = boost::asio::error::not_socket;
- #endif // defined(ENOTTY)
- return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
- }
- int listen(socket_type s, int backlog, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- clear_last_error();
- int result = error_wrapper(::listen(s, backlog), ec);
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- }
- inline void init_buf_iov_base(void*& base, void* addr)
- {
- base = addr;
- }
- template <typename T>
- inline void init_buf_iov_base(T& base, void* addr)
- {
- base = static_cast<T>(addr);
- }
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- typedef WSABUF buf;
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- typedef iovec buf;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- void init_buf(buf& b, void* data, size_t size)
- {
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- b.buf = static_cast<char*>(data);
- b.len = static_cast<u_long>(size);
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- init_buf_iov_base(b.iov_base, data);
- b.iov_len = size;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- void init_buf(buf& b, const void* data, size_t size)
- {
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- b.buf = static_cast<char*>(const_cast<void*>(data));
- b.len = static_cast<u_long>(size);
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- init_buf_iov_base(b.iov_base, const_cast<void*>(data));
- b.iov_len = size;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
- {
- name = addr;
- }
- inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
- {
- name = const_cast<socket_addr_type*>(addr);
- }
- template <typename T>
- inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
- {
- name = reinterpret_cast<T>(addr);
- }
- template <typename T>
- inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
- {
- name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
- }
- int recv(socket_type s, buf* bufs, size_t count, int flags,
- boost::system::error_code& ec)
- {
- clear_last_error();
- #if defined(BOOST_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);
- if (ec.value() == ERROR_NETNAME_DELETED)
- ec = boost::asio::error::connection_reset;
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- ec = boost::asio::error::connection_refused;
- if (result != 0)
- return socket_error_retval;
- ec = boost::system::error_code();
- return bytes_transferred;
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- msg.msg_iov = bufs;
- msg.msg_iovlen = count;
- int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
- if (result >= 0)
- ec = boost::system::error_code();
- return result;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- size_t sync_recv(socket_type s, state_type state, buf* bufs,
- size_t count, int flags, bool all_empty, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return 0;
- }
- // A request to read 0 bytes on a stream is a no-op.
- if (all_empty && (state & stream_oriented))
- {
- ec = boost::system::error_code();
- return 0;
- }
- // Read some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes = socket_ops::recv(s, bufs, count, flags, ec);
- // Check if operation succeeded.
- if (bytes > 0)
- return bytes;
- // Check for EOF.
- if ((state & stream_oriented) && bytes == 0)
- {
- ec = boost::asio::error::eof;
- return 0;
- }
- // Operation failed.
- if ((state & user_set_non_blocking)
- || (ec != boost::asio::error::would_block
- && ec != boost::asio::error::try_again))
- return 0;
- // Wait for socket to become ready.
- if (socket_ops::poll_read(s, ec) < 0)
- return 0;
- }
- }
- #if defined(BOOST_ASIO_HAS_IOCP)
- void complete_iocp_recv(state_type state,
- const weak_cancel_token_type& cancel_token, bool all_empty,
- boost::system::error_code& ec, size_t bytes_transferred)
- {
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (cancel_token.expired())
- ec = boost::asio::error::operation_aborted;
- else
- ec = boost::asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
- // Check for connection closed.
- else if (!ec && bytes_transferred == 0
- && (state & stream_oriented) != 0
- && !all_empty)
- {
- ec = boost::asio::error::eof;
- }
- }
- #else // defined(BOOST_ASIO_HAS_IOCP)
- bool non_blocking_recv(socket_type s,
- buf* bufs, size_t count, int flags, bool is_stream,
- boost::system::error_code& ec, size_t& bytes_transferred)
- {
- for (;;)
- {
- // Read some data.
- int bytes = socket_ops::recv(s, bufs, count, flags, ec);
- // Check for end of stream.
- if (is_stream && bytes == 0)
- {
- ec = boost::asio::error::eof;
- return true;
- }
- // Retry operation if interrupted by signal.
- if (ec == boost::asio::error::interrupted)
- continue;
- // Check if we need to run the operation again.
- if (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again)
- return false;
- // Operation is complete.
- if (bytes >= 0)
- {
- ec = boost::system::error_code();
- bytes_transferred = bytes;
- }
- else
- bytes_transferred = 0;
- return true;
- }
- }
- #endif // defined(BOOST_ASIO_HAS_IOCP)
- int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
- socket_addr_type* addr, std::size_t* addrlen,
- boost::system::error_code& ec)
- {
- clear_last_error();
- #if defined(BOOST_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);
- *addrlen = (std::size_t)tmp_addrlen;
- if (ec.value() == ERROR_NETNAME_DELETED)
- ec = boost::asio::error::connection_reset;
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- ec = boost::asio::error::connection_refused;
- if (result != 0)
- return socket_error_retval;
- ec = boost::system::error_code();
- return bytes_transferred;
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- init_msghdr_msg_name(msg.msg_name, addr);
- msg.msg_namelen = *addrlen;
- msg.msg_iov = bufs;
- msg.msg_iovlen = count;
- int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
- *addrlen = msg.msg_namelen;
- if (result >= 0)
- ec = boost::system::error_code();
- return result;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
- size_t count, int flags, socket_addr_type* addr,
- std::size_t* addrlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return 0;
- }
- // Read some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec);
- // Check if operation succeeded.
- if (bytes >= 0)
- return bytes;
- // Operation failed.
- if ((state & user_set_non_blocking)
- || (ec != boost::asio::error::would_block
- && ec != boost::asio::error::try_again))
- return 0;
- // Wait for socket to become ready.
- if (socket_ops::poll_read(s, ec) < 0)
- return 0;
- }
- }
- #if defined(BOOST_ASIO_HAS_IOCP)
- void complete_iocp_recvfrom(
- const weak_cancel_token_type& cancel_token,
- boost::system::error_code& ec)
- {
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (cancel_token.expired())
- ec = boost::asio::error::operation_aborted;
- else
- ec = boost::asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
- }
- #else // defined(BOOST_ASIO_HAS_IOCP)
- bool non_blocking_recvfrom(socket_type s,
- buf* bufs, size_t count, int flags,
- socket_addr_type* addr, std::size_t* addrlen,
- boost::system::error_code& ec, size_t& bytes_transferred)
- {
- for (;;)
- {
- // Read some data.
- int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec);
- // Retry operation if interrupted by signal.
- if (ec == boost::asio::error::interrupted)
- continue;
- // Check if we need to run the operation again.
- if (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again)
- return false;
- // Operation is complete.
- if (bytes >= 0)
- {
- ec = boost::system::error_code();
- bytes_transferred = bytes;
- }
- else
- bytes_transferred = 0;
- return true;
- }
- }
- #endif // defined(BOOST_ASIO_HAS_IOCP)
- int recvmsg(socket_type s, buf* bufs, size_t count,
- int in_flags, int& out_flags, boost::system::error_code& ec)
- {
- clear_last_error();
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- out_flags = 0;
- return socket_ops::recv(s, bufs, count, in_flags, ec);
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- msg.msg_iov = bufs;
- msg.msg_iovlen = count;
- int result = error_wrapper(::recvmsg(s, &msg, in_flags), ec);
- if (result >= 0)
- {
- ec = boost::system::error_code();
- out_flags = msg.msg_flags;
- }
- else
- out_flags = 0;
- return result;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- size_t sync_recvmsg(socket_type s, state_type state,
- buf* bufs, size_t count, int in_flags, int& out_flags,
- boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return 0;
- }
- // Read some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes = socket_ops::recvmsg(s, bufs, count, in_flags, out_flags, ec);
- // Check if operation succeeded.
- if (bytes >= 0)
- return bytes;
- // Operation failed.
- if ((state & user_set_non_blocking)
- || (ec != boost::asio::error::would_block
- && ec != boost::asio::error::try_again))
- return 0;
- // Wait for socket to become ready.
- if (socket_ops::poll_read(s, ec) < 0)
- return 0;
- }
- }
- #if defined(BOOST_ASIO_HAS_IOCP)
- void complete_iocp_recvmsg(
- const weak_cancel_token_type& cancel_token,
- boost::system::error_code& ec)
- {
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (cancel_token.expired())
- ec = boost::asio::error::operation_aborted;
- else
- ec = boost::asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
- }
- #else // defined(BOOST_ASIO_HAS_IOCP)
- bool non_blocking_recvmsg(socket_type s,
- buf* bufs, size_t count, int in_flags, int& out_flags,
- boost::system::error_code& ec, size_t& bytes_transferred)
- {
- for (;;)
- {
- // Read some data.
- int bytes = socket_ops::recvmsg(s, bufs, count, in_flags, out_flags, ec);
- // Retry operation if interrupted by signal.
- if (ec == boost::asio::error::interrupted)
- continue;
- // Check if we need to run the operation again.
- if (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again)
- return false;
- // Operation is complete.
- if (bytes >= 0)
- {
- ec = boost::system::error_code();
- bytes_transferred = bytes;
- }
- else
- bytes_transferred = 0;
- return true;
- }
- }
- #endif // defined(BOOST_ASIO_HAS_IOCP)
- int send(socket_type s, const buf* bufs, size_t count, int flags,
- boost::system::error_code& ec)
- {
- clear_last_error();
- #if defined(BOOST_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);
- if (ec.value() == ERROR_NETNAME_DELETED)
- ec = boost::asio::error::connection_reset;
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- ec = boost::asio::error::connection_refused;
- if (result != 0)
- return socket_error_retval;
- ec = boost::system::error_code();
- return bytes_transferred;
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- msg.msg_iov = const_cast<buf*>(bufs);
- msg.msg_iovlen = count;
- #if defined(__linux__)
- flags |= MSG_NOSIGNAL;
- #endif // defined(__linux__)
- int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
- if (result >= 0)
- ec = boost::system::error_code();
- return result;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- size_t sync_send(socket_type s, state_type state, const buf* bufs,
- size_t count, int flags, bool all_empty, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return 0;
- }
- // A request to write 0 bytes to a stream is a no-op.
- if (all_empty && (state & stream_oriented))
- {
- ec = boost::system::error_code();
- return 0;
- }
- // Read some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes = socket_ops::send(s, bufs, count, flags, ec);
- // Check if operation succeeded.
- if (bytes >= 0)
- return bytes;
- // Operation failed.
- if ((state & user_set_non_blocking)
- || (ec != boost::asio::error::would_block
- && ec != boost::asio::error::try_again))
- return 0;
- // Wait for socket to become ready.
- if (socket_ops::poll_write(s, ec) < 0)
- return 0;
- }
- }
- #if defined(BOOST_ASIO_HAS_IOCP)
- void complete_iocp_send(
- const weak_cancel_token_type& cancel_token,
- boost::system::error_code& ec)
- {
- // Map non-portable errors to their portable counterparts.
- if (ec.value() == ERROR_NETNAME_DELETED)
- {
- if (cancel_token.expired())
- ec = boost::asio::error::operation_aborted;
- else
- ec = boost::asio::error::connection_reset;
- }
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- {
- ec = boost::asio::error::connection_refused;
- }
- }
- #else // defined(BOOST_ASIO_HAS_IOCP)
- bool non_blocking_send(socket_type s,
- const buf* bufs, size_t count, int flags,
- boost::system::error_code& ec, size_t& bytes_transferred)
- {
- for (;;)
- {
- // Write some data.
- int bytes = socket_ops::send(s, bufs, count, flags, ec);
- // Retry operation if interrupted by signal.
- if (ec == boost::asio::error::interrupted)
- continue;
- // Check if we need to run the operation again.
- if (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again)
- return false;
- // Operation is complete.
- if (bytes >= 0)
- {
- ec = boost::system::error_code();
- bytes_transferred = bytes;
- }
- else
- bytes_transferred = 0;
- return true;
- }
- }
- #endif // defined(BOOST_ASIO_HAS_IOCP)
- int sendto(socket_type s, const buf* bufs, size_t count, int flags,
- const socket_addr_type* addr, std::size_t addrlen,
- boost::system::error_code& ec)
- {
- clear_last_error();
- #if defined(BOOST_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),
- send_buf_count, &bytes_transferred, flags, addr,
- static_cast<int>(addrlen), 0, 0), ec);
- if (ec.value() == ERROR_NETNAME_DELETED)
- ec = boost::asio::error::connection_reset;
- else if (ec.value() == ERROR_PORT_UNREACHABLE)
- ec = boost::asio::error::connection_refused;
- if (result != 0)
- return socket_error_retval;
- ec = boost::system::error_code();
- return bytes_transferred;
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- msghdr msg = msghdr();
- init_msghdr_msg_name(msg.msg_name, addr);
- msg.msg_namelen = addrlen;
- msg.msg_iov = const_cast<buf*>(bufs);
- msg.msg_iovlen = count;
- #if defined(__linux__)
- flags |= MSG_NOSIGNAL;
- #endif // defined(__linux__)
- int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
- if (result >= 0)
- ec = boost::system::error_code();
- return result;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- size_t sync_sendto(socket_type s, state_type state, const buf* bufs,
- size_t count, int flags, const socket_addr_type* addr,
- std::size_t addrlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return 0;
- }
- // Write some data.
- for (;;)
- {
- // Try to complete the operation without blocking.
- int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec);
- // Check if operation succeeded.
- if (bytes >= 0)
- return bytes;
- // Operation failed.
- if ((state & user_set_non_blocking)
- || (ec != boost::asio::error::would_block
- && ec != boost::asio::error::try_again))
- return 0;
- // Wait for socket to become ready.
- if (socket_ops::poll_write(s, ec) < 0)
- return 0;
- }
- }
- #if !defined(BOOST_ASIO_HAS_IOCP)
- bool non_blocking_sendto(socket_type s,
- const buf* bufs, size_t count, int flags,
- const socket_addr_type* addr, std::size_t addrlen,
- boost::system::error_code& ec, size_t& bytes_transferred)
- {
- for (;;)
- {
- // Write some data.
- int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec);
- // Retry operation if interrupted by signal.
- if (ec == boost::asio::error::interrupted)
- continue;
- // Check if we need to run the operation again.
- if (ec == boost::asio::error::would_block
- || ec == boost::asio::error::try_again)
- return false;
- // Operation is complete.
- if (bytes >= 0)
- {
- ec = boost::system::error_code();
- bytes_transferred = bytes;
- }
- else
- bytes_transferred = 0;
- return true;
- }
- }
- #endif // !defined(BOOST_ASIO_HAS_IOCP)
- socket_type socket(int af, int type, int protocol,
- boost::system::error_code& ec)
- {
- clear_last_error();
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
- WSA_FLAG_OVERLAPPED), ec);
- if (s == invalid_socket)
- return s;
- if (af == AF_INET6)
- {
- // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
- // false. This will only succeed on Windows Vista and later versions of
- // Windows, where a dual-stack IPv4/v6 implementation is available.
- DWORD optval = 0;
- ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
- reinterpret_cast<const char*>(&optval), sizeof(optval));
- }
- ec = boost::system::error_code();
- return s;
- #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
- socket_type s = error_wrapper(::socket(af, type, protocol), ec);
- if (s == invalid_socket)
- return s;
- int optval = 1;
- int result = error_wrapper(::setsockopt(s,
- SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
- if (result != 0)
- {
- ::close(s);
- return invalid_socket;
- }
- return s;
- #else
- int s = error_wrapper(::socket(af, type, protocol), ec);
- if (s >= 0)
- ec = boost::system::error_code();
- return s;
- #endif
- }
- template <typename SockLenType>
- inline int call_setsockopt(SockLenType msghdr::*,
- socket_type s, int level, int optname,
- const void* optval, std::size_t optlen)
- {
- return ::setsockopt(s, level, optname,
- (const char*)optval, (SockLenType)optlen);
- }
- int setsockopt(socket_type s, state_type& state, int level, int optname,
- const void* optval, std::size_t optlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- if (level == custom_socket_option_level && optname == always_fail_option)
- {
- ec = boost::asio::error::invalid_argument;
- return socket_error_retval;
- }
- if (level == custom_socket_option_level
- && optname == enable_connection_aborted_option)
- {
- if (optlen != sizeof(int))
- {
- ec = boost::asio::error::invalid_argument;
- return socket_error_retval;
- }
- if (*static_cast<const int*>(optval))
- state |= enable_connection_aborted;
- else
- state &= ~enable_connection_aborted;
- ec = boost::system::error_code();
- return 0;
- }
- if (level == SOL_SOCKET && optname == SO_LINGER)
- state |= user_set_linger;
- #if defined(__BORLANDC__)
- // Mysteriously, using the getsockopt and setsockopt functions directly with
- // Borland C++ results in incorrect values being set and read. The bug can be
- // worked around by using function addresses resolved with GetProcAddress.
- if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
- {
- 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,
- reinterpret_cast<const char*>(optval),
- static_cast<int>(optlen)), ec);
- }
- }
- ec = boost::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);
- if (result == 0)
- {
- ec = boost::system::error_code();
- #if defined(__MACH__) && defined(__APPLE__) \
- || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
- // 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)
- && level == SOL_SOCKET && optname == SO_REUSEADDR)
- {
- call_setsockopt(&msghdr::msg_namelen, s,
- SOL_SOCKET, SO_REUSEPORT, optval, optlen);
- }
- #endif
- }
- return result;
- #endif // defined(__BORLANDC__)
- }
- template <typename SockLenType>
- inline int call_getsockopt(SockLenType msghdr::*,
- socket_type s, int level, int optname,
- void* optval, std::size_t* optlen)
- {
- SockLenType tmp_optlen = (SockLenType)*optlen;
- int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
- *optlen = (std::size_t)tmp_optlen;
- return result;
- }
- int getsockopt(socket_type s, state_type state, int level, int optname,
- void* optval, size_t* optlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- if (level == custom_socket_option_level && optname == always_fail_option)
- {
- ec = boost::asio::error::invalid_argument;
- return socket_error_retval;
- }
- if (level == custom_socket_option_level
- && optname == enable_connection_aborted_option)
- {
- if (*optlen != sizeof(int))
- {
- ec = boost::asio::error::invalid_argument;
- return socket_error_retval;
- }
- *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
- ec = boost::system::error_code();
- return 0;
- }
- #if defined(__BORLANDC__)
- // Mysteriously, using the getsockopt and setsockopt functions directly with
- // Borland C++ results in incorrect values being set and read. The bug can be
- // worked around by using function addresses resolved with GetProcAddress.
- if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
- {
- 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);
- *optlen = static_cast<size_t>(tmp_optlen);
- if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
- && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
- {
- // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
- // only supported on Windows Vista and later. To simplify program logic
- // we will fake success of getting this option and specify that the
- // 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 = boost::system::error_code();
- }
- return result;
- }
- }
- ec = boost::asio::error::fault;
- return socket_error_retval;
- #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- clear_last_error();
- int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
- s, level, optname, optval, optlen), ec);
- if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
- && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
- {
- // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
- // supported on Windows Vista and later. To simplify program logic we will
- // fake success of getting this option and specify that the 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 = boost::system::error_code();
- }
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- clear_last_error();
- int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
- s, level, optname, optval, optlen), ec);
- #if defined(__linux__)
- if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
- && (optname == SO_SNDBUF || optname == SO_RCVBUF))
- {
- // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
- // to set the buffer size to N*2. Linux puts additional stuff into the
- // buffers so that only about half is actually available to the application.
- // The retrieved value is divided by 2 here to make it appear as though the
- // correct value has been set.
- *static_cast<int*>(optval) /= 2;
- }
- #endif // defined(__linux__)
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- }
- template <typename SockLenType>
- inline int call_getpeername(SockLenType msghdr::*,
- socket_type s, socket_addr_type* addr, std::size_t* addrlen)
- {
- SockLenType tmp_addrlen = (SockLenType)*addrlen;
- int result = ::getpeername(s, addr, &tmp_addrlen);
- *addrlen = (std::size_t)tmp_addrlen;
- return result;
- }
- int getpeername(socket_type s, socket_addr_type* addr,
- std::size_t* addrlen, bool cached, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (cached)
- {
- // Check if socket is still connected.
- DWORD connect_time = 0;
- size_t connect_time_len = sizeof(connect_time);
- if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,
- &connect_time, &connect_time_len, ec) == socket_error_retval)
- {
- return socket_error_retval;
- }
- if (connect_time == 0xFFFFFFFF)
- {
- ec = boost::asio::error::not_connected;
- return socket_error_retval;
- }
- // The cached value is still valid.
- ec = boost::system::error_code();
- return 0;
- }
- #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- (void)cached;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- clear_last_error();
- int result = error_wrapper(call_getpeername(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- }
- template <typename SockLenType>
- inline int call_getsockname(SockLenType msghdr::*,
- socket_type s, socket_addr_type* addr, std::size_t* addrlen)
- {
- SockLenType tmp_addrlen = (SockLenType)*addrlen;
- int result = ::getsockname(s, addr, &tmp_addrlen);
- *addrlen = (std::size_t)tmp_addrlen;
- return result;
- }
- int getsockname(socket_type s, socket_addr_type* addr,
- std::size_t* addrlen, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- clear_last_error();
- int result = error_wrapper(call_getsockname(
- &msghdr::msg_namelen, s, addr, addrlen), ec);
- if (result == 0)
- ec = boost::system::error_code();
- return result;
- }
- int ioctl(socket_type s, state_type& state, int cmd,
- ioctl_arg_type* arg, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- clear_last_error();
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
- #elif defined(__MACH__) && defined(__APPLE__) \
- || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
- int result = error_wrapper(::ioctl(s,
- static_cast<unsigned int>(cmd), arg), ec);
- #else
- int result = error_wrapper(::ioctl(s, cmd, arg), ec);
- #endif
- if (result >= 0)
- {
- ec = boost::system::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
- // the state that has been requested by the user. If the ioctl syscall was
- // successful then we need to update the flags to match.
- if (cmd == static_cast<int>(FIONBIO))
- {
- if (*arg)
- {
- state |= user_set_non_blocking;
- }
- else
- {
- // Clearing the non-blocking mode always overrides any internally-set
- // non-blocking flag. Any subsequent asynchronous operations will need
- // to re-enable non-blocking I/O.
- state &= ~(user_set_non_blocking | internal_non_blocking);
- }
- }
- }
- return result;
- }
- int select(int nfds, fd_set* readfds, fd_set* writefds,
- fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec)
- {
- clear_last_error();
- #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (!readfds && !writefds && !exceptfds && timeout)
- {
- DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
- if (milliseconds == 0)
- milliseconds = 1; // Force context switch.
- ::Sleep(milliseconds);
- ec = boost::system::error_code();
- return 0;
- }
- // The select() call allows timeout values measured in microseconds, but the
- // system clock (as wrapped by boost::posix_time::microsec_clock) typically
- // has a resolution of 10 milliseconds. This can lead to a spinning select
- // reactor, meaning increased CPU usage, when waiting for the earliest
- // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
- // spin we'll use a minimum timeout of 1 millisecond.
- if (timeout && timeout->tv_sec == 0
- && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
- timeout->tv_usec = 1000;
- #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- #if defined(__hpux) && defined(__SELECT)
- 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);
- #else
- int result = error_wrapper(::select(nfds, readfds,
- writefds, exceptfds, timeout), ec);
- if (result >= 0)
- ec = boost::system::error_code();
- return result;
- #endif
- }
- int poll_read(socket_type s, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- #if defined(BOOST_WINDOWS) \
- || defined(__CYGWIN__) \
- || defined(__SYMBIAN32__)
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(s, &fds);
- clear_last_error();
- int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
- if (result >= 0)
- ec = boost::system::error_code();
- return result;
- #else // defined(BOOST_WINDOWS)
- // || defined(__CYGWIN__)
- // || defined(__SYMBIAN32__)
- pollfd fds;
- fds.fd = s;
- fds.events = POLLIN;
- fds.revents = 0;
- clear_last_error();
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
- if (result >= 0)
- ec = boost::system::error_code();
- return result;
- #endif // defined(BOOST_WINDOWS)
- // || defined(__CYGWIN__)
- // || defined(__SYMBIAN32__)
- }
- int poll_write(socket_type s, boost::system::error_code& ec)
- {
- if (s == invalid_socket)
- {
- ec = boost::asio::error::bad_descriptor;
- return socket_error_retval;
- }
- #if defined(BOOST_WINDOWS) \
- || defined(__CYGWIN__) \
- || defined(__SYMBIAN3…