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