TCPSocket.cpp revision 341825
178556Sobrien//===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===//
278556Sobrien//
378556Sobrien//                     The LLVM Compiler Infrastructure
478556Sobrien//
578556Sobrien// This file is distributed under the University of Illinois Open Source
678556Sobrien// License. See LICENSE.TXT for details.
7167974Sdelphij//
8167974Sdelphij//===----------------------------------------------------------------------===//
9167974Sdelphij
1078556Sobrien#if defined(_MSC_VER)
11215041Sobrien#define _WINSOCK_DEPRECATED_NO_WARNINGS
12215041Sobrien#endif
1378556Sobrien
14167974Sdelphij#include "lldb/Host/common/TCPSocket.h"
15167974Sdelphij
1678556Sobrien#include "lldb/Host/Config.h"
17167974Sdelphij#include "lldb/Host/MainLoop.h"
18167974Sdelphij#include "lldb/Utility/Log.h"
19167974Sdelphij
2078556Sobrien#include "llvm/Config/llvm-config.h"
2178556Sobrien#include "llvm/Support/raw_ostream.h"
2278556Sobrien
2378556Sobrien#ifndef LLDB_DISABLE_POSIX
2478556Sobrien#include <arpa/inet.h>
2578556Sobrien#include <netinet/tcp.h>
2678556Sobrien#include <sys/socket.h>
2778556Sobrien#endif
2878556Sobrien
2978556Sobrien#if defined(_WIN32)
3078556Sobrien#include <winsock2.h>
3178556Sobrien#endif
3278556Sobrien
3378556Sobrien#ifdef _WIN32
3478556Sobrien#define CLOSE_SOCKET closesocket
3578556Sobrientypedef const char *set_socket_option_arg_type;
3678556Sobrien#else
3778556Sobrien#include <unistd.h>
3878556Sobrien#define CLOSE_SOCKET ::close
39215041Sobrientypedef const void *set_socket_option_arg_type;
4078556Sobrien#endif
4178556Sobrien
4278556Sobrienusing namespace lldb;
4378556Sobrienusing namespace lldb_private;
4478556Sobrien
4578556Sobriennamespace {
4678556Sobrienconst int kType = SOCK_STREAM;
4778556Sobrien}
4878556Sobrien
4978556SobrienTCPSocket::TCPSocket(bool should_close, bool child_processes_inherit)
5078556Sobrien    : Socket(ProtocolTcp, should_close, child_processes_inherit) {}
5178556Sobrien
5278556SobrienTCPSocket::TCPSocket(NativeSocket socket, const TCPSocket &listen_socket)
5378556Sobrien    : Socket(ProtocolTcp, listen_socket.m_should_close_fd,
5478556Sobrien             listen_socket.m_child_processes_inherit) {
5578556Sobrien  m_socket = socket;
5678556Sobrien}
57167974Sdelphij
5878556SobrienTCPSocket::TCPSocket(NativeSocket socket, bool should_close,
5978556Sobrien                     bool child_processes_inherit)
6078556Sobrien    : Socket(ProtocolTcp, should_close, child_processes_inherit) {
61167974Sdelphij  m_socket = socket;
6278556Sobrien}
6378556Sobrien
6478556SobrienTCPSocket::~TCPSocket() { CloseListenSockets(); }
6578556Sobrien
6678556Sobrienbool TCPSocket::IsValid() const {
6778556Sobrien  return m_socket != kInvalidSocketValue || m_listen_sockets.size() != 0;
6878556Sobrien}
6978556Sobrien
7078556Sobrien// Return the port number that is being used by the socket.
7178556Sobrienuint16_t TCPSocket::GetLocalPortNumber() const {
72167974Sdelphij  if (m_socket != kInvalidSocketValue) {
7378556Sobrien    SocketAddress sock_addr;
7478556Sobrien    socklen_t sock_addr_len = sock_addr.GetMaxLength();
7578556Sobrien    if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
7678556Sobrien      return sock_addr.GetPort();
7778556Sobrien  } else if (!m_listen_sockets.empty()) {
7878556Sobrien    SocketAddress sock_addr;
7978556Sobrien    socklen_t sock_addr_len = sock_addr.GetMaxLength();
8078556Sobrien    if (::getsockname(m_listen_sockets.begin()->first, sock_addr,
8178556Sobrien                      &sock_addr_len) == 0)
8278556Sobrien      return sock_addr.GetPort();
8378556Sobrien  }
8478556Sobrien  return 0;
85167974Sdelphij}
8678556Sobrien
87167974Sdelphijstd::string TCPSocket::GetLocalIPAddress() const {
8878556Sobrien  // We bound to port zero, so we need to figure out which port we actually
8978556Sobrien  // bound to
9078556Sobrien  if (m_socket != kInvalidSocketValue) {
91167974Sdelphij    SocketAddress sock_addr;
92167974Sdelphij    socklen_t sock_addr_len = sock_addr.GetMaxLength();
93167974Sdelphij    if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0)
94167974Sdelphij      return sock_addr.GetIPAddress();
95167974Sdelphij  }
96167974Sdelphij  return "";
97167974Sdelphij}
98167974Sdelphij
9978556Sobrienuint16_t TCPSocket::GetRemotePortNumber() const {
10078556Sobrien  if (m_socket != kInvalidSocketValue) {
10178556Sobrien    SocketAddress sock_addr;
10278556Sobrien    socklen_t sock_addr_len = sock_addr.GetMaxLength();
10378556Sobrien    if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
10478556Sobrien      return sock_addr.GetPort();
10578556Sobrien  }
10690067Ssobomax  return 0;
10790067Ssobomax}
10890067Ssobomax
10990067Ssobomaxstd::string TCPSocket::GetRemoteIPAddress() const {
11090067Ssobomax  // We bound to port zero, so we need to figure out which port we actually
11190067Ssobomax  // bound to
11290067Ssobomax  if (m_socket != kInvalidSocketValue) {
11378556Sobrien    SocketAddress sock_addr;
11478556Sobrien    socklen_t sock_addr_len = sock_addr.GetMaxLength();
11578556Sobrien    if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0)
11678556Sobrien      return sock_addr.GetIPAddress();
11778556Sobrien  }
11878556Sobrien  return "";
11978556Sobrien}
12078556Sobrien
12178556SobrienStatus TCPSocket::CreateSocket(int domain) {
12278556Sobrien  Status error;
12378556Sobrien  if (IsValid())
12478556Sobrien    error = Close();
12578556Sobrien  if (error.Fail())
12678556Sobrien    return error;
12778556Sobrien  m_socket = Socket::CreateSocket(domain, kType, IPPROTO_TCP,
12878556Sobrien                                  m_child_processes_inherit, error);
12978556Sobrien  return error;
13078556Sobrien}
13178556Sobrien
13278556SobrienStatus TCPSocket::Connect(llvm::StringRef name) {
13378556Sobrien
13478556Sobrien  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION));
13578556Sobrien  if (log)
13678556Sobrien    log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
13778556Sobrien
13878556Sobrien  Status error;
13978556Sobrien  std::string host_str;
14078556Sobrien  std::string port_str;
14178556Sobrien  int32_t port = INT32_MIN;
14278556Sobrien  if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
14378556Sobrien    return error;
14478556Sobrien
14578556Sobrien  auto addresses = lldb_private::SocketAddress::GetAddressInfo(
14678556Sobrien      host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
14778556Sobrien  for (auto address : addresses) {
14878556Sobrien    error = CreateSocket(address.GetFamily());
14978556Sobrien    if (error.Fail())
15078556Sobrien      continue;
15178556Sobrien
15278556Sobrien    address.SetPort(port);
15378556Sobrien
15478556Sobrien    if (-1 == ::connect(GetNativeSocket(), &address.sockaddr(),
15578556Sobrien                        address.GetLength())) {
15678556Sobrien      CLOSE_SOCKET(GetNativeSocket());
15778556Sobrien      continue;
15878556Sobrien    }
15978556Sobrien
16078556Sobrien    SetOptionNoDelay();
16178556Sobrien
16278556Sobrien    error.Clear();
16378556Sobrien    return error;
16478556Sobrien  }
16578556Sobrien
16678556Sobrien  error.SetErrorString("Failed to connect port");
16778556Sobrien  return error;
16878556Sobrien}
16978556Sobrien
17078556SobrienStatus TCPSocket::Listen(llvm::StringRef name, int backlog) {
17178556Sobrien  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
17278556Sobrien  if (log)
17378556Sobrien    log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data());
17478556Sobrien
17578556Sobrien  Status error;
17678556Sobrien  std::string host_str;
17778556Sobrien  std::string port_str;
17878556Sobrien  int32_t port = INT32_MIN;
17978556Sobrien  if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
18078556Sobrien    return error;
18178556Sobrien
18278556Sobrien  if (host_str == "*")
18378556Sobrien    host_str = "0.0.0.0";
18478556Sobrien  auto addresses = lldb_private::SocketAddress::GetAddressInfo(
18578556Sobrien      host_str.c_str(), NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
18678556Sobrien  for (auto address : addresses) {
18778556Sobrien    int fd = Socket::CreateSocket(address.GetFamily(), kType, IPPROTO_TCP,
18878556Sobrien                                  m_child_processes_inherit, error);
18978556Sobrien    if (error.Fail()) {
19078556Sobrien      error.Clear();
19178556Sobrien      continue;
19278556Sobrien    }
19378556Sobrien
19478556Sobrien    // enable local address reuse
19578556Sobrien    int option_value = 1;
19678556Sobrien    set_socket_option_arg_type option_value_p =
19778556Sobrien        reinterpret_cast<set_socket_option_arg_type>(&option_value);
19878556Sobrien    ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, option_value_p,
19978556Sobrien                 sizeof(option_value));
20078556Sobrien
20178556Sobrien    SocketAddress listen_address = address;
20278556Sobrien    if(!listen_address.IsLocalhost())
20378556Sobrien      listen_address.SetToAnyAddress(address.GetFamily(), port);
20478556Sobrien    else
20578556Sobrien      listen_address.SetPort(port);
20678556Sobrien
20778556Sobrien    int err =
20878556Sobrien        ::bind(fd, &listen_address.sockaddr(), listen_address.GetLength());
20978556Sobrien    if (-1 != err)
21078556Sobrien      err = ::listen(fd, backlog);
21178556Sobrien
21278556Sobrien    if (-1 == err) {
21378556Sobrien      CLOSE_SOCKET(fd);
21478556Sobrien      continue;
21578556Sobrien    }
21678556Sobrien
21778556Sobrien    if (port == 0) {
21878556Sobrien      socklen_t sa_len = address.GetLength();
21978556Sobrien      if (getsockname(fd, &address.sockaddr(), &sa_len) == 0)
22078556Sobrien        port = address.GetPort();
22178556Sobrien    }
22278556Sobrien    m_listen_sockets[fd] = address;
22378556Sobrien  }
22478556Sobrien
22578556Sobrien  if (m_listen_sockets.size() == 0)
22678556Sobrien    error.SetErrorString("Failed to connect port");
22778556Sobrien  return error;
22878556Sobrien}
22978556Sobrien
23078556Sobrienvoid TCPSocket::CloseListenSockets() {
23178556Sobrien  for (auto socket : m_listen_sockets)
23278556Sobrien  CLOSE_SOCKET(socket.first);
23378556Sobrien  m_listen_sockets.clear();
23478556Sobrien}
23578556Sobrien
23678556SobrienStatus TCPSocket::Accept(Socket *&conn_socket) {
23778556Sobrien  Status error;
23878556Sobrien  if (m_listen_sockets.size() == 0) {
23978556Sobrien    error.SetErrorString("No open listening sockets!");
24078556Sobrien    return error;
24178556Sobrien  }
24278556Sobrien
24378556Sobrien  int sock = -1;
24478556Sobrien  int listen_sock = -1;
24578556Sobrien  lldb_private::SocketAddress AcceptAddr;
24678556Sobrien  MainLoop accept_loop;
24778556Sobrien  std::vector<MainLoopBase::ReadHandleUP> handles;
24878556Sobrien  for (auto socket : m_listen_sockets) {
24978556Sobrien    auto fd = socket.first;
25078556Sobrien    auto inherit = this->m_child_processes_inherit;
25178556Sobrien    auto io_sp = IOObjectSP(new TCPSocket(socket.first, false, inherit));
25278556Sobrien    handles.emplace_back(accept_loop.RegisterReadObject(
25378556Sobrien        io_sp, [fd, inherit, &sock, &AcceptAddr, &error,
25478556Sobrien                        &listen_sock](MainLoopBase &loop) {
25578556Sobrien          socklen_t sa_len = AcceptAddr.GetMaxLength();
25678556Sobrien          sock = AcceptSocket(fd, &AcceptAddr.sockaddr(), &sa_len, inherit,
25778556Sobrien                              error);
25878556Sobrien          listen_sock = fd;
25978556Sobrien          loop.RequestTermination();
26078556Sobrien        }, error));
26178556Sobrien    if (error.Fail())
26278556Sobrien      return error;
26378556Sobrien  }
26478556Sobrien
26578556Sobrien  bool accept_connection = false;
26678556Sobrien  std::unique_ptr<TCPSocket> accepted_socket;
26778556Sobrien  // Loop until we are happy with our connection
26878556Sobrien  while (!accept_connection) {
26978556Sobrien    accept_loop.Run();
27078556Sobrien
27178556Sobrien    if (error.Fail())
27278556Sobrien        return error;
27378556Sobrien
27478556Sobrien    lldb_private::SocketAddress &AddrIn = m_listen_sockets[listen_sock];
27578556Sobrien    if (!AddrIn.IsAnyAddr() && AcceptAddr != AddrIn) {
27678556Sobrien      CLOSE_SOCKET(sock);
27778556Sobrien      llvm::errs() << llvm::formatv(
27878556Sobrien          "error: rejecting incoming connection from {0} (expecting {1})",
27978556Sobrien          AcceptAddr.GetIPAddress(), AddrIn.GetIPAddress());
28078556Sobrien      continue;
28178556Sobrien    }
28278556Sobrien    accept_connection = true;
28378556Sobrien    accepted_socket.reset(new TCPSocket(sock, *this));
28478556Sobrien  }
28578556Sobrien
28678556Sobrien  if (!accepted_socket)
28778556Sobrien    return error;
28878556Sobrien
28978556Sobrien  // Keep our TCP packets coming without any delays.
29078556Sobrien  accepted_socket->SetOptionNoDelay();
29178556Sobrien  error.Clear();
29278556Sobrien  conn_socket = accepted_socket.release();
29378556Sobrien  return error;
29478556Sobrien}
29578556Sobrien
29678556Sobrienint TCPSocket::SetOptionNoDelay() {
29778556Sobrien  return SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
29878556Sobrien}
29978556Sobrien
30078556Sobrienint TCPSocket::SetOptionReuseAddress() {
30178556Sobrien  return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
30278556Sobrien}
30378556Sobrien