1 /*
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
17 #include "perfetto/ext/base/unix_socket.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #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"
37 #include "perfetto/ext/base/string_utils.h"
38 #include "perfetto/ext/base/utils.h"
39
40 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
41 #include <sys/ucred.h>
42 #endif
43
44 namespace perfetto {
45 namespace base {
46
47 // The CMSG_* macros use NULL instead of nullptr.
48 #pragma GCC diagnostic push
49 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
50 #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
51 #endif
52
53 namespace {
54
55 // 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_APPLE)
58 constexpr int kNoSigPipe = 0;
59 #else
60 constexpr 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)
65 using CBufLenType = size_t;
66 #else
67 using CBufLenType = socklen_t;
68 #endif
69
70 // 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.
75 struct SockaddrAny {
SockaddrAnyperfetto::base::__anone7bd8eca0111::SockaddrAny76 SockaddrAny() : size() {}
SockaddrAnyperfetto::base::__anone7bd8eca0111::SockaddrAny77 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
addrperfetto::base::__anone7bd8eca0111::SockaddrAny81 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
GetSockFamily(SockFamily family)89 inline int GetSockFamily(SockFamily family) {
90 switch (family) {
91 case SockFamily::kUnix:
92 return AF_UNIX;
93 case SockFamily::kInet:
94 return AF_INET;
95 case SockFamily::kInet6:
96 return AF_INET6;
97 }
98 PERFETTO_CHECK(false); // For GCC.
99 }
100
GetSockType(SockType type)101 inline int GetSockType(SockType type) {
102 #ifdef SOCK_CLOEXEC
103 constexpr int kSockCloExec = SOCK_CLOEXEC;
104 #else
105 constexpr int kSockCloExec = 0;
106 #endif
107 switch (type) {
108 case SockType::kStream:
109 return SOCK_STREAM | kSockCloExec;
110 case SockType::kDgram:
111 return SOCK_DGRAM | kSockCloExec;
112 case SockType::kSeqPacket:
113 return SOCK_SEQPACKET | kSockCloExec;
114 }
115 PERFETTO_CHECK(false); // For GCC.
116 }
117
MakeSockAddr(SockFamily family,const std::string & socket_name)118 SockaddrAny MakeSockAddr(SockFamily family, const std::string& socket_name) {
119 switch (family) {
120 case SockFamily::kUnix: {
121 struct sockaddr_un saddr {};
122 const size_t name_len = socket_name.size();
123 if (name_len >= sizeof(saddr.sun_path)) {
124 errno = ENAMETOOLONG;
125 return SockaddrAny();
126 }
127 memcpy(saddr.sun_path, socket_name.data(), name_len);
128 if (saddr.sun_path[0] == '@')
129 saddr.sun_path[0] = '\0';
130 saddr.sun_family = AF_UNIX;
131 auto size = static_cast<socklen_t>(
132 __builtin_offsetof(sockaddr_un, sun_path) + name_len + 1);
133 PERFETTO_CHECK(static_cast<size_t>(size) <= sizeof(saddr));
134 return SockaddrAny(&saddr, size);
135 }
136 case SockFamily::kInet: {
137 auto parts = SplitString(socket_name, ":");
138 PERFETTO_CHECK(parts.size() == 2);
139 struct addrinfo* addr_info = nullptr;
140 struct addrinfo hints {};
141 hints.ai_family = AF_INET;
142 PERFETTO_CHECK(getaddrinfo(parts[0].c_str(), parts[1].c_str(), &hints,
143 &addr_info) == 0);
144 PERFETTO_CHECK(addr_info->ai_family == AF_INET);
145 SockaddrAny res(addr_info->ai_addr, addr_info->ai_addrlen);
146 freeaddrinfo(addr_info);
147 return res;
148 }
149 case SockFamily::kInet6: {
150 auto parts = SplitString(socket_name, "]");
151 PERFETTO_CHECK(parts.size() == 2);
152 auto address = SplitString(parts[0], "[");
153 PERFETTO_CHECK(address.size() == 1);
154 auto port = SplitString(parts[1], ":");
155 PERFETTO_CHECK(port.size() == 1);
156 struct addrinfo* addr_info = nullptr;
157 struct addrinfo hints {};
158 hints.ai_family = AF_INET6;
159 PERFETTO_CHECK(getaddrinfo(address[0].c_str(), port[0].c_str(), &hints,
160 &addr_info) == 0);
161 PERFETTO_CHECK(addr_info->ai_family == AF_INET6);
162 SockaddrAny res(addr_info->ai_addr, addr_info->ai_addrlen);
163 freeaddrinfo(addr_info);
164 return res;
165 }
166 }
167 PERFETTO_CHECK(false); // For GCC.
168 }
169
170 } // namespace
171
172 // +-----------------------+
173 // | UnixSocketRaw methods |
174 // +-----------------------+
175
176 // static
ShiftMsgHdr(size_t n,struct msghdr * msg)177 void UnixSocketRaw::ShiftMsgHdr(size_t n, struct msghdr* msg) {
178 using LenType = decltype(msg->msg_iovlen); // Mac and Linux don't agree.
179 for (LenType i = 0; i < msg->msg_iovlen; ++i) {
180 struct iovec* vec = &msg->msg_iov[i];
181 if (n < vec->iov_len) {
182 // We sent a part of this iovec.
183 vec->iov_base = reinterpret_cast<char*>(vec->iov_base) + n;
184 vec->iov_len -= n;
185 msg->msg_iov = vec;
186 msg->msg_iovlen -= i;
187 return;
188 }
189 // We sent the whole iovec.
190 n -= vec->iov_len;
191 }
192 // We sent all the iovecs.
193 PERFETTO_CHECK(n == 0);
194 msg->msg_iovlen = 0;
195 msg->msg_iov = nullptr;
196 }
197
198 // static
CreateMayFail(SockFamily family,SockType type)199 UnixSocketRaw UnixSocketRaw::CreateMayFail(SockFamily family, SockType type) {
200 auto fd = ScopedFile(socket(GetSockFamily(family), GetSockType(type), 0));
201 if (!fd) {
202 return UnixSocketRaw();
203 }
204 return UnixSocketRaw(std::move(fd), family, type);
205 }
206
207 // static
CreatePair(SockFamily family,SockType type)208 std::pair<UnixSocketRaw, UnixSocketRaw> UnixSocketRaw::CreatePair(
209 SockFamily family,
210 SockType type) {
211 int fds[2];
212 if (socketpair(GetSockFamily(family), GetSockType(type), 0, fds) != 0)
213 return std::make_pair(UnixSocketRaw(), UnixSocketRaw());
214
215 return std::make_pair(UnixSocketRaw(ScopedFile(fds[0]), family, type),
216 UnixSocketRaw(ScopedFile(fds[1]), family, type));
217 }
218
219 UnixSocketRaw::UnixSocketRaw() = default;
220
UnixSocketRaw(SockFamily family,SockType type)221 UnixSocketRaw::UnixSocketRaw(SockFamily family, SockType type)
222 : UnixSocketRaw(
223 ScopedFile(socket(GetSockFamily(family), GetSockType(type), 0)),
224 family,
225 type) {}
226
UnixSocketRaw(ScopedFile fd,SockFamily family,SockType type)227 UnixSocketRaw::UnixSocketRaw(ScopedFile fd, SockFamily family, SockType type)
228 : fd_(std::move(fd)), family_(family), type_(type) {
229 PERFETTO_CHECK(fd_);
230 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
231 const int no_sigpipe = 1;
232 setsockopt(*fd_, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe));
233 #endif
234
235 if (family == SockFamily::kInet || family == SockFamily::kInet6) {
236 int flag = 1;
237 PERFETTO_CHECK(
238 !setsockopt(*fd_, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)));
239 }
240
241 // There is no reason why a socket should outlive the process in case of
242 // exec() by default, this is just working around a broken unix design.
243 int fcntl_res = fcntl(*fd_, F_SETFD, FD_CLOEXEC);
244 PERFETTO_CHECK(fcntl_res == 0);
245 }
246
SetBlocking(bool is_blocking)247 void UnixSocketRaw::SetBlocking(bool is_blocking) {
248 PERFETTO_DCHECK(fd_);
249 int flags = fcntl(*fd_, F_GETFL, 0);
250 if (!is_blocking) {
251 flags |= O_NONBLOCK;
252 } else {
253 flags &= ~static_cast<int>(O_NONBLOCK);
254 }
255 bool fcntl_res = fcntl(*fd_, F_SETFL, flags);
256 PERFETTO_CHECK(fcntl_res == 0);
257 }
258
RetainOnExec()259 void UnixSocketRaw::RetainOnExec() {
260 PERFETTO_DCHECK(fd_);
261 int flags = fcntl(*fd_, F_GETFD, 0);
262 flags &= ~static_cast<int>(FD_CLOEXEC);
263 bool fcntl_res = fcntl(*fd_, F_SETFD, flags);
264 PERFETTO_CHECK(fcntl_res == 0);
265 }
266
IsBlocking() const267 bool UnixSocketRaw::IsBlocking() const {
268 PERFETTO_DCHECK(fd_);
269 return (fcntl(*fd_, F_GETFL, 0) & O_NONBLOCK) == 0;
270 }
271
Bind(const std::string & socket_name)272 bool UnixSocketRaw::Bind(const std::string& socket_name) {
273 PERFETTO_DCHECK(fd_);
274 SockaddrAny addr = MakeSockAddr(family_, socket_name);
275 if (addr.size == 0)
276 return false;
277
278 if (bind(*fd_, addr.addr(), addr.size)) {
279 PERFETTO_DPLOG("bind(%s)", socket_name.c_str());
280 return false;
281 }
282
283 return true;
284 }
285
Listen()286 bool UnixSocketRaw::Listen() {
287 PERFETTO_DCHECK(fd_);
288 PERFETTO_DCHECK(type_ == SockType::kStream || type_ == SockType::kSeqPacket);
289 return listen(*fd_, SOMAXCONN) == 0;
290 }
291
Connect(const std::string & socket_name)292 bool UnixSocketRaw::Connect(const std::string& socket_name) {
293 PERFETTO_DCHECK(fd_);
294 SockaddrAny addr = MakeSockAddr(family_, socket_name);
295 if (addr.size == 0)
296 return false;
297
298 int res = PERFETTO_EINTR(connect(*fd_, addr.addr(), addr.size));
299 if (res && errno != EINPROGRESS)
300 return false;
301
302 return true;
303 }
304
Shutdown()305 void UnixSocketRaw::Shutdown() {
306 shutdown(*fd_, SHUT_RDWR);
307 fd_.reset();
308 }
309
310 // For the interested reader, Linux kernel dive to verify this is not only a
311 // theoretical possibility: sock_stream_sendmsg, if sock_alloc_send_pskb returns
312 // NULL [1] (which it does when it gets interrupted [2]), returns early with the
313 // amount of bytes already sent.
314 //
315 // [1]:
316 // https://elixir.bootlin.com/linux/v4.18.10/source/net/unix/af_unix.c#L1872
317 // [2]: https://elixir.bootlin.com/linux/v4.18.10/source/net/core/sock.c#L2101
SendMsgAll(struct msghdr * msg)318 ssize_t UnixSocketRaw::SendMsgAll(struct msghdr* msg) {
319 // This does not make sense on non-blocking sockets.
320 PERFETTO_DCHECK(fd_);
321
322 ssize_t total_sent = 0;
323 while (msg->msg_iov) {
324 ssize_t sent = PERFETTO_EINTR(sendmsg(*fd_, msg, kNoSigPipe));
325 if (sent <= 0) {
326 if (sent == -1 && IsAgain(errno))
327 return total_sent;
328 return sent;
329 }
330 total_sent += sent;
331 ShiftMsgHdr(static_cast<size_t>(sent), msg);
332 // Only send the ancillary data with the first sendmsg call.
333 msg->msg_control = nullptr;
334 msg->msg_controllen = 0;
335 }
336 return total_sent;
337 }
338
Send(const void * msg,size_t len,const int * send_fds,size_t num_fds)339 ssize_t UnixSocketRaw::Send(const void* msg,
340 size_t len,
341 const int* send_fds,
342 size_t num_fds) {
343 PERFETTO_DCHECK(fd_);
344 msghdr msg_hdr = {};
345 iovec iov = {const_cast<void*>(msg), len};
346 msg_hdr.msg_iov = &iov;
347 msg_hdr.msg_iovlen = 1;
348 alignas(cmsghdr) char control_buf[256];
349
350 if (num_fds > 0) {
351 const auto raw_ctl_data_sz = num_fds * sizeof(int);
352 const CBufLenType control_buf_len =
353 static_cast<CBufLenType>(CMSG_SPACE(raw_ctl_data_sz));
354 PERFETTO_CHECK(control_buf_len <= sizeof(control_buf));
355 memset(control_buf, 0, sizeof(control_buf));
356 msg_hdr.msg_control = control_buf;
357 msg_hdr.msg_controllen = control_buf_len; // used by CMSG_FIRSTHDR
358 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr);
359 cmsg->cmsg_level = SOL_SOCKET;
360 cmsg->cmsg_type = SCM_RIGHTS;
361 cmsg->cmsg_len = static_cast<CBufLenType>(CMSG_LEN(raw_ctl_data_sz));
362 memcpy(CMSG_DATA(cmsg), send_fds, num_fds * sizeof(int));
363 // note: if we were to send multiple cmsghdr structures, then
364 // msg_hdr.msg_controllen would need to be adjusted, see "man 3 cmsg".
365 }
366
367 return SendMsgAll(&msg_hdr);
368 }
369
Receive(void * msg,size_t len,ScopedFile * fd_vec,size_t max_files)370 ssize_t UnixSocketRaw::Receive(void* msg,
371 size_t len,
372 ScopedFile* fd_vec,
373 size_t max_files) {
374 PERFETTO_DCHECK(fd_);
375 msghdr msg_hdr = {};
376 iovec iov = {msg, len};
377 msg_hdr.msg_iov = &iov;
378 msg_hdr.msg_iovlen = 1;
379 alignas(cmsghdr) char control_buf[256];
380
381 if (max_files > 0) {
382 msg_hdr.msg_control = control_buf;
383 msg_hdr.msg_controllen =
384 static_cast<CBufLenType>(CMSG_SPACE(max_files * sizeof(int)));
385 PERFETTO_CHECK(msg_hdr.msg_controllen <= sizeof(control_buf));
386 }
387 const ssize_t sz = PERFETTO_EINTR(recvmsg(*fd_, &msg_hdr, 0));
388 if (sz <= 0) {
389 return sz;
390 }
391 PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
392
393 int* fds = nullptr;
394 uint32_t fds_len = 0;
395
396 if (max_files > 0) {
397 for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr); cmsg;
398 cmsg = CMSG_NXTHDR(&msg_hdr, cmsg)) {
399 const size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0);
400 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
401 PERFETTO_DCHECK(payload_len % sizeof(int) == 0u);
402 PERFETTO_CHECK(fds == nullptr);
403 fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
404 fds_len = static_cast<uint32_t>(payload_len / sizeof(int));
405 }
406 }
407 }
408
409 if (msg_hdr.msg_flags & MSG_TRUNC || msg_hdr.msg_flags & MSG_CTRUNC) {
410 for (size_t i = 0; fds && i < fds_len; ++i)
411 close(fds[i]);
412 errno = EMSGSIZE;
413 return -1;
414 }
415
416 for (size_t i = 0; fds && i < fds_len; ++i) {
417 if (i < max_files)
418 fd_vec[i].reset(fds[i]);
419 else
420 close(fds[i]);
421 }
422
423 return sz;
424 }
425
SetTxTimeout(uint32_t timeout_ms)426 bool UnixSocketRaw::SetTxTimeout(uint32_t timeout_ms) {
427 PERFETTO_DCHECK(fd_);
428 struct timeval timeout {};
429 uint32_t timeout_sec = timeout_ms / 1000;
430 timeout.tv_sec = static_cast<decltype(timeout.tv_sec)>(timeout_sec);
431 timeout.tv_usec = static_cast<decltype(timeout.tv_usec)>(
432 (timeout_ms - (timeout_sec * 1000)) * 1000);
433
434 return setsockopt(*fd_, SOL_SOCKET, SO_SNDTIMEO,
435 reinterpret_cast<const char*>(&timeout),
436 sizeof(timeout)) == 0;
437 }
438
SetRxTimeout(uint32_t timeout_ms)439 bool UnixSocketRaw::SetRxTimeout(uint32_t timeout_ms) {
440 PERFETTO_DCHECK(fd_);
441 struct timeval timeout {};
442 uint32_t timeout_sec = timeout_ms / 1000;
443 timeout.tv_sec = static_cast<decltype(timeout.tv_sec)>(timeout_sec);
444 timeout.tv_usec = static_cast<decltype(timeout.tv_usec)>(
445 (timeout_ms - (timeout_sec * 1000)) * 1000);
446
447 return setsockopt(*fd_, SOL_SOCKET, SO_RCVTIMEO,
448 reinterpret_cast<const char*>(&timeout),
449 sizeof(timeout)) == 0;
450 }
451
452 #pragma GCC diagnostic pop
453
454 // +--------------------+
455 // | UnixSocket methods |
456 // +--------------------+
457
458 // TODO(primiano): Add ThreadChecker to methods of this class.
459
460 // static
Listen(const std::string & socket_name,EventListener * event_listener,TaskRunner * task_runner,SockFamily sock_family,SockType sock_type)461 std::unique_ptr<UnixSocket> UnixSocket::Listen(const std::string& socket_name,
462 EventListener* event_listener,
463 TaskRunner* task_runner,
464 SockFamily sock_family,
465 SockType sock_type) {
466 auto sock_raw = UnixSocketRaw::CreateMayFail(sock_family, sock_type);
467 if (!sock_raw || !sock_raw.Bind(socket_name))
468 return nullptr;
469
470 // Forward the call to the Listen() overload below.
471 return Listen(sock_raw.ReleaseFd(), event_listener, task_runner, sock_family,
472 sock_type);
473 }
474
475 // static
Listen(ScopedFile fd,EventListener * event_listener,TaskRunner * task_runner,SockFamily sock_family,SockType sock_type)476 std::unique_ptr<UnixSocket> UnixSocket::Listen(ScopedFile fd,
477 EventListener* event_listener,
478 TaskRunner* task_runner,
479 SockFamily sock_family,
480 SockType sock_type) {
481 return std::unique_ptr<UnixSocket>(
482 new UnixSocket(event_listener, task_runner, std::move(fd),
483 State::kListening, sock_family, sock_type));
484 }
485
486 // static
Connect(const std::string & socket_name,EventListener * event_listener,TaskRunner * task_runner,SockFamily sock_family,SockType sock_type)487 std::unique_ptr<UnixSocket> UnixSocket::Connect(const std::string& socket_name,
488 EventListener* event_listener,
489 TaskRunner* task_runner,
490 SockFamily sock_family,
491 SockType sock_type) {
492 std::unique_ptr<UnixSocket> sock(
493 new UnixSocket(event_listener, task_runner, sock_family, sock_type));
494 sock->DoConnect(socket_name);
495 return sock;
496 }
497
498 // static
AdoptConnected(ScopedFile fd,EventListener * event_listener,TaskRunner * task_runner,SockFamily sock_family,SockType sock_type)499 std::unique_ptr<UnixSocket> UnixSocket::AdoptConnected(
500 ScopedFile fd,
501 EventListener* event_listener,
502 TaskRunner* task_runner,
503 SockFamily sock_family,
504 SockType sock_type) {
505 return std::unique_ptr<UnixSocket>(
506 new UnixSocket(event_listener, task_runner, std::move(fd),
507 State::kConnected, sock_family, sock_type));
508 }
509
UnixSocket(EventListener * event_listener,TaskRunner * task_runner,SockFamily sock_family,SockType sock_type)510 UnixSocket::UnixSocket(EventListener* event_listener,
511 TaskRunner* task_runner,
512 SockFamily sock_family,
513 SockType sock_type)
514 : UnixSocket(event_listener,
515 task_runner,
516 ScopedFile(),
517 State::kDisconnected,
518 sock_family,
519 sock_type) {}
520
UnixSocket(EventListener * event_listener,TaskRunner * task_runner,ScopedFile adopt_fd,State adopt_state,SockFamily sock_family,SockType sock_type)521 UnixSocket::UnixSocket(EventListener* event_listener,
522 TaskRunner* task_runner,
523 ScopedFile adopt_fd,
524 State adopt_state,
525 SockFamily sock_family,
526 SockType sock_type)
527 : event_listener_(event_listener),
528 task_runner_(task_runner),
529 weak_ptr_factory_(this) {
530 state_ = State::kDisconnected;
531 if (adopt_state == State::kDisconnected) {
532 PERFETTO_DCHECK(!adopt_fd);
533 sock_raw_ = UnixSocketRaw::CreateMayFail(sock_family, sock_type);
534 if (!sock_raw_) {
535 last_error_ = errno;
536 return;
537 }
538 } else if (adopt_state == State::kConnected) {
539 PERFETTO_DCHECK(adopt_fd);
540 sock_raw_ = UnixSocketRaw(std::move(adopt_fd), sock_family, sock_type);
541 state_ = State::kConnected;
542 ReadPeerCredentials();
543 } else if (adopt_state == State::kListening) {
544 // We get here from Listen().
545
546 // |adopt_fd| might genuinely be invalid if the bind() failed.
547 if (!adopt_fd) {
548 last_error_ = errno;
549 return;
550 }
551
552 sock_raw_ = UnixSocketRaw(std::move(adopt_fd), sock_family, sock_type);
553 if (!sock_raw_.Listen()) {
554 last_error_ = errno;
555 PERFETTO_DPLOG("listen()");
556 return;
557 }
558 state_ = State::kListening;
559 } else {
560 PERFETTO_FATAL("Unexpected adopt_state"); // Unfeasible.
561 }
562
563 PERFETTO_CHECK(sock_raw_);
564 last_error_ = 0;
565
566 sock_raw_.SetBlocking(false);
567
568 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
569
570 task_runner_->AddFileDescriptorWatch(sock_raw_.fd(), [weak_ptr] {
571 if (weak_ptr)
572 weak_ptr->OnEvent();
573 });
574 }
575
~UnixSocket()576 UnixSocket::~UnixSocket() {
577 // The implicit dtor of |weak_ptr_factory_| will no-op pending callbacks.
578 Shutdown(true);
579 }
580
ReleaseSocket()581 UnixSocketRaw UnixSocket::ReleaseSocket() {
582 // This will invalidate any pending calls to OnEvent.
583 state_ = State::kDisconnected;
584 if (sock_raw_)
585 task_runner_->RemoveFileDescriptorWatch(sock_raw_.fd());
586
587 return std::move(sock_raw_);
588 }
589
590 // Called only by the Connect() static constructor.
DoConnect(const std::string & socket_name)591 void UnixSocket::DoConnect(const std::string& socket_name) {
592 PERFETTO_DCHECK(state_ == State::kDisconnected);
593
594 // This is the only thing that can gracefully fail in the ctor.
595 if (!sock_raw_)
596 return NotifyConnectionState(false);
597
598 if (!sock_raw_.Connect(socket_name)) {
599 last_error_ = errno;
600 return NotifyConnectionState(false);
601 }
602
603 // At this point either connect() succeeded or started asynchronously
604 // (errno = EINPROGRESS).
605 last_error_ = 0;
606 state_ = State::kConnecting;
607
608 // Even if the socket is non-blocking, connecting to a UNIX socket can be
609 // acknowledged straight away rather than returning EINPROGRESS.
610 // The decision here is to deal with the two cases uniformly, at the cost of
611 // delaying the straight-away-connect() case by one task, to avoid depending
612 // on implementation details of UNIX socket on the various OSes.
613 // Posting the OnEvent() below emulates a wakeup of the FD watch. OnEvent(),
614 // which knows how to deal with spurious wakeups, will poll the SO_ERROR and
615 // evolve, if necessary, the state into either kConnected or kDisconnected.
616 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
617 task_runner_->PostTask([weak_ptr] {
618 if (weak_ptr)
619 weak_ptr->OnEvent();
620 });
621 }
622
ReadPeerCredentials()623 void UnixSocket::ReadPeerCredentials() {
624 // Peer credentials are supported only on AF_UNIX sockets.
625 if (sock_raw_.family() != SockFamily::kUnix)
626 return;
627
628 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
629 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
630 struct ucred user_cred;
631 socklen_t len = sizeof(user_cred);
632 int fd = sock_raw_.fd();
633 int res = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &user_cred, &len);
634 PERFETTO_CHECK(res == 0);
635 peer_uid_ = user_cred.uid;
636 peer_pid_ = user_cred.pid;
637 #else
638 struct xucred user_cred;
639 socklen_t len = sizeof(user_cred);
640 int res = getsockopt(sock_raw_.fd(), 0, LOCAL_PEERCRED, &user_cred, &len);
641 PERFETTO_CHECK(res == 0 && user_cred.cr_version == XUCRED_VERSION);
642 peer_uid_ = static_cast<uid_t>(user_cred.cr_uid);
643 // There is no pid in the LOCAL_PEERCREDS for MacOS / FreeBSD.
644 #endif
645 }
646
OnEvent()647 void UnixSocket::OnEvent() {
648 if (state_ == State::kDisconnected)
649 return; // Some spurious event, typically queued just before Shutdown().
650
651 if (state_ == State::kConnected)
652 return event_listener_->OnDataAvailable(this);
653
654 if (state_ == State::kConnecting) {
655 PERFETTO_DCHECK(sock_raw_);
656 int sock_err = EINVAL;
657 socklen_t err_len = sizeof(sock_err);
658 int res =
659 getsockopt(sock_raw_.fd(), SOL_SOCKET, SO_ERROR, &sock_err, &err_len);
660
661 if (res == 0 && sock_err == EINPROGRESS)
662 return; // Not connected yet, just a spurious FD watch wakeup.
663 if (res == 0 && sock_err == 0) {
664 ReadPeerCredentials();
665 state_ = State::kConnected;
666 return event_listener_->OnConnect(this, true /* connected */);
667 }
668 PERFETTO_DLOG("Connection error: %s", strerror(sock_err));
669 last_error_ = sock_err;
670 Shutdown(false);
671 return event_listener_->OnConnect(this, false /* connected */);
672 }
673
674 // New incoming connection.
675 if (state_ == State::kListening) {
676 // There could be more than one incoming connection behind each FD watch
677 // notification. Drain'em all.
678 for (;;) {
679 struct sockaddr_in cli_addr {};
680 socklen_t size = sizeof(cli_addr);
681 ScopedFile new_fd(PERFETTO_EINTR(accept(
682 sock_raw_.fd(), reinterpret_cast<sockaddr*>(&cli_addr), &size)));
683 if (!new_fd)
684 return;
685 std::unique_ptr<UnixSocket> new_sock(new UnixSocket(
686 event_listener_, task_runner_, std::move(new_fd), State::kConnected,
687 sock_raw_.family(), sock_raw_.type()));
688 event_listener_->OnNewIncomingConnection(this, std::move(new_sock));
689 }
690 }
691 }
692
Send(const void * msg,size_t len,const int * send_fds,size_t num_fds)693 bool UnixSocket::Send(const void* msg,
694 size_t len,
695 const int* send_fds,
696 size_t num_fds) {
697 if (state_ != State::kConnected) {
698 errno = last_error_ = ENOTCONN;
699 return false;
700 }
701
702 sock_raw_.SetBlocking(true);
703 const ssize_t sz = sock_raw_.Send(msg, len, send_fds, num_fds);
704 int saved_errno = errno;
705 sock_raw_.SetBlocking(false);
706
707 if (sz == static_cast<ssize_t>(len)) {
708 last_error_ = 0;
709 return true;
710 }
711
712 // If sendmsg() succeeds but the returned size is < |len| it means that the
713 // endpoint disconnected in the middle of the read, and we managed to send
714 // only a portion of the buffer. In this case we should just give up.
715
716 if (sz < 0 && (saved_errno == EAGAIN || saved_errno == EWOULDBLOCK)) {
717 // A genuine out-of-buffer. The client should retry or give up.
718 // Man pages specify that EAGAIN and EWOULDBLOCK have the same semantic here
719 // and clients should check for both.
720 last_error_ = EAGAIN;
721 return false;
722 }
723
724 // Either the other endpoint disconnected (ECONNRESET) or some other error
725 // happened.
726 last_error_ = saved_errno;
727 PERFETTO_DPLOG("sendmsg() failed");
728 Shutdown(true);
729 return false;
730 }
731
Shutdown(bool notify)732 void UnixSocket::Shutdown(bool notify) {
733 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
734 if (notify) {
735 if (state_ == State::kConnected) {
736 task_runner_->PostTask([weak_ptr] {
737 if (weak_ptr)
738 weak_ptr->event_listener_->OnDisconnect(weak_ptr.get());
739 });
740 } else if (state_ == State::kConnecting) {
741 task_runner_->PostTask([weak_ptr] {
742 if (weak_ptr)
743 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), false);
744 });
745 }
746 }
747
748 if (sock_raw_) {
749 task_runner_->RemoveFileDescriptorWatch(sock_raw_.fd());
750 sock_raw_.Shutdown();
751 }
752 state_ = State::kDisconnected;
753 }
754
Receive(void * msg,size_t len,ScopedFile * fd_vec,size_t max_files)755 size_t UnixSocket::Receive(void* msg,
756 size_t len,
757 ScopedFile* fd_vec,
758 size_t max_files) {
759 if (state_ != State::kConnected) {
760 last_error_ = ENOTCONN;
761 return 0;
762 }
763
764 const ssize_t sz = sock_raw_.Receive(msg, len, fd_vec, max_files);
765 if (sz < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
766 last_error_ = EAGAIN;
767 return 0;
768 }
769 if (sz <= 0) {
770 last_error_ = errno;
771 Shutdown(true);
772 return 0;
773 }
774 PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
775 return static_cast<size_t>(sz);
776 }
777
ReceiveString(size_t max_length)778 std::string UnixSocket::ReceiveString(size_t max_length) {
779 std::unique_ptr<char[]> buf(new char[max_length + 1]);
780 size_t rsize = Receive(buf.get(), max_length);
781 PERFETTO_CHECK(static_cast<size_t>(rsize) <= max_length);
782 buf[static_cast<size_t>(rsize)] = '\0';
783 return std::string(buf.get());
784 }
785
NotifyConnectionState(bool success)786 void UnixSocket::NotifyConnectionState(bool success) {
787 if (!success)
788 Shutdown(false);
789
790 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
791 task_runner_->PostTask([weak_ptr, success] {
792 if (weak_ptr)
793 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), success);
794 });
795 }
796
~EventListener()797 UnixSocket::EventListener::~EventListener() {}
OnNewIncomingConnection(UnixSocket *,std::unique_ptr<UnixSocket>)798 void UnixSocket::EventListener::OnNewIncomingConnection(
799 UnixSocket*,
800 std::unique_ptr<UnixSocket>) {}
OnConnect(UnixSocket *,bool)801 void UnixSocket::EventListener::OnConnect(UnixSocket*, bool) {}
OnDisconnect(UnixSocket *)802 void UnixSocket::EventListener::OnDisconnect(UnixSocket*) {}
OnDataAvailable(UnixSocket *)803 void UnixSocket::EventListener::OnDataAvailable(UnixSocket*) {}
804
805 } // namespace base
806 } // namespace perfetto
807