xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/io/socket.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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