15ffd83dbSDimitry Andric //===-- UDPSocket.cpp -----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Host/common/UDPSocket.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Host/Config.h"
12*81ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
130b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
140b57cec5SDimitry Andric
15480093f4SDimitry Andric #if LLDB_ENABLE_POSIX
160b57cec5SDimitry Andric #include <arpa/inet.h>
170b57cec5SDimitry Andric #include <sys/socket.h>
180b57cec5SDimitry Andric #endif
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric #include <memory>
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric using namespace lldb;
230b57cec5SDimitry Andric using namespace lldb_private;
240b57cec5SDimitry Andric
25349cc55cSDimitry Andric static const int kDomain = AF_INET;
26349cc55cSDimitry Andric static const int kType = SOCK_DGRAM;
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric static const char *g_not_supported_error = "Not supported";
290b57cec5SDimitry Andric
UDPSocket(NativeSocket socket)300b57cec5SDimitry Andric UDPSocket::UDPSocket(NativeSocket socket) : Socket(ProtocolUdp, true, true) {
310b57cec5SDimitry Andric m_socket = socket;
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric
UDPSocket(bool should_close,bool child_processes_inherit)340b57cec5SDimitry Andric UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit)
350b57cec5SDimitry Andric : Socket(ProtocolUdp, should_close, child_processes_inherit) {}
360b57cec5SDimitry Andric
Send(const void * buf,const size_t num_bytes)370b57cec5SDimitry Andric size_t UDPSocket::Send(const void *buf, const size_t num_bytes) {
380b57cec5SDimitry Andric return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0,
390b57cec5SDimitry Andric m_sockaddr, m_sockaddr.GetLength());
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric
Connect(llvm::StringRef name)420b57cec5SDimitry Andric Status UDPSocket::Connect(llvm::StringRef name) {
430b57cec5SDimitry Andric return Status("%s", g_not_supported_error);
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric
Listen(llvm::StringRef name,int backlog)460b57cec5SDimitry Andric Status UDPSocket::Listen(llvm::StringRef name, int backlog) {
470b57cec5SDimitry Andric return Status("%s", g_not_supported_error);
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
Accept(Socket * & socket)500b57cec5SDimitry Andric Status UDPSocket::Accept(Socket *&socket) {
510b57cec5SDimitry Andric return Status("%s", g_not_supported_error);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
545ffd83dbSDimitry Andric llvm::Expected<std::unique_ptr<UDPSocket>>
Connect(llvm::StringRef name,bool child_processes_inherit)555ffd83dbSDimitry Andric UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit) {
565ffd83dbSDimitry Andric std::unique_ptr<UDPSocket> socket;
570b57cec5SDimitry Andric
58*81ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Connection);
595ffd83dbSDimitry Andric LLDB_LOG(log, "host/port = {0}", name);
600b57cec5SDimitry Andric
610b57cec5SDimitry Andric Status error;
62349cc55cSDimitry Andric llvm::Expected<HostAndPort> host_port = DecodeHostAndPort(name);
63349cc55cSDimitry Andric if (!host_port)
64349cc55cSDimitry Andric return host_port.takeError();
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric // At this point we have setup the receive port, now we need to setup the UDP
670b57cec5SDimitry Andric // send socket
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric struct addrinfo hints;
700b57cec5SDimitry Andric struct addrinfo *service_info_list = nullptr;
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric ::memset(&hints, 0, sizeof(hints));
730b57cec5SDimitry Andric hints.ai_family = kDomain;
740b57cec5SDimitry Andric hints.ai_socktype = kType;
75349cc55cSDimitry Andric int err = ::getaddrinfo(host_port->hostname.c_str(), std::to_string(host_port->port).c_str(), &hints,
760b57cec5SDimitry Andric &service_info_list);
770b57cec5SDimitry Andric if (err != 0) {
780b57cec5SDimitry Andric error.SetErrorStringWithFormat(
799dba64beSDimitry Andric #if defined(_WIN32) && defined(UNICODE)
80349cc55cSDimitry Andric "getaddrinfo(%s, %d, &hints, &info) returned error %i (%S)",
810b57cec5SDimitry Andric #else
82349cc55cSDimitry Andric "getaddrinfo(%s, %d, &hints, &info) returned error %i (%s)",
830b57cec5SDimitry Andric #endif
84349cc55cSDimitry Andric host_port->hostname.c_str(), host_port->port, err, gai_strerror(err));
855ffd83dbSDimitry Andric return error.ToError();
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric for (struct addrinfo *service_info_ptr = service_info_list;
890b57cec5SDimitry Andric service_info_ptr != nullptr;
900b57cec5SDimitry Andric service_info_ptr = service_info_ptr->ai_next) {
910b57cec5SDimitry Andric auto send_fd = CreateSocket(
920b57cec5SDimitry Andric service_info_ptr->ai_family, service_info_ptr->ai_socktype,
930b57cec5SDimitry Andric service_info_ptr->ai_protocol, child_processes_inherit, error);
940b57cec5SDimitry Andric if (error.Success()) {
955ffd83dbSDimitry Andric socket.reset(new UDPSocket(send_fd));
965ffd83dbSDimitry Andric socket->m_sockaddr = service_info_ptr;
970b57cec5SDimitry Andric break;
980b57cec5SDimitry Andric } else
990b57cec5SDimitry Andric continue;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric ::freeaddrinfo(service_info_list);
1030b57cec5SDimitry Andric
1045ffd83dbSDimitry Andric if (!socket)
1055ffd83dbSDimitry Andric return error.ToError();
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric SocketAddress bind_addr;
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric // Only bind to the loopback address if we are expecting a connection from
1100b57cec5SDimitry Andric // localhost to avoid any firewall issues.
111349cc55cSDimitry Andric const bool bind_addr_success = (host_port->hostname == "127.0.0.1" || host_port->hostname == "localhost")
112349cc55cSDimitry Andric ? bind_addr.SetToLocalhost(kDomain, host_port->port)
113349cc55cSDimitry Andric : bind_addr.SetToAnyAddress(kDomain, host_port->port);
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric if (!bind_addr_success) {
1160b57cec5SDimitry Andric error.SetErrorString("Failed to get hostspec to bind for");
1175ffd83dbSDimitry Andric return error.ToError();
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric bind_addr.SetPort(0); // Let the source port # be determined dynamically
1210b57cec5SDimitry Andric
1225ffd83dbSDimitry Andric err = ::bind(socket->GetNativeSocket(), bind_addr, bind_addr.GetLength());
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric struct sockaddr_in source_info;
1250b57cec5SDimitry Andric socklen_t address_len = sizeof (struct sockaddr_in);
1265ffd83dbSDimitry Andric err = ::getsockname(socket->GetNativeSocket(),
1275ffd83dbSDimitry Andric (struct sockaddr *)&source_info, &address_len);
1280b57cec5SDimitry Andric
1295ffd83dbSDimitry Andric return std::move(socket);
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric
GetRemoteConnectionURI() const1320b57cec5SDimitry Andric std::string UDPSocket::GetRemoteConnectionURI() const {
1330b57cec5SDimitry Andric if (m_socket != kInvalidSocketValue) {
1345ffd83dbSDimitry Andric return std::string(llvm::formatv(
1355ffd83dbSDimitry Andric "udp://[{0}]:{1}", m_sockaddr.GetIPAddress(), m_sockaddr.GetPort()));
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric return "";
1380b57cec5SDimitry Andric }
139