rippled
ValidatorSite.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2016 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/misc/ValidatorList.h>
21 #include <ripple/app/misc/ValidatorSite.h>
22 #include <ripple/app/misc/detail/WorkFile.h>
23 #include <ripple/app/misc/detail/WorkPlain.h>
24 #include <ripple/app/misc/detail/WorkSSL.h>
25 #include <ripple/basics/Slice.h>
26 #include <ripple/basics/base64.h>
27 #include <ripple/json/json_reader.h>
28 #include <ripple/protocol/digest.h>
29 #include <ripple/protocol/jss.h>
30 #include <algorithm>
31 
32 namespace ripple {
33 
36 unsigned short constexpr max_redirects = 3;
37 
39 {
40  if (!parseUrl(pUrl, uri))
41  throw std::runtime_error("URI '" + uri + "' cannot be parsed");
42 
43  if (pUrl.scheme == "file")
44  {
45  if (!pUrl.domain.empty())
46  throw std::runtime_error("file URI cannot contain a hostname");
47 
48 #if BOOST_OS_WINDOWS
49  // Paths on Windows need the leading / removed
50  if (pUrl.path[0] == '/')
51  pUrl.path = pUrl.path.substr(1);
52 #endif
53 
54  if (pUrl.path.empty())
55  throw std::runtime_error("file URI must contain a path");
56  }
57  else if (pUrl.scheme == "http")
58  {
59  if (pUrl.domain.empty())
60  throw std::runtime_error("http URI must contain a hostname");
61 
62  if (!pUrl.port)
63  pUrl.port = 80;
64  }
65  else if (pUrl.scheme == "https")
66  {
67  if (pUrl.domain.empty())
68  throw std::runtime_error("https URI must contain a hostname");
69 
70  if (!pUrl.port)
71  pUrl.port = 443;
72  }
73  else
74  throw std::runtime_error("Unsupported scheme: '" + pUrl.scheme + "'");
75 }
76 
78  : loadedResource{std::make_shared<Resource>(std::move(uri))}
79  , startingResource{loadedResource}
80  , redirCount{0}
81  , refreshInterval{default_refresh_interval}
82  , nextRefresh{clock_type::now()}
83  , lastRequestEndpoint{}
84  , lastRequestSuccessful{false}
85 {
86 }
87 
89  Application& app,
91  std::chrono::seconds timeout)
92  : app_{app}
93  , j_{j ? *j : app_.logs().journal("ValidatorSite")}
94  , timer_{app_.getIOService()}
95  , fetching_{false}
96  , pending_{false}
97  , stopping_{false}
98  , requestTimeout_{timeout}
99 {
100 }
101 
103 {
105  if (timer_.expires_at() > clock_type::time_point{})
106  {
107  if (!stopping_)
108  {
109  lock.unlock();
110  stop();
111  }
112  else
113  {
114  cv_.wait(lock, [&] { return !fetching_; });
115  }
116  }
117 }
118 
119 bool
121 {
122  auto const sites = app_.validators().loadLists();
123  return sites.empty() || load(sites, lock_sites);
124 }
125 
126 bool
128 {
129  JLOG(j_.debug()) << "Loading configured validator list sites";
130 
132 
133  return load(siteURIs, lock);
134 }
135 
136 bool
138  std::vector<std::string> const& siteURIs,
139  std::lock_guard<std::mutex> const& lock_sites)
140 {
141  // If no sites are provided, act as if a site failed to load.
142  if (siteURIs.empty())
143  {
144  return missingSite(lock_sites);
145  }
146 
147  for (auto const& uri : siteURIs)
148  {
149  try
150  {
151  sites_.emplace_back(uri);
152  }
153  catch (std::exception const& e)
154  {
155  JLOG(j_.error())
156  << "Invalid validator site uri: " << uri << ": " << e.what();
157  return false;
158  }
159  }
160 
161  JLOG(j_.debug()) << "Loaded " << siteURIs.size() << " sites";
162 
163  return true;
164 }
165 
166 void
168 {
171  if (timer_.expires_at() == clock_type::time_point{})
172  setTimer(l0, l1);
173 }
174 
175 void
177 {
179  cv_.wait(lock, [&] { return !pending_; });
180 }
181 
182 void
184 {
186  stopping_ = true;
187  // work::cancel() must be called before the
188  // cv wait in order to kick any asio async operations
189  // that might be pending.
190  if (auto sp = work_.lock())
191  sp->cancel();
192  cv_.wait(lock, [&] { return !fetching_; });
193 
194  // docs indicate cancel() can throw, but this should be
195  // reconsidered if it changes to noexcept
196  try
197  {
198  timer_.cancel();
199  }
200  catch (boost::system::system_error const&)
201  {
202  }
203  stopping_ = false;
204  pending_ = false;
205  cv_.notify_all();
206 }
207 
208 void
210  std::lock_guard<std::mutex> const& site_lock,
211  std::lock_guard<std::mutex> const& state_lock)
212 {
213  auto next = std::min_element(
214  sites_.begin(), sites_.end(), [](Site const& a, Site const& b) {
215  return a.nextRefresh < b.nextRefresh;
216  });
217 
218  if (next != sites_.end())
219  {
220  pending_ = next->nextRefresh <= clock_type::now();
221  cv_.notify_all();
222  timer_.expires_at(next->nextRefresh);
223  auto idx = std::distance(sites_.begin(), next);
224  timer_.async_wait([this, idx](boost::system::error_code const& ec) {
225  this->onTimer(idx, ec);
226  });
227  }
228 }
229 
230 void
233  std::size_t siteIdx,
234  std::lock_guard<std::mutex> const& sites_lock)
235 {
236  fetching_ = true;
237  sites_[siteIdx].activeResource = resource;
239  auto timeoutCancel = [this]() {
240  std::lock_guard lock_state{state_mutex_};
241  // docs indicate cancel_one() can throw, but this
242  // should be reconsidered if it changes to noexcept
243  try
244  {
245  timer_.cancel_one();
246  }
247  catch (boost::system::system_error const&)
248  {
249  }
250  };
251  auto onFetch = [this, siteIdx, timeoutCancel](
252  error_code const& err,
253  endpoint_type const& endpoint,
254  detail::response_type&& resp) {
255  timeoutCancel();
256  onSiteFetch(err, endpoint, std::move(resp), siteIdx);
257  };
258 
259  auto onFetchFile = [this, siteIdx, timeoutCancel](
260  error_code const& err, std::string const& resp) {
261  timeoutCancel();
262  onTextFetch(err, resp, siteIdx);
263  };
264 
265  JLOG(j_.debug()) << "Starting request for " << resource->uri;
266 
267  if (resource->pUrl.scheme == "https")
268  {
269  // can throw...
270  sp = std::make_shared<detail::WorkSSL>(
271  resource->pUrl.domain,
272  resource->pUrl.path,
273  std::to_string(*resource->pUrl.port),
274  app_.getIOService(),
275  j_,
276  app_.config(),
277  sites_[siteIdx].lastRequestEndpoint,
278  sites_[siteIdx].lastRequestSuccessful,
279  onFetch);
280  }
281  else if (resource->pUrl.scheme == "http")
282  {
283  sp = std::make_shared<detail::WorkPlain>(
284  resource->pUrl.domain,
285  resource->pUrl.path,
286  std::to_string(*resource->pUrl.port),
287  app_.getIOService(),
288  sites_[siteIdx].lastRequestEndpoint,
289  sites_[siteIdx].lastRequestSuccessful,
290  onFetch);
291  }
292  else
293  {
294  BOOST_ASSERT(resource->pUrl.scheme == "file");
295  sp = std::make_shared<detail::WorkFile>(
296  resource->pUrl.path, app_.getIOService(), onFetchFile);
297  }
298 
299  sites_[siteIdx].lastRequestSuccessful = false;
300  work_ = sp;
301  sp->run();
302  // start a timer for the request, which shouldn't take more
303  // than requestTimeout_ to complete
304  std::lock_guard lock_state{state_mutex_};
305  timer_.expires_after(requestTimeout_);
306  timer_.async_wait([this, siteIdx](boost::system::error_code const& ec) {
307  this->onRequestTimeout(siteIdx, ec);
308  });
309 }
310 
311 void
313 {
314  if (ec)
315  return;
316 
317  {
318  std::lock_guard lock_site{sites_mutex_};
319  JLOG(j_.warn()) << "Request for " << sites_[siteIdx].activeResource->uri
320  << " took too long";
321  }
322 
323  std::lock_guard lock_state{state_mutex_};
324  if (auto sp = work_.lock())
325  sp->cancel();
326 }
327 
328 void
330 {
331  if (ec)
332  {
333  // Restart the timer if any errors are encountered, unless the error
334  // is from the wait operation being aborted due to a shutdown request.
335  if (ec != boost::asio::error::operation_aborted)
336  onSiteFetch(ec, {}, detail::response_type{}, siteIdx);
337  return;
338  }
339 
340  try
341  {
343  sites_[siteIdx].nextRefresh =
344  clock_type::now() + sites_[siteIdx].refreshInterval;
345  sites_[siteIdx].redirCount = 0;
346  // the WorkSSL client ctor can throw if SSL init fails
347  makeRequest(sites_[siteIdx].startingResource, siteIdx, lock);
348  }
349  catch (std::exception&)
350  {
351  onSiteFetch(
352  boost::system::error_code{-1, boost::system::generic_category()},
353  {},
355  siteIdx);
356  }
357 }
358 
359 void
361  std::string const& res,
362  std::size_t siteIdx,
363  std::lock_guard<std::mutex> const& sites_lock)
364 {
365  Json::Value const body = [&res, siteIdx, this]() {
366  Json::Reader r;
367  Json::Value body;
368  if (!r.parse(res.data(), body))
369  {
370  JLOG(j_.warn()) << "Unable to parse JSON response from "
371  << sites_[siteIdx].activeResource->uri;
372  throw std::runtime_error{"bad json"};
373  }
374  return body;
375  }();
376 
377  auto const [valid, version, blobs] = [&body]() {
378  // Check the easy fields first
379  bool valid = body.isObject() && body.isMember(jss::manifest) &&
380  body[jss::manifest].isString() && body.isMember(jss::version) &&
381  body[jss::version].isInt();
382  // Check the version-specific blob & signature fields
383  std::uint32_t version;
385  if (valid)
386  {
387  version = body[jss::version].asUInt();
388  blobs = ValidatorList::parseBlobs(version, body);
389  valid = !blobs.empty();
390  }
391  return std::make_tuple(valid, version, blobs);
392  }();
393 
394  if (!valid)
395  {
396  JLOG(j_.warn()) << "Missing fields in JSON response from "
397  << sites_[siteIdx].activeResource->uri;
398  throw std::runtime_error{"missing fields"};
399  }
400 
401  auto const manifest = body[jss::manifest].asString();
402  assert(version == body[jss::version].asUInt());
403  auto const& uri = sites_[siteIdx].activeResource->uri;
404  auto const hash = sha512Half(manifest, blobs, version);
405  auto const applyResult = app_.validators().applyListsAndBroadcast(
406  manifest,
407  version,
408  blobs,
409  uri,
410  hash,
411  app_.overlay(),
413  app_.getOPs());
414 
415  sites_[siteIdx].lastRefreshStatus.emplace(
416  Site::Status{clock_type::now(), applyResult.bestDisposition(), ""});
417 
418  for (auto const& [disp, count] : applyResult.dispositions)
419  {
420  switch (disp)
421  {
423  JLOG(j_.debug()) << "Applied " << count
424  << " new validator list(s) from " << uri;
425  break;
427  JLOG(j_.debug()) << "Applied " << count
428  << " expired validator list(s) from " << uri;
429  break;
431  JLOG(j_.debug())
432  << "Ignored " << count
433  << " validator list(s) with current sequence from " << uri;
434  break;
436  JLOG(j_.debug()) << "Processed " << count
437  << " future validator list(s) from " << uri;
438  break;
440  JLOG(j_.debug())
441  << "Ignored " << count
442  << " validator list(s) with future known sequence from "
443  << uri;
444  break;
446  JLOG(j_.warn()) << "Ignored " << count
447  << "stale validator list(s) from " << uri;
448  break;
450  JLOG(j_.warn()) << "Ignored " << count
451  << " untrusted validator list(s) from " << uri;
452  break;
454  JLOG(j_.warn()) << "Ignored " << count
455  << " invalid validator list(s) from " << uri;
456  break;
458  JLOG(j_.warn())
459  << "Ignored " << count
460  << " unsupported version validator list(s) from " << uri;
461  break;
462  default:
463  BOOST_ASSERT(false);
464  }
465  }
466 
467  if (body.isMember(jss::refresh_interval) &&
468  body[jss::refresh_interval].isNumeric())
469  {
470  using namespace std::chrono_literals;
471  std::chrono::minutes const refresh = std::clamp(
472  std::chrono::minutes{body[jss::refresh_interval].asUInt()},
473  1min,
474  std::chrono::minutes{24h});
475  sites_[siteIdx].refreshInterval = refresh;
476  sites_[siteIdx].nextRefresh =
477  clock_type::now() + sites_[siteIdx].refreshInterval;
478  }
479 }
480 
484  std::size_t siteIdx,
485  std::lock_guard<std::mutex> const& sites_lock)
486 {
487  using namespace boost::beast::http;
489  if (res.find(field::location) == res.end() || res[field::location].empty())
490  {
491  JLOG(j_.warn()) << "Request for validator list at "
492  << sites_[siteIdx].activeResource->uri
493  << " returned a redirect with no Location.";
494  throw std::runtime_error{"missing location"};
495  }
496 
497  if (sites_[siteIdx].redirCount == max_redirects)
498  {
499  JLOG(j_.warn()) << "Exceeded max redirects for validator list at "
500  << sites_[siteIdx].loadedResource->uri;
501  throw std::runtime_error{"max redirects"};
502  }
503 
504  JLOG(j_.debug()) << "Got redirect for validator list from "
505  << sites_[siteIdx].activeResource->uri
506  << " to new location " << res[field::location];
507 
508  try
509  {
510  newLocation =
511  std::make_shared<Site::Resource>(std::string(res[field::location]));
512  ++sites_[siteIdx].redirCount;
513  if (newLocation->pUrl.scheme != "http" &&
514  newLocation->pUrl.scheme != "https")
515  throw std::runtime_error(
516  "invalid scheme in redirect " + newLocation->pUrl.scheme);
517  }
518  catch (std::exception&)
519  {
520  JLOG(j_.error()) << "Invalid redirect location: "
521  << res[field::location];
522  throw;
523  }
524  return newLocation;
525 }
526 
527 void
529  boost::system::error_code const& ec,
530  endpoint_type const& endpoint,
531  detail::response_type&& res,
532  std::size_t siteIdx)
533 {
534  std::lock_guard lock_sites{sites_mutex_};
535  {
536  if (endpoint != endpoint_type{})
537  sites_[siteIdx].lastRequestEndpoint = endpoint;
538  JLOG(j_.debug()) << "Got completion for "
539  << sites_[siteIdx].activeResource->uri << " "
540  << endpoint;
541  auto onError = [&](std::string const& errMsg, bool retry) {
542  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
544  if (retry)
545  sites_[siteIdx].nextRefresh =
547 
548  // See if there's a copy saved locally from last time we
549  // saw the list.
550  missingSite(lock_sites);
551  };
552  if (ec)
553  {
554  JLOG(j_.warn())
555  << "Problem retrieving from "
556  << sites_[siteIdx].activeResource->uri << " " << endpoint << " "
557  << ec.value() << ":" << ec.message();
558  onError("fetch error", true);
559  }
560  else
561  {
562  try
563  {
564  using namespace boost::beast::http;
565  switch (res.result())
566  {
567  case status::ok:
568  sites_[siteIdx].lastRequestSuccessful = true;
569  parseJsonResponse(res.body(), siteIdx, lock_sites);
570  break;
571  case status::moved_permanently:
572  case status::permanent_redirect:
573  case status::found:
574  case status::temporary_redirect: {
575  auto newLocation =
576  processRedirect(res, siteIdx, lock_sites);
577  assert(newLocation);
578  // for perm redirects, also update our starting URI
579  if (res.result() == status::moved_permanently ||
580  res.result() == status::permanent_redirect)
581  {
582  sites_[siteIdx].startingResource = newLocation;
583  }
584  makeRequest(newLocation, siteIdx, lock_sites);
585  return; // we are still fetching, so skip
586  // state update/notify below
587  }
588  default: {
589  JLOG(j_.warn())
590  << "Request for validator list at "
591  << sites_[siteIdx].activeResource->uri << " "
592  << endpoint
593  << " returned bad status: " << res.result_int();
594  onError("bad result code", true);
595  }
596  }
597  }
598  catch (std::exception& ex)
599  {
600  onError(ex.what(), false);
601  }
602  }
603  sites_[siteIdx].activeResource.reset();
604  }
605 
606  std::lock_guard lock_state{state_mutex_};
607  fetching_ = false;
608  if (!stopping_)
609  setTimer(lock_sites, lock_state);
610  cv_.notify_all();
611 }
612 
613 void
615  boost::system::error_code const& ec,
616  std::string const& res,
617  std::size_t siteIdx)
618 {
619  std::lock_guard lock_sites{sites_mutex_};
620  {
621  try
622  {
623  if (ec)
624  {
625  JLOG(j_.warn()) << "Problem retrieving from "
626  << sites_[siteIdx].activeResource->uri << " "
627  << ec.value() << ": " << ec.message();
628  throw std::runtime_error{"fetch error"};
629  }
630 
631  sites_[siteIdx].lastRequestSuccessful = true;
632 
633  parseJsonResponse(res, siteIdx, lock_sites);
634  }
635  catch (std::exception& ex)
636  {
637  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
639  }
640  sites_[siteIdx].activeResource.reset();
641  }
642 
643  std::lock_guard lock_state{state_mutex_};
644  fetching_ = false;
645  if (!stopping_)
646  setTimer(lock_sites, lock_state);
647  cv_.notify_all();
648 }
649 
652 {
653  using namespace std::chrono;
654  using Int = Json::Value::Int;
655 
657  Json::Value& jSites = (jrr[jss::validator_sites] = Json::arrayValue);
658  {
660  for (Site const& site : sites_)
661  {
662  Json::Value& v = jSites.append(Json::objectValue);
663  std::stringstream uri;
664  uri << site.loadedResource->uri;
665  if (site.loadedResource != site.startingResource)
666  uri << " (redirects to " << site.startingResource->uri + ")";
667  v[jss::uri] = uri.str();
668  v[jss::next_refresh_time] = to_string(site.nextRefresh);
669  if (site.lastRefreshStatus)
670  {
671  v[jss::last_refresh_time] =
672  to_string(site.lastRefreshStatus->refreshed);
673  v[jss::last_refresh_status] =
674  to_string(site.lastRefreshStatus->disposition);
675  if (!site.lastRefreshStatus->message.empty())
676  v[jss::last_refresh_message] =
677  site.lastRefreshStatus->message;
678  }
679  v[jss::refresh_interval_min] =
680  static_cast<Int>(site.refreshInterval.count());
681  }
682  }
683  return jrr;
684 }
685 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
Json::Value::Int
Json::Int Int
Definition: json_value.h:154
ripple::Application
Definition: Application.h:115
std::make_tuple
T make_tuple(T... args)
ripple::ListDisposition::pending
@ pending
List will be valid in the future.
ripple::ValidatorSite::Site
Definition: ValidatorSite.h:78
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::string
STL class.
std::shared_ptr
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
std::exception
STL class.
ripple::ValidatorSite::timer_
boost::asio::basic_waitable_timer< clock_type > timer_
Definition: ValidatorSite.h:127
ripple::ListDisposition::stale
@ stale
Trusted publisher key, but seq is too old.
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::ValidatorSite::endpoint_type
boost::asio::ip::tcp::endpoint endpoint_type
Definition: ValidatorSite.h:76
std::vector< std::string >
ripple::ValidatorList::applyListsAndBroadcast
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
Definition: ValidatorList.cpp:869
ripple::max_redirects
unsigned constexpr short max_redirects
Definition: ValidatorSite.cpp:36
ripple::ValidatorSite::stop
void stop()
Stop fetching lists from sites.
Definition: ValidatorSite.cpp:183
std::chrono::minutes
ripple::ValidatorSite::onRequestTimeout
void onRequestTimeout(std::size_t siteIdx, error_code const &ec)
request took too long
Definition: ValidatorSite.cpp:312
ripple::ValidatorSite::Site::Resource::uri
const std::string uri
Definition: ValidatorSite.h:90
std::stringstream
STL class.
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::ValidatorSite::work_
std::weak_ptr< detail::Work > work_
Definition: ValidatorSite.h:126
std::lock_guard
STL class.
std::distance
T distance(T... args)
ripple::ValidatorSite::makeRequest
void makeRequest(std::shared_ptr< Site::Resource > resource, std::size_t siteIdx, std::lock_guard< std::mutex > const &)
Initiate request to given resource.
Definition: ValidatorSite.cpp:231
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:362
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
ripple::parsedURL::path
std::string path
Definition: StringUtilities.h:125
ripple::ValidatorSite::onSiteFetch
void onSiteFetch(boost::system::error_code const &ec, endpoint_type const &endpoint, detail::response_type &&res, std::size_t siteIdx)
Store latest list fetched from site.
Definition: ValidatorSite.cpp:528
ripple::ListDisposition::expired
@ expired
List is expired, but has the largest non-pending sequence seen so far.
ripple::ValidatorSite::state_mutex_
std::mutex state_mutex_
Definition: ValidatorSite.h:123
algorithm
ripple::ValidatorSite::fetching_
std::atomic< bool > fetching_
Definition: ValidatorSite.h:130
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::ValidatorSite::~ValidatorSite
~ValidatorSite()
Definition: ValidatorSite.cpp:102
ripple::ValidatorSite::setTimer
void setTimer(std::lock_guard< std::mutex > const &, std::lock_guard< std::mutex > const &)
Queue next site to be fetched lock over site_mutex_ and state_mutex_ required.
Definition: ValidatorSite.cpp:209
ripple::detail::response_type
boost::beast::http::response< boost::beast::http::string_body > response_type
Definition: Work.h:31
ripple::ValidatorSite::app_
Application & app_
Definition: ValidatorSite.h:117
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::ValidatorSite::pending_
std::atomic< bool > pending_
Definition: ValidatorSite.h:133
ripple::parsedURL::port
std::optional< std::uint16_t > port
Definition: StringUtilities.h:124
ripple::Application::config
virtual Config & config()=0
std::min_element
T min_element(T... args)
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:651
std::unique_lock
STL class.
ripple::ValidatorSite::j_
const beast::Journal j_
Definition: ValidatorSite.h:118
std::to_string
T to_string(T... args)
ripple::ValidatorSite::cv_
std::condition_variable cv_
Definition: ValidatorSite.h:125
ripple::ValidatorSite::parseJsonResponse
void parseJsonResponse(std::string const &res, std::size_t siteIdx, std::lock_guard< std::mutex > const &)
Parse json response from validator list site.
Definition: ValidatorSite.cpp:360
ripple::parseUrl
bool parseUrl(parsedURL &pUrl, std::string const &strUrl)
Definition: StringUtilities.cpp:47
beast::Journal::error
Stream error() const
Definition: Journal.h:333
std::runtime_error
STL class.
ripple::ListDisposition::untrusted
@ untrusted
List signed by untrusted publisher key.
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::ValidatorSite::join
void join()
Wait for current fetches from sites to complete.
Definition: ValidatorSite.cpp:176
std::uint32_t
std::condition_variable::wait
T wait(T... args)
ripple::error_retry_interval
constexpr auto error_retry_interval
Definition: ValidatorSite.cpp:35
ripple::ValidatorSite::processRedirect
std::shared_ptr< Site::Resource > processRedirect(detail::response_type &res, std::size_t siteIdx, std::lock_guard< std::mutex > const &)
Interpret a redirect response.
Definition: ValidatorSite.cpp:482
ripple::ValidatorSite::sites_mutex_
std::mutex sites_mutex_
Definition: ValidatorSite.h:122
ripple::ListDisposition::unsupported_version
@ unsupported_version
List version is not supported.
ripple::Application::validators
virtual ValidatorList & validators()=0
ripple::ValidatorSite::sites_
std::vector< Site > sites_
Definition: ValidatorSite.h:137
ripple::Application::getIOService
virtual boost::asio::io_service & getIOService()=0
ripple::ListDisposition::known_sequence
@ known_sequence
Future sequence already seen.
ripple::ValidatorList::loadLists
std::vector< std::string > loadLists()
Definition: ValidatorList.cpp:1206
ripple::ValidatorSite::requestTimeout_
const std::chrono::seconds requestTimeout_
Definition: ValidatorSite.h:140
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
Json::Value::isNumeric
bool isNumeric() const
Definition: json_value.cpp:1003
std::clamp
T clamp(T... args)
ripple::ListDisposition::same_sequence
@ same_sequence
Same sequence as current list.
ripple::ValidatorSite::Site::Resource::Resource
Resource(std::string uri_)
Definition: ValidatorSite.cpp:38
ripple::ValidatorSite::onTextFetch
void onTextFetch(boost::system::error_code const &ec, std::string const &res, std::size_t siteIdx)
Store latest list fetched from anywhere.
Definition: ValidatorSite.cpp:614
ripple::ValidatorSite::Site::loadedResource
std::shared_ptr< Resource > loadedResource
the original uri as loaded from config
Definition: ValidatorSite.h:97
ripple::ValidatorSite::stopping_
std::atomic< bool > stopping_
Definition: ValidatorSite.h:134
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:216
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
ripple::ListDisposition::invalid
@ invalid
Invalid format or signature.
ripple::ValidatorSite::ValidatorSite
ValidatorSite(Application &app, std::optional< beast::Journal > j=std::nullopt, std::chrono::seconds timeout=std::chrono::seconds{20})
Definition: ValidatorSite.cpp:88
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:74
ripple::ValidatorSite::Site::Site
Site(std::string uri)
Definition: ValidatorSite.cpp:77
ripple::Application::overlay
virtual Overlay & overlay()=0
std::vector::empty
T empty(T... args)
ripple::ValidatorSite::Site::Resource::pUrl
parsedURL pUrl
Definition: ValidatorSite.h:91
ripple::ValidatorSite::Site::Status
Definition: ValidatorSite.h:80
std::optional
std::stringstream::str
T str(T... args)
ripple::parsedURL::scheme
std::string scheme
Definition: StringUtilities.h:120
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::ValidatorSite::start
void start()
Start fetching lists from sites.
Definition: ValidatorSite.cpp:167
ripple::ValidatorSite::onTimer
void onTimer(std::size_t siteIdx, error_code const &ec)
Fetch site whose time has come.
Definition: ValidatorSite.cpp:329
ripple::parsedURL::domain
std::string domain
Definition: StringUtilities.h:123
ripple::ValidatorSite::error_code
boost::system::error_code error_code
Definition: ValidatorSite.h:74
std::string::data
T data(T... args)
ripple::ValidatorSite::missingSite
bool missingSite(std::lock_guard< std::mutex > const &)
If no sites are provided, or a site fails to load, get a list of local cache files from the Validator...
Definition: ValidatorSite.cpp:120
std::condition_variable::notify_all
T notify_all(T... args)
ripple::ValidatorSite::load
bool load(std::vector< std::string > const &siteURIs)
Load configured site URIs.
Definition: ValidatorSite.cpp:127
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::ListDisposition::accepted
@ accepted
List is valid.
ripple::default_refresh_interval
constexpr auto default_refresh_interval
Definition: ValidatorSite.cpp:34
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
std::chrono
std::chrono::system_clock::now
T now(T... args)