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