#include "net/dns/dns_server_iterator.h"
#include <optional>
#include "base/time/time.h"
#include "net/dns/dns_session.h"
#include "net/dns/resolve_context.h"
namespace net {
DnsServerIterator::DnsServerIterator(size_t nameservers_size,
size_t starting_index,
int max_times_returned,
int max_failures,
const ResolveContext* resolve_context,
const DnsSession* session)
: times_returned_(nameservers_size, 0),
max_times_returned_(max_times_returned),
max_failures_(max_failures),
resolve_context_(resolve_context),
next_index_(starting_index),
session_(session) {
CHECK(starting_index < nameservers_size || nameservers_size == 0);
}
DnsServerIterator::~DnsServerIterator() = default;
size_t DohDnsServerIterator::GetNextAttemptIndex() {
DCHECK(resolve_context_->IsCurrentSession(session_));
DCHECK(AttemptAvailable());
std::optional<size_t> least_recently_failed_index;
base::TimeTicks least_recently_failed_time;
size_t previous_index = next_index_;
size_t curr_index;
do {
curr_index = next_index_;
next_index_ = (next_index_ + 1) % times_returned_.size();
bool secure_or_available_server =
secure_dns_mode_ == SecureDnsMode::kSecure ||
resolve_context_->GetDohServerAvailability(curr_index, session_);
if (times_returned_[curr_index] >= max_times_returned_ ||
!secure_or_available_server)
continue;
if (resolve_context_->doh_server_stats_[curr_index].last_failure_count <
max_failures_) {
times_returned_[curr_index]++;
return curr_index;
}
base::TimeTicks curr_index_failure_time =
resolve_context_->doh_server_stats_[curr_index].last_failure;
if (!least_recently_failed_index ||
curr_index_failure_time < least_recently_failed_time) {
least_recently_failed_time = curr_index_failure_time;
least_recently_failed_index = curr_index;
}
} while (next_index_ != previous_index);
DCHECK(least_recently_failed_index.has_value());
times_returned_[least_recently_failed_index.value()]++;
return least_recently_failed_index.value();
}
bool DohDnsServerIterator::AttemptAvailable() {
if (!resolve_context_->IsCurrentSession(session_))
return false;
for (size_t i = 0; i < times_returned_.size(); i++) {
bool secure_or_available_server =
secure_dns_mode_ == SecureDnsMode::kSecure ||
resolve_context_->GetDohServerAvailability(i, session_);
if (times_returned_[i] < max_times_returned_ && secure_or_available_server)
return true;
}
return false;
}
size_t ClassicDnsServerIterator::GetNextAttemptIndex() {
DCHECK(resolve_context_->IsCurrentSession(session_));
DCHECK(AttemptAvailable());
std::optional<size_t> least_recently_failed_index;
base::TimeTicks least_recently_failed_time;
size_t previous_index = next_index_;
size_t curr_index;
do {
curr_index = next_index_;
next_index_ = (next_index_ + 1) % times_returned_.size();
if (times_returned_[curr_index] >= max_times_returned_)
continue;
if (resolve_context_->classic_server_stats_[curr_index].last_failure_count <
max_failures_) {
times_returned_[curr_index]++;
return curr_index;
}
base::TimeTicks curr_index_failure_time =
resolve_context_->classic_server_stats_[curr_index].last_failure;
if (!least_recently_failed_index ||
curr_index_failure_time < least_recently_failed_time) {
least_recently_failed_time = curr_index_failure_time;
least_recently_failed_index = curr_index;
}
} while (next_index_ != previous_index);
DCHECK(least_recently_failed_index.has_value());
times_returned_[least_recently_failed_index.value()]++;
return least_recently_failed_index.value();
}
bool ClassicDnsServerIterator::AttemptAvailable() {
if (!resolve_context_->IsCurrentSession(session_))
return false;
for (int i : times_returned_) {
if (i < max_times_returned_)
return true;
}
return false;
}
}