18 Sockets [socket]

18.9 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 {
namespace net {
inline namespace v1 {

  template<class AcceptableProtocol>
  class basic_socket_acceptor : public socket_base
  {
  public:
    // types:

    using executor_type = io_context::executor_type;
    using native_handle_type = implementation-defined; // see [socket.reqmts.native]
    using protocol_type = AcceptableProtocol;
    using endpoint_type = typename protocol_type::endpoint;
    using socket_type = typename protocol_type::socket;

    // [socket.acceptor.cons], construct / copy / destroy:

    explicit basic_socket_acceptor(io_context& ctx);
    basic_socket_acceptor(io_context& ctx, const protocol_type& protocol);
    basic_socket_acceptor(io_context& ctx, const endpoint_type& endpoint,
                          bool reuse_addr = true);
    basic_socket_acceptor(io_context& ctx, 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);

    // [socket.acceptor.ops], basic_socket_acceptor operations:

    executor_type get_executor() noexcept;

    native_handle_type native_handle(); // see [socket.reqmts.native]

    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 [socket.reqmts.native]
    void assign(const protocol_type& protocol,
                const native_handle_type& native_acceptor,
                error_code& ec); // see [socket.reqmts.native]

    native_handle_type release(); // see [socket.reqmts.native]
    native_handle_type release(error_code& ec); // see [socket.reqmts.native]

    bool is_open() const noexcept;

    void close();
    void close(error_code& ec);

    void cancel();
    void cancel(error_code& ec);

    template<class SettableSocketOption>
      void set_option(const SettableSocketOption& option);
    template<class SettableSocketOption>
      void set_option(const SettableSocketOption& option, error_code& ec);

    template<class GettableSocketOption>
      void get_option(GettableSocketOption& option) const;
    template<class GettableSocketOption>
      void get_option(GettableSocketOption& option, error_code& ec) const;

    template<class IoControlCommand>
      void io_control(IoControlCommand& command);
    template<class IoControlCommand>
      void io_control(IoControlCommand& command, error_code& ec);

    void non_blocking(bool mode);
    void non_blocking(bool mode, error_code& ec);
    bool non_blocking() const;

    void native_non_blocking(bool mode);
    void native_non_blocking(bool mode, error_code& ec);
    bool native_non_blocking() const;

    void bind(const endpoint_type& endpoint);
    void bind(const endpoint_type& endpoint, error_code& ec);

    void listen(int backlog = max_listen_connections);
    void listen(int backlog, error_code& ec);

    endpoint_type local_endpoint() const;
    endpoint_type local_endpoint(error_code& ec) const;

    void enable_connection_aborted(bool mode);
    bool enable_connection_aborted() const;

    socket_type accept();
    socket_type accept(error_code& ec);
    socket_type accept(io_context& ctx);
    socket_type accept(io_context& ctx, error_code& ec);

    template<class CompletionToken>
      DEDUCED async_accept(CompletionToken&& token);
    template<class CompletionToken>
      DEDUCED async_accept(io_context& ctx, CompletionToken&& token);

    socket_type accept(endpoint_type& endpoint);
    socket_type accept(endpoint_type& endpoint, error_code& ec);
    socket_type accept(io_context& ctx, endpoint_type& endpoint);
    socket_type accept(io_context& ctx, endpoint_type& endpoint,
                       error_code& ec);

    template<class CompletionToken>
      DEDUCED async_accept(endpoint_type& endpoint,
                           CompletionToken&& token);
    template<class CompletionToken>
      DEDUCED async_accept(io_context& ctx, 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 v1
} // namespace net
} // namespace experimental
} // namespace std

Instances of class template basic_socket_acceptor meet the requirements of Destructible (C++ 2014 [destructible]), MoveConstructible (C++ 2014 [moveconstructible]), and MoveAssignable (C++ 2014 [moveassignable]).

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.

When an operation has its effects specified as if by passing the result of native_handle() to a POSIX function, then the operation fails with error condition errc::bad_file_descriptor if is_open() == false at the point in the effects when the POSIX function is called.

18.9.1 basic_socket_acceptor constructors [socket.acceptor.cons]

explicit basic_socket_acceptor(io_context& ctx);

Postconditions:

  • get_executor() == ctx.get_executor().

  • is_open() == false.

basic_socket_acceptor(io_context& ctx, const protocol_type& protocol);

Effects: Opens this acceptor as if by calling open(protocol).

Postconditions:

  • get_executor() == ctx.get_executor().

  • is_open() == true.

  • non_blocking() == false.

  • enable_connection_aborted() == false.

  • protocol_ == protocol.

basic_socket_acceptor(io_context& ctx, 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() == ctx.get_executor().

  • is_open() == true.

  • non_blocking() == false.

  • enable_connection_aborted() == false.

  • protocol_ == endpoint.protocol().

basic_socket_acceptor(io_context& ctx, 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() == ctx.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.

  • native_handle() returns the same value as rhs.native_handle() 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.

18.9.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.

18.9.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.

18.9.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.

native_handle_type release(); native_handle_type release(error_code& ec);

Requires: is_open() == true.

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.

Returns: The native representation of this acceptor.

Postconditions: is_open() == false.

Remarks: Since the native acceptor is not closed prior to returning it, the caller is responsible for closing it.

bool is_open() const noexcept;

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. The non-blocking mode determines whether subsequent synchronous socket operations ([socket.reqmts.sync]) on *this block the calling thread.

Error conditions:

  • errc::bad_file_descriptor — if is_open() is false.

Postconditions: non_blocking() == mode.

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_listen_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_context& ctx); socket_type accept(io_context& ctx, 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: On success, socket_type(ctx, protocol_, h). Otherwise socket_type(ctx).

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

Returns:

async_accept(get_executor().context(), forward<CompletionToken>(token))

template<class CompletionToken> DEDUCED async_accept(io_context& ctx, 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(ctx, protocol_, h). Otherwise, s is socket_type(ctx).

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_context& ctx, endpoint_type& endpoint); socket_type accept(io_context& ctx, 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: On success, socket_type(ctx, protocol_, h). Otherwise socket_type(ctx).

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_context& ctx, 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(ctx, protocol_, h). Otherwise, s is socket_type(ctx).

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 outstanding operations 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.