xref: /aosp_15_r20/external/libchrome/base/sync_socket_posix.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/sync_socket.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <errno.h>
8*635a8641SAndroid Build Coastguard Worker #include <fcntl.h>
9*635a8641SAndroid Build Coastguard Worker #include <limits.h>
10*635a8641SAndroid Build Coastguard Worker #include <poll.h>
11*635a8641SAndroid Build Coastguard Worker #include <stddef.h>
12*635a8641SAndroid Build Coastguard Worker #include <stdio.h>
13*635a8641SAndroid Build Coastguard Worker #include <sys/ioctl.h>
14*635a8641SAndroid Build Coastguard Worker #include <sys/socket.h>
15*635a8641SAndroid Build Coastguard Worker #include <sys/types.h>
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker #if defined(OS_SOLARIS)
18*635a8641SAndroid Build Coastguard Worker #include <sys/filio.h>
19*635a8641SAndroid Build Coastguard Worker #endif
20*635a8641SAndroid Build Coastguard Worker 
21*635a8641SAndroid Build Coastguard Worker #include "base/files/file_util.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
24*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
25*635a8641SAndroid Build Coastguard Worker 
26*635a8641SAndroid Build Coastguard Worker namespace base {
27*635a8641SAndroid Build Coastguard Worker 
28*635a8641SAndroid Build Coastguard Worker namespace {
29*635a8641SAndroid Build Coastguard Worker // To avoid users sending negative message lengths to Send/Receive
30*635a8641SAndroid Build Coastguard Worker // we clamp message lengths, which are size_t, to no more than INT_MAX.
31*635a8641SAndroid Build Coastguard Worker const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
32*635a8641SAndroid Build Coastguard Worker 
33*635a8641SAndroid Build Coastguard Worker // Writes |length| of |buffer| into |handle|.  Returns the number of bytes
34*635a8641SAndroid Build Coastguard Worker // written or zero on error.  |length| must be greater than 0.
SendHelper(SyncSocket::Handle handle,const void * buffer,size_t length)35*635a8641SAndroid Build Coastguard Worker size_t SendHelper(SyncSocket::Handle handle,
36*635a8641SAndroid Build Coastguard Worker                   const void* buffer,
37*635a8641SAndroid Build Coastguard Worker                   size_t length) {
38*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(length, 0u);
39*635a8641SAndroid Build Coastguard Worker   DCHECK_LE(length, kMaxMessageLength);
40*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(handle, SyncSocket::kInvalidHandle);
41*635a8641SAndroid Build Coastguard Worker   const char* charbuffer = static_cast<const char*>(buffer);
42*635a8641SAndroid Build Coastguard Worker   return WriteFileDescriptor(handle, charbuffer, length)
43*635a8641SAndroid Build Coastguard Worker              ? static_cast<size_t>(length)
44*635a8641SAndroid Build Coastguard Worker              : 0;
45*635a8641SAndroid Build Coastguard Worker }
46*635a8641SAndroid Build Coastguard Worker 
CloseHandle(SyncSocket::Handle handle)47*635a8641SAndroid Build Coastguard Worker bool CloseHandle(SyncSocket::Handle handle) {
48*635a8641SAndroid Build Coastguard Worker   if (handle != SyncSocket::kInvalidHandle && close(handle) < 0) {
49*635a8641SAndroid Build Coastguard Worker     DPLOG(ERROR) << "close";
50*635a8641SAndroid Build Coastguard Worker     return false;
51*635a8641SAndroid Build Coastguard Worker   }
52*635a8641SAndroid Build Coastguard Worker 
53*635a8641SAndroid Build Coastguard Worker   return true;
54*635a8641SAndroid Build Coastguard Worker }
55*635a8641SAndroid Build Coastguard Worker 
56*635a8641SAndroid Build Coastguard Worker }  // namespace
57*635a8641SAndroid Build Coastguard Worker 
58*635a8641SAndroid Build Coastguard Worker const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
59*635a8641SAndroid Build Coastguard Worker 
SyncSocket()60*635a8641SAndroid Build Coastguard Worker SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
61*635a8641SAndroid Build Coastguard Worker 
~SyncSocket()62*635a8641SAndroid Build Coastguard Worker SyncSocket::~SyncSocket() {
63*635a8641SAndroid Build Coastguard Worker   Close();
64*635a8641SAndroid Build Coastguard Worker }
65*635a8641SAndroid Build Coastguard Worker 
66*635a8641SAndroid Build Coastguard Worker // static
CreatePair(SyncSocket * socket_a,SyncSocket * socket_b)67*635a8641SAndroid Build Coastguard Worker bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
68*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(socket_a, socket_b);
69*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(socket_a->handle_, kInvalidHandle);
70*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(socket_b->handle_, kInvalidHandle);
71*635a8641SAndroid Build Coastguard Worker 
72*635a8641SAndroid Build Coastguard Worker #if defined(OS_MACOSX)
73*635a8641SAndroid Build Coastguard Worker   int nosigpipe = 1;
74*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_MACOSX)
75*635a8641SAndroid Build Coastguard Worker 
76*635a8641SAndroid Build Coastguard Worker   Handle handles[2] = { kInvalidHandle, kInvalidHandle };
77*635a8641SAndroid Build Coastguard Worker   if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
78*635a8641SAndroid Build Coastguard Worker     CloseHandle(handles[0]);
79*635a8641SAndroid Build Coastguard Worker     CloseHandle(handles[1]);
80*635a8641SAndroid Build Coastguard Worker     return false;
81*635a8641SAndroid Build Coastguard Worker   }
82*635a8641SAndroid Build Coastguard Worker 
83*635a8641SAndroid Build Coastguard Worker #if defined(OS_MACOSX)
84*635a8641SAndroid Build Coastguard Worker   // On OSX an attempt to read or write to a closed socket may generate a
85*635a8641SAndroid Build Coastguard Worker   // SIGPIPE rather than returning -1.  setsockopt will shut this off.
86*635a8641SAndroid Build Coastguard Worker   if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE,
87*635a8641SAndroid Build Coastguard Worker                       &nosigpipe, sizeof nosigpipe) ||
88*635a8641SAndroid Build Coastguard Worker       0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE,
89*635a8641SAndroid Build Coastguard Worker                       &nosigpipe, sizeof nosigpipe)) {
90*635a8641SAndroid Build Coastguard Worker     CloseHandle(handles[0]);
91*635a8641SAndroid Build Coastguard Worker     CloseHandle(handles[1]);
92*635a8641SAndroid Build Coastguard Worker     return false;
93*635a8641SAndroid Build Coastguard Worker   }
94*635a8641SAndroid Build Coastguard Worker #endif
95*635a8641SAndroid Build Coastguard Worker 
96*635a8641SAndroid Build Coastguard Worker   // Copy the handles out for successful return.
97*635a8641SAndroid Build Coastguard Worker   socket_a->handle_ = handles[0];
98*635a8641SAndroid Build Coastguard Worker   socket_b->handle_ = handles[1];
99*635a8641SAndroid Build Coastguard Worker 
100*635a8641SAndroid Build Coastguard Worker   return true;
101*635a8641SAndroid Build Coastguard Worker }
102*635a8641SAndroid Build Coastguard Worker 
103*635a8641SAndroid Build Coastguard Worker // static
UnwrapHandle(const TransitDescriptor & descriptor)104*635a8641SAndroid Build Coastguard Worker SyncSocket::Handle SyncSocket::UnwrapHandle(
105*635a8641SAndroid Build Coastguard Worker     const TransitDescriptor& descriptor) {
106*635a8641SAndroid Build Coastguard Worker   return descriptor.fd;
107*635a8641SAndroid Build Coastguard Worker }
108*635a8641SAndroid Build Coastguard Worker 
PrepareTransitDescriptor(ProcessHandle peer_process_handle,TransitDescriptor * descriptor)109*635a8641SAndroid Build Coastguard Worker bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle,
110*635a8641SAndroid Build Coastguard Worker                                           TransitDescriptor* descriptor) {
111*635a8641SAndroid Build Coastguard Worker   descriptor->fd = handle();
112*635a8641SAndroid Build Coastguard Worker   descriptor->auto_close = false;
113*635a8641SAndroid Build Coastguard Worker   return descriptor->fd != kInvalidHandle;
114*635a8641SAndroid Build Coastguard Worker }
115*635a8641SAndroid Build Coastguard Worker 
Close()116*635a8641SAndroid Build Coastguard Worker bool SyncSocket::Close() {
117*635a8641SAndroid Build Coastguard Worker   const bool retval = CloseHandle(handle_);
118*635a8641SAndroid Build Coastguard Worker   handle_ = kInvalidHandle;
119*635a8641SAndroid Build Coastguard Worker   return retval;
120*635a8641SAndroid Build Coastguard Worker }
121*635a8641SAndroid Build Coastguard Worker 
Send(const void * buffer,size_t length)122*635a8641SAndroid Build Coastguard Worker size_t SyncSocket::Send(const void* buffer, size_t length) {
123*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
124*635a8641SAndroid Build Coastguard Worker   return SendHelper(handle_, buffer, length);
125*635a8641SAndroid Build Coastguard Worker }
126*635a8641SAndroid Build Coastguard Worker 
Receive(void * buffer,size_t length)127*635a8641SAndroid Build Coastguard Worker size_t SyncSocket::Receive(void* buffer, size_t length) {
128*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
129*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(length, 0u);
130*635a8641SAndroid Build Coastguard Worker   DCHECK_LE(length, kMaxMessageLength);
131*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(handle_, kInvalidHandle);
132*635a8641SAndroid Build Coastguard Worker   char* charbuffer = static_cast<char*>(buffer);
133*635a8641SAndroid Build Coastguard Worker   if (ReadFromFD(handle_, charbuffer, length))
134*635a8641SAndroid Build Coastguard Worker     return length;
135*635a8641SAndroid Build Coastguard Worker   return 0;
136*635a8641SAndroid Build Coastguard Worker }
137*635a8641SAndroid Build Coastguard Worker 
ReceiveWithTimeout(void * buffer,size_t length,TimeDelta timeout)138*635a8641SAndroid Build Coastguard Worker size_t SyncSocket::ReceiveWithTimeout(void* buffer,
139*635a8641SAndroid Build Coastguard Worker                                       size_t length,
140*635a8641SAndroid Build Coastguard Worker                                       TimeDelta timeout) {
141*635a8641SAndroid Build Coastguard Worker   AssertBlockingAllowed();
142*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(length, 0u);
143*635a8641SAndroid Build Coastguard Worker   DCHECK_LE(length, kMaxMessageLength);
144*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(handle_, kInvalidHandle);
145*635a8641SAndroid Build Coastguard Worker 
146*635a8641SAndroid Build Coastguard Worker   // Only timeouts greater than zero and less than one second are allowed.
147*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(timeout.InMicroseconds(), 0);
148*635a8641SAndroid Build Coastguard Worker   DCHECK_LT(timeout.InMicroseconds(),
149*635a8641SAndroid Build Coastguard Worker             TimeDelta::FromSeconds(1).InMicroseconds());
150*635a8641SAndroid Build Coastguard Worker 
151*635a8641SAndroid Build Coastguard Worker   // Track the start time so we can reduce the timeout as data is read.
152*635a8641SAndroid Build Coastguard Worker   TimeTicks start_time = TimeTicks::Now();
153*635a8641SAndroid Build Coastguard Worker   const TimeTicks finish_time = start_time + timeout;
154*635a8641SAndroid Build Coastguard Worker 
155*635a8641SAndroid Build Coastguard Worker   struct pollfd pollfd;
156*635a8641SAndroid Build Coastguard Worker   pollfd.fd = handle_;
157*635a8641SAndroid Build Coastguard Worker   pollfd.events = POLLIN;
158*635a8641SAndroid Build Coastguard Worker   pollfd.revents = 0;
159*635a8641SAndroid Build Coastguard Worker 
160*635a8641SAndroid Build Coastguard Worker   size_t bytes_read_total = 0;
161*635a8641SAndroid Build Coastguard Worker   while (bytes_read_total < length) {
162*635a8641SAndroid Build Coastguard Worker     const TimeDelta this_timeout = finish_time - TimeTicks::Now();
163*635a8641SAndroid Build Coastguard Worker     const int timeout_ms =
164*635a8641SAndroid Build Coastguard Worker         static_cast<int>(this_timeout.InMillisecondsRoundedUp());
165*635a8641SAndroid Build Coastguard Worker     if (timeout_ms <= 0)
166*635a8641SAndroid Build Coastguard Worker       break;
167*635a8641SAndroid Build Coastguard Worker     const int poll_result = poll(&pollfd, 1, timeout_ms);
168*635a8641SAndroid Build Coastguard Worker     // Handle EINTR manually since we need to update the timeout value.
169*635a8641SAndroid Build Coastguard Worker     if (poll_result == -1 && errno == EINTR)
170*635a8641SAndroid Build Coastguard Worker       continue;
171*635a8641SAndroid Build Coastguard Worker     // Return if other type of error or a timeout.
172*635a8641SAndroid Build Coastguard Worker     if (poll_result <= 0)
173*635a8641SAndroid Build Coastguard Worker       return bytes_read_total;
174*635a8641SAndroid Build Coastguard Worker 
175*635a8641SAndroid Build Coastguard Worker     // poll() only tells us that data is ready for reading, not how much.  We
176*635a8641SAndroid Build Coastguard Worker     // must Peek() for the amount ready for reading to avoid blocking.
177*635a8641SAndroid Build Coastguard Worker     // At hang up (POLLHUP), the write end has been closed and there might still
178*635a8641SAndroid Build Coastguard Worker     // be data to be read.
179*635a8641SAndroid Build Coastguard Worker     // No special handling is needed for error (POLLERR); we can let any of the
180*635a8641SAndroid Build Coastguard Worker     // following operations fail and handle it there.
181*635a8641SAndroid Build Coastguard Worker     DCHECK(pollfd.revents & (POLLIN | POLLHUP | POLLERR)) << pollfd.revents;
182*635a8641SAndroid Build Coastguard Worker     const size_t bytes_to_read = std::min(Peek(), length - bytes_read_total);
183*635a8641SAndroid Build Coastguard Worker 
184*635a8641SAndroid Build Coastguard Worker     // There may be zero bytes to read if the socket at the other end closed.
185*635a8641SAndroid Build Coastguard Worker     if (!bytes_to_read)
186*635a8641SAndroid Build Coastguard Worker       return bytes_read_total;
187*635a8641SAndroid Build Coastguard Worker 
188*635a8641SAndroid Build Coastguard Worker     const size_t bytes_received =
189*635a8641SAndroid Build Coastguard Worker         Receive(static_cast<char*>(buffer) + bytes_read_total, bytes_to_read);
190*635a8641SAndroid Build Coastguard Worker     bytes_read_total += bytes_received;
191*635a8641SAndroid Build Coastguard Worker     if (bytes_received != bytes_to_read)
192*635a8641SAndroid Build Coastguard Worker       return bytes_read_total;
193*635a8641SAndroid Build Coastguard Worker   }
194*635a8641SAndroid Build Coastguard Worker 
195*635a8641SAndroid Build Coastguard Worker   return bytes_read_total;
196*635a8641SAndroid Build Coastguard Worker }
197*635a8641SAndroid Build Coastguard Worker 
Peek()198*635a8641SAndroid Build Coastguard Worker size_t SyncSocket::Peek() {
199*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(handle_, kInvalidHandle);
200*635a8641SAndroid Build Coastguard Worker   int number_chars = 0;
201*635a8641SAndroid Build Coastguard Worker   if (ioctl(handle_, FIONREAD, &number_chars) == -1) {
202*635a8641SAndroid Build Coastguard Worker     // If there is an error in ioctl, signal that the channel would block.
203*635a8641SAndroid Build Coastguard Worker     return 0;
204*635a8641SAndroid Build Coastguard Worker   }
205*635a8641SAndroid Build Coastguard Worker   DCHECK_GE(number_chars, 0);
206*635a8641SAndroid Build Coastguard Worker   return number_chars;
207*635a8641SAndroid Build Coastguard Worker }
208*635a8641SAndroid Build Coastguard Worker 
Release()209*635a8641SAndroid Build Coastguard Worker SyncSocket::Handle SyncSocket::Release() {
210*635a8641SAndroid Build Coastguard Worker   Handle r = handle_;
211*635a8641SAndroid Build Coastguard Worker   handle_ = kInvalidHandle;
212*635a8641SAndroid Build Coastguard Worker   return r;
213*635a8641SAndroid Build Coastguard Worker }
214*635a8641SAndroid Build Coastguard Worker 
215*635a8641SAndroid Build Coastguard Worker CancelableSyncSocket::CancelableSyncSocket() = default;
CancelableSyncSocket(Handle handle)216*635a8641SAndroid Build Coastguard Worker CancelableSyncSocket::CancelableSyncSocket(Handle handle)
217*635a8641SAndroid Build Coastguard Worker     : SyncSocket(handle) {
218*635a8641SAndroid Build Coastguard Worker }
219*635a8641SAndroid Build Coastguard Worker 
Shutdown()220*635a8641SAndroid Build Coastguard Worker bool CancelableSyncSocket::Shutdown() {
221*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(handle_, kInvalidHandle);
222*635a8641SAndroid Build Coastguard Worker   return HANDLE_EINTR(shutdown(handle_, SHUT_RDWR)) >= 0;
223*635a8641SAndroid Build Coastguard Worker }
224*635a8641SAndroid Build Coastguard Worker 
Send(const void * buffer,size_t length)225*635a8641SAndroid Build Coastguard Worker size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
226*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(length, 0u);
227*635a8641SAndroid Build Coastguard Worker   DCHECK_LE(length, kMaxMessageLength);
228*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(handle_, kInvalidHandle);
229*635a8641SAndroid Build Coastguard Worker 
230*635a8641SAndroid Build Coastguard Worker   const int flags = fcntl(handle_, F_GETFL);
231*635a8641SAndroid Build Coastguard Worker   if (flags != -1 && (flags & O_NONBLOCK) == 0) {
232*635a8641SAndroid Build Coastguard Worker     // Set the socket to non-blocking mode for sending if its original mode
233*635a8641SAndroid Build Coastguard Worker     // is blocking.
234*635a8641SAndroid Build Coastguard Worker     fcntl(handle_, F_SETFL, flags | O_NONBLOCK);
235*635a8641SAndroid Build Coastguard Worker   }
236*635a8641SAndroid Build Coastguard Worker 
237*635a8641SAndroid Build Coastguard Worker   const size_t len = SendHelper(handle_, buffer, length);
238*635a8641SAndroid Build Coastguard Worker 
239*635a8641SAndroid Build Coastguard Worker   if (flags != -1 && (flags & O_NONBLOCK) == 0) {
240*635a8641SAndroid Build Coastguard Worker     // Restore the original flags.
241*635a8641SAndroid Build Coastguard Worker     fcntl(handle_, F_SETFL, flags);
242*635a8641SAndroid Build Coastguard Worker   }
243*635a8641SAndroid Build Coastguard Worker 
244*635a8641SAndroid Build Coastguard Worker   return len;
245*635a8641SAndroid Build Coastguard Worker }
246*635a8641SAndroid Build Coastguard Worker 
247*635a8641SAndroid Build Coastguard Worker // static
CreatePair(CancelableSyncSocket * socket_a,CancelableSyncSocket * socket_b)248*635a8641SAndroid Build Coastguard Worker bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
249*635a8641SAndroid Build Coastguard Worker                                       CancelableSyncSocket* socket_b) {
250*635a8641SAndroid Build Coastguard Worker   return SyncSocket::CreatePair(socket_a, socket_b);
251*635a8641SAndroid Build Coastguard Worker }
252*635a8641SAndroid Build Coastguard Worker 
253*635a8641SAndroid Build Coastguard Worker }  // namespace base
254