Path: blob/main/contrib/llvm-project/lldb/source/Host/common/TCPSocket.cpp
39606 views
//===-- TCPSocket.cpp -----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#if defined(_MSC_VER)9#define _WINSOCK_DEPRECATED_NO_WARNINGS10#endif1112#include "lldb/Host/common/TCPSocket.h"1314#include "lldb/Host/Config.h"15#include "lldb/Host/MainLoop.h"16#include "lldb/Utility/LLDBLog.h"17#include "lldb/Utility/Log.h"1819#include "llvm/Config/llvm-config.h"20#include "llvm/Support/Errno.h"21#include "llvm/Support/WindowsError.h"22#include "llvm/Support/raw_ostream.h"2324#if LLDB_ENABLE_POSIX25#include <arpa/inet.h>26#include <netinet/tcp.h>27#include <sys/socket.h>28#endif2930#if defined(_WIN32)31#include <winsock2.h>32#endif3334#ifdef _WIN3235#define CLOSE_SOCKET closesocket36typedef const char *set_socket_option_arg_type;37#else38#include <unistd.h>39#define CLOSE_SOCKET ::close40typedef const void *set_socket_option_arg_type;41#endif4243using namespace lldb;44using namespace lldb_private;4546static Status GetLastSocketError() {47std::error_code EC;48#ifdef _WIN3249EC = llvm::mapWindowsError(WSAGetLastError());50#else51EC = std::error_code(errno, std::generic_category());52#endif53return EC;54}5556static const int kType = SOCK_STREAM;5758TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)59: Socket(ProtocolTcp, should_close, child_processes_inherit) {}6061TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)62: Socket(ProtocolTcp, listen_socket.m_should_close_fd,63listen_socket.m_child_processes_inherit) {64m_socket = socket;65}6667TCPSocket::TCPSocket(NativeSocket socket, bool should_close,68bool child_processes_inherit)69: Socket(ProtocolTcp, should_close, child_processes_inherit) {70m_socket = socket;71}7273TCPSocket::~TCPSocket() { CloseListenSockets(); }7475bool TCPSocket::IsValid() const {76return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;77}7879// Return the port number that is being used by the socket.80uint16_t TCPSocket::GetLocalPortNumber() const {81if (m_socket != kInvalidSocketValue) {82SocketAddress sock_addr;83socklen_t sock_addr_len = sock_addr.GetMaxLength();84if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)85return sock_addr.GetPort();86} else if (!m_listen_sockets.empty()) {87SocketAddress sock_addr;88socklen_t sock_addr_len = sock_addr.GetMaxLength();89if (::getsockname(m_listen_sockets.begin()->first, sock_addr,90&sock_addr_len) == 0)91return sock_addr.GetPort();92}93return 0;94}9596std::string TCPSocket::GetLocalIPAddress() const {97// We bound to port zero, so we need to figure out which port we actually98// bound to99if (m_socket != kInvalidSocketValue) {100SocketAddress sock_addr;101socklen_t sock_addr_len = sock_addr.GetMaxLength();102if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)103return sock_addr.GetIPAddress();104}105return "";106}107108uint16_t TCPSocket::GetRemotePortNumber() const {109if (m_socket != kInvalidSocketValue) {110SocketAddress sock_addr;111socklen_t sock_addr_len = sock_addr.GetMaxLength();112if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)113return sock_addr.GetPort();114}115return 0;116}117118std::string TCPSocket::GetRemoteIPAddress() const {119// We bound to port zero, so we need to figure out which port we actually120// bound to121if (m_socket != kInvalidSocketValue) {122SocketAddress sock_addr;123socklen_t sock_addr_len = sock_addr.GetMaxLength();124if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)125return sock_addr.GetIPAddress();126}127return "";128}129130std::string TCPSocket::GetRemoteConnectionURI() const {131if (m_socket != kInvalidSocketValue) {132return std::string(llvm::formatv(133"connect://[{0}]:{1}", GetRemoteIPAddress(), GetRemotePortNumber()));134}135return "";136}137138Status TCPSocket::CreateSocket(int domain) {139Status error;140if (IsValid())141error = Close();142if (error.Fail())143return error;144m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP,145m_child_processes_inherit, error);146return error;147}148149Status TCPSocket::Connect(llvm::StringRef name) {150151Log *log = GetLog(LLDBLog::Communication);152LLDB_LOG(log, "Connect to host/port {0}", name);153154Status error;155llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);156if (!host_port)157return Status(host_port.takeError());158159std::vector<SocketAddress> addresses =160SocketAddress::GetAddressInfo(host_port->hostname.c_str(), nullptr,161AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);162for (SocketAddress &address : addresses) {163error = CreateSocket(address.GetFamily());164if (error.Fail())165continue;166167address.SetPort(host_port->port);168169if (llvm::sys::RetryAfterSignal(-1, ::connect, GetNativeSocket(),170&address.sockaddr(),171address.GetLength()) == -1) {172Close();173continue;174}175176if (SetOptionNoDelay() == -1) {177Close();178continue;179}180181error.Clear();182return error;183}184185error.SetErrorString("Failed to connect port");186return error;187}188189Status TCPSocket::Listen(llvm::StringRef name, int backlog) {190Log *log = GetLog(LLDBLog::Connection);191LLDB_LOG(log, "Listen to {0}", name);192193Status error;194llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);195if (!host_port)196return Status(host_port.takeError());197198if (host_port->hostname == "*")199host_port->hostname = "0.0.0.0";200std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo(201host_port->hostname.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);202for (SocketAddress &address : addresses) {203int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,204m_child_processes_inherit, error);205if (error.Fail() || fd < 0)206continue;207208// enable local address reuse209int option_value = 1;210set_socket_option_arg_type option_value_p =211reinterpret_cast<set_socket_option_arg_type>(&option_value);212if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,213sizeof(option_value)) == -1) {214CLOSE_SOCKET(fd);215continue;216}217218SocketAddress listen_address = address;219if(!listen_address.IsLocalhost())220listen_address.SetToAnyAddress(address.GetFamily(), host_port->port);221else222listen_address.SetPort(host_port->port);223224int err =225::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());226if (err != -1)227err = ::listen(fd, backlog);228229if (err == -1) {230error = GetLastSocketError();231CLOSE_SOCKET(fd);232continue;233}234235if (host_port->port == 0) {236socklen_t sa_len = address.GetLength();237if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)238host_port->port = address.GetPort();239}240m_listen_sockets[fd] = address;241}242243if (m_listen_sockets.empty()) {244assert(error.Fail());245return error;246}247return Status();248}249250void TCPSocket::CloseListenSockets() {251for (auto socket : m_listen_sockets)252CLOSE_SOCKET(socket.first);253m_listen_sockets.clear();254}255256Status TCPSocket::Accept(Socket *&conn_socket) {257Status error;258if (m_listen_sockets.size() == 0) {259error.SetErrorString("No open listening sockets!");260return error;261}262263NativeSocket sock = kInvalidSocketValue;264NativeSocket listen_sock = kInvalidSocketValue;265lldb_private::SocketAddress AcceptAddr;266MainLoop accept_loop;267std::vector<MainLoopBase::ReadHandleUP> handles;268for (auto socket : m_listen_sockets) {269auto fd = socket.first;270auto inherit = this->m_child_processes_inherit;271auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));272handles.emplace_back(accept_loop.RegisterReadObject(273io_sp, [fd, inherit, &sock, &AcceptAddr, &error,274&listen_sock](MainLoopBase &loop) {275socklen_t sa_len = AcceptAddr.GetMaxLength();276sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,277error);278listen_sock = fd;279loop.RequestTermination();280}, error));281if (error.Fail())282return error;283}284285bool accept_connection = false;286std::unique_ptr<TCPSocket> accepted_socket;287// Loop until we are happy with our connection288while (!accept_connection) {289accept_loop.Run();290291if (error.Fail())292return error;293294lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];295if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {296if (sock != kInvalidSocketValue) {297CLOSE_SOCKET(sock);298sock = kInvalidSocketValue;299}300llvm::errs() << llvm::formatv(301"error: rejecting incoming connection from {0} (expecting {1})",302AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());303continue;304}305accept_connection = true;306accepted_socket.reset(new TCPSocket(sock, *this));307}308309if (!accepted_socket)310return error;311312// Keep our TCP packets coming without any delays.313accepted_socket->SetOptionNoDelay();314error.Clear();315conn_socket = accepted_socket.release();316return error;317}318319int TCPSocket::SetOptionNoDelay() {320return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);321}322323int TCPSocket::SetOptionReuseAddress() {324return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);325}326327328