20 #include <ripple/app/ledger/LedgerMaster.h>
21 #include <ripple/app/misc/HashRouter.h>
22 #include <ripple/app/misc/NetworkOPs.h>
23 #include <ripple/app/misc/ValidatorList.h>
24 #include <ripple/app/misc/ValidatorSite.h>
25 #include <ripple/basics/base64.h>
26 #include <ripple/basics/make_SSLContext.h>
27 #include <ripple/beast/core/LexicalCast.h>
28 #include <ripple/core/DatabaseCon.h>
29 #include <ripple/nodestore/DatabaseShard.h>
30 #include <ripple/overlay/Cluster.h>
31 #include <ripple/overlay/impl/ConnectAttempt.h>
32 #include <ripple/overlay/impl/PeerImp.h>
33 #include <ripple/overlay/predicates.h>
34 #include <ripple/peerfinder/make_Manager.h>
35 #include <ripple/rpc/handlers/GetCounts.h>
36 #include <ripple/rpc/json_body.h>
37 #include <ripple/server/SimpleWriter.h>
39 #include <boost/algorithm/string/predicate.hpp>
40 #include <boost/utility/in_place_factory.hpp>
44 namespace CrawlOptions {
62 overlay_.remove(*
this);
90 if (ec || overlay_.isStopping())
92 if (ec && ec != boost::asio::error::operation_aborted)
94 JLOG(overlay_.journal_.error()) <<
"on_timer: " << ec.message();
99 overlay_.m_peerFinder->once_per_second();
100 overlay_.sendEndpoints();
101 overlay_.autoConnect();
120 boost::asio::io_service& io_service,
136 app_.journal(
"PeerFinder"),
145 [counts =
m_traffic.getCounts(), collector]() {
149 for (
size_t i = 0; i < counts.size(); ++i)
189 handoff.
moved =
true;
191 JLOG(journal.
debug()) <<
"Peer connection upgrade from " << remote_endpoint;
194 auto const local_endpoint(
195 stream_ptr->next_layer().socket().local_endpoint(ec));
198 JLOG(journal.
debug()) << remote_endpoint <<
" failed: " << ec.message();
204 if (consumer.disconnect())
214 handoff.
moved =
false;
223 return boost::iequals(s,
"peer");
226 handoff.
moved =
false;
235 if (!negotiatedVersion)
238 handoff.
moved =
false;
242 remote_endpoint.address(),
243 "Unable to agree on a protocol version");
252 handoff.
moved =
false;
256 remote_endpoint.address(),
257 "Incorrect security cookie");
269 remote_endpoint.address(),
275 bool const reserved =
283 JLOG(journal.
debug())
284 <<
"Peer " << remote_endpoint <<
" redirected, slots full";
285 handoff.
moved =
false;
287 slot, request, remote_endpoint.address());
293 auto const peer = std::make_shared<PeerImp>(
301 std::move(stream_ptr),
309 auto const result =
m_peers.emplace(peer->slot(), peer);
310 assert(result.second);
313 list_.emplace(peer.get(), peer);
317 handoff.
moved =
true;
322 JLOG(journal.
debug()) <<
"Peer " << remote_endpoint
323 <<
" fails handshake (" << e.
what() <<
")";
326 handoff.
moved =
false;
328 slot, request, remote_endpoint.address(), e.
what());
342 return !versions.empty();
359 boost::beast::http::response<json_body> msg;
360 msg.version(request.version());
361 msg.result(boost::beast::http::status::service_unavailable);
363 msg.insert(
"Remote-Address", remote_address);
364 msg.insert(
"Content-Type",
"application/json");
365 msg.insert(boost::beast::http::field::connection,
"close");
370 ips.
append(_.address.to_string());
372 msg.prepare_payload();
373 return std::make_shared<SimpleWriter>(msg);
383 boost::beast::http::response<boost::beast::http::empty_body> msg;
384 msg.version(request.version());
385 msg.result(boost::beast::http::status::bad_request);
386 msg.reason(
"Bad Request (" + text +
")");
388 msg.insert(
"Remote-Address", remote_address.to_string());
389 msg.insert(boost::beast::http::field::connection,
"close");
390 msg.prepare_payload();
391 return std::make_shared<SimpleWriter>(msg);
402 if (usage.disconnect())
404 JLOG(
journal_.
info()) <<
"Over resource limit: " << remote_endpoint;
411 JLOG(
journal_.
debug()) <<
"Connect: No slot for " << remote_endpoint;
415 auto const p = std::make_shared<ConnectAttempt>(
427 list_.emplace(p.get(), p);
440 auto const result =
m_peers.emplace(peer->slot(), peer);
441 assert(result.second);
446 auto const result =
ids_.emplace(
447 std::piecewise_construct,
450 assert(result.second);
456 JLOG(
journal_.
debug()) <<
"activated " << peer->getRemoteAddress() <<
" ("
472 auto const iter =
m_peers.find(slot);
535 if (bootstrapIps.empty())
538 bootstrapIps.
push_back(
"r.ripple.com 51235");
541 bootstrapIps.
push_back(
"zaphod.alloy.ee 51235");
544 bootstrapIps.push_back(
"sahyadri.isrdc.in 51235");
554 for (
auto const& addr : addresses)
556 if (addr.port() == 0)
558 Throw<std::runtime_error>(
559 "Port not specified for "
580 if (!addresses.
empty())
589 auto const timer = std::make_shared<Timer>(*
this);
591 list_.emplace(timer.get(), timer);
620 for (
auto const& i : stats)
625 item[
"category"] = i.name;
646 auto const result(
ids_.emplace(
647 std::piecewise_construct,
650 assert(result.second);
654 JLOG(
journal_.
debug()) <<
"activated " << peer->getRemoteAddress() <<
" ("
677 auto const n = m->list_size();
678 auto const& journal = from->pjournal();
680 JLOG(journal.debug()) <<
"TMManifest, " << n
681 << (n == 1 ?
" item" :
" items");
685 auto& s = m->list().Get(i).stobject();
689 uint256 const hash = mo->hash();
690 if (!hashRouter.addSuppressionPeer(hash, from->id()))
692 JLOG(journal.info()) <<
"Duplicate manifest #" << i + 1;
698 JLOG(journal.info()) <<
"Untrusted manifest #" << i + 1;
703 auto const serialized = mo->serialized;
717 soci::transaction tr(*db);
718 static const char*
const sql =
719 "INSERT INTO ValidatorManifests (RawData) VALUES "
721 soci::blob rawData(*db);
723 *db << sql, soci::use(rawData);
726 protocol::TMManifests o;
727 o.add_list()->set_stobject(s);
729 auto const toSkip = hashRouter.shouldRelay(hash);
732 std::make_shared<Message>(o, protocol::mtMANIFESTS),
738 <<
"Bad manifest #" << i + 1 <<
": " <<
to_string(result);
743 JLOG(journal.warn()) <<
"Malformed manifest #" << i + 1;
762 using namespace std::chrono_literals;
765 auto const numPeers{
size()};
776 auto const timeout(
seconds((hops * hops) * 10));
784 for (
auto&
id :
ids_)
789 protocol::TMGetPeerShardInfo tmGPS;
790 tmGPS.set_hops(hops);
792 tmGPS, protocol::mtGET_PEER_SHARD_INFO)));
799 csLast_ = duration_cast<seconds>(
810 if (
auto psi = peer->getPeerShardInfo())
812 for (auto const& e : *psi)
814 auto it{peerShardInfo.find(e.first)};
815 if (it != peerShardInfo.end())
817 it->second.shardIndexes += e.second.shardIndexes;
819 peerShardInfo.emplace(std::move(e));
826 for (
auto const& e : peerShardInfo)
832 auto const& address{e.second.endpoint.address()};
833 if (!address.is_unspecified())
834 pv[jss::ip] = address.to_string();
836 pv[jss::complete_shards] =
to_string(e.second.shardIndexes);
880 sp->getNodePublic().data(), sp->getNodePublic().size());
881 pv[jss::type] = sp->slot()->inbound() ?
"in" :
"out";
883 duration_cast<seconds>(sp->uptime()).count());
886 pv[jss::ip] = sp->getRemoteAddress().address().to_string();
887 if (sp->slot()->inbound())
889 if (
auto port = sp->slot()->listening_port())
890 pv[jss::port] = *port;
899 auto version{sp->getVersion()};
900 if (!version.empty())
901 pv[jss::version] = std::move(version);
905 sp->ledgerRange(minSeq, maxSeq);
906 if (minSeq != 0 || maxSeq != 0)
907 pv[jss::complete_ledgers] =
910 if (
auto shardIndexes = sp->getShardIndexes())
911 pv[jss::complete_shards] =
to_string(*shardIndexes);
920 bool const humanReadable =
false;
921 bool const admin =
false;
922 bool const counters =
false;
929 server_info.
removeMember(jss::load_factor_fee_escalation);
933 if (server_info.
isMember(jss::validated_ledger))
935 Json::Value& validated_ledger = server_info[jss::validated_ledger];
956 if (validators.
isMember(jss::publisher_lists))
958 Json::Value& publisher_lists = validators[jss::publisher_lists];
960 for (
auto& publisher : publisher_lists)
972 if (validatorSites.
isMember(jss::validator_sites))
974 validators[jss::validator_sites] =
975 std::move(validatorSites[jss::validator_sites]);
996 if (req.target() !=
"/crawl" ||
1000 boost::beast::http::response<json_body> msg;
1001 msg.version(req.version());
1002 msg.result(boost::beast::http::status::ok);
1004 msg.insert(
"Content-Type",
"application/json");
1005 msg.insert(
"Connection",
"close");
1025 msg.prepare_payload();
1026 handoff.
response = std::make_shared<SimpleWriter>(msg);
1042 auto key = req.target().substr(prefix.size());
1050 boost::beast::http::response<json_body> msg;
1051 msg.version(req.version());
1053 msg.insert(
"Content-Type",
"application/json");
1054 msg.insert(
"Connection",
"close");
1059 msg.result(boost::beast::http::status::not_found);
1060 msg.insert(
"Content-Length",
"0");
1066 msg.result(boost::beast::http::status::ok);
1071 msg.prepare_payload();
1072 handoff.
response = std::make_shared<SimpleWriter>(msg);
1113 auto const iter =
ids_.find(
id);
1114 if (iter !=
ids_.end())
1115 return iter->second.lock();
1125 for (
auto const& e :
ids_)
1127 if (
auto peer = e.second.lock())
1129 if (peer->getNodePublic() == pubKey)
1139 auto const sm = std::make_shared<Message>(m, protocol::mtPROPOSE_LEDGER);
1145 auto const sm = std::make_shared<Message>(m, protocol::mtVALIDATION);
1148 SerialIter sit(m.validation().data(), m.validation().size());
1149 auto val = std::make_shared<STValidation>(
1164 std::make_shared<Message>(m, protocol::mtPROPOSE_LEDGER);
1166 if (toSkip->find(p->id()) == toSkip->end())
1177 auto const sm = std::make_shared<Message>(m, protocol::mtVALIDATION);
1179 if (toSkip->find(p->id()) == toSkip->end())
1191 list_.erase(&child);
1212 work_ = boost::none;
1215 for (
auto const& element :
list_)
1221 for (
auto const& child : children)
1223 if (child !=
nullptr)
1232 for (
auto addr : result)
1239 auto const result =
m_peerFinder->buildEndpointsForPeers();
1240 for (
auto const& e : result)
1245 auto const iter =
m_peers.find(e.first);
1247 peer = iter->second.lock();
1250 peer->sendEndpoints(e.second.begin(), e.second.end());
1260 auto const& section = config.
section(
"overlay");
1265 Throw<std::runtime_error>(
"Configured IP limit is invalid");
1268 set(ip,
"public_ip", section);
1271 boost::system::error_code ec;
1274 Throw<std::runtime_error>(
"Configured public IP is invalid");
1279 auto const& section = config.
section(
"crawl");
1280 auto const& values = section.
values();
1282 if (values.size() > 1)
1284 Throw<std::runtime_error>(
1285 "Configured [crawl] section is invalid, too many values");
1288 bool crawlEnabled =
true;
1291 if (values.size() == 1)
1295 crawlEnabled = boost::lexical_cast<bool>(values.front());
1297 catch (boost::bad_lexical_cast
const&)
1299 Throw<std::runtime_error>(
1300 "Configured [crawl] section has invalid value: " +
1307 if (get<bool>(section,
"overlay",
true))
1311 if (get<bool>(section,
"server",
true))
1315 if (get<bool>(section,
"counts",
false))
1319 if (get<bool>(section,
"unl",
true))
1326 auto const& section = config.
section(
"vl");
1333 auto id = config.
legacy(
"network_id");
1340 if (
id ==
"testnet")
1351 Throw<std::runtime_error>(
1352 "Configured [network_id] section is invalid: must be a number "
1353 "or one of the strings 'main', 'testnet' or 'devnet'.");
1367 boost::asio::io_service& io_service,
1371 return std::make_unique<OverlayImpl>(
std::string const & name() const
Returns the name of this source.
virtual Consumer newInboundEndpoint(beast::IP::Endpoint const &address)=0
Create a new endpoint keyed by inbound IP address or the forwarded IP if proxied.
std::shared_ptr< Peer > findPeerByShortID(Peer::id_t const &id) override
Returns the peer with the matching short id, or null.
void relay(protocol::TMProposeSet &m, uint256 const &uid) override
Relay a proposal.
virtual Consumer newOutboundEndpoint(beast::IP::Endpoint const &address)=0
Create a new endpoint keyed by outbound IP address and port.
Json::Value getServerCounts()
Returns information about the local server's performance counters.
const beast::Journal journal_
boost::asio::ip::address address_type
virtual Cluster & cluster()=0
virtual Json::Value getServerInfo(bool human, bool admin, bool counters)=0
auto const & getCounts() const
An up-to-date copy of all the counters.
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
boost::optional< boost::asio::io_service::work > work_
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
virtual void pubManifest(Manifest const &)=0
static bool is_upgrade(boost::beast::http::header< true, Fields > const &req)
hash_map< Peer::id_t, std::weak_ptr< PeerImp > > ids_
@ arrayValue
array value (ordered list)
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
boost::optional< Json::Value > getAvailable(boost::beast::string_view const &pubKey)
Returns the current valid list for the given publisher key, if available, as a Json object.
virtual ValidatorSite & validatorSites()=0
std::uint32_t crawlOptions
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
std::set< std::uint32_t > csIDs_
std::recursive_mutex mutex_
void on_timer(error_code ec)
virtual PeerReservationTable & peerReservations()=0
std::atomic< Peer::id_t > next_id_
std::string base64_encode(std::uint8_t const *data, std::size_t len)
bool empty() const noexcept
std::shared_ptr< boost::asio::ssl::context > make_SSLContext(std::string const &cipherList)
Create a self-signed SSL context that allows anonymous Diffie Hellman.
std::unique_ptr< Overlay > make_Overlay(Application &app, Overlay::Setup const &setup, Stoppable &parent, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_service &io_service, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
Creates the implementation of Overlay.
static std::string makePrefix(std::uint32_t id)
std::string features
The set of features we advertise.
Handoff onHandoff(std::unique_ptr< stream_type > &&bundle, http_request_type &&request, endpoint_type remote_endpoint) override
Conditionally accept an incoming HTTP request.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::condition_variable csCV_
void setup(Setup const &setup, beast::Journal journal)
boost::asio::io_service::strand strand_
Json::Value getServerInfo()
Returns information about the local server.
void onStart() override
Override called during start.
std::vector< ProtocolVersion > parseProtocolVersions(boost::beast::string_view const &value)
Parse a set of protocol versions.
Stopwatch & stopwatch()
Returns an instance of a wall clock.
std::string to_string(ListDisposition disposition)
virtual std::shared_ptr< Slot > new_outbound_slot(beast::IP::Endpoint const &remote_endpoint)=0
Create a new outbound slot with the specified remote endpoint.
void connect(beast::IP::Endpoint const &remote_endpoint) override
Establish a peer connection to the specified endpoint.
Json::Value json() override
Return diagnostics on the status of all peers.
Setup const & setup() const
bool peerPrivate
true if we want our IP address kept private.
bool processValidatorList(http_request_type const &req, Handoff &handoff)
Handles validator list requests.
Select all peers that are in the specified set.
virtual NetworkOPs & getOPs()=0
virtual DatabaseCon & getWalletDB()=0
Retrieve the "wallet database".
std::vector< std::string > const & values() const
Returns all the values in the section.
bool is_private(AddressV4 const &addr)
Returns true if the address is a private unroutable address.
Sends a message to all peers.
void onChildrenStopped() override
Override called when all children have stopped.
std::condition_variable_any cond_
boost::optional< ProtocolVersion > negotiateProtocolVersion(std::vector< ProtocolVersion > const &versions)
Given a list of supported protocol versions, choose the one we prefer.
PublicKey verifyHandshake(boost::beast::http::fields const &headers, ripple::uint256 const &sharedValue, boost::optional< std::uint32_t > networkID, beast::IP::Address public_ip, beast::IP::Address remote, Application &app)
Validate header fields necessary for upgrading the link to the peer protocol.
static IP::Endpoint from_asio(boost::asio::ip::address const &address)
boost::optional< std::string > member(PublicKey const &node) const
Determines whether a node belongs in the cluster.
PeerFinder::Manager & peerFinder()
std::size_t size() const override
The number of active peers on the network Active peers are only those peers that have completed the h...
void send(protocol::TMProposeSet &m) override
Broadcast a proposal.
bool is_keep_alive(boost::beast::http::message< isRequest, Body, Fields > const &m)
Overlay::Setup setup_Overlay(BasicConfig const &config)
Value & append(const Value &value)
Append value to array at the end.
void onManifests(std::shared_ptr< protocol::TMManifests > const &m, std::shared_ptr< PeerImp > const &from)
Provides an interface for starting and stopping.
beast::IP::Address public_ip
bool wantIncoming
true if we want to accept incoming connections.
LockedSociSession checkoutDb()
Resource::Manager & resourceManager()
@ objectValue
object value (collection of name/value pairs).
void add(Source &source)
Add a child source.
Json::Value getOverlayInfo()
Returns information about peers on the overlay network.
boost::asio::io_service & io_service_
virtual Config & config()=0
Json::Value getJson() const
Return JSON representation of configured validator sites.
std::vector< std::string > IPS_FIXED
virtual void pubValidation(std::shared_ptr< STValidation > const &val)=0
bool areChildrenStopped() const
Returns true if all children have stopped.
ServerHandler & serverHandler()
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Json::Value getUnlInfo()
Returns information about the local server's UNL.
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
boost::optional< uint256 > makeSharedValue(stream_type &ssl, beast::Journal journal)
Computes a shared value based on the SSL connection state.
double outPeers
The number of automatic outbound connections to maintain.
int maxPeers
The largest number of public peer slots to allow.
void legacy(std::string const §ion, std::string value)
Set a value that is not a key/value pair.
std::unique_ptr< PeerFinder::Manager > m_peerFinder
bool isMember(const char *key) const
Return true if the object has a member named key.
A generic endpoint for log messages.
ServerHandler & serverHandler_
void onPrepare() override
Override called during preparation.
Child(OverlayImpl &overlay)
boost::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
PeerSequence getActivePeers() const override
Returns a sequence representing the current list of peers.
Result split_commas(FwdIt first, FwdIt last)
virtual PublicKey const & getValidationPublicKey() const =0
OverlayImpl(Application &app, Setup const &setup, Stoppable &parent, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_service &io_service, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
virtual ValidatorList & validators()=0
bool processRequest(http_request_type const &req, Handoff &handoff)
Handles non-peer protocol requests.
@ accepted
Manifest is valid.
Tracks load and resource consumption.
std::string const & getFullVersionString()
Full server version string.
void applyTuning()
Adjusts the values so they follow the business rules.
Json::Value getCountsJson(Application &app, int minObjectCount)
Resource::Manager & m_resourceManager
T emplace_back(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
boost::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
void checkSanity(std::uint32_t) override
Calls the checkSanity function on each peer.
virtual beast::Journal journal(std::string const &name)=0
virtual ManifestCache & validatorManifests()=0
Value removeMember(const char *key)
Remove and return the named member.
std::uint16_t listeningPort
The listening port number.
send_if_not_pred< Predicate > send_if_not(std::shared_ptr< Message > const &m, Predicate const &f)
Helper function to aid in type deduction.
void remove(std::shared_ptr< PeerFinder::Slot > const &slot)
Manages the set of connected peers.
void activate(std::shared_ptr< PeerImp > const &peer)
Called when a peer has connected successfully This is called after the peer handshake has been comple...
double calcOutPeers() const
Returns a suitable value for outPeers according to the rules.
void onPeerDeactivate(Peer::id_t id)
boost::optional< std::uint32_t > networkID
boost::container::flat_map< Child *, std::weak_ptr< Child > > list_
void lastLink(std::uint32_t id)
Called when the last link from a peer chain is received.
void check() override
Calls the check function on each peer.
Timer(OverlayImpl &overlay)
Wraps a Journal::Sink to prefix its output with a string.
Used to indicate the result of a server connection handoff.
std::shared_ptr< Peer > findPeerByPublicKey(PublicKey const &pubKey) override
Returns the peer with the matching public key, or null.
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
bool contains(PublicKey const &nodeId)
std::vector< std::string > IPS
std::shared_ptr< Writer > makeRedirectResponse(std::shared_ptr< PeerFinder::Slot > const &slot, http_request_type const &request, address_type remote_address)
A version-independent IP address and port combination.
std::weak_ptr< Timer > timer_
std::shared_ptr< boost::asio::ssl::context > context
std::shared_ptr< Writer > response
static boost::asio::ip::tcp::endpoint to_asio_endpoint(IP::Endpoint const &address)
bool autoConnect
true if we want to establish connections automatically
PeerFinder configuration settings.
std::atomic< std::chrono::seconds > csLast_
void reportTraffic(TrafficCount::category cat, bool isInbound, int bytes)
Json::Value crawlShards(bool pubKey, std::uint32_t hops) override
Returns information reported to the crawl shard RPC command.
void addCount(category cat, bool inbound, int bytes)
Account for traffic associated with the given category.
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
std::shared_ptr< Writer > makeErrorResponse(std::shared_ptr< PeerFinder::Slot > const &slot, http_request_type const &request, address_type remote_address, std::string msg)
@ checkSeconds
How often we check connections (seconds)
hash_map< std::shared_ptr< PeerFinder::Slot >, std::weak_ptr< PeerImp > > m_peers
void resolve(std::vector< std::string > const &names, Handler handler)
resolve all hostnames on the list
static bool isPeerUpgrade(http_request_type const &request)
void add_active(std::shared_ptr< PeerImp > const &peer)
boost::system::error_code error_code
int ipLimit
Limit how many incoming connections we allow per IP.
void onWrite(beast::PropertyStream::Map &stream) override
Subclass override.
virtual HashRouter & getHashRouter()=0
Holds unparsed configuration information.
void for_each(UnaryFunc &&f) const
void onStop() override
Override called when the stop notification is issued.
Section & section(std::string const &name)
Returns the section with the given name.
int limit() override
Returns the maximum number of peers we are configured to allow.
bool processCrawl(http_request_type const &req, Handoff &handoff)
Handles crawl requests.
boost::asio::ip::tcp::endpoint endpoint_type
bool isStopping() const
Returns true if the stoppable should stop.