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
12#include "llvm/Support/Errno.h"
13#include "llvm/Support/FileSystem.h"
14
15#include <cstddef>
16#include <memory>
17#include <sys/socket.h>
18#include <sys/un.h>
19
20using namespace lldb;
21using namespace lldb_private;
22
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__
30
31static const int kDomain = AF_UNIX;
32static const int kType = SOCK_STREAM;
33
34static 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;
38
39 memset(saddr_un, 0, sizeof(*saddr_un));
40 saddr_un->sun_family = kDomain;
41
42 memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
43
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();
52
53#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
54 defined(__OpenBSD__)
55 saddr_un->sun_len = saddr_un_len;
56#endif
57
58 return true;
59}
60
62 : DomainSocket(kInvalidSocketValue, should_close) {}
63
64DomainSocket::DomainSocket(NativeSocket socket, bool should_close)
65 : Socket(ProtocolUnixDomain, should_close) {
66 m_socket = socket;
67}
68
70 : Socket(protocol, /*should_close=*/true) {}
71
73 const DomainSocket &listen_socket)
74 : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd) {
75 m_socket = socket;
76}
77
78Status 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");
83
86 if (error.Fail())
87 return error;
88 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
89 (struct sockaddr *)&saddr_un, saddr_un_len) < 0)
91
92 return error;
93}
94
95Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
96 sockaddr_un saddr_un;
97 socklen_t saddr_un_len;
98 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
99 return Status::FromErrorString("Failed to set socket address");
100
101 DeleteSocketFile(name);
102
105 if (error.Fail())
106 return error;
107 if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==
108 0)
109 if (::listen(GetNativeSocket(), backlog) == 0)
110 return error;
111
113 return error;
114}
115
116llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> DomainSocket::Accept(
117 MainLoopBase &loop,
118 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {
119 // TODO: Refactor MainLoop to avoid the shared_ptr requirement.
120 auto io_sp = std::make_shared<DomainSocket>(GetNativeSocket(), false);
121 auto cb = [this, sock_cb](MainLoopBase &loop) {
122 Log *log = GetLog(LLDBLog::Host);
124 auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, error);
125 if (error.Fail()) {
126 LLDB_LOG(log, "AcceptSocket({0}): {1}", GetNativeSocket(), error);
127 return;
128 }
129 std::unique_ptr<DomainSocket> sock_up(new DomainSocket(conn_fd, *this));
130 sock_cb(std::move(sock_up));
131 };
132
134 std::vector<MainLoopBase::ReadHandleUP> handles;
135 handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));
136 if (error.Fail())
137 return error.ToError();
138 return handles;
139}
140
141size_t DomainSocket::GetNameOffset() const { return 0; }
142
143void DomainSocket::DeleteSocketFile(llvm::StringRef name) {
144 llvm::sys::fs::remove(name);
145}
146
147std::string DomainSocket::GetSocketName() const {
149 return "";
150
151 struct sockaddr_un saddr_un;
152 saddr_un.sun_family = AF_UNIX;
153 socklen_t sock_addr_len = sizeof(struct sockaddr_un);
154 if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=
155 0)
156 return "";
157
158 if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))
159 return ""; // Unnamed domain socket
160
161 llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),
162 sock_addr_len - offsetof(struct sockaddr_un, sun_path) -
163 GetNameOffset());
164 name = name.rtrim('\0');
165
166 return name.str();
167}
168
170 std::string name = GetSocketName();
171 if (name.empty())
172 return name;
173
174 return llvm::formatv(
175 "{0}://{1}",
176 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
177}
178
179std::vector<std::string> DomainSocket::GetListeningConnectionURI() const {
181 return {};
182
183 struct sockaddr_un addr;
184 bzero(&addr, sizeof(struct sockaddr_un));
185 addr.sun_family = AF_UNIX;
186 socklen_t addr_len = sizeof(struct sockaddr_un);
187 if (::getsockname(m_socket, (struct sockaddr *)&addr, &addr_len) != 0)
188 return {};
189
190 return {llvm::formatv("unix-connect://{0}", addr.sun_path)};
191}
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:369
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
virtual size_t GetNameOffset() const
virtual void DeleteSocketFile(llvm::StringRef name)
Status Connect(llvm::StringRef name) override
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:138
static const NativeSocket kInvalidSocketValue
Definition: Socket.h:86
static NativeSocket CreateSocket(const int domain, const int type, const int protocol, Status &error)
Definition: Socket.cpp:436
static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, Status &error)
Definition: Socket.cpp:472
static void SetLastError(Status &error)
Definition: Socket.cpp:410
NativeSocket m_socket
Definition: Socket.h:174
An error handling class.
Definition: Status.h:115
static Status FromErrorString(const char *str)
Definition: Status.h:138
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:332
int NativeSocket
Definition: Socket.h:41
Definition: SBAddress.h:15