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