| //===----------------------------------------------------------------------===// | |
| // | |
| // 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 "lldb/API/SBProtocolServer.h" | |
| #include "lldb/API/SBError.h" | |
| #include "lldb/Core/ProtocolServer.h" | |
| #include "lldb/Host/Socket.h" | |
| #include "lldb/Utility/ConstString.h" | |
| #include "lldb/Utility/Instrumentation.h" | |
| #include "lldb/Utility/UriParser.h" | |
| #include "llvm/ADT/StringExtras.h" | |
| #include "llvm/Support/FormatVariadic.h" | |
| #include <memory> | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| /// PIMPL backing SBProtocolServer. | |
| class lldb_private::SBProtocolServerImpl { | |
| public: | |
| ProtocolServer *server = nullptr; | |
| }; | |
| SBProtocolServer::SBProtocolServer() | |
| : m_opaque_up(std::make_unique<SBProtocolServerImpl>()) { | |
| LLDB_INSTRUMENT_VA(this); | |
| } | |
| SBProtocolServer::SBProtocolServer(const SBProtocolServer &rhs) | |
| : m_opaque_up(std::make_unique<SBProtocolServerImpl>(*rhs.m_opaque_up)) { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| } | |
| SBProtocolServer &SBProtocolServer::operator=(const SBProtocolServer &rhs) { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| if (this != &rhs) | |
| *m_opaque_up = *rhs.m_opaque_up; | |
| return *this; | |
| } | |
| SBProtocolServer::~SBProtocolServer() = default; | |
| SBProtocolServer SBProtocolServer::Create(const char *protocol, | |
| SBError &error) { | |
| LLDB_INSTRUMENT_VA(protocol, error); | |
| SBProtocolServer server; | |
| error.Clear(); | |
| if (!protocol || !protocol[0]) { | |
| error.SetErrorString("no protocol specified"); | |
| return server; | |
| } | |
| ProtocolServer *protocol_server = ProtocolServer::GetOrCreate(protocol); | |
| if (!protocol_server) { | |
| error.SetErrorStringWithFormat( | |
| "unsupported protocol: %s. Supported protocols are: %s", protocol, | |
| llvm::join(ProtocolServer::GetSupportedProtocols(), ", ").c_str()); | |
| return server; | |
| } | |
| server.m_opaque_up->server = protocol_server; | |
| return server; | |
| } | |
| SBProtocolServer::operator bool() const { | |
| LLDB_INSTRUMENT_VA(this); | |
| return m_opaque_up->server != nullptr; | |
| } | |
| bool SBProtocolServer::IsValid() const { | |
| LLDB_INSTRUMENT_VA(this); | |
| return m_opaque_up->server != nullptr; | |
| } | |
| SBError SBProtocolServer::Start(const char *connection_uri) { | |
| LLDB_INSTRUMENT_VA(this, connection_uri); | |
| SBError error; | |
| if (!m_opaque_up->server) { | |
| error.SetErrorString("invalid protocol server"); | |
| return error; | |
| } | |
| const char *connection_error = | |
| "unsupported connection specifier, expected 'accept:///path' or " | |
| "'listen://[host]:port'"; | |
| std::optional<URI> uri = URI::Parse(connection_uri ? connection_uri : ""); | |
| if (!uri) { | |
| error.SetErrorString(connection_error); | |
| return error; | |
| } | |
| std::optional<Socket::ProtocolModePair> protocol_and_mode = | |
| Socket::GetProtocolAndMode(uri->scheme); | |
| if (!protocol_and_mode || protocol_and_mode->second != Socket::ModeAccept) { | |
| error.SetErrorString(connection_error); | |
| return error; | |
| } | |
| ProtocolServer::Connection connection; | |
| connection.protocol = protocol_and_mode->first; | |
| if (connection.protocol == Socket::SocketProtocol::ProtocolUnixDomain) | |
| connection.name = uri->path; | |
| else | |
| connection.name = | |
| llvm::formatv("[{0}]:{1}", | |
| uri->hostname.empty() ? "0.0.0.0" : uri->hostname, | |
| uri->port.value_or(0)) | |
| .str(); | |
| if (llvm::Error err = m_opaque_up->server->Start(connection)) | |
| error.SetErrorString(llvm::toString(std::move(err)).c_str()); | |
| return error; | |
| } | |
| SBError SBProtocolServer::Stop() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBError error; | |
| if (!m_opaque_up->server) { | |
| error.SetErrorString("invalid protocol server"); | |
| return error; | |
| } | |
| if (llvm::Error err = m_opaque_up->server->Stop()) | |
| error.SetErrorString(llvm::toString(std::move(err)).c_str()); | |
| return error; | |
| } | |
| const char *SBProtocolServer::GetConnectionURI() { | |
| LLDB_INSTRUMENT_VA(this); | |
| if (!m_opaque_up->server) | |
| return nullptr; | |
| Socket *socket = m_opaque_up->server->GetSocket(); | |
| if (!socket) | |
| return nullptr; | |
| std::vector<std::string> uris = socket->GetListeningConnectionURI(); | |
| if (uris.empty()) | |
| return nullptr; | |
| // A listening socket may report several equivalent URIs (e.g. IPv6 and | |
| // IPv4 loopback). Return the first, interned so the pointer stays valid. | |
| return ConstString(uris.front()).GetCString(); | |
| } |