summaryrefslogtreecommitdiff
path: root/ares_process.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2008-05-13 20:48:48 +0000
committerDaniel Stenberg <daniel@haxx.se>2008-05-13 20:48:48 +0000
commit46dbd9461af66b9aa11a7f9e776979df6be028ac (patch)
tree3bfc49e25d58aec0342727b02ba904c7ea6c7e0e /ares_process.c
parent76d91c21ad6248518e37eb6dd6b52fb7ab8a7fbd (diff)
downloadc-ares-46dbd9461af66b9aa11a7f9e776979df6be028ac.tar.gz
c-ares-46dbd9461af66b9aa11a7f9e776979df6be028ac.tar.bz2
c-ares-46dbd9461af66b9aa11a7f9e776979df6be028ac.zip
- Introducing millisecond resolution support for the timeout option. See
ares_init_options()'s ARES_OPT_TIMEOUTMS.
Diffstat (limited to 'ares_process.c')
-rw-r--r--ares_process.c132
1 files changed, 93 insertions, 39 deletions
diff --git a/ares_process.c b/ares_process.c
index 442e328..eca363a 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -1,6 +1,7 @@
/* $Id$ */
/* Copyright 1998 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2004-2008 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -42,6 +43,9 @@
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h>
#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
#endif /* WIN32 && !WATT32 */
#ifdef HAVE_STRINGS_H
@@ -71,21 +75,25 @@
static int try_again(int errnum);
static void write_tcp_data(ares_channel channel, fd_set *write_fds,
- ares_socket_t write_fd, time_t now);
+ ares_socket_t write_fd, struct timeval *now);
static void read_tcp_data(ares_channel channel, fd_set *read_fds,
- ares_socket_t read_fd, time_t now);
+ ares_socket_t read_fd, struct timeval *now);
static void read_udp_packets(ares_channel channel, fd_set *read_fds,
- ares_socket_t read_fd, time_t now);
+ ares_socket_t read_fd, struct timeval *now);
static void advance_tcp_send_queue(ares_channel channel, int whichserver,
ssize_t num_bytes);
-static void process_timeouts(ares_channel channel, time_t now);
-static void process_broken_connections(ares_channel channel, time_t now);
+static void process_timeouts(ares_channel channel, struct timeval *now);
+static void process_broken_connections(ares_channel channel,
+ struct timeval *now);
static void process_answer(ares_channel channel, unsigned char *abuf,
- int alen, int whichserver, int tcp, time_t now);
-static void handle_error(ares_channel channel, int whichserver, time_t now);
+ int alen, int whichserver, int tcp,
+ struct timeval *now);
+static void handle_error(ares_channel channel, int whichserver,
+ struct timeval *now);
static void skip_server(ares_channel channel, struct query *query,
int whichserver);
-static void next_server(ares_channel channel, struct query *query, time_t now);
+static void next_server(ares_channel channel, struct query *query,
+ struct timeval *now);
static int configure_socket(int s, ares_channel channel);
static int open_tcp_socket(ares_channel channel, struct server_state *server);
static int open_udp_socket(ares_channel channel, struct server_state *server);
@@ -94,19 +102,59 @@ static int same_questions(const unsigned char *qbuf, int qlen,
static void end_query(ares_channel channel, struct query *query, int status,
unsigned char *abuf, int alen);
+/* return true if now is exactly check time or later */
+int ares__timedout(struct timeval *now,
+ struct timeval *check)
+{
+ int secs = (now->tv_sec - check->tv_sec);
+
+ if(secs > 0)
+ return 1; /* yes, timed out */
+ if(secs < -1)
+ return 0; /* nope, not timed out */
+
+ /* if the full seconds were identical, check the sub second parts */
+ return (now->tv_usec - check->tv_usec >= 0);
+}
+
+/* add the specific number of milliseconds to the time in the first argument */
+int ares__timeadd(struct timeval *now,
+ int millisecs)
+{
+ now->tv_sec += millisecs/1000;
+ now->tv_usec += (millisecs%1000)*1000;
+
+ if(now->tv_usec >= 1000000) {
+ ++(now->tv_sec);
+ now->tv_usec -= 1000000;
+ }
+
+ return 0;
+}
+
+/* return time offset between now and (future) check, in milliseconds */
+int ares__timeoffset(struct timeval *now,
+ struct timeval *check)
+{
+ int secs = (check->tv_sec - now->tv_sec); /* this many seconds */
+ int us = (check->tv_usec - now->tv_usec); /* this many microseconds */
+
+ return secs*1000 + us/1000; /* return them combined as milliseconds */
+}
+
+
/* Something interesting happened on the wire, or there was a timeout.
* See what's up and respond accordingly.
*/
void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
{
- time_t now;
-
- time(&now);
- write_tcp_data(channel, write_fds, ARES_SOCKET_BAD, now);
- read_tcp_data(channel, read_fds, ARES_SOCKET_BAD, now);
- read_udp_packets(channel, read_fds, ARES_SOCKET_BAD, now);
- process_timeouts(channel, now);
- process_broken_connections(channel, now);
+ struct timeval now = ares__tvnow();
+
+ write_tcp_data(channel, write_fds, ARES_SOCKET_BAD, &now);
+ read_tcp_data(channel, read_fds, ARES_SOCKET_BAD, &now);
+ read_udp_packets(channel, read_fds, ARES_SOCKET_BAD, &now);
+ process_timeouts(channel, &now);
+ process_broken_connections(channel, &now);
}
/* Something interesting happened on the wire, or there was a timeout.
@@ -117,13 +165,12 @@ void ares_process_fd(ares_channel channel,
file descriptors */
ares_socket_t write_fd)
{
- time_t now;
+ struct timeval now = ares__tvnow();
- time(&now);
- write_tcp_data(channel, NULL, write_fd, now);
- read_tcp_data(channel, NULL, read_fd, now);
- read_udp_packets(channel, NULL, read_fd, now);
- process_timeouts(channel, now);
+ write_tcp_data(channel, NULL, write_fd, &now);
+ read_tcp_data(channel, NULL, read_fd, &now);
+ read_udp_packets(channel, NULL, read_fd, &now);
+ process_timeouts(channel, &now);
}
@@ -158,7 +205,7 @@ static int try_again(int errnum)
static void write_tcp_data(ares_channel channel,
fd_set *write_fds,
ares_socket_t write_fd,
- time_t now)
+ struct timeval *now)
{
struct server_state *server;
struct send_request *sendreq;
@@ -177,7 +224,8 @@ static void write_tcp_data(ares_channel channel,
/* Make sure server has data to send and is selected in write_fds or
write_fd. */
server = &channel->servers[i];
- if (!server->qhead || server->tcp_socket == ARES_SOCKET_BAD || server->is_broken)
+ if (!server->qhead || server->tcp_socket == ARES_SOCKET_BAD ||
+ server->is_broken)
continue;
if(write_fds) {
@@ -281,7 +329,7 @@ static void advance_tcp_send_queue(ares_channel channel, int whichserver,
* a packet if we finish reading one.
*/
static void read_tcp_data(ares_channel channel, fd_set *read_fds,
- ares_socket_t read_fd, time_t now)
+ ares_socket_t read_fd, struct timeval *now)
{
struct server_state *server;
int i;
@@ -377,7 +425,7 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds,
/* If any UDP sockets select true for reading, process them. */
static void read_udp_packets(ares_channel channel, fd_set *read_fds,
- ares_socket_t read_fd, time_t now)
+ ares_socket_t read_fd, struct timeval *now)
{
struct server_state *server;
int i;
@@ -428,7 +476,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
}
/* If any queries have timed out, note the timeout and move them on. */
-static void process_timeouts(ares_channel channel, time_t now)
+static void process_timeouts(ares_channel channel, struct timeval *now)
{
time_t t; /* the time of the timeouts we're processing */
struct query *query;
@@ -441,14 +489,14 @@ static void process_timeouts(ares_channel channel, time_t now)
* only a handful of requests that fall into the "now" bucket, so
* this should be quite quick.
*/
- for (t = channel->last_timeout_processed; t <= now; t++)
+ for (t = channel->last_timeout_processed; t <= now->tv_sec; t++)
{
list_head = &(channel->queries_by_timeout[t % ARES_TIMEOUT_TABLE_SIZE]);
for (list_node = list_head->next; list_node != list_head; )
{
query = list_node->data;
list_node = list_node->next; /* in case the query gets deleted */
- if (query->timeout != 0 && now >= query->timeout)
+ if (query->timeout.tv_sec && ares__timedout(now, &query->timeout))
{
query->error_status = ARES_ETIMEOUT;
++query->timeouts;
@@ -456,12 +504,13 @@ static void process_timeouts(ares_channel channel, time_t now)
}
}
}
- channel->last_timeout_processed = now;
+ channel->last_timeout_processed = now->tv_sec;
}
/* Handle an answer from a server. */
static void process_answer(ares_channel channel, unsigned char *abuf,
- int alen, int whichserver, int tcp, time_t now)
+ int alen, int whichserver, int tcp,
+ struct timeval *now)
{
int tc, rcode;
unsigned short id;
@@ -539,7 +588,8 @@ static void process_answer(ares_channel channel, unsigned char *abuf,
}
/* Close all the connections that are no longer usable. */
-static void process_broken_connections(ares_channel channel, time_t now)
+static void process_broken_connections(ares_channel channel,
+ struct timeval *now)
{
int i;
for (i = 0; i < channel->nservers; i++)
@@ -552,7 +602,8 @@ static void process_broken_connections(ares_channel channel, time_t now)
}
}
-static void handle_error(ares_channel channel, int whichserver, time_t now)
+static void handle_error(ares_channel channel, int whichserver,
+ struct timeval *now)
{
struct server_state *server;
struct query *query;
@@ -603,7 +654,8 @@ static void skip_server(ares_channel channel, struct query *query,
}
}
-static void next_server(ares_channel channel, struct query *query, time_t now)
+static void next_server(ares_channel channel, struct query *query,
+ struct timeval *now)
{
/* Advance to the next server or try. */
query->server++;
@@ -640,7 +692,8 @@ static void next_server(ares_channel channel, struct query *query, time_t now)
end_query(channel, query, query->error_status, NULL, 0);
}
-void ares__send_query(ares_channel channel, struct query *query, time_t now)
+void ares__send_query(ares_channel channel, struct query *query,
+ struct timeval *now)
{
struct send_request *sendreq;
struct server_state *server;
@@ -707,16 +760,17 @@ void ares__send_query(ares_channel channel, struct query *query, time_t now)
return;
}
}
- query->timeout = now
- + ((query->try == 0) ? channel->timeout
- : channel->timeout << query->try / channel->nservers);
+ query->timeout = *now;
+ ares__timeadd(&query->timeout,
+ (query->try == 0) ? channel->timeout
+ : channel->timeout << query->try / channel->nservers);
/* Keep track of queries bucketed by timeout, so we can process
* timeout events quickly.
*/
ares__remove_from_list(&(query->queries_by_timeout));
ares__insert_in_list(
&(query->queries_by_timeout),
- &(channel->queries_by_timeout[query->timeout %
+ &(channel->queries_by_timeout[query->timeout.tv_sec %
ARES_TIMEOUT_TABLE_SIZE]));
/* Keep track of queries bucketed by server, so we can process server