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 9 #include "lldb/Host/posix/DomainSocket.h" 10 11 #include "llvm/Support/Errno.h" 12 #include "llvm/Support/FileSystem.h" 13 14 #include <cstddef> 15 #include <sys/socket.h> 16 #include <sys/un.h> 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 #ifdef __ANDROID__ 22 // Android does not have SUN_LEN 23 #ifndef SUN_LEN 24 #define SUN_LEN(ptr) \ 25 (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) 26 #endif 27 #endif // #ifdef __ANDROID__ 28 29 static const int kDomain = AF_UNIX; 30 static const int kType = SOCK_STREAM; 31 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)) 35 return false; 36 37 memset(saddr_un, 0, sizeof(*saddr_un)); 38 saddr_un->sun_family = kDomain; 39 40 memcpy(saddr_un->sun_path + name_offset, name.data(), name.size()); 41 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. 45 if (name_offset == 0) 46 saddr_un_len = SUN_LEN(saddr_un); 47 else 48 saddr_un_len = 49 offsetof(struct sockaddr_un, sun_path) + name_offset + name.size(); 50 51 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ 52 defined(__OpenBSD__) 53 saddr_un->sun_len = saddr_un_len; 54 #endif 55 56 return true; 57 } 58 59 DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit) 60 : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {} 61 62 DomainSocket::DomainSocket(SocketProtocol protocol, 63 bool child_processes_inherit) 64 : Socket(protocol, true, child_processes_inherit) {} 65 66 DomainSocket::DomainSocket(NativeSocket socket, 67 const DomainSocket &listen_socket) 68 : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd, 69 listen_socket.m_child_processes_inherit) { 70 m_socket = socket; 71 } 72 73 Status DomainSocket::Connect(llvm::StringRef name) { 74 sockaddr_un saddr_un; 75 socklen_t saddr_un_len; 76 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 77 return Status("Failed to set socket address"); 78 79 Status error; 80 m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 81 if (error.Fail()) 82 return error; 83 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), 84 (struct sockaddr *)&saddr_un, saddr_un_len) < 0) 85 SetLastError(error); 86 87 return error; 88 } 89 90 Status DomainSocket::Listen(llvm::StringRef name, int backlog) { 91 sockaddr_un saddr_un; 92 socklen_t saddr_un_len; 93 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 94 return Status("Failed to set socket address"); 95 96 DeleteSocketFile(name); 97 98 Status error; 99 m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 100 if (error.Fail()) 101 return error; 102 if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 103 0) 104 if (::listen(GetNativeSocket(), backlog) == 0) 105 return error; 106 107 SetLastError(error); 108 return error; 109 } 110 111 Status DomainSocket::Accept(Socket *&socket) { 112 Status error; 113 auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, 114 m_child_processes_inherit, error); 115 if (error.Success()) 116 socket = new DomainSocket(conn_fd, *this); 117 118 return error; 119 } 120 121 size_t DomainSocket::GetNameOffset() const { return 0; } 122 123 void DomainSocket::DeleteSocketFile(llvm::StringRef name) { 124 llvm::sys::fs::remove(name); 125 } 126 127 std::string DomainSocket::GetSocketName() const { 128 if (m_socket == kInvalidSocketValue) 129 return ""; 130 131 struct sockaddr_un saddr_un; 132 saddr_un.sun_family = AF_UNIX; 133 socklen_t sock_addr_len = sizeof(struct sockaddr_un); 134 if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) != 135 0) 136 return ""; 137 138 if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path)) 139 return ""; // Unnamed domain socket 140 141 llvm::StringRef name(saddr_un.sun_path + GetNameOffset(), 142 sock_addr_len - offsetof(struct sockaddr_un, sun_path) - 143 GetNameOffset()); 144 name = name.rtrim('\0'); 145 146 return name.str(); 147 } 148 149 std::string DomainSocket::GetRemoteConnectionURI() const { 150 std::string name = GetSocketName(); 151 if (name.empty()) 152 return name; 153 154 return llvm::formatv( 155 "{0}://{1}", 156 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name); 157 } 158