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 <boost/algorithm/clamp.hpp>
31 #include <algorithm>
32 
33 namespace ripple {
34 
37 unsigned short constexpr max_redirects = 3;
38 
40 {
41  if (!parseUrl(pUrl, uri))
42  throw std::runtime_error("URI '" + uri + "' cannot be parsed");
43 
44  if (pUrl.scheme == "file")
45  {
46  if (!pUrl.domain.empty())
47  throw std::runtime_error("file URI cannot contain a hostname");
48 
49 #if BOOST_OS_WINDOWS
50  // Paths on Windows need the leading / removed
51  if (pUrl.path[0] == '/')
52  pUrl.path = pUrl.path.substr(1);
53 #endif
54 
55  if (pUrl.path.empty())
56  throw std::runtime_error("file URI must contain a path");
57  }
58  else if (pUrl.scheme == "http")
59  {
60  if (pUrl.domain.empty())
61  throw std::runtime_error("http URI must contain a hostname");
62 
63  if (!pUrl.port)
64  pUrl.port = 80;
65  }
66  else if (pUrl.scheme == "https")
67  {
68  if (pUrl.domain.empty())
69  throw std::runtime_error("https URI must contain a hostname");
70 
71  if (!pUrl.port)
72  pUrl.port = 443;
73  }
74  else
75  throw std::runtime_error("Unsupported scheme: '" + pUrl.scheme + "'");
76 }
77 
79  : loadedResource{std::make_shared<Resource>(std::move(uri))}
80  , startingResource{loadedResource}
81  , redirCount{0}
82  , refreshInterval{default_refresh_interval}
83  , nextRefresh{clock_type::now()}
84  , lastRequestEndpoint{}
85  , lastRequestSuccessful{false}
86 {
87 }
88 
90  Application& app,
92  std::chrono::seconds timeout)
93  : app_{app}
94  , j_{j ? *j : app_.logs().journal("ValidatorSite")}
95  , timer_{app_.getIOService()}
96  , fetching_{false}
97  , pending_{false}
98  , stopping_{false}
99  , requestTimeout_{timeout}
100 {
101 }
102 
104 {
106  if (timer_.expires_at() > clock_type::time_point{})
107  {
108  if (!stopping_)
109  {
110  lock.unlock();
111  stop();
112  }
113  else
114  {
115  cv_.wait(lock, [&] { return !fetching_; });
116  }
117  }
118 }
119 
120 bool
122 {
123  auto const sites = app_.validators().loadLists();
124  return sites.empty() || load(sites);
125 }
126 
127 bool
129 {
130  // If no sites are provided, act as if a site failed to load.
131  if (siteURIs.empty())
132  {
133  return missingSite();
134  }
135 
136  JLOG(j_.debug()) << "Loading configured validator list sites";
137 
139 
140  for (auto const& uri : siteURIs)
141  {
142  try
143  {
144  sites_.emplace_back(uri);
145  }
146  catch (std::exception const& e)
147  {
148  JLOG(j_.error())
149  << "Invalid validator site uri: " << uri << ": " << e.what();
150  return false;
151  }
152  }
153 
154  JLOG(j_.debug()) << "Loaded " << siteURIs.size() << " sites";
155 
156  return true;
157 }
158 
159 void
161 {
163  if (timer_.expires_at() == clock_type::time_point{})
164  setTimer(lock);
165 }
166 
167 void
169 {
171  cv_.wait(lock, [&] { return !pending_; });
172 }
173 
174 void
176 {
178  stopping_ = true;
179  // work::cancel() must be called before the
180  // cv wait in order to kick any asio async operations
181  // that might be pending.
182  if (auto sp = work_.lock())
183  sp->cancel();
184  cv_.wait(lock, [&] { return !fetching_; });
185 
186  // docs indicate cancel() can throw, but this should be
187  // reconsidered if it changes to noexcept
188  try
189  {
190  timer_.cancel();
191  }
192  catch (boost::system::system_error const&)
193  {
194  }
195  stopping_ = false;
196  pending_ = false;
197  cv_.notify_all();
198 }
199 
200 void
202 {
204 
205  auto next = std::min_element(
206  sites_.begin(), sites_.end(), [](Site const& a, Site const& b) {
207  return a.nextRefresh < b.nextRefresh;
208  });
209 
210  if (next != sites_.end())
211  {
212  pending_ = next->nextRefresh <= clock_type::now();
213  cv_.notify_all();
214  timer_.expires_at(next->nextRefresh);
215  auto idx = std::distance(sites_.begin(), next);
216  timer_.async_wait([this, idx](boost::system::error_code const& ec) {
217  this->onTimer(idx, ec);
218  });
219  }
220 }
221 
222 void
225  std::size_t siteIdx,
226  std::lock_guard<std::mutex>& sites_lock)
227 {
228  fetching_ = true;
229  sites_[siteIdx].activeResource = resource;
231  auto timeoutCancel = [this]() {
232  std::lock_guard lock_state{state_mutex_};
233  // docs indicate cancel_one() can throw, but this
234  // should be reconsidered if it changes to noexcept
235  try
236  {
237  timer_.cancel_one();
238  }
239  catch (boost::system::system_error const&)
240  {
241  }
242  };
243  auto onFetch = [this, siteIdx, timeoutCancel](
244  error_code const& err,
245  endpoint_type const& endpoint,
246  detail::response_type&& resp) {
247  timeoutCancel();
248  onSiteFetch(err, endpoint, std::move(resp), siteIdx);
249  };
250 
251  auto onFetchFile = [this, siteIdx, timeoutCancel](
252  error_code const& err, std::string const& resp) {
253  timeoutCancel();
254  onTextFetch(err, resp, siteIdx);
255  };
256 
257  JLOG(j_.debug()) << "Starting request for " << resource->uri;
258 
259  if (resource->pUrl.scheme == "https")
260  {
261  // can throw...
262  sp = std::make_shared<detail::WorkSSL>(
263  resource->pUrl.domain,
264  resource->pUrl.path,
265  std::to_string(*resource->pUrl.port),
266  app_.getIOService(),
267  j_,
268  app_.config(),
269  sites_[siteIdx].lastRequestEndpoint,
270  sites_[siteIdx].lastRequestSuccessful,
271  onFetch);
272  }
273  else if (resource->pUrl.scheme == "http")
274  {
275  sp = std::make_shared<detail::WorkPlain>(
276  resource->pUrl.domain,
277  resource->pUrl.path,
278  std::to_string(*resource->pUrl.port),
279  app_.getIOService(),
280  sites_[siteIdx].lastRequestEndpoint,
281  sites_[siteIdx].lastRequestSuccessful,
282  onFetch);
283  }
284  else
285  {
286  BOOST_ASSERT(resource->pUrl.scheme == "file");
287  sp = std::make_shared<detail::WorkFile>(
288  resource->pUrl.path, app_.getIOService(), onFetchFile);
289  }
290 
291  sites_[siteIdx].lastRequestSuccessful = false;
292  work_ = sp;
293  sp->run();
294  // start a timer for the request, which shouldn't take more
295  // than requestTimeout_ to complete
296  std::lock_guard lock_state{state_mutex_};
297  timer_.expires_after(requestTimeout_);
298  timer_.async_wait([this, siteIdx](boost::system::error_code const& ec) {
299  this->onRequestTimeout(siteIdx, ec);
300  });
301 }
302 
303 void
305 {
306  if (ec)
307  return;
308 
309  {
310  std::lock_guard lock_site{sites_mutex_};
311  JLOG(j_.warn()) << "Request for " << sites_[siteIdx].activeResource->uri
312  << " took too long";
313  }
314 
315  std::lock_guard lock_state{state_mutex_};
316  if (auto sp = work_.lock())
317  sp->cancel();
318 }
319 
320 void
322 {
323  if (ec)
324  {
325  // Restart the timer if any errors are encountered, unless the error
326  // is from the wait operation being aborted due to a shutdown request.
327  if (ec != boost::asio::error::operation_aborted)
328  onSiteFetch(ec, {}, detail::response_type{}, siteIdx);
329  return;
330  }
331 
332  try
333  {
335  sites_[siteIdx].nextRefresh =
336  clock_type::now() + sites_[siteIdx].refreshInterval;
337  sites_[siteIdx].redirCount = 0;
338  // the WorkSSL client ctor can throw if SSL init fails
339  makeRequest(sites_[siteIdx].startingResource, siteIdx, lock);
340  }
341  catch (std::exception&)
342  {
343  onSiteFetch(
344  boost::system::error_code{-1, boost::system::generic_category()},
345  {},
347  siteIdx);
348  }
349 }
350 
351 void
353  std::string const& res,
354  std::size_t siteIdx,
355  std::lock_guard<std::mutex>& sites_lock)
356 {
357  Json::Value const body = [&res, siteIdx, this]() {
358  Json::Reader r;
359  Json::Value body;
360  if (!r.parse(res.data(), body))
361  {
362  JLOG(j_.warn()) << "Unable to parse JSON response from "
363  << sites_[siteIdx].activeResource->uri;
364  throw std::runtime_error{"bad json"};
365  }
366  return body;
367  }();
368 
369  auto const [valid, version, blobs] = [&body]() {
370  // Check the easy fields first
371  bool valid = body.isObject() && body.isMember(jss::manifest) &&
372  body[jss::manifest].isString() && body.isMember(jss::version) &&
373  body[jss::version].isInt();
374  // Check the version-specific blob & signature fields
375  std::uint32_t version;
377  if (valid)
378  {
379  version = body[jss::version].asUInt();
380  blobs = ValidatorList::parseBlobs(version, body);
381  valid = !blobs.empty();
382  }
383  return std::make_tuple(valid, version, blobs);
384  }();
385 
386  if (!valid)
387  {
388  JLOG(j_.warn()) << "Missing fields in JSON response from "
389  << sites_[siteIdx].activeResource->uri;
390  throw std::runtime_error{"missing fields"};
391  }
392 
393  auto const manifest = body[jss::manifest].asString();
394  assert(version == body[jss::version].asUInt());
395  auto const& uri = sites_[siteIdx].activeResource->uri;
396  auto const hash = sha512Half(manifest, blobs, version);
397  auto const applyResult = app_.validators().applyListsAndBroadcast(
398  manifest,
399  version,
400  blobs,
401  uri,
402  hash,
403  app_.overlay(),
405  app_.getOPs());
406 
407  sites_[siteIdx].lastRefreshStatus.emplace(
408  Site::Status{clock_type::now(), applyResult.bestDisposition(), ""});
409 
410  for (auto const& [disp, count] : applyResult.dispositions)
411  {
412  switch (disp)
413  {
415  JLOG(j_.debug()) << "Applied " << count
416  << " new validator list(s) from " << uri;
417  break;
419  JLOG(j_.debug()) << "Applied " << count
420  << " expired validator list(s) from " << uri;
421  break;
423  JLOG(j_.debug())
424  << "Ignored " << count
425  << " validator list(s) with current sequence from " << uri;
426  break;
428  JLOG(j_.debug()) << "Processed " << count
429  << " future validator list(s) from " << uri;
430  break;
432  JLOG(j_.debug())
433  << "Ignored " << count
434  << " validator list(s) with future known sequence from "
435  << uri;
436  break;
438  JLOG(j_.warn()) << "Ignored " << count
439  << "stale validator list(s) from " << uri;
440  break;
442  JLOG(j_.warn()) << "Ignored " << count
443  << " untrusted validator list(s) from " << uri;
444  break;
446  JLOG(j_.warn()) << "Ignored " << count
447  << " invalid validator list(s) from " << uri;
448  break;
450  JLOG(j_.warn())
451  << "Ignored " << count
452  << " unsupported version validator list(s) from " << uri;
453  break;
454  default:
455  BOOST_ASSERT(false);
456  }
457  }
458 
459  if (body.isMember(jss::refresh_interval) &&
460  body[jss::refresh_interval].isNumeric())
461  {
462  using namespace std::chrono_literals;
463  std::chrono::minutes const refresh = boost::algorithm::clamp(
464  std::chrono::minutes{body[jss::refresh_interval].asUInt()},
465  1min,
466  24h);
467  sites_[siteIdx].refreshInterval = refresh;
468  sites_[siteIdx].nextRefresh =
469  clock_type::now() + sites_[siteIdx].refreshInterval;
470  }
471 }
472 
476  std::size_t siteIdx,
477  std::lock_guard<std::mutex>& sites_lock)
478 {
479  using namespace boost::beast::http;
481  if (res.find(field::location) == res.end() || res[field::location].empty())
482  {
483  JLOG(j_.warn()) << "Request for validator list at "
484  << sites_[siteIdx].activeResource->uri
485  << " returned a redirect with no Location.";
486  throw std::runtime_error{"missing location"};
487  }
488 
489  if (sites_[siteIdx].redirCount == max_redirects)
490  {
491  JLOG(j_.warn()) << "Exceeded max redirects for validator list at "
492  << sites_[siteIdx].loadedResource->uri;
493  throw std::runtime_error{"max redirects"};
494  }
495 
496  JLOG(j_.debug()) << "Got redirect for validator list from "
497  << sites_[siteIdx].activeResource->uri
498  << " to new location " << res[field::location];
499 
500  try
501  {
502  newLocation =
503  std::make_shared<Site::Resource>(std::string(res[field::location]));
504  ++sites_[siteIdx].redirCount;
505  if (newLocation->pUrl.scheme != "http" &&
506  newLocation->pUrl.scheme != "https")
507  throw std::runtime_error(
508  "invalid scheme in redirect " + newLocation->pUrl.scheme);
509  }
510  catch (std::exception&)
511  {
512  JLOG(j_.error()) << "Invalid redirect location: "
513  << res[field::location];
514  throw;
515  }
516  return newLocation;
517 }
518 
519 void
521  boost::system::error_code const& ec,
522  endpoint_type const& endpoint,
523  detail::response_type&& res,
524  std::size_t siteIdx)
525 {
526  {
527  std::lock_guard lock_sites{sites_mutex_};
528  if (endpoint != endpoint_type{})
529  sites_[siteIdx].lastRequestEndpoint = endpoint;
530  JLOG(j_.debug()) << "Got completion for "
531  << sites_[siteIdx].activeResource->uri << " "
532  << endpoint;
533  auto onError = [&](std::string const& errMsg, bool retry) {
534  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
536  if (retry)
537  sites_[siteIdx].nextRefresh =
539 
540  // See if there's a copy saved locally from last time we
541  // saw the list.
542  missingSite();
543  };
544  if (ec)
545  {
546  JLOG(j_.warn())
547  << "Problem retrieving from "
548  << sites_[siteIdx].activeResource->uri << " " << endpoint << " "
549  << ec.value() << ":" << ec.message();
550  onError("fetch error", true);
551  }
552  else
553  {
554  try
555  {
556  using namespace boost::beast::http;
557  switch (res.result())
558  {
559  case status::ok:
560  sites_[siteIdx].lastRequestSuccessful = true;
561  parseJsonResponse(res.body(), siteIdx, lock_sites);
562  break;
563  case status::moved_permanently:
564  case status::permanent_redirect:
565  case status::found:
566  case status::temporary_redirect: {
567  auto newLocation =
568  processRedirect(res, siteIdx, lock_sites);
569  assert(newLocation);
570  // for perm redirects, also update our starting URI
571  if (res.result() == status::moved_permanently ||
572  res.result() == status::permanent_redirect)
573  {
574  sites_[siteIdx].startingResource = newLocation;
575  }
576  makeRequest(newLocation, siteIdx, lock_sites);
577  return; // we are still fetching, so skip
578  // state update/notify below
579  }
580  default: {
581  JLOG(j_.warn())
582  << "Request for validator list at "
583  << sites_[siteIdx].activeResource->uri << " "
584  << endpoint
585  << " returned bad status: " << res.result_int();
586  onError("bad result code", true);
587  }
588  }
589  }
590  catch (std::exception& ex)
591  {
592  onError(ex.what(), false);
593  }
594  }
595  sites_[siteIdx].activeResource.reset();
596  }
597 
598  std::lock_guard lock_state{state_mutex_};
599  fetching_ = false;
600  if (!stopping_)
601  setTimer(lock_state);
602  cv_.notify_all();
603 }
604 
605 void
607  boost::system::error_code const& ec,
608  std::string const& res,
609  std::size_t siteIdx)
610 {
611  {
612  std::lock_guard lock_sites{sites_mutex_};
613  try
614  {
615  if (ec)
616  {
617  JLOG(j_.warn()) << "Problem retrieving from "
618  << sites_[siteIdx].activeResource->uri << " "
619  << ec.value() << ": " << ec.message();
620  throw std::runtime_error{"fetch error"};
621  }
622 
623  sites_[siteIdx].lastRequestSuccessful = true;
624 
625  parseJsonResponse(res, siteIdx, lock_sites);
626  }
627  catch (std::exception& ex)
628  {
629  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
631  }
632  sites_[siteIdx].activeResource.reset();
633  }
634 
635  std::lock_guard lock_state{state_mutex_};
636  fetching_ = false;
637  if (!stopping_)
638  setTimer(lock_state);
639  cv_.notify_all();
640 }
641 
644 {
645  using namespace std::chrono;
646  using Int = Json::Value::Int;
647 
649  Json::Value& jSites = (jrr[jss::validator_sites] = Json::arrayValue);
650  {
652  for (Site const& site : sites_)
653  {
654  Json::Value& v = jSites.append(Json::objectValue);
655  std::stringstream uri;
656  uri << site.loadedResource->uri;
657  if (site.loadedResource != site.startingResource)
658  uri << " (redirects to " << site.startingResource->uri + ")";
659  v[jss::uri] = uri.str();
660  v[jss::next_refresh_time] = to_string(site.nextRefresh);
661  if (site.lastRefreshStatus)
662  {
663  v[jss::last_refresh_time] =
664  to_string(site.lastRefreshStatus->refreshed);
665  v[jss::last_refresh_status] =
666  to_string(site.lastRefreshStatus->disposition);
667  if (!site.lastRefreshStatus->message.empty())
668  v[jss::last_refresh_message] =
669  site.lastRefreshStatus->message;
670  }
671  v[jss::refresh_interval_min] =
672  static_cast<Int>(site.refreshInterval.count());
673  }
674  }
675  return jrr;
676 }
677 } // 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:103
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:125
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:37
ripple::ValidatorSite::stop
void stop()
Stop fetching lists from sites.
Definition: ValidatorSite.cpp:175
std::chrono::minutes
ripple::ValidatorSite::onRequestTimeout
void onRequestTimeout(std::size_t siteIdx, error_code const &ec)
request took too long
Definition: ValidatorSite.cpp:304
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:124
std::lock_guard
STL class.
std::distance
T distance(T... args)
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:109
ripple::ValidatorSite::processRedirect
std::shared_ptr< Site::Resource > processRedirect(detail::response_type &res, std::size_t siteIdx, std::lock_guard< std::mutex > &lock)
Interpret a redirect response.
Definition: ValidatorSite.cpp:474
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:520
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:121
algorithm
ripple::ValidatorSite::fetching_
std::atomic< bool > fetching_
Definition: ValidatorSite.h:128
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::ValidatorSite::~ValidatorSite
~ValidatorSite()
Definition: ValidatorSite.cpp:103
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
ripple::ValidatorSite::parseJsonResponse
void parseJsonResponse(std::string const &res, std::size_t siteIdx, std::lock_guard< std::mutex > &lock)
Parse json response from validator list site.
Definition: ValidatorSite.cpp:352
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:131
ripple::parsedURL::port
std::optional< std::uint16_t > port
Definition: StringUtilities.h:108
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:643
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:123
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:168
std::uint32_t
std::condition_variable::wait
T wait(T... args)
ripple::error_retry_interval
constexpr auto error_retry_interval
Definition: ValidatorSite.cpp:36
ripple::ValidatorSite::sites_mutex_
std::mutex sites_mutex_
Definition: ValidatorSite.h:120
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:135
ripple::Application::getIOService
virtual boost::asio::io_service & getIOService()=0
ripple::ValidatorSite::makeRequest
void makeRequest(std::shared_ptr< Site::Resource > resource, std::size_t siteIdx, std::lock_guard< std::mutex > &lock)
Initiate request to given resource.
Definition: ValidatorSite.cpp:223
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:138
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
ripple::ListDisposition::same_sequence
@ same_sequence
Same sequence as current list.
ripple::ValidatorSite::Site::Resource::Resource
Resource(std::string uri_)
Definition: ValidatorSite.cpp:39
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:606
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:132
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:89
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:78
ripple::ValidatorSite::missingSite
bool missingSite()
If no sites are provided, or a site fails to load, get a list of local cache files from the Validator...
Definition: ValidatorSite.cpp:121
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:104
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:39
ripple::ValidatorSite::start
void start()
Start fetching lists from sites.
Definition: ValidatorSite.cpp:160
ripple::ValidatorSite::onTimer
void onTimer(std::size_t siteIdx, error_code const &ec)
Fetch site whose time has come.
Definition: ValidatorSite.cpp:321
ripple::parsedURL::domain
std::string domain
Definition: StringUtilities.h:107
ripple::ValidatorSite::error_code
boost::system::error_code error_code
Definition: ValidatorSite.h:74
ripple::ValidatorSite::setTimer
void setTimer(std::lock_guard< std::mutex > &)
Queue next site to be fetched lock over state_mutex_ required.
Definition: ValidatorSite.cpp:201
std::string::data
T data(T... args)
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:128
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:35
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)