mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 02:38:07 +08:00
Currently AFAICT we don't have a way to get the MCP server socket after it started. So this change introduces a new `protocol-server` subcommand that allows us to query the location of a running server: ``` (lldb) protocol-server start MCP listen://localhost:0 MCP server started with connection listeners: connection://[::1]:36051, connection://[127.0.0.1]:36051 (lldb) protocol-server get MCP MCP server connection listeners: connection://[::1]:36051, connection://[127.0.0.1]:36051 (lldb) protocol-server stop MCP (lldb) protocol-server get MCP error: MCP server is not running ```
188 lines
6.7 KiB
C++
188 lines
6.7 KiB
C++
//===-- 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;
|
|
}
|
|
}
|
|
};
|
|
|
|
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;
|