| //===-- Acceptor.cpp --------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Acceptor.h" |
| |
| #include "llvm/ADT/StringRef.h" |
| |
| #include "lldb/Core/StreamString.h" |
| #include "lldb/Host/ConnectionFileDescriptor.h" |
| #include "lldb/Host/common/TCPSocket.h" |
| |
| #include "Utility/UriParser.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| using namespace lldb_private::lldb_server; |
| using namespace llvm; |
| |
| namespace { |
| |
| struct SocketScheme |
| { |
| const char* m_scheme; |
| const Socket::SocketProtocol m_protocol; |
| }; |
| |
| SocketScheme socket_schemes[] = { |
| {"tcp", Socket::ProtocolTcp}, |
| {"udp", Socket::ProtocolUdp}, |
| {"unix", Socket::ProtocolUnixDomain}, |
| {"unix-abstract", Socket::ProtocolUnixAbstract}, |
| }; |
| |
| bool |
| FindProtocolByScheme(const char* scheme, Socket::SocketProtocol& protocol) |
| { |
| for (auto s: socket_schemes) |
| { |
| if (!strcmp(s.m_scheme, scheme)) |
| { |
| protocol = s.m_protocol; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| const char* |
| FindSchemeByProtocol(const Socket::SocketProtocol protocol) |
| { |
| for (auto s: socket_schemes) |
| { |
| if (s.m_protocol == protocol) |
| return s.m_scheme; |
| } |
| return nullptr; |
| } |
| |
| } |
| |
| Error |
| Acceptor::Listen(int backlog) |
| { |
| return m_listener_socket_up->Listen(StringRef(m_name.c_str()), |
| backlog); |
| } |
| |
| Error |
| Acceptor::Accept(const bool child_processes_inherit, Connection *&conn) |
| { |
| Socket* conn_socket = nullptr; |
| auto error = m_listener_socket_up->Accept(StringRef(m_name.c_str()), |
| child_processes_inherit, |
| conn_socket); |
| if (error.Success()) |
| conn = new ConnectionFileDescriptor(conn_socket); |
| |
| return error; |
| } |
| |
| Socket::SocketProtocol |
| Acceptor::GetSocketProtocol() const |
| { |
| return m_listener_socket_up->GetSocketProtocol(); |
| } |
| |
| const char* |
| Acceptor::GetSocketScheme() const |
| { |
| return FindSchemeByProtocol(GetSocketProtocol()); |
| } |
| |
| std::string |
| Acceptor::GetLocalSocketId() const |
| { |
| return m_local_socket_id(); |
| } |
| |
| std::unique_ptr<Acceptor> |
| Acceptor::Create(StringRef name, const bool child_processes_inherit, Error &error) |
| { |
| error.Clear(); |
| |
| Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain; |
| int port; |
| std::string scheme, host, path; |
| // Try to match socket name as URL - e.g., tcp://localhost:5555 |
| if (UriParser::Parse(name.str(), scheme, host, port, path)) |
| { |
| if (!FindProtocolByScheme(scheme.c_str(), socket_protocol)) |
| error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"", scheme.c_str()); |
| else |
| name = name.drop_front(scheme.size() + strlen("://")); |
| } |
| else |
| { |
| std::string host_str; |
| std::string port_str; |
| int32_t port = INT32_MIN; |
| // Try to match socket name as $host:port - e.g., localhost:5555 |
| if (Socket::DecodeHostAndPort (name, host_str, port_str, port, nullptr)) |
| socket_protocol = Socket::ProtocolTcp; |
| } |
| |
| if (error.Fail()) |
| return std::unique_ptr<Acceptor>(); |
| |
| std::unique_ptr<Socket> listener_socket_up = Socket::Create( |
| socket_protocol, child_processes_inherit, error); |
| |
| LocalSocketIdFunc local_socket_id; |
| if (error.Success()) |
| { |
| if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp) |
| { |
| TCPSocket* tcp_socket = static_cast<TCPSocket*>(listener_socket_up.get()); |
| local_socket_id = [tcp_socket]() { |
| auto local_port = tcp_socket->GetLocalPortNumber(); |
| return (local_port != 0) ? std::to_string(local_port) : ""; |
| }; |
| } |
| else |
| { |
| const std::string socket_name = name; |
| local_socket_id = [socket_name](){ |
| return socket_name; |
| }; |
| } |
| |
| return std::unique_ptr<Acceptor>( |
| new Acceptor(std::move(listener_socket_up), name, local_socket_id)); |
| } |
| |
| return std::unique_ptr<Acceptor>(); |
| } |
| |
| Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket, |
| StringRef name, |
| const LocalSocketIdFunc &local_socket_id) |
| : m_listener_socket_up(std::move(listener_socket)), |
| m_name(name.str()), |
| m_local_socket_id(local_socket_id) |
| { |
| } |