Skip to content

Commit cfcc661

Browse files
committed
Fix timeouts
1 parent 770a708 commit cfcc661

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

src/resolve.cc

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ struct Zone {
5050
};
5151

5252
namespace {
53-
const constexpr uint64_t MIN_UDP_TIMEOUT_MS = 300;
53+
const constexpr uint64_t MIN_QUERY_TIMEOUT_MS = 300;
5454
const constexpr int MAX_QUERY_DEPTH = 20;
5555

5656
// https://www.iana.org/domains/root/servers
@@ -78,6 +78,11 @@ const DS ROOT_DS[]
7878
.data = {},
7979
}};
8080

81+
class query_timeout_error : std::runtime_error {
82+
public:
83+
query_timeout_error() : std::runtime_error("Query timed out") {}
84+
};
85+
8186
class bad_cookie_error : std::runtime_error {
8287
public:
8388
bad_cookie_error() : std::runtime_error("Bad server cookie") {}
@@ -135,8 +140,8 @@ bool address_equals(struct sockaddr_in a, struct sockaddr_in b) {
135140
} // namespace
136141

137142
Resolver::Resolver(ResolverConfig config)
138-
: timeout_duration(config.timeout_ms),
139-
udp_timeout_ms(std::max(config.timeout_ms / 5, MIN_UDP_TIMEOUT_MS)),
143+
: query_timeout_ms(std::max(config.timeout_ms, MIN_QUERY_TIMEOUT_MS)),
144+
udp_timeout_ms(query_timeout_ms / 3),
140145
port(config.port),
141146
verbose(config.verbose),
142147
enable_rd(config.enable_rd),
@@ -175,7 +180,7 @@ std::optional<std::vector<RR>> Resolver::resolve(const std::string &domain, RRTy
175180
if (rr_type == RRType::RRSIG || rr_type == RRType::OPT) return std::nullopt;
176181

177182
try {
178-
timeout_instant = std::chrono::steady_clock::now() + timeout_duration;
183+
query_start = std::chrono::steady_clock::now();
179184
set_socket_timeout(udp_timeout_ms);
180185
return resolve_rec(fully_qualify_domain(domain), rr_type, 0);
181186
} catch (const std::exception &e) {
@@ -281,10 +286,12 @@ void Resolver::set_socket_timeout(uint64_t timeout_ms) const {
281286
}
282287

283288
void Resolver::update_timeout() {
284-
auto time_left = timeout_instant - std::chrono::steady_clock::now();
285-
auto time_left_ms = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::milli>>(time_left).count();
286-
if (time_left_ms <= 0) throw std::runtime_error("Query timed out");
287-
if (time_left_ms <= udp_timeout_ms) set_socket_timeout(time_left_ms);
289+
auto duration = std::chrono::steady_clock::now() - query_start;
290+
auto duration_ms = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::milli>>(duration).count();
291+
if (duration_ms >= query_timeout_ms) throw query_timeout_error();
292+
293+
auto time_left_ms = query_timeout_ms - duration_ms;
294+
if (time_left_ms < udp_timeout_ms) set_socket_timeout(time_left_ms);
288295
}
289296

290297
void Resolver::udp_send(const std::vector<uint8_t> &buffer, struct sockaddr_in address) {
@@ -643,6 +650,9 @@ std::optional<std::vector<RR>> Resolver::resolve_rec(const std::string &domain,
643650
next_zone = get_next_zone(current_safe_zones);
644651
if (next_zone == nullptr) return std::nullopt;
645652
break;
653+
} catch (const query_timeout_error &) {
654+
if (verbose) std::println(stderr, "Query timed out");
655+
return std::nullopt;
646656
} catch (const bad_cookie_error &) {
647657
if (!nameserver->sent_bad_cookie) {
648658
// Retry the same nameserver with the new server cookie once.

src/resolve.hh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,14 @@ public:
5353
std::optional<std::vector<RR>> resolve(const std::string &domain, RRType rr_type);
5454

5555
private:
56-
std::chrono::duration<uint64_t, std::milli> timeout_duration;
57-
uint64_t udp_timeout_ms;
56+
uint64_t query_timeout_ms, udp_timeout_ms;
5857
uint16_t port;
5958
bool verbose, enable_rd;
6059
FeatureState edns, dnssec, cookies;
6160
std::default_random_engine rng;
6261
std::unordered_map<std::string, std::shared_ptr<Zone>, StringHash, std::equal_to<>> zones;
6362
int fd;
64-
std::chrono::time_point<std::chrono::steady_clock> timeout_instant;
63+
std::chrono::time_point<std::chrono::steady_clock> query_start;
6564
// List of zones to ask when the resolver has no information.
6665
std::queue<std::shared_ptr<Zone>> safe_zones;
6766

0 commit comments

Comments
 (0)