188 lines · cpp
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-exception6//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#include <string>19 20using namespace llvm;21using namespace lldb;22using namespace lldb_private;23 24#define LLDB_OPTIONS_mcp25#include "CommandOptions.inc"26 27class CommandObjectProtocolServerStart : public CommandObjectParsed {28public:29 CommandObjectProtocolServerStart(CommandInterpreter &interpreter)30 : CommandObjectParsed(interpreter, "protocol-server start",31 "start protocol server",32 "protocol-server start <protocol> [<connection>]") {33 AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);34 AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);35 }36 37 ~CommandObjectProtocolServerStart() override = default;38 39protected:40 void DoExecute(Args &args, CommandReturnObject &result) override {41 if (args.GetArgumentCount() < 1) {42 result.AppendError("no protocol specified");43 return;44 }45 46 llvm::StringRef protocol = args.GetArgumentAtIndex(0);47 ProtocolServer *server = ProtocolServer::GetOrCreate(protocol);48 if (!server) {49 result.AppendErrorWithFormatv(50 "unsupported protocol: {0}. Supported protocols are: {1}", protocol,51 llvm::join(ProtocolServer::GetSupportedProtocols(), ", "));52 return;53 }54 55 std::string connection_uri = "listen://[localhost]:0";56 if (args.GetArgumentCount() >= 2)57 connection_uri = args.GetArgumentAtIndex(1);58 59 const char *connection_error =60 "unsupported connection specifier, expected 'accept:///path' "61 "or 'listen://[host]:port', got '{0}'.";62 auto uri = lldb_private::URI::Parse(connection_uri);63 if (!uri) {64 result.AppendErrorWithFormatv(connection_error, connection_uri);65 return;66 }67 68 std::optional<Socket::ProtocolModePair> protocol_and_mode =69 Socket::GetProtocolAndMode(uri->scheme);70 if (!protocol_and_mode || protocol_and_mode->second != Socket::ModeAccept) {71 result.AppendErrorWithFormatv(connection_error, connection_uri);72 return;73 }74 75 ProtocolServer::Connection connection;76 connection.protocol = protocol_and_mode->first;77 if (connection.protocol == Socket::SocketProtocol::ProtocolUnixDomain)78 connection.name = uri->path;79 else80 connection.name = formatv(81 "[{0}]:{1}", uri->hostname.empty() ? "0.0.0.0" : uri->hostname,82 uri->port.value_or(0));83 84 if (llvm::Error error = server->Start(connection)) {85 result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));86 return;87 }88 89 if (Socket *socket = server->GetSocket()) {90 std::string address =91 llvm::join(socket->GetListeningConnectionURI(), ", ");92 result.AppendMessageWithFormatv(93 "{0} server started with connection listeners: {1}", protocol,94 address);95 result.SetStatus(eReturnStatusSuccessFinishNoResult);96 }97 }98};99 100class CommandObjectProtocolServerStop : public CommandObjectParsed {101public:102 CommandObjectProtocolServerStop(CommandInterpreter &interpreter)103 : CommandObjectParsed(interpreter, "protocol-server stop",104 "stop protocol server",105 "protocol-server stop <protocol>") {106 AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);107 }108 109 ~CommandObjectProtocolServerStop() override = default;110 111protected:112 void DoExecute(Args &args, CommandReturnObject &result) override {113 if (args.GetArgumentCount() < 1) {114 result.AppendError("no protocol specified");115 return;116 }117 118 llvm::StringRef protocol = args.GetArgumentAtIndex(0);119 ProtocolServer *server = ProtocolServer::GetOrCreate(protocol);120 if (!server) {121 result.AppendErrorWithFormatv(122 "unsupported protocol: {0}. Supported protocols are: {1}", protocol,123 llvm::join(ProtocolServer::GetSupportedProtocols(), ", "));124 return;125 }126 127 if (llvm::Error error = server->Stop()) {128 result.AppendErrorWithFormatv("{0}", llvm::fmt_consume(std::move(error)));129 return;130 }131 }132};133 134class CommandObjectProtocolServerGet : public CommandObjectParsed {135public:136 CommandObjectProtocolServerGet(CommandInterpreter &interpreter)137 : CommandObjectParsed(interpreter, "protocol-server get",138 "get protocol server connection information",139 "protocol-server get <protocol>") {140 AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);141 }142 143 ~CommandObjectProtocolServerGet() override = default;144 145protected:146 void DoExecute(Args &args, CommandReturnObject &result) override {147 if (args.GetArgumentCount() < 1) {148 result.AppendError("no protocol specified");149 return;150 }151 152 llvm::StringRef protocol = args.GetArgumentAtIndex(0);153 ProtocolServer *server = ProtocolServer::GetOrCreate(protocol);154 if (!server) {155 result.AppendErrorWithFormatv(156 "unsupported protocol: {0}. Supported protocols are: {1}", protocol,157 llvm::join(ProtocolServer::GetSupportedProtocols(), ", "));158 return;159 }160 161 Socket *socket = server->GetSocket();162 if (!socket) {163 result.AppendErrorWithFormatv("{0} server is not running", protocol);164 return;165 }166 167 std::string address = llvm::join(socket->GetListeningConnectionURI(), ", ");168 result.AppendMessageWithFormatv("{0} server connection listeners: {1}",169 protocol, address);170 result.SetStatus(eReturnStatusSuccessFinishNoResult);171 }172};173 174CommandObjectProtocolServer::CommandObjectProtocolServer(175 CommandInterpreter &interpreter)176 : CommandObjectMultiword(interpreter, "protocol-server",177 "Start, stop, and query protocol servers.",178 "protocol-server") {179 LoadSubCommand("start", CommandObjectSP(new CommandObjectProtocolServerStart(180 interpreter)));181 LoadSubCommand("stop", CommandObjectSP(182 new CommandObjectProtocolServerStop(interpreter)));183 LoadSubCommand(184 "get", CommandObjectSP(new CommandObjectProtocolServerGet(interpreter)));185}186 187CommandObjectProtocolServer::~CommandObjectProtocolServer() = default;188