1292932Sdim//===-- DomainSocket.cpp ----------------------------------------*- C++ -*-===// 2292932Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6292932Sdim// 7292932Sdim//===----------------------------------------------------------------------===// 8292932Sdim 9292932Sdim#include "lldb/Host/posix/DomainSocket.h" 10292932Sdim 11353358Sdim#include "llvm/Support/Errno.h" 12321369Sdim#include "llvm/Support/FileSystem.h" 13292932Sdim 14292932Sdim#include <stddef.h> 15292932Sdim#include <sys/socket.h> 16292932Sdim#include <sys/un.h> 17292932Sdim 18292932Sdimusing namespace lldb; 19292932Sdimusing namespace lldb_private; 20292932Sdim 21292932Sdim#ifdef __ANDROID__ 22292932Sdim// Android does not have SUN_LEN 23292932Sdim#ifndef SUN_LEN 24314564Sdim#define SUN_LEN(ptr) \ 25314564Sdim (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) 26292932Sdim#endif 27292932Sdim#endif // #ifdef __ANDROID__ 28292932Sdim 29292932Sdimnamespace { 30292932Sdim 31292932Sdimconst int kDomain = AF_UNIX; 32314564Sdimconst int kType = SOCK_STREAM; 33292932Sdim 34314564Sdimbool SetSockAddr(llvm::StringRef name, const size_t name_offset, 35314564Sdim sockaddr_un *saddr_un, socklen_t &saddr_un_len) { 36314564Sdim if (name.size() + name_offset > sizeof(saddr_un->sun_path)) 37314564Sdim return false; 38292932Sdim 39314564Sdim memset(saddr_un, 0, sizeof(*saddr_un)); 40314564Sdim saddr_un->sun_family = kDomain; 41292932Sdim 42314564Sdim memcpy(saddr_un->sun_path + name_offset, name.data(), name.size()); 43292932Sdim 44314564Sdim // For domain sockets we can use SUN_LEN in order to calculate size of 45314564Sdim // sockaddr_un, but for abstract sockets we have to calculate size manually 46314564Sdim // because of leading null symbol. 47314564Sdim if (name_offset == 0) 48314564Sdim saddr_un_len = SUN_LEN(saddr_un); 49314564Sdim else 50314564Sdim saddr_un_len = 51314564Sdim offsetof(struct sockaddr_un, sun_path) + name_offset + name.size(); 52292932Sdim 53292932Sdim#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) 54314564Sdim saddr_un->sun_len = saddr_un_len; 55292932Sdim#endif 56292932Sdim 57314564Sdim return true; 58292932Sdim} 59321369Sdim} // namespace 60292932Sdim 61321369SdimDomainSocket::DomainSocket(bool should_close, bool child_processes_inherit) 62321369Sdim : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {} 63292932Sdim 64314564SdimDomainSocket::DomainSocket(SocketProtocol protocol, 65321369Sdim bool child_processes_inherit) 66321369Sdim : Socket(protocol, true, child_processes_inherit) {} 67292932Sdim 68321369SdimDomainSocket::DomainSocket(NativeSocket socket, 69321369Sdim const DomainSocket &listen_socket) 70321369Sdim : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd, 71321369Sdim listen_socket.m_child_processes_inherit) { 72321369Sdim m_socket = socket; 73321369Sdim} 74321369Sdim 75321369SdimStatus DomainSocket::Connect(llvm::StringRef name) { 76314564Sdim sockaddr_un saddr_un; 77314564Sdim socklen_t saddr_un_len; 78314564Sdim if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 79321369Sdim return Status("Failed to set socket address"); 80292932Sdim 81321369Sdim Status error; 82321369Sdim m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 83321369Sdim if (error.Fail()) 84321369Sdim return error; 85353358Sdim if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), 86353358Sdim (struct sockaddr *)&saddr_un, saddr_un_len) < 0) 87314564Sdim SetLastError(error); 88292932Sdim 89314564Sdim return error; 90292932Sdim} 91292932Sdim 92321369SdimStatus DomainSocket::Listen(llvm::StringRef name, int backlog) { 93314564Sdim sockaddr_un saddr_un; 94314564Sdim socklen_t saddr_un_len; 95314564Sdim if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 96321369Sdim return Status("Failed to set socket address"); 97292932Sdim 98314564Sdim DeleteSocketFile(name); 99292932Sdim 100321369Sdim Status error; 101321369Sdim m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 102321369Sdim if (error.Fail()) 103321369Sdim return error; 104314564Sdim if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 105314564Sdim 0) 106314564Sdim if (::listen(GetNativeSocket(), backlog) == 0) 107314564Sdim return error; 108292932Sdim 109314564Sdim SetLastError(error); 110314564Sdim return error; 111292932Sdim} 112292932Sdim 113321369SdimStatus DomainSocket::Accept(Socket *&socket) { 114321369Sdim Status error; 115314564Sdim auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, 116321369Sdim m_child_processes_inherit, error); 117314564Sdim if (error.Success()) 118321369Sdim socket = new DomainSocket(conn_fd, *this); 119292932Sdim 120314564Sdim return error; 121292932Sdim} 122292932Sdim 123314564Sdimsize_t DomainSocket::GetNameOffset() const { return 0; } 124292932Sdim 125314564Sdimvoid DomainSocket::DeleteSocketFile(llvm::StringRef name) { 126321369Sdim llvm::sys::fs::remove(name); 127292932Sdim} 128353358Sdim 129353358Sdimstd::string DomainSocket::GetSocketName() const { 130353358Sdim if (m_socket != kInvalidSocketValue) { 131353358Sdim struct sockaddr_un saddr_un; 132353358Sdim saddr_un.sun_family = AF_UNIX; 133353358Sdim socklen_t sock_addr_len = sizeof(struct sockaddr_un); 134353358Sdim if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) == 135353358Sdim 0) { 136353358Sdim std::string name(saddr_un.sun_path + GetNameOffset(), 137353358Sdim sock_addr_len - 138353358Sdim offsetof(struct sockaddr_un, sun_path) - 139353358Sdim GetNameOffset()); 140353358Sdim if (name.back() == '\0') name.pop_back(); 141353358Sdim return name; 142353358Sdim } 143353358Sdim } 144353358Sdim return ""; 145353358Sdim} 146353358Sdim 147353358Sdimstd::string DomainSocket::GetRemoteConnectionURI() const { 148353358Sdim if (m_socket != kInvalidSocketValue) { 149353358Sdim return llvm::formatv("{0}://{1}", 150353358Sdim GetNameOffset() == 0 ? "unix-connect" 151353358Sdim : "unix-abstract-connect", 152353358Sdim GetSocketName()); 153353358Sdim } 154353358Sdim return ""; 155353358Sdim} 156