[OptTable] Fix typo VALUE => VALUES (NFCI) (#121523)
[llvm-project.git] / lldb / source / Host / posix / DomainSocket.cpp
blobbe8fcdf2c8f2c8fab9fb952732b8b00148e87f79
1 //===-- DomainSocket.cpp --------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Host/posix/DomainSocket.h"
10 #include "lldb/Utility/LLDBLog.h"
12 #include "llvm/Support/Errno.h"
13 #include "llvm/Support/FileSystem.h"
15 #include <cstddef>
16 #include <memory>
17 #include <sys/socket.h>
18 #include <sys/un.h>
20 using namespace lldb;
21 using namespace lldb_private;
23 #ifdef __ANDROID__
24 // Android does not have SUN_LEN
25 #ifndef SUN_LEN
26 #define SUN_LEN(ptr) \
27 (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path))
28 #endif
29 #endif // #ifdef __ANDROID__
31 static const int kDomain = AF_UNIX;
32 static const int kType = SOCK_STREAM;
34 static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
35 sockaddr_un *saddr_un, socklen_t &saddr_un_len) {
36 if (name.size() + name_offset > sizeof(saddr_un->sun_path))
37 return false;
39 memset(saddr_un, 0, sizeof(*saddr_un));
40 saddr_un->sun_family = kDomain;
42 memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
44 // For domain sockets we can use SUN_LEN in order to calculate size of
45 // sockaddr_un, but for abstract sockets we have to calculate size manually
46 // because of leading null symbol.
47 if (name_offset == 0)
48 saddr_un_len = SUN_LEN(saddr_un);
49 else
50 saddr_un_len =
51 offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
53 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
54 defined(__OpenBSD__)
55 saddr_un->sun_len = saddr_un_len;
56 #endif
58 return true;
61 DomainSocket::DomainSocket(bool should_close)
62 : DomainSocket(kInvalidSocketValue, should_close) {}
64 DomainSocket::DomainSocket(NativeSocket socket, bool should_close)
65 : Socket(ProtocolUnixDomain, should_close) {
66 m_socket = socket;
69 DomainSocket::DomainSocket(SocketProtocol protocol)
70 : Socket(protocol, /*should_close=*/true) {}
72 DomainSocket::DomainSocket(NativeSocket socket,
73 const DomainSocket &listen_socket)
74 : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd) {
75 m_socket = socket;
78 Status DomainSocket::Connect(llvm::StringRef name) {
79 sockaddr_un saddr_un;
80 socklen_t saddr_un_len;
81 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
82 return Status::FromErrorString("Failed to set socket address");
84 Status error;
85 m_socket = CreateSocket(kDomain, kType, 0, error);
86 if (error.Fail())
87 return error;
88 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
89 (struct sockaddr *)&saddr_un,
90 saddr_un_len) < 0)
91 SetLastError(error);
93 return error;
96 Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
97 sockaddr_un saddr_un;
98 socklen_t saddr_un_len;
99 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
100 return Status::FromErrorString("Failed to set socket address");
102 DeleteSocketFile(name);
104 Status error;
105 m_socket = CreateSocket(kDomain, kType, 0, error);
106 if (error.Fail())
107 return error;
108 if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==
110 if (::listen(GetNativeSocket(), backlog) == 0)
111 return error;
113 SetLastError(error);
114 return error;
117 llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> DomainSocket::Accept(
118 MainLoopBase &loop,
119 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
120 // TODO: Refactor MainLoop to avoid the shared_ptr requirement.
121 auto io_sp = std::make_shared<DomainSocket>(GetNativeSocket(), false);
122 auto cb = [this, sock_cb](MainLoopBase &loop) {
123 Log *log = GetLog(LLDBLog::Host);
124 Status error;
125 auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, error);
126 if (error.Fail()) {
127 LLDB_LOG(log, "AcceptSocket({0}): {1}", GetNativeSocket(), error);
128 return;
130 std::unique_ptr<DomainSocket> sock_up(new DomainSocket(conn_fd, *this));
131 sock_cb(std::move(sock_up));
134 Status error;
135 std::vector<MainLoopBase::ReadHandleUP> handles;
136 handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
137 if (error.Fail())
138 return error.ToError();
139 return handles;
142 size_t DomainSocket::GetNameOffset() const { return 0; }
144 void DomainSocket::DeleteSocketFile(llvm::StringRef name) {
145 llvm::sys::fs::remove(name);
148 std::string DomainSocket::GetSocketName() const {
149 if (m_socket == kInvalidSocketValue)
150 return "";
152 struct sockaddr_un saddr_un;
153 saddr_un.sun_family = AF_UNIX;
154 socklen_t sock_addr_len = sizeof(struct sockaddr_un);
155 if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=
157 return "";
159 if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))
160 return ""; // Unnamed domain socket
162 llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),
163 sock_addr_len - offsetof(struct sockaddr_un, sun_path) -
164 GetNameOffset());
165 name = name.rtrim('\0');
167 return name.str();
170 std::string DomainSocket::GetRemoteConnectionURI() const {
171 std::string name = GetSocketName();
172 if (name.empty())
173 return name;
175 return llvm::formatv(
176 "{0}://{1}",
177 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
180 std::vector<std::string> DomainSocket::GetListeningConnectionURI() const {
181 if (m_socket == kInvalidSocketValue)
182 return {};
184 struct sockaddr_un addr;
185 memset(&addr, 0, sizeof(struct sockaddr_un));
186 addr.sun_family = AF_UNIX;
187 socklen_t addr_len = sizeof(struct sockaddr_un);
188 if (::getsockname(m_socket, (struct sockaddr *)&addr, &addr_len) != 0)
189 return {};
191 return {llvm::formatv("unix-connect://{0}", addr.sun_path)};