10b57cec5SDimitry Andric //===-- Acceptor.cpp --------------------------------------------*- C++ -*-===//
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 "Acceptor.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
120b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h"
150b57cec5SDimitry Andric #include "lldb/Host/common/TCPSocket.h"
160b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
170b57cec5SDimitry Andric #include "lldb/Utility/UriParser.h"
18*bdd1243dSDimitry Andric #include <optional>
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace lldb;
210b57cec5SDimitry Andric using namespace lldb_private;
220b57cec5SDimitry Andric using namespace lldb_private::lldb_server;
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric namespace {
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric struct SocketScheme {
280b57cec5SDimitry Andric const char *m_scheme;
290b57cec5SDimitry Andric const Socket::SocketProtocol m_protocol;
300b57cec5SDimitry Andric };
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric SocketScheme socket_schemes[] = {
330b57cec5SDimitry Andric {"tcp", Socket::ProtocolTcp},
340b57cec5SDimitry Andric {"udp", Socket::ProtocolUdp},
350b57cec5SDimitry Andric {"unix", Socket::ProtocolUnixDomain},
360b57cec5SDimitry Andric {"unix-abstract", Socket::ProtocolUnixAbstract},
370b57cec5SDimitry Andric };
380b57cec5SDimitry Andric
FindProtocolByScheme(const char * scheme,Socket::SocketProtocol & protocol)390b57cec5SDimitry Andric bool FindProtocolByScheme(const char *scheme,
400b57cec5SDimitry Andric Socket::SocketProtocol &protocol) {
410b57cec5SDimitry Andric for (auto s : socket_schemes) {
420b57cec5SDimitry Andric if (!strcmp(s.m_scheme, scheme)) {
430b57cec5SDimitry Andric protocol = s.m_protocol;
440b57cec5SDimitry Andric return true;
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric return false;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
FindSchemeByProtocol(const Socket::SocketProtocol protocol)500b57cec5SDimitry Andric const char *FindSchemeByProtocol(const Socket::SocketProtocol protocol) {
510b57cec5SDimitry Andric for (auto s : socket_schemes) {
520b57cec5SDimitry Andric if (s.m_protocol == protocol)
530b57cec5SDimitry Andric return s.m_scheme;
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric return nullptr;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric
Listen(int backlog)590b57cec5SDimitry Andric Status Acceptor::Listen(int backlog) {
600b57cec5SDimitry Andric return m_listener_socket_up->Listen(StringRef(m_name), backlog);
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
Accept(const bool child_processes_inherit,Connection * & conn)630b57cec5SDimitry Andric Status Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) {
640b57cec5SDimitry Andric Socket *conn_socket = nullptr;
650b57cec5SDimitry Andric auto error = m_listener_socket_up->Accept(conn_socket);
660b57cec5SDimitry Andric if (error.Success())
670b57cec5SDimitry Andric conn = new ConnectionFileDescriptor(conn_socket);
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric return error;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric
GetSocketProtocol() const720b57cec5SDimitry Andric Socket::SocketProtocol Acceptor::GetSocketProtocol() const {
730b57cec5SDimitry Andric return m_listener_socket_up->GetSocketProtocol();
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric
GetSocketScheme() const760b57cec5SDimitry Andric const char *Acceptor::GetSocketScheme() const {
770b57cec5SDimitry Andric return FindSchemeByProtocol(GetSocketProtocol());
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric
GetLocalSocketId() const800b57cec5SDimitry Andric std::string Acceptor::GetLocalSocketId() const { return m_local_socket_id(); }
810b57cec5SDimitry Andric
Create(StringRef name,const bool child_processes_inherit,Status & error)820b57cec5SDimitry Andric std::unique_ptr<Acceptor> Acceptor::Create(StringRef name,
830b57cec5SDimitry Andric const bool child_processes_inherit,
840b57cec5SDimitry Andric Status &error) {
850b57cec5SDimitry Andric error.Clear();
860b57cec5SDimitry Andric
870b57cec5SDimitry Andric Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain;
880b57cec5SDimitry Andric // Try to match socket name as URL - e.g., tcp://localhost:5555
89*bdd1243dSDimitry Andric if (std::optional<URI> res = URI::Parse(name)) {
90349cc55cSDimitry Andric if (!FindProtocolByScheme(res->scheme.str().c_str(), socket_protocol))
910b57cec5SDimitry Andric error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"",
92349cc55cSDimitry Andric res->scheme.str().c_str());
930b57cec5SDimitry Andric else
94349cc55cSDimitry Andric name = name.drop_front(res->scheme.size() + strlen("://"));
950b57cec5SDimitry Andric } else {
960b57cec5SDimitry Andric // Try to match socket name as $host:port - e.g., localhost:5555
97349cc55cSDimitry Andric if (!llvm::errorToBool(Socket::DecodeHostAndPort(name).takeError()))
980b57cec5SDimitry Andric socket_protocol = Socket::ProtocolTcp;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric if (error.Fail())
1020b57cec5SDimitry Andric return std::unique_ptr<Acceptor>();
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric std::unique_ptr<Socket> listener_socket_up =
1050b57cec5SDimitry Andric Socket::Create(socket_protocol, child_processes_inherit, error);
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric LocalSocketIdFunc local_socket_id;
1080b57cec5SDimitry Andric if (error.Success()) {
1090b57cec5SDimitry Andric if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp) {
1100b57cec5SDimitry Andric TCPSocket *tcp_socket =
1110b57cec5SDimitry Andric static_cast<TCPSocket *>(listener_socket_up.get());
1120b57cec5SDimitry Andric local_socket_id = [tcp_socket]() {
1130b57cec5SDimitry Andric auto local_port = tcp_socket->GetLocalPortNumber();
1140b57cec5SDimitry Andric return (local_port != 0) ? llvm::to_string(local_port) : "";
1150b57cec5SDimitry Andric };
1160b57cec5SDimitry Andric } else {
1175ffd83dbSDimitry Andric const std::string socket_name = std::string(name);
1180b57cec5SDimitry Andric local_socket_id = [socket_name]() { return socket_name; };
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric return std::unique_ptr<Acceptor>(
1220b57cec5SDimitry Andric new Acceptor(std::move(listener_socket_up), name, local_socket_id));
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric return std::unique_ptr<Acceptor>();
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric
Acceptor(std::unique_ptr<Socket> && listener_socket,StringRef name,const LocalSocketIdFunc & local_socket_id)1280b57cec5SDimitry Andric Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket, StringRef name,
1290b57cec5SDimitry Andric const LocalSocketIdFunc &local_socket_id)
1300b57cec5SDimitry Andric : m_listener_socket_up(std::move(listener_socket)), m_name(name.str()),
1310b57cec5SDimitry Andric m_local_socket_id(local_socket_id) {}
132