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  // In some circumstances, both this function and the response
320  // handler (onSiteFetch or onTextFetch) can get queued and
321  // processed. In all observed cases, the response handler
322  // processes a network error. Usually, this function runs first,
323  // but on extremely rare occasions, the response handler can run
324  // first, which will leave activeResource empty.
325  auto const& site = sites_[siteIdx];
326  if (site.activeResource)
327  JLOG(j_.warn()) << "Request for " << site.activeResource->uri
328  << " took too long";
329  else
330  JLOG(j_.error()) << "Request took too long, but a response has "
331  "already been processed";
332  }
333 
334  std::lock_guard lock_state{state_mutex_};
335  if (auto sp = work_.lock())
336  sp->cancel();
337 }
338 
339 void
341 {
342  if (ec)
343  {
344  // Restart the timer if any errors are encountered, unless the error
345  // is from the wait operation being aborted due to a shutdown request.
346  if (ec != boost::asio::error::operation_aborted)
347  onSiteFetch(ec, {}, detail::response_type{}, siteIdx);
348  return;
349  }
350 
351  try
352  {
354  sites_[siteIdx].nextRefresh =
355  clock_type::now() + sites_[siteIdx].refreshInterval;
356  sites_[siteIdx].redirCount = 0;
357  // the WorkSSL client ctor can throw if SSL init fails
358  makeRequest(sites_[siteIdx].startingResource, siteIdx, lock);
359  }
360  catch (std::exception const& ex)
361  {
362  JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what();
363  onSiteFetch(
364  boost::system::error_code{-1, boost::system::generic_category()},
365  {},
367  siteIdx);
368  }
369 }
370 
371 void
373  std::string const& res,
374  std::size_t siteIdx,
375  std::lock_guard<std::mutex> const& sites_lock)
376 {
377  Json::Value const body = [&res, siteIdx, this]() {
378  Json::Reader r;
379  Json::Value body;
380  if (!r.parse(res.data(), body))
381  {
382  JLOG(j_.warn()) << "Unable to parse JSON response from "
383  << sites_[siteIdx].activeResource->uri;
384  throw std::runtime_error{"bad json"};
385  }
386  return body;
387  }();
388 
389  auto const [valid, version, blobs] = [&body]() {
390  // Check the easy fields first
391  bool valid = body.isObject() && body.isMember(jss::manifest) &&
392  body[jss::manifest].isString() && body.isMember(jss::version) &&
393  body[jss::version].isInt();
394  // Check the version-specific blob & signature fields
395  std::uint32_t version;
397  if (valid)
398  {
399  version = body[jss::version].asUInt();
400  blobs = ValidatorList::parseBlobs(version, body);
401  valid = !blobs.empty();
402  }
403  return std::make_tuple(valid, version, blobs);
404  }();
405 
406  if (!valid)
407  {
408  JLOG(j_.warn()) << "Missing fields in JSON response from "
409  << sites_[siteIdx].activeResource->uri;
410  throw std::runtime_error{"missing fields"};
411  }
412 
413  auto const manifest = body[jss::manifest].asString();
414  assert(version == body[jss::version].asUInt());
415  auto const& uri = sites_[siteIdx].activeResource->uri;
416  auto const hash = sha512Half(manifest, blobs, version);
417  auto const applyResult = app_.validators().applyListsAndBroadcast(
418  manifest,
419  version,
420  blobs,
421  uri,
422  hash,
423  app_.overlay(),
425  app_.getOPs());
426 
427  sites_[siteIdx].lastRefreshStatus.emplace(
428  Site::Status{clock_type::now(), applyResult.bestDisposition(), ""});
429 
430  for (auto const& [disp, count] : applyResult.dispositions)
431  {
432  switch (disp)
433  {
435  JLOG(j_.debug()) << "Applied " << count
436  << " new validator list(s) from " << uri;
437  break;
439  JLOG(j_.debug()) << "Applied " << count
440  << " expired validator list(s) from " << uri;
441  break;
443  JLOG(j_.debug())
444  << "Ignored " << count
445  << " validator list(s) with current sequence from " << uri;
446  break;
448  JLOG(j_.debug()) << "Processed " << count
449  << " future validator list(s) from " << uri;
450  break;
452  JLOG(j_.debug())
453  << "Ignored " << count
454  << " validator list(s) with future known sequence from "
455  << uri;
456  break;
458  JLOG(j_.warn()) << "Ignored " << count
459  << "stale validator list(s) from " << uri;
460  break;
462  JLOG(j_.warn()) << "Ignored " << count
463  << " untrusted validator list(s) from " << uri;
464  break;
466  JLOG(j_.warn()) << "Ignored " << count
467  << " invalid validator list(s) from " << uri;
468  break;
470  JLOG(j_.warn())
471  << "Ignored " << count
472  << " unsupported version validator list(s) from " << uri;
473  break;
474  default:
475  BOOST_ASSERT(false);
476  }
477  }
478 
479  if (body.isMember(jss::refresh_interval) &&
480  body[jss::refresh_interval].isNumeric())
481  {
482  using namespace std::chrono_literals;
483  std::chrono::minutes const refresh = std::clamp(
484  std::chrono::minutes{body[jss::refresh_interval].asUInt()},
485  1min,
486  std::chrono::minutes{24h});
487  sites_[siteIdx].refreshInterval = refresh;
488  sites_[siteIdx].nextRefresh =
489  clock_type::now() + sites_[siteIdx].refreshInterval;
490  }
491 }
492 
496  std::size_t siteIdx,
497  std::lock_guard<std::mutex> const& sites_lock)
498 {
499  using namespace boost::beast::http;
501  if (res.find(field::location) == res.end() || res[field::location].empty())
502  {
503  JLOG(j_.warn()) << "Request for validator list at "
504  << sites_[siteIdx].activeResource->uri
505  << " returned a redirect with no Location.";
506  throw std::runtime_error{"missing location"};
507  }
508 
509  if (sites_[siteIdx].redirCount == max_redirects)
510  {
511  JLOG(j_.warn()) << "Exceeded max redirects for validator list at "
512  << sites_[siteIdx].loadedResource->uri;
513  throw std::runtime_error{"max redirects"};
514  }
515 
516  JLOG(j_.debug()) << "Got redirect for validator list from "
517  << sites_[siteIdx].activeResource->uri
518  << " to new location " << res[field::location];
519 
520  try
521  {
522  newLocation =
523  std::make_shared<Site::Resource>(std::string(res[field::location]));
524  ++sites_[siteIdx].redirCount;
525  if (newLocation->pUrl.scheme != "http" &&
526  newLocation->pUrl.scheme != "https")
527  throw std::runtime_error(
528  "invalid scheme in redirect " + newLocation->pUrl.scheme);
529  }
530  catch (std::exception const& ex)
531  {
532  JLOG(j_.error()) << "Invalid redirect location: "
533  << res[field::location];
534  throw;
535  }
536  return newLocation;
537 }
538 
539 void
541  boost::system::error_code const& ec,
542  endpoint_type const& endpoint,
543  detail::response_type&& res,
544  std::size_t siteIdx)
545 {
546  std::lock_guard lock_sites{sites_mutex_};
547  {
548  if (endpoint != endpoint_type{})
549  sites_[siteIdx].lastRequestEndpoint = endpoint;
550  JLOG(j_.debug()) << "Got completion for "
551  << sites_[siteIdx].activeResource->uri << " "
552  << endpoint;
553  auto onError = [&](std::string const& errMsg, bool retry) {
554  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
556  if (retry)
557  sites_[siteIdx].nextRefresh =
559 
560  // See if there's a copy saved locally from last time we
561  // saw the list.
562  missingSite(lock_sites);
563  };
564  if (ec)
565  {
566  JLOG(j_.warn())
567  << "Problem retrieving from "
568  << sites_[siteIdx].activeResource->uri << " " << endpoint << " "
569  << ec.value() << ":" << ec.message();
570  onError("fetch error", true);
571  }
572  else
573  {
574  try
575  {
576  using namespace boost::beast::http;
577  switch (res.result())
578  {
579  case status::ok:
580  sites_[siteIdx].lastRequestSuccessful = true;
581  parseJsonResponse(res.body(), siteIdx, lock_sites);
582  break;
583  case status::moved_permanently:
584  case status::permanent_redirect:
585  case status::found:
586  case status::temporary_redirect: {
587  auto newLocation =
588  processRedirect(res, siteIdx, lock_sites);
589  assert(newLocation);
590  // for perm redirects, also update our starting URI
591  if (res.result() == status::moved_permanently ||
592  res.result() == status::permanent_redirect)
593  {
594  sites_[siteIdx].startingResource = newLocation;
595  }
596  makeRequest(newLocation, siteIdx, lock_sites);
597  return; // we are still fetching, so skip
598  // state update/notify below
599  }
600  default: {
601  JLOG(j_.warn())
602  << "Request for validator list at "
603  << sites_[siteIdx].activeResource->uri << " "
604  << endpoint
605  << " returned bad status: " << res.result_int();
606  onError("bad result code", true);
607  }
608  }
609  }
610  catch (std::exception const& ex)
611  {
612  JLOG(j_.error())
613  << "Exception in " << __func__ << ": " << ex.what();
614  onError(ex.what(), false);
615  }
616  }
617  sites_[siteIdx].activeResource.reset();
618  }
619 
620  std::lock_guard lock_state{state_mutex_};
621  fetching_ = false;
622  if (!stopping_)
623  setTimer(lock_sites, lock_state);
624  cv_.notify_all();
625 }
626 
627 void
629  boost::system::error_code const& ec,
630  std::string const& res,
631  std::size_t siteIdx)
632 {
633  std::lock_guard lock_sites{sites_mutex_};
634  {
635  try
636  {
637  if (ec)
638  {
639  JLOG(j_.warn()) << "Problem retrieving from "
640  << sites_[siteIdx].activeResource->uri << " "
641  << ec.value() << ": " << ec.message();
642  throw std::runtime_error{"fetch error"};
643  }
644 
645  sites_[siteIdx].lastRequestSuccessful = true;
646 
647  parseJsonResponse(res, siteIdx, lock_sites);
648  }
649  catch (std::exception const& ex)
650  {
651  JLOG(j_.error())
652  << "Exception in " << __func__ << ": " << ex.what();
653  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
655  }
656  sites_[siteIdx].activeResource.reset();
657  }
658 
659  std::lock_guard lock_state{state_mutex_};
660  fetching_ = false;
661  if (!stopping_)
662  setTimer(lock_sites, lock_state);
663  cv_.notify_all();
664 }
665 
668 {
669  using namespace std::chrono;
670  using Int = Json::Value::Int;
671 
673  Json::Value& jSites = (jrr[jss::validator_sites] = Json::arrayValue);
674  {
676  for (Site const& site : sites_)
677  {
678  Json::Value& v = jSites.append(Json::objectValue);
679  std::stringstream uri;
680  uri << site.loadedResource->uri;
681  if (site.loadedResource != site.startingResource)
682  uri << " (redirects to " << site.startingResource->uri + ")";
683  v[jss::uri] = uri.str();
684  v[jss::next_refresh_time] = to_string(site.nextRefresh);
685  if (site.lastRefreshStatus)
686  {
687  v[jss::last_refresh_time] =
688  to_string(site.lastRefreshStatus->refreshed);
689  v[jss::last_refresh_status] =
690  to_string(site.lastRefreshStatus->disposition);
691  if (!site.lastRefreshStatus->message.empty())
692  v[jss::last_refresh_message] =
693  site.lastRefreshStatus->message;
694  }
695  v[jss::refresh_interval_min] =
696  static_cast<Int>(site.refreshInterval.count());
697  }
698  }
699  return jrr;
700 }
701 } // 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:540
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:667
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:372
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:494
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:628
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:340
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)