blob: e63f978e07284292964b90282292a40437447982 [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Primiano Tucci2c5488f2019-06-01 03:27:28 +010017#include "perfetto/ext/base/unix_socket.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000018
19#include <errno.h>
20#include <fcntl.h>
Primiano Tuccid4be9662019-10-22 17:45:13 -040021#include <netdb.h>
22#include <netinet/in.h>
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000023#include <stdlib.h>
24#include <string.h>
25#include <sys/socket.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <sys/un.h>
29#include <unistd.h>
30
31#include <algorithm>
32#include <memory>
33
34#include "perfetto/base/build_config.h"
35#include "perfetto/base/logging.h"
36#include "perfetto/base/task_runner.h"
Primiano Tuccid4be9662019-10-22 17:45:13 -040037#include "perfetto/ext/base/string_utils.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010038#include "perfetto/ext/base/utils.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000039
Oystein Eftevaagff729592018-02-12 14:24:06 -080040#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000041#include <sys/ucred.h>
42#endif
43
44namespace perfetto {
Florian Mayerf7f0def2018-09-27 13:59:24 +010045namespace base {
46
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010047// The CMSG_* macros use NULL instead of nullptr.
48#pragma GCC diagnostic push
49#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
50#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
51#endif
52
Florian Mayerf7f0def2018-09-27 13:59:24 +010053namespace {
Primiano Tuccid4be9662019-10-22 17:45:13 -040054
Florian Mayerf7f0def2018-09-27 13:59:24 +010055// MSG_NOSIGNAL is not supported on Mac OS X, but in that case the socket is
56// created with SO_NOSIGPIPE (See InitializeSocket()).
57#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
58constexpr int kNoSigPipe = 0;
59#else
60constexpr int kNoSigPipe = MSG_NOSIGNAL;
61#endif
62
63// Android takes an int instead of socklen_t for the control buffer size.
64#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
65using CBufLenType = size_t;
66#else
67using CBufLenType = socklen_t;
68#endif
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010069
Primiano Tuccid4be9662019-10-22 17:45:13 -040070// A wrapper around variable-size sockaddr structs.
71// This is solving the following problem: when calling connect() or bind(), the
72// caller needs to take care to allocate the right struct (sockaddr_un for
73// AF_UNIX, sockaddr_in for AF_INET). Those structs have different sizes and,
74// more importantly, are bigger than the base struct sockaddr.
75struct SockaddrAny {
76 SockaddrAny() : size() {}
77 SockaddrAny(const void* addr, socklen_t sz) : data(new char[sz]), size(sz) {
78 memcpy(data.get(), addr, static_cast<size_t>(size));
79 }
80
81 const struct sockaddr* addr() const {
82 return reinterpret_cast<const struct sockaddr*>(data.get());
83 }
84
85 std::unique_ptr<char[]> data;
86 socklen_t size;
87};
88
89inline int GetSockFamily(SockFamily family) {
90 switch (family) {
91 case SockFamily::kUnix:
92 return AF_UNIX;
93 case SockFamily::kInet:
94 return AF_INET;
95 }
96 PERFETTO_CHECK(false); // For GCC.
97}
98
99inline int GetSockType(SockType type) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100100 switch (type) {
101 case SockType::kStream:
102 return SOCK_STREAM;
103 case SockType::kDgram:
104 return SOCK_DGRAM;
105 case SockType::kSeqPacket:
106 return SOCK_SEQPACKET;
107 }
Primiano Tuccid4be9662019-10-22 17:45:13 -0400108 PERFETTO_CHECK(false); // For GCC.
Florian Mayerf7f0def2018-09-27 13:59:24 +0100109}
110
Primiano Tuccid4be9662019-10-22 17:45:13 -0400111SockaddrAny MakeSockAddr(SockFamily family, const std::string& socket_name) {
112 switch (family) {
113 case SockFamily::kUnix: {
114 struct sockaddr_un saddr {};
115 const size_t name_len = socket_name.size();
116 if (name_len >= sizeof(saddr.sun_path)) {
117 errno = ENAMETOOLONG;
118 return SockaddrAny();
119 }
120 memcpy(saddr.sun_path, socket_name.data(), name_len);
121 if (saddr.sun_path[0] == '@')
122 saddr.sun_path[0] = '\0';
123 saddr.sun_family = AF_UNIX;
124 auto size = static_cast<socklen_t>(
125 __builtin_offsetof(sockaddr_un, sun_path) + name_len + 1);
126 PERFETTO_CHECK(static_cast<size_t>(size) <= sizeof(saddr));
127 return SockaddrAny(&saddr, size);
128 }
129 case SockFamily::kInet: {
130 auto parts = SplitString(socket_name, ":");
131 PERFETTO_CHECK(parts.size() == 2);
132 struct addrinfo* addr_info = nullptr;
133 struct addrinfo hints {};
134 hints.ai_family = AF_INET;
135 PERFETTO_CHECK(getaddrinfo(parts[0].c_str(), parts[1].c_str(), &hints,
136 &addr_info) == 0);
137 PERFETTO_CHECK(addr_info->ai_family == AF_INET);
138 SockaddrAny res(addr_info->ai_addr, addr_info->ai_addrlen);
139 freeaddrinfo(addr_info);
140 return res;
141 }
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100142 }
Primiano Tuccid4be9662019-10-22 17:45:13 -0400143 PERFETTO_CHECK(false); // For GCC.
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100144}
Florian Mayerf7f0def2018-09-27 13:59:24 +0100145
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100146} // namespace
147
148// +-----------------------+
149// | UnixSocketRaw methods |
150// +-----------------------+
151
152// static
153void UnixSocketRaw::ShiftMsgHdr(size_t n, struct msghdr* msg) {
Primiano Tucci45b902a2018-10-04 14:57:09 +0100154 using LenType = decltype(msg->msg_iovlen); // Mac and Linux don't agree.
155 for (LenType i = 0; i < msg->msg_iovlen; ++i) {
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100156 struct iovec* vec = &msg->msg_iov[i];
157 if (n < vec->iov_len) {
158 // We sent a part of this iovec.
159 vec->iov_base = reinterpret_cast<char*>(vec->iov_base) + n;
160 vec->iov_len -= n;
161 msg->msg_iov = vec;
162 msg->msg_iovlen -= i;
163 return;
164 }
165 // We sent the whole iovec.
166 n -= vec->iov_len;
167 }
168 // We sent all the iovecs.
169 PERFETTO_CHECK(n == 0);
170 msg->msg_iovlen = 0;
171 msg->msg_iov = nullptr;
172}
173
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100174// static
Primiano Tuccid4be9662019-10-22 17:45:13 -0400175std::pair<UnixSocketRaw, UnixSocketRaw> UnixSocketRaw::CreatePair(
176 SockFamily family,
177 SockType type) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100178 int fds[2];
Primiano Tuccid4be9662019-10-22 17:45:13 -0400179 if (socketpair(GetSockFamily(family), GetSockType(type), 0, fds) != 0)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100180 return std::make_pair(UnixSocketRaw(), UnixSocketRaw());
181
Primiano Tuccid4be9662019-10-22 17:45:13 -0400182 return std::make_pair(UnixSocketRaw(ScopedFile(fds[0]), family, type),
183 UnixSocketRaw(ScopedFile(fds[1]), family, type));
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100184}
185
186UnixSocketRaw::UnixSocketRaw() = default;
187
Primiano Tuccid4be9662019-10-22 17:45:13 -0400188UnixSocketRaw::UnixSocketRaw(SockFamily family, SockType type)
189 : UnixSocketRaw(
190 ScopedFile(socket(GetSockFamily(family), GetSockType(type), 0)),
191 family,
192 type) {}
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100193
Primiano Tuccid4be9662019-10-22 17:45:13 -0400194UnixSocketRaw::UnixSocketRaw(ScopedFile fd, SockFamily family, SockType type)
195 : fd_(std::move(fd)), family_(family), type_(type) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100196 PERFETTO_CHECK(fd_);
197#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
198 const int no_sigpipe = 1;
199 setsockopt(*fd_, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe));
200#endif
201
Primiano Tuccid4be9662019-10-22 17:45:13 -0400202 if (family == SockFamily::kInet) {
203 int flag = 1;
204 PERFETTO_CHECK(
205 !setsockopt(*fd_, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)));
206 }
207
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100208 // There is no reason why a socket should outlive the process in case of
209 // exec() by default, this is just working around a broken unix design.
210 int fcntl_res = fcntl(*fd_, F_SETFD, FD_CLOEXEC);
211 PERFETTO_CHECK(fcntl_res == 0);
212}
213
214void UnixSocketRaw::SetBlocking(bool is_blocking) {
215 PERFETTO_DCHECK(fd_);
216 int flags = fcntl(*fd_, F_GETFL, 0);
217 if (!is_blocking) {
218 flags |= O_NONBLOCK;
219 } else {
220 flags &= ~static_cast<int>(O_NONBLOCK);
221 }
222 bool fcntl_res = fcntl(*fd_, F_SETFL, flags);
223 PERFETTO_CHECK(fcntl_res == 0);
224}
225
Ryan Savitski14c12d62019-01-08 22:38:53 +0000226void UnixSocketRaw::RetainOnExec() {
227 PERFETTO_DCHECK(fd_);
228 int flags = fcntl(*fd_, F_GETFD, 0);
229 flags &= ~static_cast<int>(FD_CLOEXEC);
230 bool fcntl_res = fcntl(*fd_, F_SETFD, flags);
231 PERFETTO_CHECK(fcntl_res == 0);
232}
233
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100234bool UnixSocketRaw::IsBlocking() const {
235 PERFETTO_DCHECK(fd_);
236 return (fcntl(*fd_, F_GETFL, 0) & O_NONBLOCK) == 0;
237}
238
239bool UnixSocketRaw::Bind(const std::string& socket_name) {
240 PERFETTO_DCHECK(fd_);
Primiano Tuccid4be9662019-10-22 17:45:13 -0400241 SockaddrAny addr = MakeSockAddr(family_, socket_name);
242 if (addr.size == 0)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100243 return false;
244
Primiano Tuccid4be9662019-10-22 17:45:13 -0400245 if (bind(*fd_, addr.addr(), addr.size)) {
Primiano Tucci301175d2019-01-11 10:10:21 +0000246 PERFETTO_DPLOG("bind(%s)", socket_name.c_str());
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100247 return false;
248 }
249
250 return true;
251}
252
253bool UnixSocketRaw::Listen() {
Ryan Savitski499d9562019-01-08 23:10:01 +0000254 PERFETTO_DCHECK(fd_);
255 PERFETTO_DCHECK(type_ == SockType::kStream || type_ == SockType::kSeqPacket);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100256 return listen(*fd_, SOMAXCONN) == 0;
257}
258
259bool UnixSocketRaw::Connect(const std::string& socket_name) {
260 PERFETTO_DCHECK(fd_);
Primiano Tuccid4be9662019-10-22 17:45:13 -0400261 SockaddrAny addr = MakeSockAddr(family_, socket_name);
262 if (addr.size == 0)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100263 return false;
264
Primiano Tuccid4be9662019-10-22 17:45:13 -0400265 int res = PERFETTO_EINTR(connect(*fd_, addr.addr(), addr.size));
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100266 if (res && errno != EINPROGRESS)
267 return false;
268
269 return true;
270}
271
272void UnixSocketRaw::Shutdown() {
273 shutdown(*fd_, SHUT_RDWR);
274 fd_.reset();
275}
276
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100277// For the interested reader, Linux kernel dive to verify this is not only a
278// theoretical possibility: sock_stream_sendmsg, if sock_alloc_send_pskb returns
279// NULL [1] (which it does when it gets interrupted [2]), returns early with the
280// amount of bytes already sent.
281//
282// [1]:
283// https://elixir.bootlin.com/linux/v4.18.10/source/net/unix/af_unix.c#L1872
284// [2]: https://elixir.bootlin.com/linux/v4.18.10/source/net/core/sock.c#L2101
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100285ssize_t UnixSocketRaw::SendMsgAll(struct msghdr* msg) {
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100286 // This does not make sense on non-blocking sockets.
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100287 PERFETTO_DCHECK(fd_);
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100288
289 ssize_t total_sent = 0;
290 while (msg->msg_iov) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100291 ssize_t sent = PERFETTO_EINTR(sendmsg(*fd_, msg, kNoSigPipe));
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100292 if (sent <= 0) {
Florian Mayerd6bdb6f2019-05-03 17:53:58 +0100293 if (sent == -1 && IsAgain(errno))
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100294 return total_sent;
295 return sent;
296 }
297 total_sent += sent;
298 ShiftMsgHdr(static_cast<size_t>(sent), msg);
299 // Only send the ancillary data with the first sendmsg call.
300 msg->msg_control = nullptr;
301 msg->msg_controllen = 0;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000302 }
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100303 return total_sent;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000304}
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100305
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100306ssize_t UnixSocketRaw::Send(const void* msg,
307 size_t len,
308 const int* send_fds,
309 size_t num_fds) {
310 PERFETTO_DCHECK(fd_);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100311 msghdr msg_hdr = {};
312 iovec iov = {const_cast<void*>(msg), len};
313 msg_hdr.msg_iov = &iov;
314 msg_hdr.msg_iovlen = 1;
315 alignas(cmsghdr) char control_buf[256];
316
317 if (num_fds > 0) {
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000318 const auto raw_ctl_data_sz = num_fds * sizeof(int);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100319 const CBufLenType control_buf_len =
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000320 static_cast<CBufLenType>(CMSG_SPACE(raw_ctl_data_sz));
Florian Mayerf7f0def2018-09-27 13:59:24 +0100321 PERFETTO_CHECK(control_buf_len <= sizeof(control_buf));
322 memset(control_buf, 0, sizeof(control_buf));
323 msg_hdr.msg_control = control_buf;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000324 msg_hdr.msg_controllen = control_buf_len; // used by CMSG_FIRSTHDR
Florian Mayerf7f0def2018-09-27 13:59:24 +0100325 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr);
326 cmsg->cmsg_level = SOL_SOCKET;
327 cmsg->cmsg_type = SCM_RIGHTS;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000328 cmsg->cmsg_len = static_cast<CBufLenType>(CMSG_LEN(raw_ctl_data_sz));
Florian Mayerf7f0def2018-09-27 13:59:24 +0100329 memcpy(CMSG_DATA(cmsg), send_fds, num_fds * sizeof(int));
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000330 // note: if we were to send multiple cmsghdr structures, then
331 // msg_hdr.msg_controllen would need to be adjusted, see "man 3 cmsg".
Florian Mayerf7f0def2018-09-27 13:59:24 +0100332 }
333
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100334 return SendMsgAll(&msg_hdr);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100335}
336
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100337ssize_t UnixSocketRaw::Receive(void* msg,
338 size_t len,
339 ScopedFile* fd_vec,
340 size_t max_files) {
341 PERFETTO_DCHECK(fd_);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100342 msghdr msg_hdr = {};
343 iovec iov = {msg, len};
344 msg_hdr.msg_iov = &iov;
345 msg_hdr.msg_iovlen = 1;
346 alignas(cmsghdr) char control_buf[256];
347
348 if (max_files > 0) {
349 msg_hdr.msg_control = control_buf;
350 msg_hdr.msg_controllen =
351 static_cast<CBufLenType>(CMSG_SPACE(max_files * sizeof(int)));
352 PERFETTO_CHECK(msg_hdr.msg_controllen <= sizeof(control_buf));
353 }
Ryan Savitskib6d65912019-01-08 16:12:53 +0000354 const ssize_t sz = PERFETTO_EINTR(recvmsg(*fd_, &msg_hdr, 0));
Florian Mayerf7f0def2018-09-27 13:59:24 +0100355 if (sz <= 0) {
356 return sz;
357 }
358 PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
359
360 int* fds = nullptr;
361 uint32_t fds_len = 0;
362
363 if (max_files > 0) {
364 for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr); cmsg;
365 cmsg = CMSG_NXTHDR(&msg_hdr, cmsg)) {
366 const size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0);
367 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
368 PERFETTO_DCHECK(payload_len % sizeof(int) == 0u);
369 PERFETTO_CHECK(fds == nullptr);
370 fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
371 fds_len = static_cast<uint32_t>(payload_len / sizeof(int));
372 }
373 }
374 }
375
376 if (msg_hdr.msg_flags & MSG_TRUNC || msg_hdr.msg_flags & MSG_CTRUNC) {
377 for (size_t i = 0; fds && i < fds_len; ++i)
378 close(fds[i]);
379 errno = EMSGSIZE;
380 return -1;
381 }
382
383 for (size_t i = 0; fds && i < fds_len; ++i) {
384 if (i < max_files)
385 fd_vec[i].reset(fds[i]);
386 else
387 close(fds[i]);
388 }
389
390 return sz;
391}
392
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100393bool UnixSocketRaw::SetTxTimeout(uint32_t timeout_ms) {
394 PERFETTO_DCHECK(fd_);
395 struct timeval timeout {};
396 uint32_t timeout_sec = timeout_ms / 1000;
397 timeout.tv_sec = static_cast<decltype(timeout.tv_sec)>(timeout_sec);
398 timeout.tv_usec = static_cast<decltype(timeout.tv_usec)>(
399 (timeout_ms - (timeout_sec * 1000)) * 1000);
400
401 return setsockopt(*fd_, SOL_SOCKET, SO_SNDTIMEO,
402 reinterpret_cast<const char*>(&timeout),
403 sizeof(timeout)) == 0;
404}
405
Florian Mayerdac31272019-02-26 12:07:02 +0000406bool UnixSocketRaw::SetRxTimeout(uint32_t timeout_ms) {
407 PERFETTO_DCHECK(fd_);
408 struct timeval timeout {};
409 uint32_t timeout_sec = timeout_ms / 1000;
410 timeout.tv_sec = static_cast<decltype(timeout.tv_sec)>(timeout_sec);
411 timeout.tv_usec = static_cast<decltype(timeout.tv_usec)>(
412 (timeout_ms - (timeout_sec * 1000)) * 1000);
413
414 return setsockopt(*fd_, SOL_SOCKET, SO_RCVTIMEO,
415 reinterpret_cast<const char*>(&timeout),
416 sizeof(timeout)) == 0;
417}
418
Florian Mayerf7f0def2018-09-27 13:59:24 +0100419#pragma GCC diagnostic pop
420
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100421// +--------------------+
422// | UnixSocket methods |
423// +--------------------+
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000424
425// TODO(primiano): Add ThreadChecker to methods of this class.
426
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000427// static
428std::unique_ptr<UnixSocket> UnixSocket::Listen(const std::string& socket_name,
429 EventListener* event_listener,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100430 TaskRunner* task_runner,
Primiano Tuccid4be9662019-10-22 17:45:13 -0400431 SockFamily sock_family,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100432 SockType sock_type) {
Primiano Tuccid4be9662019-10-22 17:45:13 -0400433 auto sock_raw = UnixSocketRaw::CreateMayFail(sock_family, sock_type);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100434 if (!sock_raw || !sock_raw.Bind(socket_name))
435 return nullptr;
436
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100437 // Forward the call to the Listen() overload below.
Primiano Tuccid4be9662019-10-22 17:45:13 -0400438 return Listen(sock_raw.ReleaseFd(), event_listener, task_runner, sock_family,
439 sock_type);
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100440}
441
442// static
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100443std::unique_ptr<UnixSocket> UnixSocket::Listen(ScopedFile fd,
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100444 EventListener* event_listener,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100445 TaskRunner* task_runner,
Primiano Tuccid4be9662019-10-22 17:45:13 -0400446 SockFamily sock_family,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100447 SockType sock_type) {
448 return std::unique_ptr<UnixSocket>(
449 new UnixSocket(event_listener, task_runner, std::move(fd),
Primiano Tuccid4be9662019-10-22 17:45:13 -0400450 State::kListening, sock_family, sock_type));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000451}
452
453// static
454std::unique_ptr<UnixSocket> UnixSocket::Connect(const std::string& socket_name,
455 EventListener* event_listener,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100456 TaskRunner* task_runner,
Primiano Tuccid4be9662019-10-22 17:45:13 -0400457 SockFamily sock_family,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100458 SockType sock_type) {
459 std::unique_ptr<UnixSocket> sock(
Primiano Tuccid4be9662019-10-22 17:45:13 -0400460 new UnixSocket(event_listener, task_runner, sock_family, sock_type));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000461 sock->DoConnect(socket_name);
462 return sock;
463}
464
Ryan Savitski9c1240e2019-01-15 22:40:46 +0000465// static
466std::unique_ptr<UnixSocket> UnixSocket::AdoptConnected(
467 ScopedFile fd,
468 EventListener* event_listener,
469 TaskRunner* task_runner,
Primiano Tuccid4be9662019-10-22 17:45:13 -0400470 SockFamily sock_family,
Ryan Savitski9c1240e2019-01-15 22:40:46 +0000471 SockType sock_type) {
472 return std::unique_ptr<UnixSocket>(
473 new UnixSocket(event_listener, task_runner, std::move(fd),
Primiano Tuccid4be9662019-10-22 17:45:13 -0400474 State::kConnected, sock_family, sock_type));
Ryan Savitski9c1240e2019-01-15 22:40:46 +0000475}
476
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100477UnixSocket::UnixSocket(EventListener* event_listener,
478 TaskRunner* task_runner,
Primiano Tuccid4be9662019-10-22 17:45:13 -0400479 SockFamily sock_family,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100480 SockType sock_type)
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100481 : UnixSocket(event_listener,
482 task_runner,
Florian Mayerf7f0def2018-09-27 13:59:24 +0100483 ScopedFile(),
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100484 State::kDisconnected,
Primiano Tuccid4be9662019-10-22 17:45:13 -0400485 sock_family,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100486 sock_type) {}
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000487
488UnixSocket::UnixSocket(EventListener* event_listener,
Florian Mayerf7f0def2018-09-27 13:59:24 +0100489 TaskRunner* task_runner,
490 ScopedFile adopt_fd,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100491 State adopt_state,
Primiano Tuccid4be9662019-10-22 17:45:13 -0400492 SockFamily sock_family,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100493 SockType sock_type)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000494 : event_listener_(event_listener),
495 task_runner_(task_runner),
496 weak_ptr_factory_(this) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100497 state_ = State::kDisconnected;
498 if (adopt_state == State::kDisconnected) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100499 PERFETTO_DCHECK(!adopt_fd);
Primiano Tuccid4be9662019-10-22 17:45:13 -0400500 sock_raw_ = UnixSocketRaw::CreateMayFail(sock_family, sock_type);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100501 if (!sock_raw_) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100502 last_error_ = errno;
503 return;
504 }
505 } else if (adopt_state == State::kConnected) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100506 PERFETTO_DCHECK(adopt_fd);
Primiano Tuccid4be9662019-10-22 17:45:13 -0400507 sock_raw_ = UnixSocketRaw(std::move(adopt_fd), sock_family, sock_type);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000508 state_ = State::kConnected;
509 ReadPeerCredentials();
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100510 } else if (adopt_state == State::kListening) {
511 // We get here from Listen().
512
513 // |adopt_fd| might genuinely be invalid if the bind() failed.
514 if (!adopt_fd) {
515 last_error_ = errno;
516 return;
517 }
518
Primiano Tuccid4be9662019-10-22 17:45:13 -0400519 sock_raw_ = UnixSocketRaw(std::move(adopt_fd), sock_family, sock_type);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100520 if (!sock_raw_.Listen()) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100521 last_error_ = errno;
522 PERFETTO_DPLOG("listen()");
523 return;
524 }
525 state_ = State::kListening;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000526 } else {
Hector Dearmanbd14fc62018-12-13 16:06:14 +0000527 PERFETTO_FATAL("Unexpected adopt_state"); // Unfeasible.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000528 }
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100529
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100530 PERFETTO_CHECK(sock_raw_);
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100531 last_error_ = 0;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000532
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100533 sock_raw_.SetBlocking(false);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000534
Florian Mayerf7f0def2018-09-27 13:59:24 +0100535 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Primiano Tuccid4be9662019-10-22 17:45:13 -0400536
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100537 task_runner_->AddFileDescriptorWatch(sock_raw_.fd(), [weak_ptr] {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000538 if (weak_ptr)
539 weak_ptr->OnEvent();
540 });
541}
542
543UnixSocket::~UnixSocket() {
544 // The implicit dtor of |weak_ptr_factory_| will no-op pending callbacks.
Florian Mayer48c139c2018-03-12 14:07:57 +0000545 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000546}
547
Florian Mayerae2603b2019-02-21 15:53:26 -0800548UnixSocketRaw UnixSocket::ReleaseSocket() {
549 // This will invalidate any pending calls to OnEvent.
550 state_ = State::kDisconnected;
551 if (sock_raw_)
552 task_runner_->RemoveFileDescriptorWatch(sock_raw_.fd());
553
554 return std::move(sock_raw_);
555}
556
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000557// Called only by the Connect() static constructor.
558void UnixSocket::DoConnect(const std::string& socket_name) {
559 PERFETTO_DCHECK(state_ == State::kDisconnected);
560
561 // This is the only thing that can gracefully fail in the ctor.
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100562 if (!sock_raw_)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000563 return NotifyConnectionState(false);
564
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100565 if (!sock_raw_.Connect(socket_name)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000566 last_error_ = errno;
567 return NotifyConnectionState(false);
568 }
569
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100570 // At this point either connect() succeeded or started asynchronously
571 // (errno = EINPROGRESS).
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000572 last_error_ = 0;
573 state_ = State::kConnecting;
574
575 // Even if the socket is non-blocking, connecting to a UNIX socket can be
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100576 // acknowledged straight away rather than returning EINPROGRESS.
577 // The decision here is to deal with the two cases uniformly, at the cost of
578 // delaying the straight-away-connect() case by one task, to avoid depending
579 // on implementation details of UNIX socket on the various OSes.
580 // Posting the OnEvent() below emulates a wakeup of the FD watch. OnEvent(),
581 // which knows how to deal with spurious wakeups, will poll the SO_ERROR and
582 // evolve, if necessary, the state into either kConnected or kDisconnected.
583 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
584 task_runner_->PostTask([weak_ptr] {
585 if (weak_ptr)
586 weak_ptr->OnEvent();
587 });
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000588}
589
590void UnixSocket::ReadPeerCredentials() {
Primiano Tuccid4be9662019-10-22 17:45:13 -0400591 // Peer credentials are supported only on AF_UNIX sockets.
592 if (sock_raw_.family() != SockFamily::kUnix)
593 return;
594
Oystein Eftevaagff729592018-02-12 14:24:06 -0800595#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
596 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000597 struct ucred user_cred;
598 socklen_t len = sizeof(user_cred);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100599 int fd = sock_raw_.fd();
600 int res = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &user_cred, &len);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000601 PERFETTO_CHECK(res == 0);
602 peer_uid_ = user_cred.uid;
Florian Mayerfa1659e2018-08-07 10:45:19 +0100603 peer_pid_ = user_cred.pid;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000604#else
605 struct xucred user_cred;
606 socklen_t len = sizeof(user_cred);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100607 int res = getsockopt(sock_raw_.fd(), 0, LOCAL_PEERCRED, &user_cred, &len);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000608 PERFETTO_CHECK(res == 0 && user_cred.cr_version == XUCRED_VERSION);
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100609 peer_uid_ = static_cast<uid_t>(user_cred.cr_uid);
Florian Mayerfa1659e2018-08-07 10:45:19 +0100610// There is no pid in the LOCAL_PEERCREDS for MacOS / FreeBSD.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000611#endif
612}
613
614void UnixSocket::OnEvent() {
615 if (state_ == State::kDisconnected)
616 return; // Some spurious event, typically queued just before Shutdown().
617
618 if (state_ == State::kConnected)
619 return event_listener_->OnDataAvailable(this);
620
621 if (state_ == State::kConnecting) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100622 PERFETTO_DCHECK(sock_raw_);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000623 int sock_err = EINVAL;
624 socklen_t err_len = sizeof(sock_err);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100625 int res =
626 getsockopt(sock_raw_.fd(), SOL_SOCKET, SO_ERROR, &sock_err, &err_len);
Primiano Tuccid4be9662019-10-22 17:45:13 -0400627
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000628 if (res == 0 && sock_err == EINPROGRESS)
629 return; // Not connected yet, just a spurious FD watch wakeup.
630 if (res == 0 && sock_err == 0) {
631 ReadPeerCredentials();
632 state_ = State::kConnected;
633 return event_listener_->OnConnect(this, true /* connected */);
634 }
Primiano Tuccid4be9662019-10-22 17:45:13 -0400635 PERFETTO_DLOG("Connection error: %s", strerror(sock_err));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000636 last_error_ = sock_err;
Florian Mayer48c139c2018-03-12 14:07:57 +0000637 Shutdown(false);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000638 return event_listener_->OnConnect(this, false /* connected */);
639 }
640
641 // New incoming connection.
642 if (state_ == State::kListening) {
643 // There could be more than one incoming connection behind each FD watch
644 // notification. Drain'em all.
645 for (;;) {
Primiano Tuccid4be9662019-10-22 17:45:13 -0400646 struct sockaddr_in cli_addr {};
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000647 socklen_t size = sizeof(cli_addr);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100648 ScopedFile new_fd(PERFETTO_EINTR(accept(
649 sock_raw_.fd(), reinterpret_cast<sockaddr*>(&cli_addr), &size)));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000650 if (!new_fd)
651 return;
Primiano Tuccid4be9662019-10-22 17:45:13 -0400652 std::unique_ptr<UnixSocket> new_sock(new UnixSocket(
653 event_listener_, task_runner_, std::move(new_fd), State::kConnected,
654 sock_raw_.family(), sock_raw_.type()));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000655 event_listener_->OnNewIncomingConnection(this, std::move(new_sock));
656 }
657 }
658}
659
Florian Mayere1cd07d2018-07-31 11:56:41 +0100660bool UnixSocket::Send(const void* msg,
661 size_t len,
662 const int* send_fds,
663 size_t num_fds,
664 BlockingMode blocking_mode) {
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100665 // TODO(b/117139237): Non-blocking sends are broken because we do not
666 // properly handle partial sends.
667 PERFETTO_DCHECK(blocking_mode == BlockingMode::kBlocking);
668
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000669 if (state_ != State::kConnected) {
670 errno = last_error_ = ENOTCONN;
671 return false;
672 }
673
Primiano Tucci7a265b62017-12-07 18:37:31 +0000674 if (blocking_mode == BlockingMode::kBlocking)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100675 sock_raw_.SetBlocking(true);
676 const ssize_t sz = sock_raw_.Send(msg, len, send_fds, num_fds);
677 int saved_errno = errno;
Primiano Tucci7a265b62017-12-07 18:37:31 +0000678 if (blocking_mode == BlockingMode::kBlocking)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100679 sock_raw_.SetBlocking(false);
Primiano Tucci7a265b62017-12-07 18:37:31 +0000680
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100681 if (sz == static_cast<ssize_t>(len)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000682 last_error_ = 0;
683 return true;
684 }
685
Hector Dearman5145e502019-09-18 16:52:24 +0100686 // If sendmsg() succeeds but the returned size is < |len| it means that the
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100687 // endpoint disconnected in the middle of the read, and we managed to send
688 // only a portion of the buffer. In this case we should just give up.
689
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100690 if (sz < 0 && (saved_errno == EAGAIN || saved_errno == EWOULDBLOCK)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000691 // A genuine out-of-buffer. The client should retry or give up.
692 // Man pages specify that EAGAIN and EWOULDBLOCK have the same semantic here
693 // and clients should check for both.
694 last_error_ = EAGAIN;
695 return false;
696 }
697
Hector Dearman2442d612019-06-04 18:05:23 +0100698 // Either the other endpoint disconnected (ECONNRESET) or some other error
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000699 // happened.
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100700 last_error_ = saved_errno;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000701 PERFETTO_DPLOG("sendmsg() failed");
Florian Mayer48c139c2018-03-12 14:07:57 +0000702 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000703 return false;
704}
705
Florian Mayer48c139c2018-03-12 14:07:57 +0000706void UnixSocket::Shutdown(bool notify) {
Florian Mayerf7f0def2018-09-27 13:59:24 +0100707 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Florian Mayer48c139c2018-03-12 14:07:57 +0000708 if (notify) {
709 if (state_ == State::kConnected) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100710 task_runner_->PostTask([weak_ptr] {
Florian Mayer48c139c2018-03-12 14:07:57 +0000711 if (weak_ptr)
712 weak_ptr->event_listener_->OnDisconnect(weak_ptr.get());
713 });
714 } else if (state_ == State::kConnecting) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100715 task_runner_->PostTask([weak_ptr] {
Florian Mayer48c139c2018-03-12 14:07:57 +0000716 if (weak_ptr)
717 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), false);
718 });
719 }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000720 }
Florian Mayer48c139c2018-03-12 14:07:57 +0000721
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100722 if (sock_raw_) {
723 task_runner_->RemoveFileDescriptorWatch(sock_raw_.fd());
724 sock_raw_.Shutdown();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000725 }
726 state_ = State::kDisconnected;
727}
728
Florian Mayere1cd07d2018-07-31 11:56:41 +0100729size_t UnixSocket::Receive(void* msg,
730 size_t len,
Florian Mayerf7f0def2018-09-27 13:59:24 +0100731 ScopedFile* fd_vec,
Florian Mayere1cd07d2018-07-31 11:56:41 +0100732 size_t max_files) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000733 if (state_ != State::kConnected) {
734 last_error_ = ENOTCONN;
735 return 0;
736 }
737
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100738 const ssize_t sz = sock_raw_.Receive(msg, len, fd_vec, max_files);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000739 if (sz < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
740 last_error_ = EAGAIN;
741 return 0;
742 }
743 if (sz <= 0) {
744 last_error_ = errno;
Florian Mayer48c139c2018-03-12 14:07:57 +0000745 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000746 return 0;
747 }
748 PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000749 return static_cast<size_t>(sz);
750}
751
752std::string UnixSocket::ReceiveString(size_t max_length) {
753 std::unique_ptr<char[]> buf(new char[max_length + 1]);
754 size_t rsize = Receive(buf.get(), max_length);
755 PERFETTO_CHECK(static_cast<size_t>(rsize) <= max_length);
756 buf[static_cast<size_t>(rsize)] = '\0';
757 return std::string(buf.get());
758}
759
760void UnixSocket::NotifyConnectionState(bool success) {
Florian Mayer48c139c2018-03-12 14:07:57 +0000761 if (!success)
762 Shutdown(false);
763
Florian Mayerf7f0def2018-09-27 13:59:24 +0100764 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100765 task_runner_->PostTask([weak_ptr, success] {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000766 if (weak_ptr)
767 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), success);
768 });
769}
770
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000771UnixSocket::EventListener::~EventListener() {}
772void UnixSocket::EventListener::OnNewIncomingConnection(
773 UnixSocket*,
774 std::unique_ptr<UnixSocket>) {}
775void UnixSocket::EventListener::OnConnect(UnixSocket*, bool) {}
776void UnixSocket::EventListener::OnDisconnect(UnixSocket*) {}
777void UnixSocket::EventListener::OnDataAvailable(UnixSocket*) {}
778
Florian Mayerf7f0def2018-09-27 13:59:24 +0100779} // namespace base
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000780} // namespace perfetto