blob: 54e3a40896b266a5f1bab21df870c15e80020874 [file] [log] [blame]
Primiano Tuccie73ac932017-11-08 18:11:17 +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 "ipc/src/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
Oystein Eftevaagdd727e42017-12-05 08:49:55 -080032#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"
Primiano Tuccie73ac932017-11-08 18:11:17 +000036
Primiano Tuccic2025af2017-11-20 12:47:49 +000037#if BUILDFLAG(OS_MACOSX)
38#include <sys/ucred.h>
39#endif
40
Primiano Tuccie73ac932017-11-08 18:11:17 +000041namespace 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()).
50#if BUILDFLAG(OS_MACOSX)
51constexpr 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.
57#if BUILDFLAG(OS_ANDROID)
58using 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
81} // namespace
82
83// static
84std::unique_ptr<UnixSocket> UnixSocket::Listen(const std::string& socket_name,
85 EventListener* event_listener,
86 base::TaskRunner* task_runner) {
87 std::unique_ptr<UnixSocket> sock(new UnixSocket(event_listener, task_runner));
88 sock->DoListen(socket_name);
89 return sock;
90}
91
92// static
93std::unique_ptr<UnixSocket> UnixSocket::Connect(const std::string& socket_name,
94 EventListener* event_listener,
95 base::TaskRunner* task_runner) {
96 std::unique_ptr<UnixSocket> sock(new UnixSocket(event_listener, task_runner));
97 sock->DoConnect(socket_name);
98 return sock;
99}
100
101UnixSocket::UnixSocket(EventListener* event_listener,
102 base::TaskRunner* task_runner)
103 : UnixSocket(event_listener, task_runner, base::ScopedFile()) {}
104
105UnixSocket::UnixSocket(EventListener* event_listener,
106 base::TaskRunner* task_runner,
107 base::ScopedFile adopt_fd)
108 : event_listener_(event_listener),
109 task_runner_(task_runner),
Primiano Tucci575af772017-11-08 18:14:17 +0000110 weak_ptr_factory_(this) {
Primiano Tuccie73ac932017-11-08 18:11:17 +0000111 if (adopt_fd) {
112 // Only in the case of OnNewIncomingConnection().
113 fd_ = std::move(adopt_fd);
114 state_ = State::kConnected;
Primiano Tuccic2025af2017-11-20 12:47:49 +0000115 ReadPeerCredentials();
Primiano Tuccie73ac932017-11-08 18:11:17 +0000116 } else {
117 fd_.reset(socket(AF_UNIX, SOCK_STREAM, 0));
118 }
119 if (!fd_) {
120 last_error_ = errno;
121 return;
122 }
123
124#if BUILDFLAG(OS_MACOSX)
125 const int no_sigpipe = 1;
126 setsockopt(*fd_, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe));
127#endif
128 // There is no reason why a socket should outlive the process in case of
129 // exec() by default, this is just working around a broken unix design.
Sami Kyostila2c6c2f52017-11-21 16:08:16 +0000130 int fcntl_res = fcntl(*fd_, F_SETFD, FD_CLOEXEC);
131 PERFETTO_CHECK(fcntl_res == 0);
Primiano Tuccie73ac932017-11-08 18:11:17 +0000132
133 // Set non-blocking mode.
134 int flags = fcntl(*fd_, F_GETFL, 0);
135 flags |= O_NONBLOCK;
136 fcntl_res = fcntl(fd(), F_SETFL, flags);
137 PERFETTO_CHECK(fcntl_res == 0);
138
Primiano Tucci575af772017-11-08 18:14:17 +0000139 base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
140 task_runner_->AddFileDescriptorWatch(*fd_, [weak_ptr]() {
141 if (weak_ptr)
142 weak_ptr->OnEvent();
Primiano Tuccie73ac932017-11-08 18:11:17 +0000143 });
144}
145
146UnixSocket::~UnixSocket() {
Primiano Tucci575af772017-11-08 18:14:17 +0000147 // The implicit dtor of |weak_ptr_factory_| will no-op pending callbacks.
Primiano Tuccie73ac932017-11-08 18:11:17 +0000148 Shutdown();
149}
150
151// Called only by the Listen() static constructor.
152void UnixSocket::DoListen(const std::string& socket_name) {
153 PERFETTO_DCHECK(state_ == State::kDisconnected);
154 if (!fd_)
155 return; // This is the only thing that can gracefully fail in the ctor.
156
157 sockaddr_un addr;
158 socklen_t addr_size;
159 if (!MakeSockAddr(socket_name, &addr, &addr_size)) {
160 last_error_ = errno;
161 return;
162 }
163
164// Android takes an int as 3rd argument of bind() instead of socklen_t.
165#if BUILDFLAG(OS_ANDROID)
166 const int bind_size = static_cast<int>(addr_size);
167#else
168 const socklen_t bind_size = addr_size;
169#endif
170
171 if (bind(*fd_, reinterpret_cast<sockaddr*>(&addr), bind_size)) {
172 last_error_ = errno;
173 PERFETTO_DPLOG("bind()");
174 return;
175 }
176 if (listen(*fd_, SOMAXCONN)) {
177 last_error_ = errno;
178 PERFETTO_DPLOG("listen()");
179 return;
180 }
181
182 last_error_ = 0;
183 state_ = State::kListening;
184}
185
186// Called only by the Connect() static constructor.
187void UnixSocket::DoConnect(const std::string& socket_name) {
188 PERFETTO_DCHECK(state_ == State::kDisconnected);
189
190 // This is the only thing that can gracefully fail in the ctor.
191 if (!fd_)
192 return NotifyConnectionState(false);
193
194 sockaddr_un addr;
195 socklen_t addr_size;
196 if (!MakeSockAddr(socket_name, &addr, &addr_size)) {
197 last_error_ = errno;
198 return NotifyConnectionState(false);
199 }
200
201 int res = PERFETTO_EINTR(
202 connect(*fd_, reinterpret_cast<sockaddr*>(&addr), addr_size));
203 if (res && errno != EINPROGRESS) {
204 last_error_ = errno;
205 return NotifyConnectionState(false);
206 }
207
208 // At this point either |res| == 0 (the connect() succeeded) or started
209 // asynchronously (EINPROGRESS).
210 last_error_ = 0;
211 state_ = State::kConnecting;
212
213 // Even if the socket is non-blocking, connecting to a UNIX socket can be
214 // acknowledged straight away rather than returning EINPROGRESS. In this case
215 // just trigger an OnEvent without waiting for the FD watch. That will poll
216 // the SO_ERROR and evolve the state into either kConnected or kDisconnected.
217 if (res == 0) {
Primiano Tucci575af772017-11-08 18:14:17 +0000218 base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
219 task_runner_->PostTask([weak_ptr]() {
220 if (weak_ptr)
221 weak_ptr->OnEvent();
Primiano Tuccie73ac932017-11-08 18:11:17 +0000222 });
223 }
224}
225
Primiano Tuccic2025af2017-11-20 12:47:49 +0000226void UnixSocket::ReadPeerCredentials() {
227#if BUILDFLAG(OS_LINUX) || BUILDFLAG(OS_ANDROID)
228 struct ucred user_cred;
229 socklen_t len = sizeof(user_cred);
230 int res = getsockopt(*fd_, SOL_SOCKET, SO_PEERCRED, &user_cred, &len);
231 PERFETTO_CHECK(res == 0);
232 peer_uid_ = user_cred.uid;
233#else
234 struct xucred user_cred;
235 socklen_t len = sizeof(user_cred);
236 int res = getsockopt(*fd_, 0, LOCAL_PEERCRED, &user_cred, &len);
237 PERFETTO_CHECK(res == 0 && user_cred.cr_version == XUCRED_VERSION);
238 peer_uid_ = user_cred.cr_uid;
239#endif
240}
241
Primiano Tuccie73ac932017-11-08 18:11:17 +0000242void UnixSocket::OnEvent() {
243 if (state_ == State::kDisconnected)
244 return; // Some spurious event, typically queued just before Shutdown().
245
246 if (state_ == State::kConnected)
247 return event_listener_->OnDataAvailable(this);
248
249 if (state_ == State::kConnecting) {
250 PERFETTO_DCHECK(fd_);
251 int sock_err = EINVAL;
252 socklen_t err_len = sizeof(sock_err);
253 int res = getsockopt(*fd_, SOL_SOCKET, SO_ERROR, &sock_err, &err_len);
254 if (res == 0 && sock_err == EINPROGRESS)
255 return; // Not connected yet, just a spurious FD watch wakeup.
256 if (res == 0 && sock_err == 0) {
Primiano Tuccic2025af2017-11-20 12:47:49 +0000257 ReadPeerCredentials();
Primiano Tuccie73ac932017-11-08 18:11:17 +0000258 state_ = State::kConnected;
259 return event_listener_->OnConnect(this, true /* connected */);
260 }
261 last_error_ = sock_err;
262 return event_listener_->OnConnect(this, false /* connected */);
263 }
264
265 // New incoming connection.
266 if (state_ == State::kListening) {
267 // There could be more than one incoming connection behind each FD watch
268 // notification. Drain'em all.
269 for (;;) {
270 sockaddr_un cli_addr = {};
271 socklen_t size = sizeof(cli_addr);
272 base::ScopedFile new_fd(PERFETTO_EINTR(
273 accept(*fd_, reinterpret_cast<sockaddr*>(&cli_addr), &size)));
274 if (!new_fd)
275 return;
276 std::unique_ptr<UnixSocket> new_sock(
277 new UnixSocket(event_listener_, task_runner_, std::move(new_fd)));
278 event_listener_->OnNewIncomingConnection(this, std::move(new_sock));
279 }
280 }
281}
282
283bool UnixSocket::Send(const std::string& msg) {
284 return Send(msg.c_str(), msg.size() + 1);
285}
286
287bool UnixSocket::Send(const void* msg, size_t len, int send_fd) {
288 if (state_ != State::kConnected) {
Primiano Tuccied0ce252017-11-09 19:35:10 +0000289 errno = last_error_ = ENOTCONN;
Primiano Tuccie73ac932017-11-08 18:11:17 +0000290 return false;
291 }
292
293 msghdr msg_hdr = {};
294 iovec iov = {const_cast<void*>(msg), len};
295 msg_hdr.msg_iov = &iov;
296 msg_hdr.msg_iovlen = 1;
297 alignas(cmsghdr) char control_buf[256];
298
299 if (send_fd > -1) {
300 const CBufLenType control_buf_len =
301 static_cast<CBufLenType>(CMSG_SPACE(sizeof(int)));
302 PERFETTO_CHECK(control_buf_len <= sizeof(control_buf));
303 memset(control_buf, 0, sizeof(control_buf));
304 msg_hdr.msg_control = control_buf;
305 msg_hdr.msg_controllen = control_buf_len;
306 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr);
307 cmsg->cmsg_level = SOL_SOCKET;
308 cmsg->cmsg_type = SCM_RIGHTS;
309 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
310 memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(int));
311 msg_hdr.msg_controllen = cmsg->cmsg_len;
312 }
313
314 const ssize_t sz = PERFETTO_EINTR(sendmsg(*fd_, &msg_hdr, kNoSigPipe));
315 if (sz >= 0) {
316 // There should be no way a non-blocking socket returns < |len|.
317 // If the queueing fails, sendmsg() must return -1 + errno = EWOULDBLOCK.
318 PERFETTO_CHECK(static_cast<size_t>(sz) == len);
319 last_error_ = 0;
320 return true;
321 }
322
323 if (errno == EAGAIN || errno == EWOULDBLOCK) {
324 // A genuine out-of-buffer. The client should retry or give up.
325 // Man pages specify that EAGAIN and EWOULDBLOCK have the same semantic here
326 // and clients should check for both.
327 last_error_ = EAGAIN;
328 return false;
329 }
330
331 // Either the the other endpoint disconnect (ECONNRESET) or some other error
332 // happened.
333 last_error_ = errno;
334 PERFETTO_DPLOG("sendmsg() failed");
335 Shutdown();
336 return false;
337}
338
339void UnixSocket::Shutdown() {
Primiano Tucci575af772017-11-08 18:14:17 +0000340 base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Primiano Tuccie73ac932017-11-08 18:11:17 +0000341 if (state_ == State::kConnected) {
Primiano Tucci575af772017-11-08 18:14:17 +0000342 task_runner_->PostTask([weak_ptr]() {
343 if (weak_ptr)
344 weak_ptr->event_listener_->OnDisconnect(weak_ptr.get());
Primiano Tuccie73ac932017-11-08 18:11:17 +0000345 });
346 } else if (state_ == State::kConnecting) {
Primiano Tucci575af772017-11-08 18:14:17 +0000347 task_runner_->PostTask([weak_ptr]() {
348 if (weak_ptr)
349 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), false);
Primiano Tuccie73ac932017-11-08 18:11:17 +0000350 });
351 }
352 if (fd_) {
353 shutdown(*fd_, SHUT_RDWR);
354 task_runner_->RemoveFileDescriptorWatch(*fd_);
355 fd_.reset();
356 }
357 state_ = State::kDisconnected;
358}
359
360size_t UnixSocket::Receive(void* msg, size_t len, base::ScopedFile* recv_fd) {
361 if (state_ != State::kConnected) {
362 last_error_ = ENOTCONN;
363 return 0;
364 }
365
366 msghdr msg_hdr = {};
367 iovec iov = {msg, len};
368 msg_hdr.msg_iov = &iov;
369 msg_hdr.msg_iovlen = 1;
370 alignas(cmsghdr) char control_buf[256];
371
372 if (recv_fd) {
373 msg_hdr.msg_control = control_buf;
374 msg_hdr.msg_controllen = static_cast<CBufLenType>(CMSG_SPACE(sizeof(int)));
375 PERFETTO_CHECK(msg_hdr.msg_controllen <= sizeof(control_buf));
376 }
377 const ssize_t sz = PERFETTO_EINTR(recvmsg(*fd_, &msg_hdr, kNoSigPipe));
378 if (sz < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
379 last_error_ = EAGAIN;
380 return 0;
381 }
Primiano Tucci60af59d2017-11-28 12:53:55 +0000382 if (sz <= 0) {
Primiano Tuccie73ac932017-11-08 18:11:17 +0000383 last_error_ = errno;
384 Shutdown();
385 return 0;
386 }
387 PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
388
389 int* fds = nullptr;
390 uint32_t fds_len = 0;
391
392 if (msg_hdr.msg_controllen > 0) {
393 for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr); cmsg;
394 cmsg = CMSG_NXTHDR(&msg_hdr, cmsg)) {
395 const size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0);
396 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
397 PERFETTO_DCHECK(payload_len % sizeof(int) == 0u);
398 PERFETTO_DCHECK(fds == nullptr);
399 fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
400 fds_len = static_cast<uint32_t>(payload_len / sizeof(int));
401 }
402 }
403 }
404
405 if (msg_hdr.msg_flags & MSG_TRUNC || msg_hdr.msg_flags & MSG_CTRUNC) {
406 for (size_t i = 0; fds && i < fds_len; ++i)
407 close(fds[i]);
408 last_error_ = EMSGSIZE;
409 Shutdown();
410 return 0;
411 }
412
413 for (size_t i = 0; fds && i < fds_len; ++i) {
414 if (recv_fd && i == 0) {
415 recv_fd->reset(fds[i]);
416 } else {
417 close(fds[i]);
418 }
419 }
420
421 last_error_ = 0;
422 return static_cast<size_t>(sz);
423}
424
425std::string UnixSocket::ReceiveString(size_t max_length) {
426 std::unique_ptr<char[]> buf(new char[max_length + 1]);
427 size_t rsize = Receive(buf.get(), max_length);
428 PERFETTO_CHECK(static_cast<size_t>(rsize) <= max_length);
429 buf[static_cast<size_t>(rsize)] = '\0';
430 return std::string(buf.get());
431}
432
433void UnixSocket::NotifyConnectionState(bool success) {
Primiano Tucci575af772017-11-08 18:14:17 +0000434 base::WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
435 task_runner_->PostTask([weak_ptr, success]() {
436 if (weak_ptr)
437 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), success);
Primiano Tuccie73ac932017-11-08 18:11:17 +0000438 });
439}
440
441UnixSocket::EventListener::~EventListener() {}
442void UnixSocket::EventListener::OnNewIncomingConnection(
443 UnixSocket*,
444 std::unique_ptr<UnixSocket>) {}
445void UnixSocket::EventListener::OnConnect(UnixSocket*, bool) {}
446void UnixSocket::EventListener::OnDisconnect(UnixSocket*) {}
447void UnixSocket::EventListener::OnDataAvailable(UnixSocket*) {}
448
449} // namespace ipc
450} // namespace perfetto