From a0fb2c8424daf2cc01f8b977a5823fba49ddd55f Mon Sep 17 00:00:00 2001 From: Robert Groenenberg Date: Mon, 26 Feb 2018 16:41:13 +0100 Subject: [PATCH] Limit back_off value to avoid very long retry interval --- src/context.c | 29 +++++++++++++++++++++++++++++ src/context.h | 2 ++ src/getdns/getdns_extra.h.in | 31 ++++++++++++++++++++++++++++++- src/libgetdns.symbols | 2 ++ src/stub.c | 9 +++++++-- 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/context.c b/src/context.c index 17b087dd..5baa8771 100644 --- a/src/context.c +++ b/src/context.c @@ -679,6 +679,7 @@ upstreams_create(getdns_context *context, size_t size) r->count = 0; r->current_udp = 0; r->current_stateful = 0; + r->max_backoff_value = context->max_backoff_value; r->tls_backoff_time = context->tls_backoff_time; r->tls_connection_retries = context->tls_connection_retries; r->log = context->log; @@ -1664,6 +1665,7 @@ getdns_context_create_with_extended_memory_functions( result->tls_backoff_time = 3600; result->tls_connection_retries = 2; result->limit_outstanding_queries = 0; + result->max_backoff_value = 1000; /* unbound context is initialized here */ /* Unbound needs SSL to be init'ed this early when TLS is used. However we @@ -2362,6 +2364,22 @@ getdns_context_set_round_robin_upstreams(getdns_context *context, uint8_t value) return GETDNS_RETURN_GOOD; } /* getdns_context_set_round_robin_upstreams */ +/* + * getdns_context_set_max_backoff_value + * + */ +getdns_return_t +getdns_context_set_max_backoff_value(getdns_context *context, uint16_t value) +{ + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + + context->max_backoff_value = value; + + dispatch_updated(context, GETDNS_CONTEXT_CODE_MAX_BACKOFF_VALUE); + + return GETDNS_RETURN_GOOD; +} /* getdns_context_set_max_backoff_value */ + /* * getdns_context_set_tls_backoff_time * @@ -3931,6 +3949,8 @@ _get_context_settings(getdns_context* context) context->tls_auth) || getdns_dict_set_int(result, "round_robin_upstreams", context->round_robin_upstreams) + || getdns_dict_set_int(result, "max_backoff_value", + context->max_backoff_value) || getdns_dict_set_int(result, "tls_backoff_time", context->tls_backoff_time) || getdns_dict_set_int(result, "tls_connection_retries", @@ -4378,6 +4398,15 @@ getdns_context_get_round_robin_upstreams(getdns_context *context, return GETDNS_RETURN_GOOD; } +getdns_return_t +getdns_context_get_max_backoff_value(getdns_context *context, + uint16_t* value) { + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); + *value = context->max_backoff_value; + return GETDNS_RETURN_GOOD; +} + getdns_return_t getdns_context_get_tls_backoff_time(getdns_context *context, uint16_t* value) { diff --git a/src/context.h b/src/context.h index 30315b98..27dd2bee 100644 --- a/src/context.h +++ b/src/context.h @@ -263,6 +263,7 @@ typedef struct getdns_upstreams { size_t count; size_t current_udp; size_t current_stateful; + uint16_t max_backoff_value; uint16_t tls_backoff_time; uint16_t tls_connection_retries; getdns_log_config log; @@ -357,6 +358,7 @@ struct getdns_context { getdns_tls_authentication_t tls_auth; /* What user requested for TLS*/ getdns_tls_authentication_t tls_auth_min; /* Derived minimum auth allowed*/ uint8_t round_robin_upstreams; + uint16_t max_backoff_value; uint16_t tls_backoff_time; uint16_t tls_connection_retries; diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index 0859b6b0..01ef2f07 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -103,6 +103,9 @@ extern "C" { #define GETDNS_CONTEXT_CODE_TLS_CURVES_LIST 634 #define GETDNS_CONTEXT_CODE_TLS_CURVES_LIST_TEXT "Change related to getdns_context_set_tls_curves_list" +#define GETDNS_CONTEXT_CODE_MAX_BACKOFF_VALUE 635 +#define GETDNS_CONTEXT_CODE_MAX_BACKOFF_VALUE_TEXT "Change related to getdns_context_set_max_backoff_value" + /** @} */ @@ -768,6 +771,19 @@ getdns_return_t getdns_context_set_tls_curves_list( getdns_context *context, const char *curves_list); +/** + * Set the maximum number of messages that can be sent to other upstreams + * before the upstream which has previously timed out will be tried again. + * @see getdns_context_get_max_backoff_value + * @param[in] context The context to configure + * @param[in[ value Number of messages sent to other upstreams before + * retrying the upstream which had timed out. + * @return GETDNS_RETURN_GOOD on success + * @return GETDNS_RETURN_INVALID_PARAMETER if context is null. + */ +getdns_return_t +getdns_context_set_max_backoff_value(getdns_context *context, uint16_t value); + /** * Get the current resolution type setting from this context. @@ -1076,7 +1092,7 @@ getdns_context_get_tls_authentication(getdns_context *context, /** * Get whether the context is configured to round robin queries over the available * upstreams. - * @see getdns_context_get_round_robin_upstreams + * @see getdns_context_set_round_robin_upstreams * @param[in] context The context from which to get the setting * @param[out] value 1 if the setting is on, 0 otherwise * @return GETDNS_RETURN_GOOD when successful @@ -1303,6 +1319,19 @@ getdns_return_t getdns_context_get_tls_curves_list( getdns_context *context, const char **curves_list); +/** + * Get the maximum number of messages that can be sent to other upstreams + * before the upstream which has previously timed out will be tried again. + * @see getdns_context_set_max_backoff_value + * @param[in] context The context from which to get the setting + * @param[out] value Number of messages sent to other upstreams before + * retrying the upstream which had timed out. + * @return GETDNS_RETURN_GOOD on success + * @return GETDNS_RETURN_INVALID_PARAMETER if context is null. + */ +getdns_return_t +getdns_context_get_max_backoff_value(getdns_context *context, + uint16_t* value); /** @} */ diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index ccbff42a..991ffcfc 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -29,6 +29,7 @@ getdns_context_get_num_pending_requests getdns_context_get_resolution_type getdns_context_get_resolvconf getdns_context_get_round_robin_upstreams +getdns_context_get_max_backoff_value getdns_context_get_suffix getdns_context_get_timeout getdns_context_get_tls_authentication @@ -73,6 +74,7 @@ getdns_context_set_resolution_type getdns_context_set_resolvconf getdns_context_set_return_dnssec_status getdns_context_set_round_robin_upstreams +getdns_context_set_max_backoff_value getdns_context_set_suffix getdns_context_set_timeout getdns_context_set_tls_authentication diff --git a/src/stub.c b/src/stub.c index 8f52ab4b..0152325f 100644 --- a/src/stub.c +++ b/src/stub.c @@ -460,8 +460,13 @@ stub_next_upstream(getdns_network_req *netreq) { getdns_dns_req *dnsreq = netreq->owner; - if (! --netreq->upstream->to_retry) - netreq->upstream->to_retry = -(netreq->upstream->back_off *= 2); + if (! --netreq->upstream->to_retry) { + /* Limit back_off value to configured maximum */ + if (netreq->upstream->back_off * 2 > dnsreq->context->max_backoff_value) + netreq->upstream->to_retry = -(dnsreq->context->max_backoff_value); + else + netreq->upstream->to_retry = -(netreq->upstream->back_off *= 2); + } dnsreq->upstreams->current_udp+=GETDNS_UPSTREAM_TRANSPORTS; if (dnsreq->upstreams->current_udp >= dnsreq->upstreams->count)