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