blob: 66c5fd8330bac9effa6365c0b46def1944d1ed61 [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
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
Oystein Eftevaagff729592018-02-12 14:24:06 -080037#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000038#include <sys/ucred.h>
39#endif
40
41namespace perfetto {
42namespace ipc {
43
44// TODO(primiano): Add ThreadChecker to methods of this class.
45
46namespace {
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()).
Oystein Eftevaagff729592018-02-12 14:24:06 -080050#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000051constexpr int kNoSigPipe = 0;
52#else
53constexpr int kNoSigPipe = MSG_NOSIGNAL;
54#endif
55
56// Android takes an int instead of socklen_t for the control buffer size.
Oystein Eftevaagff729592018-02-12 14:24:06 -080057#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000058using CBufLenType = size_t;
59#else
60using CBufLenType = socklen_t;
61#endif
62
63bool 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
Primiano Tucci9b5d3362017-12-21 21:42:17 +010081base::ScopedFile CreateSocket() {
82 return base::ScopedFile(socket(AF_UNIX, SOCK_STREAM, 0));
83}
84
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000085} // namespace
86
87// static
Primiano Tucci9b5d3362017-12-21 21:42:17 +010088base::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
Primiano Tucci3cbb10a2018-04-10 17:52:40 +010099 if (bind(*fd, reinterpret_cast<sockaddr*>(&addr), addr_size)) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100100 PERFETTO_DPLOG("bind()");
101 return base::ScopedFile();
102 }
103
104 return fd;
105}
106
107// static
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000108std::unique_ptr<UnixSocket> UnixSocket::Listen(const std::string& socket_name,
109 EventListener* event_listener,
110 base::TaskRunner* task_runner) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100111 // Forward the call to the Listen() overload below.
112 return Listen(CreateAndBind(socket_name), event_listener, task_runner);
113}
114
115// static
116std::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));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000121 return sock;
122}
123
124// static
125std::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
133UnixSocket::UnixSocket(EventListener* event_listener,
134 base::TaskRunner* task_runner)
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100135 : UnixSocket(event_listener,
136 task_runner,
137 base::ScopedFile(),
138 State::kDisconnected) {}
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000139
140UnixSocket::UnixSocket(EventListener* event_listener,
141 base::TaskRunner* task_runner,
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100142 base::ScopedFile adopt_fd,
143 State adopt_state)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000144 : event_listener_(event_listener),
145 task_runner_(task_runner),
146 weak_ptr_factory_(this) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100147 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);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000159 fd_ = std::move(adopt_fd);
160 state_ = State::kConnected;
161 ReadPeerCredentials();
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100162 } 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;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000178 } else {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100179 PERFETTO_CHECK(false); // Unfeasible.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000180 }
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100181
182 PERFETTO_DCHECK(fd_);
183 last_error_ = 0;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000184
Oystein Eftevaagff729592018-02-12 14:24:06 -0800185#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000186 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
Primiano Tucci7a265b62017-12-07 18:37:31 +0000194 SetBlockingIO(false);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000195
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
203UnixSocket::~UnixSocket() {
204 // The implicit dtor of |weak_ptr_factory_| will no-op pending callbacks.
Florian Mayer48c139c2018-03-12 14:07:57 +0000205 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000206}
207
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000208// Called only by the Connect() static constructor.
209void 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
248void UnixSocket::ReadPeerCredentials() {
Oystein Eftevaagff729592018-02-12 14:24:06 -0800249#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
250 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000251 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);
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100261 peer_uid_ = static_cast<uid_t>(user_cred.cr_uid);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000262#endif
263}
264
265void 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;
Florian Mayer48c139c2018-03-12 14:07:57 +0000285 Shutdown(false);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000286 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;
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100300 std::unique_ptr<UnixSocket> new_sock(new UnixSocket(
301 event_listener_, task_runner_, std::move(new_fd), State::kConnected));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000302 event_listener_->OnNewIncomingConnection(this, std::move(new_sock));
303 }
304 }
305}
306
307bool UnixSocket::Send(const std::string& msg) {
308 return Send(msg.c_str(), msg.size() + 1);
309}
310
Primiano Tucci7a265b62017-12-07 18:37:31 +0000311bool UnixSocket::Send(const void* msg,
312 size_t len,
313 int send_fd,
314 BlockingMode blocking_mode) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000315 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
Primiano Tucci7a265b62017-12-07 18:37:31 +0000341 if (blocking_mode == BlockingMode::kBlocking)
342 SetBlockingIO(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000343 const ssize_t sz = PERFETTO_EINTR(sendmsg(*fd_, &msg_hdr, kNoSigPipe));
Primiano Tucci7a265b62017-12-07 18:37:31 +0000344 if (blocking_mode == BlockingMode::kBlocking)
345 SetBlockingIO(false);
346
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100347 if (sz == static_cast<ssize_t>(len)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000348 last_error_ = 0;
349 return true;
350 }
351
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100352 // 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)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000357 // 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");
Florian Mayer48c139c2018-03-12 14:07:57 +0000368 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000369 return false;
370}
371
Florian Mayer48c139c2018-03-12 14:07:57 +0000372void UnixSocket::Shutdown(bool notify) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000373 base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Florian Mayer48c139c2018-03-12 14:07:57 +0000374 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 }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000386 }
Florian Mayer48c139c2018-03-12 14:07:57 +0000387
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000388 if (fd_) {
389 shutdown(*fd_, SHUT_RDWR);
390 task_runner_->RemoveFileDescriptorWatch(*fd_);
391 fd_.reset();
392 }
393 state_ = State::kDisconnected;
394}
395
396size_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;
Florian Mayer48c139c2018-03-12 14:07:57 +0000420 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000421 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;
Florian Mayer48c139c2018-03-12 14:07:57 +0000445 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000446 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
461std::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
469void UnixSocket::NotifyConnectionState(bool success) {
Florian Mayer48c139c2018-03-12 14:07:57 +0000470 if (!success)
471 Shutdown(false);
472
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000473 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
Primiano Tucci7a265b62017-12-07 18:37:31 +0000480void 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
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000491UnixSocket::EventListener::~EventListener() {}
492void UnixSocket::EventListener::OnNewIncomingConnection(
493 UnixSocket*,
494 std::unique_ptr<UnixSocket>) {}
495void UnixSocket::EventListener::OnConnect(UnixSocket*, bool) {}
496void UnixSocket::EventListener::OnDisconnect(UnixSocket*) {}
497void UnixSocket::EventListener::OnDataAvailable(UnixSocket*) {}
498
499} // namespace ipc
500} // namespace perfetto