#include "perfetto/ext/base/unix_socket.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "perfetto/base/compiler.h"
#include "perfetto/ext/base/string_utils.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <afunix.h>
#else
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
#include <sys/ucred.h>
#endif
#include <algorithm>
#include <memory>
#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/task_runner.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
#include "src/base/vm_sockets.h"
#endif
namespace perfetto {
namespace base {
#if defined(__GNUC__) && !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
namespace {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
using CBufLenType = size_t;
#else
CBufLenType;
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
constexpr char kVsockNamePrefix[] = …;
#endif
struct SockaddrAny { … };
inline int MkSockFamily(SockFamily family) { … }
inline int MkSockType(SockType type) { … }
SockaddrAny MakeSockAddr(SockFamily family, const std::string& socket_name) { … }
ScopedSocketHandle CreateSocketHandle(SockFamily family, SockType type) { … }
}
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
int CloseSocket(SocketHandle s) {
return ::closesocket(s);
}
#endif
SockFamily GetSockFamily(const char* addr) { … }
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
void UnixSocketRaw::ShiftMsgHdrPosix(size_t n, struct msghdr* msg) { … }
std::pair<UnixSocketRaw, UnixSocketRaw> UnixSocketRaw::CreatePairPosix(
SockFamily family,
SockType type) { … }
#endif
UnixSocketRaw UnixSocketRaw::CreateMayFail(SockFamily family, SockType type) { … }
UnixSocketRaw::UnixSocketRaw() = default;
UnixSocketRaw::UnixSocketRaw(SockFamily family, SockType type)
: … { … }
UnixSocketRaw::UnixSocketRaw(ScopedSocketHandle fd,
SockFamily family,
SockType type)
: … { … }
void UnixSocketRaw::SetBlocking(bool is_blocking) { … }
void UnixSocketRaw::SetRetainOnExec(bool retain) { … }
void UnixSocketRaw::DcheckIsBlocking(bool expected) const { … }
bool UnixSocketRaw::Bind(const std::string& socket_name) { … }
bool UnixSocketRaw::Listen() { … }
bool UnixSocketRaw::Connect(const std::string& socket_name) { … }
void UnixSocketRaw::Shutdown() { … }
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
ssize_t UnixSocketRaw::Send(const void* msg,
size_t len,
const int* ,
size_t num_fds) {
PERFETTO_DCHECK(num_fds == 0);
return sendto(*fd_, static_cast<const char*>(msg), static_cast<int>(len), 0,
nullptr, 0);
}
ssize_t UnixSocketRaw::Receive(void* msg,
size_t len,
ScopedFile* ,
size_t ) {
return recv(*fd_, static_cast<char*>(msg), static_cast<int>(len), 0);
}
#else
ssize_t UnixSocketRaw::SendMsgAllPosix(struct msghdr* msg) { … }
ssize_t UnixSocketRaw::Send(const void* msg,
size_t len,
const int* send_fds,
size_t num_fds) { … }
ssize_t UnixSocketRaw::Receive(void* msg,
size_t len,
ScopedFile* fd_vec,
size_t max_files) { … }
#endif
bool UnixSocketRaw::SetTxTimeout(uint32_t timeout_ms) { … }
bool UnixSocketRaw::SetRxTimeout(uint32_t timeout_ms) { … }
std::string UnixSocketRaw::GetSockAddr() const { … }
#if defined(__GNUC__) && !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
#pragma GCC diagnostic pop
#endif
std::unique_ptr<UnixSocket> UnixSocket::Listen(const std::string& socket_name,
EventListener* event_listener,
TaskRunner* task_runner,
SockFamily sock_family,
SockType sock_type) { … }
std::unique_ptr<UnixSocket> UnixSocket::Listen(ScopedSocketHandle fd,
EventListener* event_listener,
TaskRunner* task_runner,
SockFamily sock_family,
SockType sock_type) { … }
std::unique_ptr<UnixSocket> UnixSocket::Connect(
const std::string& socket_name,
EventListener* event_listener,
TaskRunner* task_runner,
SockFamily sock_family,
SockType sock_type,
SockPeerCredMode peer_cred_mode) { … }
std::unique_ptr<UnixSocket> UnixSocket::AdoptConnected(
ScopedSocketHandle fd,
EventListener* event_listener,
TaskRunner* task_runner,
SockFamily sock_family,
SockType sock_type,
SockPeerCredMode peer_cred_mode) { … }
UnixSocket::UnixSocket(EventListener* event_listener,
TaskRunner* task_runner,
SockFamily sock_family,
SockType sock_type,
SockPeerCredMode peer_cred_mode)
: … { … }
UnixSocket::UnixSocket(EventListener* event_listener,
TaskRunner* task_runner,
ScopedSocketHandle adopt_fd,
State adopt_state,
SockFamily sock_family,
SockType sock_type,
SockPeerCredMode peer_cred_mode)
: … { … }
UnixSocket::~UnixSocket() { … }
UnixSocketRaw UnixSocket::ReleaseSocket() { … }
void UnixSocket::DoConnect(const std::string& socket_name) { … }
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
void UnixSocket::ReadPeerCredentialsPosix() { … }
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
void UnixSocket::OnEvent() {
WSANETWORKEVENTS evts{};
PERFETTO_CHECK(WSAEnumNetworkEvents(sock_raw_.fd(), sock_raw_.watch_handle(),
&evts) == 0);
if (state_ == State::kDisconnected)
return;
if (state_ == State::kConnecting && (evts.lNetworkEvents & FD_CONNECT)) {
PERFETTO_DCHECK(sock_raw_);
int err = evts.iErrorCode[FD_CONNECT_BIT];
if (err) {
PERFETTO_DPLOG("Connection error: %d", err);
Shutdown(false);
event_listener_->OnConnect(this, false );
return;
}
PERFETTO_DCHECK(peer_cred_mode_ != SockPeerCredMode::kReadOnConnect);
state_ = State::kConnected;
event_listener_->OnConnect(this, true );
}
if (state_ == State::kConnected) {
if (evts.lNetworkEvents & FD_READ) {
event_listener_->OnDataAvailable(this);
return;
}
if (evts.lNetworkEvents & FD_CLOSE) {
Shutdown(true);
return;
}
}
if (state_ == State::kListening && (evts.lNetworkEvents & FD_ACCEPT)) {
for (;;) {
ScopedSocketHandle new_fd(accept(sock_raw_.fd(), nullptr, nullptr));
if (!new_fd)
return;
std::unique_ptr<UnixSocket> new_sock(new UnixSocket(
event_listener_, task_runner_, std::move(new_fd), State::kConnected,
sock_raw_.family(), sock_raw_.type(), peer_cred_mode_));
event_listener_->OnNewIncomingConnection(this, std::move(new_sock));
}
}
}
#else
void UnixSocket::OnEvent() { … }
#endif
bool UnixSocket::Send(const void* msg,
size_t len,
const int* send_fds,
size_t num_fds) { … }
void UnixSocket::Shutdown(bool notify) { … }
size_t UnixSocket::Receive(void* msg,
size_t len,
ScopedFile* fd_vec,
size_t max_files) { … }
std::string UnixSocket::ReceiveString(size_t max_length) { … }
void UnixSocket::NotifyConnectionState(bool success) { … }
UnixSocket::EventListener::~EventListener() { … }
void UnixSocket::EventListener::OnNewIncomingConnection(
UnixSocket*,
std::unique_ptr<UnixSocket>) { … }
void UnixSocket::EventListener::OnConnect(UnixSocket*, bool) { … }
void UnixSocket::EventListener::OnDisconnect(UnixSocket*) { … }
void UnixSocket::EventListener::OnDataAvailable(UnixSocket*) { … }
}
}