Path: blob/main/contrib/llvm-project/lldb/source/Host/common/Socket.cpp
39606 views
//===-- Socket.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#include "lldb/Host/Socket.h"910#include "lldb/Host/Config.h"11#include "lldb/Host/Host.h"12#include "lldb/Host/SocketAddress.h"13#include "lldb/Host/common/TCPSocket.h"14#include "lldb/Host/common/UDPSocket.h"15#include "lldb/Utility/LLDBLog.h"16#include "lldb/Utility/Log.h"1718#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/StringExtras.h"20#include "llvm/Support/Errno.h"21#include "llvm/Support/Error.h"22#include "llvm/Support/Regex.h"23#include "llvm/Support/WindowsError.h"2425#if LLDB_ENABLE_POSIX26#include "lldb/Host/posix/DomainSocket.h"2728#include <arpa/inet.h>29#include <netdb.h>30#include <netinet/in.h>31#include <netinet/tcp.h>32#include <sys/socket.h>33#include <sys/un.h>34#include <unistd.h>35#endif3637#ifdef __linux__38#include "lldb/Host/linux/AbstractSocket.h"39#endif4041#ifdef __ANDROID__42#include <arpa/inet.h>43#include <asm-generic/errno-base.h>44#include <cerrno>45#include <fcntl.h>46#include <linux/tcp.h>47#include <sys/syscall.h>48#include <unistd.h>49#endif // __ANDROID__5051using namespace lldb;52using namespace lldb_private;5354#if defined(_WIN32)55typedef const char *set_socket_option_arg_type;56typedef char *get_socket_option_arg_type;57const NativeSocket Socket::kInvalidSocketValue = INVALID_SOCKET;58#else // #if defined(_WIN32)59typedef const void *set_socket_option_arg_type;60typedef void *get_socket_option_arg_type;61const NativeSocket Socket::kInvalidSocketValue = -1;62#endif // #if defined(_WIN32)6364static bool IsInterrupted() {65#if defined(_WIN32)66return ::WSAGetLastError() == WSAEINTR;67#else68return errno == EINTR;69#endif70}7172Socket::Socket(SocketProtocol protocol, bool should_close,73bool child_processes_inherit)74: IOObject(eFDTypeSocket), m_protocol(protocol),75m_socket(kInvalidSocketValue),76m_child_processes_inherit(child_processes_inherit),77m_should_close_fd(should_close) {}7879Socket::~Socket() { Close(); }8081llvm::Error Socket::Initialize() {82#if defined(_WIN32)83auto wVersion = WINSOCK_VERSION;84WSADATA wsaData;85int err = ::WSAStartup(wVersion, &wsaData);86if (err == 0) {87if (wsaData.wVersion < wVersion) {88WSACleanup();89return llvm::createStringError("WSASock version is not expected.");90}91} else {92return llvm::errorCodeToError(llvm::mapWindowsError(::WSAGetLastError()));93}94#endif9596return llvm::Error::success();97}9899void Socket::Terminate() {100#if defined(_WIN32)101::WSACleanup();102#endif103}104105std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol,106bool child_processes_inherit,107Status &error) {108error.Clear();109110std::unique_ptr<Socket> socket_up;111switch (protocol) {112case ProtocolTcp:113socket_up =114std::make_unique<TCPSocket>(true, child_processes_inherit);115break;116case ProtocolUdp:117socket_up =118std::make_unique<UDPSocket>(true, child_processes_inherit);119break;120case ProtocolUnixDomain:121#if LLDB_ENABLE_POSIX122socket_up =123std::make_unique<DomainSocket>(true, child_processes_inherit);124#else125error.SetErrorString(126"Unix domain sockets are not supported on this platform.");127#endif128break;129case ProtocolUnixAbstract:130#ifdef __linux__131socket_up =132std::make_unique<AbstractSocket>(child_processes_inherit);133#else134error.SetErrorString(135"Abstract domain sockets are not supported on this platform.");136#endif137break;138}139140if (error.Fail())141socket_up.reset();142143return socket_up;144}145146llvm::Expected<std::unique_ptr<Socket>>147Socket::TcpConnect(llvm::StringRef host_and_port,148bool child_processes_inherit) {149Log *log = GetLog(LLDBLog::Connection);150LLDB_LOG(log, "host_and_port = {0}", host_and_port);151152Status error;153std::unique_ptr<Socket> connect_socket(154Create(ProtocolTcp, child_processes_inherit, error));155if (error.Fail())156return error.ToError();157158error = connect_socket->Connect(host_and_port);159if (error.Success())160return std::move(connect_socket);161162return error.ToError();163}164165llvm::Expected<std::unique_ptr<TCPSocket>>166Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inherit,167int backlog) {168Log *log = GetLog(LLDBLog::Connection);169LLDB_LOG(log, "host_and_port = {0}", host_and_port);170171std::unique_ptr<TCPSocket> listen_socket(172new TCPSocket(true, child_processes_inherit));173174Status error = listen_socket->Listen(host_and_port, backlog);175if (error.Fail())176return error.ToError();177178return std::move(listen_socket);179}180181llvm::Expected<std::unique_ptr<UDPSocket>>182Socket::UdpConnect(llvm::StringRef host_and_port,183bool child_processes_inherit) {184return UDPSocket::Connect(host_and_port, child_processes_inherit);185}186187llvm::Expected<Socket::HostAndPort> Socket::DecodeHostAndPort(llvm::StringRef host_and_port) {188static llvm::Regex g_regex("([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)");189HostAndPort ret;190llvm::SmallVector<llvm::StringRef, 3> matches;191if (g_regex.match(host_and_port, &matches)) {192ret.hostname = matches[1].str();193// IPv6 addresses are wrapped in [] when specified with ports194if (ret.hostname.front() == '[' && ret.hostname.back() == ']')195ret.hostname = ret.hostname.substr(1, ret.hostname.size() - 2);196if (to_integer(matches[2], ret.port, 10))197return ret;198} else {199// If this was unsuccessful, then check if it's simply an unsigned 16-bit200// integer, representing a port with an empty host.201if (to_integer(host_and_port, ret.port, 10))202return ret;203}204205return llvm::createStringError(llvm::inconvertibleErrorCode(),206"invalid host:port specification: '%s'",207host_and_port.str().c_str());208}209210IOObject::WaitableHandle Socket::GetWaitableHandle() {211// TODO: On Windows, use WSAEventSelect212return m_socket;213}214215Status Socket::Read(void *buf, size_t &num_bytes) {216Status error;217int bytes_received = 0;218do {219bytes_received = ::recv(m_socket, static_cast<char *>(buf), num_bytes, 0);220} while (bytes_received < 0 && IsInterrupted());221222if (bytes_received < 0) {223SetLastError(error);224num_bytes = 0;225} else226num_bytes = bytes_received;227228Log *log = GetLog(LLDBLog::Communication);229if (log) {230LLDB_LOGF(log,231"%p Socket::Read() (socket = %" PRIu64232", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64233" (error = %s)",234static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf,235static_cast<uint64_t>(num_bytes),236static_cast<int64_t>(bytes_received), error.AsCString());237}238239return error;240}241242Status Socket::Write(const void *buf, size_t &num_bytes) {243const size_t src_len = num_bytes;244Status error;245int bytes_sent = 0;246do {247bytes_sent = Send(buf, num_bytes);248} while (bytes_sent < 0 && IsInterrupted());249250if (bytes_sent < 0) {251SetLastError(error);252num_bytes = 0;253} else254num_bytes = bytes_sent;255256Log *log = GetLog(LLDBLog::Communication);257if (log) {258LLDB_LOGF(log,259"%p Socket::Write() (socket = %" PRIu64260", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64261" (error = %s)",262static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf,263static_cast<uint64_t>(src_len),264static_cast<int64_t>(bytes_sent), error.AsCString());265}266267return error;268}269270Status Socket::Close() {271Status error;272if (!IsValid() || !m_should_close_fd)273return error;274275Log *log = GetLog(LLDBLog::Connection);276LLDB_LOGF(log, "%p Socket::Close (fd = %" PRIu64 ")",277static_cast<void *>(this), static_cast<uint64_t>(m_socket));278279#if defined(_WIN32)280bool success = closesocket(m_socket) == 0;281#else282bool success = ::close(m_socket) == 0;283#endif284// A reference to a FD was passed in, set it to an invalid value285m_socket = kInvalidSocketValue;286if (!success) {287SetLastError(error);288}289290return error;291}292293int Socket::GetOption(int level, int option_name, int &option_value) {294get_socket_option_arg_type option_value_p =295reinterpret_cast<get_socket_option_arg_type>(&option_value);296socklen_t option_value_size = sizeof(int);297return ::getsockopt(m_socket, level, option_name, option_value_p,298&option_value_size);299}300301int Socket::SetOption(int level, int option_name, int option_value) {302set_socket_option_arg_type option_value_p =303reinterpret_cast<get_socket_option_arg_type>(&option_value);304return ::setsockopt(m_socket, level, option_name, option_value_p,305sizeof(option_value));306}307308size_t Socket::Send(const void *buf, const size_t num_bytes) {309return ::send(m_socket, static_cast<const char *>(buf), num_bytes, 0);310}311312void Socket::SetLastError(Status &error) {313#if defined(_WIN32)314error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32);315#else316error.SetErrorToErrno();317#endif318}319320NativeSocket Socket::CreateSocket(const int domain, const int type,321const int protocol,322bool child_processes_inherit, Status &error) {323error.Clear();324auto socket_type = type;325#ifdef SOCK_CLOEXEC326if (!child_processes_inherit)327socket_type |= SOCK_CLOEXEC;328#endif329auto sock = ::socket(domain, socket_type, protocol);330if (sock == kInvalidSocketValue)331SetLastError(error);332333return sock;334}335336NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr,337socklen_t *addrlen,338bool child_processes_inherit, Status &error) {339error.Clear();340#if defined(ANDROID_USE_ACCEPT_WORKAROUND)341// Hack:342// This enables static linking lldb-server to an API 21 libc, but still343// having it run on older devices. It is necessary because API 21 libc's344// implementation of accept() uses the accept4 syscall(), which is not345// available in older kernels. Using an older libc would fix this issue, but346// introduce other ones, as the old libraries were quite buggy.347int fd = syscall(__NR_accept, sockfd, addr, addrlen);348if (fd >= 0 && !child_processes_inherit) {349int flags = ::fcntl(fd, F_GETFD);350if (flags != -1 && ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1)351return fd;352SetLastError(error);353close(fd);354}355return fd;356#elif defined(SOCK_CLOEXEC) && defined(HAVE_ACCEPT4)357int flags = 0;358if (!child_processes_inherit) {359flags |= SOCK_CLOEXEC;360}361NativeSocket fd = llvm::sys::RetryAfterSignal(362static_cast<NativeSocket>(-1), ::accept4, sockfd, addr, addrlen, flags);363#else364NativeSocket fd = llvm::sys::RetryAfterSignal(365static_cast<NativeSocket>(-1), ::accept, sockfd, addr, addrlen);366#endif367if (fd == kInvalidSocketValue)368SetLastError(error);369return fd;370}371372llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS,373const Socket::HostAndPort &HP) {374return OS << '[' << HP.hostname << ']' << ':' << HP.port;375}376377378