summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/include/asio/detail/impl/win_iocp_socket_service_base.ipp
diff options
context:
space:
mode:
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.ipp140
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)
{