1dda28197Spatrick //===-- DomainSocket.cpp --------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Host/posix/DomainSocket.h"
10061da546Spatrick
11061da546Spatrick #include "llvm/Support/Errno.h"
12061da546Spatrick #include "llvm/Support/FileSystem.h"
13061da546Spatrick
14a0747c9fSpatrick #include <cstddef>
15061da546Spatrick #include <sys/socket.h>
16061da546Spatrick #include <sys/un.h>
17061da546Spatrick
18061da546Spatrick using namespace lldb;
19061da546Spatrick using namespace lldb_private;
20061da546Spatrick
21061da546Spatrick #ifdef __ANDROID__
22061da546Spatrick // Android does not have SUN_LEN
23061da546Spatrick #ifndef SUN_LEN
24061da546Spatrick #define SUN_LEN(ptr) \
25061da546Spatrick (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path))
26061da546Spatrick #endif
27061da546Spatrick #endif // #ifdef __ANDROID__
28061da546Spatrick
29*101d251dSrobert static const int kDomain = AF_UNIX;
30*101d251dSrobert static const int kType = SOCK_STREAM;
31061da546Spatrick
SetSockAddr(llvm::StringRef name,const size_t name_offset,sockaddr_un * saddr_un,socklen_t & saddr_un_len)32*101d251dSrobert static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
33061da546Spatrick sockaddr_un *saddr_un, socklen_t &saddr_un_len) {
34061da546Spatrick if (name.size() + name_offset > sizeof(saddr_un->sun_path))
35061da546Spatrick return false;
36061da546Spatrick
37061da546Spatrick memset(saddr_un, 0, sizeof(*saddr_un));
38061da546Spatrick saddr_un->sun_family = kDomain;
39061da546Spatrick
40061da546Spatrick memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
41061da546Spatrick
42061da546Spatrick // For domain sockets we can use SUN_LEN in order to calculate size of
43061da546Spatrick // sockaddr_un, but for abstract sockets we have to calculate size manually
44061da546Spatrick // because of leading null symbol.
45061da546Spatrick if (name_offset == 0)
46061da546Spatrick saddr_un_len = SUN_LEN(saddr_un);
47061da546Spatrick else
48061da546Spatrick saddr_un_len =
49061da546Spatrick offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
50061da546Spatrick
51adae0cfdSpatrick #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
52061da546Spatrick saddr_un->sun_len = saddr_un_len;
53061da546Spatrick #endif
54061da546Spatrick
55061da546Spatrick return true;
56061da546Spatrick }
57061da546Spatrick
DomainSocket(bool should_close,bool child_processes_inherit)58061da546Spatrick DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit)
59061da546Spatrick : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {}
60061da546Spatrick
DomainSocket(SocketProtocol protocol,bool child_processes_inherit)61061da546Spatrick DomainSocket::DomainSocket(SocketProtocol protocol,
62061da546Spatrick bool child_processes_inherit)
63061da546Spatrick : Socket(protocol, true, child_processes_inherit) {}
64061da546Spatrick
DomainSocket(NativeSocket socket,const DomainSocket & listen_socket)65061da546Spatrick DomainSocket::DomainSocket(NativeSocket socket,
66061da546Spatrick const DomainSocket &listen_socket)
67061da546Spatrick : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd,
68061da546Spatrick listen_socket.m_child_processes_inherit) {
69061da546Spatrick m_socket = socket;
70061da546Spatrick }
71061da546Spatrick
Connect(llvm::StringRef name)72061da546Spatrick Status DomainSocket::Connect(llvm::StringRef name) {
73061da546Spatrick sockaddr_un saddr_un;
74061da546Spatrick socklen_t saddr_un_len;
75061da546Spatrick if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
76061da546Spatrick return Status("Failed to set socket address");
77061da546Spatrick
78061da546Spatrick Status error;
79061da546Spatrick m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error);
80061da546Spatrick if (error.Fail())
81061da546Spatrick return error;
82061da546Spatrick if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
83061da546Spatrick (struct sockaddr *)&saddr_un, saddr_un_len) < 0)
84061da546Spatrick SetLastError(error);
85061da546Spatrick
86061da546Spatrick return error;
87061da546Spatrick }
88061da546Spatrick
Listen(llvm::StringRef name,int backlog)89061da546Spatrick Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
90061da546Spatrick sockaddr_un saddr_un;
91061da546Spatrick socklen_t saddr_un_len;
92061da546Spatrick if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
93061da546Spatrick return Status("Failed to set socket address");
94061da546Spatrick
95061da546Spatrick DeleteSocketFile(name);
96061da546Spatrick
97061da546Spatrick Status error;
98061da546Spatrick m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error);
99061da546Spatrick if (error.Fail())
100061da546Spatrick return error;
101061da546Spatrick if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==
102061da546Spatrick 0)
103061da546Spatrick if (::listen(GetNativeSocket(), backlog) == 0)
104061da546Spatrick return error;
105061da546Spatrick
106061da546Spatrick SetLastError(error);
107061da546Spatrick return error;
108061da546Spatrick }
109061da546Spatrick
Accept(Socket * & socket)110061da546Spatrick Status DomainSocket::Accept(Socket *&socket) {
111061da546Spatrick Status error;
112061da546Spatrick auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr,
113061da546Spatrick m_child_processes_inherit, error);
114061da546Spatrick if (error.Success())
115061da546Spatrick socket = new DomainSocket(conn_fd, *this);
116061da546Spatrick
117061da546Spatrick return error;
118061da546Spatrick }
119061da546Spatrick
GetNameOffset() const120061da546Spatrick size_t DomainSocket::GetNameOffset() const { return 0; }
121061da546Spatrick
DeleteSocketFile(llvm::StringRef name)122061da546Spatrick void DomainSocket::DeleteSocketFile(llvm::StringRef name) {
123061da546Spatrick llvm::sys::fs::remove(name);
124061da546Spatrick }
125061da546Spatrick
GetSocketName() const126061da546Spatrick std::string DomainSocket::GetSocketName() const {
127*101d251dSrobert if (m_socket == kInvalidSocketValue)
128*101d251dSrobert return "";
129*101d251dSrobert
130061da546Spatrick struct sockaddr_un saddr_un;
131061da546Spatrick saddr_un.sun_family = AF_UNIX;
132061da546Spatrick socklen_t sock_addr_len = sizeof(struct sockaddr_un);
133*101d251dSrobert if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=
134*101d251dSrobert 0)
135061da546Spatrick return "";
136*101d251dSrobert
137*101d251dSrobert if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))
138*101d251dSrobert return ""; // Unnamed domain socket
139*101d251dSrobert
140*101d251dSrobert llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),
141*101d251dSrobert sock_addr_len - offsetof(struct sockaddr_un, sun_path) -
142*101d251dSrobert GetNameOffset());
143*101d251dSrobert name = name.rtrim('\0');
144*101d251dSrobert
145*101d251dSrobert return name.str();
146061da546Spatrick }
147061da546Spatrick
GetRemoteConnectionURI() const148061da546Spatrick std::string DomainSocket::GetRemoteConnectionURI() const {
149*101d251dSrobert std::string name = GetSocketName();
150*101d251dSrobert if (name.empty())
151*101d251dSrobert return name;
152*101d251dSrobert
153*101d251dSrobert return llvm::formatv(
154dda28197Spatrick "{0}://{1}",
155*101d251dSrobert GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
156061da546Spatrick }
157