LLDB mainline
DomainSocket.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
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 <fcntl.h>
21#include <memory>
22#include <sys/socket.h>
23#include <sys/un.h>
24
25using namespace lldb;
26using namespace lldb_private;
27
28static const int kDomain = AF_UNIX;
29static const int kType = SOCK_STREAM;
30
31static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
32 sockaddr_un *saddr_un, socklen_t &saddr_un_len) {
33 if (name.size() + name_offset > sizeof(saddr_un->sun_path))
34 return false;
35
36 memset(saddr_un, 0, sizeof(*saddr_un));
37 saddr_un->sun_family = kDomain;
38
39 memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
40
41 // For domain sockets we can use SUN_LEN in order to calculate size of
42 // sockaddr_un, but for abstract sockets we have to calculate size manually
43 // because of leading null symbol.
44 if (name_offset == 0)
45 saddr_un_len = SUN_LEN(saddr_un);
46 else
47 saddr_un_len =
48 offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
49
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
81llvm::Expected<DomainSocket::Pair> DomainSocket::CreatePair() {
82 int sockets[2];
83 int type = SOCK_STREAM;
84#ifdef SOCK_CLOEXEC
85 type |= SOCK_CLOEXEC;
86#endif
87 if (socketpair(AF_UNIX, type, 0, sockets) == -1)
88 return llvm::errorCodeToError(llvm::errnoAsErrorCode());
89
90#ifndef SOCK_CLOEXEC
91 for (int s : sockets) {
92 int r = fcntl(s, F_SETFD, FD_CLOEXEC | fcntl(s, F_GETFD));
93 assert(r == 0);
94 (void)r;
95 }
96#endif
97
98#if defined(SO_NOSIGPIPE)
99 Log *log = GetLog(LLDBLog::Host);
100 if (Socket::SetOption(sockets[0], SOL_SOCKET, SO_NOSIGPIPE, 1) == -1)
101 LLDB_LOG(log, "failed to set NO_SIGPIPE on fd {0}: {1}", sockets[0],
102 llvm::sys::StrError());
103 if (Socket::SetOption(sockets[1], SOL_SOCKET, SO_NOSIGPIPE, 1) == -1)
104 LLDB_LOG(log, "failed to set NO_SIGPIPE on fd {0}: {1}", sockets[1],
105 llvm::sys::StrError());
106#endif
107
108 return Pair(std::unique_ptr<DomainSocket>(
109 new DomainSocket(ProtocolUnixDomain, sockets[0],
110 /*should_close=*/true)),
111 std::unique_ptr<DomainSocket>(
112 new DomainSocket(ProtocolUnixDomain, sockets[1],
113 /*should_close=*/true)));
114}
115
116Status DomainSocket::Connect(llvm::StringRef name) {
117 sockaddr_un saddr_un;
118 socklen_t saddr_un_len;
119 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
120 return Status::FromErrorString("Failed to set socket address");
121
124 if (error.Fail())
125 return error;
126 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
127 (struct sockaddr *)&saddr_un,
128 saddr_un_len) < 0)
130
131 return error;
132}
133
134Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
135 sockaddr_un saddr_un;
136 socklen_t saddr_un_len;
137 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
138 return Status::FromErrorString("Failed to set socket address");
139
140 DeleteSocketFile(name);
141
144 if (error.Fail())
145 return error;
146 if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==
147 0)
148 if (::listen(GetNativeSocket(), backlog) == 0)
149 return error;
150
152 return error;
153}
154
155llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> DomainSocket::Accept(
156 MainLoopBase &loop,
157 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
158 // TODO: Refactor MainLoop to avoid the shared_ptr requirement.
159 auto io_sp = std::make_shared<DomainSocket>(GetNativeSocket(), false);
160 auto cb = [this, sock_cb](MainLoopBase &loop) {
161 Log *log = GetLog(LLDBLog::Host);
163 auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, error);
164 if (error.Fail()) {
165 LLDB_LOG(log, "AcceptSocket({0}): {1}", GetNativeSocket(), error);
166 return;
167 }
168 std::unique_ptr<DomainSocket> sock_up(new DomainSocket(conn_fd, *this));
169 sock_cb(std::move(sock_up));
170 };
171
173 std::vector<MainLoopBase::ReadHandleUP> handles;
174 handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
175 if (error.Fail())
176 return error.ToError();
177 return handles;
178}
179
180size_t DomainSocket::GetNameOffset() const { return 0; }
181
182void DomainSocket::DeleteSocketFile(llvm::StringRef name) {
183 llvm::sys::fs::remove(name);
184}
185
186std::string DomainSocket::GetSocketName() const {
188 return "";
189
190 struct sockaddr_un saddr_un;
191 saddr_un.sun_family = AF_UNIX;
192 socklen_t sock_addr_len = sizeof(struct sockaddr_un);
193 if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=
194 0)
195 return "";
196
197 if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))
198 return ""; // Unnamed domain socket
199
200 llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),
201 sock_addr_len - offsetof(struct sockaddr_un, sun_path) -
202 GetNameOffset());
203 name = name.rtrim('\0');
204
205 return name.str();
206}
207
209 std::string name = GetSocketName();
210 if (name.empty())
211 return name;
212
213 return llvm::formatv(
214 "{0}://{1}",
215 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
216}
217
218std::vector<std::string> DomainSocket::GetListeningConnectionURI() const {
220 return {};
221
222 struct sockaddr_un addr;
223 memset(&addr, 0, sizeof(struct sockaddr_un));
224 addr.sun_family = AF_UNIX;
225 socklen_t addr_len = sizeof(struct sockaddr_un);
226 if (::getsockname(m_socket, (struct sockaddr *)&addr, &addr_len) != 0)
227 return {};
228
229 return {llvm::formatv("unix-connect://{0}", addr.sun_path)};
230}
231
232llvm::Expected<std::unique_ptr<DomainSocket>>
234 // Check if fd represents domain socket or abstract socket.
235 struct sockaddr_un addr;
236 socklen_t addr_len = sizeof(addr);
237 if (getsockname(sockfd, (struct sockaddr *)&addr, &addr_len) == -1)
238 return llvm::createStringError("not a socket or error occurred");
239 if (addr.sun_family != AF_UNIX)
240 return llvm::createStringError("bad socket type");
241#ifdef __linux__
242 if (addr_len > offsetof(struct sockaddr_un, sun_path) &&
243 addr.sun_path[0] == '\0')
244 return std::make_unique<AbstractSocket>(sockfd, should_close);
245#endif
246 return std::make_unique<DomainSocket>(sockfd, should_close);
247}
static llvm::raw_ostream & error(Stream &strm)
static bool SetSockAddr(llvm::StringRef name, const size_t name_offset, sockaddr_un *saddr_un, socklen_t &saddr_un_len)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:364
static const int kType
Definition TCPSocket.cpp:39
static const int kDomain
Definition UDPSocket.cpp:25
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
std::pair< std::unique_ptr< DomainSocket >, std::unique_ptr< DomainSocket > > Pair
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
static llvm::Expected< Pair > CreatePair()
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:440
static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, Status &error)
Definition Socket.cpp:482
static void SetLastError(Status &error)
Definition Socket.cpp:414
NativeSocket m_socket
Definition Socket.h:187
static int SetOption(NativeSocket sockfd, int level, int option_name, int option_value)
Definition Socket.cpp:398
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:327
int NativeSocket
Definition Socket.h:41