TCPSocket.cpp revision 360784
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#if LLDB_ENABLE_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 LLDB_LOGF(log, "TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); 144 145 Status error; 146 std::string host_str; 147 std::string port_str; 148 int32_t port = INT32_MIN; 149 if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 150 return error; 151 152 std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo( 153 host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 154 for (SocketAddress &address : addresses) { 155 error = CreateSocket(address.GetFamily()); 156 if (error.Fail()) 157 continue; 158 159 address.SetPort(port); 160 161 if (-1 == llvm::sys::RetryAfterSignal(-1, ::connect, 162 GetNativeSocket(), &address.sockaddr(), address.GetLength())) { 163 CLOSE_SOCKET(GetNativeSocket()); 164 continue; 165 } 166 167 SetOptionNoDelay(); 168 169 error.Clear(); 170 return error; 171 } 172 173 error.SetErrorString("Failed to connect port"); 174 return error; 175} 176 177Status TCPSocket::Listen(llvm::StringRef name, int backlog) { 178 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 179 LLDB_LOGF(log, "TCPSocket::%s (%s)", __FUNCTION__, name.data()); 180 181 Status error; 182 std::string host_str; 183 std::string port_str; 184 int32_t port = INT32_MIN; 185 if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 186 return error; 187 188 if (host_str == "*") 189 host_str = "0.0.0.0"; 190 std::vector<SocketAddress> addresses = SocketAddress::GetAddressInfo( 191 host_str.c_str(), nullptr, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 192 for (SocketAddress &address : addresses) { 193 int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, 194 m_child_processes_inherit, error); 195 if (error.Fail()) { 196 error.Clear(); 197 continue; 198 } 199 200 // enable local address reuse 201 int option_value = 1; 202 set_socket_option_arg_type option_value_p = 203 reinterpret_cast<set_socket_option_arg_type>(&option_value); 204 ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, 205 sizeof(option_value)); 206 207 SocketAddress listen_address = address; 208 if(!listen_address.IsLocalhost()) 209 listen_address.SetToAnyAddress(address.GetFamily(), port); 210 else 211 listen_address.SetPort(port); 212 213 int err = 214 ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength()); 215 if (-1 != err) 216 err = ::listen(fd, backlog); 217 218 if (-1 == err) { 219 CLOSE_SOCKET(fd); 220 continue; 221 } 222 223 if (port == 0) { 224 socklen_t sa_len = address.GetLength(); 225 if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) 226 port = address.GetPort(); 227 } 228 m_listen_sockets[fd] = address; 229 } 230 231 if (m_listen_sockets.size() == 0) 232 error.SetErrorString("Failed to connect port"); 233 return error; 234} 235 236void TCPSocket::CloseListenSockets() { 237 for (auto socket : m_listen_sockets) 238 CLOSE_SOCKET(socket.first); 239 m_listen_sockets.clear(); 240} 241 242Status TCPSocket::Accept(Socket *&conn_socket) { 243 Status error; 244 if (m_listen_sockets.size() == 0) { 245 error.SetErrorString("No open listening sockets!"); 246 return error; 247 } 248 249 int sock = -1; 250 int listen_sock = -1; 251 lldb_private::SocketAddress AcceptAddr; 252 MainLoop accept_loop; 253 std::vector<MainLoopBase::ReadHandleUP> handles; 254 for (auto socket : m_listen_sockets) { 255 auto fd = socket.first; 256 auto inherit = this->m_child_processes_inherit; 257 auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit)); 258 handles.emplace_back(accept_loop.RegisterReadObject( 259 io_sp, [fd, inherit, &sock, &AcceptAddr, &error, 260 &listen_sock](MainLoopBase &loop) { 261 socklen_t sa_len = AcceptAddr.GetMaxLength(); 262 sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit, 263 error); 264 listen_sock = fd; 265 loop.RequestTermination(); 266 }, error)); 267 if (error.Fail()) 268 return error; 269 } 270 271 bool accept_connection = false; 272 std::unique_ptr<TCPSocket> accepted_socket; 273 // Loop until we are happy with our connection 274 while (!accept_connection) { 275 accept_loop.Run(); 276 277 if (error.Fail()) 278 return error; 279 280 lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock]; 281 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { 282 CLOSE_SOCKET(sock); 283 llvm::errs() << llvm::formatv( 284 "error: rejecting incoming connection from {0} (expecting {1})", 285 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); 286 continue; 287 } 288 accept_connection = true; 289 accepted_socket.reset(new TCPSocket(sock, *this)); 290 } 291 292 if (!accepted_socket) 293 return error; 294 295 // Keep our TCP packets coming without any delays. 296 accepted_socket->SetOptionNoDelay(); 297 error.Clear(); 298 conn_socket = accepted_socket.release(); 299 return error; 300} 301 302int TCPSocket::SetOptionNoDelay() { 303 return SetOption(IPPROTO_TCP, TCP_NODELAY, 1); 304} 305 306int TCPSocket::SetOptionReuseAddress() { 307 return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); 308} 309