mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Add RPC/WS ports to server_info (#4427)
Enhance the /crawl endpoint by publishing WebSocket/RPC ports in the server_info response. The function processing requests to the /crawl endpoint actually calls server_info internally, so this change enables a server to advertise its WebSocket/RPC port(s) to peers via the /crawl endpoint. `grpc` and `peer` ports are included as well. The new `ports` array contains objects, each containing a `port` for the listening port (number string), and an array `protocol` listing the supported protocol(s). This allows crawlers to build a richer topology without needing to port-scan nodes. For non-admin users (including peers), the info about *admin* ports is excluded. Also increase test coverage for RPC ServerInfo. Fix #2837.
This commit is contained in:
@@ -605,6 +605,13 @@ public:
|
||||
return *m_networkOPs;
|
||||
}
|
||||
|
||||
virtual ServerHandlerImp&
|
||||
getServerHandler() override
|
||||
{
|
||||
assert(serverHandler_);
|
||||
return *serverHandler_;
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
getIOService() override
|
||||
{
|
||||
|
||||
@@ -88,6 +88,7 @@ class Overlay;
|
||||
class PathRequests;
|
||||
class PendingSaves;
|
||||
class PublicKey;
|
||||
class ServerHandlerImp;
|
||||
class SecretKey;
|
||||
class STLedgerEntry;
|
||||
class TimeKeeper;
|
||||
@@ -230,6 +231,8 @@ public:
|
||||
getOPs() = 0;
|
||||
virtual OrderBookDB&
|
||||
getOrderBookDB() = 0;
|
||||
virtual ServerHandlerImp&
|
||||
getServerHandler() = 0;
|
||||
virtual TransactionMaster&
|
||||
getMasterTransaction() = 0;
|
||||
virtual perf::PerfLog&
|
||||
|
||||
@@ -429,7 +429,7 @@ GRPCServerImpl::GRPCServerImpl(Application& app)
|
||||
// if present, get endpoint from config
|
||||
if (app_.config().exists("port_grpc"))
|
||||
{
|
||||
Section section = app_.config().section("port_grpc");
|
||||
const auto& section = app_.config().section("port_grpc");
|
||||
|
||||
auto const optIp = section.get("ip");
|
||||
if (!optIp)
|
||||
|
||||
@@ -68,10 +68,13 @@
|
||||
#include <ripple/rpc/CTID.h>
|
||||
#include <ripple/rpc/DeliveredAmount.h>
|
||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||
#include <ripple/rpc/impl/ServerHandlerImp.h>
|
||||
#include <ripple/rpc/impl/UDPInfoSub.h>
|
||||
#include <boost/asio/ip/host_name.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <exception>
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -2709,6 +2712,51 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
|
||||
info["reporting"] = app_.getReportingETL().getInfo();
|
||||
}
|
||||
|
||||
// This array must be sorted in increasing order.
|
||||
static constexpr std::array<std::string_view, 7> protocols{
|
||||
"http", "https", "peer", "ws", "ws2", "wss", "wss2"};
|
||||
static_assert(std::is_sorted(std::begin(protocols), std::end(protocols)));
|
||||
{
|
||||
Json::Value ports{Json::arrayValue};
|
||||
for (auto const& port : app_.getServerHandler().setup().ports)
|
||||
{
|
||||
// Don't publish admin ports for non-admin users
|
||||
if (!admin &&
|
||||
!(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() &&
|
||||
port.admin_user.empty() && port.admin_password.empty()))
|
||||
continue;
|
||||
std::vector<std::string> proto;
|
||||
std::set_intersection(
|
||||
std::begin(port.protocol),
|
||||
std::end(port.protocol),
|
||||
std::begin(protocols),
|
||||
std::end(protocols),
|
||||
std::back_inserter(proto));
|
||||
if (!proto.empty())
|
||||
{
|
||||
auto& jv = ports.append(Json::Value(Json::objectValue));
|
||||
jv[jss::port] = std::to_string(port.port);
|
||||
jv[jss::protocol] = Json::Value{Json::arrayValue};
|
||||
for (auto const& p : proto)
|
||||
jv[jss::protocol].append(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (app_.config().exists("port_grpc"))
|
||||
{
|
||||
auto const& grpcSection = app_.config().section("port_grpc");
|
||||
auto const optPort = grpcSection.get("port");
|
||||
if (optPort && grpcSection.get("ip"))
|
||||
{
|
||||
auto& jv = ports.append(Json::Value(Json::objectValue));
|
||||
jv[jss::port] = *optPort;
|
||||
jv[jss::protocol] = Json::Value{Json::arrayValue};
|
||||
jv[jss::protocol].append("grpc");
|
||||
}
|
||||
}
|
||||
info[jss::ports] = std::move(ports);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -562,13 +562,14 @@ JSS(peer_disconnects_resources); // Severed peer connections because of
|
||||
// excess resource consumption.
|
||||
JSS(percent_complete);
|
||||
JSS(phash);
|
||||
JSS(port); // in: Connect
|
||||
JSS(port); // in: Connect, out: NetworkOPs
|
||||
JSS(ports); // out: NetworkOPs
|
||||
JSS(previous); // out: Reservations
|
||||
JSS(previous_ledger); // out: LedgerPropose
|
||||
JSS(proof); // in: BookOffers
|
||||
JSS(propose_seq); // out: LedgerPropose
|
||||
JSS(proposers); // out: NetworkOPs, LedgerConsensus
|
||||
JSS(protocol); // out: PeerImp
|
||||
JSS(protocol); // out: NetworkOPs, PeerImp
|
||||
JSS(proxied); // out: RPC ping
|
||||
JSS(pubkey_node); // out: NetworkOPs
|
||||
JSS(pubkey_publisher); // out: ValidatorList
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/jtx.h>
|
||||
@@ -55,6 +56,16 @@ public:
|
||||
|
||||
[validators]
|
||||
%2%
|
||||
|
||||
[port_grpc]
|
||||
ip = 0.0.0.0
|
||||
port = 50051
|
||||
|
||||
[port_admin]
|
||||
ip = 0.0.0.0
|
||||
port = 50052
|
||||
protocol = wss2
|
||||
admin = 127.0.0.1
|
||||
)rippleConfig");
|
||||
|
||||
p->loadFromString(boost::str(
|
||||
@@ -77,8 +88,30 @@ public:
|
||||
BEAST_EXPECT(result[jss::result][jss::status] == "success");
|
||||
BEAST_EXPECT(result[jss::result].isMember(jss::info));
|
||||
}
|
||||
|
||||
{
|
||||
Env env(*this, makeValidatorConfig());
|
||||
Env env(*this);
|
||||
|
||||
// Call NetworkOPs directly and set the admin flag to false.
|
||||
// Expect that the admin ports are not included in the result.
|
||||
auto const result =
|
||||
env.app().getOPs().getServerInfo(true, false, 0);
|
||||
auto const& ports = result[jss::ports];
|
||||
BEAST_EXPECT(ports.isArray() && ports.size() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto config = makeValidatorConfig();
|
||||
auto const rpc_port =
|
||||
(*config)["port_rpc"].get<unsigned int>("port");
|
||||
auto const grpc_port =
|
||||
(*config)["port_grpc"].get<unsigned int>("port");
|
||||
auto const ws_port = (*config)["port_ws"].get<unsigned int>("port");
|
||||
BEAST_EXPECT(grpc_port);
|
||||
BEAST_EXPECT(rpc_port);
|
||||
BEAST_EXPECT(ws_port);
|
||||
|
||||
Env env(*this, std::move(config));
|
||||
auto const result = env.rpc("server_info");
|
||||
BEAST_EXPECT(!result[jss::result].isMember(jss::error));
|
||||
BEAST_EXPECT(result[jss::result][jss::status] == "success");
|
||||
@@ -86,6 +119,32 @@ public:
|
||||
BEAST_EXPECT(
|
||||
result[jss::result][jss::info][jss::pubkey_validator] ==
|
||||
validator_data::public_key);
|
||||
|
||||
auto const& ports = result[jss::result][jss::info][jss::ports];
|
||||
BEAST_EXPECT(ports.isArray() && ports.size() == 3);
|
||||
for (auto const& port : ports)
|
||||
{
|
||||
auto const& proto = port[jss::protocol];
|
||||
BEAST_EXPECT(proto.isArray());
|
||||
auto const p = port[jss::port].asUInt();
|
||||
BEAST_EXPECT(p == rpc_port || p == ws_port || p == grpc_port);
|
||||
if (p == grpc_port)
|
||||
{
|
||||
BEAST_EXPECT(proto.size() == 1);
|
||||
BEAST_EXPECT(proto[0u].asString() == "grpc");
|
||||
}
|
||||
if (p == rpc_port)
|
||||
{
|
||||
BEAST_EXPECT(proto.size() == 2);
|
||||
BEAST_EXPECT(proto[0u].asString() == "http");
|
||||
BEAST_EXPECT(proto[1u].asString() == "ws2");
|
||||
}
|
||||
if (p == ws_port)
|
||||
{
|
||||
BEAST_EXPECT(proto.size() == 1);
|
||||
BEAST_EXPECT(proto[0u].asString() == "ws");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user