diff options
Diffstat (limited to 'lldb/source/Host/common/UDPSocket.cpp')
| -rw-r--r-- | lldb/source/Host/common/UDPSocket.cpp | 143 | 
1 files changed, 143 insertions, 0 deletions
diff --git a/lldb/source/Host/common/UDPSocket.cpp b/lldb/source/Host/common/UDPSocket.cpp new file mode 100644 index 000000000000..7accbb651ba9 --- /dev/null +++ b/lldb/source/Host/common/UDPSocket.cpp @@ -0,0 +1,143 @@ +//===-- UDPSocket.cpp -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/common/UDPSocket.h" + +#include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" + +#ifndef LLDB_DISABLE_POSIX +#include <arpa/inet.h> +#include <sys/socket.h> +#endif + +#include <memory> + +using namespace lldb; +using namespace lldb_private; + +namespace { + +const int kDomain = AF_INET; +const int kType = SOCK_DGRAM; + +static const char *g_not_supported_error = "Not supported"; +} + +UDPSocket::UDPSocket(NativeSocket socket) : Socket(ProtocolUdp, true, true) { +  m_socket = socket; +} + +UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit) +    : Socket(ProtocolUdp, should_close, child_processes_inherit) {} + +size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { +  return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0, +                  m_sockaddr, m_sockaddr.GetLength()); +} + +Status UDPSocket::Connect(llvm::StringRef name) { +  return Status("%s", g_not_supported_error); +} + +Status UDPSocket::Listen(llvm::StringRef name, int backlog) { +  return Status("%s", g_not_supported_error); +} + +Status UDPSocket::Accept(Socket *&socket) { +  return Status("%s", g_not_supported_error); +} + +Status UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, +                          Socket *&socket) { +  std::unique_ptr<UDPSocket> final_socket; + +  Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); +  LLDB_LOGF(log, "UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); + +  Status error; +  std::string host_str; +  std::string port_str; +  int32_t port = INT32_MIN; +  if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) +    return error; + +  // At this point we have setup the receive port, now we need to setup the UDP +  // send socket + +  struct addrinfo hints; +  struct addrinfo *service_info_list = nullptr; + +  ::memset(&hints, 0, sizeof(hints)); +  hints.ai_family = kDomain; +  hints.ai_socktype = kType; +  int err = ::getaddrinfo(host_str.c_str(), port_str.c_str(), &hints, +                          &service_info_list); +  if (err != 0) { +    error.SetErrorStringWithFormat( +#if defined(_WIN32) && defined(UNICODE) +        "getaddrinfo(%s, %s, &hints, &info) returned error %i (%S)", +#else +        "getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", +#endif +        host_str.c_str(), port_str.c_str(), err, gai_strerror(err)); +    return error; +  } + +  for (struct addrinfo *service_info_ptr = service_info_list; +       service_info_ptr != nullptr; +       service_info_ptr = service_info_ptr->ai_next) { +    auto send_fd = CreateSocket( +        service_info_ptr->ai_family, service_info_ptr->ai_socktype, +        service_info_ptr->ai_protocol, child_processes_inherit, error); +    if (error.Success()) { +      final_socket.reset(new UDPSocket(send_fd)); +      final_socket->m_sockaddr = service_info_ptr; +      break; +    } else +      continue; +  } + +  ::freeaddrinfo(service_info_list); + +  if (!final_socket) +    return error; + +  SocketAddress bind_addr; + +  // Only bind to the loopback address if we are expecting a connection from +  // localhost to avoid any firewall issues. +  const bool bind_addr_success = (host_str == "127.0.0.1" || host_str == "localhost") +                                     ? bind_addr.SetToLocalhost(kDomain, port) +                                     : bind_addr.SetToAnyAddress(kDomain, port); + +  if (!bind_addr_success) { +    error.SetErrorString("Failed to get hostspec to bind for"); +    return error; +  } + +  bind_addr.SetPort(0); // Let the source port # be determined dynamically + +  err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength()); + +  struct sockaddr_in source_info; +  socklen_t address_len = sizeof (struct sockaddr_in); +  err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len); + +  socket = final_socket.release(); +  error.Clear(); +  return error; +} + +std::string UDPSocket::GetRemoteConnectionURI() const { +  if (m_socket != kInvalidSocketValue) { +    return llvm::formatv("udp://[{0}]:{1}", m_sockaddr.GetIPAddress(), +                         m_sockaddr.GetPort()); +  } +  return ""; +}  | 
