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 #include "quiche/quic/core/io/socket.h"
6
7 #include <cerrno>
8 #include <climits>
9 #include <cstddef>
10
11 #include "absl/container/flat_hash_set.h"
12 #include "absl/status/status.h"
13 #include "absl/status/statusor.h"
14 #include "absl/strings/string_view.h"
15 #include "absl/types/span.h"
16 #include "quiche/quic/core/io/socket_internal.h"
17 #include "quiche/quic/core/quic_types.h"
18 #include "quiche/quic/platform/api/quic_socket_address.h"
19 #include "quiche/common/platform/api/quiche_logging.h"
20
21 #if defined(_WIN32)
22 #include "quiche/quic/core/io/socket_win.inc"
23 #else
24 #include "quiche/quic/core/io/socket_posix.inc"
25 #endif
26
27 namespace quic::socket_api {
28
29 namespace {
30
AcceptInternal(SocketFd fd)31 absl::StatusOr<AcceptResult> AcceptInternal(SocketFd fd) {
32 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
33
34 sockaddr_storage peer_addr;
35 PlatformSocklen peer_addr_len = sizeof(peer_addr);
36 SocketFd connection_socket = SyscallAccept(
37 fd, reinterpret_cast<struct sockaddr*>(&peer_addr), &peer_addr_len);
38
39 if (connection_socket == kInvalidSocketFd) {
40 absl::Status status = LastSocketOperationError("::accept()");
41 QUICHE_DVLOG(1) << "Failed to accept connection from socket " << fd
42 << " with error: " << status;
43 return status;
44 }
45
46 absl::StatusOr<QuicSocketAddress> peer_address =
47 ValidateAndConvertAddress(peer_addr, peer_addr_len);
48
49 if (peer_address.ok()) {
50 return AcceptResult{connection_socket, *peer_address};
51 } else {
52 return peer_address.status();
53 }
54 }
55
SetSockOptInt(SocketFd fd,int level,int option,int value)56 absl::Status SetSockOptInt(SocketFd fd, int level, int option, int value) {
57 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
58
59 int result = SyscallSetsockopt(fd, level, option, &value, sizeof(value));
60
61 if (result >= 0) {
62 return absl::OkStatus();
63 } else {
64 absl::Status status = LastSocketOperationError("::setsockopt()");
65 QUICHE_DVLOG(1) << "Failed to set socket " << fd << " option " << option
66 << " to " << value << " with error: " << status;
67 return status;
68 }
69 }
70
71 } // namespace
72
SetReceiveBufferSize(SocketFd fd,QuicByteCount size)73 absl::Status SetReceiveBufferSize(SocketFd fd, QuicByteCount size) {
74 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
75 QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
76
77 return SetSockOptInt(fd, SOL_SOCKET, SO_RCVBUF, static_cast<int>(size));
78 }
79
SetSendBufferSize(SocketFd fd,QuicByteCount size)80 absl::Status SetSendBufferSize(SocketFd fd, QuicByteCount size) {
81 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
82 QUICHE_DCHECK_LE(size, QuicByteCount{INT_MAX});
83
84 return SetSockOptInt(fd, SOL_SOCKET, SO_SNDBUF, static_cast<int>(size));
85 }
86
Connect(SocketFd fd,const QuicSocketAddress & peer_address)87 absl::Status Connect(SocketFd fd, const QuicSocketAddress& peer_address) {
88 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
89 QUICHE_DCHECK(peer_address.IsInitialized());
90
91 sockaddr_storage addr = peer_address.generic_address();
92 PlatformSocklen addrlen = GetAddrlen(peer_address.host().address_family());
93
94 int connect_result =
95 SyscallConnect(fd, reinterpret_cast<sockaddr*>(&addr), addrlen);
96
97 if (connect_result >= 0) {
98 return absl::OkStatus();
99 } else {
100 // For ::connect(), only `EINPROGRESS` indicates unavailable.
101 absl::Status status =
102 LastSocketOperationError("::connect()", /*unavailable_error_numbers=*/
103 {EINPROGRESS});
104 QUICHE_DVLOG(1) << "Failed to connect socket " << fd
105 << " to address: " << peer_address.ToString()
106 << " with error: " << status;
107 return status;
108 }
109 }
110
GetSocketError(SocketFd fd)111 absl::Status GetSocketError(SocketFd fd) {
112 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
113
114 int socket_error = 0;
115 PlatformSocklen len = sizeof(socket_error);
116 int sockopt_result =
117 SyscallGetsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &len);
118
119 if (sockopt_result >= 0) {
120 if (socket_error == 0) {
121 return absl::OkStatus();
122 } else {
123 return ToStatus(socket_error, "SO_ERROR");
124 }
125 } else {
126 absl::Status status = LastSocketOperationError("::getsockopt()");
127 QUICHE_LOG_FIRST_N(ERROR, 100)
128 << "Failed to get socket error information from socket " << fd
129 << " with error: " << status;
130 return status;
131 }
132 }
133
Bind(SocketFd fd,const QuicSocketAddress & address)134 absl::Status Bind(SocketFd fd, const QuicSocketAddress& address) {
135 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
136 QUICHE_DCHECK(address.IsInitialized());
137
138 sockaddr_storage addr = address.generic_address();
139 PlatformSocklen addr_len = GetAddrlen(address.host().address_family());
140
141 int result = SyscallBind(fd, reinterpret_cast<sockaddr*>(&addr), addr_len);
142
143 if (result >= 0) {
144 return absl::OkStatus();
145 } else {
146 absl::Status status = LastSocketOperationError("::bind()");
147 QUICHE_DVLOG(1) << "Failed to bind socket " << fd
148 << " to address: " << address.ToString()
149 << " with error: " << status;
150 return status;
151 }
152 }
153
GetSocketAddress(SocketFd fd)154 absl::StatusOr<QuicSocketAddress> GetSocketAddress(SocketFd fd) {
155 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
156
157 sockaddr_storage addr;
158 PlatformSocklen addr_len = sizeof(addr);
159
160 int result =
161 SyscallGetsockname(fd, reinterpret_cast<sockaddr*>(&addr), &addr_len);
162
163 if (result >= 0) {
164 return ValidateAndConvertAddress(addr, addr_len);
165 } else {
166 absl::Status status = LastSocketOperationError("::getsockname()");
167 QUICHE_DVLOG(1) << "Failed to get socket " << fd
168 << " name with error: " << status;
169 return status;
170 }
171 }
172
Listen(SocketFd fd,int backlog)173 absl::Status Listen(SocketFd fd, int backlog) {
174 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
175 QUICHE_DCHECK_GT(backlog, 0);
176
177 int result = SyscallListen(fd, backlog);
178
179 if (result >= 0) {
180 return absl::OkStatus();
181 } else {
182 absl::Status status = LastSocketOperationError("::listen()");
183 QUICHE_DVLOG(1) << "Failed to mark socket: " << fd
184 << " to listen with error :" << status;
185 return status;
186 }
187 }
188
Accept(SocketFd fd,bool blocking)189 absl::StatusOr<AcceptResult> Accept(SocketFd fd, bool blocking) {
190 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
191
192 #if defined(HAS_ACCEPT4)
193 if (!blocking) {
194 return AcceptWithFlags(fd, SOCK_NONBLOCK);
195 }
196 #endif
197
198 absl::StatusOr<AcceptResult> accept_result = AcceptInternal(fd);
199 if (!accept_result.ok() || blocking) {
200 return accept_result;
201 }
202
203 #if !defined(__linux__) || !defined(SOCK_NONBLOCK)
204 // If non-blocking could not be set directly on socket acceptance, need to
205 // do it now.
206 absl::Status set_non_blocking_result =
207 SetSocketBlocking(accept_result->fd, /*blocking=*/false);
208 if (!set_non_blocking_result.ok()) {
209 QUICHE_LOG_FIRST_N(ERROR, 100)
210 << "Failed to set socket " << fd << " as non-blocking on acceptance.";
211 if (!Close(accept_result->fd).ok()) {
212 QUICHE_LOG_FIRST_N(ERROR, 100)
213 << "Failed to close socket " << accept_result->fd
214 << " after error setting non-blocking on acceptance.";
215 }
216 return set_non_blocking_result;
217 }
218 #endif
219
220 return accept_result;
221 }
222
Receive(SocketFd fd,absl::Span<char> buffer,bool peek)223 absl::StatusOr<absl::Span<char>> Receive(SocketFd fd, absl::Span<char> buffer,
224 bool peek) {
225 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
226 QUICHE_DCHECK(!buffer.empty());
227
228 PlatformSsizeT num_read = SyscallRecv(fd, buffer.data(), buffer.size(),
229 /*flags=*/peek ? MSG_PEEK : 0);
230
231 if (num_read > 0 && static_cast<size_t>(num_read) > buffer.size()) {
232 QUICHE_LOG_FIRST_N(WARNING, 100)
233 << "Received more bytes (" << num_read << ") from socket " << fd
234 << " than buffer size (" << buffer.size() << ").";
235 return absl::OutOfRangeError(
236 "::recv(): Received more bytes than buffer size.");
237 } else if (num_read >= 0) {
238 return buffer.subspan(0, num_read);
239 } else {
240 absl::Status status = LastSocketOperationError("::recv()");
241 QUICHE_DVLOG(1) << "Failed to receive from socket: " << fd
242 << " with error: " << status;
243 return status;
244 }
245 }
246
Send(SocketFd fd,absl::string_view buffer)247 absl::StatusOr<absl::string_view> Send(SocketFd fd, absl::string_view buffer) {
248 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
249 QUICHE_DCHECK(!buffer.empty());
250
251 PlatformSsizeT num_sent =
252 SyscallSend(fd, buffer.data(), buffer.size(), /*flags=*/0);
253
254 if (num_sent > 0 && static_cast<size_t>(num_sent) > buffer.size()) {
255 QUICHE_LOG_FIRST_N(WARNING, 100)
256 << "Sent more bytes (" << num_sent << ") to socket " << fd
257 << " than buffer size (" << buffer.size() << ").";
258 return absl::OutOfRangeError("::send(): Sent more bytes than buffer size.");
259 } else if (num_sent >= 0) {
260 return buffer.substr(num_sent);
261 } else {
262 absl::Status status = LastSocketOperationError("::send()");
263 QUICHE_DVLOG(1) << "Failed to send to socket: " << fd
264 << " with error: " << status;
265 return status;
266 }
267 }
268
SendTo(SocketFd fd,const QuicSocketAddress & peer_address,absl::string_view buffer)269 absl::StatusOr<absl::string_view> SendTo(SocketFd fd,
270 const QuicSocketAddress& peer_address,
271 absl::string_view buffer) {
272 QUICHE_DCHECK_NE(fd, kInvalidSocketFd);
273 QUICHE_DCHECK(peer_address.IsInitialized());
274 QUICHE_DCHECK(!buffer.empty());
275
276 sockaddr_storage addr = peer_address.generic_address();
277 PlatformSocklen addrlen = GetAddrlen(peer_address.host().address_family());
278
279 PlatformSsizeT num_sent =
280 SyscallSendTo(fd, buffer.data(), buffer.size(),
281 /*flags=*/0, reinterpret_cast<sockaddr*>(&addr), addrlen);
282
283 if (num_sent > 0 && static_cast<size_t>(num_sent) > buffer.size()) {
284 QUICHE_LOG_FIRST_N(WARNING, 100)
285 << "Sent more bytes (" << num_sent << ") to socket " << fd
286 << " to address: " << peer_address.ToString() << " than buffer size ("
287 << buffer.size() << ").";
288 return absl::OutOfRangeError(
289 "::sendto(): Sent more bytes than buffer size.");
290 } else if (num_sent >= 0) {
291 return buffer.substr(num_sent);
292 } else {
293 absl::Status status = LastSocketOperationError("::sendto()");
294 QUICHE_DVLOG(1) << "Failed to send to socket: " << fd
295 << " to address: " << peer_address.ToString()
296 << " with error: " << status;
297 return status;
298 }
299 }
300
301 } // namespace quic::socket_api
302