📄 socket_ops.hpp
字号:
//// socket_ops.hpp// ~~~~~~~~~~~~~~//// Copyright (c) 2003-2007 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 ASIO_DETAIL_SOCKET_OPS_HPP#define ASIO_DETAIL_SOCKET_OPS_HPP#if defined(_MSC_VER) && (_MSC_VER >= 1200)# pragma once#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)#include "asio/detail/push_options.hpp"#include "asio/detail/push_options.hpp"#include <boost/config.hpp>#include <boost/assert.hpp>#include <cstdio>#include <cstdlib>#include <cstring>#include <cerrno>#include <boost/detail/workaround.hpp>#include <new>#include "asio/detail/pop_options.hpp"#include "asio/error.hpp"#include "asio/detail/socket_types.hpp"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_error(asio::error_code& ec){#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) WSASetLastError(0);#else errno = 0;#endif ec = asio::error_code();}template <typename ReturnType>inline ReturnType error_wrapper(ReturnType return_value, asio::error_code& ec){#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) ec = asio::error_code(WSAGetLastError(), asio::error::get_system_category());#else ec = asio::error_code(errno, 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;}inline socket_type accept(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec){ clear_error(ec); 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#if defined(BOOST_WINDOWS) && defined(UNDER_CE) clear_error(ec);#endif return new_s;}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);}inline int bind(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec){ clear_error(ec); int result = error_wrapper(call_bind( &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 close(socket_type s, asio::error_code& ec){ clear_error(ec);#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::closesocket(s), ec);# if defined(UNDER_CE) if (result == 0) clear_error(ec);# endif return result;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::close(s), ec);#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int shutdown(socket_type s, int what, asio::error_code& ec){ clear_error(ec); int result = error_wrapper(::shutdown(s, what), ec);#if defined(BOOST_WINDOWS) && defined(UNDER_CE) if (result == 0) clear_error(ec);#endif 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);}inline int connect(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec){ clear_error(ec); int result = error_wrapper(call_connect( &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 listen(socket_type s, int backlog, asio::error_code& ec){ clear_error(ec); int result = error_wrapper(::listen(s, backlog), ec);#if defined(BOOST_WINDOWS) && defined(UNDER_CE) if (result == 0) clear_error(ec);#endif return result;}#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)typedef WSABUF buf;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)typedef iovec buf;#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)inline 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__) b.iov_base = data; b.iov_len = size;#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline 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__) 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));}inline int recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec){ clear_error(ec);#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 (result != 0) return -1;# if defined(UNDER_CE) clear_error(ec);# endif return bytes_transferred;#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = count; return error_wrapper(::recvmsg(s, &msg, flags), ec);#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec){ clear_error(ec);#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 (result != 0) return -1;# if defined(UNDER_CE) clear_error(ec);# endif 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; return result;#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec){ clear_error(ec);#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 (result != 0) return -1;# if defined(UNDER_CE) clear_error(ec);# endif 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__) return error_wrapper(::sendmsg(s, &msg, flags), ec);#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline int 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_error(ec);#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 (result != 0) return -1;# if defined(UNDER_CE) clear_error(ec);# endif 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__) return error_wrapper(::sendmsg(s, &msg, flags), ec);#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)}inline socket_type socket(int af, int type, int protocol, asio::error_code& ec){ clear_error(ec);#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)); }# if defined(UNDER_CE) clear_error(ec);# endif 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 return error_wrapper(::socket(af, type, protocol), ec);#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);}inline int setsockopt(socket_type s, int level, int optname, const void* optval, std::size_t optlen, asio::error_code& ec){ if (level == custom_socket_option_level && optname == always_fail_option) { ec = asio::error::invalid_argument; return -1; }#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_error(ec); return error_wrapper(sso(s, level, optname, reinterpret_cast<const char*>(optval), static_cast<int>(optlen)), ec); } } ec = asio::error::fault; return -1;#else // defined(__BORLANDC__) clear_error(ec); int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen), ec);# if defined(BOOST_WINDOWS) && defined(UNDER_CE) if (result == 0) clear_error(ec);# 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;}inline int getsockopt(socket_type s, int level, int optname, void* optval, size_t* optlen, asio::error_code& ec){ if (level == custom_socket_option_level && optname == always_fail_option) { ec = asio::error::invalid_argument; return -1; }#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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -