xref: /freebsd/contrib/llvm-project/lldb/source/Commands/CommandObjectProtocolServer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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