📄 win_iocp_socket_service.hpp
字号:
// 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) { const ::linger* linger_option = reinterpret_cast<const ::linger*>(option.data(impl.protocol_)); if (linger_option->l_onoff != 0 && linger_option->l_linger != 0) impl.flags_ |= implementation_type::close_might_block; else impl.flags_ &= ~implementation_type::close_might_block; } socket_ops::setsockopt(impl.socket_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec); 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_)); if (impl.flags_ & implementation_type::enable_connection_aborted) *target = 1; else *target = 0; option.resize(impl.protocol_, sizeof(int)); ec = asio::error_code(); } return ec; } else { size_t size = option.size(impl.protocol_); socket_ops::getsockopt(impl.socket_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), &size, ec); if (!ec) option.resize(impl.protocol_, size); return ec; } } // Perform an IO control command on the socket. template <typename IO_Control_Command> asio::error_code io_control(implementation_type& impl, IO_Control_Command& command, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } socket_ops::ioctl(impl.socket_, command.name(), static_cast<ioctl_arg_type*>(command.data()), ec); if (!ec && command.name() == static_cast<int>(FIONBIO)) { if (command.get()) impl.flags_ |= implementation_type::user_set_non_blocking; else impl.flags_ &= ~implementation_type::user_set_non_blocking; } return ec; } // Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return endpoint_type(); } endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } // Get the remote endpoint. endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return endpoint_type(); } if (impl.socket_.have_remote_endpoint()) { // Check if socket is still connected. DWORD connect_time = 0; size_t connect_time_len = sizeof(connect_time); if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME, &connect_time, &connect_time_len, ec) == socket_error_retval) { return endpoint_type(); } if (connect_time == 0xFFFFFFFF) { ec = asio::error::not_connected; return endpoint_type(); } ec = asio::error_code(); return impl.socket_.remote_endpoint(); } else { endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } } /// Disable sends or receives on the socket. asio::error_code shutdown(implementation_type& impl, socket_base::shutdown_type what, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } socket_ops::shutdown(impl.socket_, what, ec); return ec; } // Send the given data to the peer. Returns the number of bytes sent. template <typename ConstBufferSequence> size_t send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return 0; } // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; typename ConstBufferSequence::const_iterator iter = buffers.begin(); typename ConstBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { asio::const_buffer buffer(*iter); bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer)); bufs[i].buf = const_cast<char*>( asio::buffer_cast<const char*>(buffer)); total_buffer_size += asio::buffer_size(buffer); } // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { ec = asio::error_code(); return 0; } // Send the data. DWORD bytes_transferred = 0; int result = ::WSASend(impl.socket_, bufs, i, &bytes_transferred, flags, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_NETNAME_DELETED) last_error = WSAECONNRESET; else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, asio::error::get_system_category()); return 0; } ec = asio::error_code(); return bytes_transferred; } template <typename ConstBufferSequence, typename Handler> class send_operation : public operation { public: send_operation(asio::io_service& io_service, weak_cancel_token_type cancel_token, const ConstBufferSequence& buffers, Handler handler) : operation( &send_operation<ConstBufferSequence, Handler>::do_completion_impl, &send_operation<ConstBufferSequence, Handler>::destroy_impl), work_(io_service), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } private: static void do_completion_impl(operation* op, DWORD last_error, size_t bytes_transferred) { // Take ownership of the operation object. typedef send_operation<ConstBufferSequence, Handler> op_type; op_type* handler_op(static_cast<op_type*>(op)); typedef handler_alloc_traits<Handler, op_type> alloc_traits; handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. typename ConstBufferSequence::const_iterator iter = handler_op->buffers_.begin(); typename ConstBufferSequence::const_iterator end = handler_op->buffers_.end(); while (iter != end) { asio::const_buffer buffer(*iter); asio::buffer_cast<const char*>(buffer); ++iter; }#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, asio::error::get_system_category()); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) ec = asio::error::operation_aborted; else ec = asio::error::connection_reset; } else if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; } // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Handler handler(handler_op->handler_); // Free the memory associated with the handler. ptr.reset(); // Call the handler. asio_handler_invoke_helpers::invoke( detail::bind_handler(handler, ec, bytes_transferred), &handler); } static void destroy_impl(operation* op) { // Take ownership of the operation object. typedef send_operation<ConstBufferSequence, Handler> op_type; op_type* handler_op(static_cast<op_type*>(op)); typedef handler_alloc_traits<Handler, op_type> alloc_traits; handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op); } asio::io_service::work work_; weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; }; // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { if (!is_open(impl)) { this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); return; } // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Allocate and construct an operation to wrap the handler. typedef send_operation<ConstBufferSequence, Handler> value_type; typedef handler_alloc_traits<Handler, value_type> alloc_traits; raw_handler_ptr<alloc_traits> raw_ptr(handler); handler_ptr<alloc_traits> ptr(raw_ptr, this->get_io_service(), impl.cancel_token_, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; typename ConstBufferSequence::const_iterator iter = buffers.begin(); typename ConstBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { asio::const_buffer buffer(*iter); bufs[i].len = static_cast<u_long>(asio::buffer_size(buffer)); bufs[i].buf = const_cast<char*>( asio::buffer_cast<const char*>(buffer)); total_buffer_size += asio::buffer_size(buffer); } // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); return; } // Send the data. DWORD bytes_transferred = 0; int result = ::WSASend(impl.socket_, bufs, i, &bytes_transferred, flags, ptr.get(), 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -