📄 socket_ops.hpp
字号:
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_error(ec); 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; clear_error(ec); } return result; } } ec = asio::error::fault; return -1;#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_error(ec); 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; clear_error(ec); }# if defined(UNDER_CE) if (result == 0) clear_error(ec);# endif return result;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_error(ec); 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__) 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;}inline int getpeername(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec){ clear_error(ec); int result = error_wrapper(call_getpeername( &msghdr::msg_namelen, s, addr, addrlen), ec);#if defined(BOOST_WINDOWS) && defined(UNDER_CE) if (result == 0) clear_error(ec);#endif 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;}inline int getsockname(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec){ clear_error(ec); int result = error_wrapper(call_getsockname( &msghdr::msg_namelen, s, addr, addrlen), ec);#if defined(BOOST_WINDOWS) && defined(UNDER_CE) if (result == 0) clear_error(ec);#endif return result;}inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, asio::error_code& ec){ clear_error(ec);#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);# if defined(UNDER_CE) if (result == 0) clear_error(ec);# endif return result;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::ioctl(s, cmd, arg), ec);#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout, asio::error_code& ec){ clear_error(ec);#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 = asio::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(__HP_aCC) 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 defined(BOOST_WINDOWS) && defined(UNDER_CE) if (result >= 0) clear_error(ec);# endif return result;#endif}inline int poll_read(socket_type s, asio::error_code& ec){#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) FD_SET fds; FD_ZERO(&fds); FD_SET(s, &fds); clear_error(ec); int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);# if defined(UNDER_CE) if (result >= 0) clear_error(ec);# endif return result;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; fds.events = POLLIN; fds.revents = 0; clear_error(ec); return error_wrapper(::poll(&fds, 1, -1), ec);#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int poll_write(socket_type s, asio::error_code& ec){#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) FD_SET fds; FD_ZERO(&fds); FD_SET(s, &fds); clear_error(ec); int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);# if defined(UNDER_CE) if (result >= 0) clear_error(ec);# endif return result;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; fds.events = POLLOUT; fds.revents = 0; clear_error(ec); return error_wrapper(::poll(&fds, 1, -1), ec);#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, unsigned long scope_id, asio::error_code& ec){ clear_error(ec);#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) using namespace std; // For memcpy. if (af != AF_INET && af != AF_INET6) { ec = asio::error::address_family_not_supported; return 0; } sockaddr_storage_type address; DWORD address_length; if (af == AF_INET) { address_length = sizeof(sockaddr_in4_type); sockaddr_in4_type* ipv4_address = reinterpret_cast<sockaddr_in4_type*>(&address); ipv4_address->sin_family = AF_INET; ipv4_address->sin_port = 0; memcpy(&ipv4_address->sin_addr, src, sizeof(in4_addr_type)); } else // AF_INET6 { address_length = sizeof(sockaddr_in6_type); sockaddr_in6_type* ipv6_address = reinterpret_cast<sockaddr_in6_type*>(&address); ipv6_address->sin6_family = AF_INET6; ipv6_address->sin6_port = 0; ipv6_address->sin6_flowinfo = 0; ipv6_address->sin6_scope_id = scope_id; memcpy(&ipv6_address->sin6_addr, src, sizeof(in6_addr_type)); } DWORD string_length = static_cast<DWORD>(length);#if defined(BOOST_NO_ANSI_APIS) LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); int result = error_wrapper(::WSAAddressToStringW( reinterpret_cast<sockaddr*>(&address), address_length, 0, string_buffer, &string_length), ec); ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);#else int result = error_wrapper(::WSAAddressToStringA( reinterpret_cast<sockaddr*>(&address), address_length, 0, dest, &string_length), ec);#endif // Windows may set error code on success. if (result != socket_error_retval) clear_error(ec); // Windows may not set an error code on failure. else if (result == socket_error_retval && !ec) ec = asio::error::invalid_argument; return result == socket_error_retval ? 0 : dest;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); if (result == 0 && !ec) ec = asio::error::invalid_argument; if (result != 0 && af == AF_INET6 && scope_id != 0) { using namespace std; // For strcat and sprintf. char if_name[IF_NAMESIZE + 1] = "%"; const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src); bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) sprintf(if_name + 1, "%lu", scope_id); strcat(dest, if_name); } return result;#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int inet_pton(int af, const char* src, void* dest, unsigned long* scope_id, asio::error_code& ec){ clear_error(ec);#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) using namespace std; // For memcpy and strcmp. if (af != AF_INET && af != AF_INET6) { ec = asio::error::address_family_not_supported; return -1; } sockaddr_storage_type address; int address_length = sizeof(sockaddr_storage_type);#if defined(BOOST_NO_ANSI_APIS) int num_wide_chars = 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, reinterpret_cast<sockaddr*>(&address), &address_length), ec);#else int result = error_wrapper(::WSAStringToAddressA( const_cast<char*>(src), af, 0, reinterpret_cast<sockaddr*>(&address), &address_length), ec);#endif if (af == AF_INET) { if (result != socket_error_retval) { sockaddr_in4_type* ipv4_address = reinterpret_cast<sockaddr_in4_type*>(&address); memcpy(dest, &ipv4_address->sin_addr, sizeof(in4_addr_type)); clear_error(ec); } else if (strcmp(src, "255.255.255.255") == 0) { static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; clear_error(ec); } } else // AF_INET6 { if (result != socket_error_retval) { sockaddr_in6_type* ipv6_address = reinterpret_cast<sockaddr_in6_type*>(&address); memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr_type)); if (scope_id) *scope_id = ipv6_address->sin6_scope_id; clear_error(ec); } } // Windows may not set an error code on failure. if (result == socket_error_retval && !ec) ec = asio::error::invalid_argument;#if defined(UNDER_CE) if (result != socket_error_retval) clear_error(ec);#endif return result == socket_error_retval ? -1 : 1;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::inet_pton(af, src, dest), ec); if (result <= 0 && !ec) ec = asio::error::invalid_argument; if (result > 0 && af == AF_INET6 && scope_id) { using namespace std; // For strchr and atoi. *scope_id = 0; if (const char* if_name = strchr(src, '%')) { in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest); bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); if (is_link_local) *scope_id = if_nametoindex(if_name + 1); if (*scope_id == 0) *scope_id = atoi(if_name + 1); } } return result;#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int gethostname(char* name, int namelen, asio::error_code& ec){ clear_error(ec); int result = error_wrapper(::gethostname(name, namelen), ec);#if defined(BOOST_WINDOWS) && defined(UNDER_CE) if (result == 0) clear_error(ec);#endif return result;}#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ || defined(__MACH__) && defined(__APPLE__)// The following functions are only needed for emulation of getaddrinfo and// getnameinfo.inline asio::error_code translate_netdb_error(int error){ switch (error) { case 0: return asio::error_code(); case HOST_NOT_FOUND: return asio::error::host_not_found; case TRY_AGAIN: return asio::error::host_not_found_try_again; case NO_RECOVERY: return asio::error::no_recovery; case NO_DATA: return asio::error::no_data; default: BOOST_ASSERT(false); return asio::error::invalid_argument; }}inline hostent* gethostbyaddr(const char* addr, int length, int af, hostent* result, char* buffer, int buflength, asio::error_code& ec){ clear_error(ec);#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); if (!retval) return 0;# if defined(UNDER_CE) clear_error(ec);# endif *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); if (error) ec = translate_netdb_error(error); return retval;#elif defined(__MACH__) && defined(__APPLE__) (void)(buffer); (void)(buflength); int error = 0; hostent* retval = error_wrapper(::getipnodebyaddr( addr, length, af, &error), ec); if (error) ec = translate_netdb_error(error); if (!retval) return 0; *result = *retval; return retval;#else hostent* retval = 0; int error = 0; error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, buflength, &retval, &error), ec); if (error) ec = translate_netdb_error(error); return retval;#endif}inline hostent* gethostbyname(const char* name, int af, struct hostent* result, char* buffer, int buflength, int ai_flags, asio::error_code& ec){ clear_error(ec);#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -