- Introducing millisecond resolution support for the timeout option. See

ares_init_options()'s ARES_OPT_TIMEOUTMS.
pull/1/head
Daniel Stenberg 17 years ago
parent 76d91c21ad
commit 46dbd9461a
  1. 5
      CHANGES
  2. 4
      ares.h
  3. 23
      ares_init.3
  4. 12
      ares_init.c
  5. 22
      ares_private.h
  6. 132
      ares_process.c
  7. 12
      ares_send.c
  8. 27
      ares_timeout.c

@ -1,5 +1,10 @@
Changelog for the c-ares project Changelog for the c-ares project
* May 13 2008 (Daniel Stenberg)
- Introducing millisecond resolution support for the timeout option. See
ares_init_options()'s ARES_OPT_TIMEOUTMS.
* May 9 2008 (Yang Tse) * May 9 2008 (Yang Tse)
- Use monotonic time source if available, for private function ares__tvnow() - Use monotonic time source if available, for private function ares__tvnow()

@ -1,6 +1,7 @@
/* $Id$ */ /* $Id$ */
/* Copyright 1998 by the Massachusetts Institute of Technology. /* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright (C) 2007 by Daniel Stenberg
* *
* Permission to use, copy, modify, and distribute this * Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without * software and its documentation for any purpose and without
@ -112,6 +113,7 @@ extern "C" {
#define ARES_OPT_SORTLIST (1 << 10) #define ARES_OPT_SORTLIST (1 << 10)
#define ARES_OPT_SOCK_SNDBUF (1 << 11) #define ARES_OPT_SOCK_SNDBUF (1 << 11)
#define ARES_OPT_SOCK_RCVBUF (1 << 12) #define ARES_OPT_SOCK_RCVBUF (1 << 12)
#define ARES_OPT_TIMEOUTMS (1 << 13)
/* Nameinfo flag values */ /* Nameinfo flag values */
#define ARES_NI_NOFQDN (1 << 0) #define ARES_NI_NOFQDN (1 << 0)
@ -179,7 +181,7 @@ struct apattern;
struct ares_options { struct ares_options {
int flags; int flags;
int timeout; int timeout; /* in seconds or milliseconds, depending on options */
int tries; int tries;
int ndots; int ndots;
unsigned short udp_port; unsigned short udp_port;

@ -1,6 +1,7 @@
.\" $Id$ .\" $Id$
.\" .\"
.\" Copyright 1998 by the Massachusetts Institute of Technology. .\" Copyright 1998 by the Massachusetts Institute of Technology.
.\" Copyright (C) 2007-2008 by Daniel Stenberg
.\" .\"
.\" Permission to use, copy, modify, and distribute this .\" Permission to use, copy, modify, and distribute this
.\" software and its documentation for any purpose and without .\" software and its documentation for any purpose and without
@ -14,7 +15,7 @@
.\" this software for any purpose. It is provided "as is" .\" this software for any purpose. It is provided "as is"
.\" without express or implied warranty. .\" without express or implied warranty.
.\" .\"
.TH ARES_INIT 3 "7 December 2004" .TH ARES_INIT 3 "13 May 2008"
.SH NAME .SH NAME
ares_init, ares_init_options \- Initialize a resolver channel ares_init, ares_init_options \- Initialize a resolver channel
.SH SYNOPSIS .SH SYNOPSIS
@ -49,10 +50,22 @@ description of possible flag values.
.B ARES_OPT_TIMEOUT .B ARES_OPT_TIMEOUT
.B int \fItimeout\fP; .B int \fItimeout\fP;
.br .br
The number of seconds each name server is given to respond to a query The number of seconds each name server is given to respond to a query on the
on the first try. (After the first try, the timeout algorithm becomes first try. (After the first try, the timeout algorithm becomes more
more complicated, but scales linearly with the value of complicated, but scales linearly with the value of \fItimeout\fP.) The
\fItimeout\fP.) The default is five seconds. default is five seconds. This option is being deprecated by
\fIARES_OPT_TIMEOUTMS\fP starting in c-ares 1.5.2.
.TP 18
.B ARES_OPT_TIMEOUTMS
.B int \fItimeout\fP;
.br
The number of milliseconds each name server is given to respond to a query on
the first try. (After the first try, the timeout algorithm becomes more
complicated, but scales linearly with the value of \fItimeout\fP.) The
default is five seconds. Note that this option is specified with the same
struct field as the former \fIARES_OPT_TIMEOUT\fP, it is but the option bits
that tell c-ares how to interpret the number. This option was added in c-ares
1.5.2.
.TP 18 .TP 18
.B ARES_OPT_TRIES .B ARES_OPT_TRIES
.B int \fItries\fP; .B int \fItries\fP;

@ -1,6 +1,7 @@
/* $Id$ */ /* $Id$ */
/* Copyright 1998 by the Massachusetts Institute of Technology. /* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright (C) 2007-2008 by Daniel Stenberg
* *
* Permission to use, copy, modify, and distribute this * Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without * software and its documentation for any purpose and without
@ -254,13 +255,16 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
if (!ARES_CONFIG_CHECK(channel)) if (!ARES_CONFIG_CHECK(channel))
return ARES_ENODATA; return ARES_ENODATA;
(*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TIMEOUT|ARES_OPT_TRIES|ARES_OPT_NDOTS| (*optmask) = (ARES_OPT_FLAGS|ARES_OPT_TRIES|ARES_OPT_NDOTS|
ARES_OPT_UDP_PORT|ARES_OPT_TCP_PORT|ARES_OPT_SOCK_STATE_CB| ARES_OPT_UDP_PORT|ARES_OPT_TCP_PORT|ARES_OPT_SOCK_STATE_CB|
ARES_OPT_SERVERS|ARES_OPT_DOMAINS|ARES_OPT_LOOKUPS| ARES_OPT_SERVERS|ARES_OPT_DOMAINS|ARES_OPT_LOOKUPS|
ARES_OPT_SORTLIST); ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS);
/* Copy easy stuff */ /* Copy easy stuff */
options->flags = channel->flags; options->flags = channel->flags;
/* We return full millisecond resolution but that's only because we don't
set the ARES_OPT_TIMEOUT anymore, only the new ARES_OPT_TIMEOUTMS */
options->timeout = channel->timeout; options->timeout = channel->timeout;
options->tries = channel->tries; options->tries = channel->tries;
options->ndots = channel->ndots; options->ndots = channel->ndots;
@ -328,8 +332,10 @@ static int init_by_options(ares_channel channel,
/* Easy stuff. */ /* Easy stuff. */
if ((optmask & ARES_OPT_FLAGS) && channel->flags == -1) if ((optmask & ARES_OPT_FLAGS) && channel->flags == -1)
channel->flags = options->flags; channel->flags = options->flags;
if ((optmask & ARES_OPT_TIMEOUT) && channel->timeout == -1) if ((optmask & ARES_OPT_TIMEOUTMS) && channel->timeout == -1)
channel->timeout = options->timeout; channel->timeout = options->timeout;
else if ((optmask & ARES_OPT_TIMEOUT) && channel->timeout == -1)
channel->timeout = options->timeout * 1000;
if ((optmask & ARES_OPT_TRIES) && channel->tries == -1) if ((optmask & ARES_OPT_TRIES) && channel->tries == -1)
channel->tries = options->tries; channel->tries = options->tries;
if ((optmask & ARES_OPT_NDOTS) && channel->ndots == -1) if ((optmask & ARES_OPT_NDOTS) && channel->ndots == -1)

@ -4,6 +4,7 @@
/* $Id$ */ /* $Id$ */
/* Copyright 1998 by the Massachusetts Institute of Technology. /* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright (C) 2004-2008 by Daniel Stenberg
* *
* Permission to use, copy, modify, and distribute this * Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without * software and its documentation for any purpose and without
@ -48,7 +49,7 @@
#include <time.h> #include <time.h>
#endif #endif
#define DEFAULT_TIMEOUT 5 #define DEFAULT_TIMEOUT 5000 /* milliseconds */
#define DEFAULT_TRIES 4 #define DEFAULT_TRIES 4
#ifndef INADDR_NONE #ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff #define INADDR_NONE 0xffffffff
@ -149,7 +150,7 @@ struct server_state {
struct query { struct query {
/* Query ID from qbuf, for faster lookup, and current timeout */ /* Query ID from qbuf, for faster lookup, and current timeout */
unsigned short qid; unsigned short qid;
time_t timeout; struct timeval timeout;
/* /*
* Links for the doubly-linked lists in which we insert a query. * Links for the doubly-linked lists in which we insert a query.
@ -217,7 +218,7 @@ typedef struct rc4_key
struct ares_channeldata { struct ares_channeldata {
/* Configuration data */ /* Configuration data */
int flags; int flags;
int timeout; int timeout; /* in milliseconds */
int tries; int tries;
int ndots; int ndots;
int udp_port; int udp_port;
@ -242,7 +243,8 @@ struct ares_channeldata {
/* Generation number to use for the next TCP socket open/close */ /* Generation number to use for the next TCP socket open/close */
int tcp_connection_generation; int tcp_connection_generation;
/* The time at which we last called process_timeouts() */ /* The time at which we last called process_timeouts(). Uses integer seconds
just to draw the line somewhere. */
time_t last_timeout_processed; time_t last_timeout_processed;
/* Circular, doubly-linked list of queries, bucketed various ways.... */ /* Circular, doubly-linked list of queries, bucketed various ways.... */
@ -259,8 +261,18 @@ struct ares_channeldata {
void *sock_state_cb_data; void *sock_state_cb_data;
}; };
/* return true if now is exactly check time or later */
int ares__timedout(struct timeval *now,
struct timeval *check);
/* add the specific number of milliseconds to the time in the first argument */
int ares__timeadd(struct timeval *now,
int millisecs);
/* return time offset between now and (future) check, in milliseconds */
int ares__timeoffset(struct timeval *now,
struct timeval *check);
void ares__rc4(rc4_key* key,unsigned char *buffer_ptr, int buffer_len); void ares__rc4(rc4_key* key,unsigned char *buffer_ptr, int buffer_len);
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);
void ares__close_sockets(ares_channel channel, struct server_state *server); void ares__close_sockets(ares_channel channel, struct server_state *server);
int ares__get_hostent(FILE *fp, int family, struct hostent **host); int ares__get_hostent(FILE *fp, int family, struct hostent **host);
int ares__read_line(FILE *fp, char **buf, int *bufsize); int ares__read_line(FILE *fp, char **buf, int *bufsize);

@ -1,6 +1,7 @@
/* $Id$ */ /* $Id$ */
/* Copyright 1998 by the Massachusetts Institute of Technology. /* Copyright 1998 by the Massachusetts Institute of Technology.
* Copyright (C) 2004-2008 by Daniel Stenberg
* *
* Permission to use, copy, modify, and distribute this * Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without * software and its documentation for any purpose and without
@ -42,6 +43,9 @@
#ifdef HAVE_ARPA_NAMESER_COMPAT_H #ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h> #include <arpa/nameser_compat.h>
#endif #endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#endif /* WIN32 && !WATT32 */ #endif /* WIN32 && !WATT32 */
#ifdef HAVE_STRINGS_H #ifdef HAVE_STRINGS_H
@ -71,21 +75,25 @@
static int try_again(int errnum); static int try_again(int errnum);
static void write_tcp_data(ares_channel channel, fd_set *write_fds, 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, 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, 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, static void advance_tcp_send_queue(ares_channel channel, int whichserver,
ssize_t num_bytes); ssize_t num_bytes);
static void process_timeouts(ares_channel channel, time_t now); static void process_timeouts(ares_channel channel, struct timeval *now);
static void process_broken_connections(ares_channel channel, time_t now); static void process_broken_connections(ares_channel channel,
struct timeval *now);
static void process_answer(ares_channel channel, unsigned char *abuf, 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,
static void handle_error(ares_channel channel, int whichserver, time_t now); 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, static void skip_server(ares_channel channel, struct query *query,
int whichserver); 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 configure_socket(int s, ares_channel channel);
static int open_tcp_socket(ares_channel channel, struct server_state *server); static int open_tcp_socket(ares_channel channel, struct server_state *server);
static int open_udp_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, static void end_query(ares_channel channel, struct query *query, int status,
unsigned char *abuf, int alen); 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. /* Something interesting happened on the wire, or there was a timeout.
* See what's up and respond accordingly. * See what's up and respond accordingly.
*/ */
void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds) void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
{ {
time_t now; struct timeval now = ares__tvnow();
time(&now); write_tcp_data(channel, write_fds, ARES_SOCKET_BAD, &now);
write_tcp_data(channel, write_fds, ARES_SOCKET_BAD, now); read_tcp_data(channel, read_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);
read_udp_packets(channel, read_fds, ARES_SOCKET_BAD, now); process_timeouts(channel, &now);
process_timeouts(channel, now); process_broken_connections(channel, &now);
process_broken_connections(channel, now);
} }
/* Something interesting happened on the wire, or there was a timeout. /* Something interesting happened on the wire, or there was a timeout.
@ -117,13 +165,12 @@ void ares_process_fd(ares_channel channel,
file descriptors */ file descriptors */
ares_socket_t write_fd) ares_socket_t write_fd)
{ {
time_t now; struct timeval now = ares__tvnow();
time(&now); write_tcp_data(channel, NULL, write_fd, &now);
write_tcp_data(channel, NULL, write_fd, now); read_tcp_data(channel, NULL, read_fd, &now);
read_tcp_data(channel, NULL, read_fd, now); read_udp_packets(channel, NULL, read_fd, &now);
read_udp_packets(channel, NULL, read_fd, now); process_timeouts(channel, &now);
process_timeouts(channel, now);
} }
@ -158,7 +205,7 @@ static int try_again(int errnum)
static void write_tcp_data(ares_channel channel, static void write_tcp_data(ares_channel channel,
fd_set *write_fds, fd_set *write_fds,
ares_socket_t write_fd, ares_socket_t write_fd,
time_t now) struct timeval *now)
{ {
struct server_state *server; struct server_state *server;
struct send_request *sendreq; 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 /* Make sure server has data to send and is selected in write_fds or
write_fd. */ write_fd. */
server = &channel->servers[i]; 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; continue;
if(write_fds) { 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. * a packet if we finish reading one.
*/ */
static void read_tcp_data(ares_channel channel, fd_set *read_fds, 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; struct server_state *server;
int i; 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. */ /* If any UDP sockets select true for reading, process them. */
static void read_udp_packets(ares_channel channel, fd_set *read_fds, 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; struct server_state *server;
int i; 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. */ /* 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 */ time_t t; /* the time of the timeouts we're processing */
struct query *query; 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 * only a handful of requests that fall into the "now" bucket, so
* this should be quite quick. * 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]); list_head = &(channel->queries_by_timeout[t % ARES_TIMEOUT_TABLE_SIZE]);
for (list_node = list_head->next; list_node != list_head; ) for (list_node = list_head->next; list_node != list_head; )
{ {
query = list_node->data; query = list_node->data;
list_node = list_node->next; /* in case the query gets deleted */ 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->error_status = ARES_ETIMEOUT;
++query->timeouts; ++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. */ /* Handle an answer from a server. */
static void process_answer(ares_channel channel, unsigned char *abuf, 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; int tc, rcode;
unsigned short id; 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. */ /* 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; int i;
for (i = 0; i < channel->nservers; 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 server_state *server;
struct query *query; 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. */ /* Advance to the next server or try. */
query->server++; 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); 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 send_request *sendreq;
struct server_state *server; struct server_state *server;
@ -707,16 +760,17 @@ void ares__send_query(ares_channel channel, struct query *query, time_t now)
return; return;
} }
} }
query->timeout = now query->timeout = *now;
+ ((query->try == 0) ? channel->timeout ares__timeadd(&query->timeout,
: channel->timeout << query->try / channel->nservers); (query->try == 0) ? channel->timeout
: channel->timeout << query->try / channel->nservers);
/* Keep track of queries bucketed by timeout, so we can process /* Keep track of queries bucketed by timeout, so we can process
* timeout events quickly. * timeout events quickly.
*/ */
ares__remove_from_list(&(query->queries_by_timeout)); ares__remove_from_list(&(query->queries_by_timeout));
ares__insert_in_list( ares__insert_in_list(
&(query->queries_by_timeout), &(query->queries_by_timeout),
&(channel->queries_by_timeout[query->timeout % &(channel->queries_by_timeout[query->timeout.tv_sec %
ARES_TIMEOUT_TABLE_SIZE])); ARES_TIMEOUT_TABLE_SIZE]));
/* Keep track of queries bucketed by server, so we can process server /* Keep track of queries bucketed by server, so we can process server

@ -39,7 +39,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
{ {
struct query *query; struct query *query;
int i; int i;
time_t now; struct timeval now;
/* Verify that the query is at least long enough to hold the header. */ /* Verify that the query is at least long enough to hold the header. */
if (qlen < HFIXEDSZ || qlen >= (1 << 16)) if (qlen < HFIXEDSZ || qlen >= (1 << 16))
@ -74,7 +74,7 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
/* Compute the query ID. Start with no timeout. */ /* Compute the query ID. Start with no timeout. */
query->qid = (unsigned short)DNS_HEADER_QID(qbuf); query->qid = (unsigned short)DNS_HEADER_QID(qbuf);
query->timeout = 0; query->timeout.tv_sec = query->timeout.tv_usec = 0;
/* Form the TCP query buffer by prepending qlen (as two /* Form the TCP query buffer by prepending qlen (as two
* network-order bytes) to qbuf. * network-order bytes) to qbuf.
@ -114,10 +114,10 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
* responses quickly. * responses quickly.
*/ */
ares__insert_in_list( ares__insert_in_list(
&(query->queries_by_qid), &(query->queries_by_qid),
&(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE])); &(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE]));
/* Perform the first query action. */ /* Perform the first query action. */
time(&now); now = ares__tvnow();
ares__send_query(channel, query, now); ares__send_query(channel, query, &now);
} }

@ -37,16 +37,16 @@ struct timeval *ares_timeout(ares_channel channel, struct timeval *maxtv,
struct query *query; struct query *query;
struct list_node* list_head; struct list_node* list_head;
struct list_node* list_node; struct list_node* list_node;
time_t now; struct timeval now;
time_t offset, min_offset; /* these use time_t since some 32 bit systems struct timeval nextstop;
still use 64 bit time_t! (like VS2005) */ long offset, min_offset;
/* No queries, no timeout (and no fetch of the current time). */ /* No queries, no timeout (and no fetch of the current time). */
if (ares__is_list_empty(&(channel->all_queries))) if (ares__is_list_empty(&(channel->all_queries)))
return maxtv; return maxtv;
/* Find the minimum timeout for the current set of queries. */ /* Find the minimum timeout for the current set of queries. */
time(&now); now = ares__tvnow();
min_offset = -1; min_offset = -1;
list_head = &(channel->all_queries); list_head = &(channel->all_queries);
@ -54,23 +54,26 @@ struct timeval *ares_timeout(ares_channel channel, struct timeval *maxtv,
list_node = list_node->next) list_node = list_node->next)
{ {
query = list_node->data; query = list_node->data;
if (query->timeout == 0) if (query->timeout.tv_sec == 0)
continue; continue;
offset = query->timeout - now; offset = ares__timeoffset(&now, &query->timeout);
if (offset < 0) if (offset < 0)
offset = 0; offset = 0;
if (min_offset == -1 || offset < min_offset) if (min_offset == -1 || offset < min_offset)
min_offset = offset; min_offset = offset;
} }
/* If we found a minimum timeout and it's sooner than the one if(min_offset != -1) {
* specified in maxtv (if any), return it. Otherwise go with nextstop = now;
* maxtv. ares__timeadd(&now, min_offset);
}
/* If we found a minimum timeout and it's sooner than the one specified in
* maxtv (if any), return it. Otherwise go with maxtv.
*/ */
if (min_offset != -1 && (!maxtv || min_offset <= maxtv->tv_sec)) if (min_offset != -1 && (!maxtv || ares__timedout(maxtv, &nextstop)))
{ {
tvbuf->tv_sec = (long)min_offset; *tvbuf = nextstop;
tvbuf->tv_usec = 0;
return tvbuf; return tvbuf;
} }
else else

Loading…
Cancel
Save