blob: c1487eb11585eeb4bacbc02fe9ffa4bf0d9c4451 [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
Florian Mayerf7f0def2018-09-27 13:59:24 +010017#include "perfetto/base/unix_socket.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000018
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 {
Florian Mayerf7f0def2018-09-27 13:59:24 +010042namespace base {
43
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010044// 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
Florian Mayerf7f0def2018-09-27 13:59:24 +010050namespace {
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)
54constexpr int kNoSigPipe = 0;
55#else
56constexpr 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)
61using CBufLenType = size_t;
62#else
63using CBufLenType = socklen_t;
64#endif
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010065
66inline 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);
Florian Mayerf7f0def2018-09-27 13:59:24 +010076}
77
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010078bool 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}
Florian Mayerf7f0def2018-09-27 13:59:24 +010095
Primiano Tucci43ebf4d2019-01-02 20:04:34 +010096} // namespace
97
98// +-----------------------+
99// | UnixSocketRaw methods |
100// +-----------------------+
101
102// static
103void UnixSocketRaw::ShiftMsgHdr(size_t n, struct msghdr* msg) {
Primiano Tucci45b902a2018-10-04 14:57:09 +0100104 using LenType = decltype(msg->msg_iovlen); // Mac and Linux don't agree.
105 for (LenType i = 0; i < msg->msg_iovlen; ++i) {
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100106 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
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100124// static
125std::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
134UnixSocketRaw::UnixSocketRaw() = default;
135
136UnixSocketRaw::UnixSocketRaw(SockType type)
137 : UnixSocketRaw(ScopedFile(socket(AF_UNIX, GetUnixSockType(type), 0)),
138 type) {}
139
140UnixSocketRaw::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
154void 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
Ryan Savitski14c12d62019-01-08 22:38:53 +0000166void 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
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100174bool UnixSocketRaw::IsBlocking() const {
175 PERFETTO_DCHECK(fd_);
176 return (fcntl(*fd_, F_GETFL, 0) & O_NONBLOCK) == 0;
177}
178
179bool 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)) {
Primiano Tucci301175d2019-01-11 10:10:21 +0000187 PERFETTO_DPLOG("bind(%s)", socket_name.c_str());
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100188 return false;
189 }
190
191 return true;
192}
193
194bool UnixSocketRaw::Listen() {
Ryan Savitski499d9562019-01-08 23:10:01 +0000195 PERFETTO_DCHECK(fd_);
196 PERFETTO_DCHECK(type_ == SockType::kStream || type_ == SockType::kSeqPacket);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100197 return listen(*fd_, SOMAXCONN) == 0;
198}
199
200bool 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
215void UnixSocketRaw::Shutdown() {
216 shutdown(*fd_, SHUT_RDWR);
217 fd_.reset();
218}
219
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100220// 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
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100228ssize_t UnixSocketRaw::SendMsgAll(struct msghdr* msg) {
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100229 // This does not make sense on non-blocking sockets.
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100230 PERFETTO_DCHECK(fd_);
231 PERFETTO_DCHECK(IsBlocking());
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100232
233 ssize_t total_sent = 0;
234 while (msg->msg_iov) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100235 ssize_t sent = PERFETTO_EINTR(sendmsg(*fd_, msg, kNoSigPipe));
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100236 if (sent <= 0) {
237 if (sent == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
238 return total_sent;
239 return sent;
240 }
241 total_sent += sent;
242 ShiftMsgHdr(static_cast<size_t>(sent), msg);
243 // Only send the ancillary data with the first sendmsg call.
244 msg->msg_control = nullptr;
245 msg->msg_controllen = 0;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000246 }
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100247 return total_sent;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000248}
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100249
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100250ssize_t UnixSocketRaw::Send(const void* msg,
251 size_t len,
252 const int* send_fds,
253 size_t num_fds) {
254 PERFETTO_DCHECK(fd_);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100255 msghdr msg_hdr = {};
256 iovec iov = {const_cast<void*>(msg), len};
257 msg_hdr.msg_iov = &iov;
258 msg_hdr.msg_iovlen = 1;
259 alignas(cmsghdr) char control_buf[256];
260
261 if (num_fds > 0) {
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000262 const auto raw_ctl_data_sz = num_fds * sizeof(int);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100263 const CBufLenType control_buf_len =
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000264 static_cast<CBufLenType>(CMSG_SPACE(raw_ctl_data_sz));
Florian Mayerf7f0def2018-09-27 13:59:24 +0100265 PERFETTO_CHECK(control_buf_len <= sizeof(control_buf));
266 memset(control_buf, 0, sizeof(control_buf));
267 msg_hdr.msg_control = control_buf;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000268 msg_hdr.msg_controllen = control_buf_len; // used by CMSG_FIRSTHDR
Florian Mayerf7f0def2018-09-27 13:59:24 +0100269 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr);
270 cmsg->cmsg_level = SOL_SOCKET;
271 cmsg->cmsg_type = SCM_RIGHTS;
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000272 cmsg->cmsg_len = static_cast<CBufLenType>(CMSG_LEN(raw_ctl_data_sz));
Florian Mayerf7f0def2018-09-27 13:59:24 +0100273 memcpy(CMSG_DATA(cmsg), send_fds, num_fds * sizeof(int));
Ryan Savitski31e4b6c2018-11-21 19:41:57 +0000274 // note: if we were to send multiple cmsghdr structures, then
275 // msg_hdr.msg_controllen would need to be adjusted, see "man 3 cmsg".
Florian Mayerf7f0def2018-09-27 13:59:24 +0100276 }
277
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100278 return SendMsgAll(&msg_hdr);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100279}
280
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100281ssize_t UnixSocketRaw::Receive(void* msg,
282 size_t len,
283 ScopedFile* fd_vec,
284 size_t max_files) {
285 PERFETTO_DCHECK(fd_);
Florian Mayerf7f0def2018-09-27 13:59:24 +0100286 msghdr msg_hdr = {};
287 iovec iov = {msg, len};
288 msg_hdr.msg_iov = &iov;
289 msg_hdr.msg_iovlen = 1;
290 alignas(cmsghdr) char control_buf[256];
291
292 if (max_files > 0) {
293 msg_hdr.msg_control = control_buf;
294 msg_hdr.msg_controllen =
295 static_cast<CBufLenType>(CMSG_SPACE(max_files * sizeof(int)));
296 PERFETTO_CHECK(msg_hdr.msg_controllen <= sizeof(control_buf));
297 }
Ryan Savitskib6d65912019-01-08 16:12:53 +0000298 const ssize_t sz = PERFETTO_EINTR(recvmsg(*fd_, &msg_hdr, 0));
Florian Mayerf7f0def2018-09-27 13:59:24 +0100299 if (sz <= 0) {
300 return sz;
301 }
302 PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
303
304 int* fds = nullptr;
305 uint32_t fds_len = 0;
306
307 if (max_files > 0) {
308 for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr); cmsg;
309 cmsg = CMSG_NXTHDR(&msg_hdr, cmsg)) {
310 const size_t payload_len = cmsg->cmsg_len - CMSG_LEN(0);
311 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
312 PERFETTO_DCHECK(payload_len % sizeof(int) == 0u);
313 PERFETTO_CHECK(fds == nullptr);
314 fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
315 fds_len = static_cast<uint32_t>(payload_len / sizeof(int));
316 }
317 }
318 }
319
320 if (msg_hdr.msg_flags & MSG_TRUNC || msg_hdr.msg_flags & MSG_CTRUNC) {
321 for (size_t i = 0; fds && i < fds_len; ++i)
322 close(fds[i]);
323 errno = EMSGSIZE;
324 return -1;
325 }
326
327 for (size_t i = 0; fds && i < fds_len; ++i) {
328 if (i < max_files)
329 fd_vec[i].reset(fds[i]);
330 else
331 close(fds[i]);
332 }
333
334 return sz;
335}
336
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100337bool UnixSocketRaw::SetTxTimeout(uint32_t timeout_ms) {
338 PERFETTO_DCHECK(fd_);
339 struct timeval timeout {};
340 uint32_t timeout_sec = timeout_ms / 1000;
341 timeout.tv_sec = static_cast<decltype(timeout.tv_sec)>(timeout_sec);
342 timeout.tv_usec = static_cast<decltype(timeout.tv_usec)>(
343 (timeout_ms - (timeout_sec * 1000)) * 1000);
344
345 return setsockopt(*fd_, SOL_SOCKET, SO_SNDTIMEO,
346 reinterpret_cast<const char*>(&timeout),
347 sizeof(timeout)) == 0;
348}
349
Florian Mayerf7f0def2018-09-27 13:59:24 +0100350#pragma GCC diagnostic pop
351
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100352// +--------------------+
353// | UnixSocket methods |
354// +--------------------+
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000355
356// TODO(primiano): Add ThreadChecker to methods of this class.
357
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000358// static
359std::unique_ptr<UnixSocket> UnixSocket::Listen(const std::string& socket_name,
360 EventListener* event_listener,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100361 TaskRunner* task_runner,
362 SockType sock_type) {
363 auto sock_raw = UnixSocketRaw::CreateMayFail(sock_type);
364 if (!sock_raw || !sock_raw.Bind(socket_name))
365 return nullptr;
366
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100367 // Forward the call to the Listen() overload below.
Ryan Savitski499d9562019-01-08 23:10:01 +0000368 return Listen(sock_raw.ReleaseFd(), event_listener, task_runner, sock_type);
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100369}
370
371// static
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100372std::unique_ptr<UnixSocket> UnixSocket::Listen(ScopedFile fd,
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100373 EventListener* event_listener,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100374 TaskRunner* task_runner,
375 SockType sock_type) {
376 return std::unique_ptr<UnixSocket>(
377 new UnixSocket(event_listener, task_runner, std::move(fd),
378 State::kListening, sock_type));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000379}
380
381// static
382std::unique_ptr<UnixSocket> UnixSocket::Connect(const std::string& socket_name,
383 EventListener* event_listener,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100384 TaskRunner* task_runner,
385 SockType sock_type) {
386 std::unique_ptr<UnixSocket> sock(
387 new UnixSocket(event_listener, task_runner, sock_type));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000388 sock->DoConnect(socket_name);
389 return sock;
390}
391
Ryan Savitski9c1240e2019-01-15 22:40:46 +0000392// static
393std::unique_ptr<UnixSocket> UnixSocket::AdoptConnected(
394 ScopedFile fd,
395 EventListener* event_listener,
396 TaskRunner* task_runner,
397 SockType sock_type) {
398 return std::unique_ptr<UnixSocket>(
399 new UnixSocket(event_listener, task_runner, std::move(fd),
400 State::kConnected, sock_type));
401}
402
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100403UnixSocket::UnixSocket(EventListener* event_listener,
404 TaskRunner* task_runner,
405 SockType sock_type)
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100406 : UnixSocket(event_listener,
407 task_runner,
Florian Mayerf7f0def2018-09-27 13:59:24 +0100408 ScopedFile(),
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100409 State::kDisconnected,
410 sock_type) {}
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000411
412UnixSocket::UnixSocket(EventListener* event_listener,
Florian Mayerf7f0def2018-09-27 13:59:24 +0100413 TaskRunner* task_runner,
414 ScopedFile adopt_fd,
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100415 State adopt_state,
416 SockType sock_type)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000417 : event_listener_(event_listener),
418 task_runner_(task_runner),
419 weak_ptr_factory_(this) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100420 state_ = State::kDisconnected;
421 if (adopt_state == State::kDisconnected) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100422 PERFETTO_DCHECK(!adopt_fd);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100423 sock_raw_ = UnixSocketRaw::CreateMayFail(sock_type);
424 if (!sock_raw_) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100425 last_error_ = errno;
426 return;
427 }
428 } else if (adopt_state == State::kConnected) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100429 PERFETTO_DCHECK(adopt_fd);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100430 sock_raw_ = UnixSocketRaw(std::move(adopt_fd), sock_type);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000431 state_ = State::kConnected;
432 ReadPeerCredentials();
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100433 } else if (adopt_state == State::kListening) {
434 // We get here from Listen().
435
436 // |adopt_fd| might genuinely be invalid if the bind() failed.
437 if (!adopt_fd) {
438 last_error_ = errno;
439 return;
440 }
441
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100442 sock_raw_ = UnixSocketRaw(std::move(adopt_fd), sock_type);
443 if (!sock_raw_.Listen()) {
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100444 last_error_ = errno;
445 PERFETTO_DPLOG("listen()");
446 return;
447 }
448 state_ = State::kListening;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000449 } else {
Hector Dearmanbd14fc62018-12-13 16:06:14 +0000450 PERFETTO_FATAL("Unexpected adopt_state"); // Unfeasible.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000451 }
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100452
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100453 PERFETTO_CHECK(sock_raw_);
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100454 last_error_ = 0;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000455
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100456 sock_raw_.SetBlocking(false);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000457
Florian Mayerf7f0def2018-09-27 13:59:24 +0100458 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100459 task_runner_->AddFileDescriptorWatch(sock_raw_.fd(), [weak_ptr] {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000460 if (weak_ptr)
461 weak_ptr->OnEvent();
462 });
463}
464
465UnixSocket::~UnixSocket() {
466 // The implicit dtor of |weak_ptr_factory_| will no-op pending callbacks.
Florian Mayer48c139c2018-03-12 14:07:57 +0000467 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000468}
469
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000470// Called only by the Connect() static constructor.
471void UnixSocket::DoConnect(const std::string& socket_name) {
472 PERFETTO_DCHECK(state_ == State::kDisconnected);
473
474 // This is the only thing that can gracefully fail in the ctor.
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100475 if (!sock_raw_)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000476 return NotifyConnectionState(false);
477
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100478 if (!sock_raw_.Connect(socket_name)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000479 last_error_ = errno;
480 return NotifyConnectionState(false);
481 }
482
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100483 // At this point either connect() succeeded or started asynchronously
484 // (errno = EINPROGRESS).
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000485 last_error_ = 0;
486 state_ = State::kConnecting;
487
488 // Even if the socket is non-blocking, connecting to a UNIX socket can be
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100489 // acknowledged straight away rather than returning EINPROGRESS.
490 // The decision here is to deal with the two cases uniformly, at the cost of
491 // delaying the straight-away-connect() case by one task, to avoid depending
492 // on implementation details of UNIX socket on the various OSes.
493 // Posting the OnEvent() below emulates a wakeup of the FD watch. OnEvent(),
494 // which knows how to deal with spurious wakeups, will poll the SO_ERROR and
495 // evolve, if necessary, the state into either kConnected or kDisconnected.
496 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
497 task_runner_->PostTask([weak_ptr] {
498 if (weak_ptr)
499 weak_ptr->OnEvent();
500 });
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000501}
502
503void UnixSocket::ReadPeerCredentials() {
Oystein Eftevaagff729592018-02-12 14:24:06 -0800504#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
505 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000506 struct ucred user_cred;
507 socklen_t len = sizeof(user_cred);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100508 int fd = sock_raw_.fd();
509 int res = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &user_cred, &len);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000510 PERFETTO_CHECK(res == 0);
511 peer_uid_ = user_cred.uid;
Florian Mayerfa1659e2018-08-07 10:45:19 +0100512 peer_pid_ = user_cred.pid;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000513#else
514 struct xucred user_cred;
515 socklen_t len = sizeof(user_cred);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100516 int res = getsockopt(sock_raw_.fd(), 0, LOCAL_PEERCRED, &user_cred, &len);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000517 PERFETTO_CHECK(res == 0 && user_cred.cr_version == XUCRED_VERSION);
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100518 peer_uid_ = static_cast<uid_t>(user_cred.cr_uid);
Florian Mayerfa1659e2018-08-07 10:45:19 +0100519// There is no pid in the LOCAL_PEERCREDS for MacOS / FreeBSD.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000520#endif
521}
522
523void UnixSocket::OnEvent() {
524 if (state_ == State::kDisconnected)
525 return; // Some spurious event, typically queued just before Shutdown().
526
527 if (state_ == State::kConnected)
528 return event_listener_->OnDataAvailable(this);
529
530 if (state_ == State::kConnecting) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100531 PERFETTO_DCHECK(sock_raw_);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000532 int sock_err = EINVAL;
533 socklen_t err_len = sizeof(sock_err);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100534 int res =
535 getsockopt(sock_raw_.fd(), SOL_SOCKET, SO_ERROR, &sock_err, &err_len);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000536 if (res == 0 && sock_err == EINPROGRESS)
537 return; // Not connected yet, just a spurious FD watch wakeup.
538 if (res == 0 && sock_err == 0) {
539 ReadPeerCredentials();
540 state_ = State::kConnected;
541 return event_listener_->OnConnect(this, true /* connected */);
542 }
543 last_error_ = sock_err;
Florian Mayer48c139c2018-03-12 14:07:57 +0000544 Shutdown(false);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000545 return event_listener_->OnConnect(this, false /* connected */);
546 }
547
548 // New incoming connection.
549 if (state_ == State::kListening) {
550 // There could be more than one incoming connection behind each FD watch
551 // notification. Drain'em all.
552 for (;;) {
553 sockaddr_un cli_addr = {};
554 socklen_t size = sizeof(cli_addr);
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100555 ScopedFile new_fd(PERFETTO_EINTR(accept(
556 sock_raw_.fd(), reinterpret_cast<sockaddr*>(&cli_addr), &size)));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000557 if (!new_fd)
558 return;
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100559 std::unique_ptr<UnixSocket> new_sock(
560 new UnixSocket(event_listener_, task_runner_, std::move(new_fd),
561 State::kConnected, sock_raw_.type()));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000562 event_listener_->OnNewIncomingConnection(this, std::move(new_sock));
563 }
564 }
565}
566
Florian Mayere1cd07d2018-07-31 11:56:41 +0100567bool UnixSocket::Send(const void* msg,
568 size_t len,
569 const int* send_fds,
570 size_t num_fds,
571 BlockingMode blocking_mode) {
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100572 // TODO(b/117139237): Non-blocking sends are broken because we do not
573 // properly handle partial sends.
574 PERFETTO_DCHECK(blocking_mode == BlockingMode::kBlocking);
575
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000576 if (state_ != State::kConnected) {
577 errno = last_error_ = ENOTCONN;
578 return false;
579 }
580
Primiano Tucci7a265b62017-12-07 18:37:31 +0000581 if (blocking_mode == BlockingMode::kBlocking)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100582 sock_raw_.SetBlocking(true);
583 const ssize_t sz = sock_raw_.Send(msg, len, send_fds, num_fds);
584 int saved_errno = errno;
Primiano Tucci7a265b62017-12-07 18:37:31 +0000585 if (blocking_mode == BlockingMode::kBlocking)
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100586 sock_raw_.SetBlocking(false);
Primiano Tucci7a265b62017-12-07 18:37:31 +0000587
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100588 if (sz == static_cast<ssize_t>(len)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000589 last_error_ = 0;
590 return true;
591 }
592
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100593 // If sendmsg() succeds but the returned size is < |len| it means that the
594 // endpoint disconnected in the middle of the read, and we managed to send
595 // only a portion of the buffer. In this case we should just give up.
596
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100597 if (sz < 0 && (saved_errno == EAGAIN || saved_errno == EWOULDBLOCK)) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000598 // A genuine out-of-buffer. The client should retry or give up.
599 // Man pages specify that EAGAIN and EWOULDBLOCK have the same semantic here
600 // and clients should check for both.
601 last_error_ = EAGAIN;
602 return false;
603 }
604
605 // Either the the other endpoint disconnect (ECONNRESET) or some other error
606 // happened.
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100607 last_error_ = saved_errno;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000608 PERFETTO_DPLOG("sendmsg() failed");
Florian Mayer48c139c2018-03-12 14:07:57 +0000609 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000610 return false;
611}
612
Florian Mayer48c139c2018-03-12 14:07:57 +0000613void UnixSocket::Shutdown(bool notify) {
Florian Mayerf7f0def2018-09-27 13:59:24 +0100614 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Florian Mayer48c139c2018-03-12 14:07:57 +0000615 if (notify) {
616 if (state_ == State::kConnected) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100617 task_runner_->PostTask([weak_ptr] {
Florian Mayer48c139c2018-03-12 14:07:57 +0000618 if (weak_ptr)
619 weak_ptr->event_listener_->OnDisconnect(weak_ptr.get());
620 });
621 } else if (state_ == State::kConnecting) {
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100622 task_runner_->PostTask([weak_ptr] {
Florian Mayer48c139c2018-03-12 14:07:57 +0000623 if (weak_ptr)
624 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), false);
625 });
626 }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000627 }
Florian Mayer48c139c2018-03-12 14:07:57 +0000628
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100629 if (sock_raw_) {
630 task_runner_->RemoveFileDescriptorWatch(sock_raw_.fd());
631 sock_raw_.Shutdown();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000632 }
633 state_ = State::kDisconnected;
634}
635
Florian Mayere1cd07d2018-07-31 11:56:41 +0100636size_t UnixSocket::Receive(void* msg,
637 size_t len,
Florian Mayerf7f0def2018-09-27 13:59:24 +0100638 ScopedFile* fd_vec,
Florian Mayere1cd07d2018-07-31 11:56:41 +0100639 size_t max_files) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000640 if (state_ != State::kConnected) {
641 last_error_ = ENOTCONN;
642 return 0;
643 }
644
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100645 const ssize_t sz = sock_raw_.Receive(msg, len, fd_vec, max_files);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000646 if (sz < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
647 last_error_ = EAGAIN;
648 return 0;
649 }
650 if (sz <= 0) {
651 last_error_ = errno;
Florian Mayer48c139c2018-03-12 14:07:57 +0000652 Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000653 return 0;
654 }
655 PERFETTO_CHECK(static_cast<size_t>(sz) <= len);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000656 return static_cast<size_t>(sz);
657}
658
659std::string UnixSocket::ReceiveString(size_t max_length) {
660 std::unique_ptr<char[]> buf(new char[max_length + 1]);
661 size_t rsize = Receive(buf.get(), max_length);
662 PERFETTO_CHECK(static_cast<size_t>(rsize) <= max_length);
663 buf[static_cast<size_t>(rsize)] = '\0';
664 return std::string(buf.get());
665}
666
667void UnixSocket::NotifyConnectionState(bool success) {
Florian Mayer48c139c2018-03-12 14:07:57 +0000668 if (!success)
669 Shutdown(false);
670
Florian Mayerf7f0def2018-09-27 13:59:24 +0100671 WeakPtr<UnixSocket> weak_ptr = weak_ptr_factory_.GetWeakPtr();
Primiano Tucci43ebf4d2019-01-02 20:04:34 +0100672 task_runner_->PostTask([weak_ptr, success] {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000673 if (weak_ptr)
674 weak_ptr->event_listener_->OnConnect(weak_ptr.get(), success);
675 });
676}
677
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000678UnixSocket::EventListener::~EventListener() {}
679void UnixSocket::EventListener::OnNewIncomingConnection(
680 UnixSocket*,
681 std::unique_ptr<UnixSocket>) {}
682void UnixSocket::EventListener::OnConnect(UnixSocket*, bool) {}
683void UnixSocket::EventListener::OnDisconnect(UnixSocket*) {}
684void UnixSocket::EventListener::OnDataAvailable(UnixSocket*) {}
685
Florian Mayerf7f0def2018-09-27 13:59:24 +0100686} // namespace base
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000687} // namespace perfetto