blob: 634319594853aaf1fbf091c0a5a6d7638ac17044 [file] [log] [blame]
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +00001//===-- 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
14#include "lldb/Core/StreamString.h"
15#include "lldb/Host/ConnectionFileDescriptor.h"
16#include "lldb/Host/common/TCPSocket.h"
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +000017
18#include "Utility/UriParser.h"
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000019
20using namespace lldb;
21using namespace lldb_private;
22using namespace lldb_private::lldb_server;
23using namespace llvm;
24
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +000025namespace {
26
27struct SocketScheme
28{
29 const char* m_scheme;
30 const Socket::SocketProtocol m_protocol;
31};
32
33SocketScheme socket_schemes[] = {
34 {"tcp", Socket::ProtocolTcp},
35 {"udp", Socket::ProtocolUdp},
36 {"unix", Socket::ProtocolUnixDomain},
37 {"unix-abstract", Socket::ProtocolUnixAbstract},
38};
39
Oleksiy Vyalov14857122015-10-28 19:49:50 +000040bool
41FindProtocolByScheme(const char* scheme, Socket::SocketProtocol& protocol)
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +000042{
43 for (auto s: socket_schemes)
44 {
45 if (!strcmp(s.m_scheme, scheme))
46 {
47 protocol = s.m_protocol;
48 return true;
49 }
50 }
51 return false;
52}
53
Oleksiy Vyalov14857122015-10-28 19:49:50 +000054const char*
55FindSchemeByProtocol(const Socket::SocketProtocol protocol)
56{
57 for (auto s: socket_schemes)
58 {
59 if (s.m_protocol == protocol)
60 return s.m_scheme;
61 }
62 return nullptr;
63}
64
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +000065}
66
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000067Error
68Acceptor::Listen(int backlog)
69{
70 return m_listener_socket_up->Listen(StringRef(m_name.c_str()),
71 backlog);
72}
73
74Error
75Acceptor::Accept(const bool child_processes_inherit, Connection *&conn)
76{
77 Socket* conn_socket = nullptr;
78 auto error = m_listener_socket_up->Accept(StringRef(m_name.c_str()),
79 child_processes_inherit,
80 conn_socket);
81 if (error.Success())
82 conn = new ConnectionFileDescriptor(conn_socket);
83
84 return error;
85}
86
87Socket::SocketProtocol
88Acceptor::GetSocketProtocol() const
89{
90 return m_listener_socket_up->GetSocketProtocol();
91}
92
Oleksiy Vyalov14857122015-10-28 19:49:50 +000093const char*
94Acceptor::GetSocketScheme() const
95{
96 return FindSchemeByProtocol(GetSocketProtocol());
97}
98
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +000099std::string
100Acceptor::GetLocalSocketId() const
101{
102 return m_local_socket_id();
103}
104
105std::unique_ptr<Acceptor>
106Acceptor::Create(StringRef name, const bool child_processes_inherit, Error &error)
107{
108 error.Clear();
109
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +0000110 Socket::SocketProtocol socket_protocol = Socket::ProtocolUnixDomain;
111 int port;
112 std::string scheme, host, path;
113 // Try to match socket name as URL - e.g., tcp://localhost:5555
114 if (UriParser::Parse(name.str(), scheme, host, port, path))
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000115 {
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +0000116 if (!FindProtocolByScheme(scheme.c_str(), socket_protocol))
117 error.SetErrorStringWithFormat("Unknown protocol scheme \"%s\"", scheme.c_str());
118 else
119 name = name.drop_front(scheme.size() + strlen("://"));
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000120 }
121 else
122 {
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +0000123 std::string host_str;
124 std::string port_str;
125 int32_t port = INT32_MIN;
126 // Try to match socket name as $host:port - e.g., localhost:5555
127 if (Socket::DecodeHostAndPort (name, host_str, port_str, port, nullptr))
128 socket_protocol = Socket::ProtocolTcp;
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000129 }
130
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +0000131 if (error.Fail())
132 return std::unique_ptr<Acceptor>();
133
134 std::unique_ptr<Socket> listener_socket_up = Socket::Create(
135 socket_protocol, child_processes_inherit, error);
136
137 LocalSocketIdFunc local_socket_id;
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000138 if (error.Success())
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +0000139 {
140 if (listener_socket_up->GetSocketProtocol() == Socket::ProtocolTcp)
141 {
142 TCPSocket* tcp_socket = static_cast<TCPSocket*>(listener_socket_up.get());
143 local_socket_id = [tcp_socket]() {
144 auto local_port = tcp_socket->GetLocalPortNumber();
145 return (local_port != 0) ? std::to_string(local_port) : "";
146 };
147 }
148 else
149 {
150 const std::string socket_name = name;
151 local_socket_id = [socket_name](){
152 return socket_name;
153 };
154 }
155
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000156 return std::unique_ptr<Acceptor>(
Oleksiy Vyalovdb4d9862015-10-27 17:32:01 +0000157 new Acceptor(std::move(listener_socket_up), name, local_socket_id));
158 }
Oleksiy Vyalov9fe526c2015-10-21 19:34:26 +0000159
160 return std::unique_ptr<Acceptor>();
161}
162
163Acceptor::Acceptor(std::unique_ptr<Socket> &&listener_socket,
164 StringRef name,
165 const LocalSocketIdFunc &local_socket_id)
166 : m_listener_socket_up(std::move(listener_socket)),
167 m_name(name.str()),
168 m_local_socket_id(local_socket_id)
169{
170}