TCPSocket.cpp revision 355940
1//===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===// 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-exception 6// 7//===----------------------------------------------------------------------===// 8 9#if defined(_MSC_VER) 10#define _WINSOCK_DEPRECATED_NO_WARNINGS 11#endif 12 13#include "lldb/Host/common/TCPSocket.h" 14 15#include "lldb/Host/Config.h" 16#include "lldb/Host/MainLoop.h" 17#include "lldb/Utility/Log.h" 18 19#include "llvm/Config/llvm-config.h" 20#include "llvm/Support/Errno.h" 21#include "llvm/Support/raw_ostream.h" 22 23#ifndef LLDB_DISABLE_POSIX 24#include <arpa/inet.h> 25#include <netinet/tcp.h> 26#include <sys/socket.h> 27#endif 28 29#if defined(_WIN32) 30#include <winsock2.h> 31#endif 32 33#ifdef _WIN32 34#define CLOSE_SOCKET closesocket 35typedef const char *set_socket_option_arg_type; 36#else 37#include <unistd.h> 38#define CLOSE_SOCKET ::close 39typedef const void *set_socket_option_arg_type; 40#endif 41 42using namespace lldb; 43using namespace lldb_private; 44 45namespace { 46const int kType = SOCK_STREAM; 47} 48 49TCPSocket::TCPSocket(bool should_close, bool child_processes_inherit) 50 : Socket(ProtocolTcp, should_close, child_processes_inherit) {} 51 52TCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket) 53 : Socket(ProtocolTcp, listen_socket.m_should_close_fd, 54 listen_socket.m_child_processes_inherit) { 55 m_socket = socket; 56} 57 58TCPSocket::TCPSocket(NativeSocket socket, bool should_close, 59 bool child_processes_inherit) 60 : Socket(ProtocolTcp, should_close, child_processes_inherit) { 61 m_socket = socket; 62} 63 64TCPSocket::~TCPSocket() { CloseListenSockets(); } 65 66bool TCPSocket::IsValid() const { 67 return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0; 68} 69 70// Return the port number that is being used by the socket. 71uint16_t TCPSocket::GetLocalPortNumber() const { 72 if (m_socket != kInvalidSocketValue) { 73 SocketAddress sock_addr; 74 socklen_t sock_addr_len = sock_addr.GetMaxLength(); 75 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) 76 return sock_addr.GetPort(); 77 } else if (!m_listen_sockets.empty()) { 78 SocketAddress sock_addr; 79 socklen_t sock_addr_len = sock_addr.GetMaxLength(); 80 if (::getsockname(m_listen_sockets.begin()->first, sock_addr, 81 &sock_addr_len) == 0) 82 return sock_addr.GetPort(); 83 } 84 return 0; 85} 86 87std::string TCPSocket::GetLocalIPAddress() const { 88 // We bound to port zero, so we need to figure out which port we actually 89 // bound to 90 if (m_socket != kInvalidSocketValue) { 91 SocketAddress sock_addr; 92 socklen_t sock_addr_len = sock_addr.GetMaxLength(); 93 if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) 94 return sock_addr.GetIPAddress(); 95 } 96 return ""; 97} 98 99uint16_t TCPSocket::GetRemotePortNumber() const { 100 if (m_socket != kInvalidSocketValue) { 101 SocketAddress sock_addr; 102 socklen_t sock_addr_len = sock_addr.GetMaxLength(); 103 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0) 104 return sock_addr.GetPort(); 105 } 106 return 0; 107} 108 109std::string TCPSocket::GetRemoteIPAddress() const { 110 // We bound to port zero, so we need to figure out which port we actually 111 // bound to 112 if (m_socket != kInvalidSocketValue) { 113 SocketAddress sock_addr; 114 socklen_t sock_addr_len = sock_addr.GetMaxLength(); 115 if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0) 116 return sock_addr.GetIPAddress(); 117 } 118 return ""; 119} 120 121std::string TCPSocket::GetRemoteConnectionURI() const { 122 if (m_socket != kInvalidSocketValue) { 123 return llvm::formatv("connect://[{0}]:{1}", GetRemoteIPAddress(), 124 GetRemotePortNumber()); 125 } 126 return ""; 127} 128 129Status TCPSocket::CreateSocket(int domain) { 130 Status error; 131 if (IsValid()) 132 error = Close(); 133 if (error.Fail()) 134 return error; 135 m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, 136 m_child_processes_inherit, error); 137 return error; 138} 139 140Status TCPSocket::Connect(llvm::StringRef name) { 141 142 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); 143 if (log) 144 log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); 145 146 Status error; 147 std::string host_str; 148 std::string port_str; 149 int32_t port = INT32_MIN; 150 if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 151 return error; 152 153 auto addresses = lldb_private::SocketAddress::GetAddressInfo( 154 host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 155 for (auto address : addresses) { 156 error = CreateSocket(address.GetFamily()); 157 if (error.Fail()) 158 continue; 159 160 address.SetPort(port); 161 162 if (-1 == llvm::sys::RetryAfterSignal(-1, ::connect, 163 GetNativeSocket(), &address.sockaddr(), address.GetLength())) { 164 CLOSE_SOCKET(GetNativeSocket()); 165 continue; 166 } 167 168 SetOptionNoDelay(); 169 170 error.Clear(); 171 return error; 172 } 173 174 error.SetErrorString("Failed to connect port"); 175 return error; 176} 177 178Status TCPSocket::Listen(llvm::StringRef name, int backlog) { 179 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 180 if (log) 181 log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data()); 182 183 Status error; 184 std::string host_str; 185 std::string port_str; 186 int32_t port = INT32_MIN; 187 if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 188 return error; 189 190 if (host_str == "*") 191 host_str = "0.0.0.0"; 192 auto addresses = lldb_private::SocketAddress::GetAddressInfo( 193 host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 194 for (auto address : addresses) { 195 int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, 196 m_child_processes_inherit, error); 197 if (error.Fail()) { 198 error.Clear(); 199 continue; 200 } 201 202 // enable local address reuse 203 int option_value = 1; 204 set_socket_option_arg_type option_value_p = 205 reinterpret_cast<set_socket_option_arg_type>(&option_value); 206 ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, 207 sizeof(option_value)); 208 209 SocketAddress listen_address = address; 210 if(!listen_address.IsLocalhost()) 211 listen_address.SetToAnyAddress(address.GetFamily(), port); 212 else 213 listen_address.SetPort(port); 214 215 int err = 216 ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength()); 217 if (-1 != err) 218 err = ::listen(fd, backlog); 219 220 if (-1 == err) { 221 CLOSE_SOCKET(fd); 222 continue; 223 } 224 225 if (port == 0) { 226 socklen_t sa_len = address.GetLength(); 227 if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) 228 port = address.GetPort(); 229 } 230 m_listen_sockets[fd] = address; 231 } 232 233 if (m_listen_sockets.size() == 0) 234 error.SetErrorString("Failed to connect port"); 235 return error; 236} 237 238void TCPSocket::CloseListenSockets() { 239 for (auto socket : m_listen_sockets) 240 CLOSE_SOCKET(socket.first); 241 m_listen_sockets.clear(); 242} 243 244Status TCPSocket::Accept(Socket *&conn_socket) { 245 Status error; 246 if (m_listen_sockets.size() == 0) { 247 error.SetErrorString("No open listening sockets!"); 248 return error; 249 } 250 251 int sock = -1; 252 int listen_sock = -1; 253 lldb_private::SocketAddress AcceptAddr; 254 MainLoop accept_loop; 255 std::vector<MainLoopBase::ReadHandleUP> handles; 256 for (auto socket : m_listen_sockets) { 257 auto fd = socket.first; 258 auto inherit = this->m_child_processes_inherit; 259 auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit)); 260 handles.emplace_back(accept_loop.RegisterReadObject( 261 io_sp, [fd, inherit, &sock, &AcceptAddr, &error, 262 &listen_sock](MainLoopBase &loop) { 263 socklen_t sa_len = AcceptAddr.GetMaxLength(); 264 sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit, 265 error); 266 listen_sock = fd; 267 loop.RequestTermination(); 268 }, error)); 269 if (error.Fail()) 270 return error; 271 } 272 273 bool accept_connection = false; 274 std::unique_ptr<TCPSocket> accepted_socket; 275 // Loop until we are happy with our connection 276 while (!accept_connection) { 277 accept_loop.Run(); 278 279 if (error.Fail()) 280 return error; 281 282 lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock]; 283 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { 284 CLOSE_SOCKET(sock); 285 llvm::errs() << llvm::formatv( 286 "error: rejecting incoming connection from {0} (expecting {1})", 287 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); 288 continue; 289 } 290 accept_connection = true; 291 accepted_socket.reset(new TCPSocket(sock, *this)); 292 } 293 294 if (!accepted_socket) 295 return error; 296 297 // Keep our TCP packets coming without any delays. 298 accepted_socket->SetOptionNoDelay(); 299 error.Clear(); 300 conn_socket = accepted_socket.release(); 301 return error; 302} 303 304int TCPSocket::SetOptionNoDelay() { 305 return SetOption(IPPROTO_TCP, TCP_NODELAY, 1); 306} 307 308int TCPSocket::SetOptionReuseAddress() { 309 return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); 310} 311