From 639239f45cb44c4fed0853320d9cbd7d0c63af0a Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Mon, 13 Mar 2017 14:20:47 +0100 Subject: [PATCH] Schedule dnsreqs with absolute timeout/expiry time --- src/dnssec.c | 3 ++- src/general.c | 19 +++++++++++-------- src/general.h | 2 +- src/request-internal.c | 8 +++++++- src/stub.c | 23 ++++++++++++----------- src/stub.h | 3 ++- src/types-internal.h | 7 ++++++- src/util-internal.h | 20 ++++++++++++++++++++ 8 files changed, 61 insertions(+), 24 deletions(-) diff --git a/src/dnssec.c b/src/dnssec.c index 0396f045..b689aba5 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -3032,6 +3032,7 @@ static void check_chain_complete(chain_head *chain) int r = GETDNS_RETURN_GOOD; getdns_network_req **netreq_p, *netreq; + uint64_t now_ms = 0; dnsreq->avoid_dnssec_roadblocks = 1; @@ -3041,7 +3042,7 @@ static void check_chain_complete(chain_head *chain) netreq->state = NET_REQ_NOT_SENT; netreq->owner = dnsreq; - r = _getdns_submit_netreq(netreq); + r = _getdns_submit_netreq(netreq, &now_ms); } return; } diff --git a/src/general.c b/src/general.c index 69dc7462..c71a4944 100644 --- a/src/general.c +++ b/src/general.c @@ -91,6 +91,7 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req) { getdns_network_req **netreq_p, *netreq; int results_found = 0, r; + uint64_t now_ms = 0; for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) if (!_getdns_netreq_finished(netreq)) @@ -126,7 +127,7 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req) ; (netreq = *netreq_p) ; netreq_p++ ) { _getdns_netreq_reinit(netreq); - if ((r = _getdns_submit_netreq(netreq))) { + if ((r = _getdns_submit_netreq(netreq, &now_ms))) { if (r == DNS_REQ_FINISHED) return; netreq->state = NET_REQ_FINISHED; @@ -164,7 +165,7 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req) ; (netreq = *netreq_p) ; netreq_p++ ) { _getdns_netreq_reinit(netreq); - if ((r = _getdns_submit_netreq(netreq))) { + if ((r = _getdns_submit_netreq(netreq, &now_ms))) { if (r == DNS_REQ_FINISHED) return; netreq->state = NET_REQ_FINISHED; @@ -248,7 +249,7 @@ ub_resolve_callback(void* arg, int err, struct ub_result* ub_res) int -_getdns_submit_netreq(getdns_network_req *netreq) +_getdns_submit_netreq(getdns_network_req *netreq, uint64_t *now_ms) { getdns_return_t r; getdns_dns_req *dns_req = netreq->owner; @@ -284,7 +285,8 @@ _getdns_submit_netreq(getdns_network_req *netreq) _getdns_context_request_timed_out; dns_req->timeout.ev = NULL; if ((r = dns_req->loop->vmt->schedule(dns_req->loop, -1, - dns_req->context->timeout, &dns_req->timeout))) + _getdns_ms_until_expiry2(dns_req->expires, now_ms), + &dns_req->timeout))) return r; } (void) gldns_wire2str_dname_buf(dns_req->name, @@ -314,7 +316,7 @@ _getdns_submit_netreq(getdns_network_req *netreq) } /* Submit with stub resolver */ dns_req->freed = &dnsreq_freed; - r = _getdns_submit_stub_request(netreq); + r = _getdns_submit_stub_request(netreq, now_ms); if (dnsreq_freed) return DNS_REQ_FINISHED; dns_req->freed = NULL; @@ -413,6 +415,7 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop, getdns_dns_req *req; getdns_dict *localnames_response; size_t i; + uint64_t now_ms = 0; if (!context || !name || (!callbackfn && !internal_cb)) return GETDNS_RETURN_INVALID_PARAMETER; @@ -430,7 +433,7 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop, /* create the request */ if (!(req = _getdns_dns_req_new( - context, loop, name, request_type, extensions))) + context, loop, name, request_type, extensions, &now_ms))) return GETDNS_RETURN_MEMORY_ERROR; req->user_pointer = userarg; @@ -448,7 +451,7 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop, for ( netreq_p = req->netreqs ; !r && (netreq = *netreq_p) ; netreq_p++) { - if ((r = _getdns_submit_netreq(netreq))) { + if ((r = _getdns_submit_netreq(netreq, &now_ms))) { if (r == DNS_REQ_FINISHED) { if (return_netreq_p) *return_netreq_p = NULL; @@ -500,7 +503,7 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop, for ( netreq_p = req->netreqs ; !r && (netreq = *netreq_p) ; netreq_p++) { - if ((r = _getdns_submit_netreq(netreq))) { + if ((r = _getdns_submit_netreq(netreq, &now_ms))) { if (r == DNS_REQ_FINISHED) { if (return_netreq_p) *return_netreq_p = NULL; diff --git a/src/general.h b/src/general.h index 29b52f47..dcd9b9be 100644 --- a/src/general.h +++ b/src/general.h @@ -46,7 +46,7 @@ void _getdns_call_user_callback(getdns_dns_req *, getdns_dict *); void _getdns_check_dns_req_complete(getdns_dns_req *dns_req); -int _getdns_submit_netreq(getdns_network_req *netreq); +int _getdns_submit_netreq(getdns_network_req *netreq, uint64_t *now_ms); getdns_return_t diff --git a/src/request-internal.c b/src/request-internal.c index eae467e9..6c9cd9ec 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -658,7 +658,8 @@ static const uint8_t no_suffixes[] = { 1, 0 }; /* create a new dns req to be submitted */ getdns_dns_req * _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, - const char *name, uint16_t request_type, getdns_dict *extensions) + const char *name, uint16_t request_type, getdns_dict *extensions, + uint64_t *now_ms) { int dnssec_return_status = is_extension_set( extensions, "dnssec_return_status", @@ -953,5 +954,10 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, netreq_sz - sizeof(getdns_network_req), max_query_sz, extensions); + if (*now_ms == 0 && (*now_ms = _getdns_get_now_ms()) == 0) + result->expires = 0; + else + result->expires = *now_ms + context->timeout; + return result; } diff --git a/src/stub.c b/src/stub.c index e905f600..f7f1fddb 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1358,8 +1358,8 @@ stub_udp_read_cb(void *userarg) dnsreq)) == -1) break; upstream_schedule_netreq(netreq->upstream, netreq); - GETDNS_SCHEDULE_EVENT( - dnsreq->loop, -1, dnsreq->context->timeout, + GETDNS_SCHEDULE_EVENT(dnsreq->loop, -1, + _getdns_ms_until_expiry(dnsreq->expires), getdns_eventloop_event_init(&netreq->event, netreq, NULL, NULL, stub_timeout_cb)); @@ -1421,8 +1421,8 @@ stub_udp_write_cb(void *userarg) #endif return; } - GETDNS_SCHEDULE_EVENT( - dnsreq->loop, netreq->fd, dnsreq->context->timeout, + GETDNS_SCHEDULE_EVENT(dnsreq->loop, netreq->fd, + _getdns_ms_until_expiry(dnsreq->expires), getdns_eventloop_event_init(&netreq->event, netreq, stub_udp_read_cb, NULL, stub_timeout_cb)); } @@ -1928,12 +1928,13 @@ upstream_find_for_netreq(getdns_network_req *netreq) static int fallback_on_write(getdns_network_req *netreq) { + uint64_t now_ms = 0; /* Deal with UDP one day*/ DEBUG_STUB("%s %-35s: MSG: %p FALLING BACK \n", STUB_DEBUG_SCHEDULE, __FUNC__, (void*)netreq); /* Try to find a fallback transport*/ - getdns_return_t result = _getdns_submit_stub_request(netreq); + getdns_return_t result = _getdns_submit_stub_request(netreq, &now_ms); if (result != GETDNS_RETURN_GOOD) return STUB_TCP_ERROR; @@ -1997,8 +1998,8 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) if (upstream->queries_sent == 0) { /* Set a timeout on the upstream so we can catch failed setup*/ upstream->event.timeout_cb = upstream_setup_timeout_cb; - GETDNS_SCHEDULE_EVENT(upstream->loop, - upstream->fd, netreq->owner->context->timeout / 2, + GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, + _getdns_ms_until_expiry(netreq->owner->expires)/2, &upstream->event); } else { GETDNS_SCHEDULE_EVENT(upstream->loop, @@ -2027,7 +2028,7 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) } getdns_return_t -_getdns_submit_stub_request(getdns_network_req *netreq) +_getdns_submit_stub_request(getdns_network_req *netreq, uint64_t *now_ms) { DEBUG_STUB("%s %-35s: MSG: %p TYPE: %d\n", STUB_DEBUG_ENTRY, __FUNC__, (void*)netreq, netreq->request_type); @@ -2046,8 +2047,8 @@ _getdns_submit_stub_request(getdns_network_req *netreq) case GETDNS_TRANSPORT_UDP: netreq->fd = fd; GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); - GETDNS_SCHEDULE_EVENT( - dnsreq->loop, netreq->fd, dnsreq->context->timeout, + GETDNS_SCHEDULE_EVENT(dnsreq->loop, netreq->fd, + _getdns_ms_until_expiry2(dnsreq->expires, now_ms), getdns_eventloop_event_init(&netreq->event, netreq, NULL, stub_udp_write_cb, stub_timeout_cb)); return GETDNS_RETURN_GOOD; @@ -2121,7 +2122,7 @@ _getdns_submit_stub_request(getdns_network_req *netreq) */ GETDNS_SCHEDULE_EVENT( dnsreq->loop, -1, - dnsreq->context->timeout, + _getdns_ms_until_expiry2(dnsreq->expires, now_ms), getdns_eventloop_event_init( &netreq->event, netreq, NULL, NULL, stub_timeout_cb)); diff --git a/src/stub.h b/src/stub.h index 41aa629a..da45eded 100644 --- a/src/stub.h +++ b/src/stub.h @@ -37,7 +37,8 @@ #include "getdns/getdns.h" #include "types-internal.h" -getdns_return_t _getdns_submit_stub_request(getdns_network_req *netreq); +getdns_return_t _getdns_submit_stub_request( + getdns_network_req *netreq, uint64_t *now_ms); void _getdns_cancel_stub_request(getdns_network_req *netreq); diff --git a/src/types-internal.h b/src/types-internal.h index 78f1935a..9afb105d 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -338,6 +338,11 @@ typedef struct getdns_dns_req { /* the transaction id */ getdns_transaction_t trans_id; + /* Absolute time (in miliseconds since epoch), + * after which this dns request is expired; i.e. timed out + */ + uint64_t expires; + /* for scheduling timeouts when using libunbound */ getdns_eventloop_event timeout; @@ -408,7 +413,7 @@ extern getdns_dict *dnssec_ok_checking_disabled_avoid_roadblocks; /* dns request utils */ getdns_dns_req *_getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, - const char *name, uint16_t request_type, getdns_dict *extensions); + const char *name, uint16_t request_type, getdns_dict *extensions, uint64_t *now_ms); void _getdns_dns_req_free(getdns_dns_req * req); diff --git a/src/util-internal.h b/src/util-internal.h index 54c81d9d..6f8de235 100644 --- a/src/util-internal.h +++ b/src/util-internal.h @@ -198,5 +198,25 @@ INLINE void _dname_canonicalize2(uint8_t *dname) _dname_canonicalize(dname, dname); } +INLINE uint64_t _getdns_get_now_ms() +{ + struct timeval tv; + + (void) gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +INLINE uint64_t _getdns_ms_until_expiry(uint64_t expires) +{ + uint64_t now_ms = _getdns_get_now_ms(); + return now_ms >= expires ? 0 : expires - now_ms; +} + +INLINE uint64_t _getdns_ms_until_expiry2(uint64_t expires, uint64_t *now_ms) +{ + if (*now_ms == 0) *now_ms = _getdns_get_now_ms(); + return *now_ms >= expires ? 0 : expires - *now_ms; +} + #endif /* util-internal.h */