diff options
Diffstat (limited to '3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp')
-rw-r--r-- | 3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp | 140 |
1 files changed, 112 insertions, 28 deletions
diff --git a/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp b/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp index 4230f5c586a..6adcf7e558b 100644 --- a/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp +++ b/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -2,7 +2,7 @@ // detail/impl/win_iocp_socket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2021 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) @@ -27,11 +27,12 @@ namespace asio { namespace detail { win_iocp_socket_service_base::win_iocp_socket_service_base( - asio::io_context& io_context) - : io_context_(io_context), - iocp_service_(use_service<win_iocp_io_context>(io_context)), + execution_context& context) + : context_(context), + iocp_service_(use_service<win_iocp_io_context>(context)), reactor_(0), connect_ex_(0), + nt_set_info_(0), mutex_(), impl_list_(0) { @@ -44,7 +45,6 @@ void win_iocp_socket_service_base::base_shutdown() base_implementation_type* impl = impl_list_; while (impl) { - asio::error_code ignored_ec; close_for_destruction(*impl); impl = impl->next_; } @@ -72,6 +72,7 @@ void win_iocp_socket_service_base::construct( void win_iocp_socket_service_base::base_move_construct( win_iocp_socket_service_base::base_implementation_type& impl, win_iocp_socket_service_base::base_implementation_type& other_impl) + ASIO_NOEXCEPT { impl.socket_ = other_impl.socket_; other_impl.socket_ = invalid_socket; @@ -177,9 +178,16 @@ asio::error_code win_iocp_socket_service_base::close( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); - } - socket_ops::close(impl.socket_, impl.state_, false, ec); + socket_ops::close(impl.socket_, impl.state_, false, ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = asio::error_code(); + } impl.socket_ = invalid_socket; impl.state_ = 0; @@ -191,6 +199,39 @@ asio::error_code win_iocp_socket_service_base::close( return ec; } +socket_type win_iocp_socket_service_base::release( + win_iocp_socket_service_base::base_implementation_type& impl, + asio::error_code& ec) +{ + if (!is_open(impl)) + return invalid_socket; + + cancel(impl, ec); + if (ec) + return invalid_socket; + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_); + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(sock_as_handle, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = asio::error::operation_not_supported; + return invalid_socket; + } + + socket_type tmp = impl.socket_; + impl.socket_ = invalid_socket; + return tmp; +} + asio::error_code win_iocp_socket_service_base::cancel( win_iocp_socket_service_base::base_implementation_type& impl, asio::error_code& ec) @@ -209,7 +250,8 @@ asio::error_code win_iocp_socket_service_base::cancel( { // 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; + cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>( + reinterpret_cast<void*>(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)) @@ -424,23 +466,24 @@ void win_iocp_socket_service_base::start_receive_op( } } -void win_iocp_socket_service_base::start_null_buffers_receive_op( +int win_iocp_socket_service_base::start_null_buffers_receive_op( win_iocp_socket_service_base::base_implementation_type& impl, - socket_base::message_flags flags, reactor_op* op) + socket_base::message_flags flags, reactor_op* op, operation* iocp_op) { if ((impl.state_ & socket_ops::stream_oriented) != 0) { // For stream sockets on Windows, we may issue a 0-byte overlapped // WSARecv to wait until there is data available on the socket. ::WSABUF buf = { 0, 0 }; - start_receive_op(impl, &buf, 1, flags, false, op); + start_receive_op(impl, &buf, 1, flags, false, iocp_op); + return -1; } else { - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? select_reactor::except_op : select_reactor::read_op, - op); + int op_type = (flags & socket_base::message_out_of_band) + ? select_reactor::except_op : select_reactor::read_op; + start_reactor_op(impl, op_type, op); + return op_type; } } @@ -505,11 +548,17 @@ void win_iocp_socket_service_base::start_accept_op( void win_iocp_socket_service_base::restart_accept_op( socket_type s, socket_holder& new_socket, int family, int type, - int protocol, void* output_buffer, DWORD address_length, operation* op) + int protocol, void* output_buffer, DWORD address_length, + long* cancel_requested, operation* op) { new_socket.reset(); iocp_service_.work_started(); + // Check if we were cancelled after the first AcceptEx completed. + if (cancel_requested) + if (::InterlockedExchangeAdd(cancel_requested, 0) == 1) + iocp_service_.on_completion(op, asio::error::operation_aborted); + asio::error_code ec; new_socket.reset(socket_ops::socket(family, type, protocol, ec)); if (new_socket.get() == invalid_socket) @@ -523,7 +572,19 @@ void win_iocp_socket_service_base::restart_accept_op( if (!result && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error); else + { +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + if (cancel_requested) + { + if (::InterlockedExchangeAdd(cancel_requested, 0) == 1) + { + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(s); + ::CancelIoEx(sock_as_handle, op); + } + } +#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) iocp_service_.on_pending(op); + } } } @@ -545,10 +606,10 @@ void win_iocp_socket_service_base::start_reactor_op( iocp_service_.post_immediate_completion(op, false); } -void win_iocp_socket_service_base::start_connect_op( +int win_iocp_socket_service_base::start_connect_op( win_iocp_socket_service_base::base_implementation_type& impl, - int family, int type, const socket_addr_type* addr, - std::size_t addrlen, win_iocp_socket_connect_op_base* op) + int family, int type, const socket_addr_type* addr, std::size_t addrlen, + win_iocp_socket_connect_op_base* op, operation* iocp_op) { // If ConnectEx is available, use that. if (family == ASIO_OS_DEF(AF_INET) @@ -573,7 +634,7 @@ void win_iocp_socket_service_base::start_connect_op( if (op->ec_ && op->ec_ != asio::error::invalid_argument) { iocp_service_.post_immediate_completion(op, false); - return; + return -1; } op->connect_ex_ = true; @@ -581,13 +642,13 @@ void win_iocp_socket_service_base::start_connect_op( iocp_service_.work_started(); BOOL result = connect_ex(impl.socket_, - addr, static_cast<int>(addrlen), 0, 0, 0, op); + addr, static_cast<int>(addrlen), 0, 0, 0, iocp_op); DWORD last_error = ::WSAGetLastError(); if (!result && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error); + iocp_service_.on_completion(iocp_op, last_error); else - iocp_service_.on_pending(op); - return; + iocp_service_.on_pending(iocp_op); + return -1; } } @@ -607,12 +668,13 @@ void win_iocp_socket_service_base::start_connect_op( op->ec_ = asio::error_code(); r.start_op(select_reactor::connect_op, impl.socket_, impl.reactor_data_, op, false, false); - return; + return select_reactor::connect_op; } } } r.post_immediate_completion(op, false); + return -1; } void win_iocp_socket_service_base::close_for_destruction( @@ -631,10 +693,14 @@ void win_iocp_socket_service_base::close_for_destruction( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); } - asio::error_code ignored_ec; - socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); impl.socket_ = invalid_socket; impl.state_ = 0; impl.cancel_token_.reset(); @@ -663,7 +729,7 @@ select_reactor& win_iocp_socket_service_base::get_reactor() reinterpret_cast<void**>(&reactor_), 0, 0)); if (!r) { - r = &(use_service<select_reactor>(io_context_)); + r = &(use_service<select_reactor>(context_)); interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r); } return *r; @@ -704,6 +770,24 @@ win_iocp_socket_service_base::get_connect_ex( #endif // defined(ASIO_DISABLE_CONNECTEX) } +win_iocp_socket_service_base::nt_set_info_fn +win_iocp_socket_service_base::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr); +} + void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( void** dest, void* exch, void* cmp) { |