1 //===-- DomainSocket.cpp --------------------------------------------------===//
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
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"
17 #include <sys/socket.h>
21 using namespace lldb_private
;
24 // Android does not have SUN_LEN
26 #define SUN_LEN(ptr) \
27 (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path))
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
))
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.
48 saddr_un_len
= SUN_LEN(saddr_un
);
51 offsetof(struct sockaddr_un
, sun_path
) + name_offset
+ name
.size();
53 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
55 saddr_un
->sun_len
= saddr_un_len
;
61 DomainSocket::DomainSocket(bool should_close
)
62 : DomainSocket(kInvalidSocketValue
, should_close
) {}
64 DomainSocket::DomainSocket(NativeSocket socket
, bool should_close
)
65 : Socket(ProtocolUnixDomain
, should_close
) {
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
) {
78 Status
DomainSocket::Connect(llvm::StringRef name
) {
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");
85 m_socket
= CreateSocket(kDomain
, kType
, 0, error
);
88 if (llvm::sys::RetryAfterSignal(-1, ::connect
, GetNativeSocket(),
89 (struct sockaddr
*)&saddr_un
,
96 Status
DomainSocket::Listen(llvm::StringRef name
, int backlog
) {
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
);
105 m_socket
= CreateSocket(kDomain
, kType
, 0, error
);
108 if (::bind(GetNativeSocket(), (struct sockaddr
*)&saddr_un
, saddr_un_len
) ==
110 if (::listen(GetNativeSocket(), backlog
) == 0)
117 llvm::Expected
<std::vector
<MainLoopBase::ReadHandleUP
>> DomainSocket::Accept(
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
);
125 auto conn_fd
= AcceptSocket(GetNativeSocket(), nullptr, nullptr, error
);
127 LLDB_LOG(log
, "AcceptSocket({0}): {1}", GetNativeSocket(), error
);
130 std::unique_ptr
<DomainSocket
> sock_up(new DomainSocket(conn_fd
, *this));
131 sock_cb(std::move(sock_up
));
135 std::vector
<MainLoopBase::ReadHandleUP
> handles
;
136 handles
.emplace_back(loop
.RegisterReadObject(io_sp
, cb
, error
));
138 return error
.ToError();
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
)
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
) !=
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
) -
165 name
= name
.rtrim('\0');
170 std::string
DomainSocket::GetRemoteConnectionURI() const {
171 std::string name
= GetSocketName();
175 return llvm::formatv(
177 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name
);
180 std::vector
<std::string
> DomainSocket::GetListeningConnectionURI() const {
181 if (m_socket
== kInvalidSocketValue
)
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)
191 return {llvm::formatv("unix-connect://{0}", addr
.sun_path
)};