1314564Sdim//===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===// 2292932Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6292932Sdim// 7292932Sdim//===----------------------------------------------------------------------===// 8292932Sdim 9314564Sdim#if defined(_MSC_VER) 10314564Sdim#define _WINSOCK_DEPRECATED_NO_WARNINGS 11314564Sdim#endif 12314564Sdim 13292932Sdim#include "lldb/Host/common/TCPSocket.h" 14292932Sdim 15292932Sdim#include "lldb/Host/Config.h" 16321369Sdim#include "lldb/Host/MainLoop.h" 17321369Sdim#include "lldb/Utility/Log.h" 18292932Sdim 19321369Sdim#include "llvm/Config/llvm-config.h" 20353358Sdim#include "llvm/Support/Errno.h" 21321369Sdim#include "llvm/Support/raw_ostream.h" 22321369Sdim 23360784Sdim#if LLDB_ENABLE_POSIX 24292932Sdim#include <arpa/inet.h> 25292932Sdim#include <netinet/tcp.h> 26292932Sdim#include <sys/socket.h> 27292932Sdim#endif 28292932Sdim 29341825Sdim#if defined(_WIN32) 30321369Sdim#include <winsock2.h> 31321369Sdim#endif 32321369Sdim 33341825Sdim#ifdef _WIN32 34321369Sdim#define CLOSE_SOCKET closesocket 35321369Sdimtypedef const char *set_socket_option_arg_type; 36321369Sdim#else 37321369Sdim#include <unistd.h> 38321369Sdim#define CLOSE_SOCKET ::close 39321369Sdimtypedef const void *set_socket_option_arg_type; 40321369Sdim#endif 41321369Sdim 42292932Sdimusing namespace lldb; 43292932Sdimusing namespace lldb_private; 44292932Sdim 45292932Sdimnamespace { 46314564Sdimconst int kType = SOCK_STREAM; 47292932Sdim} 48292932Sdim 49321369SdimTCPSocket::TCPSocket(bool should_close, bool child_processes_inherit) 50321369Sdim : Socket(ProtocolTcp, should_close, child_processes_inherit) {} 51292932Sdim 52321369SdimTCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket) 53321369Sdim : Socket(ProtocolTcp, listen_socket.m_should_close_fd, 54321369Sdim listen_socket.m_child_processes_inherit) { 55321369Sdim m_socket = socket; 56321369Sdim} 57292932Sdim 58321369SdimTCPSocket::TCPSocket(NativeSocket socket, bool should_close, 59321369Sdim bool child_processes_inherit) 60321369Sdim : Socket(ProtocolTcp, should_close, child_processes_inherit) { 61321369Sdim m_socket = socket; 62321369Sdim} 63321369Sdim 64321369SdimTCPSocket::~TCPSocket() { CloseListenSockets(); } 65321369Sdim 66321369Sdimbool TCPSocket::IsValid() const { 67321369Sdim return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0; 68321369Sdim} 69321369Sdim 70292932Sdim// Return the port number that is being used by the socket. 71314564Sdimuint16_t TCPSocket::GetLocalPortNumber() const { 72314564Sdim if (m_socket != kInvalidSocketValue) { 73314564Sdim SocketAddress sock_addr; 74314564Sdim socklen_t sock_addr_len = sock_addr.GetMaxLength(); 75314564Sdim if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) 76314564Sdim return sock_addr.GetPort(); 77321369Sdim } else if (!m_listen_sockets.empty()) { 78321369Sdim SocketAddress sock_addr; 79321369Sdim socklen_t sock_addr_len = sock_addr.GetMaxLength(); 80321369Sdim if (::getsockname(m_listen_sockets.begin()->first, sock_addr, 81321369Sdim &sock_addr_len) == 0) 82321369Sdim return sock_addr.GetPort(); 83314564Sdim } 84314564Sdim return 0; 85292932Sdim} 86292932Sdim 87314564Sdimstd::string TCPSocket::GetLocalIPAddress() const { 88314564Sdim // We bound to port zero, so we need to figure out which port we actually 89314564Sdim // bound to 90314564Sdim if (m_socket != kInvalidSocketValue) { 91314564Sdim SocketAddress sock_addr; 92314564Sdim socklen_t sock_addr_len = sock_addr.GetMaxLength(); 93314564Sdim if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) 94314564Sdim return sock_addr.GetIPAddress(); 95314564Sdim } 96314564Sdim return ""; 97292932Sdim} 98292932Sdim 99314564Sdimuint16_t TCPSocket::GetRemotePortNumber() const { 100314564Sdim if (m_socket != kInvalidSocketValue) { 101314564Sdim SocketAddress sock_addr; 102314564Sdim socklen_t sock_addr_len = sock_addr.GetMaxLength(); 103314564Sdim if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0) 104314564Sdim return sock_addr.GetPort(); 105314564Sdim } 106314564Sdim return 0; 107292932Sdim} 108292932Sdim 109314564Sdimstd::string TCPSocket::GetRemoteIPAddress() const { 110314564Sdim // We bound to port zero, so we need to figure out which port we actually 111314564Sdim // bound to 112314564Sdim if (m_socket != kInvalidSocketValue) { 113314564Sdim SocketAddress sock_addr; 114314564Sdim socklen_t sock_addr_len = sock_addr.GetMaxLength(); 115314564Sdim if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0) 116314564Sdim return sock_addr.GetIPAddress(); 117314564Sdim } 118314564Sdim return ""; 119292932Sdim} 120292932Sdim 121353358Sdimstd::string TCPSocket::GetRemoteConnectionURI() const { 122353358Sdim if (m_socket != kInvalidSocketValue) { 123353358Sdim return llvm::formatv("connect://[{0}]:{1}", GetRemoteIPAddress(), 124353358Sdim GetRemotePortNumber()); 125353358Sdim } 126353358Sdim return ""; 127353358Sdim} 128353358Sdim 129321369SdimStatus TCPSocket::CreateSocket(int domain) { 130321369Sdim Status error; 131321369Sdim if (IsValid()) 132321369Sdim error = Close(); 133321369Sdim if (error.Fail()) 134321369Sdim return error; 135321369Sdim m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, 136321369Sdim m_child_processes_inherit, error); 137321369Sdim return error; 138321369Sdim} 139292932Sdim 140321369SdimStatus TCPSocket::Connect(llvm::StringRef name) { 141321369Sdim 142314564Sdim Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); 143360784Sdim LLDB_LOGF(log, "TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); 144292932Sdim 145321369Sdim Status error; 146314564Sdim std::string host_str; 147314564Sdim std::string port_str; 148314564Sdim int32_t port = INT32_MIN; 149314564Sdim if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 150314564Sdim return error; 151292932Sdim 152360784Sdim std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo( 153353358Sdim host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 154360784Sdim for (SocketAddress &address : addresses) { 155321369Sdim error = CreateSocket(address.GetFamily()); 156321369Sdim if (error.Fail()) 157321369Sdim continue; 158292932Sdim 159321369Sdim address.SetPort(port); 160292932Sdim 161353358Sdim if (-1 == llvm::sys::RetryAfterSignal(-1, ::connect, 162353358Sdim GetNativeSocket(), &address.sockaddr(), address.GetLength())) { 163321369Sdim CLOSE_SOCKET(GetNativeSocket()); 164321369Sdim continue; 165292932Sdim } 166292932Sdim 167321369Sdim SetOptionNoDelay(); 168321369Sdim 169321369Sdim error.Clear(); 170314564Sdim return error; 171314564Sdim } 172292932Sdim 173321369Sdim error.SetErrorString("Failed to connect port"); 174314564Sdim return error; 175292932Sdim} 176292932Sdim 177321369SdimStatus TCPSocket::Listen(llvm::StringRef name, int backlog) { 178314564Sdim Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 179360784Sdim LLDB_LOGF(log, "TCPSocket::%s (%s)", __FUNCTION__, name.data()); 180292932Sdim 181321369Sdim Status error; 182314564Sdim std::string host_str; 183314564Sdim std::string port_str; 184314564Sdim int32_t port = INT32_MIN; 185314564Sdim if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 186314564Sdim return error; 187292932Sdim 188321369Sdim if (host_str == "*") 189321369Sdim host_str = "0.0.0.0"; 190360784Sdim std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo( 191353358Sdim host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 192360784Sdim for (SocketAddress &address : addresses) { 193321369Sdim int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, 194321369Sdim m_child_processes_inherit, error); 195321369Sdim if (error.Fail()) { 196321369Sdim error.Clear(); 197321369Sdim continue; 198321369Sdim } 199292932Sdim 200321369Sdim // enable local address reuse 201321369Sdim int option_value = 1; 202321369Sdim set_socket_option_arg_type option_value_p = 203321369Sdim reinterpret_cast<set_socket_option_arg_type>(&option_value); 204321369Sdim ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, 205321369Sdim sizeof(option_value)); 206292932Sdim 207323112Sdim SocketAddress listen_address = address; 208323112Sdim if(!listen_address.IsLocalhost()) 209323112Sdim listen_address.SetToAnyAddress(address.GetFamily(), port); 210323112Sdim else 211323112Sdim listen_address.SetPort(port); 212292932Sdim 213323112Sdim int err = 214323112Sdim ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength()); 215321369Sdim if (-1 != err) 216321369Sdim err = ::listen(fd, backlog); 217292932Sdim 218321369Sdim if (-1 == err) { 219321369Sdim CLOSE_SOCKET(fd); 220321369Sdim continue; 221321369Sdim } 222292932Sdim 223321369Sdim if (port == 0) { 224321369Sdim socklen_t sa_len = address.GetLength(); 225321369Sdim if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) 226321369Sdim port = address.GetPort(); 227321369Sdim } 228321369Sdim m_listen_sockets[fd] = address; 229321369Sdim } 230321369Sdim 231321369Sdim if (m_listen_sockets.size() == 0) 232321369Sdim error.SetErrorString("Failed to connect port"); 233314564Sdim return error; 234292932Sdim} 235292932Sdim 236321369Sdimvoid TCPSocket::CloseListenSockets() { 237321369Sdim for (auto socket : m_listen_sockets) 238321369Sdim CLOSE_SOCKET(socket.first); 239321369Sdim m_listen_sockets.clear(); 240321369Sdim} 241321369Sdim 242321369SdimStatus TCPSocket::Accept(Socket *&conn_socket) { 243321369Sdim Status error; 244321369Sdim if (m_listen_sockets.size() == 0) { 245321369Sdim error.SetErrorString("No open listening sockets!"); 246314564Sdim return error; 247321369Sdim } 248292932Sdim 249321369Sdim int sock = -1; 250321369Sdim int listen_sock = -1; 251321369Sdim lldb_private::SocketAddress AcceptAddr; 252321369Sdim MainLoop accept_loop; 253321369Sdim std::vector<MainLoopBase::ReadHandleUP> handles; 254321369Sdim for (auto socket : m_listen_sockets) { 255321369Sdim auto fd = socket.first; 256321369Sdim auto inherit = this->m_child_processes_inherit; 257321369Sdim auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit)); 258321369Sdim handles.emplace_back(accept_loop.RegisterReadObject( 259321369Sdim io_sp, [fd, inherit, &sock, &AcceptAddr, &error, 260321369Sdim &listen_sock](MainLoopBase &loop) { 261321369Sdim socklen_t sa_len = AcceptAddr.GetMaxLength(); 262321369Sdim sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit, 263321369Sdim error); 264321369Sdim listen_sock = fd; 265321369Sdim loop.RequestTermination(); 266321369Sdim }, error)); 267321369Sdim if (error.Fail()) 268314564Sdim return error; 269314564Sdim } 270292932Sdim 271314564Sdim bool accept_connection = false; 272314564Sdim std::unique_ptr<TCPSocket> accepted_socket; 273314564Sdim // Loop until we are happy with our connection 274314564Sdim while (!accept_connection) { 275321369Sdim accept_loop.Run(); 276360784Sdim 277314564Sdim if (error.Fail()) 278321369Sdim return error; 279292932Sdim 280321369Sdim lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock]; 281321369Sdim if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { 282321369Sdim CLOSE_SOCKET(sock); 283321369Sdim llvm::errs() << llvm::formatv( 284321369Sdim "error: rejecting incoming connection from {0} (expecting {1})", 285321369Sdim AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); 286321369Sdim continue; 287292932Sdim } 288321369Sdim accept_connection = true; 289321369Sdim accepted_socket.reset(new TCPSocket(sock, *this)); 290314564Sdim } 291292932Sdim 292314564Sdim if (!accepted_socket) 293314564Sdim return error; 294292932Sdim 295314564Sdim // Keep our TCP packets coming without any delays. 296314564Sdim accepted_socket->SetOptionNoDelay(); 297314564Sdim error.Clear(); 298314564Sdim conn_socket = accepted_socket.release(); 299314564Sdim return error; 300292932Sdim} 301292932Sdim 302314564Sdimint TCPSocket::SetOptionNoDelay() { 303314564Sdim return SetOption(IPPROTO_TCP, TCP_NODELAY, 1); 304292932Sdim} 305292932Sdim 306314564Sdimint TCPSocket::SetOptionReuseAddress() { 307314564Sdim return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); 308292932Sdim} 309