in demo_example/asio/asio/detail/impl/socket_ops.ipp [1946:2039]
int getsockopt(socket_type s, state_type state, int level, int optname,
void* optval, size_t* optlen, asio::error_code& ec)
{
if (s == invalid_socket)
{
ec = asio::error::bad_descriptor;
return socket_error_retval;
}
if (level == custom_socket_option_level && optname == always_fail_option)
{
ec = asio::error::invalid_argument;
return socket_error_retval;
}
if (level == custom_socket_option_level
&& optname == enable_connection_aborted_option)
{
if (*optlen != sizeof(int))
{
ec = asio::error::invalid_argument;
return socket_error_retval;
}
*static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
ec.assign(0, ec.category());
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"))
{
int tmp_optlen = static_cast<int>(*optlen);
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))
{
// 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.assign(0, ec.category());
}
return result;
}
}
ec = asio::error::fault;
return socket_error_retval;
#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
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))
{
// 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.assign(0, ec.category());
}
return result;
#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
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))
{
// 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__)
return result;
#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
}