xref: /openbsd-src/gnu/llvm/lldb/source/Host/posix/DomainSocket.cpp (revision 101d251d5caf88a9341f3045ab62e122abae1b90)
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