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