blob: 052aed5b4b46cd999cd727b60997c73753440a49 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
[email protected]182c44fa2009-11-26 00:28:022// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/sync_socket.h"
6
7#include <errno.h>
[email protected]5d272092012-04-19 10:23:038#include <fcntl.h>
[email protected]62558f12013-10-19 22:13:199#include <limits.h>
grunellb464b3e2017-05-23 11:15:2610#include <poll.h>
avi9b6f42932015-12-26 22:15:1411#include <stddef.h>
[email protected]182c44fa2009-11-26 00:28:0212#include <stdio.h>
[email protected]1e1f1a72009-12-06 19:45:0813#include <sys/ioctl.h>
[email protected]182c44fa2009-11-26 00:28:0214#include <sys/socket.h>
[email protected]5d272092012-04-19 10:23:0315#include <sys/types.h>
[email protected]182c44fa2009-11-26 00:28:0216
Hans Wennborgc3cffa62020-04-27 10:09:1217#include "base/check_op.h"
Lei Zhangc9e8a162021-05-14 09:33:5218#include "base/containers/span.h"
[email protected]e3177dd52014-08-13 20:22:1419#include "base/files/file_util.h"
Peter Kastinga0b914dc2022-07-14 18:43:1920#include "base/numerics/safe_conversions.h"
Etienne Pierre-Doray3879b052018-09-17 14:17:2221#include "base/threading/scoped_blocking_call.h"
avi9b6f42932015-12-26 22:15:1422#include "build/build_config.h"
[email protected]182c44fa2009-11-26 00:28:0223
Qi Tiezhengf537c422022-09-15 06:58:3424#if BUILDFLAG(IS_SOLARIS)
25#include <sys/filio.h>
26#endif
27
[email protected]182c44fa2009-11-26 00:28:0228namespace base {
29
30namespace {
31// To avoid users sending negative message lengths to Send/Receive
32// we clamp message lengths, which are size_t, to no more than INT_MAX.
33const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
34
[email protected]62558f12013-10-19 22:13:1935// Writes |length| of |buffer| into |handle|. Returns the number of bytes
36// written or zero on error. |length| must be greater than 0.
Austin Sullivanedf168fd2024-01-17 21:37:2037size_t SendHelper(SyncSocket::Handle handle, span<const uint8_t> data) {
38 CHECK_LE(data.size(), kMaxMessageLength);
[email protected]62558f12013-10-19 22:13:1939 DCHECK_NE(handle, SyncSocket::kInvalidHandle);
Austin Sullivanedf168fd2024-01-17 21:37:2040 return WriteFileDescriptor(handle, data) ? data.size() : 0;
[email protected]62558f12013-10-19 22:13:1941}
42
[email protected]182c44fa2009-11-26 00:28:0243} // namespace
44
[email protected]532e9bd2012-01-25 12:04:1745// static
46bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
[email protected]62558f12013-10-19 22:13:1947 DCHECK_NE(socket_a, socket_b);
Robert Sesek6ab73b022020-02-13 16:42:3948 DCHECK(!socket_a->IsValid());
49 DCHECK(!socket_b->IsValid());
[email protected]532e9bd2012-01-25 12:04:1750
Xiaohan Wang38e4ebb2022-01-19 06:57:4351#if BUILDFLAG(IS_APPLE)
[email protected]182c44fa2009-11-26 00:28:0252 int nosigpipe = 1;
Xiaohan Wang38e4ebb2022-01-19 06:57:4353#endif // BUILDFLAG(IS_APPLE)
[email protected]182c44fa2009-11-26 00:28:0254
Robert Sesek6ab73b022020-02-13 16:42:3955 ScopedHandle handles[2];
56
57 {
58 Handle raw_handles[2] = {kInvalidHandle, kInvalidHandle};
59 if (socketpair(AF_UNIX, SOCK_STREAM, 0, raw_handles) != 0) {
60 return false;
61 }
62 handles[0].reset(raw_handles[0]);
63 handles[1].reset(raw_handles[1]);
[email protected]1da08e72013-11-01 19:58:1264 }
[email protected]532e9bd2012-01-25 12:04:1765
Xiaohan Wang38e4ebb2022-01-19 06:57:4366#if BUILDFLAG(IS_APPLE)
[email protected]182c44fa2009-11-26 00:28:0267 // On OSX an attempt to read or write to a closed socket may generate a
68 // SIGPIPE rather than returning -1. setsockopt will shut this off.
Robert Sesek6ab73b022020-02-13 16:42:3969 if (0 != setsockopt(handles[0].get(), SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe,
70 sizeof(nosigpipe)) ||
71 0 != setsockopt(handles[1].get(), SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe,
72 sizeof(nosigpipe))) {
[email protected]1da08e72013-11-01 19:58:1273 return false;
[email protected]182c44fa2009-11-26 00:28:0274 }
75#endif
[email protected]532e9bd2012-01-25 12:04:1776
[email protected]182c44fa2009-11-26 00:28:0277 // Copy the handles out for successful return.
Robert Sesek6ab73b022020-02-13 16:42:3978 socket_a->handle_ = std::move(handles[0]);
79 socket_b->handle_ = std::move(handles[1]);
[email protected]532e9bd2012-01-25 12:04:1780
[email protected]182c44fa2009-11-26 00:28:0281 return true;
[email protected]182c44fa2009-11-26 00:28:0282}
83
Robert Sesek6ab73b022020-02-13 16:42:3984void SyncSocket::Close() {
85 handle_.reset();
[email protected]182c44fa2009-11-26 00:28:0286}
87
Austin Sullivanedf168fd2024-01-17 21:37:2088size_t SyncSocket::Send(span<const uint8_t> data) {
Etienne Bergeron436d42212019-02-26 17:15:1289 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Austin Sullivanedf168fd2024-01-17 21:37:2090 return SendHelper(handle(), data);
[email protected]182c44fa2009-11-26 00:28:0291}
92
Austin Sullivanedf168fd2024-01-17 21:37:2093size_t SyncSocket::Receive(span<uint8_t> buffer) {
Etienne Bergeron436d42212019-02-26 17:15:1294 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Austin Sullivanedf168fd2024-01-17 21:37:2095 CHECK_LE(buffer.size(), kMaxMessageLength);
Robert Sesek6ab73b022020-02-13 16:42:3996 DCHECK(IsValid());
Austin Sullivanedf168fd2024-01-17 21:37:2097 if (ReadFromFD(handle(), as_writable_chars(buffer))) {
98 return buffer.size();
Austin Sullivan49f97442024-01-08 20:26:2799 }
[email protected]532e9bd2012-01-25 12:04:17100 return 0;
[email protected]182c44fa2009-11-26 00:28:02101}
102
Austin Sullivanedf168fd2024-01-17 21:37:20103size_t SyncSocket::ReceiveWithTimeout(span<uint8_t> buffer, TimeDelta timeout) {
Etienne Bergeron436d42212019-02-26 17:15:12104 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Austin Sullivanedf168fd2024-01-17 21:37:20105 CHECK_LE(buffer.size(), kMaxMessageLength);
Robert Sesek6ab73b022020-02-13 16:42:39106 DCHECK(IsValid());
[email protected]1bc4379e2013-11-05 00:14:27107
[email protected]62558f12013-10-19 22:13:19108 // Only timeouts greater than zero and less than one second are allowed.
109 DCHECK_GT(timeout.InMicroseconds(), 0);
Peter Kasting53fd6ee2021-10-05 20:40:48110 DCHECK_LT(timeout.InMicroseconds(), Seconds(1).InMicroseconds());
[email protected]62558f12013-10-19 22:13:19111
112 // Track the start time so we can reduce the timeout as data is read.
113 TimeTicks start_time = TimeTicks::Now();
114 const TimeTicks finish_time = start_time + timeout;
115
grunellb464b3e2017-05-23 11:15:26116 struct pollfd pollfd;
Robert Sesek6ab73b022020-02-13 16:42:39117 pollfd.fd = handle();
grunellb464b3e2017-05-23 11:15:26118 pollfd.events = POLLIN;
119 pollfd.revents = 0;
[email protected]62558f12013-10-19 22:13:19120
grunellb464b3e2017-05-23 11:15:26121 size_t bytes_read_total = 0;
Austin Sullivanedf168fd2024-01-17 21:37:20122 while (!buffer.empty()) {
grunellb464b3e2017-05-23 11:15:26123 const TimeDelta this_timeout = finish_time - TimeTicks::Now();
124 const int timeout_ms =
125 static_cast<int>(this_timeout.InMillisecondsRoundedUp());
Peter Kasting134ef9af2024-12-28 02:30:09126 if (timeout_ms <= 0) {
grunellb464b3e2017-05-23 11:15:26127 break;
Peter Kasting134ef9af2024-12-28 02:30:09128 }
grunellb464b3e2017-05-23 11:15:26129 const int poll_result = poll(&pollfd, 1, timeout_ms);
[email protected]62558f12013-10-19 22:13:19130 // Handle EINTR manually since we need to update the timeout value.
Peter Kasting134ef9af2024-12-28 02:30:09131 if (poll_result == -1 && errno == EINTR) {
[email protected]62558f12013-10-19 22:13:19132 continue;
Peter Kasting134ef9af2024-12-28 02:30:09133 }
grunellb464b3e2017-05-23 11:15:26134 // Return if other type of error or a timeout.
Peter Kasting134ef9af2024-12-28 02:30:09135 if (poll_result <= 0) {
[email protected]62558f12013-10-19 22:13:19136 return bytes_read_total;
Peter Kasting134ef9af2024-12-28 02:30:09137 }
[email protected]62558f12013-10-19 22:13:19138
grunellb464b3e2017-05-23 11:15:26139 // poll() only tells us that data is ready for reading, not how much. We
[email protected]62558f12013-10-19 22:13:19140 // must Peek() for the amount ready for reading to avoid blocking.
grunellb464b3e2017-05-23 11:15:26141 // At hang up (POLLHUP), the write end has been closed and there might still
142 // be data to be read.
143 // No special handling is needed for error (POLLERR); we can let any of the
144 // following operations fail and handle it there.
145 DCHECK(pollfd.revents & (POLLIN | POLLHUP | POLLERR)) << pollfd.revents;
Austin Sullivanedf168fd2024-01-17 21:37:20146 const size_t bytes_to_read = std::min(Peek(), buffer.size());
[email protected]62558f12013-10-19 22:13:19147
148 // There may be zero bytes to read if the socket at the other end closed.
Peter Kasting134ef9af2024-12-28 02:30:09149 if (!bytes_to_read) {
[email protected]62558f12013-10-19 22:13:19150 return bytes_read_total;
Peter Kasting134ef9af2024-12-28 02:30:09151 }
[email protected]62558f12013-10-19 22:13:19152
Tom Sepeze9d9e042025-02-26 23:04:02153 const size_t bytes_received = Receive(buffer.first(bytes_to_read));
[email protected]62558f12013-10-19 22:13:19154 bytes_read_total += bytes_received;
Austin Sullivanedf168fd2024-01-17 21:37:20155 buffer = buffer.subspan(bytes_received);
Peter Kasting134ef9af2024-12-28 02:30:09156 if (bytes_received != bytes_to_read) {
[email protected]62558f12013-10-19 22:13:19157 return bytes_read_total;
Peter Kasting134ef9af2024-12-28 02:30:09158 }
[email protected]62558f12013-10-19 22:13:19159 }
160
161 return bytes_read_total;
162}
163
[email protected]d8b65912009-12-04 22:53:22164size_t SyncSocket::Peek() {
Robert Sesek6ab73b022020-02-13 16:42:39165 DCHECK(IsValid());
[email protected]62558f12013-10-19 22:13:19166 int number_chars = 0;
Robert Sesek6ab73b022020-02-13 16:42:39167 if (ioctl(handle_.get(), FIONREAD, &number_chars) == -1) {
[email protected]1e1f1a72009-12-06 19:45:08168 // If there is an error in ioctl, signal that the channel would block.
169 return 0;
170 }
Peter Kastinga0b914dc2022-07-14 18:43:19171 return checked_cast<size_t>(number_chars);
[email protected]d8b65912009-12-04 22:53:22172}
173
Robert Sesek6ab73b022020-02-13 16:42:39174bool SyncSocket::IsValid() const {
175 return handle_.is_valid();
maxmorind4bcb112017-04-13 11:43:13176}
177
Robert Sesek6ab73b022020-02-13 16:42:39178SyncSocket::Handle SyncSocket::handle() const {
179 return handle_.get();
180}
181
182SyncSocket::Handle SyncSocket::Release() {
183 return handle_.release();
[email protected]532e9bd2012-01-25 12:04:17184}
185
186bool CancelableSyncSocket::Shutdown() {
Robert Sesek6ab73b022020-02-13 16:42:39187 DCHECK(IsValid());
188 return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR)) >= 0;
[email protected]532e9bd2012-01-25 12:04:17189}
190
Austin Sullivanedf168fd2024-01-17 21:37:20191size_t CancelableSyncSocket::Send(span<const uint8_t> data) {
192 CHECK_LE(data.size(), kMaxMessageLength);
Robert Sesek6ab73b022020-02-13 16:42:39193 DCHECK(IsValid());
[email protected]62558f12013-10-19 22:13:19194
Robert Sesek6ab73b022020-02-13 16:42:39195 const int flags = fcntl(handle(), F_GETFL);
[email protected]5d272092012-04-19 10:23:03196 if (flags != -1 && (flags & O_NONBLOCK) == 0) {
197 // Set the socket to non-blocking mode for sending if its original mode
198 // is blocking.
Robert Sesek6ab73b022020-02-13 16:42:39199 fcntl(handle(), F_SETFL, flags | O_NONBLOCK);
[email protected]5d272092012-04-19 10:23:03200 }
201
Austin Sullivanedf168fd2024-01-17 21:37:20202 const size_t len = SendHelper(handle(), data);
[email protected]5d272092012-04-19 10:23:03203
204 if (flags != -1 && (flags & O_NONBLOCK) == 0) {
205 // Restore the original flags.
Robert Sesek6ab73b022020-02-13 16:42:39206 fcntl(handle(), F_SETFL, flags);
[email protected]5d272092012-04-19 10:23:03207 }
208
209 return len;
210}
211
[email protected]532e9bd2012-01-25 12:04:17212// static
213bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
214 CancelableSyncSocket* socket_b) {
215 return SyncSocket::CreatePair(socket_a, socket_b);
216}
217
[email protected]182c44fa2009-11-26 00:28:02218} // namespace base