#endif
int disable_when_inactive;
+
+ /* Maximum timeout between two probe packets
+ * will change `global_nameserver_probe_initial_timeout`
+ * when this value is smaller */
+ int ns_max_probe_timeout;
+ /* Backoff factor of probe timeout */
+ int ns_timeout_backoff_factor;
};
struct hosts_entry {
return;
}
-#define MAX_PROBE_TIMEOUT 3600
-#define TIMEOUT_BACKOFF_FACTOR 3
-
memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout,
sizeof(struct timeval));
- for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) {
- timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR;
- timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR;
+ for (i = ns->failed_times; i > 0 && timeout.tv_sec < ns->base->ns_max_probe_timeout; --i) {
+ timeout.tv_sec *= ns->base->ns_timeout_backoff_factor;
+ timeout.tv_usec *= ns->base->ns_timeout_backoff_factor;
if (timeout.tv_usec > 1000000) {
timeout.tv_sec += timeout.tv_usec / 1000000;
timeout.tv_usec %= 1000000;
}
}
- if (timeout.tv_sec > MAX_PROBE_TIMEOUT) {
- timeout.tv_sec = MAX_PROBE_TIMEOUT;
+ if (timeout.tv_sec > ns->base->ns_max_probe_timeout) {
+ timeout.tv_sec = ns->base->ns_max_probe_timeout;
timeout.tv_usec = 0;
}
val);
memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
sizeof(tv));
+ } else if (str_matches_option(option, "max-probe-timeout:")) {
+ const int max_probe_timeout = strtoint_clipped(val, 1, 3600);
+ if (max_probe_timeout == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting maximum probe timeout to %d",
+ max_probe_timeout);
+ base->ns_max_probe_timeout = max_probe_timeout;
+ if (base->global_nameserver_probe_initial_timeout.tv_sec > max_probe_timeout) {
+ base->global_nameserver_probe_initial_timeout.tv_sec = max_probe_timeout;
+ base->global_nameserver_probe_initial_timeout.tv_usec = 0;
+ log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
+ val);
+ }
+ } else if (str_matches_option(option, "probe-backoff-factor:")) {
+ const int backoff_backtor = strtoint_clipped(val, 1, 10);
+ if (backoff_backtor == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting probe timeout backoff factor to %d",
+ backoff_backtor);
+ base->ns_timeout_backoff_factor = backoff_backtor;
} else if (str_matches_option(option, "so-rcvbuf:")) {
int buf = strtoint(val);
if (buf == -1) return -1;
base->global_getaddrinfo_allow_skew.tv_usec = 0;
base->global_nameserver_probe_initial_timeout.tv_sec = 10;
base->global_nameserver_probe_initial_timeout.tv_usec = 0;
+ base->ns_max_probe_timeout = 3600;
+ base->ns_timeout_backoff_factor = 3;
base->global_tcp_idle_timeout.tv_sec = CLIENT_IDLE_CONN_TIMEOUT;
TAILQ_INIT(&base->hostsdb);
* - attempts:
* - randomize-case:
* - initial-probe-timeout:
+ * - max-probe-timeout:
+ * - probe-backoff-factor:
* - tcp-idle-timeout:
* - edns-udp-size:
* - use-vc
The currently available configuration options are:
ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case,
- bind-to, initial-probe-timeout, getaddrinfo-allow-skew,
- so-rcvbuf, so-sndbuf, tcp-idle-timeout, use-vc, ignore-tc,
- edns-udp-size.
+ bind-to, initial-probe-timeout, max-probe-timeout, probe-backoff-factor,
+ getaddrinfo-allow-skew, so-rcvbuf, so-sndbuf, tcp-idle-timeout, use-vc,
+ ignore-tc, edns-udp-size.
+
+ - probe-backoff-factor
+ Backoff factor of probe timeout
+
+ - max-probe-timeout
+ Maximum timeout between two probe packets will change initial-probe-timeout
+ when this value is smaller
In versions before Libevent 2.0.3-alpha, the option name needed to end with
a colon.
dns_retry_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
}
+static void
+dns_probe_settings_test(void *arg)
+{
+ struct basic_test_data *data = arg;
+ struct event_base *base = data->base;
+ struct evdns_server_port *port = NULL;
+ struct evdns_base *dns = NULL;
+ int drop_count = 1;
+ ev_uint16_t portnum = 0;
+ char buf[64];
+
+ struct generic_dns_callback_result r1, r2;
+ struct timeval tval_before, tval_after;
+
+ port = regress_get_udp_dnsserver(base, &portnum, NULL,
+ fail_server_cb, &drop_count);
+ tt_assert(port);
+ evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
+
+ dns = evdns_base_new(base, 0);
+ tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
+ tt_assert(!evdns_base_set_option(dns, "timeout", "0.2"));
+ tt_assert(!evdns_base_set_option(dns, "max-timeouts", "1"));
+ tt_assert(!evdns_base_set_option(dns, "attempts", "1"));
+ tt_assert(!evdns_base_set_option(dns, "initial-probe-timeout", "10"));
+ // it will also set initial-probe-timeout to 1s (10s > 1s)
+ tt_assert(!evdns_base_set_option(dns, "max-probe-timeout", "1"));
+
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+ n_replies_left = 2;
+ exit_base = base;
+ gettimeofday(&tval_before, NULL);
+ // this will wait until the probe request done
+ // should be around 1s instead of 10s
+ event_base_dispatch(base);
+ gettimeofday(&tval_after, NULL);
+ tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT);
+ test_timeval_diff_leq(&tval_before, &tval_after, 1000, 500);
+
+ // should be ok now
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0,
+ generic_dns_callback, &r1);
+ n_replies_left = 1;
+ event_base_dispatch(base);
+
+ tt_int_op(r1.result, ==, DNS_ERR_NONE);
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
+
+ // dns server down again
+ drop_count = 3;
+ tt_assert(!evdns_base_set_option(dns, "max-probe-timeout", "3600"));
+ tt_assert(!evdns_base_set_option(dns, "initial-probe-timeout", "0.2"));
+ tt_assert(!evdns_base_set_option(dns, "probe-backoff-factor", "10"));
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0, generic_dns_callback, &r1);
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0, generic_dns_callback, &r2);
+ // probe timeout should be around 2s now
+ n_replies_left = 3;
+
+ gettimeofday(&tval_before, NULL);
+ // wait dns server up
+ event_base_dispatch(base);
+ tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT);
+ tt_int_op(r2.result, ==, DNS_ERR_TIMEOUT);
+ gettimeofday(&tval_after, NULL);
+ test_timeval_diff_leq(&tval_before, &tval_after, 2000, 1000);
+
+ // should be ok now
+ evdns_base_resolve_ipv4(dns, "host.example.com", 0, generic_dns_callback, &r1);
+ n_replies_left = 1;
+ event_base_dispatch(base);
+
+ tt_int_op(r1.result, ==, DNS_ERR_NONE);
+ tt_int_op(r1.type, ==, DNS_IPv4_A);
+ tt_int_op(r1.count, ==, 1);
+ tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
+
+ end:
+ if (dns)
+ evdns_base_free(dns, 0);
+ if (port)
+ evdns_close_server_port(port);
+}
+
static struct regress_dns_server_table internal_error_table[] = {
/* Error 4 (NOTIMPL) makes us reissue the request to another server
if we can.
{ "retry", dns_retry_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
{ "retry_disable_when_inactive", dns_retry_disable_when_inactive_test,
TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
+ { "probe_settings", dns_probe_settings_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
{ "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
{ "reissue_disable_when_inactive", dns_reissue_disable_when_inactive_test,
TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },