[go: nahoru, domu]

blob: 0a8d673f42d1bb55390c10043caf1e2394147337 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
sehr@google.com182c44fa2009-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>
xians@chromium.org5d272092012-04-19 10:23:038#include <fcntl.h>
dalecurtis@chromium.org62558f12013-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>
sehr@google.com182c44fa2009-11-26 00:28:0212#include <stdio.h>
sehr@google.com1e1f1a72009-12-06 19:45:0813#include <sys/ioctl.h>
sehr@google.com182c44fa2009-11-26 00:28:0214#include <sys/socket.h>
xians@chromium.org5d272092012-04-19 10:23:0315#include <sys/types.h>
sehr@google.com182c44fa2009-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"
brettw@chromium.orge3177dd52014-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"
sehr@google.com182c44fa2009-11-26 00:28:0223
Qi Tiezhengf537c422022-09-15 06:58:3424#if BUILDFLAG(IS_SOLARIS)
25#include <sys/filio.h>
26#endif
27
sehr@google.com182c44fa2009-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
dalecurtis@chromium.org62558f12013-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);
dalecurtis@chromium.org62558f12013-10-19 22:13:1939 DCHECK_NE(handle, SyncSocket::kInvalidHandle);
Austin Sullivanedf168fd2024-01-17 21:37:2040 return WriteFileDescriptor(handle, data) ? data.size() : 0;
dalecurtis@chromium.org62558f12013-10-19 22:13:1941}
42
sehr@google.com182c44fa2009-11-26 00:28:0243} // namespace
44
tommi@chromium.org532e9bd2012-01-25 12:04:1745// static
46bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
dalecurtis@chromium.org62558f12013-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());
tommi@chromium.org532e9bd2012-01-25 12:04:1750
Xiaohan Wang38e4ebb2022-01-19 06:57:4351#if BUILDFLAG(IS_APPLE)
sehr@google.com182c44fa2009-11-26 00:28:0252 int nosigpipe = 1;
Xiaohan Wang38e4ebb2022-01-19 06:57:4353#endif // BUILDFLAG(IS_APPLE)
sehr@google.com182c44fa2009-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]);
dalecurtis@chromium.org1da08e72013-11-01 19:58:1264 }
tommi@chromium.org532e9bd2012-01-25 12:04:1765
Xiaohan Wang38e4ebb2022-01-19 06:57:4366#if BUILDFLAG(IS_APPLE)
sehr@google.com182c44fa2009-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))) {
dalecurtis@chromium.org1da08e72013-11-01 19:58:1273 return false;
sehr@google.com182c44fa2009-11-26 00:28:0274 }
75#endif
tommi@chromium.org532e9bd2012-01-25 12:04:1776
sehr@google.com182c44fa2009-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]);
tommi@chromium.org532e9bd2012-01-25 12:04:1780
sehr@google.com182c44fa2009-11-26 00:28:0281 return true;
sehr@google.com182c44fa2009-11-26 00:28:0282}
83
Robert Sesek6ab73b022020-02-13 16:42:3984void SyncSocket::Close() {
85 handle_.reset();
sehr@google.com182c44fa2009-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);
sehr@google.com182c44fa2009-11-26 00:28:0291}
92
Austin Sullivanedf168fd2024-01-17 21:37:2093size_t SyncSocket::Send(const void* buffer, size_t length) {
94 return Send(make_span(static_cast<const uint8_t*>(buffer), length));
95}
96
97size_t SyncSocket::Receive(span<uint8_t> buffer) {
Etienne Bergeron436d42212019-02-26 17:15:1298 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Austin Sullivanedf168fd2024-01-17 21:37:2099 CHECK_LE(buffer.size(), kMaxMessageLength);
Robert Sesek6ab73b022020-02-13 16:42:39100 DCHECK(IsValid());
Austin Sullivanedf168fd2024-01-17 21:37:20101 if (ReadFromFD(handle(), as_writable_chars(buffer))) {
102 return buffer.size();
Austin Sullivan49f97442024-01-08 20:26:27103 }
tommi@chromium.org532e9bd2012-01-25 12:04:17104 return 0;
sehr@google.com182c44fa2009-11-26 00:28:02105}
106
dalecurtis@chromium.org62558f12013-10-19 22:13:19107size_t SyncSocket::ReceiveWithTimeout(void* buffer,
108 size_t length,
109 TimeDelta timeout) {
Austin Sullivanedf168fd2024-01-17 21:37:20110 return ReceiveWithTimeout(make_span(static_cast<uint8_t*>(buffer), length),
111 std::move(timeout));
112}
113
114size_t SyncSocket::Receive(void* buffer, size_t length) {
115 return Receive(make_span(static_cast<uint8_t*>(buffer), length));
116}
117
118size_t SyncSocket::ReceiveWithTimeout(span<uint8_t> buffer, TimeDelta timeout) {
Etienne Bergeron436d42212019-02-26 17:15:12119 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
Austin Sullivanedf168fd2024-01-17 21:37:20120 CHECK_LE(buffer.size(), kMaxMessageLength);
Robert Sesek6ab73b022020-02-13 16:42:39121 DCHECK(IsValid());
dalecurtis@google.com1bc4379e2013-11-05 00:14:27122
dalecurtis@chromium.org62558f12013-10-19 22:13:19123 // Only timeouts greater than zero and less than one second are allowed.
124 DCHECK_GT(timeout.InMicroseconds(), 0);
Peter Kasting53fd6ee2021-10-05 20:40:48125 DCHECK_LT(timeout.InMicroseconds(), Seconds(1).InMicroseconds());
dalecurtis@chromium.org62558f12013-10-19 22:13:19126
127 // Track the start time so we can reduce the timeout as data is read.
128 TimeTicks start_time = TimeTicks::Now();
129 const TimeTicks finish_time = start_time + timeout;
130
grunellb464b3e2017-05-23 11:15:26131 struct pollfd pollfd;
Robert Sesek6ab73b022020-02-13 16:42:39132 pollfd.fd = handle();
grunellb464b3e2017-05-23 11:15:26133 pollfd.events = POLLIN;
134 pollfd.revents = 0;
dalecurtis@chromium.org62558f12013-10-19 22:13:19135
grunellb464b3e2017-05-23 11:15:26136 size_t bytes_read_total = 0;
Austin Sullivanedf168fd2024-01-17 21:37:20137 while (!buffer.empty()) {
grunellb464b3e2017-05-23 11:15:26138 const TimeDelta this_timeout = finish_time - TimeTicks::Now();
139 const int timeout_ms =
140 static_cast<int>(this_timeout.InMillisecondsRoundedUp());
141 if (timeout_ms <= 0)
142 break;
143 const int poll_result = poll(&pollfd, 1, timeout_ms);
dalecurtis@chromium.org62558f12013-10-19 22:13:19144 // Handle EINTR manually since we need to update the timeout value.
grunellb464b3e2017-05-23 11:15:26145 if (poll_result == -1 && errno == EINTR)
dalecurtis@chromium.org62558f12013-10-19 22:13:19146 continue;
grunellb464b3e2017-05-23 11:15:26147 // Return if other type of error or a timeout.
148 if (poll_result <= 0)
dalecurtis@chromium.org62558f12013-10-19 22:13:19149 return bytes_read_total;
150
grunellb464b3e2017-05-23 11:15:26151 // poll() only tells us that data is ready for reading, not how much. We
dalecurtis@chromium.org62558f12013-10-19 22:13:19152 // must Peek() for the amount ready for reading to avoid blocking.
grunellb464b3e2017-05-23 11:15:26153 // At hang up (POLLHUP), the write end has been closed and there might still
154 // be data to be read.
155 // No special handling is needed for error (POLLERR); we can let any of the
156 // following operations fail and handle it there.
157 DCHECK(pollfd.revents & (POLLIN | POLLHUP | POLLERR)) << pollfd.revents;
Austin Sullivanedf168fd2024-01-17 21:37:20158 const size_t bytes_to_read = std::min(Peek(), buffer.size());
dalecurtis@chromium.org62558f12013-10-19 22:13:19159
160 // There may be zero bytes to read if the socket at the other end closed.
161 if (!bytes_to_read)
162 return bytes_read_total;
163
Austin Sullivanedf168fd2024-01-17 21:37:20164 const size_t bytes_received = Receive(buffer.subspan(0u, bytes_to_read));
dalecurtis@chromium.org62558f12013-10-19 22:13:19165 bytes_read_total += bytes_received;
Austin Sullivanedf168fd2024-01-17 21:37:20166 buffer = buffer.subspan(bytes_received);
dalecurtis@chromium.org62558f12013-10-19 22:13:19167 if (bytes_received != bytes_to_read)
168 return bytes_read_total;
169 }
170
171 return bytes_read_total;
172}
173
cpu@chromium.orgd8b65912009-12-04 22:53:22174size_t SyncSocket::Peek() {
Robert Sesek6ab73b022020-02-13 16:42:39175 DCHECK(IsValid());
dalecurtis@chromium.org62558f12013-10-19 22:13:19176 int number_chars = 0;
Robert Sesek6ab73b022020-02-13 16:42:39177 if (ioctl(handle_.get(), FIONREAD, &number_chars) == -1) {
sehr@google.com1e1f1a72009-12-06 19:45:08178 // If there is an error in ioctl, signal that the channel would block.
179 return 0;
180 }
Peter Kastinga0b914dc2022-07-14 18:43:19181 return checked_cast<size_t>(number_chars);
cpu@chromium.orgd8b65912009-12-04 22:53:22182}
183
Robert Sesek6ab73b022020-02-13 16:42:39184bool SyncSocket::IsValid() const {
185 return handle_.is_valid();
maxmorind4bcb112017-04-13 11:43:13186}
187
Robert Sesek6ab73b022020-02-13 16:42:39188SyncSocket::Handle SyncSocket::handle() const {
189 return handle_.get();
190}
191
192SyncSocket::Handle SyncSocket::Release() {
193 return handle_.release();
tommi@chromium.org532e9bd2012-01-25 12:04:17194}
195
196bool CancelableSyncSocket::Shutdown() {
Robert Sesek6ab73b022020-02-13 16:42:39197 DCHECK(IsValid());
198 return HANDLE_EINTR(shutdown(handle(), SHUT_RDWR)) >= 0;
tommi@chromium.org532e9bd2012-01-25 12:04:17199}
200
Austin Sullivanedf168fd2024-01-17 21:37:20201size_t CancelableSyncSocket::Send(span<const uint8_t> data) {
202 CHECK_LE(data.size(), kMaxMessageLength);
Robert Sesek6ab73b022020-02-13 16:42:39203 DCHECK(IsValid());
dalecurtis@chromium.org62558f12013-10-19 22:13:19204
Robert Sesek6ab73b022020-02-13 16:42:39205 const int flags = fcntl(handle(), F_GETFL);
xians@chromium.org5d272092012-04-19 10:23:03206 if (flags != -1 && (flags & O_NONBLOCK) == 0) {
207 // Set the socket to non-blocking mode for sending if its original mode
208 // is blocking.
Robert Sesek6ab73b022020-02-13 16:42:39209 fcntl(handle(), F_SETFL, flags | O_NONBLOCK);
xians@chromium.org5d272092012-04-19 10:23:03210 }
211
Austin Sullivanedf168fd2024-01-17 21:37:20212 const size_t len = SendHelper(handle(), data);
xians@chromium.org5d272092012-04-19 10:23:03213
214 if (flags != -1 && (flags & O_NONBLOCK) == 0) {
215 // Restore the original flags.
Robert Sesek6ab73b022020-02-13 16:42:39216 fcntl(handle(), F_SETFL, flags);
xians@chromium.org5d272092012-04-19 10:23:03217 }
218
219 return len;
220}
221
Austin Sullivanedf168fd2024-01-17 21:37:20222size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
223 return Send(make_span(static_cast<const uint8_t*>(buffer), length));
224}
225
tommi@chromium.org532e9bd2012-01-25 12:04:17226// static
227bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
228 CancelableSyncSocket* socket_b) {
229 return SyncSocket::CreatePair(socket_a, socket_b);
230}
231
sehr@google.com182c44fa2009-11-26 00:28:02232} // namespace base