1 //===-- CommandObjectProtocolServer.cpp -----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "CommandObjectProtocolServer.h"
10 #include "lldb/Core/PluginManager.h"
11 #include "lldb/Core/ProtocolServer.h"
12 #include "lldb/Host/Socket.h"
13 #include "lldb/Interpreter/CommandInterpreter.h"
14 #include "lldb/Interpreter/CommandReturnObject.h"
15 #include "lldb/Utility/UriParser.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/Support/FormatAdapters.h"
18
19 using namespace llvm;
20 using namespace lldb;
21 using namespace lldb_private;
22
23 #define LLDB_OPTIONS_mcp
24 #include "CommandOptions.inc"
25
26 class CommandObjectProtocolServerStart : public CommandObjectParsed {
27 public:
CommandObjectProtocolServerStart(CommandInterpreter & interpreter)28 CommandObjectProtocolServerStart(CommandInterpreter &interpreter)
29 : CommandObjectParsed(interpreter, "protocol-server start",
30 "start protocol server",
31 "protocol-server start <protocol> <connection>") {
32 AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
33 AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);
34 }
35
36 ~CommandObjectProtocolServerStart() override = default;
37
38 protected:
DoExecute(Args & args,CommandReturnObject & result)39 void DoExecute(Args &args, CommandReturnObject &result) override {
40 if (args.GetArgumentCount() < 1) {
41 result.AppendError("no protocol specified");
42 return;
43 }
44
45 llvm::StringRef protocol = args.GetArgumentAtIndex(0);
46 ProtocolServer *server = ProtocolServer::GetOrCreate(protocol);
47 if (!server) {
48 result.AppendErrorWithFormatv(
49 "unsupported protocol: {0}. Supported protocols are: {1}", protocol,
50 llvm::join(ProtocolServer::GetSupportedProtocols(), ", "));
51 return;
52 }
53
54 if (args.GetArgumentCount() < 2) {
55 result.AppendError("no connection specified");
56 return;
57 }
58 llvm::StringRef connection_uri = args.GetArgumentAtIndex(1);
59
60 const char *connection_error =
61 "unsupported connection specifier, expected 'accept:///path' or "
62 "'listen://[host]:port', got '{0}'.";
63 auto uri = lldb_private::URI::Parse(connection_uri);
64 if (!uri) {
65 result.AppendErrorWithFormatv(connection_error, connection_uri);
66 return;
67 }
68
69 std::optional<Socket::ProtocolModePair> protocol_and_mode =
70 Socket::GetProtocolAndMode(uri->scheme);
71 if (!protocol_and_mode || protocol_and_mode->second != Socket::ModeAccept) {
72 result.AppendErrorWithFormatv(connection_error, connection_uri);
73 return;
74 }
75
76 ProtocolServer::Connection connection;
77 connection.protocol = protocol_and_mode->first;
78 if (connection.protocol == Socket::SocketProtocol::ProtocolUnixDomain)
79 connection.name = uri->path;
80 else
81 connection.name = formatv(
82 "[{0}]:{1}", uri->hostname.empty() ? "0.0.0.0" : uri->hostname,
83 uri->port.value_or(0));
84
85 if (llvm::Error error = server->Start(connection)) {
86 result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
87 return;
88 }
89
90 if (Socket *socket = server->GetSocket()) {
91 std::string address =
92 llvm::join(socket->GetListeningConnectionURI(), ", ");
93 result.AppendMessageWithFormatv(
94 "{0} server started with connection listeners: {1}", protocol,
95 address);
96 result.SetStatus(eReturnStatusSuccessFinishNoResult);
97 }
98 }
99 };
100
101 class CommandObjectProtocolServerStop : public CommandObjectParsed {
102 public:
CommandObjectProtocolServerStop(CommandInterpreter & interpreter)103 CommandObjectProtocolServerStop(CommandInterpreter &interpreter)
104 : CommandObjectParsed(interpreter, "protocol-server stop",
105 "stop protocol server",
106 "protocol-server stop <protocol>") {
107 AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
108 }
109
110 ~CommandObjectProtocolServerStop() override = default;
111
112 protected:
DoExecute(Args & args,CommandReturnObject & result)113 void DoExecute(Args &args, CommandReturnObject &result) override {
114 if (args.GetArgumentCount() < 1) {
115 result.AppendError("no protocol specified");
116 return;
117 }
118
119 llvm::StringRef protocol = args.GetArgumentAtIndex(0);
120 ProtocolServer *server = ProtocolServer::GetOrCreate(protocol);
121 if (!server) {
122 result.AppendErrorWithFormatv(
123 "unsupported protocol: {0}. Supported protocols are: {1}", protocol,
124 llvm::join(ProtocolServer::GetSupportedProtocols(), ", "));
125 return;
126 }
127
128 if (llvm::Error error = server->Stop()) {
129 result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));
130 return;
131 }
132 }
133 };
134
CommandObjectProtocolServer(CommandInterpreter & interpreter)135 CommandObjectProtocolServer::CommandObjectProtocolServer(
136 CommandInterpreter &interpreter)
137 : CommandObjectMultiword(interpreter, "protocol-server",
138 "Start and stop a protocol server.",
139 "protocol-server") {
140 LoadSubCommand("start", CommandObjectSP(new CommandObjectProtocolServerStart(
141 interpreter)));
142 LoadSubCommand("stop", CommandObjectSP(
143 new CommandObjectProtocolServerStop(interpreter)));
144 }
145
146 CommandObjectProtocolServer::~CommandObjectProtocolServer() = default;
147