| //===-- CommandObjectProtocolServer.cpp -----------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "CommandObjectProtocolServer.h" | |
| #include "lldb/Core/PluginManager.h" | |
| #include "lldb/Core/ProtocolServer.h" | |
| #include "lldb/Host/Socket.h" | |
| #include "lldb/Interpreter/CommandInterpreter.h" | |
| #include "lldb/Interpreter/CommandReturnObject.h" | |
| #include "lldb/Utility/UriParser.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/Support/FormatAdapters.h" | |
| #include <string> | |
| using namespace llvm; | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| #define LLDB_OPTIONS_mcp | |
| #include "CommandOptions.inc" | |
| class CommandObjectProtocolServerStart : public CommandObjectParsed { | |
| public: | |
| CommandObjectProtocolServerStart(CommandInterpreter &interpreter) | |
| : CommandObjectParsed(interpreter, "protocol-server start", | |
| "start protocol server", | |
| "protocol-server start <protocol> [<connection>]") { | |
| AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain); | |
| AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain); | |
| } | |
| ~CommandObjectProtocolServerStart() override = default; | |
| protected: | |
| void DoExecute(Args &args, CommandReturnObject &result) override { | |
| if (args.GetArgumentCount() < 1) { | |
| result.AppendError("no protocol specified"); | |
| return; | |
| } | |
| llvm::StringRef protocol = args.GetArgumentAtIndex(0); | |
| ProtocolServer *server = ProtocolServer::GetOrCreate(protocol); | |
| if (!server) { | |
| result.AppendErrorWithFormatv( | |
| "unsupported protocol: {0}. Supported protocols are: {1}", protocol, | |
| llvm::join(ProtocolServer::GetSupportedProtocols(), ", ")); | |
| return; | |
| } | |
| std::string connection_uri = "listen://[localhost]:0"; | |
| if (args.GetArgumentCount() >= 2) | |
| connection_uri = args.GetArgumentAtIndex(1); | |
| const char *connection_error = | |
| "unsupported connection specifier, expected 'accept:///path' " | |
| "or 'listen://[host]:port', got '{0}'."; | |
| auto uri = lldb_private::URI::Parse(connection_uri); | |
| if (!uri) { | |
| result.AppendErrorWithFormatv(connection_error, connection_uri); | |
| return; | |
| } | |
| std::optional<Socket::ProtocolModePair> protocol_and_mode = | |
| Socket::GetProtocolAndMode(uri->scheme); | |
| if (!protocol_and_mode || protocol_and_mode->second != Socket::ModeAccept) { | |
| result.AppendErrorWithFormatv(connection_error, connection_uri); | |
| return; | |
| } | |
| ProtocolServer::Connection connection; | |
| connection.protocol = protocol_and_mode->first; | |
| if (connection.protocol == Socket::SocketProtocol::ProtocolUnixDomain) | |
| connection.name = uri->path; | |
| else | |
| connection.name = formatv( | |
| "[{0}]:{1}", uri->hostname.empty() ? "0.0.0.0" : uri->hostname, | |
| uri->port.value_or(0)); | |
| if (llvm::Error error = server->Start(connection)) { | |
| result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error))); | |
| return; | |
| } | |
| if (Socket *socket = server->GetSocket()) { | |
| std::string address = | |
| llvm::join(socket->GetListeningConnectionURI(), ", "); | |
| result.AppendMessageWithFormatv( | |
| "{0} server started with connection listeners: {1}", protocol, | |
| address); | |
| } | |
| result.SetStatus(eReturnStatusSuccessFinishNoResult); | |
| } | |
| }; | |
| class CommandObjectProtocolServerStop : public CommandObjectParsed { | |
| public: | |
| CommandObjectProtocolServerStop(CommandInterpreter &interpreter) | |
| : CommandObjectParsed(interpreter, "protocol-server stop", | |
| "stop protocol server", | |
| "protocol-server stop <protocol>") { | |
| AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain); | |
| } | |
| ~CommandObjectProtocolServerStop() override = default; | |
| protected: | |
| void DoExecute(Args &args, CommandReturnObject &result) override { | |
| if (args.GetArgumentCount() < 1) { | |
| result.AppendError("no protocol specified"); | |
| return; | |
| } | |
| llvm::StringRef protocol = args.GetArgumentAtIndex(0); | |
| ProtocolServer *server = ProtocolServer::GetOrCreate(protocol); | |
| if (!server) { | |
| result.AppendErrorWithFormatv( | |
| "unsupported protocol: {0}. Supported protocols are: {1}", protocol, | |
| llvm::join(ProtocolServer::GetSupportedProtocols(), ", ")); | |
| return; | |
| } | |
| if (llvm::Error error = server->Stop()) { | |
| result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error))); | |
| return; | |
| } | |
| result.SetStatus(eReturnStatusSuccessFinishNoResult); | |
| } | |
| }; | |
| class CommandObjectProtocolServerGet : public CommandObjectParsed { | |
| public: | |
| CommandObjectProtocolServerGet(CommandInterpreter &interpreter) | |
| : CommandObjectParsed(interpreter, "protocol-server get", | |
| "get protocol server connection information", | |
| "protocol-server get <protocol>") { | |
| AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain); | |
| } | |
| ~CommandObjectProtocolServerGet() override = default; | |
| protected: | |
| void DoExecute(Args &args, CommandReturnObject &result) override { | |
| if (args.GetArgumentCount() < 1) { | |
| result.AppendError("no protocol specified"); | |
| return; | |
| } | |
| llvm::StringRef protocol = args.GetArgumentAtIndex(0); | |
| ProtocolServer *server = ProtocolServer::GetOrCreate(protocol); | |
| if (!server) { | |
| result.AppendErrorWithFormatv( | |
| "unsupported protocol: {0}. Supported protocols are: {1}", protocol, | |
| llvm::join(ProtocolServer::GetSupportedProtocols(), ", ")); | |
| return; | |
| } | |
| Socket *socket = server->GetSocket(); | |
| if (!socket) { | |
| result.AppendErrorWithFormatv("{0} server is not running", protocol); | |
| return; | |
| } | |
| std::string address = llvm::join(socket->GetListeningConnectionURI(), ", "); | |
| result.AppendMessageWithFormatv("{0} server connection listeners: {1}", | |
| protocol, address); | |
| result.SetStatus(eReturnStatusSuccessFinishNoResult); | |
| } | |
| }; | |
| CommandObjectProtocolServer::CommandObjectProtocolServer( | |
| CommandInterpreter &interpreter) | |
| : CommandObjectMultiword(interpreter, "protocol-server", | |
| "Start, stop, and query protocol servers.", | |
| "protocol-server") { | |
| LoadSubCommand("start", CommandObjectSP(new CommandObjectProtocolServerStart( | |
| interpreter))); | |
| LoadSubCommand("stop", CommandObjectSP( | |
| new CommandObjectProtocolServerStop(interpreter))); | |
| LoadSubCommand( | |
| "get", CommandObjectSP(new CommandObjectProtocolServerGet(interpreter))); | |
| } | |
| CommandObjectProtocolServer::~CommandObjectProtocolServer() = default; |