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&)
361  {
362  onSiteFetch(
363  boost::system::error_code{-1, boost::system::generic_category()},
364  {},
366  siteIdx);
367  }
368 }
369 
370 void
372  std::string const& res,
373  std::size_t siteIdx,
374  std::lock_guard<std::mutex> const& sites_lock)
375 {
376  Json::Value const body = [&res, siteIdx, this]() {
377  Json::Reader r;
378  Json::Value body;
379  if (!r.parse(res.data(), body))
380  {
381  JLOG(j_.warn()) << "Unable to parse JSON response from "
382  << sites_[siteIdx].activeResource->uri;
383  throw std::runtime_error{"bad json"};
384  }
385  return body;
386  }();
387 
388  auto const [valid, version, blobs] = [&body]() {
389  // Check the easy fields first
390  bool valid = body.isObject() && body.isMember(jss::manifest) &&
391  body[jss::manifest].isString() && body.isMember(jss::version) &&
392  body[jss::version].isInt();
393  // Check the version-specific blob & signature fields
394  std::uint32_t version;
396  if (valid)
397  {
398  version = body[jss::version].asUInt();
399  blobs = ValidatorList::parseBlobs(version, body);
400  valid = !blobs.empty();
401  }
402  return std::make_tuple(valid, version, blobs);
403  }();
404 
405  if (!valid)
406  {
407  JLOG(j_.warn()) << "Missing fields in JSON response from "
408  << sites_[siteIdx].activeResource->uri;
409  throw std::runtime_error{"missing fields"};
410  }
411 
412  auto const manifest = body[jss::manifest].asString();
413  assert(version == body[jss::version].asUInt());
414  auto const& uri = sites_[siteIdx].activeResource->uri;
415  auto const hash = sha512Half(manifest, blobs, version);
416  auto const applyResult = app_.validators().applyListsAndBroadcast(
417  manifest,
418  version,
419  blobs,
420  uri,
421  hash,
422  app_.overlay(),
424  app_.getOPs());
425 
426  sites_[siteIdx].lastRefreshStatus.emplace(
427  Site::Status{clock_type::now(), applyResult.bestDisposition(), ""});
428 
429  for (auto const& [disp, count] : applyResult.dispositions)
430  {
431  switch (disp)
432  {
434  JLOG(j_.debug()) << "Applied " << count
435  << " new validator list(s) from " << uri;
436  break;
438  JLOG(j_.debug()) << "Applied " << count
439  << " expired validator list(s) from " << uri;
440  break;
442  JLOG(j_.debug())
443  << "Ignored " << count
444  << " validator list(s) with current sequence from " << uri;
445  break;
447  JLOG(j_.debug()) << "Processed " << count
448  << " future validator list(s) from " << uri;
449  break;
451  JLOG(j_.debug())
452  << "Ignored " << count
453  << " validator list(s) with future known sequence from "
454  << uri;
455  break;
457  JLOG(j_.warn()) << "Ignored " << count
458  << "stale validator list(s) from " << uri;
459  break;
461  JLOG(j_.warn()) << "Ignored " << count
462  << " untrusted validator list(s) from " << uri;
463  break;
465  JLOG(j_.warn()) << "Ignored " << count
466  << " invalid validator list(s) from " << uri;
467  break;
469  JLOG(j_.warn())
470  << "Ignored " << count
471  << " unsupported version validator list(s) from " << uri;
472  break;
473  default:
474  BOOST_ASSERT(false);
475  }
476  }
477 
478  if (body.isMember(jss::refresh_interval) &&
479  body[jss::refresh_interval].isNumeric())
480  {
481  using namespace std::chrono_literals;
482  std::chrono::minutes const refresh = std::clamp(
483  std::chrono::minutes{body[jss::refresh_interval].asUInt()},
484  1min,
485  std::chrono::minutes{24h});
486  sites_[siteIdx].refreshInterval = refresh;
487  sites_[siteIdx].nextRefresh =
488  clock_type::now() + sites_[siteIdx].refreshInterval;
489  }
490 }
491 
495  std::size_t siteIdx,
496  std::lock_guard<std::mutex> const& sites_lock)
497 {
498  using namespace boost::beast::http;
500  if (res.find(field::location) == res.end() || res[field::location].empty())
501  {
502  JLOG(j_.warn()) << "Request for validator list at "
503  << sites_[siteIdx].activeResource->uri
504  << " returned a redirect with no Location.";
505  throw std::runtime_error{"missing location"};
506  }
507 
508  if (sites_[siteIdx].redirCount == max_redirects)
509  {
510  JLOG(j_.warn()) << "Exceeded max redirects for validator list at "
511  << sites_[siteIdx].loadedResource->uri;
512  throw std::runtime_error{"max redirects"};
513  }
514 
515  JLOG(j_.debug()) << "Got redirect for validator list from "
516  << sites_[siteIdx].activeResource->uri
517  << " to new location " << res[field::location];
518 
519  try
520  {
521  newLocation =
522  std::make_shared<Site::Resource>(std::string(res[field::location]));
523  ++sites_[siteIdx].redirCount;
524  if (newLocation->pUrl.scheme != "http" &&
525  newLocation->pUrl.scheme != "https")
526  throw std::runtime_error(
527  "invalid scheme in redirect " + newLocation->pUrl.scheme);
528  }
529  catch (std::exception&)
530  {
531  JLOG(j_.error()) << "Invalid redirect location: "
532  << res[field::location];
533  throw;
534  }
535  return newLocation;
536 }
537 
538 void
540  boost::system::error_code const& ec,
541  endpoint_type const& endpoint,
542  detail::response_type&& res,
543  std::size_t siteIdx)
544 {
545  std::lock_guard lock_sites{sites_mutex_};
546  {
547  if (endpoint != endpoint_type{})
548  sites_[siteIdx].lastRequestEndpoint = endpoint;
549  JLOG(j_.debug()) << "Got completion for "
550  << sites_[siteIdx].activeResource->uri << " "
551  << endpoint;
552  auto onError = [&](std::string const& errMsg, bool retry) {
553  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
555  if (retry)
556  sites_[siteIdx].nextRefresh =
558 
559  // See if there's a copy saved locally from last time we
560  // saw the list.
561  missingSite(lock_sites);
562  };
563  if (ec)
564  {
565  JLOG(j_.warn())
566  << "Problem retrieving from "
567  << sites_[siteIdx].activeResource->uri << " " << endpoint << " "
568  << ec.value() << ":" << ec.message();
569  onError("fetch error", true);
570  }
571  else
572  {
573  try
574  {
575  using namespace boost::beast::http;
576  switch (res.result())
577  {
578  case status::ok:
579  sites_[siteIdx].lastRequestSuccessful = true;
580  parseJsonResponse(res.body(), siteIdx, lock_sites);
581  break;
582  case status::moved_permanently:
583  case status::permanent_redirect:
584  case status::found:
585  case status::temporary_redirect: {
586  auto newLocation =
587  processRedirect(res, siteIdx, lock_sites);
588  assert(newLocation);
589  // for perm redirects, also update our starting URI
590  if (res.result() == status::moved_permanently ||
591  res.result() == status::permanent_redirect)
592  {
593  sites_[siteIdx].startingResource = newLocation;
594  }
595  makeRequest(newLocation, siteIdx, lock_sites);
596  return; // we are still fetching, so skip
597  // state update/notify below
598  }
599  default: {
600  JLOG(j_.warn())
601  << "Request for validator list at "
602  << sites_[siteIdx].activeResource->uri << " "
603  << endpoint
604  << " returned bad status: " << res.result_int();
605  onError("bad result code", true);
606  }
607  }
608  }
609  catch (std::exception& ex)
610  {
611  onError(ex.what(), false);
612  }
613  }
614  sites_[siteIdx].activeResource.reset();
615  }
616 
617  std::lock_guard lock_state{state_mutex_};
618  fetching_ = false;
619  if (!stopping_)
620  setTimer(lock_sites, lock_state);
621  cv_.notify_all();
622 }
623 
624 void
626  boost::system::error_code const& ec,
627  std::string const& res,
628  std::size_t siteIdx)
629 {
630  std::lock_guard lock_sites{sites_mutex_};
631  {
632  try
633  {
634  if (ec)
635  {
636  JLOG(j_.warn()) << "Problem retrieving from "
637  << sites_[siteIdx].activeResource->uri << " "
638  << ec.value() << ": " << ec.message();
639  throw std::runtime_error{"fetch error"};
640  }
641 
642  sites_[siteIdx].lastRequestSuccessful = true;
643 
644  parseJsonResponse(res, siteIdx, lock_sites);
645  }
646  catch (std::exception& ex)
647  {
648  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
650  }
651  sites_[siteIdx].activeResource.reset();
652  }
653 
654  std::lock_guard lock_state{state_mutex_};
655  fetching_ = false;
656  if (!stopping_)
657  setTimer(lock_sites, lock_state);
658  cv_.notify_all();
659 }
660 
663 {
664  using namespace std::chrono;
665  using Int = Json::Value::Int;
666 
668  Json::Value& jSites = (jrr[jss::validator_sites] = Json::arrayValue);
669  {
671  for (Site const& site : sites_)
672  {
673  Json::Value& v = jSites.append(Json::objectValue);
674  std::stringstream uri;
675  uri << site.loadedResource->uri;
676  if (site.loadedResource != site.startingResource)
677  uri << " (redirects to " << site.startingResource->uri + ")";
678  v[jss::uri] = uri.str();
679  v[jss::next_refresh_time] = to_string(site.nextRefresh);
680  if (site.lastRefreshStatus)
681  {
682  v[jss::last_refresh_time] =
683  to_string(site.lastRefreshStatus->refreshed);
684  v[jss::last_refresh_status] =
685  to_string(site.lastRefreshStatus->disposition);
686  if (!site.lastRefreshStatus->message.empty())
687  v[jss::last_refresh_message] =
688  site.lastRefreshStatus->message;
689  }
690  v[jss::refresh_interval_min] =
691  static_cast<Int>(site.refreshInterval.count());
692  }
693  }
694  return jrr;
695 }
696 } // 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:539
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:662
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:371
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:493
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:625
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)