diff --git a/OverlayImpl_8cpp_source.html b/OverlayImpl_8cpp_source.html index 1f264af552..4f3e754807 100644 --- a/OverlayImpl_8cpp_source.html +++ b/OverlayImpl_8cpp_source.html @@ -1839,7 +1839,7 @@ $(function() {
ripple::OverlayImpl::getOverlayInfo
Json::Value getOverlayInfo()
Returns information about peers on the overlay network.
Definition: OverlayImpl.cpp:801
ripple::OverlayImpl::io_service_
boost::asio::io_service & io_service_
Definition: OverlayImpl.h:100
ripple::Application::config
virtual Config & config()=0
-
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:651
+
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:662
ripple::Config::IPS_FIXED
std::vector< std::string > IPS_FIXED
Definition: Config.h:130
ripple::ServerHandlerImp
Definition: ServerHandlerImp.h:47
ripple::Config::standalone
bool standalone() const
Definition: Config.h:313
diff --git a/ValidatorListSites_8cpp_source.html b/ValidatorListSites_8cpp_source.html index dce35af440..3e61e53d9e 100644 --- a/ValidatorListSites_8cpp_source.html +++ b/ValidatorListSites_8cpp_source.html @@ -114,7 +114,7 @@ $(function() {
ripple::rpcREPORTING_UNSUPPORTED
@ rpcREPORTING_UNSUPPORTED
Definition: ErrorCodes.h:141
ripple::Config::reporting
bool reporting() const
Definition: Config.h:318
ripple::Application::config
virtual Config & config()=0
-
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:651
+
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:662
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
Json::Value
Represents a JSON value.
Definition: json_value.h:145
diff --git a/ValidatorSite_8cpp_source.html b/ValidatorSite_8cpp_source.html index 72e17904b7..5103d52860 100644 --- a/ValidatorSite_8cpp_source.html +++ b/ValidatorSite_8cpp_source.html @@ -387,373 +387,384 @@ $(function() {
316 
317  {
318  std::lock_guard lock_site{sites_mutex_};
-
319  JLOG(j_.warn()) << "Request for " << sites_[siteIdx].activeResource->uri
-
320  << " took too long";
-
321  }
-
322 
-
323  std::lock_guard lock_state{state_mutex_};
-
324  if (auto sp = work_.lock())
-
325  sp->cancel();
-
326 }
-
327 
-
328 void
-
329 ValidatorSite::onTimer(std::size_t siteIdx, error_code const& ec)
-
330 {
-
331  if (ec)
-
332  {
-
333  // Restart the timer if any errors are encountered, unless the error
-
334  // is from the wait operation being aborted due to a shutdown request.
-
335  if (ec != boost::asio::error::operation_aborted)
-
336  onSiteFetch(ec, {}, detail::response_type{}, siteIdx);
-
337  return;
-
338  }
-
339 
-
340  try
-
341  {
-
342  std::lock_guard lock{sites_mutex_};
-
343  sites_[siteIdx].nextRefresh =
-
344  clock_type::now() + sites_[siteIdx].refreshInterval;
-
345  sites_[siteIdx].redirCount = 0;
-
346  // the WorkSSL client ctor can throw if SSL init fails
-
347  makeRequest(sites_[siteIdx].startingResource, siteIdx, lock);
-
348  }
-
349  catch (std::exception&)
-
350  {
-
351  onSiteFetch(
-
352  boost::system::error_code{-1, boost::system::generic_category()},
-
353  {},
-
354  detail::response_type{},
-
355  siteIdx);
-
356  }
-
357 }
-
358 
-
359 void
-
360 ValidatorSite::parseJsonResponse(
-
361  std::string const& res,
-
362  std::size_t siteIdx,
-
363  std::lock_guard<std::mutex> const& sites_lock)
-
364 {
-
365  Json::Value const body = [&res, siteIdx, this]() {
-
366  Json::Reader r;
-
367  Json::Value body;
-
368  if (!r.parse(res.data(), body))
-
369  {
-
370  JLOG(j_.warn()) << "Unable to parse JSON response from "
-
371  << sites_[siteIdx].activeResource->uri;
-
372  throw std::runtime_error{"bad json"};
-
373  }
-
374  return body;
-
375  }();
-
376 
-
377  auto const [valid, version, blobs] = [&body]() {
-
378  // Check the easy fields first
-
379  bool valid = body.isObject() && body.isMember(jss::manifest) &&
-
380  body[jss::manifest].isString() && body.isMember(jss::version) &&
-
381  body[jss::version].isInt();
-
382  // Check the version-specific blob & signature fields
-
383  std::uint32_t version;
-
384  std::vector<ValidatorBlobInfo> blobs;
-
385  if (valid)
-
386  {
-
387  version = body[jss::version].asUInt();
-
388  blobs = ValidatorList::parseBlobs(version, body);
-
389  valid = !blobs.empty();
-
390  }
-
391  return std::make_tuple(valid, version, blobs);
-
392  }();
-
393 
-
394  if (!valid)
-
395  {
-
396  JLOG(j_.warn()) << "Missing fields in JSON response from "
-
397  << sites_[siteIdx].activeResource->uri;
-
398  throw std::runtime_error{"missing fields"};
-
399  }
-
400 
-
401  auto const manifest = body[jss::manifest].asString();
-
402  assert(version == body[jss::version].asUInt());
-
403  auto const& uri = sites_[siteIdx].activeResource->uri;
-
404  auto const hash = sha512Half(manifest, blobs, version);
-
405  auto const applyResult = app_.validators().applyListsAndBroadcast(
-
406  manifest,
-
407  version,
-
408  blobs,
-
409  uri,
-
410  hash,
-
411  app_.overlay(),
-
412  app_.getHashRouter(),
-
413  app_.getOPs());
-
414 
-
415  sites_[siteIdx].lastRefreshStatus.emplace(
-
416  Site::Status{clock_type::now(), applyResult.bestDisposition(), ""});
-
417 
-
418  for (auto const& [disp, count] : applyResult.dispositions)
-
419  {
-
420  switch (disp)
-
421  {
-
422  case ListDisposition::accepted:
-
423  JLOG(j_.debug()) << "Applied " << count
-
424  << " new validator list(s) from " << uri;
-
425  break;
-
426  case ListDisposition::expired:
-
427  JLOG(j_.debug()) << "Applied " << count
-
428  << " expired validator list(s) from " << uri;
-
429  break;
-
430  case ListDisposition::same_sequence:
-
431  JLOG(j_.debug())
-
432  << "Ignored " << count
-
433  << " validator list(s) with current sequence from " << uri;
-
434  break;
-
435  case ListDisposition::pending:
-
436  JLOG(j_.debug()) << "Processed " << count
-
437  << " future validator list(s) from " << uri;
-
438  break;
-
439  case ListDisposition::known_sequence:
-
440  JLOG(j_.debug())
-
441  << "Ignored " << count
-
442  << " validator list(s) with future known sequence from "
-
443  << uri;
-
444  break;
-
445  case ListDisposition::stale:
-
446  JLOG(j_.warn()) << "Ignored " << count
-
447  << "stale validator list(s) from " << uri;
-
448  break;
-
449  case ListDisposition::untrusted:
-
450  JLOG(j_.warn()) << "Ignored " << count
-
451  << " untrusted validator list(s) from " << uri;
-
452  break;
-
453  case ListDisposition::invalid:
-
454  JLOG(j_.warn()) << "Ignored " << count
-
455  << " invalid validator list(s) from " << uri;
-
456  break;
-
457  case ListDisposition::unsupported_version:
-
458  JLOG(j_.warn())
-
459  << "Ignored " << count
-
460  << " unsupported version validator list(s) from " << uri;
-
461  break;
-
462  default:
-
463  BOOST_ASSERT(false);
-
464  }
-
465  }
-
466 
-
467  if (body.isMember(jss::refresh_interval) &&
-
468  body[jss::refresh_interval].isNumeric())
-
469  {
-
470  using namespace std::chrono_literals;
-
471  std::chrono::minutes const refresh = std::clamp(
-
472  std::chrono::minutes{body[jss::refresh_interval].asUInt()},
-
473  1min,
-
474  std::chrono::minutes{24h});
-
475  sites_[siteIdx].refreshInterval = refresh;
-
476  sites_[siteIdx].nextRefresh =
-
477  clock_type::now() + sites_[siteIdx].refreshInterval;
-
478  }
-
479 }
-
480 
-
481 std::shared_ptr<ValidatorSite::Site::Resource>
-
482 ValidatorSite::processRedirect(
-
483  detail::response_type& res,
-
484  std::size_t siteIdx,
-
485  std::lock_guard<std::mutex> const& sites_lock)
-
486 {
-
487  using namespace boost::beast::http;
-
488  std::shared_ptr<Site::Resource> newLocation;
-
489  if (res.find(field::location) == res.end() || res[field::location].empty())
-
490  {
-
491  JLOG(j_.warn()) << "Request for validator list at "
-
492  << sites_[siteIdx].activeResource->uri
-
493  << " returned a redirect with no Location.";
-
494  throw std::runtime_error{"missing location"};
-
495  }
-
496 
-
497  if (sites_[siteIdx].redirCount == max_redirects)
-
498  {
-
499  JLOG(j_.warn()) << "Exceeded max redirects for validator list at "
-
500  << sites_[siteIdx].loadedResource->uri;
-
501  throw std::runtime_error{"max redirects"};
-
502  }
-
503 
-
504  JLOG(j_.debug()) << "Got redirect for validator list from "
-
505  << sites_[siteIdx].activeResource->uri
-
506  << " to new location " << res[field::location];
+
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
+
340 ValidatorSite::onTimer(std::size_t siteIdx, error_code const& ec)
+
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  {
+
353  std::lock_guard lock{sites_mutex_};
+
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  {},
+
365  detail::response_type{},
+
366  siteIdx);
+
367  }
+
368 }
+
369 
+
370 void
+
371 ValidatorSite::parseJsonResponse(
+
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;
+
395  std::vector<ValidatorBlobInfo> blobs;
+
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(),
+
423  app_.getHashRouter(),
+
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  {
+
433  case ListDisposition::accepted:
+
434  JLOG(j_.debug()) << "Applied " << count
+
435  << " new validator list(s) from " << uri;
+
436  break;
+
437  case ListDisposition::expired:
+
438  JLOG(j_.debug()) << "Applied " << count
+
439  << " expired validator list(s) from " << uri;
+
440  break;
+
441  case ListDisposition::same_sequence:
+
442  JLOG(j_.debug())
+
443  << "Ignored " << count
+
444  << " validator list(s) with current sequence from " << uri;
+
445  break;
+
446  case ListDisposition::pending:
+
447  JLOG(j_.debug()) << "Processed " << count
+
448  << " future validator list(s) from " << uri;
+
449  break;
+
450  case ListDisposition::known_sequence:
+
451  JLOG(j_.debug())
+
452  << "Ignored " << count
+
453  << " validator list(s) with future known sequence from "
+
454  << uri;
+
455  break;
+
456  case ListDisposition::stale:
+
457  JLOG(j_.warn()) << "Ignored " << count
+
458  << "stale validator list(s) from " << uri;
+
459  break;
+
460  case ListDisposition::untrusted:
+
461  JLOG(j_.warn()) << "Ignored " << count
+
462  << " untrusted validator list(s) from " << uri;
+
463  break;
+
464  case ListDisposition::invalid:
+
465  JLOG(j_.warn()) << "Ignored " << count
+
466  << " invalid validator list(s) from " << uri;
+
467  break;
+
468  case ListDisposition::unsupported_version:
+
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 
+
492 std::shared_ptr<ValidatorSite::Site::Resource>
+
493 ValidatorSite::processRedirect(
+
494  detail::response_type& res,
+
495  std::size_t siteIdx,
+
496  std::lock_guard<std::mutex> const& sites_lock)
+
497 {
+
498  using namespace boost::beast::http;
+
499  std::shared_ptr<Site::Resource> newLocation;
+
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  try
+
508  if (sites_[siteIdx].redirCount == max_redirects)
509  {
-
510  newLocation =
-
511  std::make_shared<Site::Resource>(std::string(res[field::location]));
-
512  ++sites_[siteIdx].redirCount;
-
513  if (newLocation->pUrl.scheme != "http" &&
-
514  newLocation->pUrl.scheme != "https")
-
515  throw std::runtime_error(
-
516  "invalid scheme in redirect " + newLocation->pUrl.scheme);
-
517  }
-
518  catch (std::exception&)
-
519  {
-
520  JLOG(j_.error()) << "Invalid redirect location: "
-
521  << res[field::location];
-
522  throw;
-
523  }
-
524  return newLocation;
-
525 }
-
526 
-
527 void
-
528 ValidatorSite::onSiteFetch(
-
529  boost::system::error_code const& ec,
-
530  endpoint_type const& endpoint,
-
531  detail::response_type&& res,
-
532  std::size_t siteIdx)
-
533 {
-
534  std::lock_guard lock_sites{sites_mutex_};
-
535  {
-
536  if (endpoint != endpoint_type{})
-
537  sites_[siteIdx].lastRequestEndpoint = endpoint;
-
538  JLOG(j_.debug()) << "Got completion for "
-
539  << sites_[siteIdx].activeResource->uri << " "
-
540  << endpoint;
-
541  auto onError = [&](std::string const& errMsg, bool retry) {
-
542  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
-
543  clock_type::now(), ListDisposition::invalid, errMsg});
-
544  if (retry)
-
545  sites_[siteIdx].nextRefresh =
-
546  clock_type::now() + error_retry_interval;
-
547 
-
548  // See if there's a copy saved locally from last time we
-
549  // saw the list.
-
550  missingSite(lock_sites);
-
551  };
-
552  if (ec)
-
553  {
-
554  JLOG(j_.warn())
-
555  << "Problem retrieving from "
-
556  << sites_[siteIdx].activeResource->uri << " " << endpoint << " "
-
557  << ec.value() << ":" << ec.message();
-
558  onError("fetch error", true);
-
559  }
-
560  else
-
561  {
-
562  try
-
563  {
-
564  using namespace boost::beast::http;
-
565  switch (res.result())
-
566  {
-
567  case status::ok:
-
568  sites_[siteIdx].lastRequestSuccessful = true;
-
569  parseJsonResponse(res.body(), siteIdx, lock_sites);
-
570  break;
-
571  case status::moved_permanently:
-
572  case status::permanent_redirect:
-
573  case status::found:
-
574  case status::temporary_redirect: {
-
575  auto newLocation =
-
576  processRedirect(res, siteIdx, lock_sites);
-
577  assert(newLocation);
-
578  // for perm redirects, also update our starting URI
-
579  if (res.result() == status::moved_permanently ||
-
580  res.result() == status::permanent_redirect)
-
581  {
-
582  sites_[siteIdx].startingResource = newLocation;
-
583  }
-
584  makeRequest(newLocation, siteIdx, lock_sites);
-
585  return; // we are still fetching, so skip
-
586  // state update/notify below
-
587  }
-
588  default: {
-
589  JLOG(j_.warn())
-
590  << "Request for validator list at "
-
591  << sites_[siteIdx].activeResource->uri << " "
-
592  << endpoint
-
593  << " returned bad status: " << res.result_int();
-
594  onError("bad result code", true);
-
595  }
-
596  }
-
597  }
-
598  catch (std::exception& ex)
-
599  {
-
600  onError(ex.what(), false);
-
601  }
-
602  }
-
603  sites_[siteIdx].activeResource.reset();
-
604  }
-
605 
-
606  std::lock_guard lock_state{state_mutex_};
-
607  fetching_ = false;
-
608  if (!stopping_)
-
609  setTimer(lock_sites, lock_state);
-
610  cv_.notify_all();
-
611 }
-
612 
-
613 void
-
614 ValidatorSite::onTextFetch(
-
615  boost::system::error_code const& ec,
-
616  std::string const& res,
-
617  std::size_t siteIdx)
-
618 {
-
619  std::lock_guard lock_sites{sites_mutex_};
-
620  {
-
621  try
-
622  {
-
623  if (ec)
-
624  {
-
625  JLOG(j_.warn()) << "Problem retrieving from "
-
626  << sites_[siteIdx].activeResource->uri << " "
-
627  << ec.value() << ": " << ec.message();
-
628  throw std::runtime_error{"fetch error"};
-
629  }
-
630 
-
631  sites_[siteIdx].lastRequestSuccessful = true;
-
632 
-
633  parseJsonResponse(res, siteIdx, lock_sites);
-
634  }
-
635  catch (std::exception& ex)
-
636  {
-
637  sites_[siteIdx].lastRefreshStatus.emplace(Site::Status{
-
638  clock_type::now(), ListDisposition::invalid, ex.what()});
-
639  }
-
640  sites_[siteIdx].activeResource.reset();
-
641  }
-
642 
-
643  std::lock_guard lock_state{state_mutex_};
-
644  fetching_ = false;
-
645  if (!stopping_)
-
646  setTimer(lock_sites, lock_state);
-
647  cv_.notify_all();
-
648 }
-
649 
-
650 Json::Value
-
651 ValidatorSite::getJson() const
-
652 {
-
653  using namespace std::chrono;
-
654  using Int = Json::Value::Int;
-
655 
-
656  Json::Value jrr(Json::objectValue);
-
657  Json::Value& jSites = (jrr[jss::validator_sites] = Json::arrayValue);
-
658  {
-
659  std::lock_guard lock{sites_mutex_};
-
660  for (Site const& site : sites_)
-
661  {
-
662  Json::Value& v = jSites.append(Json::objectValue);
-
663  std::stringstream uri;
-
664  uri << site.loadedResource->uri;
-
665  if (site.loadedResource != site.startingResource)
-
666  uri << " (redirects to " << site.startingResource->uri + ")";
-
667  v[jss::uri] = uri.str();
-
668  v[jss::next_refresh_time] = to_string(site.nextRefresh);
-
669  if (site.lastRefreshStatus)
-
670  {
-
671  v[jss::last_refresh_time] =
-
672  to_string(site.lastRefreshStatus->refreshed);
-
673  v[jss::last_refresh_status] =
-
674  to_string(site.lastRefreshStatus->disposition);
-
675  if (!site.lastRefreshStatus->message.empty())
-
676  v[jss::last_refresh_message] =
-
677  site.lastRefreshStatus->message;
-
678  }
-
679  v[jss::refresh_interval_min] =
-
680  static_cast<Int>(site.refreshInterval.count());
-
681  }
-
682  }
-
683  return jrr;
-
684 }
-
685 } // namespace ripple
+
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
+
539 ValidatorSite::onSiteFetch(
+
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{
+
554  clock_type::now(), ListDisposition::invalid, errMsg});
+
555  if (retry)
+
556  sites_[siteIdx].nextRefresh =
+
557  clock_type::now() + error_retry_interval;
+
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
+
625 ValidatorSite::onTextFetch(
+
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{
+
649  clock_type::now(), ListDisposition::invalid, ex.what()});
+
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 
+
661 Json::Value
+
662 ValidatorSite::getJson() const
+
663 {
+
664  using namespace std::chrono;
+
665  using Int = Json::Value::Int;
+
666 
+
667  Json::Value jrr(Json::objectValue);
+
668  Json::Value& jSites = (jrr[jss::validator_sites] = Json::arrayValue);
+
669  {
+
670  std::lock_guard lock{sites_mutex_};
+
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
@@ -787,7 +798,7 @@ $(function() {
ripple::ValidatorList::parseBlobs
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
Definition: ValidatorList.cpp:362
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
ripple::parsedURL::path
std::string path
Definition: StringUtilities.h:125
-
ripple::ValidatorSite::onSiteFetch
void onSiteFetch(boost::system::error_code const &ec, endpoint_type const &endpoint, detail::response_type &&res, std::size_t siteIdx)
Store latest list fetched from site.
Definition: ValidatorSite.cpp:528
+
ripple::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
@@ -803,12 +814,12 @@ $(function() {
ripple::parsedURL::port
std::optional< std::uint16_t > port
Definition: StringUtilities.h:124
ripple::Application::config
virtual Config & config()=0
std::min_element
T min_element(T... args)
-
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:651
+
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:360
+
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.
@@ -818,7 +829,7 @@ $(function() {
std::uint32_t
std::condition_variable::wait
T wait(T... args)
ripple::error_retry_interval
constexpr auto error_retry_interval
Definition: ValidatorSite.cpp:35
-
ripple::ValidatorSite::processRedirect
std::shared_ptr< Site::Resource > processRedirect(detail::response_type &res, std::size_t siteIdx, std::lock_guard< std::mutex > const &)
Interpret a redirect response.
Definition: ValidatorSite.cpp:482
+
ripple::ValidatorSite::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
@@ -832,7 +843,7 @@ $(function() {
std::clamp
T clamp(T... args)
ripple::ListDisposition::same_sequence
@ same_sequence
Same sequence as current list.
ripple::ValidatorSite::Site::Resource::Resource
Resource(std::string uri_)
Definition: ValidatorSite.cpp:38
-
ripple::ValidatorSite::onTextFetch
void onTextFetch(boost::system::error_code const &ec, std::string const &res, std::size_t siteIdx)
Store latest list fetched from anywhere.
Definition: ValidatorSite.cpp:614
+
ripple::ValidatorSite::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
@@ -852,7 +863,7 @@ $(function() {
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::ValidatorSite::start
void start()
Start fetching lists from sites.
Definition: ValidatorSite.cpp:167
-
ripple::ValidatorSite::onTimer
void onTimer(std::size_t siteIdx, error_code const &ec)
Fetch site whose time has come.
Definition: ValidatorSite.cpp:329
+
ripple::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)
diff --git a/ValidatorSite_8h_source.html b/ValidatorSite_8h_source.html index 8e3bdffcfb..b7bcf740b0 100644 --- a/ValidatorSite_8h_source.html +++ b/ValidatorSite_8h_source.html @@ -272,7 +272,7 @@ $(function() {
std::lock_guard
STL class.
ripple::ValidatorSite::Site::lastRequestSuccessful
bool lastRequestSuccessful
Definition: ValidatorSite.h:114
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::ValidatorSite::onSiteFetch
void onSiteFetch(boost::system::error_code const &ec, endpoint_type const &endpoint, detail::response_type &&res, std::size_t siteIdx)
Store latest list fetched from site.
Definition: ValidatorSite.cpp:528
+
ripple::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::ValidatorSite::state_mutex_
std::mutex state_mutex_
Definition: ValidatorSite.h:123
ripple::ValidatorSite::Work
friend class Work
Definition: ValidatorSite.h:71
ripple::ValidatorSite::fetching_
std::atomic< bool > fetching_
Definition: ValidatorSite.h:130
@@ -282,15 +282,15 @@ $(function() {
ripple::ValidatorSite::app_
Application & app_
Definition: ValidatorSite.h:117
ripple::ValidatorSite::Site::Status::refreshed
clock_type::time_point refreshed
Definition: ValidatorSite.h:82
ripple::ValidatorSite::pending_
std::atomic< bool > pending_
Definition: ValidatorSite.h:133
-
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:651
+
ripple::ValidatorSite::getJson
Json::Value getJson() const
Return JSON representation of configured validator sites.
Definition: ValidatorSite.cpp:662
ripple::ValidatorSite::j_
const beast::Journal j_
Definition: ValidatorSite.h:118
ripple::ValidatorSite::cv_
std::condition_variable cv_
Definition: ValidatorSite.h:125
-
ripple::ValidatorSite::parseJsonResponse
void parseJsonResponse(std::string const &res, std::size_t siteIdx, std::lock_guard< std::mutex > const &)
Parse json response from validator list site.
Definition: ValidatorSite.cpp:360
+
ripple::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::ValidatorSite::Site::Status::message
std::string message
Definition: ValidatorSite.h:84
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::ValidatorSite::join
void join()
Wait for current fetches from sites to complete.
Definition: ValidatorSite.cpp:176
std::atomic< bool >
-
ripple::ValidatorSite::processRedirect
std::shared_ptr< Site::Resource > processRedirect(detail::response_type &res, std::size_t siteIdx, std::lock_guard< std::mutex > const &)
Interpret a redirect response.
Definition: ValidatorSite.cpp:482
+
ripple::ValidatorSite::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::ValidatorSite::Site::redirCount
unsigned short redirCount
Definition: ValidatorSite.h:109
memory
@@ -302,7 +302,7 @@ $(function() {
ripple::ValidatorSite::Site::Resource
Definition: ValidatorSite.h:87
ripple::ValidatorSite::Site::activeResource
std::shared_ptr< Resource > activeResource
the active resource being requested.
Definition: ValidatorSite.h:107
ripple::ValidatorSite::Site::Resource::Resource
Resource(std::string uri_)
Definition: ValidatorSite.cpp:38
-
ripple::ValidatorSite::onTextFetch
void onTextFetch(boost::system::error_code const &ec, std::string const &res, std::size_t siteIdx)
Store latest list fetched from anywhere.
Definition: ValidatorSite.cpp:614
+
ripple::ValidatorSite::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::Status::disposition
ListDisposition disposition
Definition: ValidatorSite.h:83
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
@@ -315,7 +315,7 @@ $(function() {
mutex
std::size_t
ripple::ValidatorSite::start
void start()
Start fetching lists from sites.
Definition: ValidatorSite.cpp:167
-
ripple::ValidatorSite::onTimer
void onTimer(std::size_t siteIdx, error_code const &ec)
Fetch site whose time has come.
Definition: ValidatorSite.cpp:329
+
ripple::ValidatorSite::onTimer
void onTimer(std::size_t siteIdx, error_code const &ec)
Fetch site whose time has come.
Definition: ValidatorSite.cpp:340
ripple::ValidatorSite::Site::startingResource
std::shared_ptr< Resource > startingResource
the resource to request at <timer> intervals.
Definition: ValidatorSite.h:102
ripple::ValidatorSite::error_code
boost::system::error_code error_code
Definition: ValidatorSite.h:74
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
diff --git a/classripple_1_1ValidatorSite.html b/classripple_1_1ValidatorSite.html index a16d7468ec..b1bc3903a9 100644 --- a/classripple_1_1ValidatorSite.html +++ b/classripple_1_1ValidatorSite.html @@ -484,7 +484,7 @@ Validator Sites

Return JSON representation of configured validator sites.

-

Definition at line 651 of file ValidatorSite.cpp.

+

Definition at line 662 of file ValidatorSite.cpp.

@@ -644,7 +644,7 @@ Validator Sites

Fetch site whose time has come.

-

Definition at line 329 of file ValidatorSite.cpp.

+

Definition at line 340 of file ValidatorSite.cpp.

@@ -696,7 +696,7 @@ Validator Sites

Store latest list fetched from site.

-

Definition at line 528 of file ValidatorSite.cpp.

+

Definition at line 539 of file ValidatorSite.cpp.

@@ -742,7 +742,7 @@ Validator Sites

Store latest list fetched from anywhere.

-

Definition at line 614 of file ValidatorSite.cpp.

+

Definition at line 625 of file ValidatorSite.cpp.

@@ -836,7 +836,7 @@ Validator Sites

Parse json response from validator list site.

lock over sites_mutex_ required

-

Definition at line 360 of file ValidatorSite.cpp.

+

Definition at line 371 of file ValidatorSite.cpp.

@@ -883,7 +883,7 @@ Validator Sites

Interpret a redirect response.

lock over sites_mutex_ required

-

Definition at line 482 of file ValidatorSite.cpp.

+

Definition at line 493 of file ValidatorSite.cpp.