xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/posix/DomainSocket.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //===-- DomainSocket.cpp --------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Host/posix/DomainSocket.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/Support/Errno.h"
120b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
130b57cec5SDimitry Andric 
14fe6060f1SDimitry Andric #include <cstddef>
150b57cec5SDimitry Andric #include <sys/socket.h>
160b57cec5SDimitry Andric #include <sys/un.h>
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace lldb;
190b57cec5SDimitry Andric using namespace lldb_private;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #ifdef __ANDROID__
220b57cec5SDimitry Andric // Android does not have SUN_LEN
230b57cec5SDimitry Andric #ifndef SUN_LEN
240b57cec5SDimitry Andric #define SUN_LEN(ptr)                                                           \
250b57cec5SDimitry Andric   (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path))
260b57cec5SDimitry Andric #endif
270b57cec5SDimitry Andric #endif // #ifdef __ANDROID__
280b57cec5SDimitry Andric 
29349cc55cSDimitry Andric static const int kDomain = AF_UNIX;
30349cc55cSDimitry Andric static const int kType = SOCK_STREAM;
310b57cec5SDimitry Andric 
SetSockAddr(llvm::StringRef name,const size_t name_offset,sockaddr_un * saddr_un,socklen_t & saddr_un_len)32349cc55cSDimitry Andric static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,
330b57cec5SDimitry Andric                         sockaddr_un *saddr_un, socklen_t &saddr_un_len) {
340b57cec5SDimitry Andric   if (name.size() + name_offset > sizeof(saddr_un->sun_path))
350b57cec5SDimitry Andric     return false;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   memset(saddr_un, 0, sizeof(*saddr_un));
380b57cec5SDimitry Andric   saddr_un->sun_family = kDomain;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   // For domain sockets we can use SUN_LEN in order to calculate size of
430b57cec5SDimitry Andric   // sockaddr_un, but for abstract sockets we have to calculate size manually
440b57cec5SDimitry Andric   // because of leading null symbol.
450b57cec5SDimitry Andric   if (name_offset == 0)
460b57cec5SDimitry Andric     saddr_un_len = SUN_LEN(saddr_un);
470b57cec5SDimitry Andric   else
480b57cec5SDimitry Andric     saddr_un_len =
490b57cec5SDimitry Andric         offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
500b57cec5SDimitry Andric 
51*5f757f3fSDimitry Andric #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) ||       \
52*5f757f3fSDimitry Andric     defined(__OpenBSD__)
530b57cec5SDimitry Andric   saddr_un->sun_len = saddr_un_len;
540b57cec5SDimitry Andric #endif
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   return true;
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
DomainSocket(bool should_close,bool child_processes_inherit)590b57cec5SDimitry Andric DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit)
600b57cec5SDimitry Andric     : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {}
610b57cec5SDimitry Andric 
DomainSocket(SocketProtocol protocol,bool child_processes_inherit)620b57cec5SDimitry Andric DomainSocket::DomainSocket(SocketProtocol protocol,
630b57cec5SDimitry Andric                            bool child_processes_inherit)
640b57cec5SDimitry Andric     : Socket(protocol, true, child_processes_inherit) {}
650b57cec5SDimitry Andric 
DomainSocket(NativeSocket socket,const DomainSocket & listen_socket)660b57cec5SDimitry Andric DomainSocket::DomainSocket(NativeSocket socket,
670b57cec5SDimitry Andric                            const DomainSocket &listen_socket)
680b57cec5SDimitry Andric     : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd,
690b57cec5SDimitry Andric              listen_socket.m_child_processes_inherit) {
700b57cec5SDimitry Andric   m_socket = socket;
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric 
Connect(llvm::StringRef name)730b57cec5SDimitry Andric Status DomainSocket::Connect(llvm::StringRef name) {
740b57cec5SDimitry Andric   sockaddr_un saddr_un;
750b57cec5SDimitry Andric   socklen_t saddr_un_len;
760b57cec5SDimitry Andric   if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
770b57cec5SDimitry Andric     return Status("Failed to set socket address");
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   Status error;
800b57cec5SDimitry Andric   m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error);
810b57cec5SDimitry Andric   if (error.Fail())
820b57cec5SDimitry Andric     return error;
830b57cec5SDimitry Andric   if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),
840b57cec5SDimitry Andric         (struct sockaddr *)&saddr_un, saddr_un_len) < 0)
850b57cec5SDimitry Andric     SetLastError(error);
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   return error;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric 
Listen(llvm::StringRef name,int backlog)900b57cec5SDimitry Andric Status DomainSocket::Listen(llvm::StringRef name, int backlog) {
910b57cec5SDimitry Andric   sockaddr_un saddr_un;
920b57cec5SDimitry Andric   socklen_t saddr_un_len;
930b57cec5SDimitry Andric   if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
940b57cec5SDimitry Andric     return Status("Failed to set socket address");
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   DeleteSocketFile(name);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   Status error;
990b57cec5SDimitry Andric   m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error);
1000b57cec5SDimitry Andric   if (error.Fail())
1010b57cec5SDimitry Andric     return error;
1020b57cec5SDimitry Andric   if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==
1030b57cec5SDimitry Andric       0)
1040b57cec5SDimitry Andric     if (::listen(GetNativeSocket(), backlog) == 0)
1050b57cec5SDimitry Andric       return error;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   SetLastError(error);
1080b57cec5SDimitry Andric   return error;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
Accept(Socket * & socket)1110b57cec5SDimitry Andric Status DomainSocket::Accept(Socket *&socket) {
1120b57cec5SDimitry Andric   Status error;
1130b57cec5SDimitry Andric   auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr,
1140b57cec5SDimitry Andric                               m_child_processes_inherit, error);
1150b57cec5SDimitry Andric   if (error.Success())
1160b57cec5SDimitry Andric     socket = new DomainSocket(conn_fd, *this);
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   return error;
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
GetNameOffset() const1210b57cec5SDimitry Andric size_t DomainSocket::GetNameOffset() const { return 0; }
1220b57cec5SDimitry Andric 
DeleteSocketFile(llvm::StringRef name)1230b57cec5SDimitry Andric void DomainSocket::DeleteSocketFile(llvm::StringRef name) {
1240b57cec5SDimitry Andric   llvm::sys::fs::remove(name);
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
GetSocketName() const1270b57cec5SDimitry Andric std::string DomainSocket::GetSocketName() const {
128349cc55cSDimitry Andric   if (m_socket == kInvalidSocketValue)
129349cc55cSDimitry Andric     return "";
130349cc55cSDimitry Andric 
1310b57cec5SDimitry Andric   struct sockaddr_un saddr_un;
1320b57cec5SDimitry Andric   saddr_un.sun_family = AF_UNIX;
1330b57cec5SDimitry Andric   socklen_t sock_addr_len = sizeof(struct sockaddr_un);
134349cc55cSDimitry Andric   if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=
135349cc55cSDimitry Andric       0)
1360b57cec5SDimitry Andric     return "";
137349cc55cSDimitry Andric 
138349cc55cSDimitry Andric   if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))
139349cc55cSDimitry Andric     return ""; // Unnamed domain socket
140349cc55cSDimitry Andric 
141349cc55cSDimitry Andric   llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),
142349cc55cSDimitry Andric                        sock_addr_len - offsetof(struct sockaddr_un, sun_path) -
143349cc55cSDimitry Andric                            GetNameOffset());
144349cc55cSDimitry Andric   name = name.rtrim('\0');
145349cc55cSDimitry Andric 
146349cc55cSDimitry Andric   return name.str();
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
GetRemoteConnectionURI() const1490b57cec5SDimitry Andric std::string DomainSocket::GetRemoteConnectionURI() const {
150349cc55cSDimitry Andric   std::string name = GetSocketName();
151349cc55cSDimitry Andric   if (name.empty())
152349cc55cSDimitry Andric     return name;
153349cc55cSDimitry Andric 
154349cc55cSDimitry Andric   return llvm::formatv(
1555ffd83dbSDimitry Andric       "{0}://{1}",
156349cc55cSDimitry Andric       GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);
1570b57cec5SDimitry Andric }
158