📄 reactive_socket_service.hpp
字号:
//// reactive_socket_service.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_REACTIVE_SOCKET_SERVICE_HPP#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_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/shared_ptr.hpp>#include "asio/detail/pop_options.hpp"#include "asio/buffer.hpp"#include "asio/error.hpp"#include "asio/io_service.hpp"#include "asio/socket_base.hpp"#include "asio/detail/bind_handler.hpp"#include "asio/detail/noncopyable.hpp"#include "asio/detail/service_base.hpp"#include "asio/detail/socket_holder.hpp"#include "asio/detail/socket_ops.hpp"#include "asio/detail/socket_types.hpp"namespace asio {namespace detail {template <typename Protocol, typename Reactor>class reactive_socket_service : public asio::detail::service_base< reactive_socket_service<Protocol, Reactor> >{public: // The protocol type. typedef Protocol protocol_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; // The native type of a socket. typedef socket_type native_type; // The implementation type of the socket. class implementation_type : private asio::detail::noncopyable { public: // Default constructor. implementation_type() : socket_(invalid_socket), flags_(0), protocol_(endpoint_type().protocol()) { } private: // Only this service will have access to the internal values. friend class reactive_socket_service<Protocol, Reactor>; // The native socket representation. socket_type socket_; enum { user_set_non_blocking = 1, // The user wants a non-blocking socket. internal_non_blocking = 2, // The socket has been set non-blocking. enable_connection_aborted = 4, // User wants connection_aborted errors. user_set_linger = 8 // The user set the linger option. }; // Flags indicating the current state of the socket. unsigned char flags_; // The protocol associated with the socket. protocol_type protocol_; }; // The maximum number of buffers to support in a single operation. enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; // Constructor. reactive_socket_service(asio::io_service& io_service) : asio::detail::service_base< reactive_socket_service<Protocol, Reactor> >(io_service), reactor_(asio::use_service<Reactor>(io_service)) { } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { } // Construct a new socket implementation. void construct(implementation_type& impl) { impl.socket_ = invalid_socket; impl.flags_ = 0; } // Destroy a socket implementation. void destroy(implementation_type& impl) { if (impl.socket_ != invalid_socket) { reactor_.close_descriptor(impl.socket_); if (impl.flags_ & implementation_type::internal_non_blocking) { ioctl_arg_type non_blocking = 0; asio::error_code ignored_ec; socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); impl.flags_ &= ~implementation_type::internal_non_blocking; } if (impl.flags_ & implementation_type::user_set_linger) { ::linger opt; opt.l_onoff = 0; opt.l_linger = 0; asio::error_code ignored_ec; socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); } asio::error_code ignored_ec; socket_ops::close(impl.socket_, ignored_ec); impl.socket_ = invalid_socket; } } // Open a new socket implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(), protocol.protocol(), ec)); if (sock.get() == invalid_socket) return ec; if (int err = reactor_.register_descriptor(sock.get())) { ec = asio::error_code(err, asio::error::get_system_category()); return ec; } impl.socket_ = sock.release(); impl.flags_ = 0; impl.protocol_ = protocol; ec = asio::error_code(); return ec; } // Assign a native socket to a socket implementation. asio::error_code assign(implementation_type& impl, const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } if (int err = reactor_.register_descriptor(native_socket)) { ec = asio::error_code(err, asio::error::get_system_category()); return ec; } impl.socket_ = native_socket; impl.flags_ = 0; impl.protocol_ = protocol; ec = asio::error_code(); return ec; } // Determine whether the socket is open. bool is_open(const implementation_type& impl) const { return impl.socket_ != invalid_socket; } // Destroy a socket implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { if (is_open(impl)) { reactor_.close_descriptor(impl.socket_); if (impl.flags_ & implementation_type::internal_non_blocking) { ioctl_arg_type non_blocking = 0; asio::error_code ignored_ec; socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); impl.flags_ &= ~implementation_type::internal_non_blocking; } if (socket_ops::close(impl.socket_, ec) == socket_error_retval) return ec; impl.socket_ = invalid_socket; } ec = asio::error_code(); return ec; } // Get the native socket representation. native_type native(implementation_type& impl) { return impl.socket_; } // Cancel all operations associated with the socket. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } reactor_.cancel_ops(impl.socket_); ec = asio::error_code(); return ec; } // Determine whether the socket is at the out-of-band data mark. bool at_mark(const implementation_type& impl, asio::error_code& ec) const { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return false; } asio::detail::ioctl_arg_type value = 0; socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);#if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket;#endif // defined(ENOTTY) return ec ? false : value != 0; } // Determine the number of bytes available for reading. std::size_t available(const implementation_type& impl, asio::error_code& ec) const { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return 0; } asio::detail::ioctl_arg_type value = 0; socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);#if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket;#endif // defined(ENOTTY) return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value); } // Bind the socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } // Place the socket into the state where it will listen for new connections. asio::error_code listen(implementation_type& impl, int backlog, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } socket_ops::listen(impl.socket_, backlog, ec); return ec; } // Set a socket option. template <typename Option> asio::error_code set_option(implementation_type& impl, const Option& option, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } if (option.level(impl.protocol_) == custom_socket_option_level && option.name(impl.protocol_) == enable_connection_aborted_option) { if (option.size(impl.protocol_) != sizeof(int)) { ec = asio::error::invalid_argument; } else { if (*reinterpret_cast<const int*>(option.data(impl.protocol_))) impl.flags_ |= implementation_type::enable_connection_aborted; else impl.flags_ &= ~implementation_type::enable_connection_aborted; ec = asio::error_code(); } return ec; } else { if (option.level(impl.protocol_) == SOL_SOCKET && option.name(impl.protocol_) == SO_LINGER) { impl.flags_ |= implementation_type::user_set_linger; } socket_ops::setsockopt(impl.socket_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec);#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 (!ec && impl.protocol_.type() == SOCK_DGRAM && option.level(impl.protocol_) == SOL_SOCKET && option.name(impl.protocol_) == SO_REUSEADDR) { asio::error_code ignored_ec; socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT, option.data(impl.protocol_), option.size(impl.protocol_), ignored_ec); }#endif return ec; } } // Set a socket option. template <typename Option> asio::error_code get_option(const implementation_type& impl, Option& option, asio::error_code& ec) const { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } if (option.level(impl.protocol_) == custom_socket_option_level && option.name(impl.protocol_) == enable_connection_aborted_option) { if (option.size(impl.protocol_) != sizeof(int)) { ec = asio::error::invalid_argument; } else { int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -