1061da546Spatrick //===-- Acceptor.cpp --------------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "Acceptor.h"
10061da546Spatrick
11061da546Spatrick #include "llvm/ADT/StringRef.h"
12061da546Spatrick #include "llvm/Support/ScopedPrinter.h"
13061da546Spatrick
14061da546Spatrick #include "lldb/Host/ConnectionFileDescriptor.h"
15061da546Spatrick #include "lldb/Host/common/TCPSocket.h"
16061da546Spatrick #include "lldb/Utility/StreamString.h"
17061da546Spatrick #include "lldb/Utility/UriParser.h"
18*f6aab3d8Srobert #include <optional>
19061da546Spatrick
20061da546Spatrick using namespace lldb;
21061da546Spatrick using namespace lldb_private;
22061da546Spatrick using namespace lldb_private::lldb_server;
23061da546Spatrick using namespace llvm;
24061da546Spatrick
25061da546Spatrick namespace {
26061da546Spatrick
27061da546Spatrick struct SocketScheme {
28061da546Spatrick const char *m_scheme;
29061da546Spatrick const Socket::SocketProtocol m_protocol;
30061da546Spatrick };
31061da546Spatrick
32061da546Spatrick SocketScheme socket_schemes[] = {
33061da546Spatrick {"tcp", Socket::ProtocolTcp},
34061da546Spatrick {"udp", Socket::ProtocolUdp},
35061da546Spatrick {"unix", Socket::ProtocolUnixDomain},
36061da546Spatrick {"unix-abstract", Socket::ProtocolUnixAbstract},
37061da546Spatrick };
38061da546Spatrick
FindProtocolByScheme(const char * scheme,Socket::SocketProtocol & protocol)39061da546Spatrick bool FindProtocolByScheme(const char *scheme,
40061da546Spatrick Socket::SocketProtocol &protocol) {
41061da546Spatrick for (auto s : socket_schemes) {
42061da546Spatrick if (!strcmp(s.m_scheme, scheme)) {
43061da546Spatrick protocol = s.m_protocol;
44061da546Spatrick return true;
45061da546Spatrick }
46061da546Spatrick }
47061da546Spatrick return false;
48061da546Spatrick }
49061da546Spatrick
FindSchemeByProtocol(const Socket::SocketProtocol protocol)50061da546Spatrick const char *FindSchemeByProtocol(const Socket::SocketProtocol protocol) {
51061da546Spatrick for (auto s : socket_schemes) {
52061da546Spatrick if (s.m_protocol == protocol)
53061da546Spatrick return s.m_scheme;
54061da546Spatrick }
55061da546Spatrick return nullptr;
56061da546Spatrick }
57061da546Spatrick }
58061da546Spatrick
Listen(int backlog)59061da546Spatrick Status Acceptor::Listen(int backlog) {
60061da546Spatrick return m_listener_socket_up->Listen(StringRef(m_name), backlog);
61061da546Spatrick }
62061da546Spatrick
Accept(const bool child_processes_inherit,Connection * & conn)63061da546Spatrick Status Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) {
64061da546Spatrick Socket *conn_socket = nullptr;
65061da546Spatrick auto error = m_listener_socket_up->Accept(conn_socket);
66061da546Spatrick if (error.Success())
67061da546Spatrick conn = new ConnectionFileDescriptor(conn_socket);
68061da546Spatrick
69061da546Spatrick return error;
70061da546Spatrick }
71061da546Spatrick
GetSocketProtocol() const72061da546Spatrick Socket::SocketProtocol Acceptor::GetSocketProtocol() const {
73061da546Spatrick return m_listener_socket_up->GetSocketProtocol();
74061da546Spatrick }
75061da546Spatrick
GetSocketScheme() const76061da546Spatrick const char *Acceptor::GetSocketScheme() const {
77061da546Spatrick return FindSchemeByProtocol(GetSocketProtocol());
78061da546Spatrick }
79061da546Spatrick
GetLocalSocketId() const80061da546Spatrick std::string Acceptor::GetLocalSocketId() const { return m_local_socket_id(); }
81061da546Spatrick
Create(StringRef name,const bool child_processes_inherit,Status & error)82061da546Spatrick std::unique_ptr<Acceptor> Acceptor::Create(StringRef name,
83061da546Spatrick const bool child_processes_inherit,
84061da546Spatrick Status &error) {
85061da546Spatrick error.Clear();
86061da546Spatrick
87061da546Spatrick Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain;
88061da546Spatrick // Try to match socket name as URL - e.g., tcp://localhost:5555
89*f6aab3d8Srobert if (std::optional<URI> res = URI::Parse(name)) {
90*f6aab3d8Srobert if (!FindProtocolByScheme(res->scheme.str().c_str(), socket_protocol))
91061da546Spatrick error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"",
92*f6aab3d8Srobert res->scheme.str().c_str());
93061da546Spatrick else
94*f6aab3d8Srobert name = name.drop_front(res->scheme.size() + strlen("://"));
95061da546Spatrick } else {
96061da546Spatrick // Try to match socket name as $host:port - e.g., localhost:5555
97*f6aab3d8Srobert if (!llvm::errorToBool(Socket::DecodeHostAndPort(name).takeError()))
98061da546Spatrick socket_protocol = Socket::ProtocolTcp;
99061da546Spatrick }
100061da546Spatrick
101061da546Spatrick if (error.Fail())
102061da546Spatrick return std::unique_ptr<Acceptor>();
103061da546Spatrick
104061da546Spatrick std::unique_ptr<Socket> listener_socket_up =
105061da546Spatrick Socket::Create(socket_protocol, child_processes_inherit, error);
106061da546Spatrick
107061da546Spatrick LocalSocketIdFunc local_socket_id;
108061da546Spatrick if (error.Success()) {
109061da546Spatrick if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp) {
110061da546Spatrick TCPSocket *tcp_socket =
111061da546Spatrick static_cast<TCPSocket *>(listener_socket_up.get());
112061da546Spatrick local_socket_id = [tcp_socket]() {
113061da546Spatrick auto local_port = tcp_socket->GetLocalPortNumber();
114061da546Spatrick return (local_port != 0) ? llvm::to_string(local_port) : "";
115061da546Spatrick };
116061da546Spatrick } else {
117dda28197Spatrick const std::string socket_name = std::string(name);
118061da546Spatrick local_socket_id = [socket_name]() { return socket_name; };
119061da546Spatrick }
120061da546Spatrick
121061da546Spatrick return std::unique_ptr<Acceptor>(
122061da546Spatrick new Acceptor(std::move(listener_socket_up), name, local_socket_id));
123061da546Spatrick }
124061da546Spatrick
125061da546Spatrick return std::unique_ptr<Acceptor>();
126061da546Spatrick }
127061da546Spatrick
Acceptor(std::unique_ptr<Socket> && listener_socket,StringRef name,const LocalSocketIdFunc & local_socket_id)128061da546Spatrick Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket, StringRef name,
129061da546Spatrick const LocalSocketIdFunc &local_socket_id)
130061da546Spatrick : m_listener_socket_up(std::move(listener_socket)), m_name(name.str()),
131061da546Spatrick m_local_socket_id(local_socket_id) {}
132