18 Sockets [socket]

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

  template<class Protocol>
  class basic_socket : 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 = Protocol;
    using endpoint_type = typename protocol_type::endpoint;

    // [socket.basic.ops], basic_socket 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_socket); // see [socket.reqmts.native]
    void assign(const protocol_type& protocol,
                const native_handle_type& native_socket,
                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;

    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:
    // [socket.basic.cons], construct / copy / destroy:

    explicit basic_socket(io_context& ctx);
    basic_socket(io_context& ctx, const protocol_type& protocol);
    basic_socket(io_context& ctx, const endpoint_type& endpoint);
    basic_socket(io_context& ctx, const protocol_type& protocol,
                 const native_handle_type& native_socket); // see [socket.reqmts.native]
    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 v1
} // namespace net
} // namespace experimental
} // namespace std

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

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.6.1 basic_socket constructors [socket.basic.cons]

explicit basic_socket(io_context& ctx);

Postconditions:

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

  • is_open() == false.

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

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

Postconditions:

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

  • is_open() == true.

  • non_blocking() == false.

  • protocol_ == protocol.

basic_socket(io_context& ctx, const endpoint_type& endpoint);

Effects: Opens and binds this socket as if by calling:

open(endpoint.protocol());
bind(endpoint);

Postconditions:

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

  • is_open() == true.

  • non_blocking() == false.

  • protocol_ == endpoint.protocol().

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

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

18.6.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() == 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() == 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.

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

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

Requires: is_open() == true.

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.

Returns: The native representation of this socket.

Postconditions: is_open() == false.

Remarks: Since the native socket 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 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.

Remarks: Does not block (C++ 2014 [defns.block]) the calling thread pending completion of the canceled operations.

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. 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 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 is 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. false if an error occurs.

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