Document number: P1322R2 Date: 2020-08-21 Project: Programming Language C++ Audience: SG4 - Networking, LEWG Reply-to: Christopher Kohlhoff <chris@kohlhoff.com>

Networking TS enhancement to enable custom I/O executors

1. Introduction

At present, the Networking TS's I/O objects -- sockets, acceptors, resolvers, and timers -- can be associated only with concrete execution contexts of type io_context . This paper proposes a minor change to the specification to permit the construction of these objects with arbitrary I/O executors and execution contexts. This would:

allow implementers to support multiple "native" execution contexts, with different design and performance trade-offs; and

simplify some use cases, by allowing users to specify their preferred executor once, at construction, rather than on each operation.

2. Rationale

Construction with arbitrary execution contexts

Users and third-party libraries may implement their own execution contexts, for example to provide different scheduling guarantees, or to natively support other types of I/O objects, such as files. This proposal would allow users to create the standard I/O objects, such as sockets, to be associated with these custom execution contexts. However, although constructing the socket with a custom execution context will provide the correct, expected behaviour, there is no guarantee that it will operate as efficiently as a socket associated with a native execution context.

Support for multiple native execution contexts

Some operating systems have multiple potential implementation strategies for the I/O objects, like sockets. For example, on Windows we can choose to have asynchronous notifications delivered via a completion port to a user-created thread, or we can have them delivered directly to the system thread pool. An implementer may want to make both of these strategies available, via the io_context and system_context execution contexts, respectively. For example:

io_context my_context; tcp::socket my_socket_1(my_context); // Implementation uses a completion port. // ... tcp::socket my_socket_2(system_executor{}); // Implementation uses the system thread pool.

Libraries can also provide additional native execution contexts as implementation-specific extensions.

Convenient construction with a preferred executor

In some use cases, all asynchronous operations on a given I/O object are performed using the same executor. One common example of this is when using a strand. This proposal allows this executor to be specified once, when the I/O object is constructed. For example:

io_context my_context; // ... strand<io_context::executor_type> my_strand(my_context.get_executor()); tcp::socket my_socket(my_strand); // ... my_socket.async_receive(my_buffer, my_handler); // my_handler is invoked in the strand

Vendor- or user-specialization of I/O object templates

The Executor template parameter also offers an opportunity to specialize the I/O object types for specific executor types. For example, some platforms support vendor-specific kernel bypass APIs for I/O such as sockets, enabling significantly lower latency and higher throughput when compared to system calls. Furthermore, these APIs are often limited to supporting only TCP and UDP. A library or user may therefore choose to define an executor type that represents this API as a venue for I/O execution:

class vendor_xyz_kernel_bypass_executor { // ... };

and specialize the socket templates for this executor type:

template<> class basic_socket<ip::tcp, vendor_xyz_kernel_bypass_executor> { // ... }; template<> class basic_datagram_socket<ip::tcp, vendor_xyz_kernel_bypass_executor> : public basic_socket<ip::tcp, vendor_xyz_kernel_bypass_executor> { // ... template<class ConstBufferSequence> void send(const ConstBufferSequence& buffers) { // Implemented using vendor_xyz_send(). // ... } // ... };

3. Overview of changes to specification

Addition of Executor template parameter

A new Executor template parameter is added to the following templates:

basic_waitable_timer

basic_socket

basic_datagram_socket

basic_stream_socket

basic_socket_acceptor

basic_socket_streambuf

basic_socket_iostream

ip::basic_resolver

To enable convenient interoperability with arbitrary executors and execution contexts, the template parameter is defaulted to the executor polymorphic wrapper. For example:

template <class Protocol , class Executor = executor > class basic_socket;

For each of:

basic_waitable_timer

basic_socket

basic_socket_acceptor

ip::basic_resolver

the existing nested type executor_type is altered to refer to the Executor type:

template <class Protocol, class Executor> class basic_socket : public socket_base { public: using executor_type = io_context::executor_type Executor ; // ... };

For the remaining four templates:

basic_datagram_socket

basic_stream_socket

basic_socket_streambuf

basic_socket_iostream

the nested type executor_type is added:

template <class Protocol, class Executor> class basic_stream_socket : public basic_socket<Protocol, Executor> { public: using executor_type = Executor ; // ... };

Addition of nested template type alias rebind_executor

For each of the following templates:

basic_waitable_timer

basic_socket

basic_datagram_socket

basic_stream_socket

basic_socket_acceptor

ip::basic_resolver

a nested template type alias rebind_executor is added: template<class Protocol, class Executor> class basic_socket : public socket_base { // ... /// The socket type when rebound to the specified executor. template<class OtherExecutor> using rebind_executor = basic_socket<Protocol, OtherExecutor>; // ... };

This enables computation of the appropriate class type for different I/O executor types.

Modification of I/O objects' constructors

For each of the following templates:

basic_waitable_timer

basic_socket

basic_datagram_socket

basic_stream_socket

basic_socket_acceptor

ip::basic_resolver

every constructor with an io_context& parameter is replaced with two constructors:

template<class Protocol, class Executor> class basic_socket : public socket_base { // ... basic_socket(io_context& ctx, const protocol_type& protocol); basic_socket(const executor_type& ex, const protocol_type& protocol); template<class ExecutionContext> basic_socket(ExecutionContext& ctx, const protocol_type& protocol); // ... };

The second of these constructors shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true , and is_constructible<executor_type, typename ExecutionContext::executor_type>::value is true .

Modification of I/O objects' converting constructors

An OtherExecutor template parameter is added as required to the converting move constructors of the following classes:

basic_socket

basic_datagram_socket

basic_stream_socket

basic_socket_acceptor

For example:

template<class Protocol, class Executor> class basic_socket : public socket_base { // ... template<class OtherProtocol , class OtherExecutor > basic_socket(basic_socket<OtherProtocol , OtherExecutor >&& rhs); // ... };

This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol , and OtherExecutor is implicitly convertible to Executor .

Modification of I/O objects' converting assignment operators

An OtherExecutor template parameter is added as required to the converting move assignment operators of the following classes:

basic_socket

basic_datagram_socket

basic_stream_socket

basic_socket_acceptor

For example:

template<class Protocol, class Executor> class basic_socket : public socket_base { // ... template<class OtherProtocol , class OtherExecutor > basic_socket& operator=(basic_socket<OtherProtocol , OtherExecutor >&& rhs); // ... };

This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol , and OtherExecutor is implicitly convertible to Executor .

Addition of template type alias to basic_socket_acceptor for rebinding a socket's executor The template basic_socket_acceptor gains a new nested template type alias rebind_socket_executor : template<class AcceptableProtocol, class Executor> class basic_socket_acceptor : public socket_base { // ... /// The socket type when rebound to the specified executor. template<class OtherExecutor> using rebind_socket_executor = typename AcceptableProtocol::socket::template rebind_executor<OtherExecutor>; // ... }; This enables computation of the appropriate socket type produced when accepting on different I/O executor types.

Modification of basic_socket_acceptor member functions

Every overload of member functions accept and async_accept with an io_context& parameter is replaced with two overloads:

template<class AcceptableProtocol, class Executor> class basic_socket_acceptor : public socket_base { // ... socket_type accept(io_context& ctx); template<class OtherExecutor> rebind_socket_executor<OtherExecutor> accept(const OtherExecutor& ex); template<class ExecutionContext> rebind_socket_executor<typename ExecutionContext::executor_type> accept(ExecutionContext& ctx); // ... };

The second of these overloads shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true , and is_constructible<executor_type, typename ExecutionContext::executor_type>::value is true .

Modification of connect and async_connect functions

An Executor template parameter is added as required to the connect and async_connect functions. For example:

template<class Protocol , class Executor , class EndpointSequence> typename Protocol::endpoint connect(basic_socket<Protocol , Executor >& s, const EndpointSequence& endpoints);

Modification of basic_socket_streambuf

The basic_socket_streambuf default constructor is modified so that it shall not participate in overload resolution unless is_constructible<executor_type, io_context::executor_type>::value is true .

Modification of basic_socket_iostream

The basic_socket_iostream specification is modified so that the executor_type type is passed to all uses of basic_socket_streambuf , as required. The basic_socket_iostream default constructor is modified so that it shall not participate in overload resolution unless is_default_constructible<basic_socket_streambuf<protocol_type, clock_type, wait_traits_type, executor_type>>::value is true .

4. Possible implementation approach

This section is intended to provide implementation suggestions only, and is not intended to be prescriptive or exhaustive.

Provision of default implementation

Implementations may use an execution context service as a container for the backend implementation.

class __socket_backend : public execution_context::service { // ... };

This service would be "used" by an I/O object implementation, and is automatically created on first use:

template <class Protocol, class Executor> class basic_socket : public socket_base { public: using executor_type = Executor; // ... explicit basic_socket(const executor_type& ex) { auto& backend = use_service<__socket_backend>(ex.context()); // ... } // ... };

This allows the I/O object to be used with arbitrary execution contexts.

Native implementations

A native execution context preemptively performs service creation by calling make_service . It can use this opportunity to pass additional constructor arguments that initialise the backend in the native mode, rather than the default:

class io_context : public execution_context { public: // ... io_context() { make_service<__socket_backend>(*this, __io_context_backend_tag{}); } // ... };

Alternatively, implementations may use a class hierarchy of services, and virtual functions, to select the desired behaviour:

class __socket_backend : public execution_context::service { public: using key_type = __socket_backend; // ... virtual void backend_function(/* ... */); // ... }; class __io_socket_backend : public __socket_backend { public: // ... void backend_function(/* ... */) override; // ... }; class io_context : public execution_context { public: // ... io_context() { make_service<__io_socket_backend>(*this); } // ... };

In both approaches, the existing service, with its native backend, is obtained by the I/O object constructor.

Performance impact

Specification of the polymorphic executor as the default I/O executor, while improving usability, has a non-zero impact on performance. This impact can be mitigated by having an I/O object's constructor detect its own well-known native executor types (e.g. by using executor::target_type ). With this information, the overhead can then be limited to simple branching, rather than the memory allocations and virtual functions that would likely be required for the type-erased function objects.

Users can avoid this overhead completely by explicitly specifying the I/O executor type:

io_context my_context; basic_stream_socket<tcp, io_context::executor_type> my_socket(my_context);

5. Implementation experience

This design change was implemented in Asio 1.13.0, and was delivered in the Boost 1.70 release as the stable Asio version 1.14.0.

6. Proposed changes to wording

These changes are relative to N4771.

Update the <experimental/netfwd> synopsis [fwd.decl.synop] as follows:

12.1 Header <experimental/netfwd> synopsis [fwd.decl.synop] namespace std { namespace experimental { namespace net { inline namespace v1 { class execution_context; template < class T, class Executor > class executor_binder; template < class Executor > class executor_work_guard; class system_executor; class executor; template < class Executor > class strand; class io_context; template < class Clock > struct wait_traits; template < class Clock, class WaitTraits = wait_traits < Clock > , class Executor = executor > class basic_waitable_timer; using system_timer = basic_waitable_timer < chrono :: system_clock > ; using steady_timer = basic_waitable_timer < chrono :: steady_clock > ; using high_resolution_timer = basic_waitable_timer < chrono :: high_resolution_clock > ; template < class Protocol , class Executor = executor > class basic_socket; template < class Protocol , class Executor = executor > class basic_datagram_socket; template < class Protocol , class Executor = executor > class basic_stream_socket; template < class Protocol , class Executor = executor > class basic_socket_acceptor; template < class Protocol, class Clock = chrono :: steady_clock, class WaitTraits = wait_traits < Clock > , class Executor = executor > class basic_socket_streambuf; template < class Protocol, class Clock = chrono :: steady_clock, class WaitTraits = wait_traits < Clock > , class Executor = executor > class basic_socket_iostream; namespace ip { class address; class address_v4; class address_v6; template < class Address > class basic_address_iterator; using address_v4_iterator = basic_address_iterator < address_v4 > ; using address_v6_iterator = basic_address_iterator < address_v6 > ; template < class Address > class basic_address_range; using address_v4_range = basic_address_range < address_v4 > ; using address_v6_range = basic_address_range < address_v6 > ; class network_v4; class network_v6; template < class InternetProtocol > class basic_endpoint; template < class InternetProtocol > class basic_resolver_entry; template < class InternetProtocol > class basic_resolver_results; template < class InternetProtocol , class Executor = executor > class basic_resolver; class tcp; class udp; } } } } }

Update the <experimental/timer> synopsis [timer.synop] as follows:

[...]

template < class Clock, class WaitTraits = wait_traits < Clock > , class Executor = executor > class basic_waitable_timer;

Update the class template basic_waitable_timer [timer.waitable] as follows:

15.4 Class template basic_­waitable_­timer [timer.waitable] namespace std { namespace experimental { namespace net { inline namespace v1 { template < class Clock, class WaitTraits = wait_traits < Clock > , class Executor = executor > class basic_waitable_timer { public : using executor_type = io_­context ​::​ executor_­type Executor ; using clock_type = Clock; using duration = typename clock_type :: duration; using time_point = typename clock_type :: time_point; using traits_type = WaitTraits; template < class OtherExecutor > using rebind_­executor = basic_­waitable_­timer < Clock, WaitTraits, OtherExecutor > ; explicit basic_waitable_timer ( io_­context & ctx const executor_­type & ex ) ; template < class ExecutionContext > explicit basic_­waitable_­timer ( ExecutionContext & ctx ) ; basic_waitable_timer ( io_­context & ctx const executor_­type & ex , const time_point & t ) ; template < class ExecutionContext > basic_­waitable_­timer ( ExecutionContext & ctx, const time_­point & t ) ; basic_waitable_timer ( io_­context & ctx const executor_­type & ex , const duration & d ) ; template < class ExecutionContext > basic_­waitable_­timer ( ExecutionContext & ctx, const duration & d ) ; basic_waitable_timer ( const basic_waitable_timer & ) = delete ; basic_waitable_timer ( basic_waitable_timer & & rhs ) ;

Update the basic_waitable_timer constructors [timer.waitable.cons] as follows:

15.4.1 basic_­waitable_­timer constructors [timer.waitable.cons] ðŸ”— explicit basic_waitable_timer ( io_­context & ctx const executor_­type & ex ) ; 1 # Effects: Equivalent to basic_­waitable_­timer ( ctx ex , time_­point ( ) ) . Equivalent to ðŸ”— template < class ExecutionContext > explicit basic_­waitable_­timer ( ExecutionContext & ctx ) ; Effects: Equivalent to basic_­waitable_­timer ( ctx . get_­executor ( ) ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_waitable_timer ( io_­context & ctx const executor_­type & ex , const time_point & t ) ; 2 # Postconditions: (2.1) get_­executor ( ) = = ctx.get_executor ( ) ex .

. (2.2) expiry ( ) = = t . ðŸ”— template < class ExecutionContext > basic_­waitable_­timer ( ExecutionContext & ctx, const time_­point & t ) ; Effects: Equivalent to basic_­waitable_­timer ( ctx . get_­executor ( ) , t ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_waitable_timer ( io_­context & ctx const executor_­type & ex , const duration & d ) ; 3 # Effects: Sets the expiry time as if by calling expires_­after ( d ) . Sets the expiry time as if by calling 4 # Postconditions: get_­executor ( ) = = ctx.get_executor ( ) ex . ðŸ”— template < class ExecutionContext > basic_­waitable_­timer ( ExecutionContext & ctx, const duration & d ) ; Effects: Equivalent to basic_­waitable_­timer ( ctx . get_­executor ( ) , d ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true .

Update the <experimental/socket> synopsis [socket.synop] as follows:

18.1 Header <experimental/socket> synopsis [socket.synop] namespace std { namespace experimental { namespace net { inline namespace v1 { enum class socket_errc { already_open = animplementation-defined non-zero value = animplementation-defined non-zero value } ; const error_category & socket_category ( ) noexcept ; error_code make_error_code ( socket_errc e ) noexcept ; error_condition make_error_condition ( socket_errc e ) noexcept ; class socket_base; template < class Protocol , class Executor = executor > class basic_socket; template < class Protocol , class Executor = executor > class basic_datagram_socket; template < class Protocol , class Executor = executor > class basic_stream_socket; template < class Protocol , class Executor = executor > class basic_socket_acceptor; template < class Protocol, class Clock = chrono :: steady_clock, class WaitTraits = wait_traits < Clock > , class Executor = executor > class basic_socket_streambuf; template < class Protocol, class Clock = chrono :: steady_clock, class WaitTraits = wait_traits < Clock > , class Executor = executor > class basic_socket_iostream; template < class Protocol , class Executor , class EndpointSequence > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints ) ; template < class Protocol , class Executor , class EndpointSequence > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, error_code & ec ) ; template < class Protocol , class Executor , class EndpointSequence, class ConnectCondition > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, ConnectCondition c ) ; template < class Protocol , class Executor , class EndpointSequence, class ConnectCondition > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, ConnectCondition c, error_code & ec ) ; template < class Protocol , class Executor , class InputIterator > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last ) ; template < class Protocol , class Executor , class InputIterator > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, error_code & ec ) ; template < class Protocol , class Executor , class InputIterator, class ConnectCondition > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, ConnectCondition c ) ; template < class Protocol , class Executor , class InputIterator, class ConnectCondition > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, ConnectCondition c, error_code & ec ) ; template < class Protocol , class Executor , class EndpointSequence, class CompletionToken > DEDUCED async_connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, CompletionToken & & token ) ; template < class Protocol , class Executor , class EndpointSequence, class ConnectCondition, class CompletionToken > DEDUCED async_connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, ConnectCondition c, CompletionToken & & token ) ; template < class Protocol , class Executor , class InputIterator, class CompletionToken > DEDUCED async_connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, CompletionToken & & token ) ; template < class Protocol , class Executor , class InputIterator, class ConnectCondition, class CompletionToken > DEDUCED async_connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, ConnectCondition c, CompletionToken & & token ) ; } } } template < > struct is_error_code_enum < experimental :: net :: v1 :: socket_errc > : public true_type { } ; }

Update the class socket_base [socket.base] as follows:

18.4 Class socket_­base [socket.base] namespace std { namespace experimental { namespace net { inline namespace v1 { class socket_base { public : class broadcast; class debug; class do_not_route; class keep_alive; class linger; class out_of_band_inline; class receive_buffer_size; class receive_low_watermark; class reuse_address; class send_buffer_size; class send_low_watermark; using shutdown_type = T1 ; static constexpr shutdown_type shutdown_receive; static constexpr shutdown_type shutdown_send; static constexpr shutdown_type shutdown_both; using wait_type = T2 ; static constexpr wait_type wait_read; static constexpr wait_type wait_write; static constexpr wait_type wait_error; using message_flags = T3 ; static constexpr message_flags message_peek; static constexpr message_flags message_out_of_band; static constexpr message_flags message_do_not_route; static const int max_listen_connections; protected : socket_base ( ) ; ~ socket_base ( ) ; } ; } } } } 1 # socket_­base defines several member types: (1.1) broadcast , debug , do_­not_­route , keep_­alive , linger , out_­of_­band_­inline , receive_­buffer_­size , receive_­low_­watermark , reuse_­address , send_­buffer_­size , and send_­low_­watermark ;

, , , , , , , , , , and ; (1.2) shutdown_­type , for use with the basic_­socket < Protocol , Executor > class's shutdown member function.

, for use with the class's member function. (1.3) wait_­type , for use with the basic_­socket < Protocol , Executor > and basic_­socket_­acceptor < Protocol , Executor > classes' wait and async_­wait member functions,

, for use with the and classes' and member functions, (1.4) message_­flags , for use with the basic_­stream_­socket < Protocol , Executor > class's send , async_­send , receive , and async_­receive member functions, and the basic_­datagram_­socket < Protocol > class's send , async_­send , send_­to , async_­send_­to , receive , async_­receive , receive_­from , and async_­receive_­from member functions.

, for use with the class's , , , and member functions, and the class's , , , , , , , and member functions. (1.5) max_­listen_­connections , for use with the basic_­socket_­acceptor < Protocol , Executor > class's listen member function. defines several member types:

Update the class template basic_socket [socket.basic] as follows:

18.6 Class template basic_­socket [socket.basic] 1 # basic_­socket < Protocol , Executor > is used as the base class for the basic_­datagram_­socket < Protocol , Executor > and basic_­stream_­socket < Protocol , Executor > class templates. It provides functionality that is common to both types of socket. namespace std { namespace experimental { namespace net { inline namespace v1 { template < class Protocol , class Executor > class basic_socket : public socket_base { public : using executor_type = io_­context ​::​ executor_­type Executor ; using native_handle_type = implementation-defined ; using protocol_type = Protocol; using endpoint_type = typename protocol_type :: endpoint; template < class OtherExecutor > using rebind_­executor = basic_­socket < Protocol, OtherExecutor > ; executor_type get_executor ( ) noexcept ; native_handle_type native_handle ( ) ; void open ( const protocol_type & protocol = protocol_type ( ) ) ; void open ( const protocol_type & protocol, error_code & ec ) ; void assign ( const protocol_type & protocol, const native_handle_type & native_socket ) ; void assign ( const protocol_type & protocol, const native_handle_type & native_socket, error_code & ec ) ; native_handle_type release ( ) ; native_handle_type release ( error_code & ec ) ; bool is_open ( ) const noexcept ; void close ( ) ; void close ( error_code & ec ) ; void cancel ( ) ; void cancel ( error_code & ec ) ; template < class SettableSocketOption > void set_option ( const SettableSocketOption & option ) ; template < class SettableSocketOption > void set_option ( const SettableSocketOption & option, error_code & ec ) ; template < class GettableSocketOption > void get_option ( GettableSocketOption & option ) const ; template < class GettableSocketOption > void get_option ( GettableSocketOption & option, error_code & ec ) const ; template < class IoControlCommand > void io_control ( IoControlCommand & command ) ; template < class IoControlCommand > void io_control ( IoControlCommand & command, error_code & ec ) ; void non_blocking ( bool mode ) ; void non_blocking ( bool mode, error_code & ec ) ; bool non_blocking ( ) const ; void native_non_blocking ( bool mode ) ; void native_non_blocking ( bool mode, error_code & ec ) ; bool native_non_blocking ( ) const ; bool at_mark ( ) const ; bool at_mark ( error_code & ec ) const ; size_t available ( ) const ; size_t available ( error_code & ec ) const ; void bind ( const endpoint_type & endpoint ) ; void bind ( const endpoint_type & endpoint, error_code & ec ) ; void shutdown ( shutdown_type what ) ; void shutdown ( shutdown_type what, error_code & ec ) ; endpoint_type local_endpoint ( ) const ; endpoint_type local_endpoint ( error_code & ec ) const ; endpoint_type remote_endpoint ( ) const ; endpoint_type remote_endpoint ( error_code & ec ) const ; void connect ( const endpoint_type & endpoint ) ; void connect ( const endpoint_type & endpoint, error_code & ec ) ; template < class CompletionToken > DEDUCED async_connect ( const endpoint_type & endpoint, CompletionToken & & token ) ; void wait ( wait_type w ) ; void wait ( wait_type w, error_code & ec ) ; template < class CompletionToken > DEDUCED async_wait ( wait_type w, CompletionToken & & token ) ; protected : explicit basic_socket ( io_­context & ctx const executor_­type & ex ) ; template < class ExecutionContext > explicit basic_­socket ( ExecutionContext & ctx ) ; basic_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; template < class ExecutionContext > basic_­socket ( ExecutionContext & ctx, const protocol_­type & protocol ) ; basic_socket ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint ) ; template < class ExecutionContext > basic_­socket ( ExecutionContext & ctx, const endpoint_­type & endpoint ) ; basic_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol, const native_handle_type & native_socket ) ; template < class ExecutionContext > basic_­socket ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; basic_socket ( const basic_socket & ) = delete ; basic_socket ( basic_socket & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_socket ( basic_socket < OtherProtocol , OtherExecutor > & & rhs ) ; ~ basic_socket ( ) ; basic_socket & operator = ( const basic_socket & ) = delete ; basic_socket & operator = ( basic_socket & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_socket & operator = ( basic_socket < OtherProtocol , OtherExecutor > & & rhs ) ; private : protocol_type protocol_; } ; } } } } Class templateis used as the base class for theandclass templates. It provides functionality that is common to both types of socket.

Update the basic_socket constructors [socket.basic.cons] as follows:

18.6.1 basic_­socket constructors [socket.basic.cons] ðŸ”— explicit basic_socket ( io_­context & ctx const executor_­type & ex ) ; 1 # Postconditions: (1.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (1.2) is_­open ( ) = = false . ðŸ”— template < class ExecutionContext > explicit basic_­socket ( ExecutionContext & ctx ) ; Effects: Equivalent to basic_­socket ( ctx . get_­executor ( ) ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; 2 # Effects: Opens this socket as if by calling open ( protocol ) . Opens this socket as if by calling 3 # Postconditions: (3.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (3.2) is_­open ( ) = = true .

. (3.3) non_­blocking ( ) = = false .

. (3.4) protocol_­ = = protocol . ðŸ”— template < class ExecutionContext > explicit basic_­socket ( ExecutionContext & ctx, const protocol_­type & protocol ) ; Effects: Equivalent to basic_­socket ( ctx . get_­executor ( ) , protocol ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint ) ; 4 # Effects: Opens and binds this socket as if by calling: open ( endpoint . protocol ( ) ) ; bind ( endpoint ) ; Opens and binds this socket as if by calling: 5 # Postconditions: (5.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (5.2) is_­open ( ) = = true .

. (5.3) non_­blocking ( ) = = false .

. (5.4) protocol_­ = = endpoint . protocol ( ) . ðŸ”— template < class ExecutionContext > explicit basic_­socket ( ExecutionContext & ctx, const endpoint_­type & endpoint ) ; Effects: Equivalent to basic_­socket ( ctx . get_­executor ( ) , endpoint ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol, const native_handle_type & native_socket ) ; 6 # Requires: native_­socket is a native handle to an open socket. is a native handle to an open socket. 7 # Effects: Assigns the existing native socket into this socket as if by calling assign ( protocol, native_­socket ) . Assigns the existing native socket into this socket as if by calling 8 # Postconditions: (8.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (8.2) is_­open ( ) = = true .

. (8.3) non_­blocking ( ) = = false .

. (8.4) protocol_­ = = protocol . ðŸ”— template < class ExecutionContext > basic_­socket ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; Effects: Equivalent to basic_­socket ( ctx . get_­executor ( ) , protocol, native_­socket ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket ( basic_socket & & rhs ) ; 9 # Effects: Move constructs an object of class basic_­socket < Protocol , Executor > that refers to the state originally represented by rhs . Move constructs an object of classthat refers to the state originally represented by 10 # Postconditions: (10.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (10.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (10.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (10.4) native_­handle ( ) returns the prior value of rhs . native_­handle ( ) .

returns the prior value of . (10.5) protocol_­ is the prior value of rhs . protocol_­ .

is the prior value of . (10.6) rhs . is_­open ( ) = = false . ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_socket ( basic_socket < OtherProtocol , OtherExecutor > & & rhs ) ; 11 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 12 # Effects: Move constructs an object of class basic_­socket < Protocol , Executor > that refers to the state originally represented by rhs . Move constructs an object of classthat refers to the state originally represented by 13 # Postconditions: (13.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (13.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (13.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (13.4) native_­handle ( ) returns the prior value of rhs . native_­handle ( ) .

returns the prior value of . (13.5) protocol_­ is the result of converting the prior value of rhs . protocol_­ .

is the result of converting the prior value of . (13.6) rhs . is_­open ( ) = = false . 14 # Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This constructor shall not participate in overload resolution unlessis implicitly convertible to

Update the basic_socket assignment operators [socket.basic.assign] as follows:

18.6.3 basic_­socket assignment [socket.basic.assign] ðŸ”— basic_socket & operator = ( basic_socket & & rhs ) ; 1 # Effects: If is_­open ( ) is true , cancels all outstanding asynchronous operations associated with this socket. Completion handlers for canceled operations are passed an error code ec such that ec = = errc ​::​ operation_­canceled yields true . Disables the linger socket option to prevent the assignment from blocking, and releases socket resources as if by POSIX close ( native_­handle ( ) ) . Moves into * this the state originally represented by rhs . Ifis, cancels all outstanding asynchronous operations associated with this socket. Completion handlers for canceled operations are passed an error codesuch thatyields. Disables the linger socket option to prevent the assignment from blocking, and releases socket resources as if by POSIX. Moves intothe state originally represented by 2 # Postconditions: (2.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (2.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the assignment.

returns the same value as prior to the assignment. (2.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the assignment.

returns the same value as prior to the assignment. (2.4) protocol_­ is the prior value of rhs . protocol_­ .

is the prior value of . (2.5) rhs . is_­open ( ) = = false . 3 # Returns: * this . ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_socket & operator = ( basic_socket < OtherProtocol , OtherExecutor > & & rhs ) ; 4 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 5 # Effects: If is_­open ( ) is true , cancels all outstanding asynchronous operations associated with this socket. Completion handlers for canceled operations are passed an error code ec such that ec = = errc ​::​ operation_­canceled yields true . Disables the linger socket option to prevent the assignment from blocking, and releases socket resources as if by POSIX close ( native_­handle ( ) ) . Moves into * this the state originally represented by rhs . Ifis, cancels all outstanding asynchronous operations associated with this socket. Completion handlers for canceled operations are passed an error codesuch thatyields. Disables the linger socket option to prevent the assignment from blocking, and releases socket resources as if by POSIX. Moves intothe state originally represented by 6 # Postconditions: (6.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (6.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the assignment.

returns the same value as prior to the assignment. (6.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the assignment.

returns the same value as prior to the assignment. (6.4) protocol_­ is the result of converting the prior value of rhs . protocol_­ .

is the result of converting the prior value of . (6.5) rhs . is_­open ( ) = = false . 7 # Returns: * this . 8 # Remarks: This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This assignment operator shall not participate in overload resolution unlessis implicitly convertible to

Update the class template basic_datagram_socket [socket.basic] as follows:

18.7 Class template basic_­datagram_­socket [socket.dgram] 1 # basic_­datagram_­socket < Protocol , Executor > is used to send and receive discrete messages of fixed maximum length. namespace std { namespace experimental { namespace net { inline namespace v1 { template < class Protocol , class Executor > class basic_datagram_socket : public basic_socket < Protocol , Executor > { public : using executor_­type = Executor; using native_handle_type = implementation-defined ; using protocol_type = Protocol; using endpoint_type = typename protocol_type :: endpoint; template < class OtherExecutor > using rebind_­executor = basic_­datagram_­socket < Protocol, OtherExecutor > ; explicit basic_datagram_socket ( io_­context & ctx const executor_­type & ex ) ; template < class ExecutionContext > explicit basic_­datagram_­socket ( ExecutionContext & ctx ) ; basic_datagram_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; template < class ExecutionContext > basic_­datagram_­socket ( ExecutionContext & ctx, const protocol_­type & protocol ) ; basic_datagram_socket ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint ) ; template < class ExecutionContext > basic_­datagram_­socket ( ExecutionContext & ctx, const endpoint_­type & endpoint ) ; basic_datagram_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol, const native_handle_type & native_socket ) ; template < class ExecutionContext > basic_­datagram_­socket ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; basic_datagram_socket ( const basic_datagram_socket & ) = delete ; basic_datagram_socket ( basic_datagram_socket & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_datagram_socket ( basic_datagram_socket < OtherProtocol , OtherExecutor > & & rhs ) ; ~ basic_datagram_socket ( ) ; basic_datagram_socket & operator = ( const basic_datagram_socket & ) = delete ; basic_datagram_socket & operator = ( basic_datagram_socket & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_datagram_socket & operator = ( basic_datagram_socket < OtherProtocol , OtherExecutor > & & rhs ) ; The class templateis used to send and receive discrete messages of fixed maximum length.

[...]

6 # native_­handle_­type and basic_­socket < Protocol , Executor > ​::​ native_­handle_­type are both defined then they name the same type. Ifandare both defined then they name the same type.

Update the basic_datagram_socket constructors [socket.dgram.cons] as follows:

18.7.1 basic_­datagram_­socket constructors [socket.dgram.cons] ðŸ”— explicit basic_datagram_socket ( io_­context & ctx const executor_­type & ex ) ; 1 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx ex ) . Initializes the base class with ðŸ”— template < class ExecutionContext > explicit basic_­datagram_­socket ( ExecutionContext & ctx ) ; Effects: Equivalent to basic_­datagram_­socket ( ctx . get_­executor ( ) ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_datagram_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; 2 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx, protocol ) . Initializes the base class with ðŸ”— template < class ExecutionContext > explicit basic_­datagram_­socket ( ExecutionContext & ctx, const protocol_­type & protocol ) ; Effects: Equivalent to basic_­datagram_­socket ( ctx . get_­executor ( ) , protocol ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_datagram_socket ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint ) ; 3 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx, endpoint ) . Initializes the base class with ðŸ”— template < class ExecutionContext > explicit basic_­datagram_­socket ( ExecutionContext & ctx, const endpoint_­type & endpoint ) ; Effects: Equivalent to basic_­datagram_­socket ( ctx . get_­executor ( ) , endpoint ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_datagram_socket ( io_context & ctx, const protocol_type & protocol, const native_handle_type & native_socket ) ; 4 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx, protocol, native_­socket ) . Initializes the base class with ðŸ”— template < class ExecutionContext > basic_­datagram_­socket ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; Effects: Equivalent to basic_­datagram_­socket ( ctx . get_­executor ( ) , protocol, native_­socket ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_datagram_socket ( basic_datagram_socket & & rhs ) ; 5 # Effects: Move constructs an object of class basic_­datagram_­socket < Protocol , Executor > , initializing the base class with basic_­socket < Protocol , Executor > ( std ​::​ move ( rhs ) ) . Move constructs an object of class, initializing the base class with ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_datagram_socket ( basic_datagram_socket < OtherProtocol , OtherExecutor > & & rhs ) ; 6 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 7 # Effects: Move constructs an object of class basic_­datagram_­socket < Protocol , Executor > , initializing the base class with basic_­socket < Protocol , Executor > ( std ​::​ move ( rhs ) ) . Move constructs an object of class, initializing the base class with 8 # Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This constructor shall not participate in overload resolution unlessis implicitly convertible to

Update the basic_datagram_socket assignment operators [socket.dgram.assign] as follows:

18.7.2 basic_­datagram_­socket assignment [socket.dgram.assign] ðŸ”— basic_datagram_socket & operator = ( basic_datagram_socket & & rhs ) ; 1 # Effects: Equivalent to basic_­socket < Protocol , Executor > ​::​ operator = ( std ​::​ move ( rhs ) ) . Equivalent to 2 # Returns: * this . ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_datagram_socket & operator = ( basic_datagram_socket < OtherProtocol , OtherExecutor > & & rhs ) ; 3 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 4 # Effects: Equivalent to basic_­socket < Protocol , Executor > ​::​ operator = ( std ​::​ move ( rhs ) ) . Equivalent to 5 # Returns: * this . 6 # Remarks: This assignment operator not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This assignment operator not participate in overload resolution unlessis implicitly convertible to

Update the class template basic_stream_socket [socket.stream] as follows:

18.8 Class template basic_­stream_­socket [socket.stream] 1 # basic_­stream_­socket < Protocol , Executor > is used to exchange data with a peer over a sequenced, reliable, bidirectional, connection-mode byte stream. namespace std { namespace experimental { namespace net { inline namespace v1 { template < class Protocol , class Executor > class basic_stream_socket : public basic_socket < Protocol , Executor > { public : using executor_­type = Executor; using native_handle_type = implementation-defined ; using protocol_type = Protocol; using endpoint_type = typename protocol_type :: endpoint; template < class OtherExecutor > using rebind_­executor = basic_­stream_­socket < Protocol, OtherExecutor > ; explicit basic_stream_socket ( io_­context & ctx const executor_­type & ex ) ; template < class ExecutionContext > explicit basic_­stream_­socket ( ExecutionContext & ctx ) ; basic_stream_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; template < class ExecutionContext > basic_­stream_­socket ( ExecutionContext & ctx, const protocol_­type & protocol ) ; basic_stream_socket ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint ) ; template < class ExecutionContext > basic_­stream_­socket ( ExecutionContext & ctx, const endpoint_­type & endpoint ) ; basic_stream_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol, const native_handle_type & native_socket ) ; template < class ExecutionContext > basic_­stream_­socket ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; basic_stream_socket ( const basic_stream_socket & ) = delete ; basic_stream_socket ( basic_stream_socket & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_stream_socket ( basic_stream_socket < OtherProtocol , OtherExecutor > & & rhs ) ; ~ basic_stream_socket ( ) ; basic_stream_socket & operator = ( const basic_stream_socket & ) = delete ; basic_stream_socket & operator = ( basic_stream_socket & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_stream_socket & operator = ( basic_stream_socket < OtherProtocol , OtherExecutor > & & rhs ) ; The class templateis used to exchange data with a peer over a sequenced, reliable, bidirectional, connection-mode byte stream.

[...]

6 # native_­handle_­type and basic_­socket < Protocol , Executor > ​::​ native_­handle_­type are both defined then they name the same type. Ifandare both defined then they name the same type.

Update the basic_stream_socket constructors [socket.stream.cons] as follows:

18.8.1 basic_­stream_­socket constructors [socket.stream.cons] ðŸ”— explicit basic_stream_socket ( io_­context & ctx const executor_­type & ex ) ; 1 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx ) . Initializes the base class with ðŸ”— template < class ExecutionContext > explicit basic_­stream_­socket ( ExecutionContext & ctx ) ; Effects: Equivalent to basic_­stream_­socket ( ctx . get_­executor ( ) ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_stream_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; 2 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx, protocol ) . Initializes the base class with ðŸ”— template < class ExecutionContext > explicit basic_­stream_­socket ( ExecutionContext & ctx, const protocol_­type & protocol ) ; Effects: Equivalent to basic_­stream_­socket ( ctx . get_­executor ( ) , protocol ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_stream_socket ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint ) ; 3 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx, endpoint ) . Initializes the base class with ðŸ”— template < class ExecutionContext > explicit basic_­stream_­socket ( ExecutionContext & ctx, const endpoint_­type & endpoint ) ; Effects: Equivalent to basic_­stream_­socket ( ctx . get_­executor ( ) , endpoint ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_stream_socket ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol, const native_handle_type & native_socket ) ; 4 # Effects: Initializes the base class with basic_­socket < Protocol , Executor > ( ctx, protocol, native_­socket ) . Initializes the base class with ðŸ”— template < class ExecutionContext > basic_­stream_­socket ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; Effects: Equivalent to basic_­stream_­socket ( ctx . get_­executor ( ) , protocol, native_­socket ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_stream_socket ( basic_stream_socket & & rhs ) ; 5 # Effects: Move constructs an object of class basic_­stream_­socket < Protocol , Executor > , initializing the base class with basic_­socket < Protocol , Executor > ( std ​::​ move ( rhs ) ) . Move constructs an object of class, initializing the base class with ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_stream_socket ( basic_stream_socket < OtherProtocol , OtherExecutor > & & rhs ) ; 6 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 7 # Effects: Move constructs an object of class basic_­stream_­socket < Protocol , Executor > , initializing the base class with basic_­socket < Protocol , Executor > ( std ​::​ move ( rhs ) ) . Move constructs an object of class, initializing the base class with 8 # Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This constructor shall not participate in overload resolution unlessis implicitly convertible to

Update the basic_stream_socket assignment operators [socket.stream.assign] as follows:

18.8.2 basic_­stream_­socket assignment [socket.stream.assign] ðŸ”— basic_stream_socket & operator = ( basic_stream_socket & & rhs ) ; 1 # Effects: Equivalent to basic_­socket < Protocol , Executor > ​::​ operator = ( std ​::​ move ( rhs ) ) . Equivalent to 2 # Returns: * this . ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_stream_socket & operator = ( basic_stream_socket < OtherProtocol , OtherExecutor > & & rhs ) ; 3 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 4 # Effects: Equivalent to basic_­socket < Protocol , Executor > ​::​ operator = ( std ​::​ move ( rhs ) ) . Equivalent to 5 # Returns: * this . 6 # Remarks: This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This assignment operator shall not participate in overload resolution unlessis implicitly convertible to

Update the class template basic_socket_acceptor [socket.acceptor] as follows:

18.9 Class template basic_­socket_­acceptor [socket.acceptor] 1 # basic_­socket_­acceptor < AcceptableProtocol , Executor > is used to listen for, and queue, incoming socket connections. Socket objects that represent the incoming connections are dequeued by calling accept or async_­accept . namespace std { namespace experimental { namespace net { inline namespace v1 { template < class AcceptableProtocol , class Executor > class basic_socket_acceptor : public socket_base { public : using executor_type = io_­context ​::​ executor_­type Executor ; using native_handle_type = implementation-defined ; using protocol_type = AcceptableProtocol; using endpoint_type = typename protocol_type :: endpoint; using socket_type = typename protocol_type :: socket; template < class OtherExecutor > using rebind_­executor = basic_­socket_­acceptor < AcceptableProtocol, OtherExecutor > ; template < class OtherExecutor > using rebind_­socket_­executor = typename AcceptableProtocol ​::​ socket ​::​ template rebind_­executor < OtherExecutor > ; explicit basic_socket_acceptor ( io_­context & ctx const executor_­type & ex ) ; template < class ExecutionContext > explicit basic_­socket_­acceptor ( ExecutionContext & ctx ) ; basic_socket_acceptor ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; template < class ExecutionContext > basic_­socket_­acceptor ( ExecutionContext & ctx, const protocol_­type & protocol ) ; basic_socket_acceptor ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint, bool reuse_addr = true ) ; template < class ExecutionContext > basic_­socket_­acceptor ( ExecutionContext & ctx, const endpoint_­type & endpoint, bool reuse_­addr = true ) ; basic_socket_acceptor ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol, const native_handle_type & native_socket ) ; template < class ExecutionContext > basic_­socket_­acceptor ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; basic_socket_acceptor ( const basic_socket_acceptor & ) = delete ; basic_socket_acceptor ( basic_socket_acceptor & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_socket_acceptor ( basic_socket_acceptor < OtherProtocol , OtherExecutor > & & rhs ) ; ~ basic_socket_acceptor ( ) ; basic_socket_acceptor & operator = ( const basic_socket_acceptor & ) = delete ; basic_socket_acceptor & operator = ( basic_socket_acceptor & & rhs ) ; template < class OtherProtocol , class OtherExecutor > basic_socket_acceptor & operator = ( basic_socket_acceptor < OtherProtocol , OtherExecutor > & & rhs ) ; executor_type get_executor ( ) noexcept ; native_handle_type native_handle ( ) ; void open ( const protocol_type & protocol = protocol_type ( ) ) ; void open ( const protocol_type & protocol, error_code & ec ) ; void assign ( const protocol_type & protocol, const native_handle_type & native_acceptor ) ; void assign ( const protocol_type & protocol, const native_handle_type & native_acceptor, error_code & ec ) ; native_handle_type release ( ) ; native_handle_type release ( error_code & ec ) ; bool is_open ( ) const noexcept ; void close ( ) ; void close ( error_code & ec ) ; void cancel ( ) ; void cancel ( error_code & ec ) ; template < class SettableSocketOption > void set_option ( const SettableSocketOption & option ) ; template < class SettableSocketOption > void set_option ( const SettableSocketOption & option, error_code & ec ) ; template < class GettableSocketOption > void get_option ( GettableSocketOption & option ) const ; template < class GettableSocketOption > void get_option ( GettableSocketOption & option, error_code & ec ) const ; template < class IoControlCommand > void io_control ( IoControlCommand & command ) ; template < class IoControlCommand > void io_control ( IoControlCommand & command, error_code & ec ) ; void non_blocking ( bool mode ) ; void non_blocking ( bool mode, error_code & ec ) ; bool non_blocking ( ) const ; void native_non_blocking ( bool mode ) ; void native_non_blocking ( bool mode, error_code & ec ) ; bool native_non_blocking ( ) const ; void bind ( const endpoint_type & endpoint ) ; void bind ( const endpoint_type & endpoint, error_code & ec ) ; void listen ( int backlog = max_listen_connections ) ; void listen ( int backlog, error_code & ec ) ; endpoint_type local_endpoint ( ) const ; endpoint_type local_endpoint ( error_code & ec ) const ; void enable_connection_aborted ( bool mode ) ; bool enable_connection_aborted ( ) const ; socket_type accept ( ) ; socket_type accept ( error_code & ec ) ; socket_­type accept ( io_­context & ctx ) ; socket_­type accept ( io_­context & ctx, error_­code & ec ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex, error_­code & ec ) ; template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx ) ; template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx, error_­code & ec ) ; template < class CompletionToken > DEDUCED async_accept ( CompletionToken & & token ) ; template < class CompletionToken > DEDUCED async_­accept ( io_­context & ctx, CompletionToken & & token ) ; template < class OtherExecutor, class CompletionToken > DEDUCED async_­accept ( const OtherExecutor & ex, CompletionToken & & token ) ; template < class ExecutionContext, class CompletionToken > DEDUCED async_­accept ( ExecutionContext & ctx, CompletionToken & & token ) ; socket_type accept ( endpoint_type & endpoint ) ; socket_type accept ( endpoint_type & endpoint, error_code & ec ) ; socket_­type accept ( io_­context & ctx, endpoint_­type & endpoint ) ; socket_­type accept ( io_­context & ctx, endpoint_­type & endpoint, error_­code & ec ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex, endpoint_­type & endpoint ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex, endpoint_­type & endpoint, error_­code & ec ) ; template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx, endpoint_­type & endpoint ) ; template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx, endpoint_­type & endpoint, error_­code & ec ) ; template < class CompletionToken > DEDUCED async_accept ( endpoint_type & endpoint, CompletionToken & & token ) ; template < class CompletionToken > DEDUCED async_­accept ( io_­context & ctx, endpoint_­type & endpoint, CompletionToken & & token ) ; template < class OtherExecutor, class CompletionToken > DEDUCED async_­accept ( const OtherExecutor & ex, endpoint_­type & endpoint, CompletionToken & & token ) ; template < class ExecutionContext, class CompletionToken > DEDUCED async_­accept ( ExecutionContext & ctx, endpoint_­type & endpoint, CompletionToken & & token ) ; An object of class templateis used to listen for, and queue, incoming socket connections. Socket objects that represent the incoming connections are dequeued by callingor

Update the basic_socket_acceptor constructors [socket.stream.cons] as follows:

18.9.1 basic_­socket_­acceptor constructors [socket.acceptor.cons] ðŸ”— explicit basic_socket_acceptor ( io_­context & ctx const executor_­type & ex ) ; 1 # Postconditions: (1.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (1.2) is_­open ( ) = = false . ðŸ”— template < class ExecutionContext > explicit basic_­socket_­acceptor ( ExecutionContext & ctx ) ; Effects: Equivalent to basic_­socket_­acceptor ( ctx . get_­executor ( ) ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket_acceptor ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol ) ; 2 # Effects: Opens this acceptor as if by calling open ( protocol ) . Opens this acceptor as if by calling 3 # Postconditions: (3.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (3.2) is_­open ( ) = = true .

. (3.3) non_­blocking ( ) = = false .

. (3.4) enable_­connection_­aborted ( ) = = false .

. (3.5) protocol_­ = = protocol . ðŸ”— template < class ExecutionContext > explicit basic_­socket_­acceptor ( ExecutionContext & ctx, const protocol_­type & protocol ) ; Effects: Equivalent to basic_­socket_­acceptor ( ctx . get_­executor ( ) , protocol ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket_acceptor ( io_­context & ctx const executor_­type & ex , const endpoint_type & endpoint, bool reuse_addr = true ) ; 4 # Effects: Opens and binds this acceptor as if by calling: open ( endpoint . protocol ( ) ) ; if ( reuse_addr ) set_option ( reuse_address ( true ) ) ; bind ( endpoint ) ; listen ( ) ; Opens and binds this acceptor as if by calling: 5 # Postconditions: (5.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (5.2) is_­open ( ) = = true .

. (5.3) non_­blocking ( ) = = false .

. (5.4) enable_­connection_­aborted ( ) = = false .

. (5.5) protocol_­ = = endpoint . protocol ( ) . ðŸ”— template < class ExecutionContext > explicit basic_­socket_­acceptor ( ExecutionContext & ctx, const endpoint_­type & endpoint, bool reuse_­addr = true ) ; Effects: Equivalent to basic_­socket_­acceptor ( ctx . get_­executor ( ) , endpoint, reuse_­addr ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket_acceptor ( io_­context & ctx const executor_­type & ex , const protocol_type & protocol, const native_handle_type & native_acceptor ) ; 6 # Requires: native_­acceptor is a native handle to an open acceptor. is a native handle to an open acceptor. 7 # Effects: Assigns the existing native acceptor into this acceptor as if by calling assign ( protocol, native_­acceptor ) . Assigns the existing native acceptor into this acceptor as if by calling 8 # Postconditions: (8.1) get_­executor ( ) = = ctx.get_­executor() ex .

. (8.2) is_­open ( ) = = true .

. (8.3) non_­blocking ( ) = = false .

. (8.4) enable_­connection_­aborted ( ) = = false .

. (8.5) protocol_­ = = protocol . ðŸ”— template < class ExecutionContext > basic_­socket_­acceptor ( ExecutionContext & ctx, const protocol_­type & protocol, const native_­handle_­type & native_­socket ) ; Effects: Equivalent to basic_­socket_­acceptor ( ctx . get_­executor ( ) , protocol, native_­socket ) . Remarks: This function shall not participate in overload resolution unless is_­convertible < ExecutionContext & , execution_­context & > ​::​ value is true and is_­constructible < executor_­type, typename ExecutionContext ​::​ executor_­type > ​::​ value is true . ðŸ”— basic_socket_acceptor ( basic_socket_acceptor & & rhs ) ; 9 # Effects: Move constructs an object of class basic_­socket_­acceptor < AcceptableProtocol , Executor > that refers to the state originally represented by rhs . Move constructs an object of classthat refers to the state originally represented by 10 # Postconditions: (10.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (10.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (10.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (10.4) enable_­connection_­aborted ( ) returns the same value as rhs . enable_­connection_­aborted ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (10.5) native_­handle ( ) returns the same value as rhs . native_­handle ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (10.6) protocol_­ is equal to the prior value of rhs . protocol_­ .

is equal to the prior value of . (10.7) rhs . is_­open ( ) = = false . ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_socket_acceptor ( basic_socket_acceptor < OtherProtocol , OtherExecutor > & & rhs ) ; 11 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 12 # Effects: Move constructs an object of class basic_­socket_­acceptor < AcceptableProtocol , Executor > that refers to the state originally represented by rhs . Move constructs an object of classthat refers to the state originally represented by 13 # Postconditions: (13.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (13.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (13.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (13.4) enable_­connection_­aborted ( ) returns the same value as rhs . enable_­connection_­aborted ( ) prior to the constructor invocation.

returns the same value as prior to the constructor invocation. (13.5) native_­handle ( ) returns the prior value of rhs . native_­handle ( ) .

returns the prior value of . (13.6) protocol_­ is the result of converting the prior value of rhs . protocol_­ .

is the result of converting the prior value of . (13.7) rhs . is_­open ( ) = = false . 14 # Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This constructor shall not participate in overload resolution unlessis implicitly convertible to

Update the basic_socket_acceptor assignment operators [socket.stream.assign] as follows:

18.9.3 basic_­socket_­acceptor assignment [socket.acceptor.assign] ðŸ”— basic_socket_acceptor & operator = ( basic_socket_acceptor & & rhs ) ; 1 # Effects: If is_­open ( ) is true , cancels all outstanding asynchronous operations associated with this acceptor, and releases acceptor resources as if by POSIX close ( native_­handle ( ) ) . Then moves into * this the state originally represented by rhs . Completion handlers for canceled operations are passed an error code ec such that ec = = errc ​::​ operation_­canceled yields true . Ifis, cancels all outstanding asynchronous operations associated with this acceptor, and releases acceptor resources as if by POSIX. Then moves intothe state originally represented by. Completion handlers for canceled operations are passed an error codesuch thatyields 2 # Postconditions: (2.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (2.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the assignment.

returns the same value as prior to the assignment. (2.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the assignment.

returns the same value as prior to the assignment. (2.4) enable_­connection_­aborted ( ) returns the same value as rhs . enable_­connection_­aborted ( ) prior to the assignment.

returns the same value as prior to the assignment. (2.5) native_­handle ( ) returns the same value as rhs . native_­handle ( ) prior to the assignment.

returns the same value as prior to the assignment. (2.6) protocol_­ is the same value as rhs . protocol_­ prior to the assignment.

is the same value as prior to the assignment. (2.7) rhs . is_­open ( ) = = false . 3 # Returns: * this . ðŸ”— template < class OtherProtocol , class OtherExecutor > basic_socket_acceptor & operator = ( basic_socket_acceptor < OtherProtocol , OtherExecutor > & & rhs ) ; 4 # Requires: OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . is implicitly convertible to 5 # Effects: If is_­open ( ) is true , cancels all outstanding asynchronous operations associated with this acceptor, and releases acceptor resources as if by POSIX close ( native_­handle ( ) ) . Then moves into * this the state originally represented by rhs . Completion handlers for canceled operations are passed an error code ec such that ec = = errc ​::​ operation_­canceled yields true . Ifis, cancels all outstanding asynchronous operations associated with this acceptor, and releases acceptor resources as if by POSIX. Then moves intothe state originally represented by. Completion handlers for canceled operations are passed an error codesuch thatyields 6 # Postconditions: (6.1) get_­executor ( ) = = rhs . get_­executor ( ) .

. (6.2) is_­open ( ) returns the same value as rhs . is_­open ( ) prior to the assignment.

returns the same value as prior to the assignment. (6.3) non_­blocking ( ) returns the same value as rhs . non_­blocking ( ) prior to the assignment.

returns the same value as prior to the assignment. (6.4) enable_­connection_­aborted ( ) returns the same value as rhs . enable_­connection_­aborted ( ) prior to the assignment.

returns the same value as prior to the assignment. (6.5) native_­handle ( ) returns the same value as rhs . native_­handle ( ) prior to the assignment.

returns the same value as prior to the assignment. (6.6) protocol_­ is the result of converting the value of rhs . protocol_­ prior to the assignment.

is the result of converting the value of prior to the assignment. (6.7) rhs . is_­open ( ) = = false . 7 # Returns: * this . 8 # Remarks: This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol and OtherExecutor is implicitly convertible to Executor . This assignment operator shall not participate in overload resolution unlessis implicitly convertible to

Update the basic_socket_acceptor operations [socket.stream.ops] as follows:

[...]

ðŸ”— socket_type accept ( ) ; socket_type accept ( error_code & ec ) ; 40 # Returns: accept ( get_­executor ( ) .context() , ec ) . ðŸ”— socket_­type accept ( io_­context & ctx ) ; socket_­type accept ( io_­context & ctx, error_­code & ec ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex, error_­code & ec ) ; 41 # Effects: Extracts a socket from the queue of pending connections of the acceptor, as if by POSIX: native_handle_type h = accept ( native_handle ( ) , nullptr , 0 ) ; Extracts a socket from the queue of pending connections of the acceptor, as if by POSIX: 42 # Returns: On success, socket_­type ( ctx ex , protocol_­, h ) . Otherwise socket_­type ( ctx ex ) . On success,. Otherwise ðŸ”— template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx ) ; template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx, error_­code & ec ) ; Returns: accept ( ctx . get_­executor ( ) , ec ) . ðŸ”— template < class CompletionToken > DEDUCED async_accept ( CompletionToken & & token ) ; 43 # Returns: async_accept ( get_executor ( ) . context ( ) , forward < CompletionToken > ( token ) ) ðŸ”— template < class CompletionToken > DEDUCED async_­accept ( io_­context & ctx, CompletionToken & & token ) ; template < class OtherExecutor, class CompletionToken > DEDUCED async_­accept ( const OtherExecutor & ex, CompletionToken & & token ) ; Let S be the type rebind_­socket_­executor < OtherExecutor > . 44 # Completion signature: void ( error_­code ec, socket_­type S s ) . 45 # Effects: Initiates an asynchronous operation to extract a socket from the queue of pending connections of the acceptor, as if by POSIX: native_handle_type h = accept ( native_handle ( ) , nullptr , 0 ) ; On success, s is socket_­type ( ctx, protocol_­, h ) . Otherwise, s is socket_­type ( ctx ) . On success, s is S ( ex, protocol_­, h ) . Otherwise, s is S ( ex ) . Initiates an asynchronous operation to extract a socket from the queue of pending connections of the acceptor, as if by POSIX: ðŸ”— template < class ExecutionContext, class CompletionToken > DEDUCED async_­accept ( ExecutionContext & ctx, CompletionToken & & token ) ; Returns: async_­accept ( ctx . get_­executor ( ) , forward < CompletionToken > ( token ) ) ðŸ”— socket_type accept ( endpoint_type & endpoint ) ; socket_type accept ( endpoint_type & endpoint, error_code & ec ) ; 46 # Returns: accept ( get_­executor ( ) .context() , endpoint, ec ) . ðŸ”— socket_­type accept ( io_­context & ctx, endpoint_­type & endpoint ) ; socket_­type accept ( io_­context & ctx, endpoint_­type & endpoint, error_­code & ec ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex, endpoint_­type & endpoint ) ; template < class OtherExecutor > rebind_­socket_­executor < OtherExecutor > accept ( const OtherExecutor & ex, endpoint_­type & endpoint, error_­code & ec ) ; 47 # Effects: Extracts a socket from the queue of pending connections of the acceptor, as if by POSIX: socklen_t endpoint_len = endpoint . capacity ( ) ; native_handle_type h = accept ( native_handle ( ) , endpoint . data ( ) , & endpoint_len ) ; if ( h > = 0 ) endpoint . resize ( endpoint_len ) ; Extracts a socket from the queue of pending connections of the acceptor, as if by POSIX: 48 # Returns: On success, socket_­type ( ctx ex , protocol_­, h ) . Otherwise socket_­type ( ctx ex ) . On success,. Otherwise ðŸ”— template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx, endpoint_­type & endpoint ) ; template < class ExecutionContext > rebind_­socket_­executor < typename ExecutionContext ​::​ executor_­type > accept ( ExecutionContext & ctx, endpoint_­type & endpoint, error_­code & ec ) ; Returns: accept ( ctx . get_­executor ( ) , endpoint, ec ) . ðŸ”— template < class CompletionToken > DEDUCED async_accept ( endpoint_type & endpoint, CompletionToken & & token ) ; 49 # Returns: async_accept ( get_executor ( ) . context ( ) , endpoint, forward < CompletionToken > ( token ) ) ðŸ”— template < class CompletionToken > DEDUCED async_­accept ( io_­context & ctx, endpoint_­type & endpoint, CompletionToken & & token ) ; template < class OtherExecutor, class CompletionToken > DEDUCED async_­accept ( const OtherExecutor & ex, endpoint_­type & endpoint, CompletionToken & & token ) ; Let S be the type rebind_­socket_­executor < OtherExecutor > . 50 # Completion signature: void ( error_­code ec, socket_­type S s ) . 51 # Effects: Initiates an asynchronous operation to extract a socket from the queue of pending connections of the acceptor, as if by POSIX: socklen_t endpoint_len = endpoint . capacity ( ) ; native_handle_type h = accept ( native_handle ( ) , endpoint . data ( ) , & endpoint_len ) ; if ( h > = 0 ) endpoint . resize ( endpoint_len ) ; On success, s is socket_­type ( ctx, protocol_­, h ) . Otherwise, s is socket_­type ( ctx ) . On success, s is S ( ex, protocol_­, h ) . Otherwise, s is S ( ex ) . Initiates an asynchronous operation to extract a socket from the queue of pending connections of the acceptor, as if by POSIX: ðŸ”— template < class ExecutionContext, class CompletionToken > DEDUCED async_­accept ( ExecutionContext & ctx, endpoint_­type & endpoint, CompletionToken & & token ) ; Returns: async_­accept ( ctx . get_­executor ( ) , forward < CompletionToken > ( token ) )

Update the class template basic_socket_streambuf [socket.streambuf] as follows:

19.1 Class template basic_­socket_­streambuf [socket.streambuf] 1 # basic_­socket_­streambuf < Protocol, Clock, WaitTraits, Executor > associates both the input sequence and the output sequence with a socket. The input and output sequences do not support seeking. Note : The input and output sequences are independent as a stream socket provides full duplex I/O. — end note ] The classassociates both the input sequence and the output sequence with a socket. The input and output sequences do not support seeking. 2 # Note : This class is intended for sending and receiving bytes, not characters. Any conversion from characters to bytes, and vice versa, occurs elsewhere. — end note ] namespace std { namespace experimental { namespace net { inline namespace v1 { template < class Protocol, class Clock, class WaitTraits , class Executor = executor > class basic_socket_streambuf : public basic_streambuf < char > { public : using executor_­type = Executor; using protocol_type = Protocol; using endpoint_type = typename protocol_type :: endpoint; using clock_type = Clock; using time_point = typename clock_type :: time_point; using duration = typename clock_type :: duration; using wait_traits_type = WaitTraits; basic_socket_streambuf ( ) ; explicit basic_socket_streambuf ( basic_stream_socket < protocol_type , executor_­type > s ) ; basic_socket_streambuf ( const basic_socket_streambuf & ) = delete ; basic_socket_streambuf ( basic_socket_streambuf & & rhs ) ; virtual ~ basic_socket_streambuf ( ) ; basic_socket_streambuf & operator = ( const basic_socket_streambuf & ) = delete ; basic_socket_streambuf & operator = ( basic_socket_streambuf & & rhs ) ; basic_socket_streambuf * connect ( const endpoint_type & e ) ; template < class . . . Args > basic_socket_streambuf * connect ( Args & & . . . ) ; basic_socket_streambuf * close ( ) ; basic_socket < protocol_type , executor_­type > & socket ( ) ; error_code error ( ) const ; time_point expiry ( ) const ; void expires_at ( const time_point & t ) ; void expires_after ( const duration & d ) ; protected : virtual int_type underflow ( ) override ; virtual int_type pbackfail ( int_type c = traits_type :: eof ( ) ) override ; virtual int_type overflow ( int_type c = traits_type :: eof ( ) ) override ; virtual int sync ( ) override ; virtual streambuf * setbuf ( char_type * s, streamsize n ) override ; private : basic_stream_socket < protocol_type , executor_­type > socket_; error_code ec_; time_point expiry_; } ; } } } } 3 # basic_­socket_­streambuf meet the requirements of Destructible (C++2014[destructible]), MoveConstructible (C++2014[moveconstructible]), and MoveAssignable (C++2014[moveassignable]). Instances of class templatemeet the requirements of(C++2014[destructible]),(C++2014[moveconstructible]), and(C++2014[moveassignable]). 19.1.1 basic_­socket_­streambuf constructors [socket.streambuf.cons] ðŸ”— basic_socket_streambuf ( ) ; 1 # Effects: Initializes socket_­ with ctx , where ctx is an unspecified object of class io_­context . Initializeswith, whereis an unspecified object of class 2 # Postconditions: expiry ( ) = = time_­point ​::​ max ( ) and ! error ( ) . and Remarks: This function shall not participate in overload resolution unless is_­constructible < executor_­type, io_­context ​::​ executor_­type > ​::​ value is true . ðŸ”— explicit basic_socket_streambuf ( basic_stream_socket < protocol_type , executor_­type > s ) ; 3 # Effects: Initializes socket_­ with std ​::​ move ( s ) . Initializeswith 4 # Postconditions: expiry ( ) = = time_­point ​::​ max ( ) and ! error ( ) . and ðŸ”— basic_socket_streambuf ( basic_socket_streambuf & & rhs ) ; 5 # Effects: Move constructs from the rvalue rhs . It is * this ( eback ( ) , gptr ( ) , egptr ( ) , pbase ( ) , pptr ( ) , epptr ( ) ) obtain the values which rhs had. Whether they do or not, * this and rhs reference separate buffers (if any at all) after the construction. Additionally * this references the socket which rhs did before the construction, and rhs references no open socket after the construction. Move constructs from the rvalue. It isimplementation-defined whether the sequence pointers in) obtain the values whichhad. Whether they do or not,andreference separate buffers (if any at all) after the construction. Additionallyreferences the socket whichdid before the construction, andreferences no open socket after the construction. 6 # Postconditions: Let rhs_­p refer to the state of rhs just prior to this construction and let rhs_­a refer to the state of rhs just after this construction. (6.1) is_­open ( ) = = rhs_­p . is_­open ( )

(6.2) rhs_­a . is_­open ( ) = = false

(6.3) error ( ) = = rhs_­p . error ( )

(6.4) ! rhs_­a . error ( )

(6.5) expiry ( ) = = rhs_­p . expiry ( )

(6.6) rhs_­a . expiry ( ) = = time_­point ​::​ max ( )

(6.7) gptr ( ) - eback ( ) = = rhs_­p . gptr ( ) - rhs_­p . eback ( )

(6.8) egptr ( ) - eback ( ) = = rhs_­p . egptr ( ) - rhs_­p . eback ( )

(6.9) ptr ( ) - pbase ( ) = = rhs_­p . pptr ( ) - rhs_­p . pbase ( )

(6.10) pptr ( ) - pbase ( ) = = rhs_­p . epptr ( ) - rhs_­p . pbase ( )

(6.11) if ( eback ( ) ) eback ( ) ! = rhs_­a . eback ( )

(6.12) if ( gptr ( ) ) gptr ( ) ! = rhs_­a . gptr ( )

(6.13) if ( egptr ( ) ) egptr ( ) ! = rhs_­a . egptr ( )

(6.14) if ( pbase ( ) ) pbase ( ) ! = rhs_­a . pbase ( )

(6.15) if ( pptr ( ) ) pptr ( ) ! = rhs_­a . pptr ( )

(6.16) if ( epptr ( ) ) epptr ( ) ! = rhs_­a . epptr ( ) Letrefer to the state ofjust prior to this construction and letrefer to the state ofjust after this construction. ðŸ”— virtual ~ basic_socket_streambuf ( ) ; 7 # Effects: If a put area exists, calls overflow ( traits_­type ​::​ eof ( ) ) to flush characters. Note : The socket is closed by the basic_­stream_­socket < protocol_­type , executor_­type > destructor. — end note ] If a put area exists, callsto flush characters. ðŸ”— basic_socket_streambuf & operator = ( basic_socket_streambuf & & rhs ) ; 8 # Effects: Calls this - > close ( ) then move assigns from rhs . After the move assignment * this and rhs have the observable state they would have had if * this had been move constructed from rhs . Callsthen move assigns from. After the move assignmentandhave the observable state they would have had ifhad been move constructed from 9 # Returns: * this . 19.1.2 basic_­socket_­streambuf members [socket.streambuf.members] ðŸ”— basic_socket_streambuf * connect ( const endpoint_type & e ) ; 1 # Effects: Initializes the basic_­socket_­streambuf as required, closes and re-opens the socket by performing socket_­ . close ( ec_­ ) and socket_­ . open ( e . protocol ( ) , ec_­ ) , then attempts to establish a connection as if by POSIX connect ( socket_­ . native_­handle ( ) , static_­cast < sockaddr * > ( e . data ( ) ) , e . size ( ) ) . ec_­ is set to reflect the error code produced by the operation. If the operation does not complete before the absolute timeout specified by expiry_­ , the socket is closed and ec_­ is set to errc ​::​ timed_­out . Initializes theas required, closes and re-opens the socket by performingand, then attempts to establish a connection as if by POSIXis set to reflect the error code produced by the operation. If the operation does not complete before the absolute timeout specified by, the socket is closed andis set to 2 # Returns: if ! ec_­ , this ; otherwise, a null pointer. if; otherwise, a null pointer. ðŸ”— template < class . . . Args > basic_socket_streambuf * connect ( Args & & . . . args ) ; 3 # Effects: Initializes the basic_­socket_­streambuf as required and closes the socket as if by calling socket_­ . close ( ec_­ ) . Obtains an endpoint sequence endpoints by performing protocol_­type ​::​ resolver ( ctx ) . resolve ( forward < Args > ( args ) . . . ) , where ctx is an unspecified object of class io_­context . For each endpoint e in the sequence, closes and re-opens the socket by performing socket_­ . close ( ec_­ ) and socket_­ . open ( e . protocol ( ) , ec_­ ) , then attempts to establish a connection as if by POSIX connect ( socket_­ . native_­handle ( ) , static_­cast < sockaddr * > ( e . data ( ) ) , e . size ( ) ) . ec_­ is set to reflect the error code produced by the operation. If the operation does not complete before the absolute timeout specified by expiry_­ , the socket is closed and ec_­ is set to errc ​::​ timed_­out . Initializes theas required and closes the socket as if by calling. Obtains an endpoint sequenceby performing, whereis an unspecified object of class. For each endpointin the sequence, closes and re-opens the socket by performingand, then attempts to establish a connection as if by POSIXis set to reflect the error code produced by the operation. If the operation does not complete before the absolute timeout specified by, the socket is closed andis set to 4 # Returns: if ! ec_­ , this ; otherwise, a null pointer. if; otherwise, a null pointer. 5 # Remarks: This function shall not participate in overload resolution unless Protocol meets the requirements for an internet protocol ( This function shall not participate in overload resolution unlessmeets the requirements for an internet protocol ( [internet.reqmts.protocol] ). ðŸ”— basic_socket_streambuf * close ( ) ; 6 # Effects: If a put area exists, calls overflow ( traits_­type ​::​ eof ( ) ) to flush characters. Regardless of whether the preceding call fails or throws an exception, the function closes the socket as if by basic_­socket < protocol_­type , executor_­type > ​::​ close ( ec_­ ) . If any of the calls made by the function fail, close fails by returning a null pointer. If one of these calls throws an exception, the exception is caught and rethrown after closing the socket. If a put area exists, callsto flush characters. Regardless of whether the preceding call fails or throws an exception, the function closes the socket as if by. If any of the calls made by the function fail,fails by returning a null pointer. If one of these calls throws an exception, the exception is caught and rethrown after closing the socket. 7 # Returns: this on success, a null pointer otherwise. on success, a null pointer otherwise. 8 # Postconditions: is_­open ( ) = = false . ðŸ”— basic_socket < protocol_type , executor_­type > & socket ( ) ; 9 # Returns: socket_­ .

Update the class template basic_socket_iostream [socket.iostream] as follows:

19.2 Class template basic_­socket_­iostream [socket.iostream] 1 # basic_­socket_­iostream < Protocol, Clock, WaitTraits, Executor > supports reading and writing on sockets. It uses a basic_­socket_­streambuf < Protocol, Clock, WaitTraits, Executor > object to control the associated sequences. The class templatesupports reading and writing on sockets. It uses aobject to control the associated sequences. 2 # Note : This class is intended for sending and receiving bytes, not characters. Any conversion from characters to bytes, and vice versa, occurs elsewhere. — end note ] namespace std { namespace experimental { namespace net { inline namespace v1 { template < class Protocol, class Clock, class WaitTraits , class Executor = executor > class basic_socket_iostream : public basic_iostream < char > { public : using executor_­type = Executor; using protocol_type = Protocol; using endpoint_type = typename protocol_type :: endpoint; using clock_type = Clock; using time_point = typename clock_type :: time_point; using duration = typename clock_type :: duration; using wait_traits_type = WaitTraits; basic_socket_iostream ( ) ; explicit basic_socket_iostream ( basic_stream_socket < protocol_type , executor_­type > s ) ; basic_socket_iostream ( const basic_socket_iostream & ) = delete ; basic_socket_iostream ( basic_socket_iostream & & rhs ) ; template < class . . . Args > explicit basic_socket_iostream ( Args & & . . . args ) ; basic_socket_iostream & operator = ( const basic_socket_iostream & ) = delete ; basic_socket_iostream & operator = ( basic_socket_iostream & & rhs ) ; template < class . . . Args > void connect ( Args & & . . . args ) ; void close ( ) ; basic_socket_streambuf < protocol_type, clock_type, wait_traits_type , executor_­type > * rdbuf ( ) const ; basic_socket < protocol_type , executor_­type > & socket ( ) ; error_code error ( ) const ; time_point expiry ( ) const ; void expires_at ( const time_point & t ) ; void expires_after ( const duration & d ) ; private : basic_socket_streambuf < protocol_type, clock_type, wait_traits_type , executor_­type > sb_; } ; } } } } 3 # basic_­socket_­iostream meet the requirements of Destructible (C++2014[destructible]), MoveConstructible (C++2014[moveconstructible]), and MoveAssignable (C++2014[moveassignable]). Instances of class templatemeet the requirements of(C++2014[destructible]),(C++2014[moveconstructible]), and(C++2014[moveassignable]). 19.2.1 basic_­socket_­iostream constructors [socket.iostream.cons] ðŸ”— basic_socket_iostream ( ) ; 1 # Effects: Initializes the base class as basic_­iostream < char > ( & sb_­ ) , value-initializes sb_­ , and performs setf ( std ​::​ ios_­base ​::​ unitbuf ) . Initializes the base class as, value-initializes, and performs Remarks: This function shall not participate in overload resolution unless is_­default_­constructible < basic_­socket_­streambuf < protocol_­type, clock_­type, wait_­traits_­type, executor_­type > > ​::​ value is true . ðŸ”— explicit basic_socket_iostream ( basic_stream_socket < protocol_type , executor_­type > s ) ; 2 # Effects: Initializes the base class as basic_­iostream < char > ( & sb_­ ) , initializes sb_­ with std ​::​ move ( s ) , and performs setf ( std ​::​ ios_­base ​::​ unitbuf ) . Initializes the base class as, initializeswith, and performs ðŸ”— basic_socket_iostream ( basic_socket_iostream & & rhs ) ; 3 # Effects: Move constructs from the rvalue rhs . This is accomplished by move constructing the base class, and the contained basic_­socket_­streambuf . Next basic_­iostream < char > ​::​ set_­rdbuf ( & sb_­ ) is called to install the contained basic_­socket_­streambuf . Move constructs from the rvalue. This is accomplished by move constructing the base class, and the contained. Nextis called to install the contained ðŸ”— template < class . . . Args > explicit basic_socket_iostream ( Args & & . . . args ) ; 4 # Effects: Initializes the base class as basic_­iostream < char > ( & sb_­ ) , value-initializes sb_­ , and performs setf ( std ​::​ ios_­base ​::​ unitbuf ) . Then calls rdbuf ( ) - > connect ( forward < Args > ( args ) . . . ) . If that function returns a null pointer, calls setstate ( failbit ) . Initializes the base class as, value-initializes, and performs. Then calls. If that function returns a null pointer, calls ðŸ”— basic_socket_iostream & operator = ( basic_socket_iostream & & rhs ) ; 5 # Effects: Move assigns the base and members of * this from the base and corresponding members of rhs . Move assigns the base and members offrom the base and corresponding members of 6 # Returns: * this . 19.2.2 basic_­socket_­iostream members [socket.iostream.members] ðŸ”— template < class . . . Args > void connect ( Args & & . . . args ) ; 1 # Effects: Calls rdbuf ( ) - > connect ( forward < Args > ( args ) . . . ) . If that function returns a null pointer, calls setstate ( failbit ) (which may throw ios_­base ​::​ failure ). Calls. If that function returns a null pointer, calls(which may throw). ðŸ”— void close ( ) ; 2 # Effects: Calls rdbuf ( ) - > close ( ) . If that function returns a null pointer, calls setstate ( failbit ) (which may throw ios_­base ​::​ failure ). Calls. If that function returns a null pointer, calls(which may throw). ðŸ”— basic_socket_streambuf < protocol_type, clock_type, wait_traits_type , executor_­type > * rdbuf ( ) const ; 3 # SB be the type basic_­socket_­streambuf < protocol_­type, clock_­type, wait_­traits_­type , executor_­type > . Letbe the type 4 # Returns: const_­cast < SB * > ( addressof ( sb_­ ) ) . ðŸ”— basic_socket < protocol_type , executor_­type > & socket ( ) ; 5 # Returns: rdbuf ( ) - > socket ( ) .

Update the connect function [socket.algo.connect] as follows:

20.1 Synchronous connect operations [socket.algo.connect] ðŸ”— template < class Protocol , class Executor , class EndpointSequence > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints ) ; template < class Protocol , class Executor , class EndpointSequence > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, error_code & ec ) ; 1 # Returns: connect ( s, endpoints, [ ] ( auto , auto ) { return true ; } , ec ) . ðŸ”— template < class Protocol , class Executor , class EndpointSequence, class ConnectCondition > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, ConnectCondition c ) ; template < class Protocol , class Executor , class EndpointSequence, class ConnectCondition > typename Protocol :: endpoint connect ( basic_socket < Protocol , Executor > & s, const EndpointSequence & endpoints, ConnectCondition c, error_code & ec ) ; 2 # Effects: Performs ec . clear ( ) , then finds the first element ep in the sequence endpoints for which: (2.1) c ( ec, ep ) yields true ;

yields ; (2.2) s . close ( ec ) succeeds;

succeeds; (2.3) s . open ( ep . protocol ( ) , ec ) succeeds; and

succeeds; and (2.4) s . connect ( ep, ec ) succeeds. Performs, then finds the first elementin the sequencefor which: 3 # Returns: typename Protocol ​::​ endpoint ( ) if no such element is found, otherwise ep . if no such element is found, otherwise 4 # Error conditions: (4.1) socket_­errc ​::​ not_­found — if endpoints . empty ( ) or if the function object c returned false for all elements in the sequence. ðŸ”— template < class Protocol , class Executor , class InputIterator > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last ) ; template < class Protocol , class Executor , class InputIterator > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, error_code & ec ) ; 5 # Returns: connect ( s, first, last, [ ] ( auto , auto ) { return true ; } , ec ) . ðŸ”— template < class Protocol , class Executor , class InputIterator, class ConnectCondition > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, ConnectCondition c ) ; template < class Protocol , class Executor , class InputIterator, class ConnectCondition > InputIterator connect ( basic_socket < Protocol , Executor > & s, InputIterator first, InputIterator last, ConnectCondition c, error_code & ec ) ; 6 # Effects: Performs ec . clear ( ) , then finds the first iterator i in the range [ first, ​last ) for which: (6.1) c ( ec, * i ) yields true ;

yields ; (6.2) s . close ( ec ) succeeds;

succeeds; (6.3) s . open ( typename Protocol ​::​ endpoint ( * i ) . protocol ( ) , ec ) succeeds; and

succeeds; and (6.4) s . connect ( * i, ec ) succeeds. Performs, then finds the first iteratorin the rangefor which: 7 # Returns: last if no such iterator is found, otherwise i . if no such iterator is found, otherwise 8 # Error conditions: (8.1) socket_­errc ​::​ not_­found — if first = = last or if the function object c returned false for all iterators in the range.

Update the async_connect function [socket.a