LLDB mainline
DomainSocket.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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//===----------------------------------------------------------------------===//
8
11#ifdef __linux__
13#endif
14
15#include "llvm/Support/Errno.h"
16#include "llvm/Support/Error.h"
17#include "llvm/Support/FileSystem.h"
18
19#include <cstddef>
20#include <memory>
21
22#ifdef _WIN32
23#include <afunix.h>
24#else
25#include <sys/socket.h>
26#include <sys/un.h>
27#endif
29using namespace lldb;
30using namespace lldb_private;
31
32static const int kDomain = AF_UNIX;
33static const int kType = SOCK_STREAM;
34
35static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
36 sockaddr_un *saddr_un, socklen_t &saddr_un_len) {
37 if (name.size() + name_offset > sizeof(saddr_un->sun_path))
38 return false;
39
40 memset(saddr_un, 0, sizeof(*saddr_un));
41 saddr_un->sun_family = kDomain;
42
43 memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
44
45 // Compute the address length explicitly rather than via SUN_LEN: that macro
46 // is not available on Windows.
47 saddr_un_len =
48 offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
50#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
51 defined(__OpenBSD__)
52 saddr_un->sun_len = saddr_un_len;
53#endif
54
55 return true;
56}
57
59 : DomainSocket(kInvalidSocketValue, should_close) {}
60
61DomainSocket::DomainSocket(NativeSocket socket, bool should_close)
62 : Socket(ProtocolUnixDomain, should_close) {
63 m_socket = socket;
64}
65
67 : Socket(protocol, /*should_close=*/true) {}
68
70 const DomainSocket &listen_socket)
72 m_socket = socket;
73}
74
76 bool should_close)
77 : Socket(protocol, should_close) {
78 m_socket = socket;
79}
80
81Status DomainSocket::Connect(llvm::StringRef name) {
82 sockaddr_un saddr_un;
83 socklen_t saddr_un_len;
84 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
85 return Status::FromErrorString("Failed to set socket address");
86
89 if (error.Fail())
90 return error;
91 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
92 (struct sockaddr *)&saddr_un,
93 saddr_un_len) < 0)
95
96 return error;
97}
98
99Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
100 sockaddr_un saddr_un;
101 socklen_t saddr_un_len;
102 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
103 return Status::FromErrorString("Failed to set socket address");
104
105 DeleteSocketFile(name);
106
109 if (error.Fail())
110 return error;
111 if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==
112 0)
113 if (::listen(GetNativeSocket(), backlog) == 0)
114 return error;
115
117 return error;
118}
119
120llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> DomainSocket::Accept(
121 MainLoopBase &loop,
122 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
123 // TODO: Refactor MainLoop to avoid the shared_ptr requirement.
124 auto io_sp = std::make_shared<DomainSocket>(GetNativeSocket(), false);
125 auto cb = [this, sock_cb](MainLoopBase &loop) {
126 Log *log = GetLog(LLDBLog::Host);
128 auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, error);
129 if (error.Fail()) {
130 LLDB_LOG(log, "AcceptSocket({0}): {1}", GetNativeSocket(), error);
131 return;
132 }
133 std::unique_ptr<DomainSocket> sock_up(new DomainSocket(conn_fd, *this));
134 sock_cb(std::move(sock_up));
135 };
136
138 std::vector<MainLoopBase::ReadHandleUP> handles;
139 handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
140 if (error.Fail())
141 return error.ToError();
142 return handles;
143}
144
145size_t DomainSocket::GetNameOffset() const { return 0; }
146
147void DomainSocket::DeleteSocketFile(llvm::StringRef name) {
148 llvm::sys::fs::remove(name);
149}
150
151std::string DomainSocket::GetSocketName() const {
153 return "";
154
155 struct sockaddr_un saddr_un;
156 saddr_un.sun_family = AF_UNIX;
157 socklen_t sock_addr_len = sizeof(struct sockaddr_un);
158 if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=
159 0)
160 return "";
161
162 if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))
163 return ""; // Unnamed domain socket
164
165 llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),
166 sock_addr_len - offsetof(struct sockaddr_un, sun_path) -
167 GetNameOffset());
168 name = name.rtrim('\0');
169
170 return name.str();
171}
172
174 std::string name = GetSocketName();
175 if (name.empty())
176 return name;
177
178 return llvm::formatv(
179 "{0}://{1}",
180 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
181}
182
183std::vector<std::string> DomainSocket::GetListeningConnectionURI() const {
185 return {};
186
187 struct sockaddr_un addr;
188 memset(&addr, 0, sizeof(struct sockaddr_un));
189 addr.sun_family = AF_UNIX;
190 socklen_t addr_len = sizeof(struct sockaddr_un);
191 if (::getsockname(m_socket, (struct sockaddr *)&addr, &addr_len) != 0)
192 return {};
193
194 return {llvm::formatv("unix-connect://{0}", addr.sun_path)};
195}
196
197llvm::Expected<std::unique_ptr<DomainSocket>>
199 // Check if fd represents domain socket or abstract socket.
200 struct sockaddr_un addr;
201 socklen_t addr_len = sizeof(addr);
202 if (getsockname(sockfd, (struct sockaddr *)&addr, &addr_len) == -1)
203 return llvm::createStringError("not a socket or error occurred");
204 if (addr.sun_family != AF_UNIX)
205 return llvm::createStringError("bad socket type");
206#ifdef __linux__
207 if (addr_len > offsetof(struct sockaddr_un, sun_path) &&
208 addr.sun_path[0] == '\0')
209 return std::make_unique<AbstractSocket>(sockfd, should_close);
210#endif
211 return std::make_unique<DomainSocket>(sockfd, should_close);
212}
static llvm::raw_ostream & error(Stream &strm)
static const int kDomain
static bool SetSockAddr(llvm::StringRef name, const size_t name_offset, sockaddr_un *saddr_un, socklen_t &saddr_un_len)
static const int kType
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:376
DomainSocket(NativeSocket socket, bool should_close)
Status Listen(llvm::StringRef name, int backlog) override
llvm::Expected< std::vector< MainLoopBase::ReadHandleUP > > Accept(MainLoopBase &loop, std::function< void(std::unique_ptr< Socket > socket)> sock_cb) override
virtual size_t GetNameOffset() const
virtual void DeleteSocketFile(llvm::StringRef name)
Status Connect(llvm::StringRef name) override
static llvm::Expected< std::unique_ptr< DomainSocket > > FromBoundNativeSocket(NativeSocket sockfd, bool should_close)
std::string GetSocketName() const
std::string GetRemoteConnectionURI() const override
std::vector< std::string > GetListeningConnectionURI() const override
virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Status &error)=0
NativeSocket GetNativeSocket() const
Definition Socket.h:151
static const NativeSocket kInvalidSocketValue
Definition Socket.h:95
static NativeSocket CreateSocket(const int domain, const int type, const int protocol, Status &error)
Definition Socket.cpp:447
static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, Status &error)
Definition Socket.cpp:489
static void SetLastError(Status &error)
Definition Socket.cpp:421
NativeSocket m_socket
Definition Socket.h:187
Socket(SocketProtocol protocol, bool should_close)
Definition Socket.cpp:170
An error handling class.
Definition Status.h:118
static Status FromErrorString(const char *str)
Definition Status.h:141
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:339
int NativeSocket
Definition Socket.h:41