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