summaryrefslogtreecommitdiff
path: root/ares_process.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2008-11-01 18:35:19 +0000
committerDaniel Stenberg <daniel@haxx.se>2008-11-01 18:35:19 +0000
commit1a1b4eb4f2fb6112534994c20ac20679c5c7339c (patch)
tree76fda13f7f58853b63f184e061cb75eec6922d44 /ares_process.c
parentaa8d8b4933ca1f5de8da3f92f614e5f3236d6f89 (diff)
downloadc-ares-1a1b4eb4f2fb6112534994c20ac20679c5c7339c.tar.gz
c-ares-1a1b4eb4f2fb6112534994c20ac20679c5c7339c.tar.bz2
c-ares-1a1b4eb4f2fb6112534994c20ac20679c5c7339c.zip
- Carlo Contavalli added support for the glibc "rotate" option, as documented
in man resolv.conf: causes round robin selection of nameservers from among those listed. This has the effect of spreading the query load among all listed servers, rather than having all clients try the first listed server first every time. You can enable it with ARES_OPT_ROTATE
Diffstat (limited to 'ares_process.c')
-rw-r--r--ares_process.c50
1 files changed, 27 insertions, 23 deletions
diff --git a/ares_process.c b/ares_process.c
index 675af48..b7f375e 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -670,30 +670,33 @@ static void skip_server(ares_channel channel, struct query *query,
static void next_server(ares_channel channel, struct query *query,
struct timeval *now)
{
- /* Advance to the next server or try. */
- query->server++;
- for (; query->try < channel->tries; query->try++)
+ /* We need to try each server channel->tries times. We have channel->nservers
+ * servers to try. In total, we need to do channel->nservers * channel->tries
+ * attempts. Use query->try to remember how many times we already attempted
+ * this query. Use modular arithmetic to find the next server to try. */
+ while (++(query->try) < (channel->nservers * channel->tries))
{
- for (; query->server < channel->nservers; query->server++)
+ struct server_state *server;
+
+ /* Move on to the next server. */
+ query->server = (query->server + 1) % channel->nservers;
+ server = &channel->servers[query->server];
+
+ /* We don't want to use this server if (1) we decided this
+ * connection is broken, and thus about to be closed, (2)
+ * we've decided to skip this server because of earlier
+ * errors we encountered, or (3) we already sent this query
+ * over this exact connection.
+ */
+ if (!server->is_broken &&
+ !query->server_info[query->server].skip_server &&
+ !(query->using_tcp &&
+ (query->server_info[query->server].tcp_connection_generation ==
+ server->tcp_connection_generation)))
{
- struct server_state *server = &channel->servers[query->server];
- /* We don't want to use this server if (1) we decided this
- * connection is broken, and thus about to be closed, (2)
- * we've decided to skip this server because of earlier
- * errors we encountered, or (3) we already sent this query
- * over this exact connection.
- */
- if (!server->is_broken &&
- !query->server_info[query->server].skip_server &&
- !(query->using_tcp &&
- (query->server_info[query->server].tcp_connection_generation ==
- server->tcp_connection_generation)))
- {
- ares__send_query(channel, query, now);
- return;
- }
+ ares__send_query(channel, query, now);
+ return;
}
- query->server = 0;
/* You might think that with TCP we only need one try. However,
* even when using TCP, servers can time-out our connection just
@@ -702,6 +705,8 @@ static void next_server(ares_channel channel, struct query *query,
* tickle a bug that drops our request.
*/
}
+
+ /* If we are here, all attempts to perform query failed. */
end_query(channel, query, query->error_status, NULL, 0);
}
@@ -775,8 +780,7 @@ void ares__send_query(ares_channel channel, struct query *query,
}
query->timeout = *now;
ares__timeadd(&query->timeout,
- (query->try == 0) ? channel->timeout
- : channel->timeout << query->try / channel->nservers);
+ channel->timeout << (query->try / channel->nservers));
/* Keep track of queries bucketed by timeout, so we can process
* timeout events quickly.
*/