Doc. no:  N4478 
Date:     2015-04-13
Revises:  N4370
Reply-To: Christopher Kohlhoff <chris@kohlhoff.com>

Networking Library Proposal (Revision 5)

1. Introduction

In the June 2014 committee meeting in Rapperswil, LEWG requested that Boost.Asio-based N2175 Networking Library Proposal for TR2 (Revision 1) be updated for C++14 and brought forward as a proposed Networking Technical Specification. This document is that revision. As well as updating the proposal for C++14, it incorporates improvements to Asio that are based on the widespread field experience accumulated since 2007.

The Boost.Asio library, from which this proposal is derived, has been deployed in numerous systems, from large (including internet-facing HTTP servers, instant messaging gateways and financial markets applications) to small (mobile phones and embedded systems). The Asio library supports, or has been ported to, many operating systems including Linux, Mac OS X, Windows (native), Windows Runtime, Solaris, FreeBSD, NetBSD, OpenBSD, HP-UX, Tru64, AIX, iOS, Android, WinCE, Symbian, vxWorks and QNX Neutrino.

2. Changes in this revision

This revision contains numerous changes resulting from the LWG wording review held in Cologne in February 2015. Please note, however, it does not yet contain all of the wording corrections and suggestions from that meeting, nor have the applied corrections and changes been reviewed. As the changes are too extensive to list here, readers may wish to view the GitHub page for this proposal at https://github.com/chriskohlhoff/asio-tr2/ for further information.

The purpose of this revision is to provide LEWG with up-to-date wording in order to confirm and/or consider certain design choices, based on feedback from Cologne. To facilitate this process, this revision contains some of the suggested design changes from the wording review. There are two significant design changes worth noting here.

First, the basic_socket_acceptor class's accept and async_accept member functions have been changed to produce the incoming socket object by moving the result, rather than by taking a socket object by non-const reference. For example, a synchronous accept operation may now look like this:

tcp::socket socket(my_acceptor.accept());
// read and write on newly accepted socket ...

and an asynchronous accept operation like this:

my_acceptor.async_accept(
    [](error_code ec, tcp::socket socket)
    {
      if (!ec)
      {
        // read and write on newly accepted socket
      }
    });

As a consequence of this change, the basic_socket_streambuf class no longer inherits from basic_socket — it did so previously to allow users to pass it to accept() or async_accept(). Instead, basic_socket_streambuf and basic_socket_iostream are move-enabled and support the ability to move-construct from a socket:

tcp::iostream s(my_acceptor.accept());

Second, there was concern about the use of resource-owning iterators associated with the ip::basic_resolver template, and the related single iterator overloads of the free functions connect and async_connect. The resolver has been changed so that its resolve operations now return a results class based on the regular expression library's match_results template. This ip::basic_resolver_results type satisfies the requirements of a sequence container, except that only the operations defined for const-qualified sequence containers are supported:

for (auto& result : my_resolver.resolve("www.boost.org", "http"))
{
  std::cout << result->endpoint() << ", ";
  std::cout << result->host_name() << ", ";
  std::cout << result->service_name() << std::endl;
}

In addition, the single iterator overloads of the free functions connect and async_connect have been removed and replaced with overloads that accept an EndpointSequence. This ensures that the following simple usage idiom is still supported:

connect(my_socket, my_resolver.resolve("www.boost.org", "http"));

3. Reference implementation

An almost complete implementation of the proposal text may be found in a variant of Asio that stands alone from Boost. This variant is available at https://github.com/chriskohlhoff/asio/tree/master.

4. Library examples

Unfamiliar readers are encouraged to look to the Boost.Asio documentation and examples for a more complete picture of the use of the library.

However, to give some idea of the flavour of the proposed library, consider the following sample code. This is part of a server program that echoes the characters it receives back to the client in upper case.

template <typename Iterator>
void uppercase(Iterator begin, Iterator end)
{
  std::locale loc("");
  for (Iterator iter = begin; iter != end; ++iter)
    *iter = std::toupper(*iter, loc);
}

void sync_connection(tcp::socket& socket)
{
  try
  {
    std::vector<char> buffer_space(1024);
    for (;;)
    {
      std::size_t length = socket.read_some(buffer(buffer_space));
      uppercase(buffer_space.begin(), buffer_space.begin() + length);
      write(socket, buffer(buffer_space, length));
    }
  }
  catch (std::system_error& e)
  {
    // ...
  }
}

The synchronous operations used above are functions that do not return control to the caller until the corresponding operating system operation completes. In Asio-based programs their use cases typically fall into two categories:

  • Simple programs that do not care about timeouts, or are happy to rely on the timeout behaviour provided by the underlying operating system.
  • Programs that require fine grained control over system calls, and are aware of the conditions under which synchronous operations will or will not block.

Next, the equivalent code developed using asynchronous operations might look something like this:

class async_connection
  : public std::enable_shared_from_this<async_connection>
{
public:
  async_connection(tcp::socket socket)
    : socket_(std::move(socket))
  {
  }

  void start()
  {
    do_read();
  }

private:
  void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(buffer(buffer_space_),
        [this, self](std::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            uppercase(buffer_space_.begin(), buffer_space_.begin() + length);
            do_write(length);
          }
        });
  }

  void do_write(std::size_t length)
  {
    auto self(shared_from_this());
    async_write(socket_, buffer(buffer_space_, length),
        [this, self](std::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }

  tcp::socket socket_;
  std::vector<char> buffer_space_{1024};
};

Asynchronous operations do not block the caller, but instead involve the delivery of a notification to the program when the corresponding operating system operation completes. Most non-trivial Asio-based programs will make use of asynchronous operations.

While the code may appear more complex due to the inverted flow of control, it allows a knowledgeable programmer to write code that will scale to a great many concurrent connections. However, this proposal uses the asynchronous model described in [N4045]. This is an extensible model that allows the asynchronous operations to support a variety of composition and notification mechanisms, and these mechanisms may alleviate this complexity. This includes futures:

std::future<std::size_t> fut =
  socket.async_read_some(buffer(buffer_space), use_future);

// ...

std::size_t length = fut.get();

and, through library extensions, coroutines:

void coro_connection(tcp::socket& socket, yield_context yield)
{
  try
  {
    std::vector<char> buffer_space(1024);
    for (;;)
    {
      std::size_t length = socket.async_read_some(buffer(buffer_space), yield);
      uppercase(buffer_space.begin(), buffer_space.begin() + length);
      async_write(socket, buffer(buffer_space, length), yield);
    }
  }
  catch (std::system_error& e)
  {
    // ...
  }
}

Finally, for many applications, networking is not a core feature, nor is it seen as a core competency of the application’s programmers. To cater to these use cases, the proposal provides a high-level interface to TCP sockets that is designed around the familiar C++ I/O streams framework.

Using the library in this way is as easy as opening a stream object with the remote host’s details:

tcp::iostream s("www.boost.org", "http");

Once connected, you send and receive any data as needed. In this case you send a request:

s << "GET / HTTP/1.0\r\n";
s << "Host: www.boost.org\r\n";
s << "Accept: */*\r\n";
s << "Connection: close\r\n\r\n";

Then receive and process the response:

std::string header;
while (std::getline(s, header) && header != "\r")
  std::cout << header << "\n";
std::cout << s.rdbuf();

You can set a timeout to detect unresponsive connections:

s.expires_after(std::chrono::seconds(60));

And, if at any time there is an error, the tcp::iostream class’s error() member function may be used to obtain an error_code that identifies the reason for failure:

if (!s)
{
  std::cout << "Unable to connect: " << s.error().message() << "\n";
  return 1;
}

5. Scope

Problem areas addressed by this proposal include:

  • Networking using TCP and UDP, including support for multicast.
  • Client and server applications.
  • Scalability to handle many concurrent connections.
  • Protocol independence between IPv4 and IPv6.
  • Name resolution (i.e. DNS).
  • Timers.

Features that are considered outside the scope of this proposal include:

  • Protocol implementations such as HTTP, SMTP or FTP.
  • Encryption (e.g. SSL, TLS).
  • Operating system specific demultiplexing APIs.
  • Support for realtime environments.
  • QoS-enabled sockets.
  • Other TCP/IP protocols such as ICMP.
  • Functions and classes for enumerating network interfaces.
  • Other forms of asynchronous I/O, such as files. (However, the asynchronous model defined below is capable of supporting these facilities.)

6. Target audience

The bulk of the library interface is intended for use by developers with at least some understanding of networking concepts (or a willingness to learn). A high level iostreams interface supports simple use cases and permits novices to develop network code without needing to get into too much depth.

7. Related work

The interface is based on the BSD sockets API, which is widely implemented and supported by extensive literature. It is also used as the basis of networking APIs in other languages (e.g. Java). Unsafe practices of the BSD sockets API, e.g. lack of compile-time type safety, are not included.

Asynchronous support is derived from the Proactor design pattern as implemented by the ADAPTIVE Communication Environment [ACE], and is influenced by the design of the Symbian C++ sockets API [SYMBIAN], which supports synchronous and asynchronous operations side-by-side. The Microsoft .NET socket classes [MS-NET] and the Extended Sockets API [ES-API] developed by The Open Group support similar styles of network programming.

8. Impact on the standard

This is a pure library proposal. It does not add any new language features, nor does it alter any existing standard library headers. It makes additions to experimental headers that may also be modified by other Technical Specifications.

This library can be implemented using compilers that conform to the C++14 standard. An implementation of this library requires operating system-specific functions that lie outside the C++14 standard.

9. Relationship to other proposals

The asynchronous operations defined in this proposal use the asynchronous model described in [N4045]. With the extensible asynchronous model presented in that paper, the user has the ability to select an asynchronous approach that is appropriate to each use case. With these library foundations, a single extensible asynchronous model can support a variety of composition methods, including:

  • Callbacks, where minimal runtime penalty is desirable.
  • Futures, and not just std::future but also future classes supplied by other libraries.
  • Coroutines or resumable functions, without adding new keywords to the language.

To facilitate the coordination of asynchronous operations in multithreaded programs, the asynchronous model also utilises the executors design described in [N4242].

As executors and the extensible asynchronous model are a prerequisite for the networking library, the proposed text below incorporates a complete specification of these facilities.

10. Proposed text

10.1. Scope
10.2. Conformance
10.2.1. POSIX conformance
10.2.2. Conditionally-supported features
10.3. Normative references
10.4. Namespaces and headers
10.5. Definitions
10.5.1. host byte order
10.5.2. network byte order
10.5.3. synchronous operation
10.5.4. asynchronous operation
10.6. Future plans (Informative)
10.7. Feature test macros (Informative)
10.8. Method of description (Informative)
10.8.1. Structure of each clause
10.8.1.1. Detailed specifications
10.9. Error reporting
10.9.1. Synchronous operations
10.9.2. Asynchronous operations
10.9.3. Error conditions
10.10. Library summary
10.11. Convenience header
10.11.1. Header <experimental/networking> synopsis
10.12. Forward declarations
10.12.1. Header <experimental/netfwd> synopsis
10.13. Asynchronous model
10.13.1. Header <experimental/executor> synopsis
10.13.2. Requirements
10.13.2.1. Proto-allocator requirements
10.13.2.2. Requirements on asynchronous operations
10.13.2.2.1. Completion tokens and handlers
10.13.2.2.2. Automatic deduction of initiating function return type
10.13.2.2.3. Production of initiating function return value
10.13.2.2.4. Lifetime of initiating function arguments
10.13.2.2.5. Associated executor
10.13.2.2.6. I/O executor
10.13.2.2.7. Completion handler executor
10.13.2.2.8. Outstanding work
10.13.2.2.9. Allocation of intermediate storage
10.13.2.2.10. Execution of completion handler on completion of asynchronous operation
10.13.2.2.11. Completion handlers and exceptions
10.13.2.3. Executor requirements
10.13.2.4. Execution context requirements
10.13.2.5. Service requirements
10.13.2.6. Signature requirements
10.13.3. Class template completion_handler_type
10.13.4. Class template async_result
10.13.5. Class template async_completion
10.13.5.1. async_completion members
10.13.6. Class template associated_allocator
10.13.6.1. associated_allocator members
10.13.7. Function get_associated_allocator
10.13.8. Class execution_context
10.13.8.1. execution_context constructor
10.13.8.2. execution_context destructor
10.13.8.3. execution_context operations
10.13.8.4. execution_context protected operations
10.13.8.5. execution_context globals
10.13.9. Class execution_context::service
10.13.9.1. execution_context::service members
10.13.10. Class template is_executor
10.13.11. Executor argument tag
10.13.12. uses_executor
10.13.12.1. uses_executor trait
10.13.12.2. uses-executor construction
10.13.13. Class template associated_executor
10.13.13.1. associated_executor members
10.13.14. Function get_associated_executor
10.13.15. Class template executor_wrapper
10.13.15.1. executor_wrapper constructors
10.13.15.2. executor_wrapper access
10.13.15.3. executor_wrapper invocation
10.13.15.4. Class template partial specialization async_result
10.13.15.5. Class template partial specialization associated_allocator
10.13.15.6. Class template partial specialization associated_executor
10.13.16. Function wrap
10.13.17. Class template executor_work
10.13.17.1. executor_work members
10.13.18. Function make_work
10.13.19. Class system_executor
10.13.19.1. system_executor operations
10.13.19.2. system_executor comparisons
10.13.20. Class bad_executor
10.13.21. Class executor
10.13.21.1. executor constructors
10.13.21.2. executor assignment
10.13.21.3. executor destructor
10.13.21.4. executor modifiers
10.13.21.5. executor operations
10.13.21.6. executor capacity
10.13.21.7. executor target access
10.13.21.8. executor comparisons
10.13.21.9. executor specialized algorithms
10.13.22. Function dispatch
10.13.23. Function post
10.13.24. Function defer
10.13.25. Class template strand
10.13.25.1. strand constructors
10.13.25.2. strand assignment
10.13.25.3. strand destructor
10.13.25.4. strand operations
10.13.25.5. strand comparisons
10.13.26. Class template use_future_t
10.13.26.1. use_future_t constructors
10.13.26.2. use_future_t members
10.13.26.3. use_future_t traits
10.13.27. Partial class template specialization async_result for packaged_task
10.13.28. Class template packaged_handler
10.13.28.1. packaged_handler members
10.13.28.2. Partial class template specialization async_result
10.13.29. Class template packaged_token
10.13.29.1. packaged_token members
10.13.30. Function package
10.14. Basic I/O services
10.14.1. Header <experimental/io_service> synopsis
10.14.2. Class io_service
10.14.2.1. io_service members
10.14.3. Class io_service::executor_type
10.14.3.1. io_service::executor_type constructors
10.14.3.2. io_service::executor_type assignment
10.14.3.3. io_service::executor_type operations
10.14.3.4. io_service::executor_type comparisons
10.15. Timers
10.15.1. Header <experimental/timer> synopsis
10.15.2. Requirements
10.15.2.1. Wait traits requirements
10.15.3. Class template wait_traits
10.15.3.1. Class template wait_traits members
10.15.4. Class template basic_waitable_timer
10.15.4.1. basic_waitable_timer constructors
10.15.4.2. basic_waitable_timer destructor
10.15.4.3. basic_waitable_timer assignment
10.15.4.4. basic_waitable_timer operations
10.16. Buffers
10.16.1. Header <experimental/buffer> synopsis
10.16.2. Requirements
10.16.2.1. Mutable buffer sequence requirements
10.16.2.2. Constant buffer sequence requirements
10.16.2.3. Dynamic buffer requirements
10.16.2.4. Requirements on synchronous read operations
10.16.2.5. Requirements on asynchronous read operations
10.16.2.6. Requirements on synchronous write operations
10.16.2.7. Requirements on asynchronous write operations
10.16.2.8. Buffer-oriented synchronous read stream requirements
10.16.2.9. Buffer-oriented asynchronous read stream requirements
10.16.2.10. Buffer-oriented synchronous write stream requirements
10.16.2.11. Buffer-oriented asynchronous write stream requirements
10.16.3. Class mutable_buffer
10.16.3.1. mutable_buffer constructors
10.16.4. Class const_buffer
10.16.4.1. const_buffer constructors
10.16.5. Class mutable_buffers_1
10.16.5.1. mutable_buffers_1 constructors
10.16.5.2. mutable_buffers_1 members
10.16.6. Class const_buffers_1
10.16.6.1. const_buffers_1 constructors
10.16.6.2. const_buffers_1 members
10.16.7. Buffer type traits
10.16.8. Function buffer_cast
10.16.9. Function buffer_size
10.16.10. Function buffer_copy
10.16.11. Buffer arithmetic
10.16.12. Buffer creation functions
10.16.13. Class template dynamic_vector_buffer
10.16.13.1. dynamic_vector_buffer constructors
10.16.13.2. dynamic_vector_buffer members
10.16.14. Class template dynamic_string_buffer
10.16.14.1. dynamic_string_buffer constructors
10.16.14.2. dynamic_string_buffer members
10.16.15. Dynamic buffer creation functions
10.16.16. Class transfer_all
10.16.17. Class transfer_at_least
10.16.18. Class transfer_exactly
10.16.19. Synchronous read operations
10.16.20. Asynchronous read operations
10.16.21. Synchronous write operations
10.16.22. Asynchronous write operations
10.16.23. Synchronous delimited read operations
10.16.24. Asynchronous delimited read operations
10.17. Sockets
10.17.1. Header <experimental/socket> synopsis
10.17.2. Requirements
10.17.2.1. Native handles
10.17.2.2. Endpoint requirements
10.17.2.3. Protocol requirements
10.17.2.4. Acceptable protocol requirements
10.17.2.5. Gettable socket option requirements
10.17.2.6. Settable socket option requirements
10.17.2.7. I/O control command requirements
10.17.2.8. Connect condition requirements
10.17.3. Error codes
10.17.4. Class socket_base
10.17.5. Boolean socket options
10.17.5.1. Boolean socket option constructors
10.17.5.2. Boolean socket option members
10.17.5.3. Boolean socket option members (extensible implementations)
10.17.6. Integral socket options
10.17.6.1. Integral socket option constructors
10.17.6.2. Integral socket option members
10.17.6.3. Integral socket option members (extensible implementations)
10.17.7. Class socket_base::linger
10.17.7.1. socket_base::linger constructors
10.17.7.2. socket_base::linger members
10.17.7.3. socket_base::linger members (extensible implementations)
10.17.8. Class template basic_socket
10.17.8.1. basic_socket constructors
10.17.8.2. basic_socket destructor
10.17.8.3. basic_socket assignment
10.17.8.4. basic_socket operations
10.17.9. Class template basic_datagram_socket
10.17.9.1. basic_datagram_socket constructors
10.17.9.2. basic_datagram_socket assignment
10.17.9.3. basic_datagram_socket operations
10.17.10. Class template basic_stream_socket
10.17.10.1. basic_stream_socket constructors
10.17.10.2. basic_stream_socket assignment
10.17.10.3. basic_stream_socket operations
10.17.11. Class template basic_socket_acceptor
10.17.11.1. basic_socket_acceptor constructors
10.17.11.2. basic_socket_acceptor destructor
10.17.11.3. basic_socket_acceptor assignment
10.17.11.4. basic_socket_acceptor operations
10.18. Socket iostreams
10.18.1. Class template basic_socket_streambuf
10.18.1.1. basic_socket_streambuf constructors
10.18.1.2. basic_socket_streambuf members
10.18.1.3. basic_socket_streambuf overridden virtual functions
10.18.2. Class template basic_socket_iostream
10.18.2.1. basic_socket_iostream constructors
10.18.2.2. basic_socket_iostream members
10.19. Socket algorithms
10.19.1. Synchronous connect operations
10.19.2. Asynchronous connect operations
10.20. Internet protocol
10.20.1. Header <experimental/internet> synopsis
10.20.2. Requirements
10.20.2.1. Internet protocol requirements
10.20.3. Error codes
10.20.4. Class ip::address
10.20.4.1. ip::address constructors
10.20.4.2. ip::address assignment
10.20.4.3. ip::address members
10.20.4.4. ip::address comparisons
10.20.4.5. ip::address creation
10.20.4.6. ip::address I/O
10.20.5. Class ip::address_v4
10.20.5.1. Struct ip::address_v4::bytes_type
10.20.5.2. ip::address_v4 constructors
10.20.5.3. ip::address_v4 assignment
10.20.5.4. ip::address_v4 members
10.20.5.5. ip::address_v4 static members
10.20.5.6. ip::address_v4 comparisons
10.20.5.7. ip::address_v4 creation
10.20.5.8. ip::address_v4 I/O
10.20.6. Class ip::address_v6
10.20.6.1. Struct ip::address_v6::bytes_type
10.20.6.2. ip::address_v6 constructors
10.20.6.3. ip::address_v6 assignment
10.20.6.4. ip::address_v6 members
10.20.6.5. ip::address_v6 static members
10.20.6.6. ip::address_v6 comparisons
10.20.6.7. ip::address_v6 creation
10.20.6.8. ip::address_v6 I/O
10.20.7. Class ip::bad_address_cast
10.20.8. Function ip::address_cast
10.20.9. Hash support
10.20.10. Class template ip::basic_address_iterator specializations
10.20.11. Class template ip::basic_address_range specializations
10.20.12. Class template ip::network_v4
10.20.12.1. ip::network_v4 constructors
10.20.12.2. ip::network_v4 members
10.20.12.3. ip::network_v4 comparisons
10.20.12.4. ip::network_v4 creation
10.20.12.5. ip::network_v4 I/O
10.20.13. Class template ip::network_v6
10.20.13.1. ip::network_v6 constructors
10.20.13.2. ip::network_v6 members
10.20.13.3. ip::network_v6 comparisons
10.20.13.4. ip::network_v6 creation
10.20.13.5. ip::network_v6 I/O
10.20.14. Class template ip::basic_endpoint
10.20.14.1. ip::basic_endpoint constructors
10.20.14.2. ip::basic_endpoint members
10.20.14.3. ip::basic_endpoint comparisons
10.20.14.4. ip::basic_endpoint I/O
10.20.14.5. ip::basic_endpoint members (extensible implementations)
10.20.15. Class template ip::basic_resolver_entry
10.20.15.1. ip::basic_resolver_entry constructors
10.20.15.2. ip::basic_resolver_entry members
10.20.15.3. op::basic_resolver_entry comparisons
10.20.16. Class template ip::basic_resolver_results
10.20.16.1. ip::basic_resolver_results constructors
10.20.16.2. ip::basic_resolver_results assignment
10.20.16.3. ip::basic_resolver_results size
10.20.16.4. ip::basic_resolver_results element access
10.20.16.5. ip::basic_resolver_results swap
10.20.16.6. ip::basic_resolver_results comparisons
10.20.17. Class ip::resolver_base
10.20.18. Class template ip::basic_resolver
10.20.18.1. ip::basic_resolver constructors
10.20.18.2. ip::basic_resolver destructor
10.20.18.3. ip::basic_resolver assignment
10.20.18.4. ip::basic_resolver operations
10.20.19. Host name functions
10.20.20. Class ip::tcp
10.20.20.1. ip::tcp comparisons
10.20.21. Class ip::tcp::no_delay
10.20.22. Class ip::udp
10.20.22.1. ip::udp comparisons
10.20.23. Class ip::v6_only
10.20.24. Class ip::unicast::hops
10.20.25. Multicast group management socket options
10.20.25.1. Multicast group management socket option constructors
10.20.25.2. Multicast group management socket option members (extensible implementations)
10.20.26. Class ip::multicast::outbound_interface
10.20.26.1. ip::multicast::outbound_interface constructors
10.20.26.2. ip::multicast::outbound_interface members (extensible implementations)
10.20.27. Class ip::multicast::hops
10.20.28. Class ip::multicast::enable_loopback
10.21. Index

10.1. Scope

[scope]

This Technical Specification describes extensions to the C++ Standard Library. This Technical Specification specifies requirements for implementations of an interface that computer programs written in the C++ programming language may use to perform operations related to networking, such as operations involving sockets, timers, buffer management, host name resolution and internet protocols. This Technical Specification is applicable to information technology systems that can perform network operations, such as those with operating systems that conform to the POSIX interface. This Technical Specification is applicable only to vendors who wish to provide the interface it describes.

10.2. Conformance

[conformance]

Conformance is specified in terms of behavior. Ideal behavior is not always implementable, so the conformance sub-clauses take that into account.

10.2.1. POSIX conformance

[conformance.9945]

Some behavior is specified by reference to POSIX. How such behavior is actually implemented is unspecified.

[Note: This constitutes an "as if" rule allowing implementations to call native operating system or other APIs. —end note]

Implementations are encouraged to provide such behavior as it is defined by POSIX. Implementations shall document any behavior that differs from the behavior defined by POSIX. Implementations that do not support exact POSIX behavior are encouraged to provide behavior as close to POSIX behavior as is reasonable given the limitations of actual operating systems and file systems. If an implementation cannot provide any reasonable behavior, the implementation shall report an error as specified in Error Reporting.

[Note: This allows users to rely on an exception being thrown or an error code being set when an implementation cannot provide any reasonable behavior. —end note]

Implementations are not required to provide behavior that is not supported by a particular operating system.

10.2.2. Conditionally-supported features

[conformance.conditional]

This Technical Specification defines conditially-supported features, in the form of additional member functions on types that satisfy Protocol, Endpoint, SettableSocketOption, GettableSocketOption or IoControlCommand requirements.

[Note: This is so that, when the additional member functions are available, C++ programs may extend the library to add support for other protocols and socket options. —end note]

For the purposes of this Technical Specification, implementations that provide all of the additional member functions are known as extensible implementations.

[Note: Implementations are encouraged to provide the additional member functions, where possible. It is intended that POSIX and Windows implementations will provide them. —end note]

10.3. Normative references

[references]

The following referenced documents are indispensable for the application of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.

  • ISO/IEC 14882, Programming Language C++
  • ISO/IEC 9945, Information Technology — Portable Operating System Interface (POSIX)
  • C++ Extensions for Library Fundamentals

[Note: The programming language and library described in ISO/IEC 14882 is herein called the C++ Standard. References to clauses within the C++ Standard are written as "C++Std [xref]".
The operating system interface described in ISO/IEC 9945 is herein called POSIX. —end note]

This Technical Specification mentions commercially available operating systems for purposes of exposition. [1]

Unless otherwise specified, the whole of the C++ Standard's Library introduction (C++Std [library]) is included into this Technical Specification by reference.

10.4. Namespaces and headers

[namespaces]

The components described in this Technical Specification are experimental and not part of the C++ standard library. All components described in this Technical Specification are declared in namespace std::experimental::network_v1 or a sub-namespace thereof unless otherwise specified. The header described in this technical specification shall import the contents of std::experimental::network_v1 into std::experimental as if by:

namespace std {
  namespace experimental {
    inline namespace network_v1 {}
  }
}

Unless otherwise specified, references to other entities described in this Technical Specification are assumed to be qualified with std::experimental::network_v1::, references to entities described in the C++ standard are assumed to be qualified with std::, and references to entities described in C++ Extensions for Library Fundamentals are assumed to be qualified with std::experimental::fundamentals_v1::.

10.5. Definitions

[defs]

10.5.1. host byte order

[defs.host.byte.order] See section 3.194 of POSIX Base Definitions, Host Byte Order.

10.5.2. network byte order

[defs.net.byte.order] See section 3.238 of POSIX Base Definitions, Network Byte Order.

10.5.3. synchronous operation

[defs.sync.op] A synchronous operation is one where control is not returned until the operation completes.

10.5.4. asynchronous operation

[defs.async.op] An asynchronous operation is one where control is returned immediately without waiting for the operation to complete. Multiple asynchronous operations may be executed concurrently.

10.6. Future plans (Informative)

[plans]

This section describes tentative plans for future versions of this technical specification and plans for moving content into future versions of the C++ Standard.

The C++ committee may release new versions of this technical specification, containing networking library extensions we hope to add to a near-future version of the C++ Standard. Future versions will define their contents in std::experimental::network_v2, std::experimental::network_v3, etc., with the most recent implemented version inlined into std::experimental.

When an extension defined in this or a future version of this technical specification represents enough existing practice, it will be moved into the next version of the C++ Standard by removing the experimental::network_vN segment of its namespace and by removing the experimental/ prefix from its header's path.

10.7. Feature test macros (Informative)

[feature.test]

These macros allow users to determine which version of this Technical Specification is supported by the headers defined by the specification. All headers in this Technical Specification shall supply the following macro definition:

#define __cpp_lib_experimental_network yyyymm

If an implementation supplies all of the conditionally-supported features specified in [conformance.conditional], all headers in this Technical Specification shall supply the following macro definition:

#define __cpp_lib_experimental_network_extensible yyyymm

[Note: The value of the macros __cpp_lib_experimental_network and __cpp_lib_experimental_network_extensible is yyyymm where yyyy is the year and mm the month when the version of the Technical Specification was completed. —end note]

10.8. Method of description (Informative)

[description]

This subclause describes the conventions used to specify this Technical Specification, in addition to those conventions specified in C++ Std, [description].

10.8.1. Structure of each clause

[structure]

10.8.1.1. Detailed specifications

[structure.specifications]

In addition to the elements defined in C++Std [structure.specifications], descriptions of function semantics contain the following elements (as appropriate):

Completion signature: - if the function initiates an asynchronous operation, specifies the signature of a completion handler used to receive the result of the operation.

10.9. Error reporting

[err.report]

10.9.1. Synchronous operations

[err.report.sync]

Most synchronous network library functions provide two overloads, one that throws an exception to report system errors, and another that sets an error_code (C++ Std, [syserr]).

[Note: This supports two common use cases:

— Uses where system errors are truly exceptional and indicate a serious failure. Throwing an exception is the most appropriate response.

— Uses where system errors are routine and do not necessarily represent failure. Returning an error code is the most appropriate response. This allows application specific error handling, including simply ignoring the error.

end note]

Functions not having an argument of type error_code& report errors as follows, unless otherwise specified:

— When a call by the implementation to an operating system or other underlying API results in an error that prevents the function from meeting its specifications, the function exits via an exception of a type that would match a handler of type system_error.

— Destructors throw nothing.

Functions having an argument of type error_code& report errors as follows, unless otherwise specified:

— If a call by the implementation to an operating system or other underlying API results in an error that prevents the function from meeting its specifications, the error_code& argument ec is set as appropriate for the specific error. Otherwise, the ec argument is set such that !ec is true.

Where a function is specified as two overloads, with and without an argument of type error_code&:

R f(A1 a1, A2 a2, ..., AN aN);
R f(A1 a1, A2 a2, ..., AN aN, error_code& ec);

then, when R is non-void, the effects of the first overload are as if:

error_code ec;
R r(f(a1, a2, ..., aN, ec));
if (ec) throw system_error(ec, __func__);
return r;

otherwise, when R is void, the effects of the first overload are as if:

error_code ec;
f(a1, a2, ..., aN, ec);
if (ec) throw system_error(ec, __func__);

except that the type thrown may differ as specified above.

For both overloads, failure to allocate storage is reported by throwing an exception as described in the C++ standard (C++14 [res.on.exception.handling]).

10.9.2. Asynchronous operations

[err.report.async]

Asynchronous network library functions in this Technical Specification are identified by having the prefix async_ and take a completion handler [async.reqmts.async.token]. These asynchronous operations report errors as follows:

— If a call by the implementation to an operating system or other underlying API results in an error that prevents the asynchronous operation from meeting its specifications, the completion handler is invoked with an error_code value ec that is set as appropriate for the specific error. Otherwise, the error_code value ec is set such that !ec is true.

— Asynchronous operations shall not fail with an error condition that indicates interruption of an operating system or underlying API by a signal [Note: Such as POSIX error number EINTRend note] . Asynchronous operations shall not fail with any error condition associated with non-blocking operations [Note: Such as POSIX error numbers EWOULDBLOCK, EAGAIN, or EINPROGRESS; Windows error numbers WSAEWOULDBLOCK or WSAEINPROGRESSend note] .

10.9.3. Error conditions

[err.report.conditions]

Unless otherwise specified, when the behavior of a synchronous or asynchronous operation is defined "as if" implemented by a POSIX function, the error_code produced by the function shall meet the following requirements:

— If the failure condition is one that is listed by POSIX for that function, the error_code shall compare equal to the error's corresponding enum class errc (C++Std [syserr]) or enum class resolver_errc constant.

— Otherwise, the error_code shall be set to an implementation-defined value that reflects the underlying operating system error.

[Example: The POSIX specification for shutdown lists EBADF as one of its possible errors. If a function that is specified "as if" implemented by shutdown fails with EBADF then the following condition holds for the error_code value ec: ec == errc::bad_file_descriptorend example]

When the description of a function contains the element Error conditions, this lists conditions where the operation may fail. The conditions are listed, together with a suitable explanation, as enum class constants. Unless otherwise specified, this list is a subset of the failure conditions associated with the function.

10.10. Library summary

[summary]

Table 1. Networking library summary

Clause

Header(s)

Convenience header

<experimental/networking>

Forward declarations

<experimental/netfwd>

Asynchronous model

<experimental/executor>

Basic I/O services

<experimental/io_service>

Timers

<experimental/timer>

Buffers

<experimental/buffer>

Sockets
Socket iostreams

<experimental/socket>

Internet protocol

<experimental/internet>


Throughout this Technical Specification, the names of the template parameters are used to express type requirements, as listed in the table below.

Table 2. Template parameters and type requirements

template parameter name

type requirements

AcceptableProtocol

acceptable protocol

Allocator

C++Std, [allocator.requirements]

AsyncReadStream

buffer-oriented asynchronous read stream

AsyncWriteStream

buffer-oriented asynchronous write stream

CompletionToken

completion token

ConnectCondition

connect condition

ConstBufferSequence

constant buffer sequence

DynamicBuffer

dynamic buffer

ExecutionContext

execution context

Executor

executor

GettableSocketOption

gettable socket option

InternetProtocol

Internet protocol

IoControlCommand

I/O control command

MutableBufferSequence

mutable buffer sequence

ProtoAllocator

proto-allocator

Protocol

protocol

Service

service

SettableSocketOption

settable socket option

Signature

signature

SyncReadStream

buffer-oriented synchronous read stream

SyncWriteStream

buffer-oriented synchronous write stream

WaitTraits

wait traits


10.11. Convenience header

[convenience.hdr]

10.11.1. Header <experimental/networking> synopsis

[convenience.hdr.synop]

#include <experimental/executor>
#include <experimental/io_service>
#include <experimental/timer>
#include <experimental/buffer>
#include <experimental/socket>
#include <experimental/internet>

[Note: This header is provided as a convenience for programs so that they may access all networking facilities via a single, self-contained #include. —end note]

10.12. Forward declarations

[fwd.decl]

10.12.1. Header <experimental/netfwd> synopsis

[fwd.decl.synop]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class execution_context;
      template<class T, class Executor>
        class executor_wrapper;
      template<class Executor>
        class executor_work;
      class system_executor;
      class executor;
      template<class Executor>
        class strand;

      class io_service;

      template<class Clock> struct wait_traits;
      template<class Clock, class WaitTraits = wait_traits<Clock>>
        class basic_waitable_timer;
      typedef basic_waitable_timer<chrono::system_clock> system_timer;
      typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
      typedef basic_waitable_timer<chrono::high_resolution_clock> high_resolution_timer;

      template<class Protocol>
        class basic_socket;
      template<class Protocol>
        class basic_datagram_socket;
      template<class Protocol>
        class basic_stream_socket;
      template<class Protocol>
        class basic_socket_acceptor;
      template<class Protocol, class Clock = chrono::steady_clock,
        class WaitTraits = wait_traits<Clock>>
          class basic_socket_streambuf;
      template<class Protocol, class Clock = chrono::steady_clock,
        class WaitTraits = wait_traits<Clock>>
          class basic_socket_iostream;

      namespace ip {

        class address;
        class address_v4;
        class address_v6;
        class address_iterator_v4;
        class address_iterator_v6;
        class address_range_v4;
        class address_range_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 basic_resolver;
        class tcp;
        class udp;

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Default template arguments are described as appearing both in <netfwd> and in the synopsis of other headers but it is well-formed to include both <netfwd> and one or more of the other headers. [Note: It is the implementation’s responsibility to implement headers so that including <netfwd> and other headers does not violate the rules about multiple occurrences of default arguments. —end note]

10.13. Asynchronous model

[async]

10.13.1. Header <experimental/executor> synopsis

[async.synop]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CompletionToken, class Signature, class = void>
        struct completion_handler_type;

      template<class CompletionToken, class Signature>
        using completion_handler_type_t =
          typename completion_handler_type<CompletionToken, Signature>::type;

      template<class CompletionHandler> class async_result;

      template<class CompletionToken, class Signature>
        struct async_completion;

      template<class T, class ProtoAllocator = allocator<void>>
        struct associated_allocator;

      template<class T, class ProtoAllocator = allocator<void>>
        using associated_allocator_t = typename associated_allocator<T, ProtoAllocator>::type;

      // get_associated_allocator:

      template<class T>
        associated_allocator_t<T> get_associated_allocator(const T& t);
      template<class T, class ProtoAllocator>
        associated_allocator_t<T, ProtoAllocator>
          get_associated_allocator(const T& t, const ProtoAllocator& a);

      enum class fork_event {
        prepare,
        parent,
        child
      };

      class execution_context;

      class service_already_exists;

      template<class Service> Service& use_service(execution_context& ctx);
      template<class Service, class... Args> Service&
        make_service(execution_context& ctx, Args&&... args);
      template<class Service> bool has_service(execution_context& ctx) noexcept;

      template<class T> struct is_executor : false_type {};

      struct executor_arg_t { };
      constexpr executor_arg_t executor_arg = executor_arg_t();

      template<class T, class Executor> struct uses_executor;

      template<class T, class Executor = system_executor>
        struct associated_executor;

      template<class T, class Executor = system_executor>
        using associated_executor_t = typename associated_executor<T, Executor>::type;

      // get_associated_executor:

      template<class T>
        associated_executor_t<T> get_associated_executor(const T& t);
      template<class T, class Executor>
        associated_executor_t<T, Executor>
          get_associated_executor(const T& t, const Executor& ex);
      template<class T, class ExecutionContext>
        associated_executor_t<T, typename ExecutionContext::executor_type>
          get_associated_executor(const T& t, ExecutionContext& ctx);

      template<class T, class Executor>
        class executor_wrapper;

      template<class T, class Executor, class Signature>
        struct completion_handler_type<executor_wrapper<T, Executor>, Signature>;

      template<class T, class Executor>
        class async_result<executor_wrapper<T, Executor>>;

      template<class T, class Executor, class ProtoAllocator>
        struct associated_allocator<executor_wrapper<T, Executor>, ProtoAllocator>;

      template<class T, class Executor, class Executor1>
        struct associated_executor<executor_wrapper<T, Executor>, Executor1>;

      // wrap:

      template<class Executor, class T>
        executor_wrapper<decay_t<T>, Executor> wrap(const Executor& ex, T&& t);
      template<class ExecutionContext, class T>
        executor_wrapper<decay_t<T>, typename ExecutionContext::executor_type>
          wrap(ExecutionContext& ctx, T&& t);

      template<class Executor>
        class executor_work;

      // make_work:

      template<class Executor>
        executor_work<Executor>
          make_work(const Executor& ex);
      template<class ExecutionContext>
        executor_work<typename ExecutionContext::executor_type>
          make_work(ExecutionContext& ctx);
      template<class T>
        executor_work<associated_executor_t<T>>
          make_work(const T& t);
      template<class T, class Executor>
        executor_work<associated_executor_t<T, Executor>>
          make_work(const T& t, const Executor& ex);
      template<class T, class ExecutionContext>
        executor_work<associated_executor_t<T, typename ExecutionContext::executor_type>>
          make_work(const T& t, ExecutionContext& ctx);

      class system_executor;

      bool operator==(const system_executor&, const system_executor&);
      bool operator!=(const system_executor&, const system_executor&);

      template<> struct is_executor<system_executor> : true_type {};

      class bad_executor;

      class executor;

      template <> struct is_executor<executor> : true_type {};

      bool operator==(const executor& a, const executor& b) noexcept;
      bool operator==(const executor& e, nullptr_t) noexcept;
      bool operator==(nullptr_t, const executor& e) noexcept;
      bool operator!=(const executor& a, const executor& b) noexcept;
      bool operator!=(const executor& e, nullptr_t) noexcept;
      bool operator!=(nullptr_t, const executor& e) noexcept;

      // dispatch:

      template<class CompletionToken>
        DEDUCED dispatch(CompletionToken&& token);
      template<class Executor, class CompletionToken>
        DEDUCED dispatch(const Executor& ex, CompletionToken&& token);
      template<class ExecutionContext, class CompletionToken>
        DEDUCED dispatch(ExecutionContext& ctx, CompletionToken&& token);

      // post:

      template<class CompletionToken>
        DEDUCED post(CompletionToken&& token);
      template<class Executor, class CompletionToken>
        DEDUCED post(const Executor& ex, CompletionToken&& token);
      template<class ExecutionContext, class CompletionToken>
        DEDUCED post(ExecutionContext& ctx, CompletionToken&& token);

      // defer:

      template<class CompletionToken>
        DEDUCED defer(CompletionToken&& token);
      template<class Executor, class CompletionToken>
        DEDUCED defer(const Executor& ex, CompletionToken&& token);
      template<class ExecutionContext, class CompletionToken>
        DEDUCED defer(ExecutionContext& ctx, CompletionToken&& token);

      template<class Executor>
        class strand;

      template<class Executor>
        bool operator==(const strand<Executor>& a, const strand<Executor>& b);
      template<class Executor>
        bool operator!=(const strand<Executor>& a, const strand<Executor>& b);

      template<class Executor>
        struct is_executor<strand<Executor>> : true_type {};

      template<class ProtoAllocator = allocator<void>>
        class use_future_t;

      constexpr use_future_t<> use_future = use_future_t<>();

      template<class ProtoAllocator, class R, class... Args>
        struct completion_handler_type<use_future_t<ProtoAllocator>, R(Args...)>;

      template<class R, class... Args>
        class async_result<packaged_task<R(Args...)>>;

      template<class, class> class packaged_handler; // undefined
      template<class R, class... Arg, class ProtoAllocator>
        class packaged_handler<R(Args...), ProtoAllocator>;

      template<class Signature, class ProtoAllocator>
        class async_result<packaged_handler<Signature, ProtoAllocator>>;

      template<class Func, class ProtoAllocator = allocator<void>>
        class packaged_token;

      template<class Func, class ProtoAllocator, class R, class... Args>
        struct completion_handler_type<packaged_token<Func, ProtoAllocator>, R(Args...)>;

      template<class Func, class ProtoAllocator = allocator<void>>
        packaged_token<decay_t<Func>, ProtoAllocator> package(
          Func&& f, const ProtoAllocator& a = ProtoAllocator());

    } // inline namespace network_v1
  } // namespace experimental

  template<class Allocator>
    struct uses_allocator<experimental::network_v1::executor, Allocator>
      : true_type {};

} // namespace std

10.13.2. Requirements

[async.reqmts]

10.13.2.1. Proto-allocator requirements

[async.reqmts.proto.allocator]

A type A meets the proto-allocator requirements if A is CopyConstructible (C++Std, [copyconstructible]), Destructible (C++Std, [destructible]), and allocator_traits<A>::rebind_alloc<U> meets the allocator requirements (C++Std, [allocator.requirements]), where U is an object type. [Note: For example, std::allocator<void> meets the proto-allocator requirements but not the allocator requirements. —end note] No constructor, comparison operator, copy operation, move operation, or swap operation on these types shall exit via an exception.

10.13.2.2. Requirements on asynchronous operations

[async.reqmts.async]

In this Technical Specification, an asynchronous operation is initiated by a function that is named with the prefix async_. These functions shall be known as initiating functions.

10.13.2.2.1. Completion tokens and handlers

[async.reqmts.async.token]

All initiating functions in this Technical Specification:

— are function templates with template parameter CompletionToken;

— accept, as the final parameter, a completion token object token of type CompletionToken;

— specify a Completion signature element that defines a call signature Signature (C++ Std [func.def]).

A completion handler is a function object that will be invoked, at most once, with the result of an asynchronous operation.

An initiating function determines the type CompletionHandler of its completion handler function object by performing completion_handler_type_t<CompletionToken, Signature>. The completion handler object completion_handler is initialized with completion_handler(forward<CompletionToken>(token)). [Note: No other requirements are placed on the type CompletionToken. —end note]

The type CompletionHandler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with the specified completion signature. The Completion signature elements in this Technical Specification have named parameters, and the result of an asynchronous operation is specified in terms of these names.

10.13.2.2.2. Automatic deduction of initiating function return type

[async.reqmts.async.return.type]

For the sake of exposition, this specification sometimes annotates functions with a return type DEDUCED. For every function declaration that returns DEDUCED, the meaning is equivalent to specifying the return type as typename async_result<CompletionHandler>::type.

10.13.2.2.3. Production of initiating function return value

[async.reqmts.async.return.value]

An initiating function in this Technical Specification produces its return type as follows:

— constructing an object result of type async_result<CompletionHandler>, initialized as result(handler); and

— using result.get() as the operand of the return statement.

[Example: Given an asynchronous operation with Completion signature void(R1 r1, R2 r2), an initiating function meeting these requirements may be implemented as follows:

template<class CompletionToken>
auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
{
  completion_handler_type_t<decay_t<CompletionToken>, void(R1 r1, R2 r2)>
    completion_handler(forward<CompletionToken>(token));

  async_result<decltype(completion_handler)> result(completion_handler);

  // initiate the operation and cause completion_handler to be invoked with
  // the result

  return result.get();
}

For convenience, initiating functions may be implemented using the async_completion template:

template<class CompletionToken>
auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
{
  async_completion<CompletionToken, void(R1 r1, R2 r2)> init(token);

  // initiate the operation and cause init.completion_handler to be invoked
  // with the result

  return init.result.get();
}

end example]

10.13.2.2.4. Lifetime of initiating function arguments

[async.reqmts.async.lifetime]

Unless otherwise specified, the lifetime of arguments to initiating functions shall be treated as follows:

— If the parameter has a pointer type or has a type of lvalue reference to non-const, the implementation may assume the validity of the pointee or referent, respectively, until the completion handler is invoked. [Note: In other words, the program must guarantee the validity of the argument until the completion handler is invoked. —end note]

— Otherwise, the implementation must not assume the validity of the argument after the initiating function completes. [Note: In other words, the program is not required to guarantee the validity of the argument after the initiating function completes. —end note] The implementation may make copies of the argument, and all copies shall be destroyed no later than immediately after invocation of the completion handler.

10.13.2.2.5. Associated executor

[async.reqmts.async.assoc.exec]

Certain objects that participate in asynchronous operations have an associated executor. These are obtained as specified below.

10.13.2.2.6. I/O executor

[async.reqmts.async.io.exec]

All asynchronous operations in this Technical Specification have an associated executor object satisfying the Executor requirements. If the initiating function is a member function, the associated executor is that returned by the get_executor member function on the same object. If the initiating function is not a member function, the associated executor is that returned by the get_executor member function of the first argument to the initiating function.

Let Executor1 be the type of the associated executor, and ex1 be the associated executor object obtained as described above.

10.13.2.2.7. Completion handler executor

[async.reqmts.async.handler.exec]

A completion handler object of type CompletionHandler has an associated executor object ex2 of type Executor2 satisfying the Executor requirements. The type Executor2 is associated_executor_t<CompletionHandler, Executor1>. The object ex2 is obtained by performing associated_executor<CompletionHandler, Executor1>::get(handler, ex1).

10.13.2.2.8. Outstanding work

[async.reqmts.async.work]

The implementation of an asynchronous operation shall maintain an object work1 of type executor_work<Executor1>, initialized with work1(ex1) and with work1.owns_work() == true, until the effects of the asynchronous operation have been realized.

The implementation of an asynchronous operation shall maintain an object work2 of type executor_work<Executor2>, initialized with work2(ex2) and with work2.owns_work() == true, until handler has been submitted for execution.

10.13.2.2.9. Allocation of intermediate storage

[async.reqmts.async.alloc]

Asynchronous operations may allocate memory. [Note: Such as a data structure to store copies of the handler object and the initiating function's arguments. —end note]

Let Alloc1 be a type, satisfying the ProtoAllocator requirements, that represents the asynchronous operation's default allocation strategy. [Note: Typically std::allocator<void>. —end note] Let alloc1 be an object of type Alloc1.

All handlers have an associated allocator object satisfying the ProtoAllocator requirements. The type Alloc2 of the handler's associated allocator shall be determined by associated_allocator_t<CompletionHandler, Alloc1>. The handler's associated allocator object alloc2 shall be obtained by performing associated_allocator<CompletionHandler, Executor1>::get(handler, alloc1).

The asynchronous operations defined in this Technical Specification:

— If required, allocate memory using only the completion handler's associated allocator.

— Prior to completion handler execution, deallocates any memory allocated.

[Note: The implementation may perform operating system or underlying API calls that perform memory allocations not using the associated allocator. Invocations of the allocator functions may not introduce data races (See C++ Std, [res.on.data.races]). —end note]

10.13.2.2.10. Execution of completion handler on completion of asynchronous operation

[async.reqmts.async.completion]

When an asynchronous operation completes, the implementation constructs a zero-argument function object f to invoke handler with the results of the operation.

If an asynchonous operation completes immediately (that is, within the thread of execution calling the initiating function, and before the initiating function returns), the completion handler shall be submitted for execution as if by performing ex2.post(std::move(f), alloc2). Otherwise, the completion handler shall be submitted for execution as if by performing ex2.dispatch(std::move(f), alloc2).

10.13.2.2.11. Completion handlers and exceptions

[async.reqmts.async.exceptions]

Completion handlers are permitted to throw exceptions. The effect of any exception propagated from the execution of a completion handler is determined by the executor which is executing the handler.

10.13.2.3. Executor requirements

[async.reqmts.executor]

The library describes a standard set of requirements for executors. A type meeting the Executor requirements embodies a set of rules for determining how submitted function objects are to be executed.

An executor type X shall satisfy the requirements of CopyConstructible (C++ Std, [copyconstructible]) and Destructible (C++ Std, [destructible]) types. No constructor, comparison operator, copy operation, move operation, swap operation, or member functions context, on_work_started, and on_work_finished on these types shall exit via an exception.

The executor copy constructor, comparison operators, and other member functions defined in these requirements shall not introduce data races as a result of concurrent calls to those functions from different threads.

In the table below, X denotes an executor class, x1 and x2 denote values of type X, cx1 and cx2 denote (possibly const) values of type X, mx1 denotes an xvalue of type X, f denotes a MoveConstructible (C++ Std, [moveconstructible]) function object callable with zero arguments, a denotes a value of type A meeting the Allocator requirements (C++ Std, [allocator.requirements]), and u denotes an identifier.

Table 3. Executor requirements

expression

type

assertion/note
pre/post-conditions

X u(cx1);

Shall not exit via an exception.

post: u == cx1

X u(mx1);

Shall not exit via an exception.

post: u equals the prior value of mx1.

cx1 == cx2

bool

Returns true only if cx1 and cx2 can be interchanged with identical effects in any of the expressions defined in these type requirements. [Note: Returning false does not necessarily imply that the effects are not identical. —end note]

operator== shall be reflexive, symmetric, and transitive, and shall not exit via an exception.

cx1 != cx2

bool

Same as !(cx1 == cx2).

x1.context()

execution_context&, or a type that is convertible to execution_context&.

Shall not exit via an exception.

x1.on_work_started()

Shall not exit via an exception.

x1.on_work_finished()

Shall not exit via an exception.

Precondition: A preceding call x2.on_work_started() where x1 == x2.

x1.dispatch(std::move(f),a)

Effects: Creates an object f1 initialized with DECAY_COPY(forward<Func>(f)) in the current thread of execution. Calls f1() at most once. The executor may invoke f1 prior to returning from dispatch.

Executor implementations should use the supplied allocator to allocate any memory required to store the function object. Prior to invoking the function object, the executor shall deallocate any memory allocated. [Note: Executors defined in this Technical Specification always use the supplied allocator. —end note]

Synchronization: The invocation of dispatch synchronizes with (C++ Std, [intro.multithread]) the invocation of f1.

x1.post(std::move(f),a)

Effects: Creates an object f1 initialized with DECAY_COPY(forward<Func>(f)) in the current thread of execution. Calls f1() at most once. The executor shall not invoke f1 in the current thread of execution prior to returning from post.

Executor implementations should use the supplied allocator to allocate any memory required to store the function object. Prior to invoking the function object, the executor shall deallocate any memory allocated. [Note: Executors defined in this Technical Specification always use the supplied allocator. —end note]

Synchronization: The invocation of post synchronizes with (C++ Std, [intro.multithread]) the invocation of f1.

x1.defer(std::move(f),a)

Effects: Creates an object f1 initialized with DECAY_COPY(forward<Func>(f)) in the current thread of execution. Calls f1() at most once. The executor shall not invoke f1 in the current thread of execution prior to returning from defer.

Executor implementations should use the supplied allocator to allocate any memory required to store the function object. Prior to invoking the function object, the executor shall deallocate any memory allocated. [Note: Executors defined in this Technical Specification always use the supplied allocator. —end note]

Synchronization: The invocation of defer synchronizes with (C++ Std, [intro.multithread]) the invocation of f1.


Although the requirements placed on defer are identical to post, defer is used to convey the intention of the caller that the submitted function is a continuation of the current call context. The executor may use this information to optimize or otherwise adjust the way in which f is invoked.

10.13.2.4. Execution context requirements

[async.reqmts.executioncontext]

An execution context shall be publicly and unambiguously derived from execution_context, and meet the additional requirements listed below.

In the table below, X denotes an execution context class, and x denotes an object of type X.

Table 4. ExecutionContext requirements

expression

return type

assertion/note
pre/post-condition

X::executor_type

type meeting executor requirements

x.get_executor()

X::executor_type

Returns an executor object that is associated with the execution context.


10.13.2.5. Service requirements

[async.reqmts.service]

A class is a service if it is publicly and unambiguously derived from execution_context::service, or if it is publicly and unambiguously derived from another service. For a service S, S::key_type is valid and denotes a type (C++Std, [temp.deduct]), and is_base_of_v<typename S::key_type, S> is true.

A service defines an explicit constructor that can be invoked with a single lvalue argument referring to the execution_context object that will own the service. Any additional constructors shall take a first lvalue argument referring to the execution_context object that will own the service. [Note: These constructors may be called by the make_service function. —end note]

[Example:

class my_service : public execution_context::service
{
public:
  typedef my_service key_type;
  explicit my_service(execution_context& ctx);
  my_service(execution_context& ctx, int some_value);
private:
  virtual void shutdown() override;
  ...
};

end example]

A service's shutdown member function shall destroy all copies of user-defined function objects that are held by the service.

10.13.2.6. Signature requirements

[async.reqmts.signature]

A type satisfies the signature requirements if it is a call signature (C++ Std, [func.def]).

10.13.3. Class template completion_handler_type

[async.handler.type]

The completion_handler_type class template is a type transformation (C++Std, [meta]) that transforms a CompletionToken into a completion handler type that is based on a Signature.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CompletionToken, class Signature, class = void>
      struct completion_handler_type
      {
        typedef CompletionToken type;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The template parameter CompletionToken shall be an object type. The template parameter Signature shall be a call signature (C++Std, [func.def]).

Specializations of completion_handler_type shall define a nested type type that satisfies the MoveConstructible requirements. An object of type type shall be a function object with call signature Signature, and type shall be constructible from a rvalue of type CompletionToken.

10.13.4. Class template async_result

[async.async.result]

The template parameter CompletionHandler is a completion handler type produced by completion_handler_type_t<T, S> for some completion token type T and call signature S.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CompletionHandler>
      class async_result
      {
      public:
        typedef void type;

        explicit async_result(CompletionHandler&) {}
        async_result(const async_result&) = delete;
        async_result& operator=(const async_result&) = delete;

        type get() {}
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Specializations of async_result shall satisfy the Destructible requirements (C++Std, [destructible]) in addition to the requirements in the table below. In this table, R is a specialization of async_result for the template parameter CompletionHandler; r is a modifiable lvalue of type R; and h is a modifiable lvalue of type CompletionHandler.

Table 5. async_result specialization requirements

Expression

Return type

Note

R::type

void; or a type satisfying MoveConstructible requirements (C++ Std, [moveconstructible])

R r(h);

r.get()

R::type

The get() member function shall be used only as the operand of a return statement.


10.13.5. Class template async_completion

[async.async.completion]

Template parameter CompletionToken specifies the model used to obtain the result of the asynchronous operation. Template parameter Signature is the call signature (C++ Std, [func.def]) for the completion handler type invoked on completion of the asynchronous operation.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CompletionToken, class Signature>
      struct async_completion
      {
        typedef completion_handler_type_t<decay_t<CompletionToken>, Signature>
          completion_handler_type;

        explicit async_completion(CompletionToken& t);
        async_completion(const async_completion&) = delete;
        async_completion& operator=(const async_completion&) = delete;

        see below completion_handler;
        async_result<completion_handler_type> result;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The template parameter Signature shall be a call signature (C++Std, [func.def]).

10.13.5.1. async_completion members

[async.async.completion.members]

explicit async_completion(CompletionToken& t);

Effects: If CompletionToken and completion_handler_type are the same type, binds completion_handler to t; otherwise, initializes completion_handler with the result of forward<CompletionToken>(t). Initializes result with completion_handler.

see below completion_handler;

Type: completion_handler_type& if CompletionToken and completion_handler_type are the same type; otherwise, completion_handler_type.

10.13.6. Class template associated_allocator

[async.assoc.alloc]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class ProtoAllocator = allocator<void>>
      struct associated_allocator
      {
        typedef see below type;

        static type get(const T& t, const ProtoAllocator& a = ProtoAllocator()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Specializations of associated_allocator shall satisfy the requirements in the table below. In this table, X is a specialization of associated_allocator for the template parameters T and ProtoAllocator; t is a value of (possibly const) T; and a is an object of type ProtoAllocator.

Table 6. associated_allocator specialization requirements

Expression

Return type

Note

typename X::type

A type meeting the proto-allocator requirements.

X::get(t)

X::type

Shall not exit via an exception.
Equivalent to X::get(t, ProtoAllocator()).

X::get(t, a)

X::type

Shall not exit via an exception.


10.13.6.1. associated_allocator members

[async.assoc.alloc.members]

typedef see below type;

Type: If T has a nested type allocator_type, typename T::allocator_type. Otherwise ProtoAllocator.

type get(const T& t, const ProtoAllocator& a = ProtoAllocator()) noexcept;

Returns: If T has a nested type allocator_type, t.get_allocator(). Otherwise a.

10.13.7. Function get_associated_allocator

[async.assoc.alloc.get]

template<class T>
  associated_allocator_t<T> get_associated_allocator(const T& t);

Returns: associated_allocator<T>::get(t).

template<class T, class ProtoAllocator>
  associated_allocator_t<T, ProtoAllocator>
    get_associated_allocator(const T& t, const ProtoAllocator& a);

Returns: associated_allocator<T, ProtoAllocator>::get(t, a).

10.13.8. Class execution_context

[async.exec.ctx]

Class execution_context implements an extensible, type-safe, polymorphic set of services, indexed by service type.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class execution_context
      {
      public:
        class service;

        // construct / copy / destroy:

        execution_context();
        execution_context(const execution_context&) = delete;
        execution_context& operator=(const execution_context&) = delete;
        virtual ~execution_context();

        // execution context operations:

        void notify_fork(fork_event e);

      protected:

        // execution context protected operations:

        void shutdown();
        void destroy();
      };

      // service access:
      template<class Service> typename Service::key_type&
        use_service(execution_context& ctx);
      template<class Service, class... Args> Service&
        make_service(execution_context& ctx, Args&&... args);
      template<class Service> bool has_service(const execution_context& ctx) noexcept;
      class service_already_exists : public logic_error { };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Access to the services of an execution_context is via three function templates, use_service<>, make_service<> and has_service<>.

In a call to use_service<Service>(), the type argument chooses a service. If the service is not present in an execution_context, an object of type Service is created and added to the execution_context. A program can check if an execution_context implements a particular service with the function template has_service<Service>().

Service objects may be explicitly added to an execution_context using the function template make_service<Service>(). If the service is already present, make_service exits via an exception of type service_already_exists.

Once a service reference is obtained from an execution_context object by calling use_service<>, that reference remains usable until a call to destroy().

10.13.8.1. execution_context constructor

[async.exec.ctx.cons]

execution_context();

Effects: Creates an object of class execution_context which contains no services. [Note: An implementation might preload service of internal service types for its own use. —end note]

10.13.8.2. execution_context destructor

[async.exec.ctx.dtor]

~execution_context();

Effects: Destroys an object of class execution_context. Performs shutdown() followed by destroy().

10.13.8.3. execution_context operations

[async.exec.ctx.ops]

void notify_fork(fork_event e);

Effects: For each service object svc in the set:
— If e == fork_event::prepare, performs svc->notify_fork(e) in reverse order of addition to the set.
— Otherwise, performs svc->notify_fork(e) in order of addition to the set.

10.13.8.4. execution_context protected operations

[async.exec.ctx.protected]

void shutdown();

Effects: For each service object svc in the execution_context set, in reverse order of addition to the set, performs svc->shutdown(). For each service in the set, svc->shutdown() is called only once irrespective of the number of calls to shutdown on the execution_context.

void destroy();

[function_effects Destroys each service object in the execution_context set, and removes it from the set, in reverse order of addition to the set.

10.13.8.5. execution_context globals

[async.exec.ctx.globals]

The functions use_service, make_service, and has_service shall not introduce data races as a result of concurrent calls to those functions from different threads.

template<class Service> typename Service::key_type&
  use_service(execution_context& ctx);

Effects: If an object of type Service::key_type does not already exist in the execution_context set identified by ctx, creates an object of type Service, initialized as Service(ctx), and adds it to the set.

Returns: A reference to the corresponding service of ctx.

Notes: The reference returned remains valid until a call to destroy.

template<class Service, class... Args> Service&
  make_service(execution_context& ctx, Args&&... args);

Requires: A service object of type Service::key_type does not already exist in the execution_context set identified by ctx.

Effects: Creates an object of type Service, initialized as Service(ctx, forward<Args>(args)...), and adds it to the execution_context set identified by ctx.

Throws: service_already_exists if a corresponding service object of type Key is already present in the set.

Notes: The reference returned remains valid until a call to destroy.

template<class Service> bool has_service(const execution_context& ctx) noexcept;

Returns: true if an object of type Service::key_type is present in ctx, otherwise false.

10.13.9. Class execution_context::service

[async.exec.ctx.svc]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class execution_context::service
      {
      protected:
        // construct / copy / destroy:

        explicit service(execution_context& owner);
        service(const service&) = delete;
        service& operator=(const service&) = delete;
        virtual ~service();

        // service observers:

        execution_context& context() noexcept;

      private:
        // service operations:

        virtual void shutdown() = 0;
        virtual void notify_fork(fork_event e) {}

        execution_context& context_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.13.9.1. execution_context::service members

[async.exec.ctx.svc.members]

explicit service(execution_context& owner);

Postconditions: std::addressof(context_) == std::addressof(owner).

execution_context& context() noexcept;

Returns: context_.

10.13.10. Class template is_executor

[async.is.exec]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T> struct is_executor : false_type {};

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

is_executor can be used to detect executor types satisfying the Executor type requirements.

Instantiations of the is_executor template shall meet the UnaryTypeTrait requirements (C++ Std, [meta.rqmts]). A program may specialize this template for a user-defined type T to have a BaseCharacteristic of integral_constant<int, N> with N > 0 to indicate that T should be treated as an executor type.

10.13.11. Executor argument tag

[async.executor.arg]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      struct executor_arg_t { };
      constexpr executor_arg_t executor_arg = executor_arg_t();

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The executor_arg_t struct is an empty structure type used as a unique type to disambiguate constructor and function overloading. Specifically, types may have constructors with executor_arg_t as the first argument, immediately followed by an argument of a type that satisfies the Executor requirements.

10.13.12. uses_executor

[async.uses.executor]

10.13.12.1. uses_executor trait

[async.uses.executor.trait]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor> struct uses_executor;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Remark: Detects whether T has a nested executor_type that is convertible from Executor. Meets the BinaryTypeTrait requirements (C++ Std, [meta.rqmts]). The implementation shall provide a definition that is derived from true_type if a type T::executor_type exists and is_convertible<Executor, T::executor_type>::value != false, otherwise it shall be derived from false_type. A program may specialize this template to derive from true_type for a user-defined type T that does not have a nested executor_type but nonetheless can be constructed with an executor if the first argument of a constructor has type executor_arg_t and the second argument has type Executor.

10.13.12.2. uses-executor construction

[async.uses.executor.cons]

Uses-executor construction with executor Executor refers to the construction of an object obj of type T, using constructor arguments v1, v2, ..., vN of types V1, V2, ..., VN, respectively, and an executor ex of type Executor, according to the following rules:

— if uses_executor<T, Executor>::value is true and is_constructible<T, executor_arg_t, Executor, V1, V2, ..., VN>::value is true, then obj is initialized as obj(executor_arg, ex, v1, v2, ..., vN);

— otherwise, obj is initialized as obj(v1, v2, ..., vN).

10.13.13. Class template associated_executor

[async.assoc.exec]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor = system_executor>
      struct associated_executor
      {
        typedef see below type;

        static type get(const T& t, const Executor& e = Executor()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

A program may specialize this traits type if the T template parameter in the specialization is a user-defined type. The template parameter Executor shall be a type meeting Executor requirements.

Specializations of associated_executor shall satisfy the requirements in the table below. In this table, X is a specialization of associated_executor for the template parameter T; t is a const reference to an object of type T; and e is an object of type Executor.

Table 7. associated_executor specialization requirements

Expression

Return type

Note

typename X::type

A type meeting Executor requirements.

X::get(t)

X::type

Shall not exit via an exception.
Equivalent to X::get(t, Executor()).

X::get(t, e)

X::type

Shall not exit via an exception.


10.13.13.1. associated_executor members

[async.assoc.exec.members]

typedef see below type;

Type: If T has a nested type executor_type, typename T::executor_type. Otherwise Executor.

type get(const T& t, const Executor& e = Executor()) noexcept;

Returns: If T has a nested type executor_type, t.get_executor(). Otherwise e.

10.13.14. Function get_associated_executor

[async.assoc.exec.get]

template<class T>
  associated_executor_t<T> get_associated_executor(const T& t);

Returns: associated_executor<T>::get(t).

template<class T, class Executor>
  associated_executor_t<T, Executor>
    get_associated_executor(const T& t, const Executor& ex);

Returns: associated_executor<T, Executor>::get(t, ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class T, class ExecutionContext>
  associated_executor_t<T, typename ExecutionContext::executor_type>
    get_associated_executor(const T& t, ExecutionContext& ctx);

Returns: get_associated_executor(t, ctx.get_executor()).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

10.13.15. Class template executor_wrapper

[async.exec.wrapper]

executor_wrapper<T, Executor> is a wrapper around an object or function of type T, and an executor object of type Executor satisfying Executor requirements.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor>
      class executor_wrapper
      {
      public:
        // types:

        typedef T wrapped_type;
        typedef Executor executor_type;

        // construct / copy / destroy:

        executor_wrapper(T t, const Executor& ex);
        executor_wrapper(const executor_wrapper& other) = default;
        executor_wrapper(executor_wrapper&& other) = default;
        template<class U, class OtherExecutor>
          executor_wrapper(const executor_wrapper<U, OtherExecutor>& other);
        template<class U, class OtherExecutor>
          executor_wrapper(executor_wrapper<U, OtherExecutor>&& other);
        template<class U, class OtherExecutor>
          executor_wrapper(executor_arg_t, const Executor& ex,
            const executor_wrapper<U, OtherExecutor>& other);
        template<class U, class OtherExecutor>
          executor_wrapper(executor_arg_t, const Executor& ex,
            executor_wrapper<U, OtherExecutor>&& other);

        ~executor_wrapper();

        // executor wrapper access:

        T& unwrap() noexcept;
        const T& unwrap() const noexcept;
        executor_type get_executor() const noexcept;

        // executor wrapper invocation:

        template<class... Args>
          result_of_t<T&(Args&&...)> operator()(Args&&... args);
        template<class... Args>
          result_of_t<const T&(Args&&...)> operator()(Args&&... args) const;

      private:
        Executor ex_; // exposition only
        T wrapped_; // exposition only
      };

      template<class T, class Executor, class Signature>
      struct completion_handler_type<executor_wrapper<T, Executor>, Signature>
      {
        typedef executor_wrapper<completion_handler_type_t<T, Signature>, Executor> type;
      };

      template<class T, class Executor>
        class async_result<executor_wrapper<T, Executor>>;

      template<class T, class Executor, class ProtoAllocator>
        struct associated_allocator<executor_wrapper<T, Executor>, ProtoAllocator>;

      template<class T, class Executor, class Executor1>
        struct associated_executor<executor_wrapper<T, Executor>, Executor1>;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.13.15.1. executor_wrapper constructors

[async.exec.wrapper.cons]

executor_wrapper(T t, const Executor& ex);

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with the value ex. Initializes wrapped_ by performing uses-executor construction, using the constructor argument std::move(t) and the executor ex_.

template<class U, class OtherExecutor>
  executor_wrapper(const executor_wrapper<U, OtherExecutor>& other);

Requires: If U is not convertible to T, or if OtherExecutor is not convertible to Executor, the program is ill-formed.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with other.get_executor(). Initializes wrapped_ by performing uses-executor construction, using the constructor argument other.unwrap() and the executor ex_.

template<class U, class OtherExecutor>
  executor_wrapper(executor_wrapper<U, OtherExecutor>&& other);

Requires: If U is not convertible to T, or if OtherExecutor is not convertible to Executor, the program is ill-formed.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with other.get_executor(). Initializes wrapped_ by performing uses-executor construction, using the constructor argument std::move(other.unwrap()) and the executor ex_.

template<class U, class OtherExecutor>
  executor_wrapper(executor_arg_t, const Executor& ex,
    const executor_wrapper<U, OtherExecutor>& other);

Requires: If U is not convertible to T the program is ill-formed.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with ex. Initializes wrapped_ by performing uses-executor construction, using the constructor argument other.unwrap() and the executor ex_.

template<class U, class OtherExecutor>
  executor_wrapper(executor_arg_t, const Executor& ex,
    executor_wrapper<U, OtherExecutor>&& other);

Requires: U is T or convertible to T.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with ex. Initializes wrapped_ by performing uses-executor construction, using the constructor argument std::move(other.unwrap()) and the executor ex_.

10.13.15.2. executor_wrapper access

[async.exec.wrapper.access]

T& unwrap() noexcept;
const T& unwrap() const noexcept;

Returns: wrapped_.

executor_type get_executor() const noexcept;

Returns: executor_.

10.13.15.3. executor_wrapper invocation

[async.exec.wrapper.invocation]

template<class... Args>
  result_of_t<T&(Args&&...)> operator()(Args&&... args);
template<class... Args>
  result_of_t<const T&(Args&&...)> operator()(Args&&... args) const;

Returns: INVOKE(unwrap(), forward<Args>(args)...) (C++ Std, [func.require]).

10.13.15.4. Class template partial specialization async_result

[async.exec.wrapper.async.result]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor>
      class async_result<executor_wrapper<T, Executor>>
      {
      public:
        typedef typename async_result<T>::type type;

        explicit async_result(executor_wrapper<T, Executor>& wrapper);
        async_result(const async_result&) = delete;
        async_result& operator=(const async_result&) = delete;

        type get();

      private:
        async_result<T> wrapped_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

explicit async_result(executor_wrapper<T, Executor>& wrapper);

Effects: Initializes wrapped_ as wrapped_(wrapper.unwrap()).

type get();

Returns: wrapped_.get().

10.13.15.5. Class template partial specialization associated_allocator

[async.exec.wrapper.assoc.alloc]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor, class ProtoAllocator>
        struct associated_allocator<executor_wrapper<T, Executor>, ProtoAllocator>
      {
        typedef associated_allocator_t<T, ProtoAllocator> type;

        static type get(const executor_wrapper<T, Executor>& w,
                        const ProtoAllocator& a = ProtoAllocator()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

static type get(const executor_wrapper<T, Executor>& w,
                const ProtoAllocator& a = ProtoAllocator()) noexcept;

Returns: associated_allocator<T, ProtoAllocator>::get(w.unwrap(), a).

10.13.15.6. Class template partial specialization associated_executor

[async.exec.wrapper.assoc.exec]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor, class Executor1>
        struct associated_executor<executor_wrapper<T, Executor>, Executor1>
      {
        typedef Executor type;

        static type get(const executor_wrapper<T, Executor>& w,
                        const Executor1& e = Executor1()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

static type get(const executor_wrapper<T, Executor>& w,
                const Executor1& e = Executor1()) noexcept;

Returns: w.get_executor().

10.13.16. Function wrap

[async.wrap]

template<class Executor, class T>
  executor_wrapper<decay_t<T>, Executor> wrap(const Executor& ex, T&& t);

Returns: executor_wrapper<decay_t<T>, Executor>(forward<T>(t), ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  executor_wrapper<decay_t<T>, typename ExecutionContext::executor_type>
    wrap(ExecutionContext& ctx, T&& t);

Returns: wrap(ctx.get_executor(), forward<T>(t)).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

10.13.17. Class template executor_work

[async.exec.work]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Executor>
      class executor_work
      {
      public:
        // types:

        typedef Executor executor_type;

        // construct / copy / destroy:

        explicit executor_work(const executor_type& ex) noexcept;
        executor_work(const executor_work& other) noexcept;
        executor_work(executor_work&& other) noexcept;

        executor_work& operator=(const executor_work&) = delete;

        ~executor_work();

        // executor work observers:

        executor_type get_executor() const noexcept;
        bool owns_work() const noexcept;

        // executor work modifiers:

        void reset() noexcept;

      private:
        Executor ex_; // exposition only
        bool owns_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.13.17.1. executor_work members

[async.exec.work.members]

explicit executor_work(const executor_type& ex) noexcept;

Effects: Constructs an object of class executor_work, initializing ex_ with ex, and then performing ex_.on_work_started().

Postconditions: ex == ex_ and owns_ == true.

executor_work(const executor_work& other) noexcept;

Effects: Constructs an object of class executor_work, initializing ex_ with other.ex_. If other.owns_ == true, performs ex_.on_work_started().

Postconditions: ex_ == other.ex_ and owns_ == other.owns_.

executor_work(executor_work&& other) noexcept;

Effects: Constructs an object of class executor_work, initializing ex_ with std::move(other.ex_) and owns_ with other.owns_, and sets other.owns_ to false.

~executor_work();

Effects: If owns_ is true, performs ex_.on_work_finished().

executor_type get_executor() const noexcept;

Returns: ex_.

bool owns_work() const noexcept;

Returns: owns_.

void reset() noexcept;

Effects: If owns_ is true, performs ex_.on_work_finished().

Postconditions: owns_ == false.

10.13.18. Function make_work

[async.make.work]

template<class Executor>
  executor_work<Executor>
    make_work(const Executor& ex);

Returns: executor_work<Executor>(ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext>
  executor_work<typename ExecutionContext::executor_type>
    make_work(ExecutionContext& ctx);

Returns: An object of type executor_work<typename ExecutionContext::executor_type> initialized with the result of ctx.get_executor().

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

template<class T>
  executor_work<associated_executor_t<T>>
    make_work(const T& t);

Returns: An object of type executor_work<associated_executor_t<T>> initialized with the result of associated_executor<T>::get(t).

Remarks: This function shall not participate in overload resolution unless is_executor<T>::value is false and is_convertible<T&, execution_context&>::value is false.

template<class T, class Executor>
  executor_work<associated_executor_t<T, Executor>>
    make_work(const T& t, const Executor& ex);

Returns: An object of type executor_work<associated_executor_t<T, Executor>> initialized with the result of associated_executor<T, Executor>::get(t, ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class T, class ExecutionContext>
  executor_work<associated_executor_t<T, typename ExecutionContext::executor_type>>
    make_work(const T& t, ExecutionContext& ctx);

Returns: An object of type executor_work<associated_executor_t<T, typename ExecutionContext::executor_type>> initialized with the result of associated_executor<T, typename ExecutionContext::executor_type>::get(t, ctx.get_executor()).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

10.13.19. Class system_executor

[async.system.exec]

Class system_executor represents a set of rules where function objects are permitted to execute on any thread.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class system_executor
      {
      public:
        // constructors:

        system_executor() {}

        // executor operations:

        execution_context& context() noexcept;

        void on_work_started() noexcept {}
        void on_work_finished() noexcept {}

        template<class Func, class ProtoAllocator>
          void dispatch(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void post(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void defer(Func&& f, const ProtoAllocator& a);
      };

      bool operator==(const system_executor&, const system_executor&) noexcept;
      bool operator!=(const system_executor&, const system_executor&) noexcept;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Class system_executor satisfies the Executor requirements.

To satisfy the executor requirements for the post and defer member functions, the system executor may create thread objects to run the submitted function objects. If the program is terminated by any means, and there remain unexecuted functions objects that have been submitted using post or defer, these function objects are discarded without calling them.

10.13.19.1. system_executor operations

[async.system.exec.ops]

execution_context& context() noexcept;

Returns: A reference to an object with static storage duration whose type is derived from execution_context.

template<class Func, class ProtoAllocator>
  void dispatch(Func&& f, const ProtoAllocator& a);

Effects: Equivalent to DECAY_COPY(forward<Func>(f))().

template<class Func, class ProtoAllocator>
  void post(Func&& f, const ProtoAllocator& a);
template<class Func, class ProtoAllocator>
  void defer(Func&& f, const ProtoAllocator& a);

Effects: Creates an object f1 initialized with DECAY_COPY(forward<Func>(f)), and calls f1 as if in a thread of execution represented by a thread object. Any exception propagated from the execution of DECAY_COPY(forward<Func>(f))() shall result in a call to std::terminate.

10.13.19.2. system_executor comparisons

[async.system.exec.comparisons]

bool operator==(const system_executor&, const system_executor&) noexcept;

Returns: true.

bool operator!=(const system_executor&, const system_executor&) noexcept;

Returns: false.

10.13.20. Class bad_executor

[async.bad.exec]

An exception of type bad_executor is thrown by executor member functions dispatch, post, and defer when the executor object has no target.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class bad_executor : public exception
      {
      public:
        // constructor:
        bad_executor() noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

bad_executor() noexcept;

Effects: constructs a bad_executor object.

Postconditions: what() returns an implementation-defined NTBS.

10.13.21. Class executor

[async.executor]

The executor class provides a polymorphic wrapper for types that satisfy the Executor requirements.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class executor
      {
      public:
        // construct / copy / destroy:

        executor() noexcept;
        executor(nullptr_t) noexcept;
        executor(const executor& e) noexcept;
        executor(executor&& e) noexcept;
        template<class Executor> executor(Executor e);
        template<class Executor, class ProtoAllocator>
          executor(allocator_arg_t, const ProtoAllocator& a, Executor e);

        executor& operator=(const executor& e) noexcept;
        executor& operator=(executor&& e) noexcept;
        executor& operator=(nullptr_t) noexcept;
        template<class Executor> executor& operator=(Executor e);

        ~executor();

        // executor modifiers:

        void swap(executor& other) noexcept;
        template<class Executor, class ProtoAllocator>
          void assign(Executor e, const ProtoAllocator& a);

        // executor operations:

        execution_context& context() noexcept;

        void on_work_started() noexcept;
        void on_work_finished() noexcept;

        template<class Func, class ProtoAllocator>
          void dispatch(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void post(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void defer(Func&& f, const ProtoAllocator& a);

        // executor capacity:

        explicit operator bool() const noexcept;

        // executor target access:

        const type_info& target_type() const noexcept;
        template<class Executor> Executor* target() noexcept;
        template<class Executor> const Executor* target() const noexcept;
      };

      template<> struct is_executor<executor> : true_type {};

      // executor comparisons:

      bool operator==(const executor& a, const executor& b) noexcept;
      bool operator==(const executor& e, nullptr_t) noexcept;
      bool operator==(nullptr_t, const executor& e) noexcept;
      bool operator!=(const executor& a, const executor& b) noexcept;
      bool operator!=(const executor& e, nullptr_t) noexcept;
      bool operator!=(nullptr_t, const executor& e) noexcept;

      // executor specialized algorithms:

      void swap(executor& a, executor& b) noexcept;

    } // inline namespace network_v1
  } // namespace experimental

  template<class Allocator>
    struct uses_allocator<experimental::network_v1::executor, Allocator>
      : true_type {};

} // namespace std

The target is the executor object that is held by the wrapper. The executor type itself meets the requirements for an Executor.

[Note: To meet the noexcept requirements for executor copy constructors and move constructors, implementations may share a target between two or more executor objects. —end note]

10.13.21.1. executor constructors

[async.executor.cons]

executor() noexcept;

Postconditions: !*this.

executor(nullptr_t) noexcept;

Postconditions: !*this.

executor(const executor& e) noexcept;

Postconditions: !*this if !e; otherwise, *this targets e.target() or a copy of e.target().

executor(executor&& e) noexcept;

Effects: If !e, *this has no target; otherwise, moves e.target() or move-constructs the target of e into the target of *this, leaving e in a valid state with an unspecified value.

template<class Executor> executor(Executor e);

Effects: *this targets a copy of e initialized with std::move(e).

template<class Executor, class ProtoAllocator>
  executor(allocator_arg_t, const ProtoAllocator& a, Executor e);

Effects: *this targets a copy of e initialized with std::move(e).

A copy of the allocator argument is used to allocate memory, if necessary, for the internal data structures of the constructed executor object.

10.13.21.2. executor assignment

[async.executor.assign]

executor& operator=(const executor& e) noexcept;

Effects: executor(e).swap(*this).

Returns: *this.

executor& operator=(executor&& e) noexcept;

Effects: Replaces the target of *this with the target of e, leaving e in a valid state with an unspecified value.

Returns: *this.

executor& operator=(nullptr_t) noexcept;

Effects: executor(nullptr).swap(*this).

Returns: *this.

template<class Executor> executor& operator=(Executor e);

Effects: executor(std::move(e)).swap(*this).

Returns: *this.

10.13.21.3. executor destructor

[async.executor.dtor]

~executor();

Effects: If *this != nullptr, releases shared ownership of, or destroys, the target of *this.

10.13.21.4. executor modifiers

[async.executor.modifiers]

void swap(executor& other) noexcept;

Effects: Interchanges the targets of *this and other.

template<class Executor, class ProtoAllocator>
  void assign(Executor e, const ProtoAllocator& a);

Effects: executor(allocator_arg, a, std::move(e)).swap(*this).

10.13.21.5. executor operations

[async.executor.ops]

execution_context& context() noexcept;

Requires: *this != nullptr.

Returns: e.context(), where e is the target object of *this.

void on_work_started() noexcept;

Requires: *this != nullptr.

Effects: e.on_work_started(), where e is the target object of *this.

void on_work_finished() noexcept;

Requires: *this != nullptr.

Effects: e.on_work_finished(), where e is the target object of *this.

template<class Func, class ProtoAllocator>
  void dispatch(Func&& f, const ProtoAllocator& a);

Effects: e.dispatch(g, a), where e is the target object of *this, and g is a function object of unspecified type that, when called as g(), performs DECAY_COPY(f)().

template<class Func, class ProtoAllocator>
  void post(Func&& f, const ProtoAllocator& a);

Effects: e.post(g, a), where e is the target object of *this, and g is a function object of unspecified type that, when called as g(), performs DECAY_COPY(f)().

template<class Func, class ProtoAllocator>
  void defer(Func&& f, const ProtoAllocator& a);

Effects: e.defer(g, a), where e is the target object of *this, and g is a function object of unspecified type that, when called as g(), performs DECAY_COPY(f)().

10.13.21.6. executor capacity

[async.executor.capacity]

explicit operator bool() const noexcept;

Returns: true if *this has a target, otherwise false.

10.13.21.7. executor target access

[async.executor.target]

const type_info& target_type() const noexcept;

Returns: If *this has a target of type T, typeid(T); otherwise, typeid(void).

template<class Executor> Executor* target() noexcept;
template<class Executor> const Executor* target() const noexcept;

Returns: If target_type() == typeid(Executor) a pointer to the stored executor target; otherwise a null pointer value.

10.13.21.8. executor comparisons

[async.executor.comparisons]

bool operator==(const executor& a, const executor& b) noexcept;

Returns:
true if !a and !b;
true if a and b share a target;
true if e and f are the same type and e == f, where e is the target of a and f is the target of b;
— otherwise false.

bool operator==(const executor& e, nullptr_t) noexcept;
bool operator==(nullptr_t, const executor& e) noexcept;

Returns: !e.

bool operator!=(const executor& a, const executor& b) noexcept;

Returns: !(a == b).

bool operator!=(const executor& e, nullptr_t) noexcept;
bool operator!=(nullptr_t, const executor& e) noexcept;

Returns: (bool) e.

10.13.21.9. executor specialized algorithms

[async.executor.algo]

void swap(executor& a, executor& b) noexcept;

Effects: a.swap(b).

10.13.22. Function dispatch

[async.dispatch]

template<class CompletionToken>
  DEDUCED dispatch(CompletionToken&& token);

Let the type CompletionHandler be the completion handler type determined by performing completion_handler_type_t<CompletionToken, void()>.

Requires: The type CompletionHandler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object completion_handler of type CompletionHandler, initialized as completion_handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<CompletionHandler>, initializing the object as result(completion_handler).
— Obtains the completion handler's associated executor object ex by performing get_associated_executor(completion_handler).
— Obtains the completion handler's associated allocator object alloc by performing get_associated_allocator(completion_handler).
— Performs ex.dispatch(std::move(completion_handler), alloc).

Returns: result.get().

template<class Executor, class CompletionToken>
  DEDUCED dispatch(const Executor& ex, CompletionToken&& token);

Let the type CompletionHandler be the completion handler type determined by performing completion_handler_type_t<CompletionToken, void()>.

Requires: The type CompletionHandler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object completion_handler of type CompletionHandler, initialized as completion_handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<CompletionHandler>, initializing the object as result(completion_handler).
— Obtains the completion handler's associated executor object ex1 by performing get_associated_executor(completion_handler).
— Creates a work object w by performing make_work(ex1).
— Obtains the completion handler's associated allocator object alloc by performing get_associated_allocator(completion_handler).
— Constructs a function object f with a function call operator that performs ex1.dispatch(std::move(completion_handler), alloc) followed by w.reset().
— Performs ex.dispatch(std::move(f), alloc).

Returns: result.get().

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  DEDUCED dispatch(ExecutionContext& ctx, CompletionToken&& token);

Returns: std::experimental::dispatch(ctx.get_executor(), forward<CompletionToken>(token)).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

10.13.23. Function post

[async.post]

template<class CompletionToken>
  DEDUCED post(CompletionToken&& token);

Let the type CompletionHandler be the completion handler type determined by performing completion_handler_type_t<CompletionToken, void()>.

Requires: The type CompletionHandler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object completion_handler of type CompletionHandler, initialized as completion_handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<CompletionHandler>, initializing the object as result(completion_handler).
— Obtains the completion handler's associated executor object ex by performing get_associated_executor(completion_handler).
— Obtains the completion handler's associated allocator object alloc by performing get_associated_allocator(completion_handler).
— Performs ex.post(std::move(completion_handler), alloc).

Returns: result.get().

template<class Executor, class CompletionToken>
  DEDUCED post(const Executor& ex, CompletionToken&& token);

Let the type CompletionHandler be the completion handler type determined by performing completion_handler_type_t<CompletionToken, void()>.

Requires: The type CompletionHandler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object completion_handler of type CompletionHandler, initialized as completion_handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<CompletionHandler>, initializing the object as result(completion_handler).
— Obtains the completion handler's associated executor object ex1 by performing get_associated_executor(completion_handler).
— Creates a work object w by performing make_work(ex1).
— Obtains the completion handler's associated allocator object alloc by performing get_associated_allocator(completion_handler).
— Constructs a function object f with a function call operator that performs ex1.dispatch(std::move(completion_handler), alloc) followed by w.reset().
— Performs ex.post(std::move(f), alloc).

Returns: result.get().

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  DEDUCED post(ExecutionContext& ctx, CompletionToken&& token);

Returns: std::experimental::post(ctx.get_executor(), forward<CompletionToken>(token)).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

10.13.24. Function defer

[async.defer]

template<class CompletionToken>
  DEDUCED defer(CompletionToken&& token);

Let the type CompletionHandler be the completion handler type determined by performing completion_handler_type_t<CompletionToken, void()>.

Requires: The type CompletionHandler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object completion_handler of type CompletionHandler, initialized as completion_handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<CompletionHandler>, initializing the object as result(completion_handler).
— Obtains the completion handler's associated executor object ex by performing get_associated_executor(completion_handler).
— Obtains the completion handler's associated allocator object alloc by performing get_associated_allocator(completion_handler).
— Performs ex.defer(std::move(completion_handler), alloc).

Returns: result.get().

template<class Executor, class CompletionToken>
  DEDUCED defer(const Executor& ex, CompletionToken&& token);

Let the type CompletionHandler be the completion handler type determined by performing completion_handler_type_t<CompletionToken, void()>.

Requires: The type CompletionHandler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object completion_handler of type CompletionHandler, initialized as completion_handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<CompletionHandler>, initializing the object as result(completion_handler).
— Obtains the completion handler's associated executor object ex1 by performing get_associated_executor(completion_handler).
— Creates a work object w by performing make_work(ex1).
— Obtains the completion handler's associated allocator object alloc by performing get_associated_allocator(completion_handler).
— Constructs a function object f with a function call operator that performs ex1.dispatch(std::move(completion_handler), alloc) followed by w.reset().
— Performs ex.defer(std::move(f), alloc).

Returns: result.get().

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  DEDUCED defer(ExecutionContext& ctx, CompletionToken&& token);

Returns: std::experimental::defer(ctx.get_executor(), forward<CompletionToken>(token)).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

10.13.25. Class template strand

[async.strand]

The class template strand is a wrapper around an object of type Executor satisfying the Executor requirements.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Executor>
      class strand
      {
      public:
        // types:

        typedef Executor inner_executor_type;

        // construct / copy / destroy:

        strand();
        explicit strand(Executor ex);
        strand(const strand& other) noexcept;
        strand(strand&& other) noexcept;
        template<class OtherExecutor> strand(const strand<OtherExecutor>& other) noexcept;
        template<class OtherExecutor> strand(strand<OtherExecutor>&& other) noexcept;

        strand& operator=(const strand& other) noexcept;
        strand& operator=(strand&& other) noexcept;
        template<class OtherExecutor> strand& operator=(const strand<OtherExecutor>& other) noexcept;
        template<class OtherExecutor> strand& operator=(strand<OtherExecutor>&& other) noexcept;

        ~strand();

        // strand operations:

        inner_executor_type get_inner_executor() const noexcept;

        bool running_in_this_thread() const noexcept;

        execution_context& context() noexcept;

        void on_work_started() noexcept;
        void on_work_finished() noexcept;

        template<class Func, class ProtoAllocator>
          void dispatch(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void post(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void defer(Func&& f, const ProtoAllocator& a);

      private:
        Executor inner_ex_; // exposition only
      };

      bool operator==(const strand<Executor>& a, const strand<Executor>& b);
      bool operator!=(const strand<Executor>& a, const strand<Executor>& b);

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

strand<Executor> satisfies the Executor requirements.

A strand provides guarantees of ordering and non-concurrency. Given:

— strand objects s1 and s2 such that s1 == s2

— a function object f1 added to the strand s1 using post or defer, or using dispatch when s1.running_in_this_thread() == false

— a function object f2 added to the strand s2 using post or defer, or using dispatch when s2.running_in_this_thread() == false

then the implementation invokes f1 and f2 such that:

— the invocation of f1 is not concurrent with the invocation of f2

— the invocation of f1 synchronizes with the invocation of f2.

Furthermore, if the addition of f1 happens before the addition of f2, then the invocation of f1 happens before the invocation of f2.

All member functions, except for the assignment operators and the destructor, do not introduce data races on *this, including its ordered, non-concurrent state. Additionally, constructors and assignment operators do not introduce data races on lvalue arguments.

If any function f executed by the strand throws an exception, the subsequent strand state is as if f had exited without throwing an exception.

10.13.25.1. strand constructors

[async.strand.cons]

strand();

Effects: Constructs an object of class strand<Executor> that represents a unique ordered, non-concurrent state. Initializes inner_ex_ with inner_ex_().

Remarks: This overload shall not participate in overload resolution unless Executor satisfies the DefaultConstructible requirements (C++ Std, [defaultconstructible]).

explicit strand(Executor ex);

Effects: Constructs an object of class strand<Executor> that represents a unique ordered, non-concurrent state. Initializes inner_ex_ as inner_ex_(ex).

strand(const strand& other) noexcept;

Effects: Constructs an object of class strand<Executor>. Initializes inner_ex_ as inner_ex_(other.inner_ex_).

Postconditions:
*this == other
get_inner_executor() == other.get_inner_executor()

strand(strand&& other) noexcept;

Effects: Constructs an object of class strand<Executor>. Initializes inner_ex_ with inner_ex_(std::move(other.inner_ex_)).

Postconditions:
*this is equal to the prior value of other
get_inner_executor() == other.get_inner_executor()

template<class OtherExecutor> strand(const strand<OtherExecutor>& other) noexcept;

Requires: OtherExecutor is convertible to Executor.

Effects: Constructs an object of class strand<Executor>. Initializes inner_ex_ with inner_ex_(other.inner_ex_).

Postconditions: *this == other.

template<class OtherExecutor> strand(strand<OtherExecutor>&& other) noexcept;

Requires: OtherExecutor is convertible to Executor.

Effects: Constructs an object of class strand<Executor>. Initializes inner_ex_ with inner_ex_(std::move(other.inner_ex_)).

Postconditions: *this is equal to the prior value of other.

10.13.25.2. strand assignment

[async.strand.assign]

strand& operator=(const strand& other) noexcept;

Requires: Executor is Assignable (C++ Std [assignable]).

Postconditions:
*this == other
get_inner_executor() == other.get_inner_executor()

Returns: *this.

strand& operator=(strand&& other) noexcept;

Requires: Executor is Assignable (C++ Std [assignable]).

Postconditions:
*this is equal to the prior value of other
get_inner_executor() == other.get_inner_executor()

Returns: *this.

template<class OtherExecutor> strand& operator=(const strand<OtherExecutor>& other) noexcept;

Requires: OtherExecutor is convertible to Executor. Executor is Assignable (C++ Std [assignable]).

Effects: Assigns other.inner_ex_ to inner_ex_.

Postconditions: *this == other.

Returns: *this.

template<class OtherExecutor> strand& operator=(strand<OtherExecutor>&& other) noexcept;

Requires: OtherExecutor is convertible to Executor. Executor is Assignable (C++ Std [assignable]).

Effects: Assigns std::move(other.inner_ex_) to inner_ex_.

Postconditions: *this is equal to the prior value of other.

Returns: *this.

10.13.25.3. strand destructor

[async.strand.dtor]

~strand();

Effects: Destroys an object of class strand<Executor>. After this destructor completes, objects that were added to the strand but have not yet been executed will be executed in a way that meets the guarantees of ordering and non-concurrency.

10.13.25.4. strand operations

[async.strand.ops]

inner_executor_type get_inner_executor() const noexcept;

Returns: inner_ex_.

bool running_in_this_thread() const noexcept;

Returns: true if the current thread of execution is running a function that was submitted to the strand, or to any other strand object s such that s == *this, using dispatch, post or defer; otherwise false. [Note: That is, the current thread of execution's call chain includes a function that was submitted to the strand. —end note]

execution_context& context() noexcept;

Returns: inner_ex_.context().

void on_work_started() noexcept;

Effects: Calls inner_ex_.on_work_started().

void on_work_finished() noexcept;

Effects: Calls inner_ex_.on_work_finished().

template<class Func, class ProtoAllocator>
  void dispatch(Func&& f, const ProtoAllocator& a);

Effects: If running_in_this_thread() == true, calls DECAY_COPY(forward<Func>(f))(). [Note: If f exits via an exception, the exception propagates to the caller of dispatch(). —end note] Otherwise, requests invocation of f, as if by forwarding the function object f and allocator a to the executor inner_ex_, such that the guarantees of ordering and non-concurrency are met.

template<class Func, class ProtoAllocator>
  void post(Func&& f, const ProtoAllocator& a);

Effects: Requests invocation of f, as if by forwarding the function object f and allocator a to the executor inner_ex_, such that the guarantees of ordering and non-concurrency are met.

template<class Func, class ProtoAllocator>
  void defer(Func&& f, const ProtoAllocator& a);

Effects: Requests invocation of f, as if by forwarding the function object f and allocator a to the executor inner_ex_, such that the guarantees of ordering and non-concurrency are met.

10.13.25.5. strand comparisons

[async.strand.comparisons]

bool operator==(const strand<Executor>& a, const strand<Executor>& b);

Returns: true, if the strand objects share the same ordered, non-concurrent state; otherwise false.

bool operator!=(const strand<Executor>& a, const strand<Executor>& b);

Returns: !(a == b).

10.13.26. Class template use_future_t

[async.use.future]

The class template use_future_t defines a set of completion token types for use with asynchronous operations.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class ProtoAllocator = allocator<void>>
      class use_future_t
      {
      public:
        // use_future_t types:
        typedef ProtoAllocator allocator_type;

        // use_future_t members:
        constexpr use_future_t() noexcept;
        explicit use_future_t(const allocator_type& a) noexcept;
        template<class OtherProtoAllocator> use_future_t<OtherProtoAllocator>
          rebind(const OtherProtoAllocator& a) const noexcept;
        allocator_type get_allocator() const noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.13.26.1. use_future_t constructors

[async.use.future.cons]

constexpr use_future_t() noexcept;

Effects: Constructs a use_future_t with a default-constructed allocator.

explicit use_future_t(const allocator_type& a) noexcept;

Effects: Constructs an object of type use_future_t.

Postconditions: get_allocator() == a.

10.13.26.2. use_future_t members

[async.use.future.members]

template<class OtherProtoAllocator> use_future_t<OtherProtoAllocator>
  rebind(const OtherProtoAllocator& a) const noexcept;

Returns: A use_future_t object where get_allocator() == a.

allocator_type get_allocator() const noexcept;

Returns: The associated allocator object.

10.13.26.3. use_future_t traits

[async.use.future.traits]

template<class ProtoAllocator, class R, class... Args>
struct completion_handler_type<use_future_t<ProtoAllocator>, R(Args...)>
{
  typedef see below type;
};

Let F be the nested function object type type.

An object t1 of type F is an asynchronous provider with an associated shared state (C++Std, [futures.state]). The type F provides F::operator() such that the expression t1(declval<Args>()...) is well formed.

The implementation shall specialize associated_executor for F. For function objects executed using the associated executor's dispatch(), post() or defer() functions, any exception thrown is caught by the executor and stored in the associated shared state.

async_result<F> is valid and when an object r1 of type async_result<F> is constructed from t1, the expression r1.get() returns a future with the same shared state as t1.

The semantics of async_result::type and F::operator() are defined in the table below. In this table, N is the value of sizeof...(Args); let i be in the range [0..N) and let Ti be the ith type in Args; let Ui be decay_t<Ti> for each type Ti in Args; and let ai be the ith argument to F::operator().

Table 8. completion_handler_type<use_future_t<ProtoAllocator>, R(Args...)>::type semantics

N

U0

async_result<type>::type

F::operator() effects

0

future<void>

Makes the shared state ready.

1

error_code

future<void>

If a0 evaluates to true, atomically stores the exception pointer produced by make_exception_ptr(system_error(a0)) in the shared state. The shared state is made ready.

1

exception_ptr

future<void>

If a0 is non-null, atomically stores the exception pointer a0 in the shared state. The shared state is made ready.

1

all other types

future<U0>

Atomically stores a0 in the shared state and makes that state ready.

2

error_code

future<U1>

If a0 evaluates to true, atomically stores the exception pointer produced by make_exception_ptr(system_error(a0)) in the shared state; otherwise, atomically stores a1 in the shared state. The shared state is made ready.

2

exception_ptr

future<U1>

If a0 is non-null, atomically stores the exception pointer in the shared state; otherwise, atomically stores a1 in the shared state. The shared state is made ready.

2

all other types

future<tuple<U0,U1>>

Atomically stores the result of make_tuple(a0,a1) in the shared state and makes that state ready.

>2

error_code

future<tuple<U1,...,UN-1>>

If a0 evaluates to true, atomically stores the exception pointer produced by make_exception_ptr(system_error(a0)) in the shared state; otherwise, atomically stores the result of make_tuple(a1,...,aN-1) in the shared state. The shared state is made ready.

>2

exception_ptr

future<tuple<U1,...,UN-1>>

If a0 is non-null, atomically stores the exception pointer in the shared state; otherwise, atomically stores the result of make_tuple(a1,...,aN-1) in the shared state. The shared state is made ready.

>2

all other types

future<tuple<U0,...,UN-1>>

Atomically stores the result of make_tuple(a0,...,aN-1) in the shared state and makes that state ready.


10.13.27. Partial class template specialization async_result for packaged_task

[async.packaged.task.specializations]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class R, class... Args>
      class async_result<packaged_task<R(Args...)>>
      {
      public:
        typedef future<R> type;

        explicit async_result(packaged_task<R(Args...)>& t);
        async_result(const async_result&) = delete;
        async_result& operator=(const async_result&) = delete;

        type get();

      private:
        type future_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

explicit async_result(packaged_task<R(Args...)>& t);

Effects: Initializes future_ with t.get_future().

type get();

Returns: std::move(future_).

10.13.28. Class template packaged_handler

[async.package.handler]

Class template packaged_handler is an adapter to enable the use of packaged tasks with asynchronous operations as a completion handler with an associated allocator.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class, class> class packaged_handler; // undefined

      template<class R, class... Args, class ProtoAllocator>
      class packaged_handler<R(Args...), ProtoAllocator>
      {
      public:
        // packaged_handler types:

        typedef ProtoAllocator allocator_type;

        // packaged_handler construct / copy / assign:

        template<class Func>
          explicit packaged_handler(packaged_token<Func, ProtoAllocator>&& token);
        packaged_handler(const packaged_handler&) = delete;
        packaged_handler(packaged_handler&& rhs) noexcept;
        packaged_handler& operator=(const packaged_handler&) = delete;
        packaged_handler& operator=(packaged_handler&& rhs) noexcept;

        // packaged_handler operations:

        allocator_type get_allocator() const noexcept;
        future<R> get_future();
        void operator()(Args... args);

      private:
        packaged_task<R(Args...)> task_; // exposition only
        ProtoAllocator allocator_; // exposition only
      };

      template<class Signature, class ProtoAllocator>
        class async_result<packaged_handler<Signature, ProtoAllocator>>;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.13.28.1. packaged_handler members

[async.package.handler.members]

template<class Func>
  explicit packaged_handler(packaged_token<Func, ProtoAllocator>&& token);

Effects: Initializes task_ with std::move(token.f_) and initializes allocator_ with token.allocator_.

packaged_handler(packaged_handler&& rhs) noexcept;

Effects: Initializes task_ with std::move(rhs.task_) and initializes allocator_ with std::move(rhs.allocator_).

packaged_handler& operator=(packaged_handler&& rhs) noexcept;

Effects: Performs task_ = std::move(rhs.task_) and allocator_ = std::move(rhs.allocator_).

Returns: *this.

allocator_type get_allocator() const noexcept;

Returns: allocator_.

future<R> get_future();

Returns: task_.get_future().

void operator()(Args... args);

Effects: Calls task_(forward<Args>(args)...).

10.13.28.2. Partial class template specialization async_result

[async.package.handler.async.result]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class R, class... Args, class ProtoAllocator>
      class async_result<packaged_handler<R(Args...), ProtoAllocator>>
      {
      public:
        typedef future<R> type;

        explicit async_result(packaged_task<R(Args...)>& t);
        async_result(const async_result&) = delete;
        async_result& operator=(const async_result&) = delete;

        type get();

      private:
        type future_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The implementation provides a partial specialization of async_result that meets the async_result specialization requirements.

explicit async_result(packaged_handler<Signature, ProtoAllocator>& h);

Effects: Initializes future_ with t.get_future().

type get();

Returns: std::move(future_).

10.13.29. Class template packaged_token

[async.package.token]

Class template packaged_handler is an adapter to enable the use of packaged tasks with asynchronous operations as a completion token. The specification of the packaged task's Signature is deferred until the completion token is transformed into a completion handler.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Func, class ProtoAllocator = allocator<void>>
      class packaged_token
      {
      public:
        // packaged_token types:

        typedef ProtoAllocator allocator_type;

        // packaged_token constructors:

        explicit packaged_token(Func f);
        packaged_token(Func f, const allocator_type& a);

        // packaged_token operations:

        allocator_type get_allocator() const noexcept;

      private:
        Func f_; // exposition only
        ProtoAllocator allocator_; // exposition only
      };

      template<class Func, class ProtoAllocator, class R, class... Args>
      struct completion_handler_type<packaged_token<Func, ProtoAllocator>, R(Args...)>
      {
        typedef packaged_handler<result_of_t<Func(Args...)>(Args...), ProtoAllocator> type;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.13.29.1. packaged_token members

[async.package.token.members]

explicit packaged_token(Func f);

Effects: Initializes f_ with std::move(f) and default constructs allocator_.

packaged_token(Func f, const allocator_type& a);

Effects: Initializes f_ with std::move(f) and allocator_ with a.

allocator_type get_allocator() const noexcept;

Returns: allocator_.

10.13.30. Function package

[async.package]

template<class Func, class ProtoAllocator = allocator<void>>
  packaged_token<decay_t<Func>, ProtoAllocator> package(
    Func&& f, const ProtoAllocator& a = ProtoAllocator());

Returns: packaged_token<decay_t<Func>, ProtoAllocator>(forward<Func>(f), a).

10.14. Basic I/O services

[io_service]

10.14.1. Header <experimental/io_service> synopsis

[io_service.synop]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class io_service;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

10.14.2. Class io_service

[io_service.io_service]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class io_service : public execution_context
      {
      public:
        // types:

        class executor_type;

        // construct / copy / destroy:

        io_service();
        explicit io_service(int concurrency_hint);
        io_service(const io_service&) = delete;
        io_service& operator=(const io_service&) = delete;

        // io_service operations:

        executor_type get_executor() noexcept;

        size_t run();
        template<class Rep, class Period>
          size_t run_for(const chrono::duration<Rep, Period>& rel_time);
        template<class Clock, class Duration>
          size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);

        size_t run_one();
        template<class Rep, class Period>
          size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);
        template<class Clock, class Duration>
          size_t run_one_until(const chrono::time_point<Clock, Duration>& abs_time);

        size_t poll();

        size_t poll_one();

        void stop();

        bool stopped() const noexcept;

        void restart();
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class io_service satsifies the ExecutionContext type requirements.

The io_service functions run, run_for, run_until, run_one, run_one_for, run_one_until, poll, or poll_one must be called for the io_service to perform asynchronous operations on behalf of a C++ program. Notification that an asynchronous operation has completed is delivered by execution of the associated handler function object, as determined by the requirements for asynchronous operations.

For an object of type io_service, outstanding work is defined as the sum of:

— the total number of calls to the on_work_started function, less the total number of calls to the on_work_finished function, to any executor of the io_service.

— the number of function objects that have been added to the io_service via any executor of the io_service, but not yet executed; and

— the number of function objects that are currently being executed by the io_service.

If at any time the outstanding work falls to 0, the io_service is stopped as if by stop().

The io_service member functions get_executor, run, run_for, run_until, run_one, run_one_for, run_one_until, poll, poll_one, stop, and stopped, and the io_service::executor_type copy constructors, member functions and comparison operators, shall not introduce data races as a result of concurrent calls to those functions from different threads of execution. [Note: The restart member function is excluded from these thread safety requirements. —end note]

10.14.2.1. io_service members

[io_service.io_service.members]

io_service();
explicit io_service(int concurrency_hint);

Effects: Creates an object of class io_service.

Remarks: The concurrency_hint parameter is a suggestion to the implementation on the number of threads that should process asynchronous operations and execute function objects.

executor_type get_executor() noexcept;

Returns: An executor that may be used for submitting function objects to the io_service.

size_t run();

Requires: Must not be called from a thread that is currently calling one of run, run_for, run_until, run_one, run_one_for, run_one_until, poll, or poll_one.

Effects: Equivalent to:

size_t n = 0;
while (run_one())
  if (n != numeric_limits<size_t>::max())
    ++n;

Returns: n.

template<class Rep, class Period>
  size_t run_for(const chrono::duration<Rep, Period>& rel_time);

Effects: Equivalent to:

return run_until(chrono::steady_clock::now() + rel_time);

template<class Clock, class Duration>
  size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);

Effects: Equivalent to:

size_t n = 0;
while (run_one_until(abs_time))
  if (n != numeric_limits<size_t>::max())
    ++n;

Returns: n.

size_t run_one();

Requires: Must not be called from a thread that is currently calling one of run, run_for, run_until, run_one, run_one_for, run_one_until, poll, or poll_one.

Effects: If the io_service object has no outstanding work, performs stop(). Otherwise, blocks while the io_service has outstanding work, or until the io_service is stopped, or until one function object has been executed.

If an executed function object throws an exception, the exception propagates to the caller of run_one(). The io_service state is as if the function object had returned normally.

Returns: 1 if a function object was executed, otherwise 0.

Notes: This function may invoke additional function objects through nested calls to the io_service executor's dispatch member function. These do not count towards the return value.

template<class Rep, class Period>
  size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);

Effects: Equivalent to:

return run_one_until(chrono::steady_clock::now() + rel_time);

template<class Clock, class Duration>
  size_t run_one_until(const chrono::time_point<Clock, Duration>& abs_time);

Effects: If the io_service object has no outstanding work, performs stop(). Otherwise, blocks while the io_service has outstanding work, or until the expiration of the absolute timeout (C++ Std, [thread.req.timing]) specified by abs_time, or until the io_service is stopped, or until one function object has been executed.

If an executed function object throws an exception, the exception propagates to the caller of run_one(). The io_service state is as if the function object had returned normally.

Returns: 1 if a function object was executed, otherwise 0.

Notes: This function may invoke additional function objects through nested calls to the io_service executor's dispatch member function. These do not count towards the return value.

size_t poll();

Effects: Equivalent to:

size_t n = 0;
while (poll_one())
  if (n != numeric_limits<size_t>::max())
    ++n;

Returns: n.

size_t poll_one();

Effects: If the io_service object has no outstanding work, performs stop(). Otherwise, if there is a function object ready for immediate execution, executes it.

If an executed function object throws an exception, the exception propagates to the caller of poll_one(). The io_service state is as if the function object had returned normally.

Returns: 1 if a function object was invoked, otherwise 0.

Notes: This function may invoke additional function objects through nested calls to the io_service executor's dispatch member function. These do not count towards the return value.

void stop();

Effects: Stops the io_service. Concurrent calls to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one will end as soon as possible. If a call to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one is currently executing a function object, the call will end only after completion of that function object. The call to stop() returns without waiting for concurrent calls to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one to complete.

Postconditions: stopped() == true.

[Note: When stopped() == true, subsequent calls to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one will exit immediately with a return value of 0, without executing any function objects. An io_service remains in the stopped state until a call to restart(). —end note]

bool stopped() const noexcept;

Returns: true if the io_service is stopped.

void restart();

Postconditions: stopped() == false.

10.14.3. Class io_service::executor_type

[io_service.exec]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class io_service::executor_type
      {
      public:
        // construct / copy / destroy:

        executor_type(const executor_type& other) noexcept;
        executor_type(executor_type&& other) noexcept;

        executor_type& operator=(const executor_type& other) noexcept;
        executor_type& operator=(executor_type&& other) noexcept;

        // executor operations:

        bool running_in_this_thread() const noexcept;

        io_service& context() noexcept;

        void on_work_started() noexcept;
        void on_work_finished() noexcept;

        template<class Func, class ProtoAllocator>
          void dispatch(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void post(Func&& f, const ProtoAllocator& a);
        template<class Func, class ProtoAllocator>
          void defer(Func&& f, const ProtoAllocator& a);
      };

      bool operator==(const io_service::executor_type& a,
                      const io_service::executor_type& b) noexcept;
      bool operator!=(const io_service::executor_type& a,
                      const io_service::executor_type& b) noexcept;

      template<> struct is_executor<io_service::executor_type> : true_type {};

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

io_service::executor_type is a type satisfying Executor requirements. Objects of type io_service::executor_type are associated with an io_service, and function objects submitted using the dispatch, post, or defer member functions will be executed by the io_service from within the run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one functions.

10.14.3.1. io_service::executor_type constructors

[io_service.exec.cons]

executor_type(const executor_type& other) noexcept;

Postconditions: *this == other.

executor_type(executor_type&& other) noexcept;

Postconditions: *this is equal to the prior value of other.

10.14.3.2. io_service::executor_type assignment

[io_service.exec.assign]

executor_type& operator=(const executor_type& other) noexcept;

Postconditions: *this == other.

Returns: *this.

executor_type& operator=(executor_type&& other) noexcept;

Postconditions: *this is equal to the prior value of other.

Returns: *this.

10.14.3.3. io_service::executor_type operations

[io_service.exec.ops]

bool running_in_this_thread() const noexcept;

Returns: true if the current thread of execution is running the run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one function of the associated io_service object. [Note: That is, the current thread of execution's call chain includes a run function. —end note]

io_service& context() noexcept;

Returns: A reference to the associated io_service object.

void on_work_started() noexcept;

Effects: Increment the count of outstanding work associated with the io_service.

void on_work_finished() noexcept;

Effects: Decrement the count of outstanding work associated with the io_service.

template<class Func, class ProtoAllocator>
  void dispatch(Func&& f, const ProtoAllocator& a);

Effects: If running_in_this_thread() is true, calls DECAY_COPY(forward<Func>(f))(). [Note: If f exits via an exception, the exception propagates to the caller of dispatch(). —end note] Otherwise, calls post(forward<Func>(f), a).

template<class Func, class ProtoAllocator>
  void post(Func&& f, const ProtoAllocator& a);

Effects: Adds f to the io_service.

template<class Func, class ProtoAllocator>
  void defer(Func&& f, const ProtoAllocator& a);

Effects: Adds f to the io_service.

10.14.3.4. io_service::executor_type comparisons

[io_service.exec.comparisons]

bool operator==(const io_service::executor_type& a,
                const io_service::executor_type& b) noexcept;

Returns: addressof(a.context()) == addressof(b.context()).

bool operator!=(const io_service::executor_type& a,
                const io_service::executor_type& b) noexcept;

Returns: !(a == b).

10.15. Timers

[timer] This clause defines components for performing timer operations.

[Example: Performing a synchronous wait operation on a timer:

io_service i;
steady_timer t(i);
t.expires_after(seconds(5));
t.wait();

end example]

[Example: Performing an asynchronous wait operation on a timer:

void handler(error_code ec) { ... }
...
io_service i;
steady_timer t(i);
t.expires_after(seconds(5));
t.async_wait(handler);
i.run();

end example]

10.15.1. Header <experimental/timer> synopsis

[timer.synop]

#include <chrono>

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Clock> struct wait_traits;

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

      typedef basic_waitable_timer<chrono::system_clock> system_timer;
      typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
      typedef basic_waitable_timer<chrono::high_resolution_clock> high_resolution_timer;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

10.15.2. Requirements

[timer.reqmts]

10.15.2.1. Wait traits requirements

[timer.reqmts.waittraits]

In the table below, X denotes a wait traits class for a type Clock meeting the Clock requirements (C++ Std [time.clock.req]); t denotes a (possibly const) value of type Clock::time_point; and d denotes a (possibly const) value of type Clock::duration.

Table 9. WaitTraits requirements

expression

return type

assertion/note
pre/post-condition

X::to_wait_duration(d)

Clock::duration

Returns a Clock::duration value that represents the duration d.

X::to_wait_duration(t)

Clock::duration

Returns a Clock::duration value that represents the duration until the time point t.


10.15.3. Class template wait_traits

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Clock>
      struct wait_traits
      {
        static typename Clock::duration to_wait_duration(
          const typename Clock::duration& d);

        static typename Clock::duration to_wait_duration(
          const typename Clock::time_point& t);
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Class template wait_traits satisfies the WaitTraits type requirements. Template argument Clock is a type meeting the Clock requirements (C++ Std [time.clock.req]).

10.15.3.1. Class template wait_traits members
static typename Clock::duration to_wait_duration(
  const typename Clock::duration& d);

Returns: d.

static typename Clock::duration to_wait_duration(
  const typename Clock::time_point& t);

Returns: Let now be Clock::now(). If now + Clock::duration::max() is before t, Clock::duration::max(); if now + Clock::duration::min() is after t, Clock::duration::min(); otherwise, t - now.

10.15.4. Class template basic_waitable_timer

[timer.waitable]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Clock, class WaitTraits = wait_traits<Clock>>
      class basic_waitable_timer
      {
      public:
        // types:

        typedef io_service::executor_type executor_type;
        typedef Clock clock_type;
        typedef typename clock_type::duration duration;
        typedef typename clock_type::time_point time_point;
        typedef WaitTraits traits_type;

        // construct / copy / destroy:

        explicit basic_waitable_timer(io_service& ios);
        basic_waitable_timer(io_service& ios, const time_point& t);
        basic_waitable_timer(io_service& ios, const duration& d);
        basic_waitable_timer(const basic_waitable_timer&) = delete;
        basic_waitable_timer(basic_waitable_timer&& rhs) noexcept;

        ~basic_waitable_timer();

        basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
        basic_waitable_timer& operator=(basic_waitable_timer&& rhs);

        // basic_waitable_timer operations:

        executor_type get_executor() noexcept;

        size_t cancel();
        size_t cancel_one();

        time_point expiry() const;
        size_t expires_at(const time_point& t);
        size_t expires_after(const duration& d);

        void wait();
        void wait(error_code& ec);

        template<class CompletionToken>
          DEDUCED async_wait(CompletionToken&& token);
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.15.4.1. basic_waitable_timer constructors

[timer.waitable.cons]

explicit basic_waitable_timer(io_service& ios);

Effects: Equivalent to basic_waitable_timer(ios, time_point()).

basic_waitable_timer(io_service& ios, const time_point& t);

Postconditions:
get_executor() == ios.get_executor().
expiry() == t.

basic_waitable_timer(io_service& ios, const duration& d);

Effects: Sets the expiry time as if by calling expires_after(d).

Postconditions: get_executor() == ios.get_executor().

basic_waitable_timer(basic_waitable_timer&& rhs) noexcept;

Effects: Move constructs an object of class basic_waitable_timer<Clock, WaitTraits> that refers to the state originally represented by rhs.

Postconditions:
get_executor() is equal to the prior value of rhs.get_executor().
expiry() returns the same value as rhs.expiry() prior to the constructor invocation.
rhs.expiry() == time_point().

10.15.4.2. basic_waitable_timer destructor

[timer.waitable.dtor]

~basic_waitable_timer();

Effects: Destroys the timer, cancelling any asynchronous wait operations associated with the timer as if by calling cancel().

10.15.4.3. basic_waitable_timer assignment

[timer.waitable.assign]

basic_waitable_timer& operator=(basic_waitable_timer&& rhs);

Effects: Cancels any outstanding asynchronous operations associated with *this as if by calling cancel(), then moves into *this the state originally represented by rhs.

Postconditions:
get_executor() is equal to the prior value of rhs.get_executor().
expiry() returns the same value as rhs.expiry() prior to the assignment.
rhs.expiry() == time_point().

Returns: *this.

10.15.4.4. basic_waitable_timer operations

[timer.waitable.ops]

executor_type get_executor() noexcept;

Returns: The associated executor.

size_t cancel();

Effects: Causes any outstanding asynchronous wait operations to complete. Completion handlers for canceled operations are passed an error code ec such that ec == errc::operation_canceled yields true.

Returns: The number of operations that were canceled.

size_t cancel_one();

Effects: Causes the outstanding asynchronous wait operation that was initiated first, if any, to complete as soon as possible. The completion handler for the canceled operation is passed an error code ec such that ec == errc::operation_canceled yields true.

Returns: 1 if an operation was cancelled, otherwise 0.

time_point expiry() const;

Returns: The expiry time associated with the timer, as previously set using expires_at() or expires_after().

size_t expires_at(const time_point& t);

Effects: Cancels outstanding asynchronous wait operations, as if by calling cancel(). Sets the expiry time associated with the timer.

Returns: The number of operations that were canceled.

Postconditions: expiry() == t.

size_t expires_after(const duration& d);

Returns: expires_at(clock_type::now() + d).

void wait();
void wait(error_code& ec);

Effects: Establishes the postcondition as if by repeatedly blocking the calling thread for the relative time produced by WaitTraits::to_wait_duration(expiry()).

Postconditions: ec || !(clock_type::now() < expiry()).

template<class CompletionToken>
  DEDUCED async_wait(CompletionToken&& token);

Completion signature: void(error_code ec).

Effects: Initiates an asynchronous wait operation such that the completion handler is submitted for execution only when the condition ec || !(clock_type::now() < expiry()) yields true.

10.16. Buffers

[buffer]

10.16.1. Header <experimental/buffer> synopsis

[buffer.synop]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      enum class stream_errc {
        eof = implementation defined,
        not_found = implementation defined
      };

      const error_category& stream_category() noexcept;

      error_code make_error_code(stream_errc e) noexcept;
      error_condition make_error_condition(stream_errc e) noexcept;

      class mutable_buffer;

      class const_buffer;

      class mutable_buffers_1;

      class const_buffers_1;

      // buffer type traits:

      template<class T> is_mutable_buffer_sequence;
      template<class T> is_const_buffer_sequence;
      template<class T> is_dynamic_buffer;

      // buffer conversions:

      template<class T> T buffer_cast(const mutable_buffer& b) noexcept;
      template<class T> T buffer_cast(const const_buffer& b) noexcept;

      // buffer size:

      size_t buffer_size(const mutable_buffer& b) noexcept;
      size_t buffer_size(const const_buffer& b) noexcept;
      template<class ConstBufferSequence>
        size_t buffer_size(const ConstBufferSequence& buffers) noexcept;

      // buffer copy:

      size_t buffer_copy(const mutable_buffer& dest,
                         const const_buffer& source) noexcept;
      size_t buffer_copy(const mutable_buffer& dest,
                         const const_buffer& source,
                         size_t max_size) noexcept;
      template<class ConstBufferSequence>
        size_t buffer_copy(const mutable_buffer& dest,
                           const ConstBufferSequence& source) noexcept;
      template<class ConstBufferSequence>
        size_t buffer_copy(const mutable_buffer& dest,
                           const ConstBufferSequence& source,
                           size_t max_size) noexcept;
      template<class MutableBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const const_buffer& source) noexcept;
      template<class MutableBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const const_buffer& source,
                           size_t max_size) noexcept;
      template<class MutableBufferSequence, class ConstBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const ConstBufferSequence& source) noexcept;
      template<class MutableBufferSequence, class ConstBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const ConstBufferSequence& source,
                           max_size) noexcept;

      // buffer arithmetic:

      mutable_buffer operator+(const mutable_buffer& b, size_t n) noexcept;
      mutable_buffer operator+(size_t n, const mutable_buffer& b) noexcept;
      const_buffer operator+(const const_buffer&, size_t n) noexcept;
      const_buffer operator+(size_t, const const_buffer&) noexcept;
      mutable_buffers_1 operator+(const mutable_buffers_1& b, size_t n) noexcept;
      mutable_buffers_1 operator+(size_t n, const mutable_buffers_1& b) noexcept;
      const_buffers_1 operator+(const const_buffers_1&, size_t n) noexcept;
      const_buffers_1 operator+(size_t, const const_buffers_1&) noexcept;

      // buffer creation:

      mutable_buffers_1 buffer(void* p, size_t n) noexcept;
      const_buffers_1 buffer(const void* p, size_t n) noexcept;

      mutable_buffers_1 buffer(const mutable_buffer& b) noexcept;
      mutable_buffers_1 buffer(const mutable_buffer& b, size_t n) noexcept;
      const_buffers_1 buffer(const const_buffer& b) noexcept;
      const_buffers_1 buffer(const const_buffer& b, size_t n) noexcept;

      template<class T, size_t N>
        mutable_buffers_1 buffer(T (&arr)[N]) noexcept;
      template<class T, size_t N>
        mutable_buffers_1 buffer(T (&arr)[N], size_t n) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const T (&arr)[N]) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const T (&arr)[N], size_t n) noexcept;

      template<class T, size_t N>
        mutable_buffers_1 buffer(array<T, N>& arr) noexcept;
      template<class T, size_t N>
        mutable_buffers_1 buffer(array<T, N>& arr, size_t n) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(array<const T, N>& arr) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(array<const T, N>& arr, size_t n) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const array<T, N>& arr) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const array<T, N>& arr, size_t n) noexcept;

      template<class T, class Allocator>
        mutable_buffers_1 buffer(vector<T, Allocator>& vec) noexcept;
      template<class T, class Allocator>
        mutable_buffers_1 buffer(vector<T, Allocator>& vec, size_t n) noexcept;
      template<class T, class Allocator>
        const_buffers_1 buffer(const vector<T, Allocator>& vec) noexcept;
      template<class T, class Allocator>
        const_buffers_1 buffer(const vector<T, Allocator>& vec, size_t n) noexcept;

      template<class CharT, class Traits, class Allocator>
        mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
      template<class CharT, class Traits, class Allocator>
        mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str,
                                 size_t n) noexcept;

      template<class CharT, class Traits>
        const_buffers_1 buffer(basic_string_view<CharT, Traits> str) noexcept;
      template<class CharT, class Traits>
        const_buffers_1 buffer(basic_string_view<CharT, Traits> str,
                               size_t n) noexcept;

      template<class T, Allocator>
        class dynamic_vector_buffer;

      template<class CharT, class Traits, Allocator>
        class dynamic_string_buffer;

      // dynamic buffer creation:

      template<class T, class Allocator>
        dynamic_vector_buffer<T, Allocator>
          dynamic_buffer(vector<T, Allocator>& vec) noexcept;
      template<class T, class Allocator>
        dynamic_vector_buffer<T, Allocator>
          dynamic_buffer(vector<T, Allocator>& vec, size_t n) noexcept;

      template<class CharT, class Traits, class Allocator>
        dynamic_string_buffer<CharT, Traits, Allocator>
          dynamic_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
      template<class CharT, class Traits, class Allocator>
        dynamic_string_buffer<CharT, Traits, Allocator>
          dynamic_buffer(basic_string<CharT, Traits, Allocator>& str, size_t n) noexcept;

      class transfer_all;
      class transfer_at_least;
      class transfer_exactly;

      // synchronous read operations:

      template<class SyncReadStream, class MutableBufferSequence>
        size_t read(SyncReadStream& stream,
                    const MutableBufferSequence& buffers);
      template<class SyncReadStream, class MutableBufferSequence>
        size_t read(SyncReadStream& stream,
                    const MutableBufferSequence& buffers, error_code& ec);
      template<class SyncReadStream, class MutableBufferSequence,
        class CompletionCondition>
          size_t read(SyncReadStream& stream,
                      const MutableBufferSequence& buffers,
                      CompletionCondition completion_condition);
      template<class SyncReadStream, class MutableBufferSequence,
        class CompletionCondition>
          size_t read(SyncReadStream& stream,
                      const MutableBufferSequence& buffers,
                      CompletionCondition completion_condition,
                      error_code& ec);

      template<class SyncReadStream, class DynamicBuffer>
        size_t read(SyncReadStream& stream, DynamicBuffer&& b);
      template<class SyncReadStream, class DynamicBuffer>
        size_t read(SyncReadStream& stream, DynamicBuffer&& b, error_code& ec);
      template<class SyncReadStream, class DynamicBuffer, class CompletionCondition>
        size_t read(SyncReadStream& stream, DynamicBuffer&& b,
                    CompletionCondition completion_condition);
      template<class SyncReadStream, class DynamicBuffer, class CompletionCondition>
        size_t read(SyncReadStream& stream, DynamicBuffer&& b,
                    CompletionCondition completion_condition, error_code& ec);

      // asynchronous read operations:

      template<class AsyncReadStream, class MutableBufferSequence,
        class CompletionToken>
          DEDUCED async_read(AsyncReadStream& stream,
                          const MutableBufferSequence& buffers,
                          CompletionToken&& token);
      template<class AsyncReadStream, class MutableBufferSequence,
        class CompletionCondition, class CompletionToken>
          DEDUCED async_read(AsyncReadStream& stream,
                          const MutableBufferSequence& buffers,
                          CompletionCondition completion_condition,
                          CompletionToken&& token);

      template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
        DEDUCED async_read(AsyncReadStream& stream,
                        DynamicBuffer&& b, CompletionToken&& token);
      template<class AsyncReadStream, class DynamicBuffer,
        class CompletionCondition, class CompletionToken>
          DEDUCED async_read(AsyncReadStream& stream,
                          DynamicBuffer&& b,
                          CompletionCondition completion_condition,
                          CompletionToken&& token);

      // synchronous write operations:

      template<class SyncWriteStream, class ConstBufferSequence>
        size_t write(SyncWriteStream& stream,
                     const ConstBufferSequence& buffers);
      template<class SyncWriteStream, class ConstBufferSequence>
        size_t write(SyncWriteStream& stream,
                     const ConstBufferSequence& buffers, error_code& ec);
      template<class SyncWriteStream, class ConstBufferSequence,
        class CompletionCondition>
          size_t write(SyncWriteStream& stream,
                       const ConstBufferSequence& buffers,
                       CompletionCondition completion_condition);
      template<class SyncWriteStream, class ConstBufferSequence,
        class CompletionCondition>
          size_t write(SyncWriteStream& stream,
                       const ConstBufferSequence& buffers,
                       CompletionCondition completion_condition,
                       error_code& ec);

      template<class SyncWriteStream, class DynamicBuffer>
        size_t write(SyncWriteStream& stream, DynamicBuffer&& b);
      template<class SyncWriteStream, class DynamicBuffer>
        size_t write(SyncWriteStream& stream, DynamicBuffer&& b, error_code& ec);
      template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
        size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
                     CompletionCondition completion_condition);
      template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
        size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
                     CompletionCondition completion_condition, error_code& ec);

      // asynchronous write operations:

      template<class AsyncWriteStream, class ConstBufferSequence,
        class CompletionToken>
          DEDUCED async_write(AsyncWriteStream& stream,
                           const ConstBufferSequence& buffers,
                           CompletionToken&& token);
      template<class AsyncWriteStream, class ConstBufferSequence,
        class CompletionCondition, class CompletionToken>
          DEDUCED async_write(AsyncWriteStream& stream,
                           const ConstBufferSequence& buffers,
                           CompletionCondition completion_condition,
                           CompletionToken&& token);

      template<class AsyncWriteStream, class DynamicBuffer, class CompletionToken>
        DEDUCED async_write(AsyncWriteStream& stream,
                         DynamicBuffer&& b, CompletionToken&& token);
      template<class AsyncWriteStream, class DynamicBuffer,
        class CompletionCondition, class CompletionToken>
          DEDUCED async_write(AsyncWriteStream& stream,
                           DynamicBuffer&& b,
                           CompletionCondition completion_condition,
                           CompletionToken&& token);

      // synchronous delimited read operations:

      template<class SyncReadStream, class DynamicBuffer>
        size_t read_until(SyncReadStream& s, DynamicBuffer&& b, char delim);
      template<class SyncReadStream, class DynamicBuffer>
        size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
                          char delim, error_code& ec);
      template<class SyncReadStream, class DynamicBuffer>
        size_t read_until(SyncReadStream& s, DynamicBuffer&& b, string_view delim);
      template<class SyncReadStream, class DynamicBuffer>
        size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
                          string_view delim, error_code& ec);

      // asynchronous delimited read operations:

      template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
        DEDUCED async_read_until(AsyncReadStream& s,
                              DynamicBuffer&& b, char delim,
                              CompletionToken&& token);
      template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
        DEDUCED async_read_until(AsyncReadStream& s,
                              DynamicBuffer&& b, string_view delim,
                              CompletionToken&& token);

    } // inline namespace network_v1
  } // namespace experimental

  template<> struct is_error_code_enum<
    experimental::network_v1::stream_errc>
      : public true_type {};

} // namespace std

10.16.2. Requirements

[buffer.reqmts]

10.16.2.1. Mutable buffer sequence requirements

[buffer.reqmts.mutablebuffersequence]

A mutable buffer sequence satisfies the requirements for a constant buffer sequence as well as the requirements in the table below.

In the table below, X denotes a constant buffer sequence class, x denotes a (possibly const) value of type X, and u denotes an identifier.

Table 10. ConstBufferSequence requirements

expression

return type

assertion/note
pre/post-condition

X::value_type

convertible to mutable_buffer

X u(x);

post:

equal(u.begin(), u.end(), x.begin(), x.end(),
  [](const typename X::value_type& v1,
     const typename X::value_type& v2)
   {
     mutable_buffer b1(v1);
     mutable_buffer b2(v2);
     return buffer_cast<void*>(b1)
       == buffer_cast<void*>(b2)
         && buffer_size(b1) == buffer_size(b2);
   })


10.16.2.2. Constant buffer sequence requirements

[buffer.reqmts.constbuffersequence]

A constant buffer sequence satisfies the requirements for Destructible (C++ Std, [destructible]) and CopyConstructible (C++ Std, [copyconstructible]), as well as the requirements in the table below.

In the table below, X denotes a constant buffer sequence class, x denotes a (possibly const) value of type X, and u denotes an identifier.

Table 11. ConstBufferSequence requirements

expression

return type

assertion/note
pre/post-condition

X::value_type

convertible to const_buffer

X::const_iterator

iterator type pointing to X::value_type

X::const_iterator meets the requirements for bidirectional iterators (C++ Std, [bidirection.iterators]).

X u(x);

post:

equal(u.begin(), u.end(), x.begin(), x.end(),
  [](const typename X::value_type& v1,
     const typename X::value_type& v2)
   {
     const_buffer b1(v1);
     const_buffer b2(v2);
     return buffer_cast<const void*>(b1)
       == buffer_cast<const void*>(b2)
         && buffer_size(b1) == buffer_size(b2);
   })

x.begin()

convertible to X::const_iterator

x.end()

convertible to X::const_iterator


10.16.2.3. Dynamic buffer requirements

[buffer.reqmts.dynamicbuffer]

A dynamic buffer encapsulates memory storage that may be automatically resized as required, where the memory is divided into an input sequence followed by an output sequence. These memory regions are internal to the dynamic buffer, but direct access to the elements is provided to permit them to be efficiently used with I/O operations, such as the send or receive operations of a socket. Data written to the output sequence of a dynamic buffer object is appended to the input sequence of the same object.

A dynamic buffer type X shall satisfy the requirements of MoveConstructible (C++ Std, [moveconstructible]) types in addition to those listed below.

In the table below, X denotes a dynamic buffer class, x denotes a value of type X, x1 denotes a (possibly const) value of type X, and n denotes a value of type size_t.

Table 12. DynamicBuffer requirements

expression

type

assertion/note
pre/post-conditions

X::const_buffers_type

type meeting ConstBufferSequence requirements.

This type represents the memory associated with the input sequence.

X::mutable_buffers_type

type meeting MutableBufferSequence requirements.

This type represents the memory associated with the output sequence.

x1.size()

size_t

Returns the size, in bytes, of the input sequence.

x1.max_size()

size_t

Returns the permitted maximum of the sum of the sizes of the input sequence and output sequence.

x1.capacity()

size_t

Returns the maximum sum of the sizes of the input sequence and output sequence that the dynamic buffer can hold without requiring reallocation.

x1.data()

X::const_buffers_type

Returns a constant buffer sequence u that represents the memory associated with the input sequence, and where buffer_size(u) == size().

x.prepare(n)

X::mutable_buffers_type

Returns a mutable buffer sequence u representing the output sequence, and where buffer_size(u) == n. The dynamic buffer reallocates memory as required. All constant or mutable buffer sequences previously obtained using data() or prepare() are invalidated.

Throws: length_error if size() + n exceeds max_size().

x.commit(n)

Appends n bytes from the start of the output sequence to the end of the input sequence. The remainder of the output sequence is discarded. If n is greater than the size of the output sequence, the entire output sequence is appended to the input sequence. All constant or mutable buffer sequences previously obtained using data() or prepare() are invalidated.

x.consume(n)

Removes n bytes from beginning of the input sequence. If n is greater than the size of the input sequence, the entire input sequence is removed. All constant or mutable buffer sequences previously obtained using data() or prepare() are invalidated.


10.16.2.4. Requirements on synchronous read operations

[buffer.reqmts.sync.read]

In this Technical Specification, a synchronous read operation is a function that reads data into a mutable buffer sequence argument of a type meeting MutableBufferSequence requirements.

The mutable buffer sequence specifies memory where the data should be placed. A synchronous read operation shall always fill a buffer in the sequence completely before proceeding to the next.

10.16.2.5. Requirements on asynchronous read operations

[buffer.reqmts.async.read]

In this Technical Specification, an asynchronous read operation is an asynchronous operation that reads data into a mutable buffer sequence argument of a type meeting MutableBufferSequence requirements.

The mutable buffer sequence specifies memory where the data should be placed. An asynchronous read operation shall always fill a buffer in the sequence completely before proceeding to the next.

The read operation's implementation shall maintain one or more copies of the buffer sequence until such time as the read operation no longer requires access to the memory specified by the buffers in the sequence. The program shall ensure the memory remains valid until:

— the last copy of the buffer sequence is destroyed, or

— the completion handler for the asynchronous operation is invoked,

whichever comes first.

10.16.2.6. Requirements on synchronous write operations

[buffer.reqmts.sync.write]

In this Technical Specification, a synchronous write operation is a function that writes data from a constant buffer sequence argument of a type meeting ConstBufferSequence requirements.

The constant buffer sequence specifies memory where the data to be written is located. A synchronous write operation shall always write a buffer in the sequence completely before proceeding to the next.

10.16.2.7. Requirements on asynchronous write operations

[buffer.reqmts.async.write]

In this Technical Specification, an asynchronous write operation is an asynchronous operation that writes data from a constant buffer sequence argument of a type meeting ConstBufferSequence requirements.

The constant buffer sequence specifies memory where the data to be written is located. An asynchronous write operation shall always write a buffer in the sequence completely before proceeding to the next.

The write operation's implementation shall maintain one or more copies of the buffer sequence until such time as the write operation no longer requires access to the memory specified by the buffers in the sequence. The program shall ensure the memory remains valid until:

— the last copy of the buffer sequence is destroyed, or

— the completion handler for the asynchronous operation is invoked,

whichever comes first.

10.16.2.8. Buffer-oriented synchronous read stream requirements

[buffer.reqmts.syncreadstream]

In the table below, a denotes a synchronous read stream object, mb denotes an object satisfying mutable buffer sequence requirements, and ec denotes an object of type error_code.

Table 13. Buffer-oriented synchronous read stream requirements

operation

type

semantics, pre/post-conditions

a.read_some(mb)
a.read_some(mb,ec)

size_t

Meets the requirements for a synchronous read operation.

Reads one or more bytes of data from the stream a.

If successful, returns the number of bytes read and sets ec such that !ec is true. If an error occurred, returns 0 and sets ec such that !!ec is true. If all data has been read from the stream and the stream has been shut down in an orderly manner, sets ec such that ec == stream_errc::eof.

The operation shall not block if buffer_size(mb) == 0.


10.16.2.9. Buffer-oriented asynchronous read stream requirements

[buffer.reqmts.asyncreadstream]

In the table below, a denotes an asynchronous read stream object, mb denotes an object satisfying mutable buffer sequence requirements, and t is a completion token.

Table 14. Buffer-oriented asynchronous read stream requirements

operation

type

semantics, pre/post-conditions

a.get_executor()

A type satisfying the Executor requirements.

Returns the associated I/O executor.

a.async_read_some(mb,t)

The return type is determined according to the requirements for an asynchronous operation.

Meets the requirements for an asynchronous read operation with completion signature void(error_code ec, size_t n).

Initiates an asynchronous operation to read one or more bytes of data from the stream a.

If successful, n is the number of bytes read and ec is set such that !ec is true. If an error occurred, n is 0 and ec is set such that !!ec is true. If all data has been read from the stream and the stream has been shut down in an orderly manner, n is 0 and ec is set such that ec == stream_errc::eof.

The operation shall complete immediately if buffer_size(mb) == 0.


10.16.2.10. Buffer-oriented synchronous write stream requirements

[buffer.reqmts.syncwritestream]

In the table below, a denotes a synchronous write stream object, cb denotes an object satisfying constant buffer sequence requirements, and ec denotes an object of type error_code.

Table 15. Buffer-oriented synchronous write stream requirements

operation

type

semantics, pre/post-conditions

a.write_some(cb)
a.write_some(cb,ec)

size_t

Meets the requirements for a synchronous write operation.

Writes one or more bytes of data to the stream a.

If successful, returns the number of bytes written and sets ec such that !ec is true. If an error occurred, returns 0 and sets ec such that !!ec is true.

The operation shall not block if buffer_size(cb) == 0.


10.16.2.11. Buffer-oriented asynchronous write stream requirements

[buffer.reqmts.asyncwritestream]

In the table below, a denotes an asynchronous write stream object, cb denotes an object satisfying constant buffer sequence requirements, and t is a completion token.

Table 16. Buffer-oriented asynchronous write stream requirements

operation

type

semantics, pre/post-conditions

a.get_executor()

A type satisfying the Executor requirements.

Returns the associated I/O executor.

a.async_write_some(cb,t)

The return type is determined according to the requirements for an asynchronous operation.

Meets the requirements for an asynchronous write operation with completion signature void(error_code ec, size_t n).

Initiates an asynchronous operation to write one or more bytes of data to the stream a.

If successful, n is the number of bytes written and ec is set such that !ec is true. If an error occurred, n is 0 and ec is set such that !!ec is true.

The operation shall complete immediately if buffer_size(cb) == 0.


10.16.3. Class mutable_buffer

[buffer.mutable]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class mutable_buffer
      {
      public:
        // constructors:
        mutable_buffer() noexcept;
        mutable_buffer(void* p, size_t n) noexcept;

      private:
        void* data_; // exposition only
        size_t size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.16.3.1. mutable_buffer constructors

[buffer.mutable.cons]

mutable_buffer() noexcept;

Postconditions: data_ == nullptr and size_ == 0.

mutable_buffer(void* p, size_t n) noexcept;

Postconditions: data_ == p and size_ == n.

10.16.4. Class const_buffer

[buffer.const]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class const_buffer
      {
      public:
        // constructors:
        const_buffer() noexcept;
        const_buffer(const void* p, size_t n) noexcept;
        const_buffer(const mutable_buffer& b) noexcept;

      private:
        const void* data_; // exposition only
        size_t size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.16.4.1. const_buffer constructors

[buffer.const.cons]

const_buffer() noexcept;

Postconditions: data_ == nullptr and size_t == 0.

const_buffer(const void* p, size_t n) noexcept;

Postconditions: data_ == p and size_ == n.

const_buffer(const mutable_buffer& b);

Postconditions: data_ == b.data_ and size_ == b.size_.

10.16.5. Class mutable_buffers_1

[buffer.mutable.1]

An object of class mutable_buffers_1 represents a sequence of exactly one mutable_buffer object.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class mutable_buffers_1 : public mutable_buffer
      {
      public:
        // types:
        typedef mutable_buffer value_type;
        typedef unspecified const_iterator;

        // constructors:
        mutable_buffers_1(void* p, size_t n) noexcept;
        explicit mutable_buffers_1(const mutable_buffer& b) noexcept;

        // members:
        const_iterator begin() const noexcept;
        const_iterator end() const noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The mutable_buffers_1 class meets the requirements for MutableBufferSequence.

10.16.5.1. mutable_buffers_1 constructors

[buffer.mutable.1.cons]

mutable_buffers_1(const void* p, size_t n) noexcept;

Effects: Constructs an object of class mutable_buffers_1, initializing the base class with mutable_buffer(p, n).

explicit mutable_buffers_1(const mutable_buffer& b) noexcept;

Effects: Constructs an object of class mutable_buffers_1, initializing the base class with mutable_buffer(b).

10.16.5.2. mutable_buffers_1 members

[buffer.mutable.1.members]

const_iterator begin() const noexcept;

Returns: An iterator referring to the first (and only) mutable_buffer object in the sequence.

const_iterator end() const noexcept;

Returns: An iterator which is the past-the-end value.

10.16.6. Class const_buffers_1

[buffer.const.1]

An object of class const_buffers_1 represents a sequence of exactly one const_buffer object.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class const_buffers_1 :
        public const_buffer
      {
      public:
        // types:
        typedef const_buffer value_type;
        typedef unspecified const_iterator;

        // constructors:
        const_buffers_1(const void* p, size_t n) noexcept;
        explicit const_buffers_1(const const_buffer& b) noexcept;

        // members:
        const_iterator begin() const noexcept;
        const_iterator end() const noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The const_buffers_1 class meets the requirements for ConstBufferSequence.

10.16.6.1. const_buffers_1 constructors

[buffer.const.1.cons]

const_buffers_1(const void* p, size_t n) noexcept;

Effects: Constructs an object of class const_buffers_1, initializing the base class with const_buffer(p, n).

explicit const_buffers_1(const const_buffer& b) noexcept;

Effects: Constructs an object of class const_buffers_1, initializing the base class with const_buffer(b).

10.16.6.2. const_buffers_1 members

[buffer.const.1.members]

const_iterator begin() const noexcept;

Returns: An iterator referring to the first (and only) const_buffer object in the sequence.

const_iterator end() const noexcept;

Returns: An iterator which is the past-the-end value.

10.16.7. Buffer type traits

[buffer.traits]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T> is_mutable_buffer_sequence;
      template<class T> is_const_buffer_sequence;
      template<class T> is_dynamic_buffer;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

This sub-clause contains templates that may be used to query the properties of a type at compile time. Each of these templates shall be a UnaryTypeTrait (C++ Std, [meta.rqmts]) with a BaseCharacteristic of true_type if the corresponding condition is true, otherwise false_type.

Table 17. Buffer type traits

Template

Condition

Preconditions

template<class T> is_mutable_buffer_sequence

T meets the syntactic requirements for mutable buffer sequence.

T is a complete type.

template<class T> is_const_buffer_sequence

T meets the syntactic requirements for constant buffer sequence.

T is a complete type.

template<class T> is_dynamic_buffer

T meets the syntactic requirements for dynamic buffer.

T is a complete type.


10.16.8. Function buffer_cast

[buffer.cast]

template<class T> T buffer_cast(const mutable_buffer& b) noexcept;
template<class T> T buffer_cast(const const_buffer& b) noexcept;

Returns: static_cast<T>(b.data_).

10.16.9. Function buffer_size

[buffer.size]

size_t buffer_size(const mutable_buffer& b) noexcept;
size_t buffer_size(const const_buffer& b) noexcept;

Returns: b.size_.

template<class ConstBufferSequence>
  size_t buffer_size(const ConstBufferSequence& buffers) noexcept;

Returns: The total size of all buffers in the sequence, as if computed as follows:

size_t total_size = 0;
for (const auto& v: buffers)
{
  const_buffer b(v);
  total_size += b.size_;
}
return total_size;

Remarks: This function overload shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.

10.16.10. Function buffer_copy

[buffer.copy]

size_t buffer_copy(const mutable_buffer& dest,
                   const const_buffer& source) noexcept;
size_t buffer_copy(const mutable_buffer& dest,
                   const const_buffer& source,
                   size_t max_size) noexcept;
template<class ConstBufferSequence>
  size_t buffer_copy(const mutable_buffer& dest,
                     const ConstBufferSequence& source) noexcept;
template<class ConstBufferSequence>
  size_t buffer_copy(const mutable_buffer& dest,
                     const ConstBufferSequence& source,
                     size_t max_size) noexcept;
template<class MutableBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const const_buffer& source) noexcept;
template<class MutableBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const const_buffer& source,
                     size_t max_size) noexcept;
template<class MutableBufferSequence, class ConstBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const ConstBufferSequence& source) noexcept;
template<class MutableBufferSequence, class ConstBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const ConstBufferSequence& source,
                     size_t max_size) noexcept;

Effects: Copies bytes from the buffer or buffer sequence source to the buffer or buffer sequence dest, as if by calls to memcpy.

The number of bytes copied is the lesser of:
buffer_size(dest);
buffer_size(source); and
max_size, if specified.

The mutable buffer or mutable buffer sequence dest specifies memory where the data should be placed. The operation always fills a buffer in the sequence completely before proceeding to the next.

The constant buffer or constant buffer sequence source specifies memory where the data to be written is located. The operation always copies a buffer in the sequence completely before proceeding to the next.

Returns: The number of bytes copied from source to dest.

Remarks: Where an overload accepts a template parameter MutableBufferSequence, the overload shall not participate in overload resolution unless is_mutable_buffer_sequence<MutableBufferSequence>::value is true. Where an overload accepts a template parameter ConstBufferSequence, the overload shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.

10.16.11. Buffer arithmetic

[buffer.arithmetic]

mutable_buffer operator+(const mutable_buffer& b, size_t n) noexcept;
mutable_buffer operator+(size_t n, const mutable_buffer& b) noexcept;

Returns: A mutable_buffer equivalent to

mutable_buffer(
  buffer_cast<char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

const_buffer operator+(const const_buffer& b, size_t n) noexcept;
const_buffer operator+(size_t n, const const_buffer& b) noexcept;

Returns: A const_buffer equivalent to

const_buffer(
  buffer_cast<const char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

mutable_buffers_1 operator+(const mutable_buffers_1& b, size_t n) noexcept;
mutable_buffers_1 operator+(size_t n, const mutable_buffers_1& b) noexcept;

Returns: A mutable_buffers_1 equivalent to

mutable_buffers_1(
  buffer_cast<char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

const_buffers_1 operator+(const const_buffers_1& b, size_t n) noexcept;
const_buffers_1 operator+(size_t n, const const_buffers_1& b) noexcept;

Returns: A const_buffers_1 equivalent to

const_buffers_1(
  buffer_cast<const char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

10.16.12. Buffer creation functions

[buffer.creation]

In the functions below, T must be a trivially copyable type.

For the function overloads below that accept an argument of type vector<>, the buffer objects returned are invalidated by any vector operation that also invalidates all references, pointers and iterators referring to the elements in the sequence (C++ Std, [vector]).

For the function overloads below that accept an argument of type basic_string<>, the buffer objects returned are invalidated according to the rules defined for invalidation of references, pointers and iterators referring to elements of the sequence (C++ Std, [string.require]).

mutable_buffers_1 buffer(void* p, size_t n) noexcept;

Returns: mutable_buffers_1(p, n).

const_buffers_1 buffer(const void* p, size_t n) noexcept;

Returns: const_buffers_1(p, n).

mutable_buffers_1 buffer(const mutable_buffer& b) noexcept;

Returns: mutable_buffers_1(b).

mutable_buffers_1 buffer(const mutable_buffer& b, size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  buffer_cast<void*>(b),
  min(buffer_size(b), n));

const_buffers_1 buffer(const const_buffer& b) noexcept;

Returns: const_buffers_1(b).

const_buffers_1 buffer(const const_buffer& b, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  buffer_cast<const void*>(b),
  min(buffer_size(b), n));

template<class T, size_t N>
  mutable_buffers_1 buffer(T (&arr)[N]) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  static_cast<void*>(arr),
  N * sizeof(T));

template<class T, size_t N>
  mutable_buffers_1 buffer(T (&arr)[N], size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  static_cast<void*>(arr),
  min(N * sizeof(T), n));

template<class T, size_t N>
  const_buffers_1 buffer(const T (&arr)[N]) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  static_cast<const void*>(arr),
  N * sizeof(T));

template<class T, size_t N>
  const_buffers_1 buffer(const T (&arr)[N], size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  static_cast<const void*>(arr),
  min(N * sizeof(T), n));

template<class T, size_t N>
  mutable_buffers_1 buffer(array<T, N>& arr) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  arr.data(),
  arr.size() * sizeof(T));

template<class T, size_t N>
  mutable_buffers_1 buffer(array<T, N>& arr, size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  arr.data(),
  min(arr.size() * sizeof(T), n));

template<class T, size_t N>
  const_buffers_1 buffer(array<const T, N>& arr) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  arr.size() * sizeof(T));

template<class T, size_t N>
  const_buffers_1 buffer(array<const T, N>& arr, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  min(arr.size() * sizeof(T), n));

template<class T, size_t N>
  const_buffers_1 buffer(const array<T, N>& arr) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  arr.size() * sizeof(T));

template<class T, size_t N>
  const_buffers_1 buffer(const array<T, N>& arr, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  min(arr.size() * sizeof(T), n));

template<class T, class Allocator>
  mutable_buffers_1 buffer(vector<T, Allocator>& vec) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  !vec.empty() ? &vec[0] : nullptr,
  vec.size() * sizeof(T));

template<class T, class Allocator>
  mutable_buffers_1 buffer(vector<T, Allocator>& vec, size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  !vec.empty() ? &vec[0] : nullptr,
  min(vec.size() * sizeof(T), n));

template<class T, class Allocator>
  const_buffers_1 buffer(const vector<T, Allocator>& vec) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  !vec.empty() ? &vec[0] : nullptr,
  vec.size() * sizeof(T));

template<class T, class Allocator>
  const_buffers_1 buffer(const vector<T, Allocator>& vec, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  !vec.empty() ? &vec[0] : nullptr,
  min(vec.size() * sizeof(T), n));

template<class CharT, class Traits, class Allocator>
  mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  !str.empty() ? &str[0] : nullptr,
  str.size() * sizeof(CharT));

template<class CharT, class Traits, class Allocator>
  mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str,
                           size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  !str.empty() ? &str[0] : nullptr,
  min(str.size() * sizeof(CharT), n));

template<class CharT, class Traits>
  const_buffers_1 buffer(basic_string_view<CharT, Traits> str) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  str.data(),
  str.size() * sizeof(CharT));

template<class CharT, class Traits>
  const_buffers_1 buffer(basic_string_view<CharT, Traits> str,
                         size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  str.data(),
  min(str.size() * sizeof(CharT), n));

10.16.13. Class template dynamic_vector_buffer

[buffer.dynamic.vector]

The dynamic_vector_buffer class template meets the requirements for DynamicBuffer.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Allocator>
      class dynamic_vector_buffer
      {
      public:
        // types:
        typedef const_buffers_1 const_buffers_type;
        typedef mutable_buffers_1 mutable_buffers_type;

        // constructors:
        explicit dynamic_vector_buffer(vector<T, Allocator>& vec) noexcept;
        dynamic_vector_buffer(vector<T, Allocator>& vec,
                              size_t maximum_size) noexcept;
        dynamic_vector_buffer(dynamic_vector_buffer&&) = default;

        // members:
        size_t size() const noexcept;
        size_t max_size() const noexcept;
        size_t capacity() const noexcept;
        const_buffers_type data() const noexcept;
        mutable_buffers_type prepare(size_t n);
        void commit(size_t n);
        void consume(size_t n);

      private:
        vector<T, Allocator>& vec_; // exposition only
        size_t size_; // exposition only
        const size_t max_size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The dynamic_vector_buffer class template requires that T is a trivially copyable type and that sizeof(T) == 1.

10.16.13.1. dynamic_vector_buffer constructors

[buffer.dynamic.vector.cons]

explicit dynamic_vector_buffer(vector<T, Allocator>& vec) noexcept;

Effects: Initializes vec_ with vec, size_ with vec.size(), and max_size_ with vec.max_size().

dynamic_vector_buffer(vector<T, Allocator>& vec,
                      size_t maximum_size) noexcept;

Requires: vec.size() <= maximum_size.

Effects: Initializes vec_ with vec, size_ with vec.size(), and max_size_ with maximum_size.

10.16.13.2. dynamic_vector_buffer members

[buffer.dynamic.vector.members]

size_t size() const noexcept;

Returns: size_.

size_t max_size() const noexcept;

Returns: max_size_.

size_t capacity() const noexcept;

Returns: vec_.capacity().

const_buffers_type data() const noexcept;

Returns: buffer(vec_, size_).

mutable_buffers_type prepare(size_t n);

Effects: Performs vec_.resize(size_ + n).

Returns: buffer(buffer(vec_) + size_, n).

Throws: length_error if size() + n exceeds max_size().

void commit(size_t n);

Effects: Performs:

size_ += min(n, vec_.size() - size_);
vec_.resize(size_);

void consume(size_t n);

Effects: Performs:

size_t m = min(n, size_);
vec_.erase(vec_.begin(), vec_.begin() + m);
size_ -= m;

10.16.14. Class template dynamic_string_buffer

[buffer.dynamic.string]

The dynamic_string_buffer class template meets the requirements for DynamicBuffer.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CharT, class Traits, class Allocator>
      class dynamic_string_buffer
      {
      public:
        // types:
        typedef const_buffers_1 const_buffers_type;
        typedef mutable_buffers_1 mutable_buffers_type;

        // constructors:
        explicit dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
        dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str,
                              size_t maximum_size) noexcept;
        dynamic_string_buffer(dynamic_string_buffer&&) = default;

        // members:
        size_t size() const noexcept;
        size_t max_size() const noexcept;
        size_t capacity() const noexcept;
        const_buffers_type data() const noexcept;
        mutable_buffers_type prepare(size_t n);
        void commit(size_t n) noexcept;
        void consume(size_t n);

      private:
        basic_string<CharT, Traits, Allocator>& str_; // exposition only
        size_t size_; // exposition only
        const size_t max_size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The dynamic_string_buffer class template requires that sizeof(CharT) == 1.

10.16.14.1. dynamic_string_buffer constructors

[buffer.dynamic.string.cons]

explicit dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;

Effects: Initializes str_ with str, size_ with str.size(), and max_size_ with str.max_size().

dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str,
                      size_t maximum_size) noexcept;

Requires: str.size() <= maximum_size.

Effects: Initializes str_ with str, size_ with str.size(), and max_size_ with maximum_size.

10.16.14.2. dynamic_string_buffer members

[buffer.dynamic.string.members]

size_t size() const noexcept;

Returns: size_.

size_t max_size() const noexcept;

Returns: max_size_.

size_t capacity() const noexcept;

Returns: str_.capacity().

const_buffers_type data() const noexcept;

Returns: buffer(str_, size_).

mutable_buffers_type prepare(size_t n);

Effects: Performs str_.resize(size_ + n).

Returns: buffer(buffer(str_) + size_, n).

Throws: length_error if size() + n exceeds max_size().

void commit(size_t n) noexcept;

Effects: Performs:

size_ += min(n, str_.size() - size_);
str_.resize(size_);

void consume(size_t n);

Effects: Performs:

size_t m = min(n, size_);
str_.erase(m);
size_ -= m;

10.16.15. Dynamic buffer creation functions

[buffer.dynamic.creation]

template<class T, class Allocator>
  dynamic_vector_buffer<T, Allocator>
    dynamic_buffer(vector<T, Allocator>& vec) noexcept;

Returns: dynamic_vector_buffer<T, Allocator>(vec).

template<class T, class Allocator>
  dynamic_vector_buffer<T, Allocator>
    dynamic_buffer(vector<T, Allocator>& vec, size_t n) noexcept;

Returns: dynamic_vector_buffer<T, Allocator>(vec, n).

template<class CharT, class Traits, class Allocator>
  dynamic_string_buffer<CharT, Traits, Allocator>
    dynamic_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;

Returns: dynamic_string_buffer<CharT, Traits, Allocator>(str).

template<class CharT, class Traits, class Allocator>
  dynamic_string_buffer<CharT, Traits, Allocator>
    dynamic_buffer(basic_string<CharT, Traits, Allocator>& str, size_t n) noexcept;

Returns: dynamic_string_buffer<CharT, Traits, Allocator>(str, n).

10.16.16. Class transfer_all

[buffer.transfer.all]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class transfer_all
      {
      public:
        size_t operator()(const error_code& ec, size_t) const;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class transfer_all is a function object type for use as a CompletionCondition argument to synchronous read, asynchronous read, synchronous write, or asynchronous write operations.

size_t operator()(const error_code& ec, size_t) const;

Returns: If !ec, an unspecified non-zero value. Otherwise 0.

10.16.17. Class transfer_at_least

[buffer.transfer.at.least]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class transfer_at_least
      {
      public:
        explicit transfer_at_least(size_t m);
        size_t operator()(const error_code& ec, size_t s) const;
      private:
        size_t minimum_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class transfer_at_least is a function object type for use as a CompletionCondition argument to synchronous read, asynchronous read, synchronous write, or asynchronous write operations.

explicit transfer_at_least(size_t m);

Postconditions: minimum_ == m.

size_t operator()(const error_code& ec, size_t n) const;

Returns: If !ec && n < minimum_, an unspecified non-zero value. Otherwise 0.

10.16.18. Class transfer_exactly

[buffer.transfer.exactly]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class transfer_exactly
      {
      public:
        explicit transfer_exactly(size_t e);
        size_t operator()(const error_code& ec, size_t s) const;
      private:
        size_t exact_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class transfer_exactly is a function object type for use as a CompletionCondition argument to synchronous read, asynchronous read, synchronous write, or asynchronous write operations.

explicit transfer_exactly(size_t e);

Postconditions: exact_ == e.

size_t operator()(const error_code& ec, size_t n) const;

Returns: If !ec && n < exact_, the result of min(exact_ - n, N), where N is an unspecified non-zero value. Otherwise 0.

10.16.19. Synchronous read operations

[buffer.read]

template<class SyncReadStream, class MutableBufferSequence>
  size_t read(SyncReadStream& stream,
              const MutableBufferSequence& buffers);
template<class SyncReadStream, class MutableBufferSequence>
  size_t read(SyncReadStream& stream,
              const MutableBufferSequence& buffers, error_code& ec);
template<class SyncReadStream, class MutableBufferSequence,
  class CompletionCondition>
    size_t read(SyncReadStream& stream,
                const MutableBufferSequence& buffers,
                CompletionCondition completion_condition);
template<class SyncReadStream, class MutableBufferSequence,
  class CompletionCondition>
    size_t read(SyncReadStream& stream,
                const MutableBufferSequence& buffers,
                CompletionCondition completion_condition,
                error_code& ec);

Effects: Clears ec, then reads data from the buffer-oriented synchronous read stream object stream by performing zero or more calls to the stream's read_some member function.

The completion_condition parameter specifies a function object to be called prior to each call to the stream's read_some member function. The function object is passed the error_code value from the most recent read_some call, and the total number of bytes transferred in the synchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent read_some call. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous read operation continues until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent read_some call.

Returns: The total number of bytes transferred in the synchronous read operation.

Remarks: This function shall not participate in overload resolution unless is_mutable_buffer_sequence<MutableBufferSequence>::value is true.

template<class SyncReadStream, class DynamicBuffer>
  size_t read(SyncReadStream& stream, DynamicBuffer&& b);
template<class SyncReadStream, class DynamicBuffer>
  size_t read(SyncReadStream& stream, DynamicBuffer&& b, error_code& ec);
template<class SyncReadStream, class DynamicBuffer,
  class CompletionCondition>
    size_t read(SyncReadStream& stream, DynamicBuffer&& b,
                CompletionCondition completion_condition);
template<class SyncReadStream, class DynamicBuffer,
  class CompletionCondition>
    size_t read(SyncReadStream& stream, DynamicBuffer&& b,
                CompletionCondition completion_condition,
                error_code& ec);

Effects: Clears ec, then reads data from the synchronous read stream object stream by performing zero or more calls to the stream's read_some member function.

Data is placed into the dynamic buffer object b. A mutable buffer sequence is obtained prior to each read_some call using b.prepare(N), where N is an unspecified value less than or equal to b.max_size() - b.size(). [Note: Implementations are encouraged to use b.capacity() when determining N, to minimize the number of read_some calls performed on the stream. —end note] After each read_some call, the implementation performs b.commit(n), where n is the return value from read_some.

The completion_condition parameter specifies a function object to be called prior to each call to the stream's read_some member function. The function object is passed the error_code value from the most recent read_some call, and the total number of bytes transferred in the synchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent read_some call. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous read operation continues until:

b.size() == b.max_size(); or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent read_some call.

Returns: The total number of bytes transferred in the synchronous read operation.

Remarks: This function shall not participate in overload resolution unless is_dynamic_buffer<DynamicBuffer>::value is true.

10.16.20. Asynchronous read operations

[buffer.async.read]

template<class AsyncReadStream, class MutableBufferSequence,
  class CompletionToken>
    DEDUCED async_read(AsyncReadStream& stream,
                    const MutableBufferSequence& buffers,
                    CompletionToken&& token);
template<class AsyncReadStream, class MutableBufferSequence,
  class CompletionCondition, class CompletionToken>
    DEDUCED async_read(AsyncReadStream& stream,
                    const MutableBufferSequence& buffers,
                    CompletionCondition completion_condition,
                    CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Reads data from the buffer-oriented asynchronous read stream object stream by invoking the stream's async_read_some member function (henceforth referred to as asynchronous read_some operations) zero or more times.

The completion_condition parameter specifies a function object to be called prior to each asynchronous read_some operation. The function object is passed the error_code value from the most recent asynchronous read_some operation, and the total number of bytes transferred in the asynchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent asynchronous read_some operation. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

This asynchronous read operation is outstanding until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

The program shall ensure the AsyncReadStream object stream is valid until the handler for the asynchronous operation is invoked.

On completion of the asynchronous operation, ec is the error_code value from the most recent asynchronous read_some operation, and n is the total number of bytes transferred.

Remarks: This function shall not participate in overload resolution unless is_mutable_buffer_sequence<MutableBufferSequence>::value is true.

template<class AsyncReadStream, class DynamicBuffer,
  class CompletionToken>
    DEDUCED async_read(AsyncReadStream& stream,
                    DynamicBuffer&& b, CompletionToken&& token);
template<class AsyncReadStream, class DynamicBuffer,
  class CompletionCondition, class CompletionToken>
    DEDUCED async_read(AsyncReadStream& stream,
                    DynamicBuffer&& b,
                    CompletionCondition completion_condition,
                    CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to read data from the buffer-oriented asynchronous read stream object stream by performing one or more asynchronous read_some operations on the stream.

Data is placed into the dynamic buffer object b. A mutable buffer sequence is obtained prior to each async_read_some call using b.prepare(N), where N is an unspecified value such that N is less than or equal to b.max_size() - b.size(). [Note: Implementations are encouraged to use b.capacity() when determining N, to minimize the number of asynchronous read_some operations performed on the stream. —end note] After the completion of each asynchronous read_some operation, the implementation performs b.commit(n), where n is the value passed to the asynchronous read_some operation's completion handler.

The completion_condition parameter specifies a function object to be called prior to each asynchronous read_some operation. The function object is passed the error_code value from the most recent asynchronous read_some operation, and the total number of bytes transferred in the asynchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent asynchronous read_some operation. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The asynchronous read operation is outstanding until:

b.size() == b.max_size(); or

— the completion condition returns 0.

The program must ensure both the AsyncReadStream object stream and the memory associated with the dynamic buffer b are valid until the handler for the asynchronous operation is invoked.

On completion of the asynchronous operation, ec is the error_code value from the most recent asynchronous read_some operation, and n is the total number of bytes transferred.

Remarks: This function shall not participate in overload resolution unless is_dynamic_buffer<DynamicBuffer>::value is true.

10.16.21. Synchronous write operations

[buffer.write]

template<class SyncWriteStream, class ConstBufferSequence>
  size_t write(SyncWriteStream& stream,
               const ConstBufferSequence& buffers);
template<class SyncWriteStream, class ConstBufferSequence>
  size_t write(SyncWriteStream& stream,
               const ConstBufferSequence& buffers, error_code& ec);
template<class SyncWriteStream, class ConstBufferSequence,
  class CompletionCondition>
    size_t write(SyncWriteStream& stream,
                 const ConstBufferSequence& buffers,
                 CompletionCondition completion_condition);
template<class SyncWriteStream, class ConstBufferSequence,
  class CompletionCondition>
    size_t write(SyncWriteStream& stream,
                 const ConstBufferSequence& buffers,
                 CompletionCondition completion_condition,
                 error_code& ec);

Effects: Writes data to the buffer-oriented synchronous write stream object stream by performing zero or more calls to the stream's write_some member function.

The completion_condition parameter specifies a function object to be called prior to each call to the stream's write_some member function. The function object is passed the error_code value from the most recent write_some call, and the total number of bytes transferred in the synchronous write operation so far. The function object return value specifies the maximum number of bytes to be write on the subsequent write_some call. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous write operation continues until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent write_some call.

Returns: The total number of bytes transferred in the synchronous write operation.

Remarks: This function shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.

template<class SyncWriteStream, class DynamicBuffer>
  size_t write(SyncWriteStream& stream, DynamicBuffer&& b);
template<class SyncWriteStream, class DynamicBuffer>
  size_t write(SyncWriteStream& stream, DynamicBuffer&& b, error_code& ec);
template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
  size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
               CompletionCondition completion_condition);
template<class SyncWriteStream, class DynamicBuffer, class CompletionCondition>
  size_t write(SyncWriteStream& stream, DynamicBuffer&& b,
               CompletionCondition completion_condition,
               error_code& ec);

Effects: Writes data to the synchronous write stream object stream by performing zero or more calls to the stream's write_some member function.

Data is written from the dynamic buffer object b. A constant buffer sequence is obtained using b.data(). After the data has been written to the stream, the implementation performs b.consume(n), where n is the number of bytes successfully written.

The completion_condition parameter specifies a function object to be called after each call to the stream's write_some member function. The function object is passed the error_code value from the most recent write_some call, and the total number of bytes transferred in the synchronous write operation so far. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous write operation continues until:

b.size() == 0; or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent write_some call.

Returns: The total number of bytes transferred in the synchronous write operation.

Remarks: This function shall not participate in overload resolution unless is_dynamic_buffer<DynamicBuffer>::value is true.

10.16.22. Asynchronous write operations

[buffer.async.write]

template<class AsyncWriteStream, class ConstBufferSequence,
  class CompletionToken>
    DEDUCED async_write(AsyncWriteStream& stream,
                     const ConstBufferSequence& buffers,
                     CompletionToken&& token);
template<class AsyncWriteStream, class ConstBufferSequence,
  class CompletionCondition, class CompletionToken>
    DEDUCED async_write(AsyncWriteStream& stream,
                     const ConstBufferSequence& buffers,
                     CompletionCondition completion_condition,
                     CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to write data to the buffer-oriented asynchronous write stream object stream by performing zero or more asynchronous operations on the stream using the stream's async_write_some member function (henceforth referred to as asynchronous write_some operations).

The completion_condition parameter specifies a function object to be called prior to each asynchronous write_some operation. The function object is passed the error_code value from the most recent asynchronous write_some operation, and the total number of bytes transferred in the asynchronous write operation so far. The function object return value specifies the maximum number of bytes to be write on the subsequent asynchronous write_some operation. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The asynchronous write operation continues until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

The program must ensure the AsyncWriteStream object stream is valid until the handler for the asynchronous operation is invoked.

On completion of the asynchronous operation, ec is the error_code value from the most recent asynchronous write_some operation, and n is the total number of bytes transferred.

Remarks: This function shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.

template<class AsyncWriteStream, class DynamicBuffer, class CompletionToken>
  DEDUCED async_write(AsyncWriteStream& stream,
                   DynamicBuffer&& b, CompletionToken&& token);
template<class AsyncWriteStream, class DynamicBuffer,
  class CompletionCondition, class CompletionToken>
    DEDUCED async_write(AsyncWriteStream& stream,
                     DynamicBuffer&& b,
                     CompletionCondition completion_condition,
                     CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to write data to the buffer-oriented asynchronous write stream object stream by performing zero or more asynchronous write_some operations on the stream.

Data is written from the dynamic buffer object b. A constant buffer sequence is obtained using b.data(). After the data has been written to the stream, the implementation performs b.consume(n), where n is the number of bytes successfully written.

The completion_condition parameter specifies a function object to be called prior to each asynchronous write_some operation. The function object is passed the error_code value from the most recent asynchronous write_some operation, and the total number of bytes transferred in the asynchronous write operation so far. The function object return value specifies the maximum number of bytes to be write on the subsequent asynchronous write_some operation. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The asynchronous write operation continues until:

b.size() == 0; or

— the completion condition returns 0.

The program must ensure both the AsyncWriteStream object stream and the memory associated with the dynamic buffer b are valid until the handler for the asynchronous operation is invoked.

On completion of the asynchronous operation, ec is the error_code value from the most recent asynchronous write_some operation, and n is the total number of bytes transferred.

Remarks: This function shall not participate in overload resolution unless is_dynamic_buffer<DynamicBuffer>::value is true.

10.16.23. Synchronous delimited read operations

[buffer.read.until]

template<class SyncReadStream, class DynamicBuffer>
  size_t read_until(SyncReadStream& s, DynamicBuffer&& b, char delim);
template<class SyncReadStream, class DynamicBuffer>
  size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
                    char delim, error_code& ec);
template<class SyncReadStream, class DynamicBuffer>
  size_t read_until(SyncReadStream& s, DynamicBuffer&& b, string_view delim);
template<class SyncReadStream, class DynamicBuffer>
  size_t read_until(SyncReadStream& s, DynamicBuffer&& b,
                    string_view delim, error_code& ec);

Effects: Reads data from the buffer-oriented synchronous read stream object stream by performing zero or more calls to the stream's read_some member function, until the input sequence of the dynamic buffer object b contains the specified delimiter delim.

Data is placed into the dynamic buffer object b. A mutable buffer sequence is obtained prior to each read_some call using b.prepare(N), where N is an unspecified value such that N <= max_size() - size(). [Note: Implementations are encouraged to use b.capacity() when determining N, to minimize the number of read_some calls performed on the stream. —end note] After each read_some call, the implementation performs b.commit(n), where n is the return value from read_some.

The synchronous read_until operation continues until:

— the input sequence of b contains the delimiter delim; or

b.size() == b.max_size(); or

— an synchronous read_some operation fails.

On exit, if the input sequence of b contains the delimiter, ec is set such that !ec is true. Otherwise, if b.size() == b.max_size(), ec is set such that ec == stream_errc::not_found. If b.size() < b.max_size(), ec contains the error_code from the most recent read_some call.

Returns: The number of bytes in the input sequence of b up to and including the delimiter, if present. [Note: On completion, the buffer may contain additional bytes following the delimiter. —end note] Otherwise returns 0.

10.16.24. Asynchronous delimited read operations

[buffer.async.read.until]

template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
  DEDUCED async_read_until(AsyncReadStream& s,
                        DynamicBuffer&& b, char delim,
                        CompletionToken&& token);
template<class AsyncReadStream, class DynamicBuffer, class CompletionToken>
  DEDUCED async_read_until(AsyncReadStream& s,
                        DynamicBuffer&& b, string_view delim,
                        CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to read data from the buffer-oriented asynchronous read stream object stream by performing zero or more asynchronous read_some operations on the stream, until the input sequence of the dynamic buffer object b contains the specified delimiter delim.

Data is placed into the dynamic buffer object b. A mutable buffer sequence is obtained prior to each async_read_some call using b.prepare(N), where N is an unspecified value such that N <= max_size() - size(). [Note: Implementations are encouraged to use b.capacity() when determining N, to minimize the number of asynchronous read_some operations performed on the stream. —end note] After the completion of each asynchronous read_some operation, the implementation performs b.commit(n), where n is the value passed to the asynchronous read_some operation's completion handler.

The asynchronous read_until operation continues until:

— the input sequence of b contains the delimiter delim; or

b.size() == b.max_size(); or

— an asynchronous read_some operation fails.

The program must ensure both the AsyncReadStream object stream and the memory associated with the dynamic buffer b are valid until the handler for the asynchronous operation is invoked.

If delim is of type string_view, the implementation copies the underlying sequence of characters prior to initiating an asynchronous read_some operation on the stream. [Note: This means that the caller is not required to guarantee the validity of the delimiter string after the call to async_read_until returns. —end note]

On completion of the asynchronous operation, if the input sequence of b contains the delimiter, ec is set such that !ec is true. Otherwise, if b.size() == b.max_size(), ec is set such that ec == stream_errc::not_found. If b.size() < b.max_size(), ec contains the error_code from the most recent asynchronous read_some operation. n shall contain the number of bytes in the input sequence of b up to and including the delimiter, if present, otherwise 0.

10.17. Sockets

[socket]

10.17.1. Header <experimental/socket> synopsis

[socket.synop]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      enum class socket_errc {
        already_open = implementation defined,
        not_found = implementation defined
      };

      const error_category& socket_category() noexcept;

      error_code make_error_code(socket_errc e) noexcept;
      error_condition make_error_condition(socket_errc e) noexcept;

      // Sockets:

      class socket_base;

      template<class Protocol>
        class basic_socket;

      template<class Protocol>
        class basic_datagram_socket;

      template<class Protocol>
        class basic_stream_socket;

      template<class Protocol>
        class basic_socket_acceptor;

      // Socket streams:

      template<class Protocol, class Clock = chrono::steady_clock,
        class WaitTraits = wait_traits<Clock>>
          class basic_socket_streambuf;

      template<class Protocol, class Clock = chrono::steady_clock,
        class WaitTraits = wait_traits<Clock>>
          class basic_socket_iostream;

      // synchronous connect operations:

      template<class Protocol, class EndpointSequence>
        typename Protocol::endpoint connect(basic_socket<Protocol>& s,
                                            const EndpointSequence& endpoints);
      template<class Protocol, class EndpointSequence>
        typename Protocol::endpoint connect(basic_socket<Protocol>& s,
                                            const EndpointSequence& endpoints);
                                            error_code& ec);
      template<class Protocol, class EndpointSequence, class ConnectCondition>
        typename Protocol::endpoint connect(basic_socket<Protocol>& s,
                                            const EndpointSequence& endpoints,
                                            ConnectCondition c);
      template<class Protocol, class EndpointSequence, class ConnectCondition>
        typename Protocol::endpoint connect(basic_socket<Protocol>& s,
                                            const EndpointSequence& endpoints,
                                            ConnectCondition c,
                                            error_code& ec);

      template<class Protocol, class InputIterator>
        InputIterator connect(basic_socket<Protocol>& s,
                              InputIterator first, InputIterator last);
      template<class Protocol, class InputIterator>
        InputIterator connect(basic_socket<Protocol>& s,
                              InputIterator first, InputIterator last,
                              error_code& ec);
      template<class Protocol, class InputIterator, class ConnectCondition>
        InputIterator connect(basic_socket<Protocol>& s,
                              InputIterator first, InputIterator last,
                              ConnectCondition c);
      template<class Protocol, class InputIterator, class ConnectCondition>
        InputIterator connect(basic_socket<Protocol>& s,
                              InputIterator first, InputIterator last,
                              ConnectCondition c,
                              error_code& ec);

      // asynchronous connect operations:

      template<class Protocol, class EndpointSequence, class CompletionToken>
        DEDUCED async_connect(basic_socket<Protocol>& s,
                              const EndpointSequence& endpoints,
                              CompletionToken&& token);
      template<class Protocol, class EndpointSequence,
        class ConnectCondition, class CompletionToken>
          DEDUCED async_connect(basic_socket<Protocol>& s,
                                const EndpointSequence& endpoints,
                                ConnectCondition c,
                                CompletionToken&& token);

      template<class Protocol, class InputIterator, class CompletionToken>
        DEDUCED async_connect(basic_socket<Protocol>& s,
                              InputIterator first, InputIterator last,
                              CompletionToken&& token);
      template<class Protocol, class InputIterator,
        class ConnectCondition, class CompletionToken>
          DEDUCED async_connect(basic_socket<Protocol>& s,
                                InputIterator first, InputIterator last,
                                ConnectCondition c,
                                CompletionToken&& token);

    } // inline namespace network_v1
  } // namespace experimental

  template<> struct is_error_code_enum<
    experimental::network_v1::socket_errc>
      : public true_type {};

} // namespace std

The figure below illustrates relationships between various types described in this Technical Specification. A solid line from A to B that is terminated by an open arrow indicates that A is derived from B. A solid line from A to B that starts with a diamond and is terminated by a solid arrow indicates that A contains an object of type B. A dotted line from A to B indicates that A is a typedef for the class template B with the specified template argument.

sockets

10.17.2. Requirements

[socket.reqmts]

10.17.2.1. Native handles

[socket.reqmts.native]

Several classes described in this Technical Specification have a member type native_handle_type, a member function native_handle, and member functions that accept arguments of type native_handle_type. The presence of these members and their semantics is implementation-defined.

[Note: These members allow implementations to provide access to their implementation details. Their names are specified to facilitate portable compile-time detection. Actual use of these members is inherently non-portable. For operating systems that are based on POSIX, implementations are encouraged to define the native_handle_type for sockets as int, representing the native file descriptor associated with the socket. —end note]

10.17.2.2. Endpoint requirements

[socket.reqmts.endpoint]

An endpoint must meet the requirements of DefaultConstructible types (C++ Std, [defaultconstructible]), CopyConstructible types (C++ Std, 20.1.3), and the requirements of Assignable types (C++ Std, 23.1).

In the table below, X denotes an endpoint class, a denotes a (possibly const) value of type X, and u denotes an identifier.

Table 18. Endpoint requirements

expression

type

assertion/note
pre/post-conditions

X::protocol_type

type meeting protocol requirements

a.protocol()

protocol_type


In the table below, X denotes an endpoint class, a denotes a (possibly const) value of type X, b denotes a value of type X, and s denotes a (possibly const) value of a type that is convertible to size_t and denotes a size in bytes.

Table 19. Endpoint requirements for extensible implementations

expression

type

assertion/note
pre/post-conditions

a.data()

const void*

Returns a pointer suitable for passing as the address argument to functions such as POSIX connect, or as the dest_addr argument to functions such as POSIX sendto. The implementation shall perform a static_cast on the pointer to convert it to const sockaddr*.

b.data()

void*

Returns a pointer suitable for passing as the address argument to functions such as POSIX accept, getpeername, getsockname and recvfrom. The implementation shall perform a static_cast on the pointer to convert it to sockaddr*.

a.size()

size_t

Returns a value suitable for passing as the address_len argument to functions such as POSIX connect, or as the dest_len argument to functions such as POSIX sendto, after appropriate integer conversion has been performed.

b.resize(s)

pre: s >= 0
post: a.size() == s
Passed the value contained in the address_len argument to functions such as POSIX accept, getpeername, getsockname and recvfrom, after successful completion of the function. Permitted to throw an exception if the protocol associated with the endpoint object a does not support the specified size.

a.capacity()

size_t

Returns a value suitable for passing as the address_len argument to functions such as POSIX accept, getpeername, getsockname and recvfrom, after appropriate integer conversion has been performed.


10.17.2.3. Protocol requirements

[socket.reqmts.protocol]

A protocol must meet the requirements of Destructible (C++ Std, [destructible]), CopyConstructible types (C++ Std, 20.1.3), and the requirements of Assignable types (C++ Std, 23.1).

In the table below, X denotes a protocol class.

Table 20. Protocol requirements

expression

return type

assertion/note
pre/post-conditions

X::endpoint

type meeting endpoint requirements


In the table below, X denotes a protocol class, and a denotes a (possibly const) value of type X.

Table 21. Protocol requirements for extensible implementations

expression

return type

assertion/note
pre/post-conditions

a.family()

int

Returns a value suitable for passing as the domain argument to POSIX socket (or equivalent).

a.type()

int

Returns a value suitable for passing as the type argument to POSIX socket (or equivalent).

a.protocol()

int

Returns a value suitable for passing as the protocol argument to POSIX socket (or equivalent).


10.17.2.4. Acceptable protocol requirements

[socket.reqmts.acceptableprotocol]

An acceptable protocol must meet the requirements for protocol as well as the additional requirements listed below.

In the table below, X denotes an acceptable protocol class.

Table 22. AcceptableProtocol requirements

expression

return type

assertion/note
pre/post-conditions

X::socket

A type that is publicly and unambiguously derived from basic_socket<X>.


10.17.2.5. Gettable socket option requirements

[socket.reqmts.gettablesocketoption]

In the table below, X denotes a socket option class, a denotes a (possibly const) value of type X, b denotes a value of type X, p denotes a (possibly const) value that meets the protocol requirements, and s denotes a (possibly const) value of a type that is convertible to size_t and denotes a size in bytes.

Table 23. GettableSocketOption requirements for extensible implementations

expression

type

assertion/note
pre/post-conditions

a.level(p)

int

Returns a value suitable for passing as the level argument to POSIX getsockopt (or equivalent).

a.name(p)

int

Returns a value suitable for passing as the option_name argument to POSIX getsockopt (or equivalent).

b.data(p)

void*

Returns a pointer suitable for passing as the option_value argument to POSIX getsockopt (or equivalent).

a.size(p)

size_t

Returns a value suitable for passing as the option_len argument to POSIX getsockopt (or equivalent), after appropriate integer conversion has been performed.

b.resize(p,s)

post: b.size(p) == s.
Passed the value contained in the option_len argument to POSIX getsockopt (or equivalent) after successful completion of the function. Permitted to throw an exception if the socket option object b does not support the specified size.


10.17.2.6. Settable socket option requirements

[socket.reqmts.settablesocketoption]

In the table below, X denotes a socket option class, a denotes a (possibly const) value of type X, p denotes a (possibly const) value that meets the protocol requirements, and u denotes an identifier.

Table 24. SettableSocketOption requirements for extensible implementations

expression

type

assertion/note
pre/post-conditions

a.level(p)

int

Returns a value suitable for passing as the level argument to POSIX setsockopt (or equivalent).

a.name(p)

int

Returns a value suitable for passing as the option_name argument to POSIX setsockopt (or equivalent).

a.data(p)

const void*

Returns a pointer suitable for passing as the option_value argument to POSIX setsockopt (or equivalent).

a.size(p)

size_t

Returns a value suitable for passing as the option_len argument to POSIX setsockopt (or equivalent), after appropriate integer conversion has been performed.


10.17.2.7. I/O control command requirements

[socket.reqmts.iocontrolcommand]

In the table below, a denotes a (possibly const) value of an I/O control command class, and b denotes a value of an I/O control command class.

Table 25. IoControlCommand requirements for extensible implementations

expression

type

assertion/note
pre/post-conditions

a.name()

int

Returns a value suitable for passing as the request argument to POSIX ioctl (or equivalent).

b.data()

void*


10.17.2.8. Connect condition requirements

[socket.reqmts.connectcondition]

A connect condition type shall satisfy the requirements of Destructible (C++ Std, [destructible]) and CopyConstructible (C++ Std, [copyconstructible]) as well as the additional requirements listed below.

In the table below, x denotes an object of a connect condition type, ec denotes a (possibly const) value of type error_code, and ep denotes a (possibly const) value of some type satisfying the endpoint requirements.

Table 26. ConnectCondition requirements

expression

return type

assertion/note
pre/post-condition

x(ec, ep)

bool

Returns true to indicate that the connect or async_connect algorithm should attempt a connection to the endpoint ep. Otherwise, returns false to indicate that the algorithm should not attempt connection to the endpoint ep, and should instead skip to the next endpoint in the sequence.


10.17.3. Error codes

[socket.err]

const error_category& socket_category() noexcept;

Returns: A reference to an object of a type derived from class error_category.

The object’s default_error_condition and equivalent virtual functions behave as specified for the class error_category. The object’s name virtual function returns a pointer to the string "socket".

error_code make_error_code(socket_errc e) noexcept;

Returns: error_code(static_cast<int>(e), socket_category()).

error_condition make_error_condition(socket_errc e) noexcept;

Returns: error_condition(static_cast<int>(e), socket_category()).

10.17.4. Class socket_base

[socket.base]

namespace std {
  namespace experimental {
    inline namespace network_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;

        typedef T1 shutdown_type;
        static constexpr shutdown_type shutdown_receive;
        static constexpr shutdown_type shutdown_send;
        static constexpr shutdown_type shutdown_both;

        typedef T2 wait_type;
        static constexpr wait_type wait_read;
        static constexpr wait_type wait_write;
        static constexpr wait_type wait_error;

        typedef T3 message_flags;
        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();
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

socket_base defines several member types:

— socket option classes 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;

— an enumerated type, shutdown_type, for use with the basic_socket<Protocol> class's shutdown member function.

— an enumerated type, wait_type, for use with the basic_socket<Protocol> and basic_socket_acceptor<Protocol> classes' wait and async_wait member functions,

— a bitmask type, message_flags, for use with the basic_stream_socket<Protocol> 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.

— a constant, max_listen_connections, for use with the basic_socket_acceptor<Protocol> class's listen member function.

Table 27. socket_base constants

Constant Name

POSIX macro

Definition or notes

shutdown_receive

SHUT_RD

Disables further receive operations.

shutdown_send

SHUT_WR

Disables further send operations.

shutdown_both

SHUT_RDWR

Disables further send and receive operations.

wait_read

Wait until the socket is ready-to-read.

For a given socket, when a wait or async_wait operation using wait_read completes successfuly, a subsequent call to the socket's receive or receive_from functions may complete without blocking.
Similarly, for a given acceptor, when a wait or async_wait operation using wait_read completes successfully, a subsequent call to the acceptor's accept function may complete without blocking.

wait_write

Wait until the socket is ready-to-write.

For a given socket, when a wait or async_wait operation using wait_write completes successfuly, a subsequent call to the socket's send or send_to functions may complete without blocking.

wait_error

Wait until the socket has a pending error condition.

For a given socket, when a wait or async_wait operation using wait_error completes successfuly, a subsequent call to one of the socket's synchronous operations may complete without blocking. The nature of the pending error condition determines which.

message_peek

MSG_PEEK

Leave received data in queue.

message_out_of_band

MSG_OOB

Out-of-band data.

message_do_not_route

MSG_DONTROUTE

Send without using routing tables.

max_listen_connections

SOMAXCONN

The implementation-defined limit on the length of the queue of pending incoming connections.


10.17.5. Boolean socket options

[socket.opt.bool]

The socket_base::broadcast, socket_base::debug, socket_base::do_not_route, socket_base::keep_alive, socket_base::out_of_band_inline and socket_base::reuse_address classes are boolean socket options.

Boolean socket option classes satisfy the requirements for Destructible (C++ Std, [destructible]), CopyConstructible (C++ Std, [copyconstructible]), Assignable (C++ Std, [assignable]), GettableSocketOption, and SettableSocketOption. The boolean socket option classes are contextually convertible to bool.

Boolean socket option classes are defined as follows:

class C
{
public:
  // constructors:
  C() noexcept;
  explicit C(bool v) noexcept;

  // members:
  C& operator=(bool v) noexcept;

  bool value() const noexcept;

  explicit operator bool() const noexcept;
  bool operator!() const noexcept;
};

Extensible implementations provide the following member functions:

class C
{
public:
  template<class Protocol> int level(const Protocol& p) const noexcept;
  template<class Protocol> int name(const Protocol& p) const noexcept;
  template<class Protocol> void* data(const Protocol& p) noexcept;
  template<class Protocol> const void* data(const Protocol& p) const noexcept;
  template<class Protocol> size_t size(const Protocol& p) const noexcept;
  template<class Protocol> void resize(const Protocol& p, size_t s);
  // remainder unchanged
private:
  int value_; // exposition only
};

Let L and N identify the POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt.

Table 28. Boolean socket options

C

L

N

Definition or notes

socket_base::broadcast

SOL_SOCKET

SO_BROADCAST

Determines whether a socket permits sending of broadcast messages, if supported by the protocol.

socket_base::debug

SOL_SOCKET

SO_DEBUG

Determines whether debugging information is recorded by the underlying protocol.

socket_base::do_not_route

SOL_SOCKET

SO_DONTROUTE

Determines whether outgoing messages bypass standard routing facilities.

socket_base::keep_alive

SOL_SOCKET

SO_KEEPALIVE

Determines whether a socket permits sending of keep_alive messages, if supported by the protocol.

socket_base::out_of_band_inline

SOL_SOCKET

SO_OOBINLINE

Determines whether out-of-band data (also known as urgent data) is received inline.

socket_base::reuse_address

SOL_SOCKET

SO_REUSEADDR

Determines whether the validation of endpoints used for binding a socket should allow the reuse of local endpoints, if supported by the protocol.


10.17.5.1. Boolean socket option constructors

[socket.opt.bool.cons]

C() noexcept;

Postconditions: !value().

explicit C(bool v) noexcept;

Postconditions: value() == v.

10.17.5.2. Boolean socket option members

[socket.opt.bool.members]

C& operator=(bool v) noexcept;

Returns: *this.

Postconditions: value() == v.

bool value() const noexcept;

Returns: The stored socket option value. For extensible implementations, returns value_ != 0.

explicit operator bool() const noexcept;

Returns: value().

bool operator!() const noexcept;

Returns: !value().

10.17.5.3. Boolean socket option members (extensible implementations)

[socket.opt.bool.extensible]

template<class Protocol> int level(const Protocol& p) const noexcept;

Returns: L.

template<class Protocol> int name(const Protocol& p) const noexcept;

Returns: N.

template<class Protocol> void* data(const Protocol& p) noexcept;

Returns: std::addressof(value_).

template<class Protocol> const void* data(const Protocol& p) const noexcept;

Returns: std::addressof(value_).

template<class Protocol> size_t size(const Protocol& p) const noexcept;

Returns: sizeof(value_).

template<class Protocol> void resize(const Protocol& p, size_t s);

Throws: length_error if s is not a valid data size for the protocol specified by p.

10.17.6. Integral socket options

[socket.opt.int]

The socket_base::receive_buffer_size, socket_base::receive_low_watermark, socket_base::send_buffer_size and socket_base::send_low_watermark classes are integral socket options.

Integral socket option classes satisfy the requirements for Destructible (C++ Std, [destructible]), CopyConstructible (C++ Std, [copyconstructible]), Assignable (C++ Std, [assignable]), GettableSocketOption, and SettableSocketOption.

Integral socket option classes are defined as follows:

class C
{
public:
  // constructors:
  C() noexcept;
  explicit C(int v);

  // members:
  C& operator=(int v);

  int value() const noexcept;
};

Extensible implementations provide the following member functions:

class C
{
public:
  template<class Protocol> int level(const Protocol& p) const noexcept;
  template<class Protocol> int name(const Protocol& p) const noexcept;
  template<class Protocol> void* data(const Protocol& p) noexcept;
  template<class Protocol> const void* data(const Protocol& p) const noexcept;
  template<class Protocol> size_t size(const Protocol& p) const noexcept;
  template<class Protocol> void resize(const Protocol& p, size_t s);
  // remainder unchanged
private:
  int value_; // exposition only
};

Let L and N identify the POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt.

Table 29. Integral socket options

C

L

N

Definition or notes

socket_base::receive_buffer_size

SOL_SOCKET

SO_RCVBUF

Specifies the size of the receive buffer associated with a socket.

socket_base::receive_low_watermark

SOL_SOCKET

SO_RCVLOWAT

Specifies the minimum number of bytes to process for socket input operations.

socket_base::send_buffer_size

SOL_SOCKET

SO_SNDBUF

Specifies the size of the send buffer associated with a socket.

socket_base::send_low_watermark

SOL_SOCKET

SO_SNDLOWAT

Specifies the minimum number of bytes to process for socket output operations.


[Note: The constants SOL_SOCKET, SO_RCVBUF, SO_RCVLOWAT, SO_SNDBUF and SO_SNDLOWAT are defined in the POSIX header file sys/socket.h. —end note]

10.17.6.1. Integral socket option constructors

[socket.opt.int.cons]

C() noexcept;

Postconditions: value() == 0.

explicit C(int v);

Postconditions: value() == v.

10.17.6.2. Integral socket option members

[socket.opt.int.members]

C& operator=(int v);

Returns: *this.

Postconditions: value() == v.

int value() const noexcept;

Returns: The stored socket option value. For extensible implementations, returns value_.

10.17.6.3. Integral socket option members (extensible implementations)

[socket.base.int.extensible]

template<class Protocol> int level(const Protocol& p) const noexcept;

Returns: L.

template<class Protocol> int name(const Protocol& p) const noexcept;

Returns: N.

template<class Protocol> void* data(const Protocol& p) noexcept;

Returns: std::addressof(value_).

template<class Protocol> const void* data(const Protocol& p) const noexcept;

Returns: std::addressof(value_).

template<class Protocol> size_t size(const Protocol& p) const noexcept;

Returns: sizeof(value_).

template<class Protocol> void resize(const Protocol& p, size_t s);

Throws: length_error if s is not a valid data size for the protocol specified by p.

10.17.7. Class socket_base::linger

[socket.opt.linger]

The linger class represents a socket option for controlling the behavior when a socket is closed and unsent data is present.

linger satisfies the requirements for Destructible (C++ Std, [destructible]), CopyConstructible (C++ Std, [copyconstructible]), Assignable (C++ Std, [assignable]), GettableSocketOption, and SettableSocketOption.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class socket_base::linger
      {
      public:
        // constructors:
        linger() noexcept;
        linger(bool e, chrono::seconds t) noexcept;

        // members:
        bool enabled() const noexcept;
        void enabled(bool e) noexcept;

        chrono::seconds timeout() const noexcept;
        void timeout(chrono::seconds t) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Extensible implementations provide the following member functions:

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class socket_base::linger
      {
      public:
        template<class Protocol> int level(const Protocol& p) const noexcept;
        template<class Protocol> int name(const Protocol& p) const noexcept;
        template<class Protocol> void data(const Protocol& p) noexcept;
        template<class Protocol> const void* data(const Protocol& p) const noexcept;
        template<class Protocol> size_t size(const Protocol& p) const noexcept;
        template<class Protocol> void resize(const Protocol& p, size_t s);
        // remainder unchanged
      private:
        ::linger value_;  // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.17.7.1. socket_base::linger constructors

[socket.opt.linger.cons]

linger() noexcept;

Postconditions: !enabled() && timeout() == chrono::seconds(0).

linger(bool e, chrono::seconds t) noexcept;

Postconditions: enabled() == e && timeout() == t.

10.17.7.2. socket_base::linger members

[socket.opt.linger.members]

bool enabled() const noexcept;

Returns: value_.l_onoff != 0.

void enabled(bool e) noexcept;

Postconditions: enabled() == e.

chrono::seconds timeout() const noexcept;

Returns: chrono::seconds(value_.l_linger).

void timeout(chrono::seconds t) noexcept;

Postconditions: timeout() == t.

10.17.7.3. socket_base::linger members (extensible implementations)

[socket.opt.linger.extensible]

template<class Protocol> int level(const Protocol& p) const noexcept;

Returns: SOL_SOCKET.

[Note: The constant SOL_SOCKET is defined in the POSIX header file sys/socket.h. —end note]

template<class Protocol> int name(const Protocol& p) const noexcept;

Returns: SO_LINGER.

[Note: The constant SO_LINGER is defined in the POSIX header file sys/socket.h. —end note]

template<class Protocol> void* data(const Protocol& p) const noexcept;

Returns: std::addressof(value_).

template<class Protocol> const void* data(const Protocol& p) const noexcept;

Returns: std::addressof(value_).

template<class Protocol> size_t size(const Protocol& p) const noexcept;

Returns: sizeof(value_).

template<class Protocol> void resize(const Protocol& p, size_t s);

Throws: length_error if s != sizeof(value_).

10.17.8. Class template basic_socket

[socket.basic]

Class template basic_socket<Protocol> is used as the base class for the basic_datagram_socket<Protocol> and basic_stream_socket<Protocol> class templates. It provides functionality that is common to both types of socket.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Protocol>
      class basic_socket : public socket_base
      {
      public:
        // types:

        typedef io_service::executor_type executor_type;
        typedef implementation defined native_handle_type; // See native handles
        typedef Protocol protocol_type;
        typedef typename protocol_type::endpoint endpoint_type;

        // basic_socket operations:

        executor_type get_executor() noexcept;

        native_handle_type native_handle(); // See native handles

        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); // See native handles
        void assign(const protocol_type& protocol,
                    const native_handle_type& native_socket,
                    error_code& ec); // See native handles

        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:
        // construct / copy / destroy:

        explicit basic_socket(io_service& ios);
        basic_socket(io_service& ios, const protocol_type& protocol);
        basic_socket(io_service& ios, const endpoint_type& endpoint);
        basic_socket(io_service& ios, const protocol_type& protocol,
                     const native_handle_type& native_socket); // See native handles
        basic_socket(const basic_socket&) = delete;
        basic_socket(basic_socket&& rhs);
        template<class OtherProtocol>
          basic_socket(basic_socket<OtherProtocol>&& rhs);

        ~basic_socket();

        basic_socket& operator=(const basic_socket&) = delete;
        basic_socket& operator=(basic_socket&& rhs);
        template<class OtherProtocol>
          basic_socket& operator=(basic_socket<OtherProtocol>&& rhs);

      private:
        protocol_type protocol_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.17.8.1. basic_socket constructors

[socket.basic.cons]

explicit basic_socket(io_service& ios);

Postconditions:
get_executor() == ios.get_executor().
is_open() == false.

basic_socket(io_service& ios, const protocol_type& protocol);

Effects: Opens this socket as if by calling open(protocol).

Postconditions:
get_executor() == ios.get_executor().
is_open() == true.
non_blocking() == false.
protocol_ == protocol.

basic_socket(io_service& ios, const endpoint_type& endpoint);

Effects: Opens and binds this socket as if by calling:

open(endpoint.protocol());
bind(endpoint);

Postconditions:
get_executor() == ios.get_executor().
is_open() == true.
non_blocking() == false.
protocol_ == endpoint.protocol().

basic_socket(io_service& ios, const protocol_type& protocol,
             const native_handle_type& native_socket);

Requires: native_socket is a native handle to an open socket.

Effects: Assigns the existing native socket into this socket as if by calling assign(protocol, native_socket).

Postconditions:
get_executor() == ios.get_executor().
is_open() == true.
non_blocking() == false.
protocol_ == protocol.

basic_socket(basic_socket&& rhs);

Effects: Move constructs an object of class basic_socket<Protocol> that refers to the state originally represented by rhs.

Postconditions:
get_executor() is equal to the prior value of rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the constructor invocation.
non_blocking() returns the same value as rhs.non_blocking() prior to the constructor invocation.
native_handle() returns the prior value of rhs.native_handle().
protocol_ is the prior value of rhs.protocol_.
rhs.is_open() == false.

template<class OtherProtocol>
  basic_socket(basic_socket<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

Effects: Move constructs an object of class basic_socket<Protocol> that refers to the state originally represented by rhs.

Postconditions:
get_executor() is equal to the prior value of rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the constructor invocation.
non_blocking() returns the same value as rhs.non_blocking() prior to the constructor invocation.
native_handle() returns the prior value of rhs.native_handle().
protocol_ is the result of converting the prior value of rhs.protocol_.
rhs.is_open() == false.

Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.8.2. basic_socket destructor

[socket.basic.dtor]

~basic_socket();

Effects: If is_open() is true, cancels all outstanding asynchronous operations associated with this socket, disables the linger socket option to prevent the destructor from blocking, and releases socket resources as if by POSIX close(native_handle()). Completion handlers for canceled operations are passed an error code ec such that ec == errc::operation_canceled yields true.

10.17.8.3. basic_socket assignment

[socket.basic.assign]

basic_socket& operator=(basic_socket&& rhs);

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.

Postconditions:
get_executor() is equal to the prior value of rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the assignment.
non_blocking() returns the same value as rhs.non_blocking() prior to the assignment.
protocol_ is the prior value of rhs.protocol_.
rhs.is_open() == false.

Returns: *this.

template<class OtherProtocol>
  basic_socket& operator=(basic_socket<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

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.

Postconditions:
get_executor() is equal to the prior value of rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the assignment.
non_blocking() returns the same value as rhs.non_blocking() prior to the assignment.
protocol_ is the result of converting the prior value of rhs.protocol_.
rhs.is_open() == false.

Returns: *this.

Remarks: This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.8.4. basic_socket operations

[socket.basic.ops]

executor_type get_executor() noexcept;

Returns: The associated executor.

native_handle_type native_handle();

Returns: The native representation of this socket.

void open(const protocol_type& protocol);
void open(const protocol_type& protocol, error_code& ec);

Effects: Establishes the postcondition, as if by POSIX socket(protocol.family(), protocol.type(), protocol.protocol()).

Postconditions:
is_open() == true.
non_blocking() == false.
protocol_ == protocol.

Error conditions:
socket_errc::already_open — if is_open() == true.

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);

Requires: native_socket is a native handle to an open socket.

Effects: Assigns the native socket handle to this socket object.

Postconditions:
is_open() == true.
non_blocking() == false.
protocol_ == protocol.

Error conditions:
socket_errc::already_open — if is_open() == true.

bool is_open() const noexcept;

Returns: A bool indicating whether this socket was opened by a previous call to open or assign.

void close();
void close(error_code& ec);

Effects: If is_open() is true, cancels all outstanding asynchronous operations associated with this socket, and establishes the postcondition as if by POSIX close(native_handle()). Completion handlers for canceled asynchronous operations are passed an error code ec such that ec == errc::operation_canceled yields true.

Postconditions: is_open() == false.

void cancel();
void cancel(error_code& ec);

Effects: Cancels all outstanding asynchronous operations associated with this socket. Completion handlers for canceled asynchronous operations are passed an error code ec such that ec == errc::operation_canceled yields true.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

template<class SettableSocketOption>
  void set_option(const SettableSocketOption& option);
template<class SettableSocketOption>
  void set_option(const SettableSocketOption& option, error_code& ec);

Effects: Sets an option on this socket, as if by POSIX setsockopt(native_handle(), option.level(protocol_), option.name(protocol_), option.data(protocol_), option.size(protocol_)).

template<class GettableSocketOption>
  void get_option(GettableSocketOption& option);
template<class GettableSocketOption>
  void get_option(GettableSocketOption& option, error_code& ec);

Effects: Gets an option from this socket, as if by POSIX:

socklen_t option_len = option.size(protocol_);
int result = getsockopt(native_handle(), option.level(protocol_),
                        option.name(protocol_), option.data(protocol_),
                        &option_len);
if (result == 0)
  option.resize(option_len);

template<class IoControlCommand>
  void io_control(IoControlCommand& command);
template<class IoControlCommand>
  void io_control(IoControlCommand& command, error_code& ec);

Effects: Executes an I/O control command on this socket, as if by POSIX ioctl(native_handle(), command.name(), command.data()).

void non_blocking(bool mode);
void non_blocking(bool mode, error_code& ec);

Effects: Sets the non-blocking mode of this socket. If mode is true, subsequent synchronous operations may fail with error condition errc::operation_would_block if they are unable to perform the requested operation immediately. If mode is false, subsequent synchronous operations block until complete.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

[Note: The non-blocking mode has no effect on the behavior of asynchronous operations. —end note]

bool non_blocking() const;

Returns: The non-blocking mode of this socket.

void native_non_blocking(bool mode);
void native_non_blocking(bool mode, error_code& ec);

Effects: Sets the non-blocking mode of the underlying native socket, as if by POSIX:

int flags = fcntl(native_handle(), F_GETFL, 0);
if (flags >= 0)
{
  if (mode)
    flags |= O_NONBLOCK;
  else
    flags &= ~O_NONBLOCK;
  fcntl(native_handle(), F_SETFL, flags);
}

The native non-blocking mode has no effect on the behavior of the synchronous or asynchronous operations specified in this clause.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.
errc::invalid_argument — if mode == false and non_blocking() == true. [Note: As the combination does not make sense. —end note]

bool native_non_blocking() const;

Returns: The non-blocking mode of the underlying native socket.

Remarks: Implementations are permitted and encouraged to cache the native non-blocking mode that was applied through a prior call to native_non_blocking. Implementations may return an incorrect value if a program sets the non-blocking mode directly on the socket, by calling an operating system-specific function on the result of native_handle().

bool at_mark() const;
bool at_mark(error_code& ec) const;

Effects: Determines if this socket is at the out-of-band data mark, as if by POSIX sockatmark(native_handle()). [Note: The at_mark() function must be used in conjunction with the socket_base::out_of_band_inline socket option. —end note]

Returns: A bool indicating whether this socket is at the out-of-band data mark.

size_t available() const;
size_t available(error_code& ec) const;

Returns: An indication of the number of bytes that may be read without blocking, or 0 if an error occurs.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

void bind(const endpoint_type& endpoint);
void bind(const endpoint_type& endpoint, error_code& ec);

Effects: Binds this socket to the specified local endpoint, as if by POSIX bind(native_handle(), endpoint.data(), endpoint.size()).

void shutdown(shutdown_type what);
void shutdown(shutdown_type what, error_code& ec);

Effects: Shuts down all or part of a full-duplex connection for the socket, as if by POSIX shutdown(native_handle(), static_cast<int>(what)).

endpoint_type local_endpoint() const;
endpoint_type local_endpoint(error_code& ec) const;

Effects: Determines the locally-bound endpoint associated with the socket, as if by POSIX:

endpoint_type endpoint;
socklen_t endpoint_len = endpoint.capacity();
int result == getsockname(native_handle(), endpoint.data(), &endpoint_len);
if (result == 0)
  endpoint.resize(endpoint_len);

Returns: On success, endpoint. Otherwise endpoint_type().

endpoint_type remote_endpoint() const;
endpoint_type remote_endpoint(error_code& ec) const;

Effects: Determines the remote endpoint associated with this socket, as if by POSIX:

endpoint_type endpoint;
socklen_t endpoint_len = endpoint.capacity();
int result == getpeername(native_handle(), endpoint.data(), &endpoint_len);
if (result == 0)
  endpoint.resize(endpoint_len);

Returns: On success, endpoint. Otherwise endpoint_type().

void connect(const endpoint_type& endpoint);
void connect(const endpoint_type& endpoint, error_code& ec);

Effects: If is_open() is false, opens this socket by performing open(endpoint.protocol(), ec). If ec, returns with no further action. Connects this socket to the specified remote endpoint, as if by POSIX connect(native_handle(), endpoint.data(), endpoint.size()).

template<class CompletionToken>
  DEDUCED async_connect(const endpoint_type& endpoint, CompletionToken&& token);

Completion signature: void(error_code ec).

Effects: If is_open() is false, opens this socket by performing open(endpoint.protocol(), ec). If ec, the operation completes immediately with no further action. Initiates an asynchronous operation to connect this socket to the specified remote endpoint, as if by POSIX connect(native_handle(), endpoint.data(), endpoint.size()).

When an asynchronous connect operation on this socket is simultaneously outstanding with another asynchronous connect, read, or write operation on this socket, the behavior is undefined.

If a program performs a synchronous operation on this socket, other than close or cancel, while there is an outstanding asynchronous connect operation, the behavior is undefined.

void wait(wait_type w);
void wait(wait_type w, error_code& ec);

Effects: Waits for this socket to be ready to read, ready to write, or to have error conditions pending, as if by POSIX poll.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

template<class CompletionToken>
  DEDUCED async_wait(wait_type w, CompletionToken&& token);

Completion signature: void(error_code ec).

Effects: Initiates an asynchronous operation to wait for this socket to be ready to read, ready to write, or to have error conditions pending, as if by POSIX poll.

When there are multiple simultaneously outstanding asynchronous wait operations on this socket with the same wait_type value, all of these operations complete when this socket enters the corresponding ready state. The order of invocation of the completion handlers for these operations is unspecified.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

10.17.9. Class template basic_datagram_socket

[socket.dgram]

The class template basic_datagram_socket<Protocol> is used to send and receive discrete messages of fixed maximum length.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Protocol>
      class basic_datagram_socket : public basic_socket<Protocol>
      {
      public:
        // types:

        typedef implementation defined native_handle_type; // See native handles
        typedef Protocol protocol_type;
        typedef typename protocol_type::endpoint endpoint_type;

        // construct / copy / destroy:

        explicit basic_datagram_socket(io_service& ios);
        basic_datagram_socket(io_service& ios, const protocol_type& protocol);
        basic_datagram_socket(io_service& ios, const endpoint_type& endpoint);
        basic_datagram_socket(io_service& ios, 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>
          basic_datagram_socket(basic_datagram_socket<OtherProtocol>&& rhs);

        ~basic_datagram_socket();

        basic_datagram_socket& operator=(const basic_datagram_socket&) = delete;
        basic_datagram_socket& operator=(basic_datagram_socket&& rhs);
        template<class OtherProtocol>
          basic_datagram_socket& operator=(basic_datagram_socket<OtherProtocol>&& rhs);

        // basic_datagram_socket operations:

        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers);
        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers,
                         error_code& ec);

        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers,
                         socket_base::message_flags flags);
        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers,
                         socket_base::message_flags flags, error_code& ec);

        template<class MutableBufferSequence, class CompletionToken>
          DEDUCED async_receive(const MutableBufferSequence& buffers,
                             CompletionToken&& token);

        template<class MutableBufferSequence, class CompletionToken>
          DEDUCED async_receive(const MutableBufferSequence& buffers,
                             socket_base::message_flags flags,
                             CompletionToken&& token);

        template<class MutableBufferSequence>
          size_t receive_from(const MutableBufferSequence& buffers,
                              endpoint_type& sender);
        template<class MutableBufferSequence>
          size_t receive_from(const MutableBufferSequence& buffers,
                              endpoint_type& sender, error_code& ec);

        template<class MutableBufferSequence>
          size_t receive_from(const MutableBufferSequence& buffers,
                              endpoint_type& sender,
                              socket_base::message_flags flags);
        template<class MutableBufferSequence>
          size_t receive_from(const MutableBufferSequence& buffers,
                              endpoint_type& sender,
                              socket_base::message_flags flags,
                              error_code& ec);

        template<class MutableBufferSequence, class CompletionToken>
          DEDUCED async_receive_from(const MutableBufferSequence& buffers,
                                  endpoint_type& sender,
                                  CompletionToken&& token);

        template<class MutableBufferSequence, class CompletionToken>
          DEDUCED async_receive_from(const MutableBufferSequence& buffers,
                                  endpoint_type& sender,
                                  socket_base::message_flags flags,
                                  CompletionToken&& token);

        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers);
        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers, error_code& ec);

        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers,
                      socket_base::message_flags flags);
        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers,
                      socket_base::message_flags flags, error_code& ec);

        template<class ConstBufferSequence, class CompletionToken>
          DEDUCED async_send(const ConstBufferSequence& buffers,
                          CompletionToken&& token);

        template<class ConstBufferSequence, class CompletionToken>
          DEDUCED async_send(const ConstBufferSequence& buffers,
                          socket_base::message_flags flags,
                          CompletionToken&& token);

        template<class ConstBufferSequence>
          size_t send_to(const ConstBufferSequence& buffers,
                         const endpoint_type& destination);
        template<class ConstBufferSequence>
          size_t send_to(const ConstBufferSequence& buffers,
                         const endpoint_type& destination, error_code& ec);

        template<class ConstBufferSequence>
          size_t send_to(const ConstBufferSequence& buffers,
                         const endpoint_type& destination,
                         socket_base::message_flags flags);
        template<class ConstBufferSequence>
          size_t send_to(const ConstBufferSequence& buffers,
                         const endpoint_type& destination,
                         socket_base::message_flags flags, error_code& ec);

        template<class ConstBufferSequence, class CompletionToken>
          DEDUCED async_send_to(const ConstBufferSequence& buffers,
                             const endpoint_type& destination,
                             CompletionToken&& token);

        template<class ConstBufferSequence, class CompletionToken>
          DEDUCED async_send_to(const ConstBufferSequence& buffers,
                             const endpoint_type& destination,
                             socket_base::message_flags flags,
                             CompletionToken&& token);
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

For a given socket, a program may initiate asynchronous read or write operations such that there are multiple simultaneously outstanding asynchronous operations.

When there are multiple outstanding asynchronous read operations with zero flags, the buffers are filled in the order in which the operations were issued. The order of invocation of the handlers for these operations is unspecified. When there are multiple asynchronous read operations, where at least one has non-zero flags, the behavior is unspecified.

When there are multiple outstanding asynchronous write operations with zero flags, the buffers are transmitted in the order in which the operations were issued. The order of invocation of the handlers for these operations is unspecified. When there are multiple outstanding asynchronous write operations, where at least one has non-zero flags, the behavior is unspecified.

If a program performs a synchronous operation on this socket, other than close, cancel, shutdown, send, or send_to, while there is an outstanding asynchronous read operation, the behavior is undefined.

If a program performs a synchronous operation on this socket, other than close, cancel, shutdown, receive, or receive_from, while there is an outstanding asynchronous write operation, the behavior is undefined.

10.17.9.1. basic_datagram_socket constructors

[socket.dgram.cons]

explicit basic_datagram_socket(io_service& ios);

Effects: Initializes the base class with basic_socket<Protocol>(ios).

basic_datagram_socket(io_service& ios, const protocol_type& protocol);

Effects: Initializes the base class with basic_socket<Protocol>(ios, protocol).

basic_datagram_socket(io_service& ios, const endpoint_type& endpoint);

Effects: Initializes the base class with basic_socket<Protocol>(ios, endpoint).

basic_datagram_socket(io_service& ios, const protocol_type& protocol,
                      const native_handle_type& native_socket);

Effects: Initializes the base class with basic_socket<Protocol>(ios, protocol, native_socket).

basic_datagram_socket(basic_datagram_socket&& rhs);

Effects: Move constructs an object of class basic_datagram_socket<Protocol>, initializing the base class with basic_socket<Protocol>(std::move(rhs)).

template<class OtherProtocol>
  basic_datagram_socket(basic_datagram_socket<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

Effects: Move constructs an object of class basic_datagram_socket<Protocol>, initializing the base class with basic_socket<Protocol>(std::move(rhs)).

Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.9.2. basic_datagram_socket assignment

[socket.dgram.assign]

basic_datagram_socket& operator=(basic_datagram_socket&& rhs);

Effects: Equivalent to basic_socket<Protocol>::operator=(std::move(rhs)).

Returns: *this.

template<class OtherProtocol>
  basic_datagram_socket& operator=(basic_datagram_socket<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

Effects: Equivalent to basic_socket<Protocol>::operator=(std::move(rhs)).

Returns: *this.

Remarks: This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.9.3. basic_datagram_socket operations

[socket.dgram.op]

template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers);
template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers,
                 error_code& ec);

Returns: receive(buffers, socket_base::message_flags(), ec).

template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers,
                 socket_base::message_flags flags);
template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers,
                 socket_base::message_flags flags, error_code& ec);

Effects: Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, and reads data from this socket as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
recvmsg(native_handle(), &message, static_cast<int>(flags));

Returns: On success, the number of bytes received. Otherwise 0.

[Note: This operation may be used with connection-mode or connectionless-mode sockets, but it is normally used with connection-mode sockets because it does not permit the application to retrieve the source endpoint of received data. —end note]

template<class MutableBufferSequence, class CompletionToken>
  DEDUCED async_receive(const MutableBufferSequence& buffers,
                     CompletionToken&& token);

Returns: async_receive(buffers, socket_base::message_flags(), forward<CompletionToken>(token)).

template<class MutableBufferSequence, class CompletionToken>
  DEDUCED async_receive(const MutableBufferSequence& buffers,
                     socket_base::message_flags flags,
                     CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to read data from this socket. Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, then reads data as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
recvmsg(native_handle(), &message, static_cast<int>(flags));

If the operation completes successfully, n is the number of bytes received. Otherwise n is 0.

[Note: This operation may be used with connection-mode or connectionless-mode sockets, but it is normally used with connection-mode sockets because it does not permit the application to retrieve the source endpoint of received data. —end note]

Error conditions:
errc::invalid_argument — if socket_base::message_peek is set in flags.

template<class MutableBufferSequence>
  size_t receive_from(const MutableBufferSequence& buffers,
                      endpoint_type& sender);
template<class MutableBufferSequence>
  size_t receive_from(const MutableBufferSequence& buffers,
                      endpoint_type& sender, error_code& ec);

Returns: receive_from(buffers, endpoint, socket_base::message_flags(), ec).

template<class MutableBufferSequence>
  size_t receive_from(const MutableBufferSequence& buffers,
                      endpoint_type& sender,
                      socket_base::message_flags flags);
template<class MutableBufferSequence>
  size_t receive_from(const MutableBufferSequence& buffers,
                      endpoint_type& sender,
                      socket_base::message_flags flags,
                      error_code& ec);

Effects: Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, and reads data from this socket as if by POSIX:

msghdr message;
message.msg_name = sender.data();
message.msg_namelen = sender.capacity();
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
ssize_t result = recvmsg(native_handle(), &message, static_cast<int>(flags));
if (result >= 0)
  sender.resize(message.msg_namelen);

Returns: On success, the number of bytes received. Otherwise 0.

[Note: This operation may be used with connection-mode or connectionless-mode sockets, but it is normally used with connectionless-mode sockets because it permits the application to retrieve the source endpoint of received data. —end note]

template<class MutableBufferSequence, class CompletionToken>
  DEDUCED async_receive_from(const MutableBufferSequence& buffers,
                          endpoint_type& sender,
                          CompletionToken&& token);

Effects: Returns async_receive_from(buffers, sender, socket_base::message_flags(), forward<CompletionToken>(token)).

template<class MutableBufferSequence, class CompletionToken>
  DEDUCED async_receive_from(const MutableBufferSequence& buffers,
                          endpoint_type& sender,
                          socket_base::message_flags flags,
                          CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to read data from this socket. Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, then reads data as if by POSIX:

msghdr message;
message.msg_name = sender.data();
message.msg_namelen = sender.capacity();
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
ssize_t result = recvmsg(native_handle(), &message, static_cast<int>(flags));
if (result >= 0)
  sender.resize(message.msg_namelen);

If the operation completes successfully, n is the number of bytes received. Otherwise n is 0.

[Note: This operation may be used with connection-mode or connectionless-mode sockets, but it is normally used with connectionless-mode sockets because it permits the application to retrieve the source endpoint of received data. —end note]

Error conditions:
errc::invalid_argument — if socket_base::message_peek is set in flags.

template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers);
template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers, error_code& ec);

Returns: send(buffers, socket_base::message_flags(), ec).

template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers,
              socket_base::message_flags flags);
template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers,
              socket_base::message_flags flags, error_code& ec);

Effects: Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, and writes data to this socket as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
sendmsg(native_handle(), &message, static_cast<int>(flags));

Returns: On success, the number of bytes sent. Otherwise 0.

template<class ConstBufferSequence, class CompletionToken>
  DEDUCED async_send(const ConstBufferSequence& buffers, CompletionToken&& token);

Returns: async_send(buffers, socket_base::message_flags(), forward<CompletionToken>(token)).

template<class ConstBufferSequence, class CompletionToken>
  DEDUCED async_send(const ConstBufferSequence& buffers,
                  socket_base::message_flags flags,
                  CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to write data to this socket. Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, then writes data as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
sendmsg(native_handle(), &message, static_cast<int>(flags));

If the operation completes successfully, n is the number of bytes sent. Otherwise n is 0.

template<class ConstBufferSequence>
  size_t send_to(const ConstBufferSequence& buffers,
                 const endpoint_type& destination);
template<class ConstBufferSequence>
  size_t send_to(const ConstBufferSequence& buffers,
                 const endpoint_type& destination, error_code& ec);

Returns: send_to(buffers, destination, socket_base::message_flags(), ec).

template<class ConstBufferSequence>
  size_t send_to(const ConstBufferSequence& buffers,
                 const endpoint_type& destination,
                 socket_base::message_flags flags);
template<class ConstBufferSequence>
  size_t send_to(const ConstBufferSequence& buffers,
                 const endpoint_type& recipient,
                 socket_base::message_flags flags, error_code& ec);

Effects: Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, and writes data to this socket as if by POSIX:

msghdr message;
message.msg_name = sender.data();
message.msg_namelen = sender.size();
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
sendmsg(native_handle(), &message, static_cast<int>(flags));

Returns: On success, the number of bytes sent. Otherwise 0.

template<class ConstBufferSequence, class CompletionToken>
  DEDUCED async_send_to(const ConstBufferSequence& buffers,
                     const endpoint_type& recipient,
                     CompletionToken&& token);

Returns: async_send_to(buffers, recipient, socket_base::message_flags(), forward<CompletionToken>(token)).

template<class ConstBufferSequence, class CompletionToken>
  DEDUCED async_send_to(const ConstBufferSequence& buffers,
                     const endpoint_type& recipient,
                     socket_base::message_flags flags,
                     CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to write data to this socket. Constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, then writes data as if by POSIX:

msghdr message;
message.msg_name = sender.data();
message.msg_namelen = sender.size();
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
sendmsg(native_handle(), &message, static_cast<int>(flags));

If the operation completes successfully, n is the number of bytes sent. Otherwise n is 0.

10.17.10. Class template basic_stream_socket

[socket.stream]

The class template basic_stream_socket<Protocol> is used to exchange data with a peer over a sequenced, reliable, bidirectional, connection-mode byte stream.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Protocol>
      class basic_stream_socket : public basic_socket<Protocol>
      {
      public:
        // types:

        typedef implementation defined native_handle_type; // See native handles
        typedef Protocol protocol_type;
        typedef typename protocol_type::endpoint endpoint_type;

        // construct / copy / destroy:

        explicit basic_stream_socket(io_service& ios);
        basic_stream_socket(io_service& ios, const protocol_type& protocol);
        basic_stream_socket(io_service& ios, const endpoint_type& endpoint);
        basic_stream_socket(io_service& ios, 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>
          basic_stream_socket(basic_stream_socket<OtherProtocol>&& rhs);

        ~basic_stream_socket();

        basic_stream_socket& operator=(const basic_stream_socket&) = delete;
        basic_stream_socket& operator=(basic_stream_socket&& rhs);
        template<class OtherProtocol>
          basic_stream_socket& operator=(basic_stream_socket<OtherProtocol>&& rhs);

        // basic_stream_socket operations:

        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers);
        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers,
                         error_code& ec);

        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers,
                         socket_base::message_flags flags);
        template<class MutableBufferSequence>
          size_t receive(const MutableBufferSequence& buffers,
                         socket_base::message_flags flags, error_code& ec);

        template<class MutableBufferSequence, class CompletionToken>
          DEDUCED async_receive(const MutableBufferSequence& buffers,
                             CompletionToken&& token);

        template<class MutableBufferSequence, class CompletionToken>
          DEDUCED async_receive(const MutableBufferSequence& buffers,
                             socket_base::message_flags flags,
                             CompletionToken&& token);

        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers);
        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers, error_code& ec);

        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers,
                      socket_base::message_flags flags);
        template<class ConstBufferSequence>
          size_t send(const ConstBufferSequence& buffers,
                      socket_base::message_flags flags, error_code& ec);

        template<class ConstBufferSequence, class CompletionToken>
          DEDUCED async_send(const ConstBufferSequence& buffers,
                          CompletionToken&& token);

        template<class ConstBufferSequence, class CompletionToken>
          DEDUCED async_send(const ConstBufferSequence& buffers,
                          socket_base::message_flags flags,
                          CompletionToken&& token);

        template<class MutableBufferSequence>
          size_t read_some(const MutableBufferSequence& buffers);
        template<class MutableBufferSequence>
          size_t read_some(const MutableBufferSequence& buffers,
                           error_code& ec);

        template<class MutableBufferSequence, class CompletionToken>
          DEDUCED async_read_some(const MutableBufferSequence& buffers,
                               CompletionToken&& token);

        template<class ConstBufferSequence>
          size_t write_some(const ConstBufferSequence& buffers);
        template<class ConstBufferSequence>
          size_t write_some(const ConstBufferSequence& buffers,
                            error_code& ec);

        template<class ConstBufferSequence, class CompletionToken>
          DEDUCED async_write_some(const ConstBufferSequence& buffers,
                                CompletionToken&& token);
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Instances of the basic_stream_socket class template meet the requirements for synchronous read streams, synchronous write streams, asynchronous read streams, and asynchronous write streams.

For a given socket, a program may initiate asynchronous read or write operations such that there are multiple simultaneously outstanding asynchronous operations.

When there are multiple outstanding asynchronous read operations with zero flags, the buffers are filled in the order in which the operations were issued. The order of invocation of the handlers for these operations is unspecified. When there are multiple asynchronous read operations, where at least one has non-zero flags, the behavior is unspecified.

When there are multiple outstanding asynchronous write operations with zero flags, the buffers are transmitted in the order in which the operations were issued. The order of invocation of the handlers for these operations is unspecified. When there are multiple outstanding asynchronous write operations, where at least one has non-zero flags, the behavior is unspecified.

If a program performs a synchronous operation on this socket, other than close, cancel, shutdown, or send, while there is an outstanding asynchronous read operation, the behavior is undefined.

If a program performs a synchronous operation on this socket, other than close, cancel, shutdown, or receive, while there is an outstanding asynchronous write operation, the behavior is undefined.

10.17.10.1. basic_stream_socket constructors

[socket.stream.cons]

explicit basic_stream_socket(io_service& ios);

Effects: Initializes the base class with basic_socket<Protocol>(ios).

basic_stream_socket(io_service& ios, const protocol_type& protocol);

Effects: Initializes the base class with basic_socket<Protocol>(ios, protocol).

basic_stream_socket(io_service& ios, const endpoint_type& endpoint);

Effects: Initializes the base class with basic_socket<Protocol>(ios, endpoint).

basic_stream_socket(io_service& ios, const protocol_type& protocol,
                      const native_handle_type& native_socket);

Effects: Initializes the base class with basic_socket<Protocol>(ios, protocol, native_socket).

basic_stream_socket(basic_stream_socket&& rhs);

Effects: Move constructs an object of class basic_stream_socket<Protocol>, initializing the base class with basic_socket<Protocol>(std::move(rhs)).

template<class OtherProtocol>
  basic_stream_socket(basic_stream_socket<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

Effects: Move constructs an object of class basic_stream_socket<Protocol>, initializing the base class with basic_socket<Protocol>(std::move(rhs)).

Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.10.2. basic_stream_socket assignment

[socket.stream.assign]

basic_stream_socket& operator=(basic_stream_socket&& rhs);

Effects: Equivalent to basic_socket<Protocol>::operator=(std::move(rhs)).

Returns: *this.

template<class OtherProtocol>
  basic_stream_socket& operator=(basic_stream_socket<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

Effects: Equivalent to basic_socket<Protocol>::operator=(std::move(rhs)).

Returns: *this.

Remarks: This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.10.3. basic_stream_socket operations

[socket.stream.ops]

template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers);
template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers,
                 error_code& ec);

Returns: receive(buffers, socket_base::message_flags(), ec).

template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers,
                 socket_base::message_flags flags);
template<class MutableBufferSequence>
  size_t receive(const MutableBufferSequence& buffers,
                 socket_base::message_flags flags, error_code& ec);

Effects: If buffer_size(buffers) == 0, returns immediately with no error. Otherwise, constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, and reads data from this socket as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
recvmsg(native_handle(), &message, static_cast<int>(flags));

Returns: On success, the number of bytes received. Otherwise 0.

Error conditions:
stream_errc::eof — if there is no data to be received and the peer performed an orderly shutdown.

template<class MutableBufferSequence, class CompletionToken>
  DEDUCED async_receive(const MutableBufferSequence& buffers,
                     CompletionToken&& token);

Returns: async_receive(buffers, socket_base::message_flags(), forward<CompletionToken>(token)).

template<class MutableBufferSequence, class CompletionToken>
  DEDUCED async_receive(const MutableBufferSequence& buffers,
                     socket_base::message_flags flags,
                     CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to read data from this socket. If buffer_size(buffers) == 0, the asynchronous operation completes immediately with no error and n == 0. Otherwise, constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, then reads data as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
recvmsg(native_handle(), &message, static_cast<int>(flags));

If the operation completes successfully, n is the number of bytes received. Otherwise n is 0.

Error conditions:
errc::invalid_argument — if socket_base::message_peek is set in flags. — stream_errc::eof — if there is no data to be received and the peer performed an orderly shutdown.

template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers);
template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers, error_code& ec);

Returns: send(buffers, socket_base::message_flags(), ec).

template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers,
              socket_base::message_flags flags);
template<class ConstBufferSequence>
  size_t send(const ConstBufferSequence& buffers,
              socket_base::message_flags flags, error_code& ec);

Effects: If buffer_size(buffers) == 0, returns immediately with no error. Otherwise, constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, and writes data to this socket as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
sendmsg(native_handle(), &message, static_cast<int>(flags));

Returns: On success, the number of bytes sent. Otherwise 0.

template<class ConstBufferSequence, class CompletionToken>
  DEDUCED async_send(const ConstBufferSequence& buffers, CompletionToken&& token);

Returns: async_send(buffers, socket_base::message_flags(), forward<CompletionToken>(token)).

template<class ConstBufferSequence, class CompletionToken>
  DEDUCED async_send(const ConstBufferSequence& buffers,
                  socket_base::message_flags flags,
                  CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to write data to this socket. If buffer_size(buffers) == 0, the asynchronous operation completes immediately with no error and n == 0. Otherwise, constructs an array iov of POSIX type struct iovec and length iovlen, corresponding to buffers, then writes data as if by POSIX:

msghdr message;
message.msg_name = nullptr;
message.msg_namelen = 0;
message.msg_iov = iov;
message.msg_iovlen = iovlen;
message.msg_control = nullptr;
message.msg_controllen = 0;
message.msg_flags = 0;
sendmsg(native_handle(), &message, static_cast<int>(flags));

If the operation completes successfully, n is the number of bytes sent. Otherwise n is 0.

template<class MutableBufferSequence>
  size_t read_some(const MutableBufferSequence& buffers);
template<class MutableBufferSequence>
  size_t read_some(const MutableBufferSequence& buffers,
                   error_code& ec);

Returns: receive(buffers, ec).

template<class MutableBufferSequence, class CompletionToken>
  DEDUCED async_read_some(const MutableBufferSequence& buffers,
                       CompletionToken&& token);

Returns: async_receive(buffers, forward<CompletionToken>(token)).

template<class ConstBufferSequence>
  size_t write_some(const ConstBufferSequence& buffers);
template<class ConstBufferSequence>
  size_t write_some(const ConstBufferSequence& buffers,
                    error_code& ec);

Returns: send(buffers, ec).

template<class ConstBufferSequence, class CompletionToken>
  DEDUCED async_write_some(const ConstBufferSequence& buffers,
                        CompletionToken&& token);

Returns: async_send(buffers, forward<CompletionToken>(token)).

10.17.11. Class template basic_socket_acceptor

[socket.acceptor]

An object of class template basic_socket_acceptor<AcceptableProtocol> 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 {
    inline namespace network_v1 {

      template<class AcceptableProtocol>
      class basic_socket_acceptor : public socket_base
      {
      public:
        // types:

        typedef io_service::executor_type executor_type;
        typedef implementation defined native_handle_type; // See native handles
        typedef AcceptableProtocol protocol_type;
        typedef typename protocol_type::endpoint endpoint_type;
        typedef typename protocol_type::socket socket_type;

        // construct / copy / destroy:

        explicit basic_socket_acceptor(io_service& ios);
        basic_socket_acceptor(io_service& ios, const protocol_type& protocol);
        basic_socket_acceptor(io_service& ios, const endpoint_type& endpoint,
                              bool reuse_addr = true);
        basic_socket_acceptor(io_service& ios, const protocol_type& protocol,
                              const native_handle_type& native_acceptor);
        basic_socket_acceptor(const basic_socket_acceptor&) = delete;
        basic_socket_acceptor(basic_socket_acceptor&& rhs);
        template<class OtherProtocol>
          basic_socket_acceptor(basic_socket_acceptor<OtherProtocol>&& rhs);

        ~basic_socket_acceptor();

        basic_socket_acceptor& operator=(const basic_socket_acceptor&) = delete;
        basic_socket_acceptor& operator=(basic_socket_acceptor&& rhs);
        template<class OtherProtocol>
          basic_socket_acceptor& operator=(basic_socket_acceptor<OtherProtocol>&& rhs);

        // basic_socket_acceptor operations:

        executor_type get_executor() noexcept;

        native_handle_type native_handle(); // See native handles

        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); // See native handles
        void assign(const protocol_type& protocol,
                    const native_handle_type& native_acceptor,
                    error_code& ec); // See native handles

        bool is_open() const;

        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_service& ios);
        socket_type accept(io_service& ios, error_code& ec);

        template<class CompletionToken>
          DEDUCED async_accept(CompletionToken&& token);
        template<class CompletionToken>
          DEDUCED async_accept(io_service& ios, CompletionToken&& token);

        socket_type accept(endpoint_type& endpoint);
        socket_type accept(endpoint_type& endpoint, error_code& ec);
        socket_type accept(io_service& ios, endpoint_type& endpoint);
        socket_type accept(io_service& ios, endpoint_type& endpoint,
                           error_code& ec);

        template<class CompletionToken>
          DEDUCED async_accept(endpoint_type& endpoint,
                               CompletionToken&& token);
        template<class CompletionToken>
          DEDUCED async_accept(io_service& ios, 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);

      private:
        protocol_type protocol_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

For a given acceptor, a program may initiate asynchronous accept or wait operations such that there are multiple simultaneously outstanding asynchronous operations.

When there are multiple outstanding asynchronous accept operations the order in which the incoming connections are dequeued, and the order of invocation of the completion handlers for these operations, is unspecified.

10.17.11.1. basic_socket_acceptor constructors

[socket.acceptor.cons]

explicit basic_socket_acceptor(io_service& ios);

Postconditions:
get_executor() == ios.get_executor().
is_open() == false.

basic_socket_acceptor(io_service& ios, const protocol_type& protocol);

Effects: Opens this acceptor as if by calling open(protocol).

Postconditions:
get_executor() == ios.get_executor().
is_open() == true.
non_blocking() == false.
enable_connection_aborted() == false.
protocol_ == protocol.

basic_socket_acceptor(io_service& ios, const endpoint_type& endpoint,
                      bool reuse_addr = true);

Effects: Opens and binds this acceptor as if by calling:

open(endpoint.protocol());
if (reuse_addr)
  set_option(reuse_address(true));
bind(endpoint);
listen();

Postconditions:
get_executor() == ios.get_executor().
is_open() == true.
non_blocking() == false.
enable_connection_aborted() == false.
protocol_ == endpoint.protocol().

basic_socket_acceptor(io_service& ios, const protocol_type& protocol,
                      const native_handle_type& native_acceptor);

Requires: native_acceptor is a native handle to an open acceptor.

Effects: Assigns the existing native acceptor into this acceptor as if by calling assign(protocol, native_acceptor).

Postconditions:
get_executor() == ios.get_executor().
is_open() == true.
non_blocking() == false.
enable_connection_aborted() == false.
protocol_ == protocol.

basic_socket_acceptor(basic_socket_acceptor&& rhs);

Effects: Move constructs an object of class basic_socket_acceptor<AcceptableProtocol> that refers to the state originally represented by rhs.

Postconditions:
get_executor() == rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the constructor invocation.
non_blocking() returns the same value as rhs.non_blocking() prior to the constructor invocation.
enable_connection_aborted() returns the same value as rhs.enable_connection_aborted() prior to the constructor invocation.
protocol_ is equal to the prior value of rhs.protocol_.
rhs.is_open() == false.

template<class OtherProtocol>
  basic_socket_acceptor(basic_socket_acceptor<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

Effects: Move constructs an object of class basic_socket_acceptor<AcceptableProtocol> that refers to the state originally represented by rhs.

Postconditions:
get_executor() == rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the constructor invocation.
non_blocking() returns the same value as rhs.non_blocking() prior to the constructor invocation.
enable_connection_aborted() returns the same value as rhs.enable_connection_aborted() prior to the constructor invocation.
native_handle() returns the prior value of rhs.native_handle().
protocol_ is the result of converting the prior value of rhs.protocol_.
rhs.is_open() == false.

Remarks: This constructor shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.11.2. basic_socket_acceptor destructor

[socket.acceptor.dtor]

~basic_socket_acceptor();

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()). Completion handlers for canceled operations are passed an error code ec such that ec == errc::operation_canceled yields true.

10.17.11.3. basic_socket_acceptor assignment

[socket.acceptor.assign]

basic_socket_acceptor& operator=(basic_socket_acceptor&& rhs);

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.

Postconditions:
get_executor() == rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the assignment.
non_blocking() returns the same value as rhs.non_blocking() prior to the assignment.
enable_connection_aborted() returns the same value as rhs.enable_connection_aborted() prior to the assignment.
native_handle() returns the same value as rhs.native_handle() prior to the assignment.
protocol_ is the same value as rhs.protocol_ prior to the assignment.
rhs.is_open() == false.

Returns: *this.

template<class OtherProtocol>
  basic_socket_acceptor& operator=(basic_socket_acceptor<OtherProtocol>&& rhs);

Requires: OtherProtocol is implicitly convertible to Protocol.

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.

Postconditions:
get_executor() == rhs.get_executor().
is_open() returns the same value as rhs.is_open() prior to the assignment.
non_blocking() returns the same value as rhs.non_blocking() prior to the assignment.
enable_connection_aborted() returns the same value as rhs.enable_connection_aborted() prior to the assignment.
native_handle() returns the same value as rhs.native_handle() prior to the assignment.
protocol_ is the result of converting the value of rhs.protocol_ prior to the assignment.
rhs.is_open() == false.

Returns: *this.

Remarks: This assignment operator shall not participate in overload resolution unless OtherProtocol is implicitly convertible to Protocol.

10.17.11.4. basic_socket_acceptor operations

[socket.acceptor.ops]

executor_type get_executor() noexcept;

Returns: The associated executor.

native_handle_type native_handle();

Returns: The native representation of this acceptor.

void open(const protocol_type& protocol);
void open(const protocol_type& protocol, error_code& ec);

Effects: Establishes the postcondition, as if by POSIX socket(protocol.family(), protocol.type(), protocol.protocol()).

Postconditions:
is_open() == true.
non_blocking() == false.
enable_connection_aborted() == false.
protocol_ == protocol.

Error conditions:
socket_errc::already_open — if is_open() is true.

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);

Requires: native_acceptor is a native handle to an open acceptor.

Effects: Assigns the native acceptor handle to this acceptor object.

Postconditions:
is_open() == true.
non_blocking() == false.
enable_connection_aborted() == false.
protocol_ == protocol.

Error conditions:
socket_errc::already_open — if is_open() is true.

bool is_open() const;

Returns: A bool indicating whether this acceptor was opened by a previous call to open or assign.

void close();
void close(error_code& ec);

Effects: If is_open() is true, cancels all outstanding asynchronous operations associated with this acceptor, and establishes the postcondition as if by POSIX close(native_handle()). Completion handlers for canceled asynchronous operations are passed an error code ec such that ec == errc::operation_canceled yields true.

Postconditions: is_open() == false.

void cancel();
void cancel(error_code& ec);

Effects: Cancels all outstanding asynchronous operations associated with this acceptor. Completion handlers for canceled asynchronous operations are passed an error code ec such that ec == errc::operation_canceled yields true.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.
errc::operation_not_supported — Current conditions do not permit cancelation. The conditions under which cancelation of asynchronous operations is permitted are implementation-defined.

template<class SettableSocketOption>
  void set_option(const SettableSocketOption& option);
template<class SettableSocketOption>
  void set_option(const SettableSocketOption& option, error_code& ec);

Effects: Sets an option on this acceptor, as if by POSIX setsockopt(native_handle(), option.level(protocol_), option.name(protocol_), option.data(protocol_), option.size(protocol_)).

template<class GettableSocketOption>
  void get_option(GettableSocketOption& option);
template<class GettableSocketOption>
  void get_option(GettableSocketOption& option, error_code& ec);

Effects: Gets an option from this acceptor, as if by POSIX:

socklen_t option_len = option.size(protocol_);
int result = getsockopt(native_handle(), option.level(protocol_),
                        option.name(protocol_), option.data(protocol_),
                        &option_len);
if (result == 0)
  option.resize(option_len);

template<class IoControlCommand>
  void io_control(IoControlCommand& command);
template<class IoControlCommand>
  void io_control(IoControlCommand& command, error_code& ec);

Effects: Executes an I/O control command on this acceptor, as if by POSIX ioctl(native_handle(), command.name(), command.data()).

void non_blocking(bool mode);
void non_blocking(bool mode, error_code& ec);

Effects: Sets the non-blocking mode of this acceptor. If mode is true, subsequent synchronous operations may fail with error condition errc::operation_would_block if they are unable to perform the requested operation immediately. If mode is false, subsequent synchronous operations shall block until complete.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

[Note: The non-blocking mode has no effect on the behavior of asynchronous operations. —end note]

bool non_blocking() const;

Returns: The non-blocking mode of this acceptor.

void native_non_blocking(bool mode);
void native_non_blocking(bool mode, error_code& ec);

Effects: Sets the non-blocking mode of the underlying native acceptor, as if by POSIX:

int flags = fcntl(native_handle(), F_GETFL, 0);
if (flags >= 0)
{
  if (mode)
    flags |= O_NONBLOCK;
  else
    flags &= ~O_NONBLOCK;
  fcntl(native_handle(), F_SETFL, flags);
}

The native non-blocking mode has no effect on the behavior of the synchronous or asynchronous operations specified in this clause.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.
errc::invalid_argument — if mode == false and non_blocking() == true. [Note: As the combination does not make sense. —end note]

bool native_non_blocking() const;

Returns: The non-blocking mode of the underlying native acceptor.

Remarks: Implementations are permitted and encouraged to cache the native non-blocking mode that was applied through a prior call to native_non_blocking. Implementations may return an incorrect value if a program sets the non-blocking mode directly on the acceptor, by calling an operating system-specific function on the result of native_handle().

void bind(const endpoint_type& endpoint);
void bind(const endpoint_type& endpoint, error_code& ec);

Effects: Binds this acceptor to the specified local endpoint, as if by POSIX bind(native_handle(), endpoint.data(), endpoint.size()).

void listen(int backlog = socket_base::max_connections);
void listen(int backlog, error_code& ec);

Effects: Marks this acceptor as ready to accept connections, as if by POSIX listen(native_handle(), backlog).

endpoint_type local_endpoint() const;
endpoint_type local_endpoint(error_code& ec) const;

Effects: Determines the locally-bound endpoint associated with this acceptor, as if by POSIX:

endpoint_type endpoint;
socklen_t endpoint_len = endpoint.capacity();
int result == getsockname(native_handle(), endpoint.data(), &endpoint_len);
if (result == 0)
  endpoint.resize(endpoint_len);

Returns: On success, endpoint. Otherwise endpoint_type().

void enable_connection_aborted(bool mode);

Effects: If mode is true, subsequent synchronous or asynchronous accept operations on this acceptor are permitted to fail with error condition errc::connection_aborted. If mode is false, subsequent accept operations will not fail with errc::connection_aborted. [Note: If mode is false, the implementation will restart the call to POSIX accept if it fails with ECONNABORTED. —end note]

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

bool enable_connection_aborted() const;

Returns: Whether accept operations on this acceptor are permitted to fail with errc::connection_aborted.

socket_type accept();
socket_type accept(error_code& ec);

Returns: accept(get_executor().context(), ec).

socket_type accept(io_service& ios);
socket_type accept(io_service& ios, error_code& ec);

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);

Returns: If h is an open native socket, socket_type(ios, s); otherwise socket_type(ios).

template<class CompletionToken>
  DEDUCED async_accept(CompletionToken&& token);

Returns: async_accept(get_executor().context(), forward<CompletionToken>(token)).

template<class CompletionToken>
  DEDUCED async_accept(io_service& ios, CompletionToken&& token);

Completion signature: void(error_code ec, socket_type s).

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(ios, h). Otherwise, s is socket_type(ios)`.

socket_type accept(endpoint_type& endpoint);
socket_type accept(endpoint_type& endpoint, error_code& ec);

Returns: accept(get_executor().context(), endpoint, ec).

socket_type accept(io_service& ios, endpoint_type& endpoint);
socket_type accept(io_service& ios, endpoint_type& endpoint,
                   error_code& ec);

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);

Returns: If h is an open native socket, socket_type(ios, s); otherwise socket_type(ios).

template<class CompletionToken>
  DEDUCED async_accept(endpoint_type& endpoint,
                       CompletionToken&& token);

Returns: async_accept(get_executor().context(), endpoint, forward<CompletionToken>(token)).

template<class CompletionToken>
  DEDUCED async_accept(io_service& ios, endpoint_type& endpoint,
                       CompletionToken&& token);

Completion signature: void(error_code ec, socket_type s).

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(ios, h). Otherwise, s is socket_type(ios)`.

void wait(wait_type w);
void wait(wait_type w, error_code& ec);

Effects: Waits for the acceptor to have a queued incoming connection, or to have error conditions pending, as if by POSIX poll.

template<class CompletionToken>
  DEDUCED async_wait(wait_type w, CompletionToken&& token);

Completion signature: void(error_code ec).

Effects: Initiates an asynchronous operation to wait for the acceptor to have a queued incoming connection, or to have error conditions pending, as if by POSIX poll.

When multiple asynchronous wait operations are initiated with the same wait_type value, all operations shall complete when the acceptor enters the corresponding ready state. The order of invocation of the completions handlers for these operations is unspecified.

Error conditions:
errc::bad_file_descriptor — if is_open() is false.

10.18. Socket iostreams

[socket.iostreams]

10.18.1. Class template basic_socket_streambuf

[socket.streambuf]

The class basic_socket_streambuf<Protocol, Clock, WaitTraits> 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]

[Note: This class is intended for sending and receiving bytes, not characters. The conversion from characters to bytes, and vice versa, must occur elsewhere. —end note]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Protocol, class Clock, class WaitTraits>
      class basic_socket_streambuf : public basic_streambuf<char>
      {
      public:
        // types:

        typedef Protocol protocol_type;
        typedef typename protocol_type::endpoint endpoint_type;
        typedef Clock clock_type;
        typedef typename clock_type::time_point time_point;
        typedef typename clock_type::duration duration;
        typedef WaitTraits traits_type;

        // construct / copy / destroy:

        basic_socket_streambuf();
        explicit basic_socket_streambuf(basic_stream_socket<protocol_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);

        // members:

        basic_socket_streambuf* connect(const endpoint_type& e);
        template<class... Args> basic_socket_streambuf* connect(Args&&... );

        basic_socket_streambuf<protocol_type>* close();

        basic_socket<protocol_type>& socket();
        error_code error() const;

        time_point expiry() const;
        void expires_at(const time_point& t);
        void expires_after(const duration& d);

      protected:
        // overridden virtual functions:
        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> socket_; // exposition only
        error_code ec_; // exposition only
        time_point expiry_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.18.1.1. basic_socket_streambuf constructors

[socket.streambuf.cons]

basic_socket_streambuf();

Effects: Initializes socket_ with ios, where ios is an unspecified object of class io_service.

Postconditions: expiry() == clock_type::max().

explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s);

Effects: Initializes socket_ with std::move(s).

Postconditions: expiry() == clock_type::max().

basic_socket_streambuf(basic_socket_streambuf&& rhs);

Effects: Move constructs from the rvalue rhs. It is implementation-defined whether the sequence pointers in *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.

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.
is_open() == rhs_p.is_open()
rhs_a.is_open() == false
expiry() == rhs_p.expiry()
rhs_a.expiry() == clock_type::max()
gptr() - eback() == rhs_p.gptr() - rhs_p.eback()
egptr() - eback() == rhs_p.egptr() - rhs_p.eback()
ptr() - pbase() == rhs_p.pptr() - rhs_p.pbase()
pptr() - pbase() == rhs_p.epptr() - rhs_p.pbase()
if (eback()) eback() != rhs_a.eback()
if (gptr()) gptr() != rhs_a.gptr()
if (egptr()) egptr() != rhs_a.egptr()
if (pbase()) pbase() != rhs_a.pbase()
if (pptr()) pptr() != rhs_a.pptr()
if (epptr()) epptr() != rhs_a.epptr()

virtual ~basic_socket_streambuf();

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> destructor. —end note]

basic_socket_streambuf& operator=(basic_socket_streambuf&& rhs);

Effects: Calls this->close() then move assigns from rhs. After the move assignment *this has the observable state it would have had if it had been move constructed from rhs.

Returns: *this.

10.18.1.2. basic_socket_streambuf members

[socket.streambuf.members]

basic_socket_streambuf<protocol_type>* connect(const endpoint_type& e);

Effects: Resets the streambuf get and put areas, 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.

Returns: if !ec_, this; otherwise, a null pointer.

template<class... Args>
  basic_socket_streambuf* connect(Args&&... args);

Effects: Resets the streambuf get and put areas and closes the socket as if by calling socket_.close(ec_). Obtains an endpoint sequence endpoints by performing protocol_type::resolver(ios).resolve(forward<Args>(args)...), where ios is an unspecified object of class io_service. 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.

Returns: if !ec_, this; otherwise, a null pointer.

Remarks: This function shall not participate in overload resolution unless Protocol meets the requirements for an internet protocol.

basic_socket_streambuf* close();

Effects: If a put area exists, calls overflow(traits_type::eof()) to flush characters. Calls:

basic_socket<protocol_type>::close(ec_);

then resets the get and put areas. If the call to overflow fails, or if !ec_, then close fails.

Returns: this on success, a null pointer otherwise.

basic_socket<protocol_type>& socket();

Returns: socket_.

error_code error() const;

Returns: ec_.

time_point expiry() const;

Returns: expiry_.

void expires_at(const time_point& t);

Postconditions: expiry_ == t.

void expires_after(const duration& d);

Effects: Equivalent to expires_at(clock_type::now() + d).

10.18.1.3. basic_socket_streambuf overridden virtual functions

[socket.streambuf.virtual]

virtual int_type underflow() override;

Effects: Behaves according to the description of basic_streambuf<char>::underflow(), with the specialization that a sequence of characters is read from the input sequence as if by POSIX recvmsg, and 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.

Effects: Returns traits_type::eof() to indicate failure. Otherwise returns traits_type::to_int_type(*gptr()).

virtual int_type pbackfail(int_type c = traits_type::eof()) override;

Effects: Puts back the character designated by c to the input sequence, if possible, in one of three ways:

— If traits_type::eq_int_type(c,traits_type::eof()) returns false, and if the function makes a putback position available, and if traits_type::eq(traits_type::to_char_type(c),gptr()[-1]) returns true, decrements the next pointer for the input sequence, gptr().
Returns: c.

— If traits_type::eq_int_type(c,traits_type::eof()) returns false, and if the function makes a putback position available, and if the function is permitted to assign to the putback position, decrements the next pointer for the input sequence, and stores c there.
Returns: c.

— If traits_type::eq_int_type(c,traits_type::eof()) returns true, and if either the input sequence has a putback position available or the function makes a putback position available, decrements the next pointer for the input sequence, gptr().
Returns: traits_type::not_eof(c).

Returns: traits_type::eof() to indicate failure.

Notes: The function does not put back a character directly to the input sequence. If the function can succeed in more than one of these ways, it is unspecified which way is chosen. The function can alter the number of putback positions available as a result of any call.

virtual int_type overflow(int_type c = traits_type::eof()) override;

Effects: Behaves according to the description of basic_streambuf<char>::overflow(c), except that the behavior of "consuming characters" is performed by output of the characters to the socket as if by one or more calls to POSIX sendmsg, and 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.

Returns: traits_type::not_eof(c) to indicate success, and traits_type::eof() to indicate failure.

virtual int sync() override;

Effects: If a put area exists, calls overflow(traits_type::eof()) to flush characters.

virtual streambuf* setbuf(char_type* s, streamsize n) override;

Effects: If setbuf(nullptr, 0) is called on a stream before any I/O has occurred on that stream, the stream becomes unbuffered. Otherwise the results are unspecified. "Unbuffered" means that pbase() and pptr() always return null and output to the socket should appear as soon as possible.

10.18.2. Class template basic_socket_iostream

[socket.iostream]

The class template basic_socket_iostream<Protocol, Clock, WaitTraits> supports reading and writing on sockets. It uses a basic_socket_streambuf<Protocol, Clock, WaitTraits> object to control the associated sequences.

[Note: This class is intended for sending and receiving bytes, not characters. The conversion from characters to bytes, and vice versa, must occur elsewhere. —end note]

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Protocol, class Clock, class WaitTraits>
      class basic_socket_iostream : public basic_iostream<char>
      {
      public:
        // types:

        typedef Protocol protocol_type;
        typedef typename protocol_type::endpoint endpoint_type;
        typedef Clock clock_type;
        typedef typename clock_type::time_point time_point;
        typedef typename clock_type::duration duration;
        typedef WaitTraits traits_type;

        // construct / copy / destroy:

        basic_socket_iostream();
        explicit basic_socket_streambuf(basic_stream_socket<protocol_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);

        // members:

        template<class... Args> void connect(Args&&... args);

        void close();

        basic_socket_streambuf<protocol_type, clock_type, traits_type>* rdbuf() const;

        basic_socket<protocol_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, traits_type> sb_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.18.2.1. basic_socket_iostream constructors

[socket.iostream.cons]

basic_socket_iostream();

Effects: Initializes the base class as basic_iostream<char>(&sb_), sb_ as basic_socket_streambuf<Protocol, Clock, WaitTraits>(), and performs setf(std::ios_base::unitbuf).

explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s);

Effects: Initializes the base class as basic_iostream<char>(&sb_), sb_ as basic_socket_streambuf<Protocol, Clock, WaitTraits>(std::move(s)), and performs setf(std::ios_base::unitbuf).

basic_socket_iostream(basic_socket_iostream&& rhs);

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.

template<class... Args>
  explicit basic_socket_iostream(Args&&... args);

Effects: Initializes the base class as basic_iostream<char>(&sb_), initializes sb_ as basic_socket_streambuf<Protocol, Clock, WaitTraits>(), and performs setf(std::ios_base::unitbuf). Then calls rdbuf()->connect(forward<Args>(args)...). If that function returns a null pointer, calls setstate(failbit).

basic_socket_iostream& operator=(basic_socket_iostream&& rhs);

Effects: Move assigns the base and members of *this from the base and corresponding members of rhs.

Returns: *this.

10.18.2.2. basic_socket_iostream members

[socket.iostream.members]

template<class... Args>
  void connect(Args&&... args);

Effects: Calls rdbuf()->connect(forward<Args>(args)...). If that function returns a null pointer, calls setstate(failbit) (which may throw ios_base::failure).

void close();

Effects: Calls rdbuf()->close(). If that function returns a null pointer, calls setstate(failbit) (which may throw ios_base::failure).

basic_socket_streambuf<protocol_type, clock_type, traits_type>* rdbuf() const;

Returns: const_cast<basic_socket_streambuf<protocol_type, clock_type, traits_type>*>(std::addressof(sb_)).

basic_socket<protocol_type>& socket();

Returns: rdbuf()->socket().

error_code error() const;

Returns: rdbuf()->error().

time_point expiry() const;

Returns: rdbuf()->expiry().

void expires_at(const time_point& t);

Effects: Equivalent to rdbuf()->expires_at(t).

void expires_after(const duration& d);

Effects: Equivalent to rdbuf()->expires_after(d).

10.19. Socket algorithms

[socket.algo]

10.19.1. Synchronous connect operations

[socket.algo.connect]

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

Returns: connect(s, endpoints, [](auto, auto){ return true; }, ec).

template<class Protocol, class EndpointSequence, class ConnectCondition>
  typename Protocol::endpoint connect(basic_socket<Protocol>& s,
                                      const EndpointSequence& endpoints,
                                      ConnectCondition c);
template<class Protocol, class InputIterator, class ConnectCondition>
  typename Protocol::endpoint connect(basic_socket<Protocol>& s,
                                      const EndpointSequence& endpoints,
                                      ConnectCondition c, error_code& ec);

Effects: If s.is_open() is true, performs s.close(ec). Performs ec.clear(). Returns the first element ep in the sequence endpoints for which c(ec, ep) yields true and, if so, for which the synchronous operation s.connect(ep, ec) succeeds. If no such element is found, ec contains the error code produced by the last unsuccessful connect operation and the function returns typename Protocol::endpoint().

Error conditions:
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 InputIterator>
  InputIterator connect(basic_socket<Protocol>& s,
                        InputIterator first, InputIterator last);
template<class Protocol, class InputIterator>
  InputIterator connect(basic_socket<Protocol>& s,
                        InputIterator first, InputIterator last,
                        error_code& ec);

Returns: connect(s, first, last, [](auto, auto){ return true; }, ec).

template<class Protocol, class InputIterator, class ConnectCondition>
  InputIterator connect(basic_socket<Protocol>& s,
                        InputIterator first, InputIterator last,
                        ConnectCondition c);
template<class Protocol, class InputIterator, class ConnectCondition>
  InputIterator connect(basic_socket<Protocol>& s,
                        InputIterator first, InputIterator last,
                        ConnectCondition c, error_code& ec);

Requires: ConnectCondition is a function object type meeting CopyConstructible requirements (C++ Std [copyconstructible]).

Effects: If s.is_open() is true, performs s.close(ec). Performs ec.clear(). Returns the first iterator i in the range [first,last) for which c(ec, *i) yields true and, if so, for which the synchronous operation s.connect(*i, ec) succeeds. If no such iterator is found, ec contains the error code produced by the last unsuccessful connect operation and the function returns last.

Error conditions:
socket_errc::not_found — if first == last or if the function object c returned false for all iterators in the range.

10.19.2. Asynchronous connect operations

[socket.algo.async.connect]

template<class Protocol, class EndpointSequence, class CompletionToken>
  DEDUCED async_connect(basic_socket<Protocol>& s,
                        const EndpointSequence& endpoints,
                        CompletionToken&& token);

Returns: async_connect(s, endpoints, [](auto, auto){ return true; }, forward<CompletionToken>(token)).

template<class Protocol, class InputIterator,
  class ConnectCondition, class CompletionToken>
    DEDUCED async_connect(basic_socket<Protocol>& s,
                          const EndpointSequence& endpoints,
                          ConnectCondition c,
                          CompletionToken&& token);

Completion signature: void(error_code ec, typename Protocol::endpoint ep).

Requires: ConnectCondition is a function object type meeting CopyConstructible requirements (C++ Std [copyconstructible]).

Effects: If s.is_open() is true, performs s.close(ec). Define previous_ec as an object of type error_code initialized such that !previous_ec yields true. Initiates an asynchronous operation to determine the first element ep in the sequence endpoints for which c(previous_ec, ep) yields true and, if so, for which the asynchronous operation s.async_connect(ep, unspecified) succeeds. If an asynchronous operation s.async_connect(ep, unspecified) fails, previous_ec is updated with the result of the operation. If no such element is found, ec contains previous_ec and ep is typename Protocol::endpoint(). [Note: The underlying async_connect operations are performed sequentially. —end note]

Error conditions:
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 InputIterator, class CompletionToken>
  DEDUCED async_connect(basic_socket<Protocol>& s,
                        InputIterator first, InputIterator last,
                        CompletionToken&& token);

Returns: async_connect(s, first, last, [](auto, auto){ return true; }, forward<CompletionToken>(token)).

template<class Protocol, class InputIterator,
  class ConnectCondition, class CompletionToken>
    DEDUCED async_connect(basic_socket<Protocol>& s,
                          InputIterator first, InputIterator last,
                          ConnectCondition c,
                          CompletionToken&& token);

Completion signature: void(error_code ec, InputIterator i).

Requires: ConnectCondition is a function object type meeting CopyConstructible requirements (C++ Std [copyconstructible]).

Effects: If s.is_open() is true, performs s.close(ec). Define previous_ec as an object of type error_code initialized such that !previous_ec yields true. Initiates an asynchronous operation to determine the first iterator i in the range [first,last) for which c(previous_ec, *i) yields true and, if so, for which the asynchronous operation s.async_connect(*i, unspecified) succeeds. If an asynchronous operation s.async_connect(*i, unspecified) fails, previous_ec is updated with the result of the operation. If no such iterator is found, ec contains previous_ec and i contains last. [Note: The underlying async_connect operations are performed sequentially. —end note]

Error conditions:
socket_errc::not_found — if first == last or if the function object c returned false for all iterators in the range.

10.20. Internet protocol

[internet]

10.20.1. Header <experimental/internet> synopsis

[internet.synop]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        enum class resolver_errc {
          host_not_found = implementation defined, // EAI_NONAME
          host_not_found_try_again = implementation defined, // EAI_AGAIN
          service_not_found = implementation defined // EAI_SERVICE
        };

        const error_category& resolver_category() noexcept;

        error_code make_error_code(resolver_errc e) noexcept;
        error_condition make_error_condition(resolver_errc e) noexcept;

        typedef uint16_least_t port_type;
        typedef uint32_least_t address_v4_uint_type;
        typedef uint32_least_t scope_id_type;

        struct v4_mapped_t {};
        constexpr v4_mapped_t v4_mapped;

        class address;
        class address_v4;
        class address_v6;

        class bad_address_cast;

        // address comparisons:
        bool operator==(const address&, const address&) noexcept;
        bool operator!=(const address&, const address&) noexcept;
        bool operator< (const address&, const address&) noexcept;
        bool operator> (const address&, const address&) noexcept;
        bool operator<=(const address&, const address&) noexcept;
        bool operator>=(const address&, const address&) noexcept;

        // address_v4 comparisons:
        bool operator==(const address_v4&, const address_v4&) noexcept;
        bool operator!=(const address_v4&, const address_v4&) noexcept;
        bool operator< (const address_v4&, const address_v4&) noexcept;
        bool operator> (const address_v4&, const address_v4&) noexcept;
        bool operator<=(const address_v4&, const address_v4&) noexcept;
        bool operator>=(const address_v4&, const address_v4&) noexcept;

        // address_v6 comparisons:
        bool operator==(const address_v6&, const address_v6&) noexcept;
        bool operator!=(const address_v6&, const address_v6&) noexcept;
        bool operator< (const address_v6&, const address_v6&) noexcept;
        bool operator> (const address_v6&, const address_v6&) noexcept;
        bool operator<=(const address_v6&, const address_v6&) noexcept;
        bool operator>=(const address_v6&, const address_v6&) noexcept;

        // address creation:
        address make_address(const char*);
        address make_address(const char*, error_code&) noexcept;
        address make_address(string_view);
        address make_address(string_view, error_code&) noexcept;

        // address_v4 creation:
        constexpr address_v4 make_address_v4(const address_v4::bytes_type&);
        constexpr address_v4 make_address_v4(address_v4_uint_type);
        constexpr address_v4 make_address_v4(v4_mapped_t, const address_v6&);
        address_v4 make_address_v4(const char*);
        address_v4 make_address_v4(const char*, error_code&) noexcept;
        address_v4 make_address_v4(string_view);
        address_v4 make_address_v4(string_view, error_code&) noexcept;

        // address_v6 creation:
        constexpr address_v6 make_address_v6(const address_v6::bytes_type&,
                                             scope_id_type = 0);
        constexpr address_v6 make_address_v6(v4_mapped_t, const address_v4&) noexcept;
        address_v6 make_address_v6(const char*);
        address_v6 make_address_v6(const char*, error_code&) noexcept;
        address_v6 make_address_v6(string_view);
        address_v6 make_address_v6(string_view, error_code&) noexcept;

        // address I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>&, const address&);

        // address_v4 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>&, const address_v4&);

        // address_v6 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>&, const address_v6&);

        // address conversions:
        template<class T> constexpr T address_cast(const address&) noexcept(see below);
        template<class T> constexpr T address_cast(const address_v4&) noexcept(see below);
        template<class T> constexpr T address_cast(const address_v6&) noexcept(see below);

        template<class> basic_address_iterator; // not defined
        template<> class basic_address_iterator<address_v4>;
        typedef basic_address_iterator<address_v4> address_v4_iterator;
        template<> class basic_address_iterator<address_v6>;
        typedef basic_address_iterator<address_v6> address_v6_iterator;

        template<class> basic_address_range; // not defined
        template<> class basic_address_range<address_v4>;
        typedef basic_address_range<address_v4> address_v4_range;
        template<> class basic_address_range<address_v6>;
        typedef basic_address_range<address_v6> address_v6_range;

        class network_v4;
        class network_v6;

        // network_v4 comparisons:
        bool operator==(const network_v4&, const network_v4&) noexcept;
        bool operator!=(const network_v4&, const network_v4&) noexcept;

        // network_v6 comparisons:
        bool operator==(const network_v6&, const network_v6&) noexcept;
        bool operator!=(const network_v6&, const network_v6&) noexcept;

        // network_v4 creation:
        network_v4 make_network_v4(const address_v4&, unsigned);
        network_v4 make_network_v4(const address_v4&, const address_v4&);
        network_v4 make_network_v4(const char*);
        network_v4 make_network_v4(const char*, error_code&) noexcept;
        network_v4 make_network_v4(string_view);
        network_v4 make_network_v4(string_view, error_code&) noexcept;

        // network_v6 creation:
        network_v6 make_network_v6(const address_v6&, unsigned);
        network_v6 make_network_v6(const char*);
        network_v6 make_network_v6(const char*, error_code&) noexcept;
        network_v6 make_network_v6(string_view);
        network_v6 make_network_v6(string_view, error_code&) noexcept;

        // network_v4 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>&, const network_v4&);

        // network_v6 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>&, const network_v6&);

        template<class InternetProtocol>
          class basic_endpoint;

        // basic_endpoint comparisons:
        template<class InternetProtocol>
          bool operator==(const basic_endpoint<InternetProtocol>&,
                          const basic_endpoint<InternetProtocol>&);
        template<class InternetProtocol>
          bool operator!=(const basic_endpoint<InternetProtocol>&,
                          const basic_endpoint<InternetProtocol>&);
        template<class InternetProtocol>
          bool operator< (const basic_endpoint<InternetProtocol>&,
                          const basic_endpoint<InternetProtocol>&);
        template<class InternetProtocol>
          bool operator> (const basic_endpoint<InternetProtocol>&,
                          const basic_endpoint<InternetProtocol>&);
        template<class InternetProtocol>
          bool operator<=(const basic_endpoint<InternetProtocol>&,
                          const basic_endpoint<InternetProtocol>&);
        template<class InternetProtocol>
          bool operator>=(const basic_endpoint<InternetProtocol>&,
                          const basic_endpoint<InternetProtocol>&);

        // basic_endpoint I/O:
        template<class CharT, class Traits, class InternetProtocol>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>&,
            const basic_endpoint<InternetProtocol>&);

        template<class InternetProtocol>
          basic_resolver_entry;

        template<class InternetProtocol>
          bool operator==(const basic_resolver_entry<InternetProtocol>&,
                          const basic_resolver_entry<InternetProtocol>&);
        template<class InternetProtocol>
          bool operator!=(const basic_resolver_entry<InternetProtocol>&,
                          const basic_resolver_entry<InternetProtocol>&);

        template<class InternetProtocol>
          basic_resolver_results;

        template<class InternetProtocol>
          bool operator==(const basic_resolver_results<InternetProtocol>&,
                          const basic_resolver_results<InternetProtocol>&);
        template<class InternetProtocol>
          bool operator!=(const basic_resolver_results<InternetProtocol>&,
                          const basic_resolver_results<InternetProtocol>&);

        class resolver_base;

        template<class InternetProtocol>
          class basic_resolver;

        string host_name();
        string host_name(error_code&);
        template<class Allocator>
          basic_string<char, char_traits<char>, Allocator>
            host_name(const Allocator&) const;
        template<class Allocator>
          basic_string<char, char_traits<char>, Allocator>
            host_name(const Allocator&, error_code&) const;

        class tcp;

        // tcp comparisons:
        bool operator==(const tcp& a, const tcp& b);
        bool operator!=(const tcp& a, const tcp& b);

        class udp;

        // udp comparisons:
        bool operator==(const udp& a, const udp& b);
        bool operator!=(const udp& a, const udp& b);

        class v6_only;

        namespace unicast {

          class hops;

        } // namespace unicast

        namespace multicast {

          class join_group;

          class leave_group;

          class outbound_interface;

          class hops;

          class enable_loopback;

        } // namespace multicast
      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental

  template<> struct is_error_condition_enum<
    experimental::ip::resolver_errc>
      : public true_type {};

  // hash support
  template<class T> struct hash;
  template<> struct hash<experimental::ip::address>;
  template<> struct hash<experimental::ip::address_v4>;
  template<> struct hash<experimental::ip::address_v6>;

} // namespace std

10.20.2. Requirements

[internet.reqmts]

10.20.2.1. Internet protocol requirements

[internet.reqmts.protocol]

An internet protocol must meet the requirements for requirements.acceptable_protocol, as well as the additional requirements listed below.

In the table below, X denotes an internet protocol class, a denotes a (possibly const) value of type X, and b denotes a (possibly const) value of type X.

Table 30. InternetProtocol requirements

expression

return type

assertion/note
pre/post-conditions

X::resolver

ip::basic_resolver<X>

The type of a resolver for the protocol.

X::v4()

X

Returns an object representing the IP version 4 protocol.

X::v6()

X

Returns an object representing the IP version 6 protocol.

a == b

convertible to bool

Returns true if a and b represent the same IP protocol version, otherwise false.

a != b

convertible to bool

Returns !(a == b).


10.20.3. Error codes

[internet.resolver.err]

const error_category& resolver_category() noexcept;

Returns: A reference to an object of a type derived from class error_category.

The object’s default_error_condition and equivalent virtual functions behave as specified for the class error_category. The object’s name virtual function returns a pointer to the string "resolver".

error_code make_error_code(resolver_errc e) noexcept;

Returns: error_code(static_cast<int>(e), resolver_category()).

error_condition make_error_condition(resolver_errc e) noexcept;

Returns: error_condition(static_cast<int>(e), resolver_category()).

10.20.4. Class ip::address

[internet.address]

The class address is a version-independent representation for an IP address. An object of class address holds either an IPv4 address, an IPv6 address, or no valid address.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class address
        {
        public:
          // constructors:
          constexpr address() noexcept;
          constexpr address(const address& a) noexcept;
          template<class T> constexpr address(const T& t) noexcept(see below);

          // assignment:
          address& operator=(const address& a) noexcept;

          // members:
          constexpr bool is_v4() const noexcept;
          constexpr bool is_v6() const noexcept;
          constexpr bool is_unspecified() const noexcept;
          constexpr bool is_loopback() const noexcept;
          constexpr bool is_multicast() const noexcept;
          template<class Allocator = allocator<char>>
            basic_string<char, char_traits<char>, Allocator>
              to_string(const Allocator& a = Allocator()) const;

        private:
          address_v4 v4_; // exposition only
          address_v6 v6_; // exposition only
        };

        // address comparisons:
        bool operator==(const address& a, const address& b) noexcept;
        bool operator!=(const address& a, const address& b) noexcept;
        bool operator< (const address& a, const address& b) noexcept;
        bool operator> (const address& a, const address& b) noexcept;
        bool operator<=(const address& a, const address& b) noexcept;
        bool operator>=(const address& a, const address& b) noexcept;

        // address creation:
        address make_address(const char* str);
        address make_address(const char* str, error_code& ec) noexcept;
        address make_address(string_view str);
        address make_address(string_view str, error_code& ec) noexcept;

        // address I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>& os, const address& addr);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.20.4.1. ip::address constructors

[internet.address.cons]

constexpr address() noexcept;

Postconditions: is_v4() == true, is_v6() == false, and is_unspecified() == true.

constexpr address(const address& a) noexcept;

Postconditions: *this == a

template<class T> constexpr address(const T& t) noexcept(see below);

Remarks: This constructor shall not participate in overload resolution unless address_cast<address>(t) is valid and yields an rvalue of type address. The expression inside noexcept shall be equivalent to noexcept(address_cast<address>(t)).

Effects: Constructs an object of type address with the result of the expression address_cast<address>(t).

Throws: Nothing unless the expression address_cast<address>(t) throws an exception.

10.20.4.2. ip::address assignment

[internet.address.assign]

address& operator=(const address& a) noexcept;

Postconditions: *this == a

Returns: *this

10.20.4.3. ip::address members

[internet.address.members]

constexpr bool is_v4() const noexcept;

Returns: true if the object contains an IP version 4 address, otherwise false.

constexpr bool is_v6() const noexcept;

Returns: true if the object contains an IP version 6 address, otherwise false.

constexpr bool is_unspecified() const noexcept;

Returns: If is_v4(), returns v4_.is_unspecified(). Otherwise returns v6_.is_unspecified().

constexpr bool is_loopback() const noexcept;

Returns: If is_v4(), returns v4_.is_loopback(). Otherwise returns v6_.is_loopback().

constexpr bool is_multicast() const noexcept;

Returns: If is_v4(), returns v4_.is_multicast(). Otherwise returns v6_.is_multicast().

template<class Allocator = allocator<char>>
  basic_string<char, char_traits<char>, Allocator>
    to_string(const Allocator& a = Allocator()) const;

Returns: If is_v4(), returns v4_.to_string(a). Otherwise returns v6_.to_string(a).

10.20.4.4. ip::address comparisons

[internet.address.comparisons]

bool operator==(const address& a, const address& b) noexcept;

Returns:
— if a.is_v4() != b.is_v4(), false;
— if a.is_v4(), the result of a.v4_ == b.v4_;
— otherwise, the result of a.v6_ == b.v6_.

bool operator!=(const address& a, const address& b) noexcept;

Returns: !(a == b).

bool operator< (const address& a, const address& b) noexcept;

Returns:
— if a.is_v4() && !b.is_v4(), true;
— if !a.is_v4() && b.is_v4(), false;
— if a.is_v4(), the result of a.v4_ < b.v4_;
— otherwise, the result of a.v6_ < b.v6_.

bool operator> (const address& a, const address& b) noexcept;

Returns: b < a.

bool operator<=(const address& a, const address& b) noexcept;

Returns: !(b < a).

bool operator>=(const address& a, const address& b) noexcept;

Returns: !(a < b).

10.20.4.5. ip::address creation

[internet.address.creation]

address make_address(const char* str);
address make_address(const char* str, error_code& ec) noexcept;
address make_address(string_view str);
address make_address(string_view str, error_code& ec) noexcept;

Effects: Converts a textual representation of an address into an object of class address, as if by calling:

address a;
address_v6 v6a = make_address_v6(str, ec);
if (!ec)
  a = v6a;
else
{
  address_v4 v4a = make_address_v4(str, ec);
  if (!ec)
    a = v4a;
}

Returns: a.

10.20.4.6. ip::address I/O

[internet.address.io]

template<class CharT, class Traits>
  basic_ostream<CharT, Traits>& operator<<(
    basic_ostream<CharT, Traits>& os, const address& addr);

Returns: os << addr.to_string().c_str().

10.20.5. Class ip::address_v4

[internet.address.v4]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class address_v4
        {
        public:
          // types:
          struct bytes_type;

          // constructors:
          constexpr address_v4() noexcept;
          constexpr address_v4(const address_v4& a) noexcept;
          constexpr address_v4(const bytes_type& bytes);
          explicit constexpr address_v4(address_v4_uint_type val);

          // assignment:
          address_v4& operator=(const address_v4& a) noexcept;

          // members:
          constexpr bool is_unspecified() const noexcept;
          constexpr bool is_loopback() const noexcept;
          constexpr bool is_class_a() const noexcept;
          constexpr bool is_class_b() const noexcept;
          constexpr bool is_class_c() const noexcept;
          constexpr bool is_multicast() const noexcept;
          constexpr bytes_type to_bytes() const noexcept;
          constexpr address_v4_uint_type to_uint() const noexcept;
          template<class Allocator = allocator<char>>
            basic_string<char, char_traits<char>, Allocator>
              to_string(const Allocator& a = Allocator()) const;

          // static members:
          static constexpr address_v4 any() noexcept;
          static constexpr address_v4 loopback() noexcept;
          static constexpr address_v4 broadcast() noexcept;
          static constexpr address_v4 broadcast(const address_v4& addr,
            const address_v4& mask) noexcept;
        };

        // address_v4 comparisons:
        constexpr bool operator==(const address_v4& a, const address_v4& b) noexcept;
        constexpr bool operator!=(const address_v4& a, const address_v4& b) noexcept;
        constexpr bool operator< (const address_v4& a, const address_v4& b) noexcept;
        constexpr bool operator> (const address_v4& a, const address_v4& b) noexcept;
        constexpr bool operator<=(const address_v4& a, const address_v4& b) noexcept;
        constexpr bool operator>=(const address_v4& a, const address_v4& b) noexcept;

        // address_v4 creation:
        constexpr address_v4 make_address_v4(const address_v4::bytes_type& bytes);
        constexpr address_v4 make_address_v4(address_v4_uint_type val);
        constexpr address_v4 make_address_v4(v4_mapped_t, const address_v6& a);
        address_v4 make_address_v4(const char* str);
        address_v4 make_address_v4(const char* str, error_code& ec) noexcept;
        address_v4 make_address_v4(string_view str);
        address_v4 make_address_v4(string_view str, error_code& ec) noexcept;

        // address_v4 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>& os, const address_v4& addr);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.20.5.1. Struct ip::address_v4::bytes_type

[internet.address.v4.bytes]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        struct address_v4::bytes_type : array<unsigned char, 4>
        {
          template<class... T> explicit constexpr bytes_type(T... t)
            : array<unsigned char, 4>{{static_cast<unsigned char>(t)...}} {}
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The ip::address_v4::bytes_type type is a standard-layout struct that provides a byte-level representation of an IPv4 address in network byte order.

10.20.5.2. ip::address_v4 constructors

[internet.address.v4.cons]

constexpr address_v4() noexcept;

Effects: Constructs an object of class address_v4.

Postconditions: to_bytes() yields {0, 0, 0, 0} and to_uint() == 0.

constexpr address_v4(const address_v4& a) noexcept;

Effects: Constructs an object of class address_v4.

Postconditions: *this == a

constexpr address_v4(const bytes_type& bytes);

Throws: out_of_range if any element of bytes is not in the range [0, 0xFF]. [Note: For implementations where numeric_limits<unsigned char>::max() == 0xFF, no out-of-range detection is needed. —end note]

Postconditions: to_bytes() == bytes and to_uint() == (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3].

explicit constexpr address_v4(address_v4_uint_type val);

Throws: out_of_range if val is not in the range [0, 0xFFFFFFFF]. [Note: For implementations where numeric_limits<address_v4_uint_type>::max() == 0xFFFFFFFF, no out-of-range detection is needed. —end note]

Postconditions: to_uint() == val and to_bytes() is { (val >> 24) & 0xFF, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF }.

10.20.5.3. ip::address_v4 assignment

[internet.address.v4.assign]

address_v4& operator=(const address_v4& a) noexcept;

Postconditions: *this == a

Returns: *this

10.20.5.4. ip::address_v4 members

[internet.address.v4.members]

constexpr bool is_unspecified() const noexcept;

Returns: to_uint() == 0.

constexpr bool is_loopback() const noexcept;

Returns: (to_uint() & 0xFF000000) == 0x7F000000.

constexpr bool is_class_a() const noexcept;

Returns: (to_uint() & 0x80000000) == 0.

constexpr bool is_class_b() const noexcept;

Returns: (to_uint() & 0xC0000000) == 0x80000000.

constexpr bool is_class_c() const noexcept;

Returns: (to_uint() & 0xE0000000) == 0xC0000000.

constexpr bool is_multicast() const noexcept;

Returns: (to_uint() & 0xF0000000) == 0xE0000000.

constexpr bytes_type to_bytes() const noexcept;

Returns: A representation of the address in network byte order.

constexpr address_v4_uint_type to_uint() const noexcept;

Returns: A representation of the address in host byte order.

template<class Allocator = allocator<char>>
  basic_string<char, char_traits<char>, Allocator>
    to_string(const Allocator& a = Allocator()) const;

Returns: If successful, the textual representation of the address, determined as if by POSIX inet_ntop when invoked with address family AF_INET. Otherwise basic_string<char, char_traits<char>, Allocator>(a).

10.20.5.5. ip::address_v4 static members

[internet.address.v4.static]

static constexpr address_v4 any() noexcept;

Returns: address_v4().

static constexpr address_v4 loopback() noexcept;

Returns: address_v4(0x7F000001).

static constexpr address_v4 broadcast() noexcept;

Returns: address_v4(0xFFFFFFFF).

static constexpr address_v4 broadcast(const address_v4& addr, const address_v4& mask) noexcept;

Returns: address_v4(addr.to_uint() | ~mask.to_uint()).

10.20.5.6. ip::address_v4 comparisons

[internet.address.v4.comparisons]

constexpr bool operator==(const address_v4& a, const address_v4& b) noexcept;

Returns: a.to_uint() == b.to_uint().

constexpr bool operator!=(const address_v4& a, const address_v4& b) noexcept;

Returns: !(a == b).

constexpr bool operator< (const address_v4& a, const address_v4& b) noexcept;

Returns: a.to_uint() < b.to_uint().

constexpr bool operator> (const address_v4& a, const address_v4& b) noexcept;

Returns: b < a.

constexpr bool operator<=(const address_v4& a, const address_v4& b) noexcept;

Returns: !(b < a).

constexpr bool operator>=(const address_v4& a, const address_v4& b) noexcept;

Returns: !(a < b).

10.20.5.7. ip::address_v4 creation

[internet.address.v4.creation]

constexpr address_v4 make_address_v4(const address_v4::bytes_type& bytes);

Returns: address_v4(bytes).

constexpr address_v4 make_address_v4(address_v4_uint_type val);

Returns: address_v4(val).

constexpr address_v4 make_address_v4(v4_mapped_t, const address_v6& a);

Returns: An address_v4 object corresponding to the IPv4-mapped IPv6 address, as if computed by the following method:

bytes_type v6b = a.to_bytes();
address_v4::bytes_type v4b(v6b[12], v6b[13], v6b[14], v6b[15]);
return address_v4(v4b);

Throws: bad_address_cast if a.is_v4_mapped() is false.

address_v4 make_address_v4(const char* str);
address_v4 make_address_v4(const char* str, error_code& ec) noexcept;
address_v4 make_address_v4(string_view str);
address_v4 make_address_v4(string_view str, error_code& ec) noexcept;

Effects: Converts a textual representation of an address into a corresponding address_v4 value, as if by POSIX inet_pton when invoked with address family AF_INET.

Returns: If successful, an address_v4 value corresponding to the string str. Otherwise address_v4().

Error conditions:
errc::invalid_argument — if str is not a valid textual representation of an IPv4 address.

10.20.5.8. ip::address_v4 I/O

[internet.address.v4.io]

template<class CharT, class Traits>
  basic_ostream<CharT, Traits>& operator<<(
    basic_ostream<CharT, Traits>& os, const address_v4& addr);

Returns: os << addr.to_string().c_str().

10.20.6. Class ip::address_v6

[internet.address.v6]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class address_v6
        {
        public:
          // types:
          struct bytes_type;

          // constructors:
          constexpr address_v6() noexcept;
          constexpr address_v6(const address_v6& a) noexcept;
          constexpr address_v6(const bytes_type& bytes,
                               scope_id_type scope = 0);

          // assignment:
          address_v6& operator=(const address_v6& a) noexcept;

          // members:
          void scope_id(scope_id_type id) noexcept;
          constexpr scope_id_type scope_id() const noexcept;
          constexpr bool is_unspecified() const noexcept;
          constexpr bool is_loopback() const noexcept;
          constexpr bool is_multicast() const noexcept;
          constexpr bool is_link_local() const noexcept;
          constexpr bool is_site_local() const noexcept;
          constexpr bool is_v4_mapped() const noexcept;
          constexpr bool is_multicast_node_local() const noexcept;
          constexpr bool is_multicast_link_local() const noexcept;
          constexpr bool is_multicast_site_local() const noexcept;
          constexpr bool is_multicast_org_local() const noexcept;
          constexpr bool is_multicast_global() const noexcept;
          constexpr bytes_type to_bytes() const noexcept;
          template<class Allocator = allocator<char>>
            basic_string<char, char_traits<char>, Allocator>
              to_string(const Allocator& a = Allocator()) const;

          // static members:
          static constexpr address_v6 any() noexcept;
          static constexpr address_v6 loopback() noexcept;
        };

        // address_v6 comparisons:
        constexpr bool operator==(const address_v6& a, const address_v6& b) noexcept;
        constexpr bool operator!=(const address_v6& a, const address_v6& b) noexcept;
        constexpr bool operator< (const address_v6& a, const address_v6& b) noexcept;
        constexpr bool operator> (const address_v6& a, const address_v6& b) noexcept;
        constexpr bool operator<=(const address_v6& a, const address_v6& b) noexcept;
        constexpr bool operator>=(const address_v6& a, const address_v6& b) noexcept;

        // address_v6 creation:
        constexpr address_v6 make_address_v6(const address_v6::bytes_type& bytes,
                                             scope_id_type scope_id = 0);
        constexpr address_v6 make_address_v6(v4_mapped_t, const address_v4& a) noexcept;
        address_v6 make_address_v6(const char* str);
        address_v6 make_address_v6(const char* str, error_code& ec) noexcept;
        address_v6 make_address_v6(string_view str);
        address_v6 make_address_v6(string_view str, error_code& ec) noexcept;

        // address_v6 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>& os, const address_v6& addr);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

[Note: The implementations of the functions is_unspecified, is_loopback, is_multicast, is_link_local, is_site_local, is_v4_mapped, is_multicast_node_local, is_multicast_link_local, is_multicast_site_local, is_multicast_org_local and is_multicast_global are determined by [RFC4291]. —end note]

10.20.6.1. Struct ip::address_v6::bytes_type

[internet.address.v6.bytes]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        struct address_v6::bytes_type : array<unsigned char, 16>
        {
          template<class... T> explicit constexpr bytes_type(T... t)
            : array<unsigned char, 16>{{static_cast<unsigned char>(t)...}} {}
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The ip::address_v6::bytes_type type is a standard-layout struct that provides a byte-level representation of an IPv6 address in network byte order.

10.20.6.2. ip::address_v6 constructors

[internet.address.v6.cons]

constexpr address_v6() noexcept;

Postconditions: is_unspecified() == true and scope_id() == 0.

constexpr address_v6(const address_v6& a) noexcept;

Postconditions: *this == a

constexpr address_v6(const bytes_type& bytes,
                     scope_id_type scope = 0);

Throws: out_of_range if any element of bytes is not in the range [0, 0xFF]. [Note: For implementations where numeric_limits<unsigned char>::max() == 0xFF, no out-of-range detection is needed. —end note]

Postconditions: to_bytes() == bytes and scope_id() == scope.

10.20.6.3. ip::address_v6 assignment

[internet.address.v6.assign]

address_v6& operator=(const address_v6& a) noexcept;

Postconditions: *this == a

Returns: *this

10.20.6.4. ip::address_v6 members

[internet.address.v6.members]

void scope_id(scope_id_type id) noexcept;

Postconditions: scope_id() == id.

constexpr scope_id_type scope_id() const noexcept;

Returns: The scope identifier associated with the address.

constexpr bool is_unspecified() const noexcept;

Returns: *this == make_address_v6("::").

constexpr bool is_loopback() const noexcept;

Returns: *this == make_address_v6("::1").

constexpr bool is_multicast() const noexcept;

Returns: A boolean indicating whether the address_v6 object represents a multicast address, as if computed by the following method:

bytes_type b = to_bytes();
return b[0] == 0xFF;

constexpr bool is_link_local() const noexcept;

Returns: A boolean indicating whether the address_v6 object represents a unicast link-local address, as if computed by the following method:

bytes_type b = to_bytes();
return b[0] == 0xFE && (b[1] & 0xC0) == 0x80;

constexpr bool is_site_local() const noexcept;

Returns: A boolean indicating whether the address_v6 object represents a unicast site-local address, as if computed by the following method:

bytes_type b = to_bytes();
return b[0] == 0xFE && (b[1] & 0xC0) == 0xC0;

constexpr bool is_v4_mapped() const noexcept;

Returns: A boolean indicating whether the address_v6 object represents an IPv4-mapped IPv6 address, as if computed by the following method:

bytes_type b = to_bytes();
return b[ 0] == 0 && b[ 1] == 0 && b[ 2] == 0    && b[ 3] == 0
    && b[ 4] == 0 && b[ 5] == 0 && b[ 6] == 0    && b[ 7] == 0
    && b[ 8] == 0 && b[ 9] == 0 && b[10] == 0xFF && b[11] == 0xFF;

constexpr bool is_multicast_node_local() const noexcept;

Returns: is_multicast() && (to_bytes()[1] & 0x0F) == 0x01.

constexpr bool is_multicast_link_local() const noexcept;

Returns: is_multicast() && (to_bytes()[1] & 0x0F) == 0x02.

constexpr bool is_multicast_site_local() const noexcept;

Returns: is_multicast() && (to_bytes()[1] & 0x0F) == 0x05.

constexpr bool is_multicast_org_local() const noexcept;

Returns: is_multicast() && (to_bytes()[1] & 0x0F) == 0x08.

constexpr bool is_multicast_global() const noexcept;

Returns: is_multicast() && (to_bytes()[1] & 0x0F) == 0x0E.

constexpr bytes_type to_bytes() const noexcept;

Returns: A representation of the address in network byte order.

template<class Allocator = allocator<char>>
  basic_string<char, char_traits<char>, Allocator>
    to_string(const Allocator& a = Allocator()) const;

Effects: Converts an address into a textual representation. If scope_id() == 0, converts as if by POSIX inet_ntop when invoked with address family AF_INET6. If scope_id() != 0, the format is address%scope-id, where address is the textual representation of the equivalent address having scope_id() == 0, and scope-id is an implementation-defined textual representation of the scope identifier.

Returns: If successful, the textual representation of the address. Otherwise basic_string<char, char_traits<char>, Allocator>(a).

10.20.6.5. ip::address_v6 static members

[internet.address.v6.static]

static constexpr address_v6 any() noexcept;

Returns: An address a such that the a.is_unspecified() == true and a.scope_id() == 0.

static constexpr address_v6 loopback() noexcept;

Returns: An address a such that the a.is_loopback() == true and a.scope_id() == 0.

10.20.6.6. ip::address_v6 comparisons

[internet.address.v6.comparisons]

constexpr bool operator==(const address_v6& a, const address_v6& b) noexcept;

Returns: a.to_bytes() == b.to_bytes() && a.scope_id() == b.scope_id().

constexpr bool operator!=(const address_v6& a, const address_v6& b) noexcept;

Returns: !(a == b).

constexpr bool operator< (const address_v6& a, const address_v6& b) noexcept;

Returns: a.to_bytes() < b.to_bytes() || (!(b.to_bytes() < a.to_bytes()) && a.scope_id() < b.scope_id()).

constexpr bool operator> (const address_v6& a, const address_v6& b) noexcept;

Returns: b < a.

constexpr bool operator<=(const address_v6& a, const address_v6& b) noexcept;

Returns: !(b < a).

constexpr bool operator>=(const address_v6& a, const address_v6& b) noexcept;

Returns: !(a < b).

10.20.6.7. ip::address_v6 creation

[internet.address.v6.creation]

constexpr address_v6 make_address_v6(const address_v6::bytes_type& bytes,
                                     scope_id_type scope_id);

Returns: address_v6(bytes, scope_id).

constexpr address_v6 make_address_v6(v4_mapped_t, const address_v4& a) noexcept;

Returns: An address_v6 object containing the IPv4-mapped IPv6 address corresponding to the specified IPv4 address, as if computed by the following method:

address_v4::bytes_type v4b = a.to_bytes();
bytes_type v6b(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
               0xFF, 0xFF, v4b[0], v4b[1], v4b[2], v4b[3]);
return address_v6(v6b);

address_v6 make_address_v6(const char* str);
address_v6 make_address_v6(const char* str, error_code& ec) noexcept;
address_v6 make_address_v6(string_view str);
address_v6 make_address_v6(string_view str, error_code& ec) noexcept;

Effects: Converts a textual representation of an address into a corresponding address_v6 value. The format is either address or address%scope-id, where address is in the format specified by POSIX inet_pton when invoked with address family AF_INET6, and scope-id is an optional string specifying the scope identifier. All implementations shall accept as scope-id a textual representation of an unsigned decimal integer. It is implementation-defined whether alternative scope identifier representations are permitted. If scope-id is not supplied, an address_v6 object shall be returned such that scope_id() == 0.

Returns: If successful, an address_v6 value corresponding to the string str. Otherwise returns address_v6().

Error conditions:
errc::invalid_argument — if str is not a valid textual representation of an IPv6 address.

10.20.6.8. ip::address_v6 I/O

[internet.address.v6.io]

template<class CharT, class Traits>
  basic_ostream<CharT, Traits>& operator<<(
    basic_ostream<CharT, Traits>& os, const address_v6& addr);

Returns: os << addr.to_string().c_str().

10.20.7. Class ip::bad_address_cast

[internet.bad.address.cast]

An exception of type bad_address_cast is thrown by a failed address_cast.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class bad_address_cast : bad_cast
        {
        public:
          // constructor:
          bad_address_cast() noexcept;
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

bad_address_cast() noexcept;

Effects: constructs a bad_address_cast object.

Postconditions: what() returns an implementation-defined NTBS.

10.20.8. Function ip::address_cast

[internet.address.cast]

This implementation shall specialize address_cast for the types T listed in the tables below.

template<class T> constexpr T address_cast(const address& a) noexcept(see below);

Table 31. template<class T> constexpr T address_cast(const address&) effects

T

noexcept

remarks

address

true

Returns a.

address_v4

false

If a.is_v4() is true, returns the IP version 4 address specified in a. Otherwise, throws bad_address_cast.

address_v6

false

If a.is_v6() is true, returns the IP version 6 address specified in a. Otherwise, throws bad_address_cast.


template<class T> constexpr T address_cast(const address_v4& a) noexcept(see below);

This function template shall participate in overload resolution only for the types T listed in the table below.

Table 32. template<class T> constexpr T address_cast(const address_v4&) effects

T

noexcept

remarks

address

true

Returns a version-independent address object b such that b.is_v4() is true, b.is_v6() is false, and address_cast<address_v4>(b) == a.

address_v4

true

Returns a.

address_v6

Function overload is deleted.


template<class T> constexpr T address_cast(const address_v6& a) noexcept(see below);

This function template shall participate in overload resolution only for the types T listed in the table below.

Table 33. template<class T> constexpr T address_cast(const address_v6&) effects

T

noexcept

remarks

address

true

Returns a version-independent address object b such that b.is_v4() is false, b.is_v6() is true, and address_cast<address_v6>(b) == a.

address_v4

Function overload is deleted.

address_v6

true

Returns a.


10.20.9. Hash support

[internet.hash]

template<> struct hash<experimental::network_v1::ip::address>;
template<> struct hash<experimental::network_v1::ip::address_v4>;
template<> struct hash<experimental::network_v1::ip::address_v6>;

Requires: the template specializations shall meet the requirements of class template hash (C++ Std [unord.hash]).

10.20.10. Class template ip::basic_address_iterator specializations

[internet.address.iter]

The class template basic_address_iterator enables iteration over IP addresses in network byte order. This clause defines two specializations of the class template basic_address_iterator: basic_address_iterator<address_v4> and basic_address_iterator<address_v6>. The members and operational semantics of these specializations are defined below.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        template<> class basic_address_iterator<Address>
        {
        public:
          // types:
          typedef Address value_type;
          typedef ptrdiff_t difference_type;
          typedef const Address* pointer;
          typedef const Address& reference;
          typedef input_iterator_tag iterator_category;

          // constructors:
          basic_address_iterator(const Address& a) noexcept;

          // members:
          reference operator*() const noexcept;
          pointer operator->() const noexcept;
          basic_address_iterator& operator++() noexcept;
          basic_address_iterator& operator++(int) noexcept;
          basic_address_iterator& operator--() noexcept;
          basic_address_iterator& operator--(int) noexcept;

          // other members as required by C++ Std [input.iterators]

        private:
          Address address_; // exposition only
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

basic_address_iterator(const Address& a) noexcept;

Effects: Initializes address_ with a.

reference operator*() const noexcept;

Returns: address_.

pointer operator->() const noexcept;

Returns: std::addressof(address_).

basic_address_iterator& operator++() noexcept;

Effects: Sets address_ to the next unique address in network byte order.

Returns: *this.

basic_address_iterator& operator++(int) noexcept;

Effects: Sets address_ to the next unique address in network byte order.

Returns: The prior value of *this.

basic_address_iterator& operator--() noexcept;

Effects: Sets address_ to the prior unique address in network byte order.

Returns: *this.

basic_address_iterator& operator--(int) noexcept;

Effects: Sets address_ to the prior unique address in network byte order.

Returns: The prior value of *this.

10.20.11. Class template ip::basic_address_range specializations

[internet.address.range]

The class template basic_address_range represents a range of IP addresses in network byte order. This clause defines two specializations of the class template basic_address_range: basic_address_range<address_v4> and basic_address_range<address_v6>. The members and operational semantics of these specializations are defined below.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        template<> class basic_address_range<Address>
        {
        public:
          // types:
          typedef basic_address_iterator<Address> iterator;

          // constructors:
          basic_address_range() noexcept;
          basic_address_range(const Address& first,
                              const Address& last) noexcept;

          // members:
          iterator begin() const noexcept;
          iterator end() const noexcept;
          bool empty() const noexcept;
          size_t size() const noexcept; // not always defined
          iterator find(const Address& addr) const noexcept;
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

basic_address_range() noexcept;

Effects: Constructs an object of type basic_address_range<Address> that represents an empty range.

basic_address_range(const Address& first,
                    const Address& last) noexcept;

Effects: Constructs an object of type basic_address_range<Address> that represents the half open range [first,last).

iterator begin() const noexcept;

Returns: An iterator that points to the beginning of the range.

iterator end() const noexcept;

Returns: An iterator that points to the end of the range.

bool empty() const noexcept;

Returns: true if *this represents an empty range, otherwise false.

size_t size() const noexcept;

Returns: The number of unique addresses in the range.

Remarks: This member function is not defined when Address is type address_v6.

iterator find(const Address& addr) const noexcept;

Returns: If addr is in the range, an iterator that points to addr; otherwise, end().

Complexity: Constant time.

10.20.12. Class template ip::network_v4

[internet.network.v4]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class network_v4
        {
        public:
          // constructors:
          constexpr network_v4() noexcept;
          constexpr network_v4(const address_v4& addr, unsigned prefix_len);
          constexpr network_v4(const address_v4& addr, const address_v4& mask);

          // members:
          constexpr address_v4 address() const noexcept;
          constexpr unsigned prefix_length() const noexcept;
          constexpr address_v4 netmask() const noexcept;
          constexpr address_v4 network() const noexcept;
          constexpr address_v4 broadcast() const noexcept;
          address_v4_range hosts() const noexcept;
          constexpr network_v4 canonical() const noexcept;
          constexpr bool is_host() const noexcept;
          constexpr bool is_subnet_of(const network_v4& other) const noexcept;
          template<class Allocator = allocator<char>>
            basic_string<char, char_traits<char>, Allocator>
              to_string(const Allocator& a = Allocator()) const;
        };

        // network_v4 comparisons:
        constexpr bool operator==(const network_v4& a, const network_v4& b) noexcept;
        constexpr bool operator!=(const network_v4& a, const network_v4& b) noexcept;

        // network_v4 creation:
        constexpr network_v4 make_network_v4(const address_v4& addr, unsigned prefix_len);
        constexpr network_v4 make_network_v4(const address_v4& addr, const address_v4& mask);
        network_v4 make_network_v4(const char* str);
        network_v4 make_network_v4(const char* str, error_code& ec) noexcept;
        network_v4 make_network_v4(string_view str);
        network_v4 make_network_v4(string_view str, error_code& ec) noexcept;

        // network_v4 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>& os, const network_v4& addr);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.20.12.1. ip::network_v4 constructors

[internet.network.v4.cons]

constexpr network_v4() noexcept;

Postconditions: this->address().is_unspecified() == true and prefix_length() == 0.

constexpr network_v4(const address_v4& addr, unsigned prefix_len);

Postconditions: this->address() == addr and prefix_length() == prefix_len.

Throws: out_of_range if prefix_len > 32.

constexpr network_v4(const address_v4& addr, const address_v4& mask);

Postconditions: this->address() == addr and prefix_length() is equal to the number of contiguous non-zero bits.

Throws: invalid_argument if mask contains non-contiguous non-zero bits, or if the most significant bit is zero and any other bits are non-zero.

10.20.12.2. ip::network_v4 members

[internet.network.v4.members]

constexpr address_v4 address() const noexcept;

Returns: The address specified when the network_v4 object was constructed.

constexpr unsigned prefix_length() const noexcept;

Returns: The prefix length of the network.

constexpr address_v4 netmask() const noexcept;

Returns: An address_v4 object with prefix_length() contiguous non-zero bits set, starting from the most significant bit in network byte order. All other bits are zero.

constexpr address_v4 network() const noexcept;

Returns: An address_v4 object with the first prefix_length() bits, starting from the most significant bit in network byte order, set to the corresponding bit value of this->address(). All other bits are zero.

constexpr address_v4 broadcast() const noexcept;

Returns: An address_v4 object with the first prefix_length() bits, starting from the most significant bit in network byte order, set to the corresponding bit value of this->address(). All other bits are non-zero.

address_v4_range hosts() const noexcept;

Returns: If is_host() == true, an address_v4_range object representing the single address this->address(). Otherwise, an address_v4_range object representing the range of unique host IP addresses in the network.

[Note: For IPv4, the network address and the broadcast address are not included in the range of host IP addresses. For example, given a network 192.168.1.0/24, the range returned by hosts() is from 192.168.1.1 to 192.168.1.254 inclusive, and neither 192.168.1.0 nor the broadcast address 192.168.1.255 are in the range. —end note]

constexpr network_v4 canonical() const noexcept;

Returns: network_v4(network(), prefix_length()).

constexpr bool is_host() const noexcept;

Returns: prefix_length() == 32.

constexpr bool is_subnet_of(const network_v4& other) const noexcept;

Returns: true if other.prefix_length() < prefix_length() and network_v4(this->address(), other.prefix_length()).canonical() == other.canonical(), otherwise false.

template<class Allocator = allocator<char>>
  basic_string<char, char_traits<char>, Allocator>
    to_string(const Allocator& a = Allocator()) const;

Returns: this->address().to_string(a) + "/" + to_string(prefix_length()).c_str().

10.20.12.3. ip::network_v4 comparisons

[internet.network.v4.comparisons]

constexpr bool operator==(const network_v4& a, const network_v4& b) noexcept;

Returns: true if a.address() == b.address() and a.prefix_length() == b.prefix_length(), otherwise false.

constexpr bool operator!=(const network_v4& a, const network_v4& b) noexcept;

Returns: !(a == b).

10.20.12.4. ip::network_v4 creation

[internet.network.v4.creation]

constexpr network_v4 make_network_v4(const address_v4& addr, unsigned prefix_len);

Returns: network_v4(addr, prefix_len).

constexpr network_v4 make_network_v4(const address_v4& addr, const address_v4& mask);

Returns: network_v4(addr, mask).

network_v4 make_network_v4(const char* str);
network_v4 make_network_v4(const char* str, error_code& ec) noexcept;
network_v4 make_network_v4(string_view str);
network_v4 make_network_v4(string_view str, error_code& ec) noexcept;

Returns: If str contains a value of the form address '/' prefix-length, a network_v4 object constructed with the result of applying make_address_v4() to the address portion of the string, and the result of converting prefix-length to an integer of type unsigned. Otherwise returns network_v4() and sets ec to reflect the error.

Error conditions:
errc::invalid_argument — if str is not a valid textual representation of an IPv4 address and prefix length.

10.20.12.5. ip::network_v4 I/O

[internet.network.v4.io]

template<class CharT, class Traits>
  basic_ostream<CharT, Traits>& operator<<(
    basic_ostream<CharT, Traits>& os, const network_v4& net);

Returns: os << net.to_string().c_str().

10.20.13. Class template ip::network_v6

[internet.network.v6]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class network_v6
        {
        public:
          // constructors:
          constexpr network_v6() noexcept;
          constexpr network_v6(const address_v6& addr, unsigned prefix_len);

          // members:
          constexpr address_v6 address() const noexcept;
          constexpr unsigned prefix_length() const noexcept;
          constexpr address_v6 network() const noexcept;
          address_v6_range hosts() const noexcept;
          constexpr network_v6 canonical() const noexcept;
          constexpr bool is_host() const noexcept;
          constexpr bool is_subnet_of(const network_v6& other) const noexcept;
          template<class Allocator = allocator<char>>
            basic_string<char, char_traits<char>, Allocator>
              to_string(const Allocator& a = Allocator()) const;
        };

        // network_v6 comparisons:
        constexpr bool operator==(const network_v6& a, const network_v6& b) noexcept;
        constexpr bool operator!=(const network_v6& a, const network_v6& b) noexcept;

        // network_v6 creation:
        constexpr network_v6 make_network_v6(const address_v6& addr, unsigned prefix_len);
        network_v6 make_network_v6(const char* str);
        network_v6 make_network_v6(const char* str, error_code& ec) noexcept;
        network_v6 make_network_v6(const string_v6& str);
        network_v6 make_network_v6(const string_v6& str, error_code& ec) noexcept;

        // network_v6 I/O:
        template<class CharT, class Traits>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>& os, const network_v6& addr);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.20.13.1. ip::network_v6 constructors

[internet.network.v6.cons]

constexpr network_v6() noexcept;

Postconditions: this->address().is_unspecified() == true and prefix_length() == 0.

constexpr network_v6(const address_v6& addr, unsigned prefix_len);

Postconditions: this->address() == addr and prefix_length() == prefix_len.

Throws: out_of_range if prefix_len > 128.

10.20.13.2. ip::network_v6 members

[internet.network.v6.members]

constexpr address_v6 address() const noexcept;

Returns: The address specified when the network_v6 object was constructed.

constexpr unsigned prefix_length() const noexcept;

Returns: The prefix length of the network.

constexpr address_v6 network() const noexcept;

Returns: An address_v6 object with the first prefix_length() bits, starting from the most significant bit in network byte order, set to the corresponding bit value of this->address(). All other bits are zero.

address_v6_range hosts() const noexcept;

Returns: If is_host() == true, an address_v6_range object representing the single address this->address(). Otherwise, an address_v6_range object representing the range of unique host IP addresses in the network.

constexpr network_v6 canonical() const noexcept;

Returns: network_v6(network(), prefix_length()).

constexpr bool is_host() const noexcept;

Returns: prefix_length() == 128.

constexpr bool is_subnet_of(const network_v6& other) const noexcept;

Returns: true if other.prefix_length() < prefix_length() and network_v6(this->address(), other.prefix_length()).canonical() == other.canonical(), otherwise false.

template<class Allocator = allocator<char>>
  basic_string<char, char_traits<char>, Allocator>
    to_string(const Allocator& a = Allocator()) const;

Returns: this->address().to_string(a) + "/" + to_string(prefix_length()).c_str().

10.20.13.3. ip::network_v6 comparisons

[internet.network.v6.comparisons]

constexpr bool operator==(const network_v6& a, const network_v6& b) noexcept;

Returns: true if a.address() == b.address() and a.prefix_length() == b.prefix_length(), otherwise false.

constexpr bool operator!=(const network_v6& a, const network_v6& b) noexcept;

Returns: !(a == b).

10.20.13.4. ip::network_v6 creation

[internet.network.v6.creation]

constexpr network_v6 make_network_v6(const address_v6& addr, unsigned prefix_len);

Returns: network_v6(addr, prefix_len).

network_v6 make_network_v6(const char* str);
network_v6 make_network_v6(const char* str, error_code& ec) noexcept;
network_v6 make_network_v6(const string_v6& str);
network_v6 make_network_v6(const string_v6& str, error_code& ec) noexcept;

Returns: If str contains a value of the form address '/' prefix-length, a network_v6 object constructed with the result of applying make_address_v6() to the address portion of the string, and the result of converting prefix-length to an integer of type unsigned. Otherwise returns network_v6() and sets ec to reflect the error.

Error conditions:
errc::invalid_argument — if str is not a valid textual representation of an IPv6 address and prefix length.

10.20.13.5. ip::network_v6 I/O

[internet.network.v6.io]

template<class CharT, class Traits>
  basic_ostream<CharT, Traits>& operator<<(
    basic_ostream<CharT, Traits>& os, const network_v6& net);

Returns: os << net.to_string().c_str().

10.20.14. Class template ip::basic_endpoint

[internet.endpoint]

Instances of the basic_endpoint class template meet the requirements for an Endpoint.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        template<class InternetProtocol>
        class basic_endpoint
        {
        public:
          // types:
          typedef InternetProtocol protocol_type;

          // constructors:
          constexpr basic_endpoint() noexcept;
          constexpr basic_endpoint(const protocol_type& proto,
                                   port_type port_num) noexcept;
          constexpr basic_endpoint(const ip::address& addr,
                                   port_type port_num) noexcept;

          // members:
          constexpr protocol_type protocol() const noexcept;
          constexpr ip::address address() const noexcept;
          void address(const ip::address& addr) noexcept;
          constexpr port_type port() const noexcept;
          void port(port_type port_num) noexcept;
        };

        // basic_endpoint comparisons:
        template<class InternetProtocol>
          constexpr bool operator==(const basic_endpoint<InternetProtocol>& a,
                                    const basic_endpoint<InternetProtocol>& b) noexcept;
        template<class InternetProtocol>
          constexpr bool operator!=(const basic_endpoint<InternetProtocol>& a,
                                    const basic_endpoint<InternetProtocol>& b) noexcept;
        template<class InternetProtocol>
          constexpr bool operator< (const basic_endpoint<InternetProtocol>& a,
                                    const basic_endpoint<InternetProtocol>& b) noexcept;
        template<class InternetProtocol>
          constexpr bool operator> (const basic_endpoint<InternetProtocol>& a,
                                    const basic_endpoint<InternetProtocol>& b) noexcept;
        template<class InternetProtocol>
          constexpr bool operator<=(const basic_endpoint<InternetProtocol>& a,
                                    const basic_endpoint<InternetProtocol>& b) noexcept;
        template<class InternetProtocol>
          constexpr bool operator>=(const basic_endpoint<InternetProtocol>& a,
                                    const basic_endpoint<InternetProtocol>& b) noexcept;

        // basic_endpoint I/O:
        template<class CharT, class Traits, class InternetProtocol>
          basic_ostream<CharT, Traits>& operator<<(
            basic_ostream<CharT, Traits>& os,
            const basic_endpoint<InternetProtocol>& ep);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Extensible implementations provide the following member functions:

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        template<class InternetProtocol>
        class basic_endpoint
        {
        public:
          void* data() noexcept;
          const void* data() const noexcept;
          constexpr size_t size() const noexcept;
          void resize(size_t s);
          constexpr size_t capacity() const noexcept;
          // remainder unchanged
        private:
          union
          {
            sockaddr_in v4_;
            sockaddr_in6 v6_;
          } data_; // exposition only
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.20.14.1. ip::basic_endpoint constructors

[internet.endpoint.cons]

constexpr basic_endpoint() noexcept;

Postconditions: this->address() == ip::address() and port() == 0.

constexpr basic_endpoint(const protocol_type& proto,
                         port_type port_num) noexcept;

Requires: proto == protocol_type::v4() || proto == protocol_type::v6().

Postconditions:
— If proto == protocol_type::v6(), this->address() == ip::address_v6(); otherwise, this->address() == ip::address_v4().
port() == port_num.

constexpr basic_endpoint(const ip::address& addr,
                         port_type port_num) noexcept;

Postconditions: this->address() == addr and port() == port_num.

10.20.14.2. ip::basic_endpoint members

[internet.endpoint.members]

constexpr protocol_type protocol() const noexcept;

Returns: protocol_type::v6() if the expression this->address().is_v6() is true, otherwise protocol_type::v4().

constexpr ip::address address() const noexcept;

Returns: The address associated with the endpoint.

void address(const ip::address& addr) noexcept;

Postconditions: this->address() == addr.

constexpr port_type port() const noexcept;

Returns: The port number associated with the endpoint.

void port(port_type port_num) noexcept;

Postconditions: port() == port_num.

10.20.14.3. ip::basic_endpoint comparisons

[internet.endpoint.comparisons]

template<class InternetProtocol>
  constexpr bool operator==(const basic_endpoint<InternetProtocol>& a,
                            const basic_endpoint<InternetProtocol>& b) noexcept;

Returns: a.address() == b.address() && a.port() == b.port()).

template<class InternetProtocol>
  constexpr bool operator!=(const basic_endpoint<InternetProtocol>& a,
                            const basic_endpoint<InternetProtocol>& b) noexcept;

Returns: !(a == b).

template<class InternetProtocol>
  constexpr bool operator< (const basic_endpoint<InternetProtocol>& a,
                            const basic_endpoint<InternetProtocol>& b) noexcept;

Returns: a.address() < b.address() || (!(b.address() < a.address()) && a.port() < b.port()).

template<class InternetProtocol>
  constexpr bool operator> (const basic_endpoint<InternetProtocol>& a,
                            const basic_endpoint<InternetProtocol>& b) noexcept;

Returns: b < a.

template<class InternetProtocol>
  constexpr bool operator<=(const basic_endpoint<InternetProtocol>& a,
                            const basic_endpoint<InternetProtocol>& b) noexcept;

Returns: !(b < a).

template<class InternetProtocol>
  constexpr bool operator>=(const basic_endpoint<InternetProtocol>& a,
                            const basic_endpoint<InternetProtocol>& b) noexcept;

Returns: !(a < b).

10.20.14.4. ip::basic_endpoint I/O

[internet.endpoint.io]

template<class CharT, class Traits, class InternetProtocol>
  basic_ostream<CharT, Traits>& operator<<(
    basic_ostream<CharT, Traits>& os,
    const basic_endpoint<InternetProtocol>& ep);

Effects: Outputs a representation of the endpoint to the stream, as if it were implemented as follows:

basic_ostringstream<CharT, Traits> ss;
if (ep.protocol() == protocol_type::v6())
  ss << "[" << ep.address() << "]";
else
  ss << ep.address();
ss << ":" << ep.port();
os << ss.str();

Returns: os.

[Note: The representation of the endpoint when it contains an IP version 6 address is based on [RFC2732]. —end note]

10.20.14.5. ip::basic_endpoint members (extensible implementations)

[internet.endpoint.extensible]

void* data() noexcept;

Returns: std::addressof(data_).

const void* data() const noexcept;

Returns: std::addressof(data_).

constexpr size_t size() const noexcept;

Returns: sizeof(sockaddr_in6) if protocol().family() == AF_INET6, otherwise sizeof(sockaddr_in).

void resize(size_t s);

Throws: length_error if the condition protocol().family() == AF_INET6 && s != sizeof(sockaddr_in6) || protocol().family() == AF_INET4 && s != sizeof(sockaddr_in) is true.

constexpr size_t capacity() const noexcept;

Returns: sizeof(data_).

10.20.15. Class template ip::basic_resolver_entry

[internet.resolver.entry]

An object of type basic_resolver_entry<InternetProtocol> represents a single element in the results returned by a name resolution operation.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        template<class InternetProtocol>
        class basic_resolver_entry
        {
        public:
          // types:
          typedef InternetProtocol protocol_type;
          typedef typename InternetProtocol::endpoint endpoint_type;

          // constructors:
          basic_resolver_entry();
          basic_resolver_entry(const endpoint_type& ep,
                               string_view h,
                               string_view s);

          // members:
          endpoint_type endpoint() const;
          operator endpoint_type() const;
          template<class Allocator = allocator<char>>
            basic_string<char, char_traits<char>, Allocator>
              host_name(const Allocator& a = Allocator()) const;
          template<class Allocator = allocator<char>>
            basic_string<char, char_traits<char>, Allocator>
              service_name(const Allocator& a = Allocator()) const;
        };

        // basic_resolver_entry comparisons:
        template<class InternetProtocol>
          bool operator==(const basic_resolver_entry<InternetProtocol>& a,
                          const basic_resolver_entry<InternetProtocol>& b);
        template<class InternetProtocol>
          bool operator!=(const basic_resolver_entry<InternetProtocol>& a,
                          const basic_resolver_entry<InternetProtocol>& b);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.20.15.1. ip::basic_resolver_entry constructors

[internet.resolver.entry.cons]

basic_resolver_entry();

Effects: Equivalent to basic_resolver_entry<InternetProtocol>(endpoint_type(), "", "").

basic_resolver_entry(const endpoint_type& ep,
                     string_view h,
                     string_view s);

Postconditions:
endpoint() == ep.
host_name() == h.
service_name() == s.

10.20.15.2. ip::basic_resolver_entry members

[internet.resolver.entry.members]

endpoint_type endpoint() const;

Returns: The endpoint associated with the resolver entry.

operator endpoint_type() const;

Returns: endpoint().

template<class Allocator = allocator<char>>
  basic_string<char, char_traits<char>, Allocator>
    host_name(const Allocator& a = Allocator()) const;

Returns: The host name associated with the resolver entry.

template<class Allocator = allocator<char>>
  basic_string<char, char_traits<char>, Allocator>
    service_name(const Allocator& a = Allocator()) const;

Returns: The service name associated with the resolver entry.

10.20.15.3. op::basic_resolver_entry comparisons

[internet.resolver.entry.comparisons]

template<class InternetProtocol>
  bool operator==(const basic_resolver_entry<InternetProtocol>& a,
                  const basic_resolver_entry<InternetProtocol>& b);

Returns: a.endpoint() == b.endpoint() && a.host_name() == b.host_name() && a.service_name() == b.service_name().

template<class InternetProtocol>
  bool operator!=(const basic_resolver_entry<InternetProtocol>& a,
                  const basic_resolver_entry<InternetProtocol>& b);

Returns: !(a == b).

10.20.16. Class template ip::basic_resolver_results

[internet.resolver.results]

An object of type basic_resolver_results<InternetProtocol> represents a sequence of basic_resolver_entry<InternetProtocol> elements resulting from a single name resolution operation.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        template<class InternetProtocol>
        class basic_resolver_results
        {
        public:
          // types:
          typedef InternetProtocol protocol_type;
          typedef typename protocol_type::endpoint endpoint_type;
          typedef basic_resolver_entry<protocol_type> value_type;
          typedef const value_type& const_reference;
          typedef value_type& reference;
          typedef implementation-defined const_iterator;
          typedef const_iterator iterator;
          typedef ptrdiff_t difference_type;
          typedef size_t size_type;

          // construct / copy / destroy:
          basic_resolver_results();
          basic_resolver_results(const basic_resolver_results& rhs);
          basic_resolver_results(basic_resolver_results& rhs) noexcept;
          basic_resolver_results& operator=(const basic_resolver_results& rhs);
          basic_resolver_results& operator=(basic_resolver_results&& rhs);
          ~basic_resolver_results();

          // size:
          size_type size() const noexcept;
          size_type max_size() const noexcept;
          bool empty() const noexcept;

          // element access:
          const_iterator begin() const;
          const_iterator end() const;
          const_iterator cbegin() const;
          const_iterator cend() const;

          // swap:
          void swap(basic_resolver_results& that) noexcept;
        };

        // basic_resolver_results comparisons:
        template<class InternetProtocol>
          bool operator==(const basic_resolver_results<InternetProtocol>& a,
                          const basic_resolver_results<InternetProtocol>& b);
        template<class InternetProtocol>
          bool operator!=(const basic_resolver_results<InternetProtocol>& a,
                          const basic_resolver_results<InternetProtocol>& b);

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class template basic_resolver_results satisfies the requirements of a sequence container (C++Std [sequence.reqmts]), except that only the operations defined for const-qualified sequence containers are supported. The class template basic_resolver_results supports forward iterators.

A default-constructed basic_resolver_results object is empty. A non-empty results object is obtained only by calling a basic_resolver object's wait or async_wait operations, or otherwise by copy construction, move construction, assignment, or swap from another non-empty results object.

10.20.16.1. ip::basic_resolver_results constructors

[internet.resolver.results.cons]

basic_resolver_results();

Postconditions: size() == 0.

basic_resolver_results(const basic_resolver_results& rhs);

Postconditions: *this == rhs.

basic_resolver_results(basic_resolver_results& rhs) noexcept;

Postconditions: *this is equal to the prior value of rhs.

10.20.16.2. ip::basic_resolver_results assignment

[internet.resolver.results.assign]

basic_resolver_results& operator=(const basic_resolver_results& rhs);

Postconditions: *this == rhs.

Returns: *this.

basic_resolver_results& operator=(basic_resolver_results& rhs) noexcept;

Postconditions: *this is equal to the prior value of rhs.

Returns: *this.

10.20.16.3. ip::basic_resolver_results size

[internet.resolver.results.size]

size_type size() const noexcept;

Returns: The number of basic_resolver_entry elements in *this.

size_type max_size() const noexcept;

Returns: The maximum number of basic_resolver_entry elements that can be stored in *this.

bool empty() const noexcept;

Returns: size() == 0.

10.20.16.4. ip::basic_resolver_results element access

[internet.resolver.results.access]

const_iterator begin() const;
const_iterator cbegin() const;

Returns: A starting iterator that enumerates over all the basic_resolver_entry elements stored in *this.

const_iterator end() const;
const_iterator cend() const;

Returns: A terminating iterator that enumerates over all the basic_resolver_entry elements stored in *this.

10.20.16.5. ip::basic_resolver_results swap

[internet.resolver.results.swap]

void swap(basic_resolver_results& that) noexcept;

Postconditions: *this is equal to the prior value of that, and that is equal to the prior value of *this.

10.20.16.6. ip::basic_resolver_results comparisons

[internet.resolver.results.comparisons]

template<class InternetProtocol>
  bool operator==(const basic_resolver_results<InternetProtocol>& a,
                  const basic_resolver_results<InternetProtocol>& b);

Returns: a.size() == b.size() && equal(a.cbegin(), a.cend(), b.cbegin()).

template<class InternetProtocol>
  bool operator!=(const basic_resolver_results<InternetProtocol>& a,
                  const basic_resolver_results<InternetProtocol>& b);

Returns: !(a == b).

10.20.17. Class ip::resolver_base

[internet.resolver.base]

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class resolver_base
        {
        public:
          typedef T1 flags;
          static const flags passive;
          static const flags canonical_name;
          static const flags numeric_host;
          static const flags numeric_service;
          static const flags v4_mapped;
          static const flags all_matching;
          static const flags address_configured;

        protected:
          resolver_base();
          ~resolver_base();
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

resolver_base defines a bitmask type, flags, with the bitmask elements shown above.

Table 34. resolver flags

Constant name

POSIX macro

Definition or notes

passive

AI_PASSIVE

Returned endpoints are intended for use as locally bound socket endpoints.

canonical_name

AI_CANONNAME

Determine the canonical name of the host specified in the query.

numeric_host

AI_NUMERICHOST

Host name should be treated as a numeric string defining an IPv4 or IPv6 address and no host name resolution should be attempted.

numeric_service

AI_NUMERICSERV

Service name should be treated as a numeric string defining a port number and no service name resolution should be attempted.

v4_mapped

AI_V4MAPPED

If the protocol is specified as an IPv6 protocol, return IPv4-mapped IPv6 addresses on finding no IPv6 addresses.

all_matching

AI_ALL

If used with v4_mapped, return all matching IPv6 and IPv4 addresses.

address_configured

AI_ADDRCONFIG

Only return IPv4 addresses if a non-loopback IPv4 address is configured for the system. Only return IPv6 addresses if a non-loopback IPv6 address is configured for the system.


10.20.18. Class template ip::basic_resolver

[internet.resolver]

Objects of type basic_resolver<InternetProtocol> are used to perform name resolution. Name resolution is the translation of a host name and service name into a sequence of endpoints, or the translation of an endpoint into its corresponding host name and service name.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        template<class InternetProtocol>
        class basic_resolver : public resolver_base
        {
        public:
          // types:

          typedef io_service::executor_type executor_type;
          typedef InternetProtocol protocol_type;
          typedef typename InternetProtocol::endpoint endpoint_type;
          typedef basic_resolver_results<InternetProtocol> results_type;

          // construct / copy / destroy:

          explicit basic_resolver(io_service& ios);
          basic_resolver(const basic_resolver&) = delete;
          basic_resolver(basic_resolver&& rhs) noexcept;

          ~basic_resolver();

          basic_resolver& operator=(const basic_resolver&) = delete;
          basic_resolver& operator=(basic_resolver&& rhs);

          // basic_resolver operations:

          executor_type get_executor() noexcept;

          void cancel();

          results_type resolve(string_view host_name, string_view service_name);
          results_type resolve(string_view host_name, string_view service_name,
                               error_code& ec);
          results_type resolve(string_view host_name, string_view service_name,
                               flags f);
          results_type resolve(string_view host_name, string_view service_name,
                               flags f, error_code& ec);

          template<class CompletionToken>
            DEDUCED async_resolve(string_view host_name, string_view service_name,
                                  CompletionToken&& token);
          template<class CompletionToken>
            DEDUCED async_resolve(string_view host_name, string_view service_name,
                                  flags f, CompletionToken&& token);

          results_type resolve(const protocol_type& protocol,
                               string_view host_name, string_view service_name);
          results_type resolve(const protocol_type& protocol,
                               string_view host_name, string_view service_name,
                               error_code& ec);
          results_type resolve(const protocol_type& protocol,
                               string_view host_name, string_view service_name,
                               flags f);
          results_type resolve(const protocol_type& protocol,
                               string_view host_name, string_view service_name,
                               flags f, error_code& ec);

          template<class CompletionToken>
            DEDUCED async_resolve(const protocol_type& protocol,
                                  string_view host_name, string_view service_name,
                                  CompletionToken&& token);
          template<class CompletionToken>
            DEDUCED async_resolve(const protocol_type& protocol,
                                  string_view host_name, string_view service_name,
                                  flags f, CompletionToken&& token);

          results_type resolve(const endpoint_type& e);
          results_type resolve(const endpoint_type& e, error_code& ec);

          template<class CompletionToken>
            DEDUCED async_resolve(const endpoint_type& e,
                                  CompletionToken&& token);
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
10.20.18.1. ip::basic_resolver constructors

[internet.resolver.cons]

explicit basic_resolver(io_service& ios);

Postconditions: get_executor() == ios.get_executor().

basic_resolver(basic_resolver&& rhs) noexcept;

Effects: Move constructs an object of class basic_resolver<InternetProtocol> that refers to the state originally represented by rhs.

Postconditions: get_executor() == rhs.get_executor().

10.20.18.2. ip::basic_resolver destructor

[internet.resolver.dtor]

~basic_resolver();

Effects: Destroys the resolver, canceling all asynchronous operations associated with this resolver as if by calling cancel().

10.20.18.3. ip::basic_resolver assignment

[internet.resolver.assign]

basic_resolver& operator=(basic_resolver&& rhs);

Effects: Cancels all outstanding asynchronous operations associated with *this as if by calling cancel(), then moves into *this the state originally represented by rhs.

Postconditions: get_executor() == ios.get_executor().

Returns: *this.

10.20.18.4. ip::basic_resolver operations

[internet.resolver.ops]

executor_type& get_executor() noexcept;

Returns: The associated executor.

void cancel();

Effects: Cancels all outstanding asynchronous resolve operations associated with *this. Completion handlers for canceled operations are passed an error code ec such that ec == errc::operation_canceled yields true.

results_type resolve(string_view host_name, string_view service_name);
results_type resolve(string_view host_name, string_view service_name,
                     error_code& ec);

Returns: resolve(host_name, service_name, resolver_base::flags(), ec).

results_type resolve(string_view host_name, string_view service_name,
                     flags f);
results_type resolve(string_view host_name, string_view service_name,
                     flags f, error_code& ec);

Effects: If host_name.data() != nullptr, let H be an NTBS constructed from host_name; otherwise, let H be nullptr. If service_name.data() != nullptr, let S be an NTBS constructed from service_name; otherwise, let S be nullptr. Resolves a host name and service name, as if by POSIX:

addrinfo hints;
hints.ai_flags = static_cast<int>(f);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = endpoint_type().protocol().type();
hints.ai_protocol = endpoint_type().protocol().protocol();
hints.ai_addr = nullptr;
hints.ai_addrlen = 0;
hints.ai_canonname = nullptr;
hints.ai_next = nullptr;
addrinfo* result = nullptr;
getaddrinfo(H, S, &hints, &result);

Returns: On success, a non-empty results object containing the results of the resolve operation. Otherwise results_type().

template<class CompletionToken>
  DEDUCED async_resolve(string_view host_name, string_view service_name,
                        CompletionToken&& token);

Returns: async_resolve(host_name, service_name, resolver_base::flags(), forward<CompletionToken>(token)).

template<class CompletionToken>
  DEDUCED async_resolve(string_view host_name, string_view service_name,
                        flags f, CompletionToken&& token);

Completion signature: void(error_code ec, results_type r).

Effects: If host_name.data() != nullptr, let H be an NTBS constructed from host_name; otherwise, let H be nullptr. If service_name.data() != nullptr, let S be an NTBS constructed from service_name; otherwise, let S be nullptr. Initiates an asynchronous operation to resolve a host name and service name, as if by POSIX:

addrinfo hints;
hints.ai_flags = static_cast<int>(f);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = endpoint_type().protocol().type();
hints.ai_protocol = endpoint_type().protocol().protocol();
hints.ai_addr = nullptr;
hints.ai_addrlen = 0;
hints.ai_canonname = nullptr;
hints.ai_next = nullptr;
addrinfo* result = nullptr;
getaddrinfo(H, S, &hints, &result);

On success, r is a non-empty results object containing the results of the resolve opeation. Otherwise, r is results_type().

results_type resolve(const protocol_type& protocol,
                     string_view host_name, string_view service_name);
results_type resolve(const protocol_type& protocol,
                     string_view host_name, string_view service_name,
                     error_code& ec);

Returns: resolve(protocol, host_name, service_name, resolver_base::flags(), ec).

results_type resolve(const protocol_type& protocol,
                     string_view host_name, string_view service_name,
                     flags f);
results_type resolve(const protocol_type& protocol,
                     string_view host_name, string_view service_name,
                     flags f, error_code& ec);

Effects: If host_name.data() != nullptr, let H be an NTBS constructed from host_name; otherwise, let H be nullptr. If service_name.data() != nullptr, let S be an NTBS constructed from service_name; otherwise, let S be nullptr. Resolves a host name and service name, as if by POSIX:

addrinfo hints;
hints.ai_flags = static_cast<int>(f);
hints.ai_family = protocol.family();
hints.ai_socktype = protocol.type();
hints.ai_protocol = protocol.protocol();
hints.ai_addr = nullptr;
hints.ai_addrlen = 0;
hints.ai_canonname = nullptr;
hints.ai_next = nullptr;
addrinfo* result = nullptr;
getaddrinfo(H, S, &hints, &result);

Returns: On success, a non-empty results object containing the results of the resolve operation. Otherwise results_type().

template<class CompletionToken>
  DEDUCED async_resolve(const protocol_type& protocol,
                        string_view host_name, string_view service_name,
                        CompletionToken&& token);

Returns: async_resolve(protocol, host_name, service_name, resolver_base::flags(), forward<CompletionToken>(token)).

template<class CompletionToken>
  DEDUCED async_resolve(const protocol& protocol,
                        string_view host_name, string_view service_name,
                        flags f, CompletionToken&& token);

Completion signature: void(error_code ec, results_type r).

Effects: If host_name.data() != nullptr, let H be an NTBS constructed from host_name; otherwise, let H be nullptr. If service_name.data() != nullptr, let S be an NTBS constructed from service_name; otherwise, let S be nullptr. Initiates an asynchronous operation to resolve a host name and service name, as if by POSIX:

addrinfo hints;
hints.ai_flags = static_cast<int>(f);
hints.ai_family = protocol.family();
hints.ai_socktype = protocol.type();
hints.ai_protocol = protocol.protocol();
hints.ai_addr = nullptr;
hints.ai_addrlen = 0;
hints.ai_canonname = nullptr;
hints.ai_next = nullptr;
addrinfo* result = nullptr;
getaddrinfo(H, S, &hints, &result);

On success, r is a non-empty results object containing the results of the resolve opeation. Otherwise, r is results_type().

results_type resolve(const endpoint_type& e);
results_type resolve(const endpoint_type& e, error_code& ec);

Effects: Let S1 and S2 be implementation-defined values that are sufficiently large to hold the host name and service name respectively. Resolves an endpoint as if by POSIX:

char host_name[S1];
char service_name[S2];
int flags = 0;
if (endpoint_type().protocol().type() == SOCK_DGRAM)
  flags |= NI_DGRAM;
int result = getnameinfo(e.data(), e.size(),
                             host_name, S1,
                             service_name, S2,
                             flags);
if (result != 0)
{
  flags |= NI_NUMERICSERV;
  result = getnameinfo(e.data(), e.size(),
                           host_name, S1,
                           service_name, S2,
                           flags);
}

Returns: On success, a results object with size() == 1 containing the results of the resolve operation. Otherwise results_type().

template<class CompletionToken>
  DEDUCED async_resolve(const endpoint_type& e,
                        CompletionToken&& token);

Completion signature: void(error_code ec, results_type r).

Effects: Let S1 and S2 be implementation-defined values that are sufficiently large to hold the host name and service name respectively. Initiates an asynchronous operation to resolve an endpoint as if by POSIX:

char host_name[S1];
char service_name[S2];
int flags = 0;
if (endpoint_type().protocol().type() == SOCK_DGRAM)
  flags |= NI_DGRAM;
int result = getnameinfo(e.data(), e.size(),
                             host_name, S1,
                             service_name, S2,
                             flags);
if (result != 0)
{
  flags |= NI_NUMERICSERV;
  result = getnameinfo(e.data(), e.size(),
                           host_name, S1,
                           service_name, S2,
                           flags);
}

On success, r is a results object with size() == 1 containing the results of the resolve operation; otherwise, r is results_type().

10.20.19. Host name functions

[internet.host.name]

string host_name();
string host_name(error_code& ec);
template<class Allocator>
  basic_string<char, char_traits<char>, Allocator>
    host_name(const Allocator& a) const;
template<class Allocator>
  basic_string<char, char_traits<char>, Allocator>
    host_name(const Allocator& a, error_code& ec) const;

Returns: The standard host name for the current machine, determined as if by POSIX gethostname.

10.20.20. Class ip::tcp

[internet.tcp]

The tcp class meets the requirements for an InternetProtocol.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class tcp
        {
        public:
          // types:
          typedef basic_endpoint<tcp> endpoint;
          typedef basic_resolver<tcp> resolver;
          typedef basic_stream_socket<tcp> socket;
          typedef basic_socket_acceptor<tcp> acceptor;
          typedef basic_socket_iostream<tcp> iostream;
          class no_delay;

          // static members:
          static constexpr tcp v4() noexcept;
          static constexpr tcp v6() noexcept;

          tcp() = delete;
        };

        // tcp comparisons:
        constexpr bool operator==(const tcp& a, const tcp& b) noexcept;
        constexpr bool operator!=(const tcp& a, const tcp& b) noexcept;

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Extensible implementations provide the following member functions:

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class tcp
        {
        public:
          constexpr int family() const noexcept;
          constexpr int type() const noexcept;
          constexpr int protocol() const noexcept;
          // remainder unchanged
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The return values for these member functions are listed in the table below.

Table 35. Behavior of extensible implementations

value

family()

type()

protocol()

tcp::v4()

AF_INET

SOCK_DGRAM

IPPROTO_UDP

tcp::v6()

AF_INET6

SOCK_DGRAM

IPPROTO_UDP


[Note: The constants AF_INET, AF_INET6 and SOCK_STREAM are defined in the POSIX header file sys/socket.h. The constant IPPROTO_TCP is defined in the POSIX header file netinet/in.h. —end note]

10.20.20.1. ip::tcp comparisons

[internet.tcp.comparisons]

constexpr bool operator==(const tcp& a, const tcp& b) noexcept;

Returns: A boolean indicating whether two objects of class tcp are equal, such that the expression tcp::v4() == tcp::v4() is true, the expression tcp::v6() == tcp::v6() is true, and the expression tcp::v4() == tcp::v6() is false.

constexpr bool operator!=(const tcp& a, const tcp& b) noexcept;

Returns: !(a == b).

10.20.21. Class ip::tcp::no_delay

[internet.tcp.nodelay]

The no_delay class represents a socket option that determines whether a TCP socket will avoid coalescing of small segments. [Note: That is, setting this option disables the Nagle algorithm. —end note] It is defined as a boolean socket option.

Let L and N identify POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt.

Table 36. tcp::no_delay boolean socket option

C

L

N

tcp::no_delay

IPPROTO_TCP

TCP_NODELAY


[Note: The constant IPPROTO_TCP is defined in the POSIX header file netinet/in.h. The constant TCP_NODELAY is defined in the POSIX header file netinet/tcp.h. —end note]

10.20.22. Class ip::udp

[internet.udp]

The udp class meets the requirements for an InternetProtocol.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class udp
        {
        public:
          // types:
          typedef basic_endpoint<udp> endpoint;
          typedef basic_resolver<udp> resolver;
          typedef basic_datagram_socket<udp> socket;

          // static members:
          static constexpr udp v4() noexcept;
          static constexpr udp v6() noexcept;

          udp() = delete;
        };

        // udp comparisons:
        constexpr bool operator==(const udp& a, const udp& b) noexcept;
        constexpr bool operator!=(const udp& a, const udp& b) noexcept;

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Extensible implementations provide the following member functions:

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {

        class udp
        {
        public:
          constexpr int family() const noexcept;
          constpexr int type() const noexcept;
          constexpr int protocol() const noexcept;
          // remainder unchanged
        };

      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The return values for these member functions are listed in the table below.

Table 37. Behavior of extensible implementations

value

family()

type()

protocol()

udp::v4()

AF_INET

SOCK_DGRAM

IPPROTO_UDP

udp::v6()

AF_INET6

SOCK_DGRAM

IPPROTO_UDP


[Note: The constants AF_INET, AF_INET6 and SOCK_DGRAM are defined in the POSIX header file sys/socket.h. The constant IPPROTO_UDP is defined in the POSIX header file netinet/in.h. —end note]

10.20.22.1. ip::udp comparisons

[internet.udp.comparisons]

constexpr bool operator==(const udp& a, const udp& b) noexcept;

Returns: A boolean indicating whether two objects of class udp are equal, such that the expression udp::v4() == udp::v4() is true, the expression udp::v6() == udp::v6() is true, and the expression udp::v4() == udp::v6() is false.

constexpr bool operator!=(const udp& a, const udp& b) noexcept;

Returns: !(a == b).

10.20.23. Class ip::v6_only

[internet.v6only]

The v6_only class represents a socket option for determining whether a socket created for an IPv6 protocol is restricted to IPv6 communications only. It shall be defined as a boolean socket option with the name and values in the table below:

Table 38. v6_only boolean socket option

C

L

N

v6_only

IPPROTO_IPV6

IPV6_V6ONLY


[Note: The constants IPPROTO_IPV6 and IPV6_V6ONLY are defined in the POSIX header file netinet/in.h. —end note]

10.20.24. Class ip::unicast::hops

[internet.unicast.hops]

The hops class represents a socket option for specifying the default number of hops (also known as time-to-live or TTL) on outbound datagrams. It is an integral socket option.

L and N identify POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt. In the table below, p denotes a (possibly const) value of a type meeting the protocol requirements, as passed to the socket option's level and name member functions.

Table 39. hops integral socket option

C

L if p.family() == AF_INET4

N if p.family() == AF_INET4

L if p.family() == AF_INET6

N if p.family() == AF_INET6

ip::unicast::hops

IPPROTO_IP

IP_TTL

IPPROTO_IPV6

IPV6_UNICAST_HOPS


[Note: The constants IPPROTO_IP, IPPROTO_IPV6 and IPV6_UNICAST_HOPS are defined in the POSIX header file netinet/in.h. —end note]

The constructor and assignment operator for the hops class that accept an int throw out_of_range if the argument is not in the range [0, 255].

10.20.25. Multicast group management socket options

[internet.multicast.group]

The ip::multicast::join_group and ip::multicast::leave_group classes are socket options for multicast group management.

Multicast group management socket option classes satisfy the requirements for Destructible (C++ Std, [destructible]), CopyConstructible (C++ Std, [copyconstructible]), Assignable (C++ Std, [assignable]), and SettableSocketOption.

[Example: Creating a UDP socket and joining a multicast group:

// Open an IPv4 UDP socket bound to a specific port.
ip::udp::endpoint ep(ip::udp::v4(), 12345);
ip::udp::socket sock(io_svc, ep);

// Join a multicast group.
ip::address addr = ip::make_address("239.255.0.1");
sock.set_option(ip::multicast::join_group(addr));

end example]

Multicast group management socket option classes shall be defined as follows:

class C
{
public:
  // constructors:
  explicit C(const address& multicast_group) noexcept;
  explicit C(const address_v4& multicast_group,
             const address_v4& network_interface = address_v4::any()) noexcept;
  explicit C(const address_v6& multicast_group,
             unsigned int network_interface = 0) noexcept;
};

Extensible implementations shall provide the following member functions:

class C
{
public:
  template<class Protocol> int level(const Protocol& p) const noexcept;
  template<class Protocol> int name(const Protocol& p) const noexcept;
  template<class Protocol> const void* data(const Protocol& p) const noexcept;
  template<class Protocol> size_t size(const Protocol& p) const noexcept;
  // remainder unchanged
private:
  ip_mreq v4_value_; // exposition only
  ipv6_mreq v6_value_; // exposition only
};

Let L and N identify POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt. In the table below, p denotes a (possibly const) value of a type meeting the protocol requirements, as passed to the socket option's level and name member functions.

Table 40. Multicast group management socket options

C

L if p.family() == AF_INET4

N if p.family() == AF_INET4

L if p.family() == AF_INET6

N if p.family() == AF_INET6

ip::multicast::join_group

IPPROTO_IP

IP_ADD_MEMBERSHIP

IPPROTO_IPV6

IPV6_JOIN_GROUP

ip::multicast::leave_group

IPPROTO_IP

IP_DROP_MEMBERSHIP

IPPROTO_IPV6

IPV6_LEAVE_GROUP


[Note: The constants IPPROTO_IP and IPPROTO_IPV6 are defined in the POSIX header file netinet/in.h. The constants IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP are defined in the POSIX header file netinet/in.h. —end note]

10.20.25.1. Multicast group management socket option constructors

[internet.multicast.group.cons]

explicit C(const address& multicast_group) noexcept;

Effects: If multicast_group.is_v6() is true, calls C(address_cast<address_v6>(multicast_group)); otherwise, calls C(address_cast<address_v4>(multicast_group)).

explicit C(const address_v4& multicast_group,
           const address_v4& network_interface = address_v4::any()) noexcept;

Effects: For extensible implementations, v4_value_.imr_multiaddr is initialized to correspond to the address multicast_group, v4_value_.imr_interface is initialized to correspond to address network_interface, and v6_value_ is zero-initialized.

explicit C(const address_v6& multicast_group,
           unsigned int network_interface = 0) noexcept;

Effects: For extensible implementations, v6_value_.ipv6mr_multiaddr is initialized to correspond to the address multicast_group, v6_value_.ipv6mr_interface is initialized to network_interface, and v4_value_ is zero-initialized.

10.20.25.2. Multicast group management socket option members (extensible implementations)

[internet.multicast.group.extensible]

template<class Protocol> int level(const Protocol& p) const noexcept;

Returns: L.

template<class Protocol> int name(const Protocol& p) const noexcept;

Returns: N.

template<class Protocol> const void* data(const Protocol& p) const noexcept;

Returns: std::addressof(v6_value_) if p.family() == AF_INET6, otherwise std::addressof(v4_value_).

template<class Protocol> size_t size(const Protocol& p) const noexcept;

Returns: sizeof(v6_value_) if p.family() == AF_INET6, otherwise sizeof(v4_value_).

10.20.26. Class ip::multicast::outbound_interface

[internet.multicast.outbound]

The outbound_interface class represents a socket option that specifies the network interface to use for outgoing multicast datagrams.

outbound_interface satisfies the requirements for Destructible (C++ Std, [destructible]), CopyConstructible (C++ Std, [copyconstructible]), Assignable (C++ Std, [assignable]), and SettableSocketOption.

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {
        namespace multicast {

          class outbound_interface
          {
          public:
            // constructors:
            explicit outbound_interface(const address_v4& network_interface) noexcept;
            explicit outbound_interface(unsigned int network_interface) noexcept;
          };

        } // namespace multicast
      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Extensible implementations shall provide the following member functions:

namespace std {
  namespace experimental {
    inline namespace network_v1 {
      namespace ip {
        namespace multicast {

          class outbound_interface
          {
          public:
            template<class Protocol> int level(const Protocol& p) const noexcept;
            template<class Protocol> int name(const Protocol& p) const noexcept;
            template<class Protocol> const void* data(const Protocol& p) const noexcept;
            template<class Protocol> size_t size(const Protocol& p) const noexcept;
            // remainder unchanged
          private:
              in_addr v4_value_; // exposition only
              unsigned int v6_value_; // exposition only
          };

        } // namespace multicast
      } // namespace ip
    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Let L and N identify POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt. In the table below, p denotes a (possibly const) value of a type meeting the protocol requirements, as passed to the socket option's level and name member functions.

Table 41. outbound_interface socket option

L if p.family() == AF_INET4

N if p.family() == AF_INET4

L if p.family() == AF_INET6

N if p.family() == AF_INET6

IPPROTO_IP

IP_MULTICAST_TTL

IPPROTO_IPV6

IPV6_MULTICAST_HOPS


[Note: The constants IPPROTO_IP, IPPROTO_IPV6, and IPV6_MULTICAST_IF are defined in the POSIX header file netinet/in.h. —end note]

10.20.26.1. ip::multicast::outbound_interface constructors

[internet.multicast.outbound.cons]

explicit outbound_interface(const address_v4& network_interface) noexcept;

Effects: For extensible implementations, v4_value_ is initialized to correspond to the IPv4 address network_interface, and v6_value_ is zero-initialized.

explicit outbound_interface(unsigned int network_interface) noexcept;

Effects: For extensible implementations, v6_value_ is initialized to network_interface, and v4_value_ is zero-initialized.

10.20.26.2. ip::multicast::outbound_interface members (extensible implementations)

[internet.multicast.outbound.extensible]

template<class Protocol> int level(const Protocol& p) const noexcept;

Returns: L.

template<class Protocol> int name(const Protocol& p) const noexcept;

Returns: N.

template<class Protocol> const void* data(const Protocol& p) const noexcept;

Returns: std::addressof(v6_value_) if p.family() == AF_INET6, otherwise std::addressof(v4_value_).

template<class Protocol> size_t size(const Protocol& p) const noexcept;

Returns: sizeof(v6_value_) if p.family() == AF_INET6, otherwise sizeof(v4_value_).

10.20.27. Class ip::multicast::hops

[internet.multicast.hops]

The hops class represents a socket option for specifying the default number of hops (also known as time-to-live or TTL) on outbound multicast datagrams. It is defined as an integral socket option.

L and N identify POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt. In the table below, p denotes a (possibly const) value of a type meeting the protocol requirements, as passed to the socket option's level and name member functions.

Table 42. hops integral socket option

C

L if p.family() == AF_INET4

N if p.family() == AF_INET4

L if p.family() == AF_INET6

N if p.family() == AF_INET6

ip::multicast::hops

IPPROTO_IP

IP_MULTICAST_TTL

IPPROTO_IPV6

IPV6_MULTICAST_HOPS


[Note: The constants IPPROTO_IP, IPPROTO_IPV6 and IPV6_MULTICAST_HOPS are defined in the POSIX header file netinet/in.h. —end note]

Constructors for the hops class shall throw out_of_range if the argument is not in the range [0, 255].

10.20.28. Class ip::multicast::enable_loopback

[internet.multicast.enable.loopback]

The enable_loopback class represents a socket option for determining whether multicast datagrams are delivered back to the local application. It is defined as a boolean socket option.

L and N identify POSIX macros to be passed as the level and option_name arguments, respectively, to POSIX setsockopt and getsockopt. In the table below, p denotes a (possibly const) value of a type meeting the protocol requirements, as passed to the socket option's level and name member functions.

Table 43. enable_loopback boolean socket option

C

L if p.family() == AF_INET4

N if p.family() == AF_INET4

L if p.family() == AF_INET6

N if p.family() == AF_INET6

ip::multicast::enable_loopback

IPPROTO_IP

IP_MULTICAST_LOOP

IPPROTO_IPV6

IPV6_MULTICAST_LOOP


[Note: The constants IPPROTO_IP, IPPROTO_IPV6 and IPV6_MULTICAST_LOOP are defined in the POSIX header file netinet/in.h. —end note]

10.21. Index

Cross references

A

async, Asynchronous model
async.assoc.alloc, Class template associated_allocator
async.assoc.alloc.get, Function get_associated_allocator
async.assoc.alloc.members, associated_allocator members
async.assoc.exec, Class template associated_executor
async.assoc.exec.get, Function get_associated_executor
async.assoc.exec.members, associated_executor members
async.async.completion, Class template async_completion
async.async.completion.members, async_completion members
async.async.result, Class template async_result
async.bad.exec, Class bad_executor
async.defer, Function defer
async.dispatch, Function dispatch
async.exec.ctx, Class execution_context
async.exec.ctx.cons, execution_context constructor
async.exec.ctx.dtor, execution_context destructor
async.exec.ctx.globals, execution_context globals
async.exec.ctx.ops, execution_context operations
async.exec.ctx.protected, execution_context protected operations
async.exec.ctx.svc, Class execution_context::service
async.exec.ctx.svc.members, execution_context::service members
async.exec.work, Class template executor_work
async.exec.work.members, executor_work members
async.exec.wrapper, Class template executor_wrapper
async.exec.wrapper.access, executor_wrapper access
async.exec.wrapper.assoc.alloc, Class template partial specialization associated_allocator
async.exec.wrapper.assoc.exec, Class template partial specialization associated_executor
async.exec.wrapper.async.result, Class template partial specialization async_result
async.exec.wrapper.cons, executor_wrapper constructors
async.exec.wrapper.invocation, executor_wrapper invocation
async.executor, Class executor
async.executor.algo, executor specialized algorithms
async.executor.arg, Executor argument tag
async.executor.assign, executor assignment
async.executor.capacity, executor capacity
async.executor.comparisons, executor comparisons
async.executor.cons, executor constructors
async.executor.dtor, executor destructor
async.executor.modifiers, executor modifiers
async.executor.ops, executor operations
async.executor.target, executor target access
async.handler.type, Class template completion_handler_type
async.is.exec, Class template is_executor
async.make.work, Function make_work
async.package, Function package
async.package.handler, Class template packaged_handler
async.package.handler.async.result, Partial class template specialization async_result
async.package.handler.members, packaged_handler members
async.package.token, Class template packaged_token
async.package.token.members, packaged_token members
async.packaged.task.specializations, Partial class template specialization async_result for packaged_task
async.post, Function post
async.reqmts, Requirements
async.reqmts.async, Requirements on asynchronous operations
async.reqmts.async.alloc, Allocation of intermediate storage
async.reqmts.async.assoc.exec, Associated executor
async.reqmts.async.completion, Execution of completion handler on completion of asynchronous operation
async.reqmts.async.exceptions, Completion handlers and exceptions
async.reqmts.async.handler.exec, Completion handler executor
async.reqmts.async.io.exec, I/O executor
async.reqmts.async.lifetime, Lifetime of initiating function arguments
async.reqmts.async.return.type, Automatic deduction of initiating function return type
async.reqmts.async.return.value, Production of initiating function return value
async.reqmts.async.token, Completion tokens and handlers
async.reqmts.async.work, Outstanding work
async.reqmts.executioncontext, Execution context requirements
async.reqmts.executor, Executor requirements
async.reqmts.proto.allocator, Proto-allocator requirements
async.reqmts.service, Service requirements
async.reqmts.signature, Signature requirements
async.strand, Class template strand
async.strand.assign, strand assignment
async.strand.comparisons, strand comparisons
async.strand.cons, strand constructors
async.strand.dtor, strand destructor
async.strand.ops, strand operations
async.synop, Header <experimental/executor> synopsis
async.system.exec, Class system_executor
async.system.exec.comparisons, system_executor comparisons
async.system.exec.ops, system_executor operations
async.use.future, Class template use_future_t
async.use.future.cons, use_future_t constructors
async.use.future.members, use_future_t members
async.use.future.traits, use_future_t traits
async.uses.executor, uses_executor
async.uses.executor.cons, uses-executor construction
async.uses.executor.trait, uses_executor trait
async.wrap, Function wrap

B

buffer, Buffers
buffer.arithmetic, Buffer arithmetic
buffer.async.read, Asynchronous read operations
buffer.async.read.until, Asynchronous delimited read operations
buffer.async.write, Asynchronous write operations
buffer.cast, Function buffer_cast
buffer.const, Class const_buffer
buffer.const.1, Class const_buffers_1
buffer.const.1.cons, const_buffers_1 constructors
buffer.const.1.members, const_buffers_1 members
buffer.const.cons, const_buffer constructors
buffer.copy, Function buffer_copy
buffer.creation, Buffer creation functions
buffer.dynamic.creation, Dynamic buffer creation functions
buffer.dynamic.string, Class template dynamic_string_buffer
buffer.dynamic.string.cons, dynamic_string_buffer constructors
buffer.dynamic.string.members, dynamic_string_buffer members
buffer.dynamic.vector, Class template dynamic_vector_buffer
buffer.dynamic.vector.cons, dynamic_vector_buffer constructors
buffer.dynamic.vector.members, dynamic_vector_buffer members
buffer.mutable, Class mutable_buffer
buffer.mutable.1, Class mutable_buffers_1
buffer.mutable.1.cons, mutable_buffers_1 constructors
buffer.mutable.1.members, mutable_buffers_1 members
buffer.mutable.cons, mutable_buffer constructors
buffer.read, Synchronous read operations
buffer.read.until, Synchronous delimited read operations
buffer.reqmts, Requirements
buffer.reqmts.async.read, Requirements on asynchronous read operations
buffer.reqmts.async.write, Requirements on asynchronous write operations
buffer.reqmts.asyncreadstream, Buffer-oriented asynchronous read stream requirements
buffer.reqmts.asyncwritestream, Buffer-oriented asynchronous write stream requirements
buffer.reqmts.constbuffersequence, Constant buffer sequence requirements
buffer.reqmts.dynamicbuffer, Dynamic buffer requirements
buffer.reqmts.mutablebuffersequence, Mutable buffer sequence requirements
buffer.reqmts.sync.read, Requirements on synchronous read operations
buffer.reqmts.sync.write, Requirements on synchronous write operations
buffer.reqmts.syncreadstream, Buffer-oriented synchronous read stream requirements
buffer.reqmts.syncwritestream, Buffer-oriented synchronous write stream requirements
buffer.size, Function buffer_size
buffer.synop, Header <experimental/buffer> synopsis
buffer.traits, Buffer type traits
buffer.transfer.all, Class transfer_all
buffer.transfer.at.least, Class transfer_at_least
buffer.transfer.exactly, Class transfer_exactly
buffer.write, Synchronous write operations

C

conformance, Conformance
conformance.9945, POSIX conformance
conformance.conditional, Conditionally-supported features
convenience.hdr, Convenience header
convenience.hdr.synop, Header <experimental/networking> synopsis

D

defs, Definitions
defs.async.op, asynchronous operation
defs.host.byte.order, host byte order
defs.net.byte.order, network byte order
defs.sync.op, synchronous operation
description, Method of description (Informative)

E

err.report, Error reporting
err.report.async, Asynchronous operations
err.report.conditions, Error conditions
err.report.sync, Synchronous operations

I

internet, Internet protocol
internet.address, Class ip::address
internet.address.assign, ip::address assignment
internet.address.cast, Function ip::address_cast
internet.address.comparisons, ip::address comparisons
internet.address.cons, ip::address constructors
internet.address.creation, ip::address creation
internet.address.io, ip::address I/O
internet.address.iter, Class template ip::basic_address_iterator specializations
internet.address.members, ip::address members
internet.address.range, Class template ip::basic_address_range specializations
internet.address.v4, Class ip::address_v4
internet.address.v4.assign, ip::address_v4 assignment
internet.address.v4.bytes, Struct ip::address_v4::bytes_type
internet.address.v4.comparisons, ip::address_v4 comparisons
internet.address.v4.cons, ip::address_v4 constructors
internet.address.v4.creation, ip::address_v4 creation
internet.address.v4.io, ip::address_v4 I/O
internet.address.v4.members, ip::address_v4 members
internet.address.v4.static, ip::address_v4 static members
internet.address.v6, Class ip::address_v6
internet.address.v6.assign, ip::address_v6 assignment
internet.address.v6.bytes, Struct ip::address_v6::bytes_type
internet.address.v6.comparisons, ip::address_v6 comparisons
internet.address.v6.cons, ip::address_v6 constructors
internet.address.v6.creation, ip::address_v6 creation
internet.address.v6.io, ip::address_v6 I/O
internet.address.v6.members, ip::address_v6 members
internet.address.v6.static, ip::address_v6 static members
internet.bad.address.cast, Class ip::bad_address_cast
internet.endpoint, Class template ip::basic_endpoint
internet.endpoint.comparisons, ip::basic_endpoint comparisons
internet.endpoint.cons, ip::basic_endpoint constructors
internet.endpoint.extensible, ip::basic_endpoint members (extensible implementations)
internet.endpoint.io, ip::basic_endpoint I/O
internet.endpoint.members, ip::basic_endpoint members
internet.hash, Hash support
internet.host.name, Host name functions
internet.multicast.enable.loopback, Class ip::multicast::enable_loopback
internet.multicast.group, Multicast group management socket options
internet.multicast.group.cons, Multicast group management socket option constructors
internet.multicast.group.extensible, Multicast group management socket option members (extensible implementations)
internet.multicast.hops, Class ip::multicast::hops
internet.multicast.outbound, Class ip::multicast::outbound_interface
internet.multicast.outbound.cons, ip::multicast::outbound_interface constructors
internet.multicast.outbound.extensible, ip::multicast::outbound_interface members (extensible implementations)
internet.network.v4, Class template ip::network_v4
internet.network.v4.comparisons, ip::network_v4 comparisons
internet.network.v4.cons, ip::network_v4 constructors
internet.network.v4.creation, ip::network_v4 creation
internet.network.v4.io, ip::network_v4 I/O
internet.network.v4.members, ip::network_v4 members
internet.network.v6, Class template ip::network_v6
internet.network.v6.comparisons, ip::network_v6 comparisons
internet.network.v6.cons, ip::network_v6 constructors
internet.network.v6.creation, ip::network_v6 creation
internet.network.v6.io, ip::network_v6 I/O
internet.network.v6.members, ip::network_v6 members
internet.reqmts, Requirements
internet.reqmts.protocol, Internet protocol requirements
internet.resolver, Class template ip::basic_resolver
internet.resolver.assign, ip::basic_resolver assignment
internet.resolver.base, Class ip::resolver_base
internet.resolver.cons, ip::basic_resolver constructors
internet.resolver.dtor, ip::basic_resolver destructor
internet.resolver.entry, Class template ip::basic_resolver_entry
internet.resolver.entry.comparisons, op::basic_resolver_entry comparisons
internet.resolver.entry.cons, ip::basic_resolver_entry constructors
internet.resolver.entry.members, ip::basic_resolver_entry members
internet.resolver.err, Error codes
internet.resolver.ops, ip::basic_resolver operations
internet.resolver.results, Class template ip::basic_resolver_results
internet.resolver.results.access, ip::basic_resolver_results element access
internet.resolver.results.assign, ip::basic_resolver_results assignment
internet.resolver.results.comparisons, ip::basic_resolver_results comparisons
internet.resolver.results.cons, ip::basic_resolver_results constructors
internet.resolver.results.size, ip::basic_resolver_results size
internet.resolver.results.swap, ip::basic_resolver_results swap
internet.synop, Header <experimental/internet> synopsis
internet.tcp, Class ip::tcp
internet.tcp.comparisons, ip::tcp comparisons
internet.tcp.nodelay, Class ip::tcp::no_delay
internet.udp, Class ip::udp
internet.udp.comparisons, ip::udp comparisons
internet.unicast.hops, Class ip::unicast::hops
internet.v6only, Class ip::v6_only
io_service, Basic I/O services
io_service.exec, Class io_service::executor_type
io_service.exec.assign, io_service::executor_type assignment
io_service.exec.comparisons, io_service::executor_type comparisons
io_service.exec.cons, io_service::executor_type constructors
io_service.exec.ops, io_service::executor_type operations
io_service.io_service, Class io_service
io_service.io_service.members, io_service members
io_service.synop, Header <experimental/io_service> synopsis

S

scope, Scope
socket, Sockets
socket.acceptor, Class template basic_socket_acceptor
socket.acceptor.assign, basic_socket_acceptor assignment
socket.acceptor.cons, basic_socket_acceptor constructors
socket.acceptor.dtor, basic_socket_acceptor destructor
socket.acceptor.ops, basic_socket_acceptor operations
socket.algo, Socket algorithms
socket.algo.async.connect, Asynchronous connect operations
socket.algo.connect, Synchronous connect operations
socket.base, Class socket_base
socket.base.int.extensible, Integral socket option members (extensible implementations)
socket.basic, Class template basic_socket
socket.basic.assign, basic_socket assignment
socket.basic.cons, basic_socket constructors
socket.basic.dtor, basic_socket destructor
socket.basic.ops, basic_socket operations
socket.dgram, Class template basic_datagram_socket
socket.dgram.assign, basic_datagram_socket assignment
socket.dgram.cons, basic_datagram_socket constructors
socket.dgram.op, basic_datagram_socket operations
socket.err, Error codes
socket.iostream, Class template basic_socket_iostream
socket.iostream.cons, basic_socket_iostream constructors
socket.iostream.members, basic_socket_iostream members
socket.iostreams, Socket iostreams
socket.opt.bool, Boolean socket options
socket.opt.bool.cons, Boolean socket option constructors
socket.opt.bool.extensible, Boolean socket option members (extensible implementations)
socket.opt.bool.members, Boolean socket option members
socket.opt.int, Integral socket options
socket.opt.int.cons, Integral socket option constructors
socket.opt.int.members, Integral socket option members
socket.opt.linger, Class socket_base::linger
socket.opt.linger.cons, socket_base::linger constructors
socket.opt.linger.extensible, socket_base::linger members (extensible implementations)
socket.opt.linger.members, socket_base::linger members
socket.reqmts, Requirements
socket.reqmts.acceptableprotocol, Acceptable protocol requirements
socket.reqmts.connectcondition, Connect condition requirements
socket.reqmts.endpoint, Endpoint requirements
socket.reqmts.gettablesocketoption, Gettable socket option requirements
socket.reqmts.iocontrolcommand, I/O control command requirements
socket.reqmts.native, Native handles
socket.reqmts.protocol, Protocol requirements
socket.reqmts.settablesocketoption, Settable socket option requirements
socket.stream, Class template basic_stream_socket
socket.stream.assign, basic_stream_socket assignment
socket.stream.cons, basic_stream_socket constructors
socket.stream.ops, basic_stream_socket operations
socket.streambuf, Class template basic_socket_streambuf
socket.streambuf.cons, basic_socket_streambuf constructors
socket.streambuf.members, basic_socket_streambuf members
socket.streambuf.virtual, basic_socket_streambuf overridden virtual functions
socket.synop, Header <experimental/socket> synopsis
structure, Structure of each clause
structure.specifications, Detailed specifications
summary, Library summary

T

timer, Timers
timer.reqmts, Requirements
timer.reqmts.waittraits, Wait traits requirements
timer.synop, Header <experimental/timer> synopsis
timer.waitable, Class template basic_waitable_timer
timer.waitable.assign, basic_waitable_timer assignment
timer.waitable.cons, basic_waitable_timer constructors
timer.waitable.dtor, basic_waitable_timer destructor
timer.waitable.ops, basic_waitable_timer operations

11. Acknowledgements

In the eleven years since Asio's inception, hundreds of people have contributed to its development through design review, patches, feature suggestions, bug reports, and usage feedback from the field. With respect to the 2014 refresh of the Networking Library Proposal, the author would particularly like to thank Jamie Allsop for providing feedback during the drafting process, and Oliver Kowalke for contributing towards the design and implementation of the CIDR support.

Thanks go to Marshall Clow, Jens Maurer, Arash Partow, Jamie Allsop, Dietmar Kühl, Detlef Vollmann, Jonathan Wakely, Mikael Kilpeläinen, Jens Weller, Michael Wong, Eric Fisselier, and Jeffrey Yasskin for participating in the Cologne wording review, and also to Roger Orr for some pre-Cologne review feedback.

12. References

[POSIX] ISO/IEC 9945:2003, IEEE Std 1003.1-2001, and The Open Group Base Specifications, Issue 6. Also known as The Single Unix Specification, Version 3.

[N4045] Kohlhoff, Christopher, Library Foundations for Asynchronous Operations, Revision 2, 2014.

[N4242] Kohlhoff, Christopher, Executors and Asynchronous Operations, Revision 1, 2014.

[N4099] Draft Filesystem Technical Specification, 2014.

[ACE] Schmidt, Douglas C., ADAPTIVE Communication Environment, http://www.cs.wustl.edu/~schmidt/ACE.html.

[SYMBIAN] Symbian Ltd, Sockets Client, http://www.symbian.com/developer/techlib/v70sdocs/doc_source/reference/cpp/SocketsClient/index.html.

[MS-NET] Microsoft Corporation, .NET Framework Class Library, Socket Class, http://msdn2.microsoft.com/en-us/library/system.net.sockets.socket.aspx.

[ES-API] The Interconnect Software Consortium / The Open Group, Extended Sockets API (ES-API), Issue 1.0, 2005, http://opengroup.org/icsc/uploads/40/6415/ES_API_1_0.pdf.

[UNPV1] Stevens, W. Richard, UNIX Network Programming, Volume 1, 2nd Edition, Prentice Hall, 1998.

[POSA2] Schmidt, Douglas C. et al, Pattern Oriented Software Architecture, Volume 2, Wiley, 2000.

[RFC821] Postel, J., RFC 821: Simple Mail Transfer Protocol, 1982, http://www.ietf.org/rfc/rfc0821.txt.

[RFC959] Postel, J. and Reynolds, J., RFC 959: File Transfer Protocol (FTP), 1985, http://www.ietf.org/rfc/rfc0959.txt.

[RFC2616] Fielding, R. et al, RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1, 1999, http://www.ietf.org/rfc/rfc2616.txt.

[RFC2732] Hinden, R., Carpenter, B. and Masinter, L., RFC 2732: Format for Literal IPv6 Addresses in URL's, 1999, http://www.ietf.org/rfc/rfc2732.txt.

[RFC3513] Hinden, R. and Deering, S., RFC 3513: Internet Protocol Version 6 (IPv6) Addressing Architecture, 2003, http://www.ietf.org/rfc/rfc3513.txt.



[1] POSIX® is a registered trademark of The IEEE. Windows® is a registered trademark of Microsoft Corporation. This information is given for the convenience of users of this document and does not constitute an endorsement by ISO or IEC of these products.