1 //===-- DomainSocket.cpp ----------------------------------------*- C++ -*-===// 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 <stddef.h> 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 namespace { 30 31 const int kDomain = AF_UNIX; 32 const int kType = SOCK_STREAM; 33 34 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)) 37 return false; 38 39 memset(saddr_un, 0, sizeof(*saddr_un)); 40 saddr_un->sun_family = kDomain; 41 42 memcpy(saddr_un->sun_path + name_offset, name.data(), name.size()); 43 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. 47 if (name_offset == 0) 48 saddr_un_len = SUN_LEN(saddr_un); 49 else 50 saddr_un_len = 51 offsetof(struct sockaddr_un, sun_path) + name_offset + name.size(); 52 53 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 54 saddr_un->sun_len = saddr_un_len; 55 #endif 56 57 return true; 58 } 59 } // namespace 60 61 DomainSocket::DomainSocket(bool should_close, bool child_processes_inherit) 62 : Socket(ProtocolUnixDomain, should_close, child_processes_inherit) {} 63 64 DomainSocket::DomainSocket(SocketProtocol protocol, 65 bool child_processes_inherit) 66 : Socket(protocol, true, child_processes_inherit) {} 67 68 DomainSocket::DomainSocket(NativeSocket socket, 69 const DomainSocket &listen_socket) 70 : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd, 71 listen_socket.m_child_processes_inherit) { 72 m_socket = socket; 73 } 74 75 Status DomainSocket::Connect(llvm::StringRef name) { 76 sockaddr_un saddr_un; 77 socklen_t saddr_un_len; 78 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 79 return Status("Failed to set socket address"); 80 81 Status error; 82 m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 83 if (error.Fail()) 84 return error; 85 if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(), 86 (struct sockaddr *)&saddr_un, saddr_un_len) < 0) 87 SetLastError(error); 88 89 return error; 90 } 91 92 Status DomainSocket::Listen(llvm::StringRef name, int backlog) { 93 sockaddr_un saddr_un; 94 socklen_t saddr_un_len; 95 if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len)) 96 return Status("Failed to set socket address"); 97 98 DeleteSocketFile(name); 99 100 Status error; 101 m_socket = CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); 102 if (error.Fail()) 103 return error; 104 if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 105 0) 106 if (::listen(GetNativeSocket(), backlog) == 0) 107 return error; 108 109 SetLastError(error); 110 return error; 111 } 112 113 Status DomainSocket::Accept(Socket *&socket) { 114 Status error; 115 auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, 116 m_child_processes_inherit, error); 117 if (error.Success()) 118 socket = new DomainSocket(conn_fd, *this); 119 120 return error; 121 } 122 123 size_t DomainSocket::GetNameOffset() const { return 0; } 124 125 void DomainSocket::DeleteSocketFile(llvm::StringRef name) { 126 llvm::sys::fs::remove(name); 127 } 128 129 std::string DomainSocket::GetSocketName() const { 130 if (m_socket != kInvalidSocketValue) { 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 std::string name(saddr_un.sun_path + GetNameOffset(), 137 sock_addr_len - 138 offsetof(struct sockaddr_un, sun_path) - 139 GetNameOffset()); 140 if (name.back() == '\0') name.pop_back(); 141 return name; 142 } 143 } 144 return ""; 145 } 146 147 std::string DomainSocket::GetRemoteConnectionURI() const { 148 if (m_socket != kInvalidSocketValue) { 149 return llvm::formatv("{0}://{1}", 150 GetNameOffset() == 0 ? "unix-connect" 151 : "unix-abstract-connect", 152 GetSocketName()); 153 } 154 return ""; 155 } 156