xref: /aosp_15_r20/external/cronet/net/socket/socket_posix.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
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 "net/socket/socket_posix.h"
6 
7 #include <errno.h>
8 #include <netinet/in.h>
9 #include <sys/socket.h>
10 
11 #include <memory>
12 #include <utility>
13 
14 #include "base/files/file_util.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback_helpers.h"
17 #include "base/logging.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "base/task/current_thread.h"
20 #include "build/build_config.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/ip_endpoint.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/sockaddr_storage.h"
25 #include "net/base/trace_constants.h"
26 #include "net/base/tracing.h"
27 #include "net/traffic_annotation/network_traffic_annotation.h"
28 
29 #if BUILDFLAG(IS_FUCHSIA)
30 #include <poll.h>
31 #include <sys/ioctl.h>
32 #endif  // BUILDFLAG(IS_FUCHSIA)
33 
34 namespace net {
35 
36 namespace {
37 
MapAcceptError(int os_error)38 int MapAcceptError(int os_error) {
39   switch (os_error) {
40     // If the client aborts the connection before the server calls accept,
41     // POSIX specifies accept should fail with ECONNABORTED. The server can
42     // ignore the error and just call accept again, so we map the error to
43     // ERR_IO_PENDING. See UNIX Network Programming, Vol. 1, 3rd Ed., Sec.
44     // 5.11, "Connection Abort before accept Returns".
45     case ECONNABORTED:
46       return ERR_IO_PENDING;
47     default:
48       return MapSystemError(os_error);
49   }
50 }
51 
MapConnectError(int os_error)52 int MapConnectError(int os_error) {
53   switch (os_error) {
54     case EINPROGRESS:
55       return ERR_IO_PENDING;
56     case EACCES:
57       return ERR_NETWORK_ACCESS_DENIED;
58     case ETIMEDOUT:
59       return ERR_CONNECTION_TIMED_OUT;
60     default: {
61       int net_error = MapSystemError(os_error);
62       if (net_error == ERR_FAILED)
63         return ERR_CONNECTION_FAILED;  // More specific than ERR_FAILED.
64       return net_error;
65     }
66   }
67 }
68 
69 }  // namespace
70 
SocketPosix()71 SocketPosix::SocketPosix()
72     : socket_fd_(kInvalidSocket),
73       accept_socket_watcher_(FROM_HERE),
74       read_socket_watcher_(FROM_HERE),
75       write_socket_watcher_(FROM_HERE) {}
76 
~SocketPosix()77 SocketPosix::~SocketPosix() {
78   Close();
79 }
80 
Open(int address_family)81 int SocketPosix::Open(int address_family) {
82   DCHECK(thread_checker_.CalledOnValidThread());
83   DCHECK_EQ(kInvalidSocket, socket_fd_);
84   DCHECK(address_family == AF_INET ||
85          address_family == AF_INET6 ||
86          address_family == AF_UNIX);
87 
88   socket_fd_ = CreatePlatformSocket(
89       address_family,
90       SOCK_STREAM,
91       address_family == AF_UNIX ? 0 : IPPROTO_TCP);
92   if (socket_fd_ < 0) {
93     PLOG(ERROR) << "CreatePlatformSocket() failed";
94     return MapSystemError(errno);
95   }
96 
97   if (!base::SetNonBlocking(socket_fd_)) {
98     int rv = MapSystemError(errno);
99     Close();
100     return rv;
101   }
102 
103   return OK;
104 }
105 
AdoptConnectedSocket(SocketDescriptor socket,const SockaddrStorage & address)106 int SocketPosix::AdoptConnectedSocket(SocketDescriptor socket,
107                                       const SockaddrStorage& address) {
108   int rv = AdoptUnconnectedSocket(socket);
109   if (rv != OK)
110     return rv;
111 
112   SetPeerAddress(address);
113   return OK;
114 }
115 
AdoptUnconnectedSocket(SocketDescriptor socket)116 int SocketPosix::AdoptUnconnectedSocket(SocketDescriptor socket) {
117   DCHECK(thread_checker_.CalledOnValidThread());
118   DCHECK_EQ(kInvalidSocket, socket_fd_);
119 
120   socket_fd_ = socket;
121 
122   if (!base::SetNonBlocking(socket_fd_)) {
123     int rv = MapSystemError(errno);
124     Close();
125     return rv;
126   }
127 
128   return OK;
129 }
130 
ReleaseConnectedSocket()131 SocketDescriptor SocketPosix::ReleaseConnectedSocket() {
132   // It's not safe to release a socket with a pending write.
133   DCHECK(!write_buf_);
134 
135   StopWatchingAndCleanUp(false /* close_socket */);
136   SocketDescriptor socket_fd = socket_fd_;
137   socket_fd_ = kInvalidSocket;
138   return socket_fd;
139 }
140 
Bind(const SockaddrStorage & address)141 int SocketPosix::Bind(const SockaddrStorage& address) {
142   DCHECK(thread_checker_.CalledOnValidThread());
143   DCHECK_NE(kInvalidSocket, socket_fd_);
144 
145   int rv = bind(socket_fd_, address.addr, address.addr_len);
146   if (rv < 0) {
147     PLOG(ERROR) << "bind() failed";
148     return MapSystemError(errno);
149   }
150 
151   return OK;
152 }
153 
Listen(int backlog)154 int SocketPosix::Listen(int backlog) {
155   DCHECK(thread_checker_.CalledOnValidThread());
156   DCHECK_NE(kInvalidSocket, socket_fd_);
157   DCHECK_LT(0, backlog);
158 
159   int rv = listen(socket_fd_, backlog);
160   if (rv < 0) {
161     PLOG(ERROR) << "listen() failed";
162     return MapSystemError(errno);
163   }
164 
165   return OK;
166 }
167 
Accept(std::unique_ptr<SocketPosix> * socket,CompletionOnceCallback callback)168 int SocketPosix::Accept(std::unique_ptr<SocketPosix>* socket,
169                         CompletionOnceCallback callback) {
170   DCHECK(thread_checker_.CalledOnValidThread());
171   DCHECK_NE(kInvalidSocket, socket_fd_);
172   DCHECK(accept_callback_.is_null());
173   DCHECK(socket);
174   DCHECK(!callback.is_null());
175 
176   int rv = DoAccept(socket);
177   if (rv != ERR_IO_PENDING)
178     return rv;
179 
180   if (!base::CurrentIOThread::Get()->WatchFileDescriptor(
181           socket_fd_, true, base::MessagePumpForIO::WATCH_READ,
182           &accept_socket_watcher_, this)) {
183     PLOG(ERROR) << "WatchFileDescriptor failed on accept";
184     return MapSystemError(errno);
185   }
186 
187   accept_socket_ = socket;
188   accept_callback_ = std::move(callback);
189   return ERR_IO_PENDING;
190 }
191 
Connect(const SockaddrStorage & address,CompletionOnceCallback callback)192 int SocketPosix::Connect(const SockaddrStorage& address,
193                          CompletionOnceCallback callback) {
194   DCHECK(thread_checker_.CalledOnValidThread());
195   DCHECK_NE(kInvalidSocket, socket_fd_);
196   DCHECK(!waiting_connect_);
197   DCHECK(!callback.is_null());
198 
199   SetPeerAddress(address);
200 
201   int rv = DoConnect();
202   if (rv != ERR_IO_PENDING)
203     return rv;
204 
205   if (!base::CurrentIOThread::Get()->WatchFileDescriptor(
206           socket_fd_, true, base::MessagePumpForIO::WATCH_WRITE,
207           &write_socket_watcher_, this)) {
208     PLOG(ERROR) << "WatchFileDescriptor failed on connect";
209     return MapSystemError(errno);
210   }
211 
212   // There is a race-condition in the above code if the kernel receive a RST
213   // packet for the "connect" call before the registration of the socket file
214   // descriptor to the message loop pump. On most platform it is benign as the
215   // message loop pump is awakened for that socket in an error state, but on
216   // iOS this does not happens. Check the status of the socket at this point
217   // and if in error, consider the connection as failed.
218   int os_error = 0;
219   socklen_t len = sizeof(os_error);
220   if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
221     // TCPSocketPosix expects errno to be set.
222     errno = os_error;
223   }
224 
225   rv = MapConnectError(errno);
226   if (rv != OK && rv != ERR_IO_PENDING) {
227     write_socket_watcher_.StopWatchingFileDescriptor();
228     return rv;
229   }
230 
231   write_callback_ = std::move(callback);
232   waiting_connect_ = true;
233   return ERR_IO_PENDING;
234 }
235 
IsConnected() const236 bool SocketPosix::IsConnected() const {
237   DCHECK(thread_checker_.CalledOnValidThread());
238 
239   if (socket_fd_ == kInvalidSocket || waiting_connect_)
240     return false;
241 
242   // Checks if connection is alive.
243   char c;
244   int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
245   if (rv == 0)
246     return false;
247   if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
248     return false;
249 
250   return true;
251 }
252 
IsConnectedAndIdle() const253 bool SocketPosix::IsConnectedAndIdle() const {
254   DCHECK(thread_checker_.CalledOnValidThread());
255 
256   if (socket_fd_ == kInvalidSocket || waiting_connect_)
257     return false;
258 
259   // Check if connection is alive and we haven't received any data
260   // unexpectedly.
261   char c;
262   int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
263   if (rv >= 0)
264     return false;
265   if (errno != EAGAIN && errno != EWOULDBLOCK)
266     return false;
267 
268   return true;
269 }
270 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)271 int SocketPosix::Read(IOBuffer* buf,
272                       int buf_len,
273                       CompletionOnceCallback callback) {
274   // Use base::Unretained() is safe here because OnFileCanReadWithoutBlocking()
275   // won't be called if |this| is gone.
276   int rv = ReadIfReady(
277       buf, buf_len,
278       base::BindOnce(&SocketPosix::RetryRead, base::Unretained(this)));
279   if (rv == ERR_IO_PENDING) {
280     read_buf_ = buf;
281     read_buf_len_ = buf_len;
282     read_callback_ = std::move(callback);
283   }
284   return rv;
285 }
286 
ReadIfReady(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)287 int SocketPosix::ReadIfReady(IOBuffer* buf,
288                              int buf_len,
289                              CompletionOnceCallback callback) {
290   DCHECK(thread_checker_.CalledOnValidThread());
291   DCHECK_NE(kInvalidSocket, socket_fd_);
292   DCHECK(!waiting_connect_);
293   CHECK(read_if_ready_callback_.is_null());
294   DCHECK(!callback.is_null());
295   DCHECK_LT(0, buf_len);
296 
297   int rv = DoRead(buf, buf_len);
298   if (rv != ERR_IO_PENDING)
299     return rv;
300 
301   if (!base::CurrentIOThread::Get()->WatchFileDescriptor(
302           socket_fd_, true, base::MessagePumpForIO::WATCH_READ,
303           &read_socket_watcher_, this)) {
304     PLOG(ERROR) << "WatchFileDescriptor failed on read";
305     return MapSystemError(errno);
306   }
307 
308   read_if_ready_callback_ = std::move(callback);
309   return ERR_IO_PENDING;
310 }
311 
CancelReadIfReady()312 int SocketPosix::CancelReadIfReady() {
313   DCHECK(read_if_ready_callback_);
314 
315   bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
316   DCHECK(ok);
317 
318   read_if_ready_callback_.Reset();
319   return net::OK;
320 }
321 
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag &)322 int SocketPosix::Write(
323     IOBuffer* buf,
324     int buf_len,
325     CompletionOnceCallback callback,
326     const NetworkTrafficAnnotationTag& /* traffic_annotation */) {
327   DCHECK(thread_checker_.CalledOnValidThread());
328   CHECK_NE(kInvalidSocket, socket_fd_);
329   CHECK(!waiting_connect_);
330   CHECK(write_callback_.is_null());
331   // Synchronous operation not supported
332   CHECK(!callback.is_null());
333   CHECK_LT(0, buf_len);
334 
335   int rv = DoWrite(buf, buf_len);
336   if (rv == ERR_IO_PENDING)
337     rv = WaitForWrite(buf, buf_len, std::move(callback));
338   return rv;
339 }
340 
WaitForWrite(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)341 int SocketPosix::WaitForWrite(IOBuffer* buf,
342                               int buf_len,
343                               CompletionOnceCallback callback) {
344   DCHECK(thread_checker_.CalledOnValidThread());
345   DCHECK_NE(kInvalidSocket, socket_fd_);
346   DCHECK(write_callback_.is_null());
347   // Synchronous operation not supported
348   DCHECK(!callback.is_null());
349   DCHECK_LT(0, buf_len);
350 
351   if (!base::CurrentIOThread::Get()->WatchFileDescriptor(
352           socket_fd_, true, base::MessagePumpForIO::WATCH_WRITE,
353           &write_socket_watcher_, this)) {
354     PLOG(ERROR) << "WatchFileDescriptor failed on write";
355     return MapSystemError(errno);
356   }
357 
358   write_buf_ = buf;
359   write_buf_len_ = buf_len;
360   write_callback_ = std::move(callback);
361   return ERR_IO_PENDING;
362 }
363 
GetLocalAddress(SockaddrStorage * address) const364 int SocketPosix::GetLocalAddress(SockaddrStorage* address) const {
365   DCHECK(thread_checker_.CalledOnValidThread());
366   DCHECK(address);
367 
368   if (getsockname(socket_fd_, address->addr, &address->addr_len) < 0)
369     return MapSystemError(errno);
370   return OK;
371 }
372 
GetPeerAddress(SockaddrStorage * address) const373 int SocketPosix::GetPeerAddress(SockaddrStorage* address) const {
374   DCHECK(thread_checker_.CalledOnValidThread());
375   DCHECK(address);
376 
377   if (!HasPeerAddress())
378     return ERR_SOCKET_NOT_CONNECTED;
379 
380   *address = *peer_address_;
381   return OK;
382 }
383 
SetPeerAddress(const SockaddrStorage & address)384 void SocketPosix::SetPeerAddress(const SockaddrStorage& address) {
385   DCHECK(thread_checker_.CalledOnValidThread());
386   // |peer_address_| will be non-nullptr if Connect() has been called. Unless
387   // Close() is called to reset the internal state, a second call to Connect()
388   // is not allowed.
389   // Please note that we don't allow a second Connect() even if the previous
390   // Connect() has failed. Connecting the same |socket_| again after a
391   // connection attempt failed results in unspecified behavior according to
392   // POSIX.
393   DCHECK(!peer_address_);
394   peer_address_ = std::make_unique<SockaddrStorage>(address);
395 }
396 
HasPeerAddress() const397 bool SocketPosix::HasPeerAddress() const {
398   DCHECK(thread_checker_.CalledOnValidThread());
399   return peer_address_ != nullptr;
400 }
401 
Close()402 void SocketPosix::Close() {
403   DCHECK(thread_checker_.CalledOnValidThread());
404 
405   StopWatchingAndCleanUp(true /* close_socket */);
406 }
407 
DetachFromThread()408 void SocketPosix::DetachFromThread() {
409   thread_checker_.DetachFromThread();
410 }
411 
OnFileCanReadWithoutBlocking(int fd)412 void SocketPosix::OnFileCanReadWithoutBlocking(int fd) {
413   TRACE_EVENT0(NetTracingCategory(),
414                "SocketPosix::OnFileCanReadWithoutBlocking");
415   if (!accept_callback_.is_null()) {
416     AcceptCompleted();
417   } else {
418     DCHECK(!read_if_ready_callback_.is_null());
419     ReadCompleted();
420   }
421 }
422 
OnFileCanWriteWithoutBlocking(int fd)423 void SocketPosix::OnFileCanWriteWithoutBlocking(int fd) {
424   DCHECK(!write_callback_.is_null());
425   if (waiting_connect_) {
426     ConnectCompleted();
427   } else {
428     WriteCompleted();
429   }
430 }
431 
DoAccept(std::unique_ptr<SocketPosix> * socket)432 int SocketPosix::DoAccept(std::unique_ptr<SocketPosix>* socket) {
433   SockaddrStorage new_peer_address;
434   int new_socket = HANDLE_EINTR(accept(socket_fd_,
435                                        new_peer_address.addr,
436                                        &new_peer_address.addr_len));
437   if (new_socket < 0)
438     return MapAcceptError(errno);
439 
440   auto accepted_socket = std::make_unique<SocketPosix>();
441   int rv = accepted_socket->AdoptConnectedSocket(new_socket, new_peer_address);
442   if (rv != OK)
443     return rv;
444 
445   *socket = std::move(accepted_socket);
446   return OK;
447 }
448 
AcceptCompleted()449 void SocketPosix::AcceptCompleted() {
450   DCHECK(accept_socket_);
451   int rv = DoAccept(accept_socket_);
452   if (rv == ERR_IO_PENDING)
453     return;
454 
455   bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
456   DCHECK(ok);
457   accept_socket_ = nullptr;
458   std::move(accept_callback_).Run(rv);
459 }
460 
DoConnect()461 int SocketPosix::DoConnect() {
462   int rv = HANDLE_EINTR(connect(socket_fd_,
463                                 peer_address_->addr,
464                                 peer_address_->addr_len));
465   DCHECK_GE(0, rv);
466   return rv == 0 ? OK : MapConnectError(errno);
467 }
468 
ConnectCompleted()469 void SocketPosix::ConnectCompleted() {
470   // Get the error that connect() completed with.
471   int os_error = 0;
472   socklen_t len = sizeof(os_error);
473   if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
474     // TCPSocketPosix expects errno to be set.
475     errno = os_error;
476   }
477 
478   int rv = MapConnectError(errno);
479   if (rv == ERR_IO_PENDING)
480     return;
481 
482   bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
483   DCHECK(ok);
484   waiting_connect_ = false;
485   std::move(write_callback_).Run(rv);
486 }
487 
DoRead(IOBuffer * buf,int buf_len)488 int SocketPosix::DoRead(IOBuffer* buf, int buf_len) {
489   int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len));
490   return rv >= 0 ? rv : MapSystemError(errno);
491 }
492 
RetryRead(int rv)493 void SocketPosix::RetryRead(int rv) {
494   DCHECK(read_callback_);
495   DCHECK(read_buf_);
496   DCHECK_LT(0, read_buf_len_);
497 
498   if (rv == OK) {
499     rv = ReadIfReady(
500         read_buf_.get(), read_buf_len_,
501         base::BindOnce(&SocketPosix::RetryRead, base::Unretained(this)));
502     if (rv == ERR_IO_PENDING)
503       return;
504   }
505   read_buf_ = nullptr;
506   read_buf_len_ = 0;
507   std::move(read_callback_).Run(rv);
508 }
509 
ReadCompleted()510 void SocketPosix::ReadCompleted() {
511   DCHECK(read_if_ready_callback_);
512 
513   bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
514   DCHECK(ok);
515   std::move(read_if_ready_callback_).Run(OK);
516 }
517 
DoWrite(IOBuffer * buf,int buf_len)518 int SocketPosix::DoWrite(IOBuffer* buf, int buf_len) {
519 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
520   // Disable SIGPIPE for this write. Although Chromium globally disables
521   // SIGPIPE, the net stack may be used in other consumers which do not do
522   // this. MSG_NOSIGNAL is a Linux-only API. On OS X, this is a setsockopt on
523   // socket creation.
524   int rv = HANDLE_EINTR(send(socket_fd_, buf->data(), buf_len, MSG_NOSIGNAL));
525 #else
526   int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len));
527 #endif
528   if (rv >= 0) {
529     CHECK_LE(rv, buf_len);
530   }
531   return rv >= 0 ? rv : MapSystemError(errno);
532 }
533 
WriteCompleted()534 void SocketPosix::WriteCompleted() {
535   int rv = DoWrite(write_buf_.get(), write_buf_len_);
536   if (rv == ERR_IO_PENDING)
537     return;
538 
539   bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
540   DCHECK(ok);
541   write_buf_.reset();
542   write_buf_len_ = 0;
543   std::move(write_callback_).Run(rv);
544 }
545 
StopWatchingAndCleanUp(bool close_socket)546 void SocketPosix::StopWatchingAndCleanUp(bool close_socket) {
547   bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
548   DCHECK(ok);
549   ok = read_socket_watcher_.StopWatchingFileDescriptor();
550   DCHECK(ok);
551   ok = write_socket_watcher_.StopWatchingFileDescriptor();
552   DCHECK(ok);
553 
554   // These needs to be done after the StopWatchingFileDescriptor() calls, but
555   // before deleting the write buffer.
556   if (close_socket) {
557     if (socket_fd_ != kInvalidSocket) {
558       if (IGNORE_EINTR(close(socket_fd_)) < 0)
559         DPLOG(ERROR) << "close() failed";
560       socket_fd_ = kInvalidSocket;
561     }
562   }
563 
564   if (!accept_callback_.is_null()) {
565     accept_socket_ = nullptr;
566     accept_callback_.Reset();
567   }
568 
569   if (!read_callback_.is_null()) {
570     read_buf_.reset();
571     read_buf_len_ = 0;
572     read_callback_.Reset();
573   }
574 
575   read_if_ready_callback_.Reset();
576 
577   if (!write_callback_.is_null()) {
578     write_buf_.reset();
579     write_buf_len_ = 0;
580     write_callback_.Reset();
581   }
582 
583   waiting_connect_ = false;
584   peer_address_.reset();
585 }
586 
587 }  // namespace net
588