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
19using namespace llvm;
20using namespace lldb;
21using namespace lldb_private;
22
23#define LLDB_OPTIONS_mcp
24#include "CommandOptions.inc"
25
26class CommandObjectProtocolServerStart : public CommandObjectParsed {
27public:
28 CommandObjectProtocolServerStart(CommandInterpreter &interpreter)
29 : CommandObjectParsed(interpreter, "protocol-server start",
30 "start protocol server",
31 "protocol-server start <protocol> <connection>") {
32 AddSimpleArgumentList(arg_type: lldb::eArgTypeProtocol, repetition_type: eArgRepeatPlain);
33 AddSimpleArgumentList(arg_type: lldb::eArgTypeConnectURL, repetition_type: eArgRepeatPlain);
34 }
35
36 ~CommandObjectProtocolServerStart() override = default;
37
38protected:
39 void DoExecute(Args &args, CommandReturnObject &result) override {
40 if (args.GetArgumentCount() < 1) {
41 result.AppendError(in_string: "no protocol specified");
42 return;
43 }
44
45 llvm::StringRef protocol = args.GetArgumentAtIndex(idx: 0);
46 ProtocolServer *server = ProtocolServer::GetOrCreate(name: protocol);
47 if (!server) {
48 result.AppendErrorWithFormatv(
49 format: "unsupported protocol: {0}. Supported protocols are: {1}", args&: protocol,
50 args: llvm::join(R: ProtocolServer::GetSupportedProtocols(), Separator: ", "));
51 return;
52 }
53
54 if (args.GetArgumentCount() < 2) {
55 result.AppendError(in_string: "no connection specified");
56 return;
57 }
58 llvm::StringRef connection_uri = args.GetArgumentAtIndex(idx: 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(uri: connection_uri);
64 if (!uri) {
65 result.AppendErrorWithFormatv(format: connection_error, args&: connection_uri);
66 return;
67 }
68
69 std::optional<Socket::ProtocolModePair> protocol_and_mode =
70 Socket::GetProtocolAndMode(scheme: uri->scheme);
71 if (!protocol_and_mode || protocol_and_mode->second != Socket::ModeAccept) {
72 result.AppendErrorWithFormatv(format: connection_error, args&: 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 Fmt: "[{0}]:{1}", Vals: uri->hostname.empty() ? "0.0.0.0" : uri->hostname,
83 Vals: uri->port.value_or(u: 0));
84
85 if (llvm::Error error = server->Start(connection)) {
86 result.AppendErrorWithFormatv(format: "{0}", args: llvm::fmt_consume(Item: std::move(error)));
87 return;
88 }
89
90 if (Socket *socket = server->GetSocket()) {
91 std::string address =
92 llvm::join(R: socket->GetListeningConnectionURI(), Separator: ", ");
93 result.AppendMessageWithFormatv(
94 format: "{0} server started with connection listeners: {1}", args&: protocol,
95 args&: address);
96 result.SetStatus(eReturnStatusSuccessFinishNoResult);
97 }
98 }
99};
100
101class CommandObjectProtocolServerStop : public CommandObjectParsed {
102public:
103 CommandObjectProtocolServerStop(CommandInterpreter &interpreter)
104 : CommandObjectParsed(interpreter, "protocol-server stop",
105 "stop protocol server",
106 "protocol-server stop <protocol>") {
107 AddSimpleArgumentList(arg_type: lldb::eArgTypeProtocol, repetition_type: eArgRepeatPlain);
108 }
109
110 ~CommandObjectProtocolServerStop() override = default;
111
112protected:
113 void DoExecute(Args &args, CommandReturnObject &result) override {
114 if (args.GetArgumentCount() < 1) {
115 result.AppendError(in_string: "no protocol specified");
116 return;
117 }
118
119 llvm::StringRef protocol = args.GetArgumentAtIndex(idx: 0);
120 ProtocolServer *server = ProtocolServer::GetOrCreate(name: protocol);
121 if (!server) {
122 result.AppendErrorWithFormatv(
123 format: "unsupported protocol: {0}. Supported protocols are: {1}", args&: protocol,
124 args: llvm::join(R: ProtocolServer::GetSupportedProtocols(), Separator: ", "));
125 return;
126 }
127
128 if (llvm::Error error = server->Stop()) {
129 result.AppendErrorWithFormatv(format: "{0}", args: llvm::fmt_consume(Item: std::move(error)));
130 return;
131 }
132 }
133};
134
135CommandObjectProtocolServer::CommandObjectProtocolServer(
136 CommandInterpreter &interpreter)
137 : CommandObjectMultiword(interpreter, "protocol-server",
138 "Start and stop a protocol server.",
139 "protocol-server") {
140 LoadSubCommand(cmd_name: "start", command_obj: CommandObjectSP(new CommandObjectProtocolServerStart(
141 interpreter)));
142 LoadSubCommand(cmd_name: "stop", command_obj: CommandObjectSP(
143 new CommandObjectProtocolServerStop(interpreter)));
144}
145
146CommandObjectProtocolServer::~CommandObjectProtocolServer() = default;
147

source code of lldb/source/Commands/CommandObjectProtocolServer.cpp