1 //===-- UDPSocket.cpp -----------------------------------------------------===// 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 #include "lldb/Host/common/UDPSocket.h" 10 11 #include "lldb/Host/Config.h" 12 #include "lldb/Utility/Log.h" 13 14 #if LLDB_ENABLE_POSIX 15 #include <arpa/inet.h> 16 #include <sys/socket.h> 17 #endif 18 19 #include <memory> 20 21 using namespace lldb; 22 using namespace lldb_private; 23 24 static const int kDomain = AF_INET; 25 static const int kType = SOCK_DGRAM; 26 27 static const char *g_not_supported_error = "Not supported"; 28 29 UDPSocket::UDPSocket(NativeSocket socket) : Socket(ProtocolUdp, true, true) { 30 m_socket = socket; 31 } 32 33 UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit) 34 : Socket(ProtocolUdp, should_close, child_processes_inherit) {} 35 36 size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { 37 return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0, 38 m_sockaddr, m_sockaddr.GetLength()); 39 } 40 41 Status UDPSocket::Connect(llvm::StringRef name) { 42 return Status("%s", g_not_supported_error); 43 } 44 45 Status UDPSocket::Listen(llvm::StringRef name, int backlog) { 46 return Status("%s", g_not_supported_error); 47 } 48 49 Status UDPSocket::Accept(Socket *&socket) { 50 return Status("%s", g_not_supported_error); 51 } 52 53 llvm::Expected<std::unique_ptr<UDPSocket>> 54 UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit) { 55 std::unique_ptr<UDPSocket> socket; 56 57 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); 58 LLDB_LOG(log, "host/port = {0}", name); 59 60 Status error; 61 llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name); 62 if (!host_port) 63 return host_port.takeError(); 64 65 // At this point we have setup the receive port, now we need to setup the UDP 66 // send socket 67 68 struct addrinfo hints; 69 struct addrinfo *service_info_list = nullptr; 70 71 ::memset(&hints, 0, sizeof(hints)); 72 hints.ai_family = kDomain; 73 hints.ai_socktype = kType; 74 int err = ::getaddrinfo(host_port->hostname.c_str(), std::to_string(host_port->port).c_str(), &hints, 75 &service_info_list); 76 if (err != 0) { 77 error.SetErrorStringWithFormat( 78 #if defined(_WIN32) && defined(UNICODE) 79 "getaddrinfo(%s, %d, &hints, &info) returned error %i (%S)", 80 #else 81 "getaddrinfo(%s, %d, &hints, &info) returned error %i (%s)", 82 #endif 83 host_port->hostname.c_str(), host_port->port, err, gai_strerror(err)); 84 return error.ToError(); 85 } 86 87 for (struct addrinfo *service_info_ptr = service_info_list; 88 service_info_ptr != nullptr; 89 service_info_ptr = service_info_ptr->ai_next) { 90 auto send_fd = CreateSocket( 91 service_info_ptr->ai_family, service_info_ptr->ai_socktype, 92 service_info_ptr->ai_protocol, child_processes_inherit, error); 93 if (error.Success()) { 94 socket.reset(new UDPSocket(send_fd)); 95 socket->m_sockaddr = service_info_ptr; 96 break; 97 } else 98 continue; 99 } 100 101 ::freeaddrinfo(service_info_list); 102 103 if (!socket) 104 return error.ToError(); 105 106 SocketAddress bind_addr; 107 108 // Only bind to the loopback address if we are expecting a connection from 109 // localhost to avoid any firewall issues. 110 const bool bind_addr_success = (host_port->hostname == "127.0.0.1" || host_port->hostname == "localhost") 111 ? bind_addr.SetToLocalhost(kDomain, host_port->port) 112 : bind_addr.SetToAnyAddress(kDomain, host_port->port); 113 114 if (!bind_addr_success) { 115 error.SetErrorString("Failed to get hostspec to bind for"); 116 return error.ToError(); 117 } 118 119 bind_addr.SetPort(0); // Let the source port # be determined dynamically 120 121 err = ::bind(socket->GetNativeSocket(), bind_addr, bind_addr.GetLength()); 122 123 struct sockaddr_in source_info; 124 socklen_t address_len = sizeof (struct sockaddr_in); 125 err = ::getsockname(socket->GetNativeSocket(), 126 (struct sockaddr *)&source_info, &address_len); 127 128 return std::move(socket); 129 } 130 131 std::string UDPSocket::GetRemoteConnectionURI() const { 132 if (m_socket != kInvalidSocketValue) { 133 return std::string(llvm::formatv( 134 "udp://[{0}]:{1}", m_sockaddr.GetIPAddress(), m_sockaddr.GetPort())); 135 } 136 return ""; 137 } 138