• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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