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 saddr_un->sun_len = saddr_un_len; 53 #endif 54 55 return true; 56 } 57 58 DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit) 59 : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {} 60 61 DomainSocket::DomainSocket(SocketProtocol protocol, 62 bool child_processes_inherit) 63 : Socket(protocol, true, child_processes_inherit) {} 64 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) { 69 m_socket = socket; 70 } 71 72 Status DomainSocket::Connect(llvm::StringRef name) { 73 sockaddr_un saddr_un; 74 socklen_t saddr_un_len; 75 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 76 return Status("Failed to set socket address"); 77 78 Status error; 79 m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 80 if (error.Fail()) 81 return error; 82 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), 83 (struct sockaddr *)&saddr_un, saddr_un_len) < 0) 84 SetLastError(error); 85 86 return error; 87 } 88 89 Status DomainSocket::Listen(llvm::StringRef name, int backlog) { 90 sockaddr_un saddr_un; 91 socklen_t saddr_un_len; 92 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 93 return Status("Failed to set socket address"); 94 95 DeleteSocketFile(name); 96 97 Status error; 98 m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 99 if (error.Fail()) 100 return error; 101 if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 102 0) 103 if (::listen(GetNativeSocket(), backlog) == 0) 104 return error; 105 106 SetLastError(error); 107 return error; 108 } 109 110 Status DomainSocket::Accept(Socket *&socket) { 111 Status error; 112 auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, 113 m_child_processes_inherit, error); 114 if (error.Success()) 115 socket = new DomainSocket(conn_fd, *this); 116 117 return error; 118 } 119 120 size_t DomainSocket::GetNameOffset() const { return 0; } 121 122 void DomainSocket::DeleteSocketFile(llvm::StringRef name) { 123 llvm::sys::fs::remove(name); 124 } 125 126 std::string DomainSocket::GetSocketName() const { 127 if (m_socket == kInvalidSocketValue) 128 return ""; 129 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) != 134 0) 135 return ""; 136 137 if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path)) 138 return ""; // Unnamed domain socket 139 140 llvm::StringRef name(saddr_un.sun_path + GetNameOffset(), 141 sock_addr_len - offsetof(struct sockaddr_un, sun_path) - 142 GetNameOffset()); 143 name = name.rtrim('\0'); 144 145 return name.str(); 146 } 147 148 std::string DomainSocket::GetRemoteConnectionURI() const { 149 std::string name = GetSocketName(); 150 if (name.empty()) 151 return name; 152 153 return llvm::formatv( 154 "{0}://{1}", 155 GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name); 156 } 157