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