TCPSocket.cpp revision 323112
1//===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#if defined(_MSC_VER) 11#define _WINSOCK_DEPRECATED_NO_WARNINGS 12#endif 13 14#include "lldb/Host/common/TCPSocket.h" 15 16#include "lldb/Host/Config.h" 17#include "lldb/Host/MainLoop.h" 18#include "lldb/Utility/Log.h" 19 20#include "llvm/Config/llvm-config.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(LLVM_ON_WIN32) 30#include <winsock2.h> 31#endif 32 33#ifdef LLVM_ON_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 121Status TCPSocket::CreateSocket(int domain) { 122 Status error; 123 if (IsValid()) 124 error = Close(); 125 if (error.Fail()) 126 return error; 127 m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP, 128 m_child_processes_inherit, error); 129 return error; 130} 131 132Status TCPSocket::Connect(llvm::StringRef name) { 133 134 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); 135 if (log) 136 log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); 137 138 Status error; 139 std::string host_str; 140 std::string port_str; 141 int32_t port = INT32_MIN; 142 if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 143 return error; 144 145 auto addresses = lldb_private::SocketAddress::GetAddressInfo( 146 host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 147 for (auto address : addresses) { 148 error = CreateSocket(address.GetFamily()); 149 if (error.Fail()) 150 continue; 151 152 address.SetPort(port); 153 154 if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(), 155 address.GetLength())) { 156 CLOSE_SOCKET(GetNativeSocket()); 157 continue; 158 } 159 160 SetOptionNoDelay(); 161 162 error.Clear(); 163 return error; 164 } 165 166 error.SetErrorString("Failed to connect port"); 167 return error; 168} 169 170Status TCPSocket::Listen(llvm::StringRef name, int backlog) { 171 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 172 if (log) 173 log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data()); 174 175 Status error; 176 std::string host_str; 177 std::string port_str; 178 int32_t port = INT32_MIN; 179 if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) 180 return error; 181 182 if (host_str == "*") 183 host_str = "0.0.0.0"; 184 auto addresses = lldb_private::SocketAddress::GetAddressInfo( 185 host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); 186 for (auto address : addresses) { 187 int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP, 188 m_child_processes_inherit, error); 189 if (error.Fail()) { 190 error.Clear(); 191 continue; 192 } 193 194 // enable local address reuse 195 int option_value = 1; 196 set_socket_option_arg_type option_value_p = 197 reinterpret_cast<set_socket_option_arg_type>(&option_value); 198 ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p, 199 sizeof(option_value)); 200 201 SocketAddress listen_address = address; 202 if(!listen_address.IsLocalhost()) 203 listen_address.SetToAnyAddress(address.GetFamily(), port); 204 else 205 listen_address.SetPort(port); 206 207 int err = 208 ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength()); 209 if (-1 != err) 210 err = ::listen(fd, backlog); 211 212 if (-1 == err) { 213 CLOSE_SOCKET(fd); 214 continue; 215 } 216 217 if (port == 0) { 218 socklen_t sa_len = address.GetLength(); 219 if (getsockname(fd, &address.sockaddr(), &sa_len) == 0) 220 port = address.GetPort(); 221 } 222 m_listen_sockets[fd] = address; 223 } 224 225 if (m_listen_sockets.size() == 0) 226 error.SetErrorString("Failed to connect port"); 227 return error; 228} 229 230void TCPSocket::CloseListenSockets() { 231 for (auto socket : m_listen_sockets) 232 CLOSE_SOCKET(socket.first); 233 m_listen_sockets.clear(); 234} 235 236Status TCPSocket::Accept(Socket *&conn_socket) { 237 Status error; 238 if (m_listen_sockets.size() == 0) { 239 error.SetErrorString("No open listening sockets!"); 240 return error; 241 } 242 243 int sock = -1; 244 int listen_sock = -1; 245 lldb_private::SocketAddress AcceptAddr; 246 MainLoop accept_loop; 247 std::vector<MainLoopBase::ReadHandleUP> handles; 248 for (auto socket : m_listen_sockets) { 249 auto fd = socket.first; 250 auto inherit = this->m_child_processes_inherit; 251 auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit)); 252 handles.emplace_back(accept_loop.RegisterReadObject( 253 io_sp, [fd, inherit, &sock, &AcceptAddr, &error, 254 &listen_sock](MainLoopBase &loop) { 255 socklen_t sa_len = AcceptAddr.GetMaxLength(); 256 sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit, 257 error); 258 listen_sock = fd; 259 loop.RequestTermination(); 260 }, error)); 261 if (error.Fail()) 262 return error; 263 } 264 265 bool accept_connection = false; 266 std::unique_ptr<TCPSocket> accepted_socket; 267 // Loop until we are happy with our connection 268 while (!accept_connection) { 269 accept_loop.Run(); 270 271 if (error.Fail()) 272 return error; 273 274 lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock]; 275 if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) { 276 CLOSE_SOCKET(sock); 277 llvm::errs() << llvm::formatv( 278 "error: rejecting incoming connection from {0} (expecting {1})", 279 AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress()); 280 continue; 281 } 282 accept_connection = true; 283 accepted_socket.reset(new TCPSocket(sock, *this)); 284 } 285 286 if (!accepted_socket) 287 return error; 288 289 // Keep our TCP packets coming without any delays. 290 accepted_socket->SetOptionNoDelay(); 291 error.Clear(); 292 conn_socket = accepted_socket.release(); 293 return error; 294} 295 296int TCPSocket::SetOptionNoDelay() { 297 return SetOption(IPPROTO_TCP, TCP_NODELAY, 1); 298} 299 300int TCPSocket::SetOptionReuseAddress() { 301 return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); 302} 303