diff --git a/docs/ares_init_options.3 b/docs/ares_init_options.3 index fac9a3d6..835b1413 100644 --- a/docs/ares_init_options.3 +++ b/docs/ares_init_options.3 @@ -28,7 +28,6 @@ struct ares_options { int timeout; /* in seconds or milliseconds, depending on options */ int tries; int ndots; - int maxtimeout; /* in milliseconds */ unsigned short udp_port; unsigned short tcp_port; int socket_send_buffer_size; @@ -46,6 +45,7 @@ struct ares_options { char *resolvconf_path; char *hosts_path; int udp_max_queries; + int maxtimeout; /* in milliseconds */ }; int ares_init_options(ares_channel_t **\fIchannelptr\fP, @@ -106,7 +106,9 @@ resolv.conf or the RES_OPTIONS environment variable. .B ARES_OPT_MAXTIMEOUTMS .B int \fImaxtimeout\fP; .br -The upper bound for timeout between sequential retry attempts. +The upper bound for timeout between sequential retry attempts. When retrying +queries, the timeout is increased from the requested timeout parameter, this +caps the value. .TP 18 .B ARES_OPT_UDP_PORT .B unsigned short \fIudp_port\fP; diff --git a/include/ares.h b/include/ares.h index 48ab322f..ec7699ba 100644 --- a/include/ares.h +++ b/include/ares.h @@ -288,7 +288,6 @@ struct ares_options { int timeout; /* in seconds or milliseconds, depending on options */ int tries; int ndots; - int maxtimeout; /* in milliseconds */ unsigned short udp_port; unsigned short tcp_port; int socket_send_buffer_size; @@ -306,6 +305,7 @@ struct ares_options { char *resolvconf_path; char *hosts_path; int udp_max_queries; + int maxtimeout; /* in milliseconds */ }; struct hostent; diff --git a/src/lib/ares_process.c b/src/lib/ares_process.c index f254f8f8..4a25beee 100644 --- a/src/lib/ares_process.c +++ b/src/lib/ares_process.c @@ -802,28 +802,14 @@ static size_t ares__calc_query_timeout(struct query *query) { const ares_channel_t *channel = query->channel; size_t timeplus = channel->timeout; - size_t shift; + size_t rounds; - /* For each trip through the entire server list, double the channel's - * assigned timeout, avoiding overflow. If channel->timeout is negative, - * leave it as-is, even though that should be impossible here. - */ - - /* How many times do we want to double it? Presume sane values here. */ - shift = query->try_count / ares__slist_len(channel->servers); + /* For each trip through the entire server list, we want to double the + * retry from the last retry */ + rounds = (query->try_count / ares__slist_len(channel->servers)); - /* Is there enough room to shift timeplus left that many times? - * - * To find out, confirm that all of the bits we'll shift away are zero. - * Stop considering a shift if we get to the point where we could shift - * a 1 into the sign bit (i.e. when shift is within two of the bit - * count). - * - * This has the side benefit of leaving negative numbers unchanged. - */ - if (shift <= (sizeof(int) * CHAR_BIT - 1) && - (timeplus >> (sizeof(int) * CHAR_BIT - 1 - shift)) == 0) { - timeplus <<= shift; + if (rounds > 0) { + timeplus <<= rounds; } if (channel->maxtimeout && timeplus > channel->maxtimeout) @@ -837,21 +823,20 @@ static size_t ares__calc_query_timeout(struct query *query) * * Value of timeplus adjusted randomly to the range [0.5 * timeplus, timeplus]. */ - if (query->try_count > 0) { + if (rounds > 0) { unsigned short r; float delta_multiplier; ares__rand_bytes(channel->rand_state, (unsigned char *)&r, sizeof(r)); delta_multiplier = ((float)r / USHRT_MAX) * 0.5f; timeplus -= (size_t)((float)timeplus * delta_multiplier); - - // With shift that doubles each iteration and constant 0.5 above this situation - // is impossible, but we want explicitly guarantee that timeplus - // is greater or equal to timeout specified in channel options. - if (timeplus < channel->timeout) - timeplus = channel->timeout; } + /* We want explicitly guarantee that timeplus is greater or equal to timeout + * specified in channel options. */ + if (timeplus < channel->timeout) + timeplus = channel->timeout; + return timeplus; }