diff options
Diffstat (limited to '3rdparty/asio/include/asio/basic_socket.hpp')
-rw-r--r-- | 3rdparty/asio/include/asio/basic_socket.hpp | 722 |
1 files changed, 476 insertions, 246 deletions
diff --git a/3rdparty/asio/include/asio/basic_socket.hpp b/3rdparty/asio/include/asio/basic_socket.hpp index a1e7b81c3f8..88c4b03fe18 100644 --- a/3rdparty/asio/include/asio/basic_socket.hpp +++ b/3rdparty/asio/include/asio/basic_socket.hpp @@ -2,7 +2,7 @@ // basic_socket.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2024 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) @@ -15,37 +15,43 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <utility> +#include "asio/any_io_executor.hpp" #include "asio/detail/config.hpp" #include "asio/async_result.hpp" -#include "asio/basic_io_object.hpp" #include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/io_object_impl.hpp" +#include "asio/detail/non_const_lvalue.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/type_traits.hpp" #include "asio/error.hpp" +#include "asio/execution_context.hpp" #include "asio/post.hpp" #include "asio/socket_base.hpp" -#if defined(ASIO_HAS_MOVE) -# include <utility> -#endif // defined(ASIO_HAS_MOVE) - -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# if defined(ASIO_WINDOWS_RUNTIME) -# include "asio/detail/winrt_ssocket_service.hpp" -# define ASIO_SVC_T detail::winrt_ssocket_service<Protocol> -# elif defined(ASIO_HAS_IOCP) -# include "asio/detail/win_iocp_socket_service.hpp" -# define ASIO_SVC_T detail::win_iocp_socket_service<Protocol> -# else -# include "asio/detail/reactive_socket_service.hpp" -# define ASIO_SVC_T detail::reactive_socket_service<Protocol> -# endif -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) +#if defined(ASIO_WINDOWS_RUNTIME) +# include "asio/detail/null_socket_service.hpp" +#elif defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_socket_service.hpp" +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) +# include "asio/detail/io_uring_socket_service.hpp" +#else +# include "asio/detail/reactive_socket_service.hpp" +#endif #include "asio/detail/push_options.hpp" namespace asio { +#if !defined(ASIO_BASIC_SOCKET_FWD_DECL) +#define ASIO_BASIC_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol, typename Executor = any_io_executor> +class basic_socket; + +#endif // !defined(ASIO_BASIC_SOCKET_FWD_DECL) + /// Provides socket functionality. /** * The basic_socket class template provides functionality that is common to both @@ -55,20 +61,41 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename Protocol ASIO_SVC_TPARAM> +template <typename Protocol, typename Executor> class basic_socket - : ASIO_SVC_ACCESS basic_io_object<ASIO_SVC_T>, - public socket_base + : public socket_base { +private: + class initiate_async_connect; + class initiate_async_wait; + public: /// The type of the executor associated with the object. - typedef io_context::executor_type executor_type; + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template <typename Executor1> + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_socket<Protocol, Executor1> other; + }; /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; +#elif defined(ASIO_WINDOWS_RUNTIME) + typedef typename detail::null_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IOCP) + typedef typename detail::win_iocp_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + typedef typename detail::io_uring_socket_service< + Protocol>::native_handle_type native_handle_type; #else - typedef typename ASIO_SVC_T::native_handle_type native_handle_type; + typedef typename detail::reactive_socket_service< + Protocol>::native_handle_type native_handle_type; #endif /// The protocol type. @@ -79,18 +106,35 @@ public: #if !defined(ASIO_NO_EXTENSIONS) /// A basic_socket is always the lowest layer. - typedef basic_socket<Protocol ASIO_SVC_TARG> lowest_layer_type; + typedef basic_socket<Protocol, Executor> lowest_layer_type; #endif // !defined(ASIO_NO_EXTENSIONS) /// Construct a basic_socket without opening it. /** * This constructor creates a socket without opening it. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. */ - explicit basic_socket(asio::io_context& io_context) - : basic_io_object<ASIO_SVC_T>(io_context) + explicit basic_socket(const executor_type& ex) + : impl_(0, ex) + { + } + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template <typename ExecutionContext> + explicit basic_socket(ExecutionContext& context, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) { } @@ -98,19 +142,43 @@ public: /** * This constructor creates and opens a socket. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ - basic_socket(asio::io_context& io_context, - const protocol_type& protocol) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_socket(const executor_type& ex, const protocol_type& protocol) + : impl_(0, ex) + { + asio::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket(ExecutionContext& context, const protocol_type& protocol, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value, + defaulted_constraint + > = defaulted_constraint()) + : impl_(0, 0, context) { asio::error_code ec; - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); } @@ -121,7 +189,7 @@ public: * specified endpoint on the local machine. The protocol used is the protocol * associated with the given endpoint. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the socket will @@ -129,15 +197,45 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_socket(asio::io_context& io_context, - const endpoint_type& endpoint) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_socket(const executor_type& ex, const endpoint_type& endpoint) + : impl_(0, ex) { asio::error_code ec; const protocol_type protocol = endpoint.protocol(); - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + asio::detail::throw_error(ec, "bind"); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a socket and automatically opens it bound to the + * specified endpoint on the local machine. The protocol used is the protocol + * associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket(ExecutionContext& context, const endpoint_type& endpoint, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + asio::detail::throw_error(ec, "open"); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); asio::detail::throw_error(ec, "bind"); } @@ -145,7 +243,7 @@ public: /** * This constructor creates a socket object to hold an existing native socket. * - * @param io_context The io_context object that the socket will use to + * @param ex The I/O executor that the socket will use, by default, to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. @@ -154,17 +252,44 @@ public: * * @throws asio::system_error Thrown on failure. */ - basic_socket(asio::io_context& io_context, - const protocol_type& protocol, const native_handle_type& native_socket) - : basic_io_object<ASIO_SVC_T>(io_context) + basic_socket(const executor_type& ex, const protocol_type& protocol, + const native_handle_type& native_socket) + : impl_(0, ex) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws asio::system_error Thrown on failure. + */ + template <typename ExecutionContext> + basic_socket(ExecutionContext& context, const protocol_type& protocol, + const native_handle_type& native_socket, + constraint_t< + is_convertible<ExecutionContext&, execution_context&>::value + > = 0) + : impl_(0, 0, context) + { + asio::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), protocol, native_socket, ec); asio::detail::throw_error(ec, "assign"); } -#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a basic_socket from another. /** * This constructor moves a socket from one object to another. @@ -173,10 +298,10 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ - basic_socket(basic_socket&& other) - : basic_io_object<ASIO_SVC_T>(std::move(other)) + basic_socket(basic_socket&& other) noexcept + : impl_(std::move(other.impl_)) { } @@ -188,16 +313,16 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ basic_socket& operator=(basic_socket&& other) { - basic_io_object<ASIO_SVC_T>::operator=(std::move(other)); + impl_ = std::move(other.impl_); return *this; } // All sockets have access to each other's implementations. - template <typename Protocol1 ASIO_SVC_TPARAM1> + template <typename Protocol1, typename Executor1> friend class basic_socket; /// Move-construct a basic_socket from a socket of another protocol type. @@ -208,15 +333,16 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - basic_socket(basic_socket<Protocol1 ASIO_SVC_TARG1>&& other, - typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_io_object<ASIO_SVC_T>(other.get_service().get_io_context()) + template <typename Protocol1, typename Executor1> + basic_socket(basic_socket<Protocol1, Executor1>&& other, + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value + > = 0) + : impl_(std::move(other.impl_)) { - this->get_service().template converting_move_construct<Protocol1>( - this->get_implementation(), other.get_implementation()); } /// Move-assign a basic_socket from a socket of another protocol type. @@ -227,58 +353,25 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_context&) constructor. + * constructed using the @c basic_socket(const executor_type&) constructor. */ - template <typename Protocol1 ASIO_SVC_TPARAM1> - typename enable_if<is_convertible<Protocol1, Protocol>::value, - basic_socket>::type& operator=( - basic_socket<Protocol1 ASIO_SVC_TARG1>&& other) + template <typename Protocol1, typename Executor1> + constraint_t< + is_convertible<Protocol1, Protocol>::value + && is_convertible<Executor1, Executor>::value, + basic_socket& + > operator=(basic_socket<Protocol1, Executor1>&& other) { basic_socket tmp(std::move(other)); - basic_io_object<ASIO_SVC_T>::operator=(std::move(tmp)); + impl_ = std::move(tmp.impl_); return *this; } -#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - -#if defined(ASIO_ENABLE_OLD_SERVICES) - // These functions are provided by basic_io_object<>. -#else // defined(ASIO_ENABLE_OLD_SERVICES) -#if !defined(ASIO_NO_DEPRECATED) - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_context() - { - return basic_io_object<ASIO_SVC_T>::get_io_context(); - } - - /// (Deprecated: Use get_executor().) Get the io_context associated with the - /// object. - /** - * This function may be used to obtain the io_context object that the I/O - * object uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_context object that the I/O object will use - * to dispatch handlers. Ownership is not transferred to the caller. - */ - asio::io_context& get_io_service() - { - return basic_io_object<ASIO_SVC_T>::get_io_service(); - } -#endif // !defined(ASIO_NO_DEPRECATED) /// Get the executor associated with the object. - executor_type get_executor() ASIO_NOEXCEPT + const executor_type& get_executor() noexcept { - return basic_io_object<ASIO_SVC_T>::get_executor(); + return impl_.get_executor(); } -#endif // defined(ASIO_ENABLE_OLD_SERVICES) #if !defined(ASIO_NO_EXTENSIONS) /// Get a reference to the lowest layer. @@ -320,14 +413,14 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * socket.open(asio::ip::tcp::v4()); * @endcode */ void open(const protocol_type& protocol = protocol_type()) { asio::error_code ec; - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); asio::detail::throw_error(ec, "open"); } @@ -341,7 +434,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::error_code ec; * socket.open(asio::ip::tcp::v4(), ec); * if (ec) @@ -353,7 +446,7 @@ public: ASIO_SYNC_OP_VOID open(const protocol_type& protocol, asio::error_code& ec) { - this->get_service().open(this->get_implementation(), protocol, ec); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -371,7 +464,7 @@ public: const native_handle_type& native_socket) { asio::error_code ec; - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), protocol, native_socket, ec); asio::detail::throw_error(ec, "assign"); } @@ -389,7 +482,7 @@ public: ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, const native_handle_type& native_socket, asio::error_code& ec) { - this->get_service().assign(this->get_implementation(), + impl_.get_service().assign(impl_.get_implementation(), protocol, native_socket, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -397,7 +490,7 @@ public: /// Determine whether the socket is open. bool is_open() const { - return this->get_service().is_open(this->get_implementation()); + return impl_.get_service().is_open(impl_.get_implementation()); } /// Close the socket. @@ -415,7 +508,7 @@ public: void close() { asio::error_code ec; - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "close"); } @@ -430,7 +523,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * socket.close(ec); @@ -445,10 +538,62 @@ public: */ ASIO_SYNC_OP_VOID close(asio::error_code& ec) { - this->get_service().close(this->get_implementation(), ec); + impl_.get_service().close(impl_.get_implementation(), ec); 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 = impl_.get_service().release( + impl_.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 impl_.get_service().release(impl_.get_implementation(), ec); + } + /// Get the native socket representation. /** * This function may be used to obtain the underlying representation of the @@ -457,7 +602,7 @@ public: */ native_handle_type native_handle() { - return this->get_service().native_handle(this->get_implementation()); + return impl_.get_service().native_handle(impl_.get_implementation()); } /// Cancel all asynchronous operations associated with the socket. @@ -504,7 +649,7 @@ public: void cancel() { asio::error_code ec; - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "cancel"); } @@ -551,7 +696,7 @@ public: #endif ASIO_SYNC_OP_VOID cancel(asio::error_code& ec) { - this->get_service().cancel(this->get_implementation(), ec); + impl_.get_service().cancel(impl_.get_implementation(), ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -568,7 +713,7 @@ public: bool at_mark() const { asio::error_code ec; - bool b = this->get_service().at_mark(this->get_implementation(), ec); + bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec); asio::detail::throw_error(ec, "at_mark"); return b; } @@ -585,7 +730,7 @@ public: */ bool at_mark(asio::error_code& ec) const { - return this->get_service().at_mark(this->get_implementation(), ec); + return impl_.get_service().at_mark(impl_.get_implementation(), ec); } /// Determine the number of bytes available for reading. @@ -601,8 +746,8 @@ public: std::size_t available() const { asio::error_code ec; - std::size_t s = this->get_service().available( - this->get_implementation(), ec); + std::size_t s = impl_.get_service().available( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "available"); return s; } @@ -619,7 +764,7 @@ public: */ std::size_t available(asio::error_code& ec) const { - return this->get_service().available(this->get_implementation(), ec); + return impl_.get_service().available(impl_.get_implementation(), ec); } /// Bind the socket to the given local endpoint. @@ -634,7 +779,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * socket.open(asio::ip::tcp::v4()); * socket.bind(asio::ip::tcp::endpoint( * asio::ip::tcp::v4(), 12345)); @@ -643,7 +788,7 @@ public: void bind(const endpoint_type& endpoint) { asio::error_code ec; - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); asio::detail::throw_error(ec, "bind"); } @@ -659,7 +804,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * socket.open(asio::ip::tcp::v4()); * asio::error_code ec; * socket.bind(asio::ip::tcp::endpoint( @@ -673,7 +818,7 @@ public: ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, asio::error_code& ec) { - this->get_service().bind(this->get_implementation(), endpoint, ec); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -694,7 +839,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.connect(endpoint); @@ -705,11 +850,11 @@ public: asio::error_code ec; if (!is_open()) { - this->get_service().open(this->get_implementation(), + impl_.get_service().open(impl_.get_implementation(), peer_endpoint.protocol(), ec); asio::detail::throw_error(ec, "connect"); } - this->get_service().connect(this->get_implementation(), peer_endpoint, ec); + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); asio::detail::throw_error(ec, "connect"); } @@ -730,7 +875,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * asio::error_code ec; @@ -746,7 +891,7 @@ public: { if (!is_open()) { - this->get_service().open(this->get_implementation(), + impl_.get_service().open(impl_.get_implementation(), peer_endpoint.protocol(), ec); if (ec) { @@ -754,14 +899,15 @@ public: } } - this->get_service().connect(this->get_implementation(), peer_endpoint, ec); + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous connect. /** * This function is used to asynchronously connect a socket to the specified - * remote endpoint. The function call always returns immediately. + * remote endpoint. It is an initiating function for an @ref + * asynchronous_operation, and always returns immediately. * * The socket is automatically opened if it is not already open. If the * connect fails, and the socket was automatically opened, the socket is @@ -770,16 +916,21 @@ public: * @param peer_endpoint The remote endpoint to which the socket will be * connected. Copies will be made of the endpoint object as required. * - * @param handler The handler to be called when the connection operation - * completes. Copies will be made of the handler as required. The function - * signature of the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the connect completes. + * Potential completion tokens include @ref use_future, @ref use_awaitable, + * @ref yield_context, or a function object with the correct completion + * signature. The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode * * @par Example * @code @@ -793,54 +944,41 @@ public: * * ... * - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.async_connect(endpoint, connect_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename ConnectHandler> - ASIO_INITFN_RESULT_TYPE(ConnectHandler, - void (asio::error_code)) - async_connect(const endpoint_type& peer_endpoint, - ASIO_MOVE_ARG(ConnectHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + ConnectToken = default_completion_token_t<executor_type>> + auto async_connect(const endpoint_type& peer_endpoint, + ConnectToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<ConnectToken, void (asio::error_code)>( + declval<initiate_async_connect>(), token, + peer_endpoint, declval<asio::error_code&>())) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ConnectHandler. - ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check; - + asio::error_code open_ec; if (!is_open()) { - asio::error_code ec; const protocol_type protocol = peer_endpoint.protocol(); - this->get_service().open(this->get_implementation(), protocol, ec); - if (ec) - { - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - asio::post(this->get_executor(), - asio::detail::bind_handler( - ASIO_MOVE_CAST(ASIO_HANDLER_TYPE( - ConnectHandler, void (asio::error_code)))( - init.completion_handler), ec)); - - return init.result.get(); - } + impl_.get_service().open(impl_.get_implementation(), protocol, open_ec); } -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_connect(this->get_implementation(), - peer_endpoint, ASIO_MOVE_CAST(ConnectHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<ConnectHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_connect( - this->get_implementation(), peer_endpoint, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<ConnectToken, void (asio::error_code)>( + initiate_async_connect(this), token, peer_endpoint, open_ec); } /// Set an option on the socket. @@ -871,7 +1009,7 @@ public: * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::no_delay option(true); * socket.set_option(option); @@ -881,7 +1019,7 @@ public: void set_option(const SettableSocketOption& option) { asio::error_code ec; - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "set_option"); } @@ -913,7 +1051,7 @@ public: * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::no_delay option(true); * asio::error_code ec; @@ -928,7 +1066,7 @@ public: ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, asio::error_code& ec) { - this->get_service().set_option(this->get_implementation(), option, ec); + impl_.get_service().set_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -960,7 +1098,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::keep_alive option; * socket.get_option(option); @@ -971,7 +1109,7 @@ public: void get_option(GettableSocketOption& option) const { asio::error_code ec; - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); asio::detail::throw_error(ec, "get_option"); } @@ -1003,7 +1141,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::keep_alive option; * asio::error_code ec; @@ -1019,7 +1157,7 @@ public: ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, asio::error_code& ec) const { - this->get_service().get_option(this->get_implementation(), option, ec); + impl_.get_service().get_option(impl_.get_implementation(), option, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1038,7 +1176,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::bytes_readable command; * socket.io_control(command); @@ -1049,7 +1187,7 @@ public: void io_control(IoControlCommand& command) { asio::error_code ec; - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); asio::detail::throw_error(ec, "io_control"); } @@ -1068,7 +1206,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::socket::bytes_readable command; * asio::error_code ec; @@ -1084,7 +1222,7 @@ public: ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, asio::error_code& ec) { - this->get_service().io_control(this->get_implementation(), command, ec); + impl_.get_service().io_control(impl_.get_implementation(), command, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1101,7 +1239,7 @@ public: */ bool non_blocking() const { - return this->get_service().non_blocking(this->get_implementation()); + return impl_.get_service().non_blocking(impl_.get_implementation()); } /// Sets the non-blocking mode of the socket. @@ -1120,7 +1258,7 @@ public: void non_blocking(bool mode) { asio::error_code ec; - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "non_blocking"); } @@ -1140,7 +1278,7 @@ public: ASIO_SYNC_OP_VOID non_blocking( bool mode, asio::error_code& ec) { - this->get_service().non_blocking(this->get_implementation(), mode, ec); + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1230,7 +1368,7 @@ public: */ bool native_non_blocking() const { - return this->get_service().native_non_blocking(this->get_implementation()); + return impl_.get_service().native_non_blocking(impl_.get_implementation()); } /// Sets the non-blocking mode of the native socket implementation. @@ -1321,8 +1459,8 @@ public: void native_non_blocking(bool mode) { asio::error_code ec; - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); asio::detail::throw_error(ec, "native_non_blocking"); } @@ -1414,8 +1552,8 @@ public: ASIO_SYNC_OP_VOID native_non_blocking( bool mode, asio::error_code& ec) { - this->get_service().native_non_blocking( - this->get_implementation(), mode, ec); + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1429,7 +1567,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); * @endcode @@ -1437,8 +1575,8 @@ public: endpoint_type local_endpoint() const { asio::error_code ec; - endpoint_type ep = this->get_service().local_endpoint( - this->get_implementation(), ec); + endpoint_type ep = impl_.get_service().local_endpoint( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "local_endpoint"); return ep; } @@ -1454,7 +1592,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); @@ -1466,7 +1604,7 @@ public: */ endpoint_type local_endpoint(asio::error_code& ec) const { - return this->get_service().local_endpoint(this->get_implementation(), ec); + return impl_.get_service().local_endpoint(impl_.get_implementation(), ec); } /// Get the remote endpoint of the socket. @@ -1479,7 +1617,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); * @endcode @@ -1487,8 +1625,8 @@ public: endpoint_type remote_endpoint() const { asio::error_code ec; - endpoint_type ep = this->get_service().remote_endpoint( - this->get_implementation(), ec); + endpoint_type ep = impl_.get_service().remote_endpoint( + impl_.get_implementation(), ec); asio::detail::throw_error(ec, "remote_endpoint"); return ep; } @@ -1504,7 +1642,7 @@ public: * * @par Example * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); @@ -1516,7 +1654,7 @@ public: */ endpoint_type remote_endpoint(asio::error_code& ec) const { - return this->get_service().remote_endpoint(this->get_implementation(), ec); + return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec); } /// Disable sends or receives on the socket. @@ -1531,7 +1669,7 @@ public: * @par Example * Shutting down the send side of the socket: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * socket.shutdown(asio::ip::tcp::socket::shutdown_send); * @endcode @@ -1539,7 +1677,7 @@ public: void shutdown(shutdown_type what) { asio::error_code ec; - this->get_service().shutdown(this->get_implementation(), what, ec); + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); asio::detail::throw_error(ec, "shutdown"); } @@ -1555,7 +1693,7 @@ public: * @par Example * Shutting down the send side of the socket: * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec); @@ -1568,7 +1706,7 @@ public: ASIO_SYNC_OP_VOID shutdown(shutdown_type what, asio::error_code& ec) { - this->get_service().shutdown(this->get_implementation(), what, ec); + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1583,7 +1721,7 @@ public: * @par Example * Waiting for a socket to become readable. * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * socket.wait(asio::ip::tcp::socket::wait_read); * @endcode @@ -1591,7 +1729,7 @@ public: void wait(wait_type w) { asio::error_code ec; - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); asio::detail::throw_error(ec, "wait"); } @@ -1608,7 +1746,7 @@ public: * @par Example * Waiting for a socket to become readable. * @code - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * asio::error_code ec; * socket.wait(asio::ip::tcp::socket::wait_read, ec); @@ -1616,7 +1754,7 @@ public: */ ASIO_SYNC_OP_VOID wait(wait_type w, asio::error_code& ec) { - this->get_service().wait(this->get_implementation(), w, ec); + impl_.get_service().wait(impl_.get_implementation(), w, ec); ASIO_SYNC_OP_VOID_RETURN(ec); } @@ -1624,20 +1762,27 @@ public: /// write, or to have pending error conditions. /** * This function is used to perform an asynchronous wait for a socket to enter - * a ready to read, write or error condition state. + * a ready to read, write or error condition state. It is an initiating + * function for an @ref asynchronous_operation, and always returns + * immediately. * * @param w Specifies the desired socket state. * - * @param handler The handler to be called when the wait operation completes. - * Copies will be made of the handler as required. The function signature of - * the handler must be: + * @param token The @ref completion_token that will be used to produce a + * completion handler, which will be called when the wait completes. Potential + * completion tokens include @ref use_future, @ref use_awaitable, @ref + * yield_context, or a function object with the correct completion signature. + * The function signature of the completion handler must be: * @code void handler( - * const asio::error_code& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or - * not, the handler will not be invoked from within this function. Invocation - * of the handler will be performed in a manner equivalent to using - * asio::io_context::post(). + * not, the completion handler will not be invoked from within this function. + * On immediate completion, invocation of the handler will be performed in a + * manner equivalent to using asio::post(). + * + * @par Completion Signature + * @code void(asio::error_code) @endcode * * @par Example * @code @@ -1651,32 +1796,32 @@ public: * * ... * - * asio::ip::tcp::socket socket(io_context); + * asio::ip::tcp::socket socket(my_context); * ... * socket.async_wait(asio::ip::tcp::socket::wait_read, wait_handler); * @endcode + * + * @par Per-Operation Cancellation + * On POSIX or Windows operating systems, this asynchronous operation supports + * cancellation for the following asio::cancellation_type values: + * + * @li @c cancellation_type::terminal + * + * @li @c cancellation_type::partial + * + * @li @c cancellation_type::total */ - template <typename WaitHandler> - ASIO_INITFN_RESULT_TYPE(WaitHandler, - void (asio::error_code)) - async_wait(wait_type w, ASIO_MOVE_ARG(WaitHandler) handler) + template < + ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code)) + WaitToken = default_completion_token_t<executor_type>> + auto async_wait(wait_type w, + WaitToken&& token = default_completion_token_t<executor_type>()) + -> decltype( + async_initiate<WaitToken, void (asio::error_code)>( + declval<initiate_async_wait>(), token, w)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WaitHandler. - ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - -#if defined(ASIO_ENABLE_OLD_SERVICES) - return this->get_service().async_wait(this->get_implementation(), - w, ASIO_MOVE_CAST(WaitHandler)(handler)); -#else // defined(ASIO_ENABLE_OLD_SERVICES) - async_completion<WaitHandler, - void (asio::error_code)> init(handler); - - this->get_service().async_wait(this->get_implementation(), - w, init.completion_handler); - - return init.result.get(); -#endif // defined(ASIO_ENABLE_OLD_SERVICES) + return async_initiate<WaitToken, void (asio::error_code)>( + initiate_async_wait(this), token, w); } protected: @@ -1689,18 +1834,103 @@ protected: { } +#if defined(ASIO_WINDOWS_RUNTIME) + detail::io_object_impl< + detail::null_socket_service<Protocol>, Executor> impl_; +#elif defined(ASIO_HAS_IOCP) + detail::io_object_impl< + detail::win_iocp_socket_service<Protocol>, Executor> impl_; +#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT) + detail::io_object_impl< + detail::io_uring_socket_service<Protocol>, Executor> impl_; +#else + detail::io_object_impl< + detail::reactive_socket_service<Protocol>, Executor> impl_; +#endif + private: // Disallow copying and assignment. - basic_socket(const basic_socket&) ASIO_DELETED; - basic_socket& operator=(const basic_socket&) ASIO_DELETED; + basic_socket(const basic_socket&) = delete; + basic_socket& operator=(const basic_socket&) = delete; + + class initiate_async_connect + { + public: + typedef Executor executor_type; + + explicit initiate_async_connect(basic_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename ConnectHandler> + void operator()(ConnectHandler&& handler, + const endpoint_type& peer_endpoint, + const asio::error_code& open_ec) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ConnectHandler. + ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check; + + if (open_ec) + { + asio::post(self_->impl_.get_executor(), + asio::detail::bind_handler( + static_cast<ConnectHandler&&>(handler), open_ec)); + } + else + { + detail::non_const_lvalue<ConnectHandler> handler2(handler); + self_->impl_.get_service().async_connect( + self_->impl_.get_implementation(), peer_endpoint, + handler2.value, self_->impl_.get_executor()); + } + } + + private: + basic_socket* self_; + }; + + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_socket* self) + : self_(self) + { + } + + const executor_type& get_executor() const noexcept + { + return self_->get_executor(); + } + + template <typename WaitHandler> + void operator()(WaitHandler&& handler, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue<WaitHandler> handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); + } + + private: + basic_socket* self_; + }; }; } // namespace asio #include "asio/detail/pop_options.hpp" -#if !defined(ASIO_ENABLE_OLD_SERVICES) -# undef ASIO_SVC_T -#endif // !defined(ASIO_ENABLE_OLD_SERVICES) - #endif // ASIO_BASIC_SOCKET_HPP |