• 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_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