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"
11 #include "llvm/Support/Errno.h"
12 #include "llvm/Support/FileSystem.h"
15 #include <sys/socket.h>
19 using namespace lldb_private
;
22 // Android does not have SUN_LEN
24 #define SUN_LEN(ptr) \
25 (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path))
27 #endif // #ifdef __ANDROID__
29 static const int kDomain
= AF_UNIX
;
30 static const int kType
= SOCK_STREAM
;
32 static bool SetSockAddr(llvm::StringRef name
, const size_t name_offset
,
33 sockaddr_un
*saddr_un
, socklen_t
&saddr_un_len
) {
34 if (name
.size() + name_offset
> sizeof(saddr_un
->sun_path
))
37 memset(saddr_un
, 0, sizeof(*saddr_un
));
38 saddr_un
->sun_family
= kDomain
;
40 memcpy(saddr_un
->sun_path
+ name_offset
, name
.data(), name
.size());
42 // For domain sockets we can use SUN_LEN in order to calculate size of
43 // sockaddr_un, but for abstract sockets we have to calculate size manually
44 // because of leading null symbol.
46 saddr_un_len
= SUN_LEN(saddr_un
);
49 offsetof(struct sockaddr_un
, sun_path
) + name_offset
+ name
.size();
51 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
52 saddr_un
->sun_len
= saddr_un_len
;
58 DomainSocket::DomainSocket(bool should_close
, bool child_processes_inherit
)
59 : Socket(ProtocolUnixDomain
, should_close
, child_processes_inherit
) {}
61 DomainSocket::DomainSocket(SocketProtocol protocol
,
62 bool child_processes_inherit
)
63 : Socket(protocol
, true, child_processes_inherit
) {}
65 DomainSocket::DomainSocket(NativeSocket socket
,
66 const DomainSocket
&listen_socket
)
67 : Socket(ProtocolUnixDomain
, listen_socket
.m_should_close_fd
,
68 listen_socket
.m_child_processes_inherit
) {
72 Status
DomainSocket::Connect(llvm::StringRef name
) {
74 socklen_t saddr_un_len
;
75 if (!SetSockAddr(name
, GetNameOffset(), &saddr_un
, saddr_un_len
))
76 return Status("Failed to set socket address");
79 m_socket
= CreateSocket(kDomain
, kType
, 0, m_child_processes_inherit
, error
);
82 if (llvm::sys::RetryAfterSignal(-1, ::connect
, GetNativeSocket(),
83 (struct sockaddr
*)&saddr_un
, saddr_un_len
) < 0)
89 Status
DomainSocket::Listen(llvm::StringRef name
, int backlog
) {
91 socklen_t saddr_un_len
;
92 if (!SetSockAddr(name
, GetNameOffset(), &saddr_un
, saddr_un_len
))
93 return Status("Failed to set socket address");
95 DeleteSocketFile(name
);
98 m_socket
= CreateSocket(kDomain
, kType
, 0, m_child_processes_inherit
, error
);
101 if (::bind(GetNativeSocket(), (struct sockaddr
*)&saddr_un
, saddr_un_len
) ==
103 if (::listen(GetNativeSocket(), backlog
) == 0)
110 Status
DomainSocket::Accept(Socket
*&socket
) {
112 auto conn_fd
= AcceptSocket(GetNativeSocket(), nullptr, nullptr,
113 m_child_processes_inherit
, error
);
115 socket
= new DomainSocket(conn_fd
, *this);
120 size_t DomainSocket::GetNameOffset() const { return 0; }
122 void DomainSocket::DeleteSocketFile(llvm::StringRef name
) {
123 llvm::sys::fs::remove(name
);
126 std::string
DomainSocket::GetSocketName() const {
127 if (m_socket
== kInvalidSocketValue
)
130 struct sockaddr_un saddr_un
;
131 saddr_un
.sun_family
= AF_UNIX
;
132 socklen_t sock_addr_len
= sizeof(struct sockaddr_un
);
133 if (::getpeername(m_socket
, (struct sockaddr
*)&saddr_un
, &sock_addr_len
) !=
137 if (sock_addr_len
<= offsetof(struct sockaddr_un
, sun_path
))
138 return ""; // Unnamed domain socket
140 llvm::StringRef
name(saddr_un
.sun_path
+ GetNameOffset(),
141 sock_addr_len
- offsetof(struct sockaddr_un
, sun_path
) -
143 name
= name
.rtrim('\0');
148 std::string
DomainSocket::GetRemoteConnectionURI() const {
149 std::string name
= GetSocketName();
153 return llvm::formatv(
155 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name
);