Add ability to release ownership of the underlying native socket.
This commit adds release() member functions to basic_socket and basic_socket_acceptor. Note: When using I/O completion ports on Windows, these functions fail with error::operation_not_supported for versions of Windows prior to Windows 8.1.
This commit is contained in:
parent
d28ec54750
commit
d3ca90a05c
@ -449,6 +449,58 @@ public:
|
||||
ASIO_SYNC_OP_VOID_RETURN(ec);
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying native socket.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous connect, send and receive
|
||||
* operations to finish immediately, and the handlers for cancelled operations
|
||||
* will be passed the asio::error::operation_aborted error. Ownership
|
||||
* of the native socket is then transferred to the caller.
|
||||
*
|
||||
* @throws asio::system_error Thrown on failure.
|
||||
*
|
||||
* @note This function is unsupported on Windows versions prior to Windows
|
||||
* 8.1, and will fail with asio::error::operation_not_supported on
|
||||
* these platforms.
|
||||
*/
|
||||
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
|
||||
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
|
||||
__declspec(deprecated("This function always fails with "
|
||||
"operation_not_supported when used on Windows versions "
|
||||
"prior to Windows 8.1."))
|
||||
#endif
|
||||
native_handle_type release()
|
||||
{
|
||||
asio::error_code ec;
|
||||
native_handle_type s = this->get_service().release(
|
||||
this->get_implementation(), ec);
|
||||
asio::detail::throw_error(ec, "release");
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying native socket.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous connect, send and receive
|
||||
* operations to finish immediately, and the handlers for cancelled operations
|
||||
* will be passed the asio::error::operation_aborted error. Ownership
|
||||
* of the native socket is then transferred to the caller.
|
||||
*
|
||||
* @param ec Set to indicate what error occurred, if any.
|
||||
*
|
||||
* @note This function is unsupported on Windows versions prior to Windows
|
||||
* 8.1, and will fail with asio::error::operation_not_supported on
|
||||
* these platforms.
|
||||
*/
|
||||
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
|
||||
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
|
||||
__declspec(deprecated("This function always fails with "
|
||||
"operation_not_supported when used on Windows versions "
|
||||
"prior to Windows 8.1."))
|
||||
#endif
|
||||
native_handle_type release(asio::error_code& ec)
|
||||
{
|
||||
return this->get_service().release(this->get_implementation(), ec);
|
||||
}
|
||||
|
||||
/// Get the native socket representation.
|
||||
/**
|
||||
* This function may be used to obtain the underlying representation of the
|
||||
|
@ -566,6 +566,58 @@ public:
|
||||
ASIO_SYNC_OP_VOID_RETURN(ec);
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying native acceptor.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous accept operations to
|
||||
* finish immediately, and the handlers for cancelled operations will be
|
||||
* passed the asio::error::operation_aborted error. Ownership of the
|
||||
* native acceptor is then transferred to the caller.
|
||||
*
|
||||
* @throws asio::system_error Thrown on failure.
|
||||
*
|
||||
* @note This function is unsupported on Windows versions prior to Windows
|
||||
* 8.1, and will fail with asio::error::operation_not_supported on
|
||||
* these platforms.
|
||||
*/
|
||||
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
|
||||
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
|
||||
__declspec(deprecated("This function always fails with "
|
||||
"operation_not_supported when used on Windows versions "
|
||||
"prior to Windows 8.1."))
|
||||
#endif
|
||||
native_handle_type release()
|
||||
{
|
||||
asio::error_code ec;
|
||||
native_handle_type s = this->get_service().release(
|
||||
this->get_implementation(), ec);
|
||||
asio::detail::throw_error(ec, "release");
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying native acceptor.
|
||||
/**
|
||||
* This function causes all outstanding asynchronous accept operations to
|
||||
* finish immediately, and the handlers for cancelled operations will be
|
||||
* passed the asio::error::operation_aborted error. Ownership of the
|
||||
* native acceptor is then transferred to the caller.
|
||||
*
|
||||
* @param ec Set to indicate what error occurred, if any.
|
||||
*
|
||||
* @note This function is unsupported on Windows versions prior to Windows
|
||||
* 8.1, and will fail with asio::error::operation_not_supported on
|
||||
* these platforms.
|
||||
*/
|
||||
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
|
||||
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
|
||||
__declspec(deprecated("This function always fails with "
|
||||
"operation_not_supported when used on Windows versions "
|
||||
"prior to Windows 8.1."))
|
||||
#endif
|
||||
native_handle_type release(asio::error_code& ec)
|
||||
{
|
||||
return this->get_service().release(this->get_implementation(), ec);
|
||||
}
|
||||
|
||||
/// Get the native acceptor representation.
|
||||
/**
|
||||
* This function may be used to obtain the underlying representation of the
|
||||
|
@ -167,6 +167,13 @@ public:
|
||||
ASIO_SYNC_OP_VOID_RETURN(ec);
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying socket.
|
||||
native_handle_type release(implementation_type& impl,
|
||||
asio::error_code& ec)
|
||||
{
|
||||
return service_impl_.release(impl, ec);
|
||||
}
|
||||
|
||||
/// Get the native socket implementation.
|
||||
native_handle_type native_handle(implementation_type& impl)
|
||||
{
|
||||
|
@ -121,6 +121,25 @@ asio::error_code reactive_socket_service_base::close(
|
||||
return ec;
|
||||
}
|
||||
|
||||
socket_type reactive_socket_service_base::release(
|
||||
reactive_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;
|
||||
|
||||
reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
|
||||
(impl.state_ & socket_ops::possible_dup) == 0);
|
||||
|
||||
socket_type tmp = impl.socket_;
|
||||
impl.socket_ = invalid_socket;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
asio::error_code reactive_socket_service_base::cancel(
|
||||
reactive_socket_service_base::base_implementation_type& impl,
|
||||
asio::error_code& ec)
|
||||
|
@ -32,6 +32,7 @@ win_iocp_socket_service_base::win_iocp_socket_service_base(
|
||||
iocp_service_(use_service<win_iocp_io_context>(io_context)),
|
||||
reactor_(0),
|
||||
connect_ex_(0),
|
||||
nt_set_info_(0),
|
||||
mutex_(),
|
||||
impl_list_(0)
|
||||
{
|
||||
@ -191,6 +192,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)
|
||||
@ -704,6 +738,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 = GetModuleHandle("NTDLL.DLL"))
|
||||
ptr = 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)
|
||||
{
|
||||
|
@ -148,6 +148,23 @@ asio::error_code winrt_ssocket_service_base::close(
|
||||
return ec;
|
||||
}
|
||||
|
||||
winrt_ssocket_service_base::native_handle_type
|
||||
winrt_ssocket_service_base::release(
|
||||
winrt_ssocket_service_base::base_implementation_type& impl,
|
||||
asio::error_code& ec)
|
||||
{
|
||||
if (!is_open(impl))
|
||||
return nullptr;
|
||||
|
||||
cancel(impl, ec);
|
||||
if (ec)
|
||||
return nullptr;
|
||||
|
||||
native_handle_type tmp = impl.socket_;
|
||||
impl.socket_ = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::size_t winrt_ssocket_service_base::do_get_endpoint(
|
||||
const base_implementation_type& impl, bool local,
|
||||
void* addr, std::size_t addr_len, asio::error_code& ec) const
|
||||
|
@ -119,6 +119,14 @@ public:
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Release ownership of the socket.
|
||||
native_handle_type release(implementation_type&,
|
||||
asio::error_code& ec)
|
||||
{
|
||||
ec = asio::error::operation_not_supported;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the native socket representation.
|
||||
native_handle_type native_handle(implementation_type&)
|
||||
{
|
||||
|
@ -93,6 +93,10 @@ public:
|
||||
ASIO_DECL asio::error_code close(
|
||||
base_implementation_type& impl, asio::error_code& ec);
|
||||
|
||||
// Release ownership of the socket.
|
||||
ASIO_DECL socket_type release(
|
||||
base_implementation_type& impl, asio::error_code& ec);
|
||||
|
||||
// Get the native socket representation.
|
||||
native_handle_type native_handle(base_implementation_type& impl)
|
||||
{
|
||||
|
@ -116,6 +116,10 @@ public:
|
||||
ASIO_DECL asio::error_code close(
|
||||
base_implementation_type& impl, asio::error_code& ec);
|
||||
|
||||
// Release ownership of the socket.
|
||||
ASIO_DECL socket_type release(
|
||||
base_implementation_type& impl, asio::error_code& ec);
|
||||
|
||||
// Cancel all operations associated with the socket.
|
||||
ASIO_DECL asio::error_code cancel(
|
||||
base_implementation_type& impl, asio::error_code& ec);
|
||||
@ -528,6 +532,15 @@ protected:
|
||||
ASIO_DECL connect_ex_fn get_connect_ex(
|
||||
base_implementation_type& impl, int type);
|
||||
|
||||
// The type of a NtSetInformationFile function pointer.
|
||||
typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG);
|
||||
|
||||
// Helper function to get the NtSetInformationFile function pointer. If no
|
||||
// NtSetInformationFile pointer has been obtained yet, one is obtained using
|
||||
// GetProcAddress and the pointer is cached. Returns a null pointer if
|
||||
// NtSetInformationFile is not available.
|
||||
ASIO_DECL nt_set_info_fn get_nt_set_info();
|
||||
|
||||
// Helper function to emulate InterlockedCompareExchangePointer functionality
|
||||
// for:
|
||||
// - very old Platform SDKs; and
|
||||
@ -554,6 +567,9 @@ protected:
|
||||
// Pointer to ConnectEx implementation.
|
||||
void* connect_ex_;
|
||||
|
||||
// Pointer to NtSetInformationFile implementation.
|
||||
void* nt_set_info_;
|
||||
|
||||
// Mutex to protect access to the linked list of implementations.
|
||||
asio::detail::mutex mutex_;
|
||||
|
||||
|
@ -92,6 +92,10 @@ public:
|
||||
ASIO_DECL asio::error_code close(
|
||||
base_implementation_type& impl, asio::error_code& ec);
|
||||
|
||||
// Release ownership of the socket.
|
||||
ASIO_DECL native_handle_type release(
|
||||
base_implementation_type& impl, asio::error_code& ec);
|
||||
|
||||
// Get the native socket representation.
|
||||
native_handle_type native_handle(base_implementation_type& impl)
|
||||
{
|
||||
|
@ -167,6 +167,13 @@ public:
|
||||
ASIO_SYNC_OP_VOID_RETURN(ec);
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying socket.
|
||||
native_handle_type release(implementation_type& impl,
|
||||
asio::error_code& ec)
|
||||
{
|
||||
return service_impl_.release(impl, ec);
|
||||
}
|
||||
|
||||
/// Get the native socket implementation.
|
||||
native_handle_type native_handle(implementation_type& impl)
|
||||
{
|
||||
|
@ -169,6 +169,13 @@ public:
|
||||
ASIO_SYNC_OP_VOID_RETURN(ec);
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying socket.
|
||||
native_handle_type release(implementation_type& impl,
|
||||
asio::error_code& ec)
|
||||
{
|
||||
return service_impl_.release(impl, ec);
|
||||
}
|
||||
|
||||
/// Get the native socket implementation.
|
||||
native_handle_type native_handle(implementation_type& impl)
|
||||
{
|
||||
|
@ -188,6 +188,13 @@ public:
|
||||
ASIO_SYNC_OP_VOID_RETURN(ec);
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying acceptor.
|
||||
native_handle_type release(implementation_type& impl,
|
||||
asio::error_code& ec)
|
||||
{
|
||||
return service_impl_.release(impl, ec);
|
||||
}
|
||||
|
||||
/// Get the native acceptor implementation.
|
||||
native_handle_type native_handle(implementation_type& impl)
|
||||
{
|
||||
|
@ -167,6 +167,13 @@ public:
|
||||
ASIO_SYNC_OP_VOID_RETURN(ec);
|
||||
}
|
||||
|
||||
/// Release ownership of the underlying socket.
|
||||
native_handle_type release(implementation_type& impl,
|
||||
asio::error_code& ec)
|
||||
{
|
||||
return service_impl_.release(impl, ec);
|
||||
}
|
||||
|
||||
/// Get the native socket implementation.
|
||||
native_handle_type native_handle(implementation_type& impl)
|
||||
{
|
||||
|
@ -156,6 +156,9 @@ void test()
|
||||
socket1.close();
|
||||
socket1.close(ec);
|
||||
|
||||
socket1.release();
|
||||
socket1.release(ec);
|
||||
|
||||
ip::icmp::socket::native_handle_type native_socket4
|
||||
= socket1.native_handle();
|
||||
(void)native_socket4;
|
||||
|
@ -304,6 +304,9 @@ void test()
|
||||
socket1.close();
|
||||
socket1.close(ec);
|
||||
|
||||
socket1.release();
|
||||
socket1.release(ec);
|
||||
|
||||
ip::tcp::socket::native_handle_type native_socket4
|
||||
= socket1.native_handle();
|
||||
(void)native_socket4;
|
||||
@ -870,6 +873,9 @@ void test()
|
||||
acceptor1.close();
|
||||
acceptor1.close(ec);
|
||||
|
||||
acceptor1.release();
|
||||
acceptor1.release(ec);
|
||||
|
||||
ip::tcp::acceptor::native_handle_type native_acceptor4
|
||||
= acceptor1.native_handle();
|
||||
(void)native_acceptor4;
|
||||
|
@ -172,6 +172,9 @@ void test()
|
||||
socket1.close();
|
||||
socket1.close(ec);
|
||||
|
||||
socket1.release();
|
||||
socket1.release(ec);
|
||||
|
||||
ip::udp::socket::native_handle_type native_socket4
|
||||
= socket1.native_handle();
|
||||
(void)native_socket4;
|
||||
|
Loading…
Reference in New Issue
Block a user