📄 win_iocp_socket_service.hpp
字号:
{ if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return 0; } // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { boost::asio::mutable_buffer buffer(*iter); bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer)); bufs[i].buf = boost::asio::buffer_cast<char*>(buffer); total_buffer_size += boost::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 = boost::system::error_code(); return 0; } // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecv(impl.socket_, bufs, i, &bytes_transferred, &recv_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 = boost::system::error_code(last_error, boost::asio::error::get_system_category()); return 0; } if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) { ec = boost::asio::error::eof; return 0; } ec = boost::system::error_code(); return bytes_transferred; } // Wait until data can be received without blocking. size_t receive(implementation_type& impl, const null_buffers&, socket_base::message_flags, boost::system::error_code& ec) { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return 0; } // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); return 0; } template <typename MutableBufferSequence, typename Handler> class receive_operation : public operation { public: receive_operation(int protocol_type, win_iocp_io_service& io_service, weak_cancel_token_type cancel_token, const MutableBufferSequence& buffers, Handler handler) : operation(io_service, &receive_operation< MutableBufferSequence, Handler>::do_completion_impl, &receive_operation< MutableBufferSequence, Handler>::destroy_impl), protocol_type_(protocol_type), work_(io_service.get_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 receive_operation<MutableBufferSequence, 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(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. typename MutableBufferSequence::const_iterator iter = handler_op->buffers_.begin(); typename MutableBufferSequence::const_iterator end = handler_op->buffers_.end(); while (iter != end) { boost::asio::mutable_buffer buffer(*iter); boost::asio::buffer_cast<char*>(buffer); ++iter; }#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. boost::system::error_code ec(last_error, boost::asio::error::get_system_category()); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) ec = boost::asio::error::operation_aborted; else ec = boost::asio::error::connection_reset; } else if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = boost::asio::error::connection_refused; } // Check for connection closed. else if (!ec && bytes_transferred == 0 && handler_op->protocol_type_ == SOCK_STREAM && !boost::is_same<MutableBufferSequence, null_buffers>::value) { ec = boost::asio::error::eof; } // 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. boost_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 receive_operation<MutableBufferSequence, 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); // A sub-object of the handler may be the true owner of the memory // associated with the handler. Consequently, a local copy of the handler // is required to ensure that any owning sub-object remains valid until // after we have deallocated the memory here. Handler handler(handler_op->handler_); (void)handler; // Free the memory associated with the handler. ptr.reset(); } int protocol_type_; boost::asio::io_service::work work_; weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; }; // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. template <typename MutableBufferSequence, typename Handler> void async_receive(implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { if (!is_open(impl)) { this->get_io_service().post(bind_handler(handler, boost::asio::error::bad_descriptor, 0)); return; }#if defined(BOOST_ASIO_ENABLE_CANCELIO) // 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);#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) // Allocate and construct an operation to wrap the handler. typedef receive_operation<MutableBufferSequence, Handler> value_type; typedef handler_alloc_traits<Handler, value_type> alloc_traits; raw_handler_ptr<alloc_traits> raw_ptr(handler); int protocol_type = impl.protocol_.type(); handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type, iocp_service_, impl.cancel_token_, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { boost::asio::mutable_buffer buffer(*iter); bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer)); bufs[i].buf = boost::asio::buffer_cast<char*>(buffer); total_buffer_size += boost::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) { boost::asio::io_service::work work(this->get_io_service()); ptr.reset(); boost::system::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); return; } // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecv(impl.socket_, bufs, i, &bytes_transferred, &recv_flags, ptr.get(), 0); DWORD last_error = ::WSAGetLastError(); if (result != 0 && last_error != WSA_IO_PENDING) { boost::asio::io_service::work work(this->get_io_service()); ptr.reset(); boost::system::error_code ec(last_error, boost::asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { ptr.release(); } } // Wait until data can be received without blocking. template <typename Handler> void async_receive(implementation_type& impl, const null_buffers& buffers, socket_base::message_flags flags, Handler handler) { if (!is_open(impl)) { this->get_io_service().post(bind_handler(handler, boost::asio::error::bad_descriptor, 0)); } else if (impl.protocol_.type() == SOCK_STREAM) { // For stream sockets on Windows, we may issue a 0-byte overlapped // WSARecv to wait until there is data available on the socket.#if defined(BOOST_ASIO_ENABLE_CANCELIO) // 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);#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) // Allocate and construct an operation to wrap the handler. typedef receive_operation<null_buffers, Handler> value_type; typedef handler_alloc_traits<Handler, value_type> alloc_traits; raw_handler_ptr<alloc_traits> raw_ptr(handler); int protocol_type = impl.protocol_.type(); handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type, iocp_service_, impl.cancel_token_, buffers, handler); // Issue a receive operation with an empty buffer. ::WSABUF buf = { 0, 0 }; DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecv(impl.socket_, &buf, 1, &bytes_transferred, &recv_flags, ptr.get(), 0); DWORD last_error = ::WSAGetLastError(); if (result != 0 && last_error != WSA_IO_PENDING) { boost::asio::io_service::work work(this->get_io_service()); ptr.reset(); boost::system::error_code ec(last_error, boost::asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { ptr.release(); } } else { // Check if the reactor was already obtained from the io_service. reactor_type* reactor = static_cast<reactor_type*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (!reactor) { reactor = &(boost::asio::use_service<reactor_type>( this->get_io_service())); interlocked_exchange_pointer( reinterpret_cast<void**>(&reactor_), reactor); } if (flags & socket_base::message_out_of_band) { reactor->start_except_op(impl.socket_, impl.reactor_data_, null_buffers_operation<Handler>(this->get_io_service(), handler)); } else { reactor->start_read_op(impl.socket_, impl.reactor_data_, null_buffers_operation<Handler>(this->get_io_service(), handler), false); } } } // Receive a datagram with the endpoint of the sender. Returns the number of // bytes received. template <typename MutableBufferSequence> size_t receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, boost::system::error_code& ec) { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return 0; } // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { boost::asio::mutable_buffer buffer(*iter); bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer)); bufs[i].buf = boost::asio::buffer_cast<char*>(buffer); } // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; int endpoint_size = static_cast<int>(sender_endpoint.capacity()); int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred, &recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = boost::system::error_code(last_error, boost::asio::error::get_system_category()); return 0; } if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) { ec = boost::asio::error::eof; return 0; } sender_endpoint.resize(static_cast<std::size_t>(endpoint_size)); ec = boost::system::error_code(); return bytes_transferred; } // Wait until data can be received without blocking. size_t receive_from(implementation_type& impl, const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags, boost::system::error_code& ec) { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return 0; } // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -