brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.4 KiB · 6a73032 Raw
238 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/posix/DomainSocket.h"10#include "lldb/Utility/LLDBLog.h"11#ifdef __linux__12#include <lldb/Host/linux/AbstractSocket.h>13#endif14 15#include "llvm/Support/Errno.h"16#include "llvm/Support/Error.h"17#include "llvm/Support/FileSystem.h"18 19#include <cstddef>20#include <fcntl.h>21#include <memory>22#include <sys/socket.h>23#include <sys/un.h>24 25using namespace lldb;26using namespace lldb_private;27 28static const int kDomain = AF_UNIX;29static const int kType = SOCK_STREAM;30 31static bool SetSockAddr(llvm::StringRef name, const size_t name_offset,32                        sockaddr_un *saddr_un, socklen_t &saddr_un_len) {33  if (name.size() + name_offset > sizeof(saddr_un->sun_path))34    return false;35 36  memset(saddr_un, 0, sizeof(*saddr_un));37  saddr_un->sun_family = kDomain;38 39  memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());40 41  // For domain sockets we can use SUN_LEN in order to calculate size of42  // sockaddr_un, but for abstract sockets we have to calculate size manually43  // because of leading null symbol.44  if (name_offset == 0)45    saddr_un_len = SUN_LEN(saddr_un);46  else47    saddr_un_len =48        offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();49 50#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) ||       \51    defined(__OpenBSD__)52  saddr_un->sun_len = saddr_un_len;53#endif54 55  return true;56}57 58DomainSocket::DomainSocket(bool should_close)59    : DomainSocket(kInvalidSocketValue, should_close) {}60 61DomainSocket::DomainSocket(NativeSocket socket, bool should_close)62    : Socket(ProtocolUnixDomain, should_close) {63  m_socket = socket;64}65 66DomainSocket::DomainSocket(SocketProtocol protocol)67    : Socket(protocol, /*should_close=*/true) {}68 69DomainSocket::DomainSocket(NativeSocket socket,70                           const DomainSocket &listen_socket)71    : Socket(ProtocolUnixDomain, listen_socket.m_should_close_fd) {72  m_socket = socket;73}74 75DomainSocket::DomainSocket(SocketProtocol protocol, NativeSocket socket,76                           bool should_close)77    : Socket(protocol, should_close) {78  m_socket = socket;79}80 81llvm::Expected<DomainSocket::Pair> DomainSocket::CreatePair() {82  int sockets[2];83  int type = SOCK_STREAM;84#ifdef SOCK_CLOEXEC85  type |= SOCK_CLOEXEC;86#endif87  if (socketpair(AF_UNIX, type, 0, sockets) == -1)88    return llvm::errorCodeToError(llvm::errnoAsErrorCode());89 90#ifndef SOCK_CLOEXEC91  for (int s : sockets) {92    int r = fcntl(s, F_SETFD, FD_CLOEXEC | fcntl(s, F_GETFD));93    assert(r == 0);94    (void)r;95  }96#endif97 98  return Pair(std::unique_ptr<DomainSocket>(99                  new DomainSocket(ProtocolUnixDomain, sockets[0],100                                   /*should_close=*/true)),101              std::unique_ptr<DomainSocket>(102                  new DomainSocket(ProtocolUnixDomain, sockets[1],103                                   /*should_close=*/true)));104}105 106Status DomainSocket::Connect(llvm::StringRef name) {107  sockaddr_un saddr_un;108  socklen_t saddr_un_len;109  if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))110    return Status::FromErrorString("Failed to set socket address");111 112  Status error;113  m_socket = CreateSocket(kDomain, kType, 0, error);114  if (error.Fail())115    return error;116  if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),117                                  (struct sockaddr *)&saddr_un,118                                  saddr_un_len) < 0)119    SetLastError(error);120 121  return error;122}123 124Status DomainSocket::Listen(llvm::StringRef name, int backlog) {125  sockaddr_un saddr_un;126  socklen_t saddr_un_len;127  if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))128    return Status::FromErrorString("Failed to set socket address");129 130  DeleteSocketFile(name);131 132  Status error;133  m_socket = CreateSocket(kDomain, kType, 0, error);134  if (error.Fail())135    return error;136  if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) ==137      0)138    if (::listen(GetNativeSocket(), backlog) == 0)139      return error;140 141  SetLastError(error);142  return error;143}144 145llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> DomainSocket::Accept(146    MainLoopBase &loop,147    std::function<void(std::unique_ptr<Socket> socket)> sock_cb) {148  // TODO: Refactor MainLoop to avoid the shared_ptr requirement.149  auto io_sp = std::make_shared<DomainSocket>(GetNativeSocket(), false);150  auto cb = [this, sock_cb](MainLoopBase &loop) {151    Log *log = GetLog(LLDBLog::Host);152    Status error;153    auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, error);154    if (error.Fail()) {155      LLDB_LOG(log, "AcceptSocket({0}): {1}", GetNativeSocket(), error);156      return;157    }158    std::unique_ptr<DomainSocket> sock_up(new DomainSocket(conn_fd, *this));159    sock_cb(std::move(sock_up));160  };161 162  Status error;163  std::vector<MainLoopBase::ReadHandleUP> handles;164  handles.emplace_back(loop.RegisterReadObject(io_sp, cb, error));165  if (error.Fail())166    return error.ToError();167  return handles;168}169 170size_t DomainSocket::GetNameOffset() const { return 0; }171 172void DomainSocket::DeleteSocketFile(llvm::StringRef name) {173  llvm::sys::fs::remove(name);174}175 176std::string DomainSocket::GetSocketName() const {177  if (m_socket == kInvalidSocketValue)178    return "";179 180  struct sockaddr_un saddr_un;181  saddr_un.sun_family = AF_UNIX;182  socklen_t sock_addr_len = sizeof(struct sockaddr_un);183  if (::getpeername(m_socket, (struct sockaddr *)&saddr_un, &sock_addr_len) !=184      0)185    return "";186 187  if (sock_addr_len <= offsetof(struct sockaddr_un, sun_path))188    return ""; // Unnamed domain socket189 190  llvm::StringRef name(saddr_un.sun_path + GetNameOffset(),191                       sock_addr_len - offsetof(struct sockaddr_un, sun_path) -192                           GetNameOffset());193  name = name.rtrim('\0');194 195  return name.str();196}197 198std::string DomainSocket::GetRemoteConnectionURI() const {199  std::string name = GetSocketName();200  if (name.empty())201    return name;202 203  return llvm::formatv(204      "{0}://{1}",205      GetNameOffset() == 0 ? "unix-connect" : "unix-abstract-connect", name);206}207 208std::vector<std::string> DomainSocket::GetListeningConnectionURI() const {209  if (m_socket == kInvalidSocketValue)210    return {};211 212  struct sockaddr_un addr;213  memset(&addr, 0, sizeof(struct sockaddr_un));214  addr.sun_family = AF_UNIX;215  socklen_t addr_len = sizeof(struct sockaddr_un);216  if (::getsockname(m_socket, (struct sockaddr *)&addr, &addr_len) != 0)217    return {};218 219  return {llvm::formatv("unix-connect://{0}", addr.sun_path)};220}221 222llvm::Expected<std::unique_ptr<DomainSocket>>223DomainSocket::FromBoundNativeSocket(NativeSocket sockfd, bool should_close) {224  // Check if fd represents domain socket or abstract socket.225  struct sockaddr_un addr;226  socklen_t addr_len = sizeof(addr);227  if (getsockname(sockfd, (struct sockaddr *)&addr, &addr_len) == -1)228    return llvm::createStringError("not a socket or error occurred");229  if (addr.sun_family != AF_UNIX)230    return llvm::createStringError("Bad socket type");231#ifdef __linux__232  if (addr_len > offsetof(struct sockaddr_un, sun_path) &&233      addr.sun_path[0] == '\0')234    return std::make_unique<AbstractSocket>(sockfd, should_close);235#endif236  return std::make_unique<DomainSocket>(sockfd, should_close);237}238