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