brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.7 KiB · eb333f7 Raw
521 lines · cpp
1//===-- Socket.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/Socket.h"10 11#include "lldb/Host/Config.h"12#include "lldb/Host/Host.h"13#include "lldb/Host/MainLoop.h"14#include "lldb/Host/SocketAddress.h"15#include "lldb/Host/common/TCPSocket.h"16#include "lldb/Host/common/UDPSocket.h"17#include "lldb/Utility/LLDBLog.h"18#include "lldb/Utility/Log.h"19 20#include "llvm/ADT/STLExtras.h"21#include "llvm/ADT/StringExtras.h"22#include "llvm/Support/Errno.h"23#include "llvm/Support/Error.h"24#include "llvm/Support/Regex.h"25#include "llvm/Support/WindowsError.h"26 27#if LLDB_ENABLE_POSIX28#include "lldb/Host/posix/DomainSocket.h"29 30#include <arpa/inet.h>31#include <netdb.h>32#include <netinet/in.h>33#include <netinet/tcp.h>34#include <sys/socket.h>35#include <sys/un.h>36#include <unistd.h>37#endif38 39#ifdef __linux__40#include "lldb/Host/linux/AbstractSocket.h"41#endif42 43using namespace lldb;44using namespace lldb_private;45 46#if defined(_WIN32)47typedef const char *set_socket_option_arg_type;48typedef char *get_socket_option_arg_type;49const NativeSocket Socket::kInvalidSocketValue = INVALID_SOCKET;50const shared_fd_t SharedSocket::kInvalidFD = LLDB_INVALID_PIPE;51#else  // #if defined(_WIN32)52typedef const void *set_socket_option_arg_type;53typedef void *get_socket_option_arg_type;54const NativeSocket Socket::kInvalidSocketValue = -1;55const shared_fd_t SharedSocket::kInvalidFD = Socket::kInvalidSocketValue;56#endif // #if defined(_WIN32)57 58static bool IsInterrupted() {59#if defined(_WIN32)60  return ::WSAGetLastError() == WSAEINTR;61#else62  return errno == EINTR;63#endif64}65 66SharedSocket::SharedSocket(const Socket *socket, Status &error) {67#ifdef _WIN3268  m_socket = socket->GetNativeSocket();69  m_fd = kInvalidFD;70 71  // Create a pipe to transfer WSAPROTOCOL_INFO to the child process.72  error = m_socket_pipe.CreateNew();73  if (error.Fail())74    return;75 76  m_fd = m_socket_pipe.GetReadPipe();77#else78  m_fd = socket->GetNativeSocket();79  error = Status();80#endif81}82 83Status SharedSocket::CompleteSending(lldb::pid_t child_pid) {84#ifdef _WIN3285  // Transfer WSAPROTOCOL_INFO to the child process.86  m_socket_pipe.CloseReadFileDescriptor();87 88  WSAPROTOCOL_INFO protocol_info;89  if (::WSADuplicateSocket(m_socket, child_pid, &protocol_info) ==90      SOCKET_ERROR) {91    int last_error = ::WSAGetLastError();92    return Status::FromErrorStringWithFormat(93        "WSADuplicateSocket() failed, error: %d", last_error);94  }95 96  llvm::Expected<size_t> num_bytes = m_socket_pipe.Write(97      &protocol_info, sizeof(protocol_info), std::chrono::seconds(10));98  if (!num_bytes)99    return Status::FromError(num_bytes.takeError());100  if (*num_bytes != sizeof(protocol_info))101    return Status::FromErrorStringWithFormatv(102        "Write(WSAPROTOCOL_INFO) failed: wrote {0}/{1} bytes", *num_bytes,103        sizeof(protocol_info));104#endif105  return Status();106}107 108Status SharedSocket::GetNativeSocket(shared_fd_t fd, NativeSocket &socket) {109#ifdef _WIN32110  socket = Socket::kInvalidSocketValue;111  // Read WSAPROTOCOL_INFO from the parent process and create NativeSocket.112  WSAPROTOCOL_INFO protocol_info;113  {114    Pipe socket_pipe(fd, LLDB_INVALID_PIPE);115    llvm::Expected<size_t> num_bytes = socket_pipe.Read(116        &protocol_info, sizeof(protocol_info), std::chrono::seconds(10));117    if (!num_bytes)118      return Status::FromError(num_bytes.takeError());119    if (*num_bytes != sizeof(protocol_info)) {120      return Status::FromErrorStringWithFormatv(121          "Read(WSAPROTOCOL_INFO) failed: read {0}/{1} bytes", *num_bytes,122          sizeof(protocol_info));123    }124  }125  socket = ::WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,126                       FROM_PROTOCOL_INFO, &protocol_info, 0, 0);127  if (socket == INVALID_SOCKET) {128    return Status::FromErrorStringWithFormatv(129        "WSASocket(FROM_PROTOCOL_INFO) failed: error {0}", ::WSAGetLastError());130  }131  return Status();132#else133  socket = fd;134  return Status();135#endif136}137 138struct SocketScheme {139  const char *m_scheme;140  const Socket::SocketProtocol m_protocol;141};142 143static SocketScheme socket_schemes[] = {144    {"tcp", Socket::ProtocolTcp},145    {"udp", Socket::ProtocolUdp},146    {"unix", Socket::ProtocolUnixDomain},147    {"unix-abstract", Socket::ProtocolUnixAbstract},148};149 150const char *151Socket::FindSchemeByProtocol(const Socket::SocketProtocol protocol) {152  for (auto s : socket_schemes) {153    if (s.m_protocol == protocol)154      return s.m_scheme;155  }156  return nullptr;157}158 159bool Socket::FindProtocolByScheme(const char *scheme,160                                  Socket::SocketProtocol &protocol) {161  for (auto s : socket_schemes) {162    if (!strcmp(s.m_scheme, scheme)) {163      protocol = s.m_protocol;164      return true;165    }166  }167  return false;168}169 170Socket::Socket(SocketProtocol protocol, bool should_close)171    : IOObject(eFDTypeSocket), m_protocol(protocol),172      m_socket(kInvalidSocketValue), m_should_close_fd(should_close) {}173 174Socket::~Socket() { Close(); }175 176llvm::Error Socket::Initialize() {177#if defined(_WIN32)178  auto wVersion = WINSOCK_VERSION;179  WSADATA wsaData;180  int err = ::WSAStartup(wVersion, &wsaData);181  if (err == 0) {182    if (wsaData.wVersion < wVersion) {183      WSACleanup();184      return llvm::createStringError("WSASock version is not expected.");185    }186  } else {187    return llvm::errorCodeToError(llvm::mapWindowsError(::WSAGetLastError()));188  }189#endif190 191  return llvm::Error::success();192}193 194void Socket::Terminate() {195#if defined(_WIN32)196  ::WSACleanup();197#endif198}199 200std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol,201                                       Status &error) {202  error.Clear();203 204  const bool should_close = true;205  std::unique_ptr<Socket> socket_up;206  switch (protocol) {207  case ProtocolTcp:208    socket_up = std::make_unique<TCPSocket>(should_close);209    break;210  case ProtocolUdp:211    socket_up = std::make_unique<UDPSocket>(should_close);212    break;213  case ProtocolUnixDomain:214#if LLDB_ENABLE_POSIX215    socket_up = std::make_unique<DomainSocket>(should_close);216#else217    error = Status::FromErrorString(218        "Unix domain sockets are not supported on this platform.");219#endif220    break;221  case ProtocolUnixAbstract:222#ifdef __linux__223    socket_up = std::make_unique<AbstractSocket>();224#else225    error = Status::FromErrorString(226        "Abstract domain sockets are not supported on this platform.");227#endif228    break;229  }230 231  if (error.Fail())232    socket_up.reset();233 234  return socket_up;235}236 237llvm::Expected<Socket::Pair>238Socket::CreatePair(std::optional<SocketProtocol> protocol) {239  constexpr SocketProtocol kBestProtocol =240      LLDB_ENABLE_POSIX ? ProtocolUnixDomain : ProtocolTcp;241  switch (protocol.value_or(kBestProtocol)) {242  case ProtocolTcp:243    return TCPSocket::CreatePair();244#if LLDB_ENABLE_POSIX245  case ProtocolUnixDomain:246  case ProtocolUnixAbstract:247    return DomainSocket::CreatePair();248#endif249  default:250    return llvm::createStringError("Unsupported protocol");251  }252}253 254llvm::Expected<std::unique_ptr<Socket>>255Socket::TcpConnect(llvm::StringRef host_and_port) {256  Log *log = GetLog(LLDBLog::Connection);257  LLDB_LOG(log, "host_and_port = {0}", host_and_port);258 259  Status error;260  std::unique_ptr<Socket> connect_socket = Create(ProtocolTcp, error);261  if (error.Fail())262    return error.ToError();263 264  error = connect_socket->Connect(host_and_port);265  if (error.Success())266    return std::move(connect_socket);267 268  return error.ToError();269}270 271llvm::Expected<std::unique_ptr<TCPSocket>>272Socket::TcpListen(llvm::StringRef host_and_port, int backlog) {273  Log *log = GetLog(LLDBLog::Connection);274  LLDB_LOG(log, "host_and_port = {0}", host_and_port);275 276  std::unique_ptr<TCPSocket> listen_socket(277      new TCPSocket(/*should_close=*/true));278 279  Status error = listen_socket->Listen(host_and_port, backlog);280  if (error.Fail())281    return error.ToError();282 283  return std::move(listen_socket);284}285 286llvm::Expected<std::unique_ptr<UDPSocket>>287Socket::UdpConnect(llvm::StringRef host_and_port) {288  return UDPSocket::CreateConnected(host_and_port);289}290 291llvm::Expected<Socket::HostAndPort>292Socket::DecodeHostAndPort(llvm::StringRef host_and_port) {293  static llvm::Regex g_regex("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)");294  HostAndPort ret;295  llvm::SmallVector<llvm::StringRef, 3> matches;296  if (g_regex.match(host_and_port, &matches)) {297    ret.hostname = matches[1].str();298    // IPv6 addresses are wrapped in [] when specified with ports299    if (ret.hostname.front() == '[' && ret.hostname.back() == ']')300      ret.hostname = ret.hostname.substr(1, ret.hostname.size() - 2);301    if (to_integer(matches[2], ret.port, 10))302      return ret;303  } else {304    // If this was unsuccessful, then check if it's simply an unsigned 16-bit305    // integer, representing a port with an empty host.306    if (to_integer(host_and_port, ret.port, 10))307      return ret;308  }309 310  return llvm::createStringError(llvm::inconvertibleErrorCode(),311                                 "invalid host:port specification: '%s'",312                                 host_and_port.str().c_str());313}314 315IOObject::WaitableHandle Socket::GetWaitableHandle() {316  return (IOObject::WaitableHandle)m_socket;317}318 319Status Socket::Read(void *buf, size_t &num_bytes) {320  Status error;321  int bytes_received = 0;322  do {323    bytes_received = ::recv(m_socket, static_cast<char *>(buf), num_bytes, 0);324  } while (bytes_received < 0 && IsInterrupted());325 326  if (bytes_received < 0) {327    SetLastError(error);328    num_bytes = 0;329  } else330    num_bytes = bytes_received;331 332  Log *log = GetLog(LLDBLog::Communication);333  if (log) {334    LLDB_LOGF(log,335              "%p Socket::Read() (socket = %" PRIu64336              ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64337              " (error = %s)",338              static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf,339              static_cast<uint64_t>(num_bytes),340              static_cast<int64_t>(bytes_received), error.AsCString());341  }342 343  return error;344}345 346Status Socket::Write(const void *buf, size_t &num_bytes) {347  const size_t src_len = num_bytes;348  Status error;349  int bytes_sent = 0;350  do {351    bytes_sent = Send(buf, num_bytes);352  } while (bytes_sent < 0 && IsInterrupted());353 354  if (bytes_sent < 0) {355    SetLastError(error);356    num_bytes = 0;357  } else358    num_bytes = bytes_sent;359 360  Log *log = GetLog(LLDBLog::Communication);361  if (log) {362    LLDB_LOGF(log,363              "%p Socket::Write() (socket = %" PRIu64364              ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64365              " (error = %s)",366              static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf,367              static_cast<uint64_t>(src_len), static_cast<int64_t>(bytes_sent),368              error.AsCString());369  }370 371  return error;372}373 374Status Socket::Close() {375  Status error;376  if (!IsValid() || !m_should_close_fd)377    return error;378 379  Log *log = GetLog(LLDBLog::Connection);380  LLDB_LOGF(log, "%p Socket::Close (fd = %" PRIu64 ")",381            static_cast<void *>(this), static_cast<uint64_t>(m_socket));382 383  bool success = CloseSocket(m_socket) == 0;384  // A reference to a FD was passed in, set it to an invalid value385  m_socket = kInvalidSocketValue;386  if (!success) {387    SetLastError(error);388  }389 390  return error;391}392 393int Socket::GetOption(NativeSocket sockfd, int level, int option_name,394                      int &option_value) {395  get_socket_option_arg_type option_value_p =396      reinterpret_cast<get_socket_option_arg_type>(&option_value);397  socklen_t option_value_size = sizeof(int);398  return ::getsockopt(sockfd, level, option_name, option_value_p,399                      &option_value_size);400}401 402int Socket::SetOption(NativeSocket sockfd, int level, int option_name,403                      int option_value) {404  set_socket_option_arg_type option_value_p =405      reinterpret_cast<set_socket_option_arg_type>(&option_value);406  return ::setsockopt(sockfd, level, option_name, option_value_p,407                      sizeof(option_value));408}409 410size_t Socket::Send(const void *buf, const size_t num_bytes) {411  return ::send(m_socket, static_cast<const char *>(buf), num_bytes, 0);412}413 414void Socket::SetLastError(Status &error) {415#if defined(_WIN32)416  error = Status(::WSAGetLastError(), lldb::eErrorTypeWin32);417#else418  error = Status::FromErrno();419#endif420}421 422Status Socket::GetLastError() {423  std::error_code EC;424#ifdef _WIN32425  EC = llvm::mapWindowsError(WSAGetLastError());426#else427  EC = std::error_code(errno, std::generic_category());428#endif429  return EC;430}431 432int Socket::CloseSocket(NativeSocket sockfd) {433#ifdef _WIN32434  return ::closesocket(sockfd);435#else436  return ::close(sockfd);437#endif438}439 440NativeSocket Socket::CreateSocket(const int domain, const int type,441                                  const int protocol, Status &error) {442  error.Clear();443  auto socket_type = type;444#ifdef SOCK_CLOEXEC445  socket_type |= SOCK_CLOEXEC;446#endif447  auto sock = ::socket(domain, socket_type, protocol);448  if (sock == kInvalidSocketValue)449    SetLastError(error);450 451  return sock;452}453 454Status Socket::Accept(const Timeout<std::micro> &timeout, Socket *&socket) {455  socket = nullptr;456  MainLoop accept_loop;457  llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> expected_handles =458      Accept(accept_loop,459             [&accept_loop, &socket](std::unique_ptr<Socket> sock) {460               socket = sock.release();461               accept_loop.RequestTermination();462             });463  if (!expected_handles)464    return Status::FromError(expected_handles.takeError());465  if (timeout) {466    accept_loop.AddCallback(467        [](MainLoopBase &loop) { loop.RequestTermination(); }, *timeout);468  }469  if (Status status = accept_loop.Run(); status.Fail())470    return status;471  if (socket)472    return Status();473  return Status(std::make_error_code(std::errc::timed_out));474}475 476NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr,477                                  socklen_t *addrlen, Status &error) {478  error.Clear();479#if defined(SOCK_CLOEXEC) && defined(HAVE_ACCEPT4)480  int flags = SOCK_CLOEXEC;481  NativeSocket fd = llvm::sys::RetryAfterSignal(482      static_cast<NativeSocket>(-1), ::accept4, sockfd, addr, addrlen, flags);483#else484  NativeSocket fd = llvm::sys::RetryAfterSignal(485      static_cast<NativeSocket>(-1), ::accept, sockfd, addr, addrlen);486#endif487  if (fd == kInvalidSocketValue)488    SetLastError(error);489  return fd;490}491 492llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS,493                                            const Socket::HostAndPort &HP) {494  return OS << '[' << HP.hostname << ']' << ':' << HP.port;495}496 497std::optional<Socket::ProtocolModePair>498Socket::GetProtocolAndMode(llvm::StringRef scheme) {499  // Keep in sync with ConnectionFileDescriptor::Connect.500  return llvm::StringSwitch<std::optional<ProtocolModePair>>(scheme)501      .Case("listen", ProtocolModePair{SocketProtocol::ProtocolTcp,502                                       SocketMode::ModeAccept})503      .Cases({"accept", "unix-accept"},504             ProtocolModePair{SocketProtocol::ProtocolUnixDomain,505                              SocketMode::ModeAccept})506      .Case("unix-abstract-accept",507            ProtocolModePair{SocketProtocol::ProtocolUnixAbstract,508                             SocketMode::ModeAccept})509      .Cases({"connect", "tcp-connect", "connection"},510             ProtocolModePair{SocketProtocol::ProtocolTcp,511                              SocketMode::ModeConnect})512      .Case("udp", ProtocolModePair{SocketProtocol::ProtocolTcp,513                                    SocketMode::ModeConnect})514      .Case("unix-connect", ProtocolModePair{SocketProtocol::ProtocolUnixDomain,515                                             SocketMode::ModeConnect})516      .Case("unix-abstract-connect",517            ProtocolModePair{SocketProtocol::ProtocolUnixAbstract,518                             SocketMode::ModeConnect})519      .Default(std::nullopt);520}521