1 //===-- Acceptor.cpp --------------------------------------------*- C++ -*-===// 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 "Acceptor.h" 10 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/Support/ScopedPrinter.h" 13 14 #include "lldb/Host/ConnectionFileDescriptor.h" 15 #include "lldb/Host/common/TCPSocket.h" 16 #include "lldb/Utility/StreamString.h" 17 #include "lldb/Utility/UriParser.h" 18 19 using namespace lldb; 20 using namespace lldb_private; 21 using namespace lldb_private::lldb_server; 22 using namespace llvm; 23 24 namespace { 25 26 struct SocketScheme { 27 const char *m_scheme; 28 const Socket::SocketProtocol m_protocol; 29 }; 30 31 SocketScheme socket_schemes[] = { 32 {"tcp", Socket::ProtocolTcp}, 33 {"udp", Socket::ProtocolUdp}, 34 {"unix", Socket::ProtocolUnixDomain}, 35 {"unix-abstract", Socket::ProtocolUnixAbstract}, 36 }; 37 38 bool FindProtocolByScheme(const char *scheme, 39 Socket::SocketProtocol &protocol) { 40 for (auto s : socket_schemes) { 41 if (!strcmp(s.m_scheme, scheme)) { 42 protocol = s.m_protocol; 43 return true; 44 } 45 } 46 return false; 47 } 48 49 const char *FindSchemeByProtocol(const Socket::SocketProtocol protocol) { 50 for (auto s : socket_schemes) { 51 if (s.m_protocol == protocol) 52 return s.m_scheme; 53 } 54 return nullptr; 55 } 56 } 57 58 Status Acceptor::Listen(int backlog) { 59 return m_listener_socket_up->Listen(StringRef(m_name), backlog); 60 } 61 62 Status Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) { 63 Socket *conn_socket = nullptr; 64 auto error = m_listener_socket_up->Accept(conn_socket); 65 if (error.Success()) 66 conn = new ConnectionFileDescriptor(conn_socket); 67 68 return error; 69 } 70 71 Socket::SocketProtocol Acceptor::GetSocketProtocol() const { 72 return m_listener_socket_up->GetSocketProtocol(); 73 } 74 75 const char *Acceptor::GetSocketScheme() const { 76 return FindSchemeByProtocol(GetSocketProtocol()); 77 } 78 79 std::string Acceptor::GetLocalSocketId() const { return m_local_socket_id(); } 80 81 std::unique_ptr<Acceptor> Acceptor::Create(StringRef name, 82 const bool child_processes_inherit, 83 Status &error) { 84 error.Clear(); 85 86 Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain; 87 int port; 88 StringRef scheme, host, path; 89 // Try to match socket name as URL - e.g., tcp://localhost:5555 90 if (UriParser::Parse(name, scheme, host, port, path)) { 91 if (!FindProtocolByScheme(scheme.str().c_str(), socket_protocol)) 92 error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"", 93 scheme.str().c_str()); 94 else 95 name = name.drop_front(scheme.size() + strlen("://")); 96 } else { 97 std::string host_str; 98 std::string port_str; 99 int32_t port = INT32_MIN; 100 // Try to match socket name as $host:port - e.g., localhost:5555 101 if (Socket::DecodeHostAndPort(name, host_str, port_str, port, nullptr)) 102 socket_protocol = Socket::ProtocolTcp; 103 } 104 105 if (error.Fail()) 106 return std::unique_ptr<Acceptor>(); 107 108 std::unique_ptr<Socket> listener_socket_up = 109 Socket::Create(socket_protocol, child_processes_inherit, error); 110 111 LocalSocketIdFunc local_socket_id; 112 if (error.Success()) { 113 if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp) { 114 TCPSocket *tcp_socket = 115 static_cast<TCPSocket *>(listener_socket_up.get()); 116 local_socket_id = [tcp_socket]() { 117 auto local_port = tcp_socket->GetLocalPortNumber(); 118 return (local_port != 0) ? llvm::to_string(local_port) : ""; 119 }; 120 } else { 121 const std::string socket_name = name; 122 local_socket_id = [socket_name]() { return socket_name; }; 123 } 124 125 return std::unique_ptr<Acceptor>( 126 new Acceptor(std::move(listener_socket_up), name, local_socket_id)); 127 } 128 129 return std::unique_ptr<Acceptor>(); 130 } 131 132 Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket, StringRef name, 133 const LocalSocketIdFunc &local_socket_id) 134 : m_listener_socket_up(std::move(listener_socket)), m_name(name.str()), 135 m_local_socket_id(local_socket_id) {} 136