fix: Replaces random endpoint resolution with sequential (#5365)

This change addresses an issue where `rippled` attempts to connect to an IPv6 address, even when the local network lacks IPv6 support, resulting in a "Network is unreachable" error.

The fix replaces the custom endpoint selection logic with `boost::async_connect`, which sequentially attempts to connect to available endpoints until one succeeds or all fail.
This commit is contained in:
Vito Tumas
2025-04-28 21:38:55 +02:00
committed by GitHub
parent fa1e25abef
commit 3502df2174
2 changed files with 23 additions and 40 deletions

View File

@@ -102,7 +102,7 @@ ValidatorSite::ValidatorSite(
ValidatorSite::~ValidatorSite()
{
std::unique_lock<std::mutex> lock{state_mutex_};
if (timer_.expires_at() > clock_type::time_point{})
if (timer_.expiry() > clock_type::time_point{})
{
if (!stopping_)
{
@@ -168,7 +168,7 @@ ValidatorSite::start()
{
std::lock_guard l0{sites_mutex_};
std::lock_guard l1{state_mutex_};
if (timer_.expires_at() == clock_type::time_point{})
if (timer_.expiry() == clock_type::time_point{})
setTimer(l0, l1);
}

View File

@@ -96,6 +96,9 @@ public:
void
onResolve(error_code const& ec, results_type results);
void
onConnect(error_code const& ec, endpoint_type const& endpoint);
void
onStart();
@@ -195,46 +198,26 @@ WorkBase<Impl>::onResolve(error_code const& ec, results_type results)
if (ec)
return fail(ec);
// Use last endpoint if it is successfully connected
// and is in the list, otherwise pick a random endpoint
// from the list (excluding last endpoint). If there is
// only one endpoint and it is the last endpoint then
// use the last endpoint.
lastEndpoint_ = [&]() -> endpoint_type {
int foundIndex = 0;
auto const foundIt = std::find_if(
results.begin(), results.end(), [&](endpoint_type const& e) {
if (e == lastEndpoint_)
return true;
foundIndex++;
return false;
});
if (foundIt != results.end() && lastStatus_)
return lastEndpoint_;
else if (results.size() == 1)
return *results.begin();
else if (foundIt == results.end())
return *std::next(results.begin(), rand_int(results.size() - 1));
// lastEndpoint_ is part of the collection
// Pick a random number from the n-1 valid choices, if we use
// this as an index, note the last element will never be chosen
// and the `lastEndpoint_` index may be chosen. So when the
// `lastEndpoint_` index is chosen, that is treated as if the
// last element was chosen.
auto randIndex =
(results.size() > 2) ? rand_int(results.size() - 2) : 0;
if (randIndex == foundIndex)
randIndex = results.size() - 1;
return *std::next(results.begin(), randIndex);
}();
socket_.async_connect(
lastEndpoint_,
boost::asio::async_connect(
socket_,
results,
strand_.wrap(std::bind(
&Impl::onConnect,
&WorkBase::onConnect,
impl().shared_from_this(),
std::placeholders::_1)));
std::placeholders::_1,
std::placeholders::_2)));
}
template <class Impl>
void
WorkBase<Impl>::onConnect(error_code const& ec, endpoint_type const& endpoint)
{
lastEndpoint_ = endpoint;
if (ec)
return fail(ec);
impl().onConnect(ec);
}
template <class Impl>