| // Copyright 2022 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef QUICHE_QUIC_CORE_IO_SOCKET_H_ | 
 | #define QUICHE_QUIC_CORE_IO_SOCKET_H_ | 
 |  | 
 | #include <functional> | 
 | #include <string> | 
 |  | 
 | #include "absl/status/status.h" | 
 | #include "absl/status/statusor.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "absl/types/span.h" | 
 | #include "quiche/quic/core/quic_types.h" | 
 | #include "quiche/quic/platform/api/quic_ip_address_family.h" | 
 | #include "quiche/quic/platform/api/quic_socket_address.h" | 
 | #include "quiche/common/platform/api/quiche_export.h" | 
 | #include "quiche/common/platform/api/quiche_mem_slice.h" | 
 |  | 
 | #if defined(_WIN32) | 
 | #include <winsock2.h> | 
 | #endif  // defined(_WIN32) | 
 |  | 
 | namespace quic { | 
 |  | 
 | #if defined(_WIN32) | 
 | using SocketFd = SOCKET; | 
 | inline constexpr SocketFd kInvalidSocketFd = INVALID_SOCKET; | 
 | #else | 
 | using SocketFd = int; | 
 | inline constexpr SocketFd kInvalidSocketFd = -1; | 
 | #endif | 
 |  | 
 | // A read/write socket. | 
 | // | 
 | // Warning regarding blocking calls: Code in the QUICHE library typically | 
 | // handles IO on a single thread, so if making calls from that typical | 
 | // environment, it would be problematic to make a blocking call and block that | 
 | // single thread. | 
 | class QUICHE_EXPORT_PRIVATE Socket { | 
 |  public: | 
 |   class AsyncVisitor { | 
 |    public: | 
 |     virtual ~AsyncVisitor() = default; | 
 |  | 
 |     // If the operation completed without error, `data` is set to the received | 
 |     // data. | 
 |     virtual void ReceiveComplete( | 
 |         absl::StatusOr<quiche::QuicheMemSlice> data) = 0; | 
 |  | 
 |     virtual void SendComplete(absl::Status status) = 0; | 
 |   }; | 
 |  | 
 |   virtual ~Socket() = default; | 
 |  | 
 |   // Blocking read. Receives and returns a buffer of up to `max_size` bytes from | 
 |   // socket. Returns status on error. | 
 |   virtual absl::StatusOr<quiche::QuicheMemSlice> ReceiveBlocking( | 
 |       QuicByteCount max_size) = 0; | 
 |  | 
 |   // Asynchronous read. Receives up to `max_size` bytes from socket. If | 
 |   // no data is synchronously available to be read, waits until some data is | 
 |   // available or the socket is closed. On completion, calls ReceiveComplete() | 
 |   // on the visitor, potentially before return from ReceiveAsync(). | 
 |   // | 
 |   // After calling, the socket must not be destroyed until ReceiveComplete() is | 
 |   // called. | 
 |   virtual void ReceiveAsync(QuicByteCount max_size) = 0; | 
 |  | 
 |   // Blocking write. Sends all of `data` (potentially via multiple underlying | 
 |   // socket sends). | 
 |   virtual absl::Status SendBlocking(std::string data) = 0; | 
 |   virtual absl::Status SendBlocking(quiche::QuicheMemSlice data) = 0; | 
 |  | 
 |   // Asynchronous write. Sends all of `data` (potentially via multiple | 
 |   // underlying socket sends). On completion, calls SendComplete() on the | 
 |   // visitor, potentially before return from SendAsync(). | 
 |   // | 
 |   // After calling, the socket must not be destroyed until SendComplete() is | 
 |   // called. | 
 |   virtual void SendAsync(std::string data) = 0; | 
 |   virtual void SendAsync(quiche::QuicheMemSlice data) = 0; | 
 | }; | 
 |  | 
 | // Low-level platform-agnostic socket operations. Closely follows the behavior | 
 | // of basic POSIX socket APIs, diverging mostly only to convert to/from cleaner | 
 | // and platform-agnostic types. | 
 | namespace socket_api { | 
 | enum class SocketProtocol { | 
 |   kUdp, | 
 |   kTcp, | 
 | }; | 
 |  | 
 | struct QUICHE_EXPORT_PRIVATE AcceptResult { | 
 |   // Socket for interacting with the accepted connection. | 
 |   SocketFd fd; | 
 |  | 
 |   // Address of the connected peer. | 
 |   QuicSocketAddress peer_address; | 
 | }; | 
 |  | 
 | // Creates a socket with blocking or non-blocking behavior. | 
 | absl::StatusOr<SocketFd> CreateSocket(IpAddressFamily address_family, | 
 |                                       SocketProtocol protocol, | 
 |                                       bool blocking = false); | 
 |  | 
 | // Sets socket `fd` to blocking (if `blocking` true) or non-blocking (if | 
 | // `blocking` false). Must be a change from previous state. | 
 | absl::Status SetSocketBlocking(SocketFd fd, bool blocking); | 
 |  | 
 | // Sets buffer sizes for socket `fd` to `size` bytes. | 
 | absl::Status SetReceiveBufferSize(SocketFd fd, QuicByteCount size); | 
 | absl::Status SetSendBufferSize(SocketFd fd, QuicByteCount size); | 
 |  | 
 | // Connects socket `fd` to `peer_address`.  Returns a status with | 
 | // `absl::StatusCode::kUnavailable` iff the socket is non-blocking and the | 
 | // connection could not be immediately completed.  The socket will then complete | 
 | // connecting asynchronously, and on becoming writable, the result can be | 
 | // checked using GetSocketError(). | 
 | absl::Status Connect(SocketFd fd, const QuicSocketAddress& peer_address); | 
 |  | 
 | // Gets and clears socket error information for socket `fd`. Note that returned | 
 | // error could be either the found socket error, or unusually, an error from the | 
 | // attempt to retrieve error information. Typically used to determine connection | 
 | // result after asynchronous completion of a Connect() call. | 
 | absl::Status GetSocketError(SocketFd fd); | 
 |  | 
 | // Assign `address` to socket `fd`. | 
 | absl::Status Bind(SocketFd fd, const QuicSocketAddress& address); | 
 |  | 
 | // Gets the address assigned to socket `fd`. | 
 | absl::StatusOr<QuicSocketAddress> GetSocketAddress(SocketFd fd); | 
 |  | 
 | // Marks socket `fd` as a passive socket listening for connection requests. | 
 | // `backlog` is the maximum number of queued connection requests. Typically | 
 | // expected to return a status with `absl::StatusCode::InvalidArgumentError` | 
 | // if `fd` is not a TCP socket. | 
 | absl::Status Listen(SocketFd fd, int backlog); | 
 |  | 
 | // Accepts an incoming connection to the listening socket `fd`.  The returned | 
 | // connection socket will be set as non-blocking iff `blocking` is false. | 
 | // Typically expected to return a status with | 
 | // `absl::StatusCode::InvalidArgumentError` if `fd` is not a TCP socket or not | 
 | // listening for connections.  Returns a status with | 
 | // `absl::StatusCode::kUnavailable` iff the socket is non-blocking and no | 
 | // incoming connection could be immediately accepted. | 
 | absl::StatusOr<AcceptResult> Accept(SocketFd fd, bool blocking = false); | 
 |  | 
 | // Receives data from socket `fd`. Will fill `buffer.data()` with up to | 
 | // `buffer.size()` bytes. On success, returns a span pointing to the buffer | 
 | // but resized to the actual number of bytes received. Returns a status with | 
 | // `absl::StatusCode::kUnavailable` iff the socket is non-blocking and the | 
 | // receive operation could not be immediately completed.  If `peek` is true, | 
 | // received data is not removed from the underlying socket data queue. | 
 | absl::StatusOr<absl::Span<char>> Receive(SocketFd fd, absl::Span<char> buffer, | 
 |                                          bool peek = false); | 
 |  | 
 | // Sends some or all of the data in `buffer` to socket `fd`. On success, | 
 | // returns a string_view pointing to the unsent remainder of the buffer (or an | 
 | // empty string_view if all of `buffer` was successfully sent). Returns a status | 
 | // with `absl::StatusCode::kUnavailable` iff the socket is non-blocking and the | 
 | // send operation could not be immediately completed. | 
 | absl::StatusOr<absl::string_view> Send(SocketFd fd, absl::string_view buffer); | 
 |  | 
 | // Closes socket `fd`. | 
 | absl::Status Close(SocketFd fd); | 
 | }  // namespace socket_api | 
 |  | 
 | }  // namespace quic | 
 |  | 
 | #endif  // QUICHE_QUIC_CORE_IO_SOCKET_H_ |