📄 win_iocp_socket_service.hpp
字号:
//// win_iocp_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_WIN_IOCP_SOCKET_SERVICE_HPP#define ASIO_DETAIL_WIN_IOCP_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/win_iocp_io_service_fwd.hpp"#if defined(ASIO_HAS_IOCP)#include "asio/detail/push_options.hpp"#include <cstring>#include <boost/shared_ptr.hpp>#include <boost/weak_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/handler_alloc_helpers.hpp"#include "asio/detail/handler_invoke_helpers.hpp"#include "asio/detail/mutex.hpp"#include "asio/detail/select_reactor.hpp"#include "asio/detail/socket_holder.hpp"#include "asio/detail/socket_ops.hpp"#include "asio/detail/socket_types.hpp"#include "asio/detail/win_iocp_io_service.hpp"namespace asio {namespace detail {template <typename Protocol>class win_iocp_socket_service : public asio::detail::service_base<win_iocp_socket_service<Protocol> >{public: // The protocol type. typedef Protocol protocol_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; // Base class for all operations. typedef win_iocp_operation operation; struct noop_deleter { void operator()(void*) {} }; typedef boost::shared_ptr<void> shared_cancel_token_type; typedef boost::weak_ptr<void> weak_cancel_token_type; // The native type of a socket. class native_type { public: native_type(socket_type s) : socket_(s), have_remote_endpoint_(false) { } native_type(socket_type s, const endpoint_type& ep) : socket_(s), have_remote_endpoint_(true), remote_endpoint_(ep) { } void operator=(socket_type s) { socket_ = s; have_remote_endpoint_ = false; remote_endpoint_ = endpoint_type(); } operator socket_type() const { return socket_; } HANDLE as_handle() const { return reinterpret_cast<HANDLE>(socket_); } bool have_remote_endpoint() const { return have_remote_endpoint_; } endpoint_type remote_endpoint() const { return remote_endpoint_; } private: socket_type socket_; bool have_remote_endpoint_; endpoint_type remote_endpoint_; }; // The implementation type of the socket. class implementation_type { public: // Default constructor. implementation_type() : socket_(invalid_socket), flags_(0), cancel_token_(), protocol_(endpoint_type().protocol()), next_(0), prev_(0) { } private: // Only this service will have access to the internal values. friend class win_iocp_socket_service; // The native socket representation. native_type socket_; enum { enable_connection_aborted = 1, // User wants connection_aborted errors. close_might_block = 2, // User set linger option for blocking close. user_set_non_blocking = 4 // The user wants a non-blocking socket. }; // Flags indicating the current state of the socket. unsigned char flags_; // We use a shared pointer as a cancellation token here to work around the // broken Windows support for cancellation. MSDN says that when you call // closesocket any outstanding WSARecv or WSASend operations will complete // with the error ERROR_OPERATION_ABORTED. In practice they complete with // ERROR_NETNAME_DELETED, which means you can't tell the difference between // a local cancellation and the socket being hard-closed by the peer. shared_cancel_token_type cancel_token_; // The protocol associated with the socket. protocol_type protocol_; // The ID of the thread from which it is safe to cancel asynchronous // operations. 0 means no asynchronous operations have been started yet. // ~0 means asynchronous operations have been started from more than one // thread, and cancellation is not supported for the socket. DWORD safe_cancellation_thread_id_; // Pointers to adjacent socket implementations in linked list. implementation_type* next_; implementation_type* prev_; }; // The type of the reactor used for connect operations. typedef detail::select_reactor<true> reactor_type; // The maximum number of buffers to support in a single operation. enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; // Constructor. win_iocp_socket_service(asio::io_service& io_service) : asio::detail::service_base< win_iocp_socket_service<Protocol> >(io_service), iocp_service_(asio::use_service<win_iocp_io_service>(io_service)), reactor_(0), mutex_(), impl_list_(0) { } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { // Close all implementations, causing all operations to complete. asio::detail::mutex::scoped_lock lock(mutex_); implementation_type* impl = impl_list_; while (impl) { asio::error_code ignored_ec; close_for_destruction(*impl); impl = impl->next_; } } // Construct a new socket implementation. void construct(implementation_type& impl) { impl.socket_ = invalid_socket; impl.flags_ = 0; impl.cancel_token_.reset(); impl.safe_cancellation_thread_id_ = 0; // Insert implementation into linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); impl.next_ = impl_list_; impl.prev_ = 0; if (impl_list_) impl_list_->prev_ = &impl; impl_list_ = &impl; } // Destroy a socket implementation. void destroy(implementation_type& impl) { close_for_destruction(impl); // Remove implementation from linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); if (impl_list_ == &impl) impl_list_ = impl.next_; if (impl.prev_) impl.prev_->next_ = impl.next_; if (impl.next_) impl.next_->prev_= impl.prev_; impl.next_ = 0; impl.prev_ = 0; } // 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; HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get()); iocp_service_.register_handle(sock_as_handle); impl.socket_ = sock.release(); impl.flags_ = 0; impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter()); 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; } iocp_service_.register_handle(native_socket.as_handle()); impl.socket_ = native_socket; impl.flags_ = 0; impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter()); 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)) { // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. reactor_type* reactor = static_cast<reactor_type*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (reactor) reactor->close_descriptor(impl.socket_); if (socket_ops::close(impl.socket_, ec) == socket_error_retval) return ec; impl.socket_ = invalid_socket; impl.flags_ = 0; impl.cancel_token_.reset(); impl.safe_cancellation_thread_id_ = 0; } 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; } else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) { // The version of Windows supports cancellation from any thread. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; socket_type sock = impl.socket_; HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); if (!cancel_io_ex(sock_as_handle, 0)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); } else { ec = asio::error_code(); } } else if (impl.safe_cancellation_thread_id_ == 0) { // No operations have been started, so there's nothing to cancel. ec = asio::error_code(); } else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) { // Asynchronous operations have been started from the current thread only, // so it is safe to try to cancel them using CancelIo. socket_type sock = impl.socket_; HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock); if (!::CancelIo(sock_as_handle)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); } else { ec = asio::error_code(); } } else { // Asynchronous operations have been started from more than one thread, // so cancellation is not safe. ec = asio::error::operation_not_supported; } 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); 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); return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -