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: 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: 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: 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: 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 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