• 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 "src/ipc/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 ipc {
43 
44 // TODO(primiano): Add ThreadChecker to methods of this class.
45 
46 namespace {
47 
48 // MSG_NOSIGNAL is not supported on Mac OS X, but in that case the socket is
49 // created with SO_NOSIGPIPE (See InitializeSocket()).
50 #if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
51 constexpr int kNoSigPipe = 0;
52 #else
53 constexpr int kNoSigPipe = MSG_NOSIGNAL;
54 #endif
55 
56 // Android takes an int instead of socklen_t for the control buffer size.
57 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
58 using CBufLenType = size_t;
59 #else
60 using CBufLenType = socklen_t;
61 #endif
62 
MakeSockAddr(const std::string & socket_name,sockaddr_un * addr,socklen_t * addr_size)63 bool MakeSockAddr(const std::string& socket_name,
64                   sockaddr_un* addr,
65                   socklen_t* addr_size) {
66   memset(addr, 0, sizeof(*addr));
67   const size_t name_len = socket_name.size();
68   if (name_len >= sizeof(addr->sun_path)) {
69     errno = ENAMETOOLONG;
70     return false;
71   }
72   memcpy(addr->sun_path, socket_name.data(), name_len);
73   if (addr->sun_path[0] == '@')
74     addr->sun_path[0] = '\0';
75   addr->sun_family = AF_UNIX;
76   *addr_size = static_cast<socklen_t>(
77       __builtin_offsetof(sockaddr_un, sun_path) + name_len + 1);
78   return true;
79 }
80 
CreateSocket()81 base::ScopedFile CreateSocket() {
82   return base::ScopedFile(socket(AF_UNIX, SOCK_STREAM, 0));
83 }
84 
85 }  // namespace
86 
87 // static
CreateAndBind(const std::string & socket_name)88 base::ScopedFile UnixSocket::CreateAndBind(const std::string& socket_name) {
89   base::ScopedFile fd = CreateSocket();
90   if (!fd)
91     return fd;
92 
93   sockaddr_un addr;
94   socklen_t addr_size;
95   if (!MakeSockAddr(socket_name, &addr, &addr_size)) {
96     return base::ScopedFile();
97   }
98 
99   if (bind(*fd, reinterpret_cast<sockaddr*>(&addr), addr_size)) {
100     PERFETTO_DPLOG("bind()");
101     return base::ScopedFile();
102   }
103 
104   return fd;
105 }
106 
107 // static
Listen(const std::string & socket_name,EventListener * event_listener,base::TaskRunner * task_runner)108 std::unique_ptr<UnixSocket> UnixSocket::Listen(const std::string& socket_name,
109                                                EventListener* event_listener,
110                                                base::TaskRunner* task_runner) {
111   // Forward the call to the Listen() overload below.
112   return Listen(CreateAndBind(socket_name), event_listener, task_runner);
113 }
114 
115 // static
Listen(base::ScopedFile socket_fd,EventListener * event_listener,base::TaskRunner * task_runner)116 std::unique_ptr<UnixSocket> UnixSocket::Listen(base::ScopedFile socket_fd,
117                                                EventListener* event_listener,
118                                                base::TaskRunner* task_runner) {
119   std::unique_ptr<UnixSocket> sock(new UnixSocket(
120       event_listener, task_runner, std::move(socket_fd), State::kListening));
121   return sock;
122 }
123 
124 // static
Connect(const std::string & socket_name,EventListener * event_listener,base::TaskRunner * task_runner)125 std::unique_ptr<UnixSocket> UnixSocket::Connect(const std::string& socket_name,
126                                                 EventListener* event_listener,
127                                                 base::TaskRunner* task_runner) {
128   std::unique_ptr<UnixSocket> sock(new UnixSocket(event_listener, task_runner));
129   sock->DoConnect(socket_name);
130   return sock;
131 }
132 
UnixSocket(EventListener * event_listener,base::TaskRunner * task_runner)133 UnixSocket::UnixSocket(EventListener* event_listener,
134                        base::TaskRunner* task_runner)
135     : UnixSocket(event_listener,
136                  task_runner,
137                  base::ScopedFile(),
138                  State::kDisconnected) {}
139 
UnixSocket(EventListener * event_listener,base::TaskRunner * task_runner,base::ScopedFile adopt_fd,State adopt_state)140 UnixSocket::UnixSocket(EventListener* event_listener,
141                        base::TaskRunner* task_runner,
142                        base::ScopedFile adopt_fd,
143                        State adopt_state)
144     : event_listener_(event_listener),
145       task_runner_(task_runner),
146       weak_ptr_factory_(this) {
147   state_ = State::kDisconnected;
148   if (adopt_state == State::kDisconnected) {
149     // We get here from the default ctor().
150     PERFETTO_DCHECK(!adopt_fd);
151     fd_ = CreateSocket();
152     if (!fd_) {
153       last_error_ = errno;
154       return;
155     }
156   } else if (adopt_state == State::kConnected) {
157     // We get here from OnNewIncomingConnection().
158     PERFETTO_DCHECK(adopt_fd);
159     fd_ = std::move(adopt_fd);
160     state_ = State::kConnected;
161     ReadPeerCredentials();
162   } else if (adopt_state == State::kListening) {
163     // We get here from Listen().
164 
165     // |adopt_fd| might genuinely be invalid if the bind() failed.
166     if (!adopt_fd) {
167       last_error_ = errno;
168       return;
169     }
170 
171     fd_ = std::move(adopt_fd);
172     if (listen(*fd_, SOMAXCONN)) {
173       last_error_ = errno;
174       PERFETTO_DPLOG("listen()");
175       return;
176     }
177     state_ = State::kListening;
178   } else {
179     PERFETTO_CHECK(false);  // Unfeasible.
180   }
181 
182   PERFETTO_DCHECK(fd_);
183   last_error_ = 0;
184 
185 #if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
186   const int no_sigpipe = 1;
187   setsockopt(*fd_, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe));
188 #endif
189   // There is no reason why a socket should outlive the process in case of
190   // exec() by default, this is just working around a broken unix design.
191   int fcntl_res = fcntl(*fd_, F_SETFD, FD_CLOEXEC);
192   PERFETTO_CHECK(fcntl_res == 0);
193 
194   SetBlockingIO(false);
195 
196   base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
197   task_runner_->AddFileDescriptorWatch(*fd_, [weak_ptr]() {
198     if (weak_ptr)
199       weak_ptr->OnEvent();
200   });
201 }
202 
~UnixSocket()203 UnixSocket::~UnixSocket() {
204   // The implicit dtor of |weak_ptr_factory_| will no-op pending callbacks.
205   Shutdown(true);
206 }
207 
208 // Called only by the Connect() static constructor.
DoConnect(const std::string & socket_name)209 void UnixSocket::DoConnect(const std::string& socket_name) {
210   PERFETTO_DCHECK(state_ == State::kDisconnected);
211 
212   // This is the only thing that can gracefully fail in the ctor.
213   if (!fd_)
214     return NotifyConnectionState(false);
215 
216   sockaddr_un addr;
217   socklen_t addr_size;
218   if (!MakeSockAddr(socket_name, &addr, &addr_size)) {
219     last_error_ = errno;
220     return NotifyConnectionState(false);
221   }
222 
223   int res = PERFETTO_EINTR(
224       connect(*fd_, reinterpret_cast<sockaddr*>(&addr), addr_size));
225   if (res && errno != EINPROGRESS) {
226     last_error_ = errno;
227     return NotifyConnectionState(false);
228   }
229 
230   // At this point either |res| == 0 (the connect() succeeded) or started
231   // asynchronously (EINPROGRESS).
232   last_error_ = 0;
233   state_ = State::kConnecting;
234 
235   // Even if the socket is non-blocking, connecting to a UNIX socket can be
236   // acknowledged straight away rather than returning EINPROGRESS. In this case
237   // just trigger an OnEvent without waiting for the FD watch. That will poll
238   // the SO_ERROR and evolve the state into either kConnected or kDisconnected.
239   if (res == 0) {
240     base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
241     task_runner_->PostTask([weak_ptr]() {
242       if (weak_ptr)
243         weak_ptr->OnEvent();
244     });
245   }
246 }
247 
ReadPeerCredentials()248 void UnixSocket::ReadPeerCredentials() {
249 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
250     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
251   struct ucred user_cred;
252   socklen_t len = sizeof(user_cred);
253   int res = getsockopt(*fd_, SOL_SOCKET, SO_PEERCRED, &user_cred, &len);
254   PERFETTO_CHECK(res == 0);
255   peer_uid_ = user_cred.uid;
256 #else
257   struct xucred user_cred;
258   socklen_t len = sizeof(user_cred);
259   int res = getsockopt(*fd_, 0, LOCAL_PEERCRED, &user_cred, &len);
260   PERFETTO_CHECK(res == 0 && user_cred.cr_version == XUCRED_VERSION);
261   peer_uid_ = static_cast<uid_t>(user_cred.cr_uid);
262 #endif
263 }
264 
OnEvent()265 void UnixSocket::OnEvent() {
266   if (state_ == State::kDisconnected)
267     return;  // Some spurious event, typically queued just before Shutdown().
268 
269   if (state_ == State::kConnected)
270     return event_listener_->OnDataAvailable(this);
271 
272   if (state_ == State::kConnecting) {
273     PERFETTO_DCHECK(fd_);
274     int sock_err = EINVAL;
275     socklen_t err_len = sizeof(sock_err);
276     int res = getsockopt(*fd_, SOL_SOCKET, SO_ERROR, &sock_err, &err_len);
277     if (res == 0 && sock_err == EINPROGRESS)
278       return;  // Not connected yet, just a spurious FD watch wakeup.
279     if (res == 0 && sock_err == 0) {
280       ReadPeerCredentials();
281       state_ = State::kConnected;
282       return event_listener_->OnConnect(this, true /* connected */);
283     }
284     last_error_ = sock_err;
285     Shutdown(false);
286     return event_listener_->OnConnect(this, false /* connected */);
287   }
288 
289   // New incoming connection.
290   if (state_ == State::kListening) {
291     // There could be more than one incoming connection behind each FD watch
292     // notification. Drain'em all.
293     for (;;) {
294       sockaddr_un cli_addr = {};
295       socklen_t size = sizeof(cli_addr);
296       base::ScopedFile new_fd(PERFETTO_EINTR(
297           accept(*fd_, reinterpret_cast<sockaddr*>(&cli_addr), &size)));
298       if (!new_fd)
299         return;
300       std::unique_ptr<UnixSocket> new_sock(new UnixSocket(
301           event_listener_, task_runner_, std::move(new_fd), State::kConnected));
302       event_listener_->OnNewIncomingConnection(this, std::move(new_sock));
303     }
304   }
305 }
306 
Send(const std::string & msg)307 bool UnixSocket::Send(const std::string& msg) {
308   return Send(msg.c_str(), msg.size() + 1);
309 }
310 
Send(const void * msg,size_t len,int send_fd,BlockingMode blocking_mode)311 bool UnixSocket::Send(const void* msg,
312                       size_t len,
313                       int send_fd,
314                       BlockingMode blocking_mode) {
315   if (state_ != State::kConnected) {
316     errno = last_error_ = ENOTCONN;
317     return false;
318   }
319 
320   msghdr msg_hdr = {};
321   iovec iov = {const_cast<void*>(msg), len};
322   msg_hdr.msg_iov = &iov;
323   msg_hdr.msg_iovlen = 1;
324   alignas(cmsghdr) char control_buf[256];
325 
326   if (send_fd > -1) {
327     const CBufLenType control_buf_len =
328         static_cast<CBufLenType>(CMSG_SPACE(sizeof(int)));
329     PERFETTO_CHECK(control_buf_len <= sizeof(control_buf));
330     memset(control_buf, 0, sizeof(control_buf));
331     msg_hdr.msg_control = control_buf;
332     msg_hdr.msg_controllen = control_buf_len;
333     struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr);
334     cmsg->cmsg_level = SOL_SOCKET;
335     cmsg->cmsg_type = SCM_RIGHTS;
336     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
337     memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(int));
338     msg_hdr.msg_controllen = cmsg->cmsg_len;
339   }
340 
341   if (blocking_mode == BlockingMode::kBlocking)
342     SetBlockingIO(true);
343   const ssize_t sz = PERFETTO_EINTR(sendmsg(*fd_, &msg_hdr, kNoSigPipe));
344   if (blocking_mode == BlockingMode::kBlocking)
345     SetBlockingIO(false);
346 
347   if (sz == static_cast<ssize_t>(len)) {
348     last_error_ = 0;
349     return true;
350   }
351 
352   // If sendmsg() succeds but the returned size is < |len| it means that the
353   // endpoint disconnected in the middle of the read, and we managed to send
354   // only a portion of the buffer. In this case we should just give up.
355 
356   if (sz < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
357     // A genuine out-of-buffer. The client should retry or give up.
358     // Man pages specify that EAGAIN and EWOULDBLOCK have the same semantic here
359     // and clients should check for both.
360     last_error_ = EAGAIN;
361     return false;
362   }
363 
364   // Either the the other endpoint disconnect (ECONNRESET) or some other error
365   // happened.
366   last_error_ = errno;
367   PERFETTO_DPLOG("sendmsg() failed");
368   Shutdown(true);
369   return false;
370 }
371 
Shutdown(bool notify)372 void UnixSocket::Shutdown(bool notify) {
373   base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
374   if (notify) {
375     if (state_ == State::kConnected) {
376       task_runner_->PostTask([weak_ptr]() {
377         if (weak_ptr)
378           weak_ptr->event_listener_->OnDisconnect(weak_ptr.get());
379       });
380     } else if (state_ == State::kConnecting) {
381       task_runner_->PostTask([weak_ptr]() {
382         if (weak_ptr)
383           weak_ptr->event_listener_->OnConnect(weak_ptr.get(), false);
384       });
385     }
386   }
387 
388   if (fd_) {
389     shutdown(*fd_, SHUT_RDWR);
390     task_runner_->RemoveFileDescriptorWatch(*fd_);
391     fd_.reset();
392   }
393   state_ = State::kDisconnected;
394 }
395 
Receive(void * msg,size_t len,base::ScopedFile * recv_fd)396 size_t UnixSocket::Receive(void* msg, size_t len, base::ScopedFile* recv_fd) {
397   if (state_ != State::kConnected) {
398     last_error_ = ENOTCONN;
399     return 0;
400   }
401 
402   msghdr msg_hdr = {};
403   iovec iov = {msg, len};
404   msg_hdr.msg_iov = &iov;
405   msg_hdr.msg_iovlen = 1;
406   alignas(cmsghdr) char control_buf[256];
407 
408   if (recv_fd) {
409     msg_hdr.msg_control = control_buf;
410     msg_hdr.msg_controllen = static_cast<CBufLenType>(CMSG_SPACE(sizeof(int)));
411     PERFETTO_CHECK(msg_hdr.msg_controllen <= sizeof(control_buf));
412   }
413   const ssize_t sz = PERFETTO_EINTR(recvmsg(*fd_, &msg_hdr, kNoSigPipe));
414   if (sz < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
415     last_error_ = EAGAIN;
416     return 0;
417   }
418   if (sz <= 0) {
419     last_error_ = errno;
420     Shutdown(true);
421     return 0;
422   }
423   PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
424 
425   int* fds = nullptr;
426   uint32_t fds_len = 0;
427 
428   if (msg_hdr.msg_controllen > 0) {
429     for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr); cmsg;
430          cmsg = CMSG_NXTHDR(&msg_hdr, cmsg)) {
431       const size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0);
432       if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
433         PERFETTO_DCHECK(payload_len % sizeof(int) == 0u);
434         PERFETTO_DCHECK(fds == nullptr);
435         fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
436         fds_len = static_cast<uint32_t>(payload_len / sizeof(int));
437       }
438     }
439   }
440 
441   if (msg_hdr.msg_flags & MSG_TRUNC || msg_hdr.msg_flags & MSG_CTRUNC) {
442     for (size_t i = 0; fds && i < fds_len; ++i)
443       close(fds[i]);
444     last_error_ = EMSGSIZE;
445     Shutdown(true);
446     return 0;
447   }
448 
449   for (size_t i = 0; fds && i < fds_len; ++i) {
450     if (recv_fd && i == 0) {
451       recv_fd->reset(fds[i]);
452     } else {
453       close(fds[i]);
454     }
455   }
456 
457   last_error_ = 0;
458   return static_cast<size_t>(sz);
459 }
460 
ReceiveString(size_t max_length)461 std::string UnixSocket::ReceiveString(size_t max_length) {
462   std::unique_ptr<char[]> buf(new char[max_length + 1]);
463   size_t rsize = Receive(buf.get(), max_length);
464   PERFETTO_CHECK(static_cast<size_t>(rsize) <= max_length);
465   buf[static_cast<size_t>(rsize)] = '\0';
466   return std::string(buf.get());
467 }
468 
NotifyConnectionState(bool success)469 void UnixSocket::NotifyConnectionState(bool success) {
470   if (!success)
471     Shutdown(false);
472 
473   base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
474   task_runner_->PostTask([weak_ptr, success]() {
475     if (weak_ptr)
476       weak_ptr->event_listener_->OnConnect(weak_ptr.get(), success);
477   });
478 }
479 
SetBlockingIO(bool is_blocking)480 void UnixSocket::SetBlockingIO(bool is_blocking) {
481   int flags = fcntl(*fd_, F_GETFL, 0);
482   if (!is_blocking) {
483     flags |= O_NONBLOCK;
484   } else {
485     flags &= ~static_cast<int>(O_NONBLOCK);
486   }
487   bool fcntl_res = fcntl(fd(), F_SETFL, flags);
488   PERFETTO_CHECK(fcntl_res == 0);
489 }
490 
~EventListener()491 UnixSocket::EventListener::~EventListener() {}
OnNewIncomingConnection(UnixSocket *,std::unique_ptr<UnixSocket>)492 void UnixSocket::EventListener::OnNewIncomingConnection(
493     UnixSocket*,
494     std::unique_ptr<UnixSocket>) {}
OnConnect(UnixSocket *,bool)495 void UnixSocket::EventListener::OnConnect(UnixSocket*, bool) {}
OnDisconnect(UnixSocket *)496 void UnixSocket::EventListener::OnDisconnect(UnixSocket*) {}
OnDataAvailable(UnixSocket *)497 void UnixSocket::EventListener::OnDataAvailable(UnixSocket*) {}
498 
499 }  // namespace ipc
500 }  // namespace perfetto
501