• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_IO_SOCKET_H_
6 #define QUICHE_QUIC_CORE_IO_SOCKET_H_
7 
8 #include <functional>
9 #include <string>
10 
11 #include "absl/status/status.h"
12 #include "absl/status/statusor.h"
13 #include "absl/strings/string_view.h"
14 #include "absl/types/span.h"
15 #include "quiche/quic/core/quic_types.h"
16 #include "quiche/quic/platform/api/quic_ip_address_family.h"
17 #include "quiche/quic/platform/api/quic_socket_address.h"
18 #include "quiche/common/platform/api/quiche_export.h"
19 
20 #if defined(_WIN32)
21 #include <winsock2.h>
22 #else
23 #include <sys/socket.h>
24 #endif  // defined(_WIN32)
25 
26 namespace quic {
27 
28 #if defined(_WIN32)
29 using SocketFd = SOCKET;
30 inline constexpr SocketFd kInvalidSocketFd = INVALID_SOCKET;
31 inline constexpr int kSocketErrorMsgSize = WSAEMSGSIZE;
32 #else
33 using SocketFd = int;
34 inline constexpr SocketFd kInvalidSocketFd = -1;
35 inline constexpr int kSocketErrorMsgSize = EMSGSIZE;
36 #endif
37 
38 // Low-level platform-agnostic socket operations. Closely follows the behavior
39 // of basic POSIX socket APIs, diverging mostly only to convert to/from cleaner
40 // and platform-agnostic types.
41 namespace socket_api {
42 enum class SocketProtocol {
43   kUdp,
44   kTcp,
45 };
46 
GetProtocolName(SocketProtocol protocol)47 inline absl::string_view GetProtocolName(SocketProtocol protocol) {
48   switch (protocol) {
49     case SocketProtocol::kUdp:
50       return "UDP";
51     case SocketProtocol::kTcp:
52       return "TCP";
53   }
54 
55   return "unknown";
56 }
57 
58 struct AcceptResult {
59   // Socket for interacting with the accepted connection.
60   SocketFd fd;
61 
62   // Address of the connected peer.
63   QuicSocketAddress peer_address;
64 };
65 
66 // Creates a socket with blocking or non-blocking behavior.
67 absl::StatusOr<SocketFd> CreateSocket(IpAddressFamily address_family,
68                                       SocketProtocol protocol,
69                                       bool blocking = false);
70 
71 // Sets socket `fd` to blocking (if `blocking` true) or non-blocking (if
72 // `blocking` false). Must be a change from previous state.
73 absl::Status SetSocketBlocking(SocketFd fd, bool blocking);
74 
75 // Sets buffer sizes for socket `fd` to `size` bytes.
76 absl::Status SetReceiveBufferSize(SocketFd fd, QuicByteCount size);
77 absl::Status SetSendBufferSize(SocketFd fd, QuicByteCount size);
78 
79 // Connects socket `fd` to `peer_address`.  Returns a status with
80 // `absl::StatusCode::kUnavailable` iff the socket is non-blocking and the
81 // connection could not be immediately completed.  The socket will then complete
82 // connecting asynchronously, and on becoming writable, the result can be
83 // checked using GetSocketError().
84 absl::Status Connect(SocketFd fd, const QuicSocketAddress& peer_address);
85 
86 // Gets and clears socket error information for socket `fd`. Note that returned
87 // error could be either the found socket error, or unusually, an error from the
88 // attempt to retrieve error information. Typically used to determine connection
89 // result after asynchronous completion of a Connect() call.
90 absl::Status GetSocketError(SocketFd fd);
91 
92 // Assign `address` to socket `fd`.
93 absl::Status Bind(SocketFd fd, const QuicSocketAddress& address);
94 
95 // Gets the address assigned to socket `fd`.
96 absl::StatusOr<QuicSocketAddress> GetSocketAddress(SocketFd fd);
97 
98 // Marks socket `fd` as a passive socket listening for connection requests.
99 // `backlog` is the maximum number of queued connection requests. Typically
100 // expected to return a status with `absl::StatusCode::InvalidArgumentError`
101 // if `fd` is not a TCP socket.
102 absl::Status Listen(SocketFd fd, int backlog);
103 
104 // Accepts an incoming connection to the listening socket `fd`.  The returned
105 // connection socket will be set as non-blocking iff `blocking` is false.
106 // Typically expected to return a status with
107 // `absl::StatusCode::InvalidArgumentError` if `fd` is not a TCP socket or not
108 // listening for connections.  Returns a status with
109 // `absl::StatusCode::kUnavailable` iff the socket is non-blocking and no
110 // incoming connection could be immediately accepted.
111 absl::StatusOr<AcceptResult> Accept(SocketFd fd, bool blocking = false);
112 
113 // Receives data from socket `fd`. Will fill `buffer.data()` with up to
114 // `buffer.size()` bytes. On success, returns a span pointing to the buffer
115 // but resized to the actual number of bytes received. Returns a status with
116 // `absl::StatusCode::kUnavailable` iff the socket is non-blocking and the
117 // receive operation could not be immediately completed.  If `peek` is true,
118 // received data is not removed from the underlying socket data queue.
119 absl::StatusOr<absl::Span<char>> Receive(SocketFd fd, absl::Span<char> buffer,
120                                          bool peek = false);
121 
122 // Sends some or all of the data in `buffer` to socket `fd`. On success,
123 // returns a string_view pointing to the unsent remainder of the buffer (or an
124 // empty string_view if all of `buffer` was successfully sent). Returns a status
125 // with `absl::StatusCode::kUnavailable` iff the socket is non-blocking and the
126 // send operation could not be immediately completed.
127 absl::StatusOr<absl::string_view> Send(SocketFd fd, absl::string_view buffer);
128 
129 // Closes socket `fd`.
130 absl::Status Close(SocketFd fd);
131 }  // namespace socket_api
132 
133 }  // namespace quic
134 
135 #endif  // QUICHE_QUIC_CORE_IO_SOCKET_H_
136