From f70f09f01c5c904b890dbe440184a580f435d1fd Mon Sep 17 00:00:00 2001 From: Brad House Date: Wed, 29 May 2024 12:07:43 -0400 Subject: [PATCH] Fix windows y2k38 issue by creating our own timeval datatype (#772) As per Issue #760, the use of `struct timeval` is meant for only time differentials, however it could be used to denote an exact timeout. This could lead to y2k38 issues on some platforms. Fixes Issue #760 Fix By: Brad House (@bradh352) --- src/lib/ares__close_sockets.c | 2 +- src/lib/ares__threads.c | 16 +++---- src/lib/ares__timeval.c | 89 ++++++++++++++--------------------- src/lib/ares_init.c | 8 ++-- src/lib/ares_private.h | 48 +++++++++++-------- src/lib/ares_process.c | 52 ++++++++++---------- src/lib/ares_qcache.c | 18 +++---- src/lib/ares_rand.c | 6 +-- src/lib/ares_send.c | 8 ++-- src/lib/ares_timeout.c | 59 ++++++++++++++++------- src/lib/ares_update_servers.c | 4 +- test/ares-test.cc | 38 ++++++++------- 12 files changed, 186 insertions(+), 162 deletions(-) diff --git a/src/lib/ares__close_sockets.c b/src/lib/ares__close_sockets.c index 13ecca8f..03ba4abf 100644 --- a/src/lib/ares__close_sockets.c +++ b/src/lib/ares__close_sockets.c @@ -34,7 +34,7 @@ static void ares__requeue_queries(struct server_connection *conn) { struct query *query; - struct timeval now = ares__tvnow(); + ares_timeval_t now = ares__tvnow(); while ((query = ares__llist_first_val(conn->queries_to_conn)) != NULL) { ares__requeue_query(query, &now); diff --git a/src/lib/ares__threads.c b/src/lib/ares__threads.c index 39d98d22..b0454f74 100644 --- a/src/lib/ares__threads.c +++ b/src/lib/ares__threads.c @@ -551,7 +551,7 @@ void ares__channel_unlock(const ares_channel_t *channel) ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms) { ares_status_t status = ARES_SUCCESS; - struct timeval tout; + ares_timeval_t tout; if (!ares_threadsafety()) { return ARES_ENOTIMP; @@ -562,9 +562,9 @@ ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms) } if (timeout_ms >= 0) { - tout = ares__tvnow(); - tout.tv_sec += timeout_ms / 1000; - tout.tv_usec += (timeout_ms % 1000) * 1000; + tout = ares__tvnow(); + tout.sec += (ares_int64_t)(timeout_ms / 1000); + tout.usec += (unsigned int)(timeout_ms % 1000) * 1000; } ares__thread_mutex_lock(channel->lock); @@ -572,13 +572,13 @@ ares_status_t ares_queue_wait_empty(ares_channel_t *channel, int timeout_ms) if (timeout_ms < 0) { ares__thread_cond_wait(channel->cond_empty, channel->lock); } else { - struct timeval tv_remaining; - struct timeval tv_now = ares__tvnow(); + ares_timeval_t tv_remaining; + ares_timeval_t tv_now = ares__tvnow(); unsigned long tms; ares__timeval_remaining(&tv_remaining, &tv_now, &tout); - tms = (unsigned long)((tv_remaining.tv_sec * 1000) + - (tv_remaining.tv_usec / 1000)); + tms = (unsigned long)((tv_remaining.sec * 1000) + + (tv_remaining.usec / 1000)); if (tms == 0) { status = ARES_ETIMEOUT; } else { diff --git a/src/lib/ares__timeval.c b/src/lib/ares__timeval.c index 11996f9f..801214b3 100644 --- a/src/lib/ares__timeval.c +++ b/src/lib/ares__timeval.c @@ -30,79 +30,62 @@ #if defined(WIN32) && !defined(MSDOS) -struct timeval ares__tvnow(void) +ares_timeval_t ares__tvnow(void) { - /* - ** GetTickCount() is available on _all_ Windows versions from W95 up - ** to nowadays. Returns milliseconds elapsed since last system boot, - ** increases monotonically and wraps once 49.7 days have elapsed. - */ - struct timeval now; + /* GetTickCount() is available on _all_ Windows versions from W95 up + * to nowadays. Returns milliseconds elapsed since last system boot, + * increases monotonically and wraps once 49.7 days have elapsed. */ + ares_timeval_t now; DWORD milliseconds = GetTickCount(); - now.tv_sec = (long)milliseconds / 1000; - now.tv_usec = (long)(milliseconds % 1000) * 1000; + + now.sec = (ares_int64_t)milliseconds / 1000; + now.usec = (unsigned int)(milliseconds % 1000) * 1000; return now; } #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) -struct timeval ares__tvnow(void) +ares_timeval_t ares__tvnow(void) { - /* - ** clock_gettime() is granted to be increased monotonically when the - ** monotonic clock is queried. Time starting point is unspecified, it - ** could be the system start-up time, the Epoch, or something else, - ** in any case the time starting point does not change once that the - ** system has started up. - */ - struct timeval now; + /* clock_gettime() is guaranteed to be increased monotonically when the + * monotonic clock is queried. Time starting point is unspecified, it + * could be the system start-up time, the Epoch, or something else, + * in any case the time starting point does not change once that the + * system has started up. */ + ares_timeval_t now; struct timespec tsnow; - if (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) { - now.tv_sec = tsnow.tv_sec; - now.tv_usec = (int)(tsnow.tv_nsec / 1000); - } - /* - ** Even when the configure process has truly detected monotonic clock - ** availability, it might happen that it is not actually available at - ** run-time. When this occurs simply fallback to other time source. - */ -# ifdef HAVE_GETTIMEOFDAY - else - (void)gettimeofday(&now, NULL); /* LCOV_EXCL_LINE */ -# else - else { - now.tv_sec = (long)time(NULL); - now.tv_usec = 0; + + if (clock_gettime(CLOCK_MONOTONIC, &tsnow) == 0) { + now.sec = (ares_int64_t)tsnow.tv_sec; + now.usec = (unsigned int)(tsnow.tv_nsec / 1000); + } else { + struct timeval tv; + (void)gettimeofday(&tv, NULL); + now.sec = (ares_int64_t)tv.tv_sec; + now.usec = (unsigned int)tv.tv_usec; } -# endif return now; } #elif defined(HAVE_GETTIMEOFDAY) -struct timeval ares__tvnow(void) +ares_timeval_t ares__tvnow(void) { - /* - ** gettimeofday() is not granted to be increased monotonically, due to - ** clock drifting and external source time synchronization it can jump - ** forward or backward in time. - */ - struct timeval now; - (void)gettimeofday(&now, NULL); + /* gettimeofday() is not granted to be increased monotonically, due to + * clock drifting and external source time synchronization it can jump + * forward or backward in time. */ + ares_timeval_t now; + struct timeval tv; + + (void)gettimeofday(&tv, NULL); + now.sec = (ares_int64_t)tv.tv_sec; + now.usec = (unsigned int)tv.tv_usec; + return now; } #else -struct timeval ares__tvnow(void) -{ - /* - ** time() returns the value of time in seconds since the Epoch. - */ - struct timeval now; - now.tv_sec = (long)time(NULL); - now.tv_usec = 0; - return now; -} +# error missing sub-second time retrieval function #endif diff --git a/src/lib/ares_init.c b/src/lib/ares_init.c index 518abd54..c8b4c345 100644 --- a/src/lib/ares_init.c +++ b/src/lib/ares_init.c @@ -82,17 +82,17 @@ static int ares_query_timeout_cmp_cb(const void *arg1, const void *arg2) const struct query *q1 = arg1; const struct query *q2 = arg2; - if (q1->timeout.tv_sec > q2->timeout.tv_sec) { + if (q1->timeout.sec > q2->timeout.sec) { return 1; } - if (q1->timeout.tv_sec < q2->timeout.tv_sec) { + if (q1->timeout.sec < q2->timeout.sec) { return -1; } - if (q1->timeout.tv_usec > q2->timeout.tv_usec) { + if (q1->timeout.usec > q2->timeout.usec) { return 1; } - if (q1->timeout.tv_usec < q2->timeout.tv_usec) { + if (q1->timeout.usec < q2->timeout.usec) { return -1; } diff --git a/src/lib/ares_private.h b/src/lib/ares_private.h index fd290c4d..4ea89f4b 100644 --- a/src/lib/ares_private.h +++ b/src/lib/ares_private.h @@ -167,6 +167,22 @@ struct server_connection { ares__llist_t *queries_to_conn; }; +#ifdef _MSC_VER +typedef __int64 ares_int64_t; +typedef unsigned __int64 ares_uint64_t; +#else +typedef long long ares_int64_t; +typedef unsigned long long ares_uint64_t; +#endif + +/*! struct timeval on some systems like Windows doesn't support 64bit time so + * therefore can't be used due to Y2K38 issues. Make our own that does have + * 64bit time. */ +typedef struct { + ares_int64_t sec; /*!< Seconds */ + unsigned int usec; /*!< Microseconds. Can't be negative. */ +} ares_timeval_t; + struct server_state { /* Configuration */ size_t idx; /* index for server in system configuration */ @@ -183,7 +199,7 @@ struct server_state { struct server_connection *tcp_conn; /* The next time when we will retry this server if it has hit failures */ - struct timeval next_retry_time; + ares_timeval_t next_retry_time; /* TCP buffer since multiple responses can come back in one read, or partial * in a read */ @@ -200,7 +216,7 @@ struct server_state { struct query { /* Query ID from qbuf, for faster lookup, and current timeout */ unsigned short qid; /* host byte order */ - struct timeval timeout; + ares_timeval_t timeout; ares_channel_t *channel; /* @@ -358,12 +374,12 @@ void *ares_malloc_zero(size_t size); void *ares_realloc_zero(void *ptr, size_t orig_size, size_t new_size); /* return true if now is exactly check time or later */ -ares_bool_t ares__timedout(const struct timeval *now, - const struct timeval *check); +ares_bool_t ares__timedout(const ares_timeval_t *now, + const ares_timeval_t *check); /* Returns one of the normal ares status codes like ARES_SUCCESS */ -ares_status_t ares__send_query(struct query *query, struct timeval *now); -ares_status_t ares__requeue_query(struct query *query, struct timeval *now); +ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now); +ares_status_t ares__requeue_query(struct query *query, const ares_timeval_t *now); /*! Retrieve a list of names to use for searching. The first successful * query in the list wins. This function also uses the HOSTSALIASES file @@ -402,10 +418,10 @@ void ares__destroy_rand_state(ares_rand_state *state); void ares__rand_bytes(ares_rand_state *state, unsigned char *buf, size_t len); unsigned short ares__generate_new_id(ares_rand_state *state); -struct timeval ares__tvnow(void); -void ares__timeval_remaining(struct timeval *remaining, - const struct timeval *now, - const struct timeval *tout); +ares_timeval_t ares__tvnow(void); +void ares__timeval_remaining(ares_timeval_t *remaining, + const ares_timeval_t *now, + const ares_timeval_t *tout); ares_status_t ares__expand_name_validated(const unsigned char *encoded, const unsigned char *abuf, size_t alen, char **s, size_t *enclen, @@ -640,11 +656,11 @@ ares_status_t ares__qcache_create(ares_rand_state *rand_state, ares__qcache_t **cache_out); void ares__qcache_flush(ares__qcache_t *cache); ares_status_t ares_qcache_insert(ares_channel_t *channel, - const struct timeval *now, + const ares_timeval_t *now, const struct query *query, ares_dns_record_t *dnsrec); ares_status_t ares_qcache_fetch(ares_channel_t *channel, - const struct timeval *now, + const ares_timeval_t *now, const ares_dns_record_t *dnsrec, const ares_dns_record_t **dnsrec_resp); @@ -660,14 +676,6 @@ void ares_event_thread_destroy(ares_channel_t *channel); ares_status_t ares_event_thread_init(ares_channel_t *channel); -#ifdef _MSC_VER -typedef __int64 ares_int64_t; -typedef unsigned __int64 ares_uint64_t; -#else -typedef long long ares_int64_t; -typedef unsigned long long ares_uint64_t; -#endif - #ifdef _WIN32 # define HOSTENT_ADDRTYPE_TYPE short # define HOSTENT_LENGTH_TYPE short diff --git a/src/lib/ares_process.c b/src/lib/ares_process.c index eefcc782..967e6cc0 100644 --- a/src/lib/ares_process.c +++ b/src/lib/ares_process.c @@ -50,17 +50,17 @@ #include "ares_nameser.h" #include "ares_dns.h" -static void timeadd(struct timeval *now, size_t millisecs); +static void timeadd(ares_timeval_t *now, size_t millisecs); static ares_bool_t try_again(int errnum); static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds, ares_socket_t write_fd); static void read_packets(ares_channel_t *channel, fd_set *read_fds, - ares_socket_t read_fd, struct timeval *now); -static void process_timeouts(ares_channel_t *channel, struct timeval *now); + ares_socket_t read_fd, ares_timeval_t *now); +static void process_timeouts(ares_channel_t *channel, ares_timeval_t *now); static ares_status_t process_answer(ares_channel_t *channel, const unsigned char *abuf, size_t alen, struct server_connection *conn, - ares_bool_t tcp, struct timeval *now); + ares_bool_t tcp, ares_timeval_t *now); static void handle_conn_error(struct server_connection *conn, ares_bool_t critical_failure); @@ -111,7 +111,7 @@ static void server_increment_failures(struct server_state *server, { ares__slist_node_t *node; const ares_channel_t *channel = server->channel; - struct timeval next_retry_time; + ares_timeval_t next_retry_time; node = ares__slist_node_find(channel->servers, server); if (node == NULL) { @@ -145,8 +145,8 @@ static void server_set_good(struct server_state *server, ares_bool_t used_tcp) ares__slist_node_reinsert(node); } - server->next_retry_time.tv_sec = 0; - server->next_retry_time.tv_usec = 0; + server->next_retry_time.sec = 0; + server->next_retry_time.usec = 0; invoke_server_state_cb(server, ARES_TRUE, used_tcp == ARES_TRUE ? ARES_SERV_STATE_TCP @@ -154,10 +154,10 @@ static void server_set_good(struct server_state *server, ares_bool_t used_tcp) } /* return true if now is exactly check time or later */ -ares_bool_t ares__timedout(const struct timeval *now, - const struct timeval *check) +ares_bool_t ares__timedout(const ares_timeval_t *now, + const ares_timeval_t *check) { - ares_int64_t secs = ((ares_int64_t)now->tv_sec - (ares_int64_t)check->tv_sec); + ares_int64_t secs = (now->sec - check->sec); if (secs > 0) { return ARES_TRUE; /* yes, timed out */ @@ -167,20 +167,20 @@ ares_bool_t ares__timedout(const struct timeval *now, } /* if the full seconds were identical, check the sub second parts */ - return ((ares_int64_t)now->tv_usec - (ares_int64_t)check->tv_usec) >= 0 + return ((ares_int64_t)now->usec - (ares_int64_t)check->usec) >= 0 ? ARES_TRUE : ARES_FALSE; } /* add the specific number of milliseconds to the time in the first argument */ -static void timeadd(struct timeval *now, size_t millisecs) +static void timeadd(ares_timeval_t *now, size_t millisecs) { - now->tv_sec += (time_t)millisecs / 1000; - now->tv_usec += (time_t)((millisecs % 1000) * 1000); + now->sec += (ares_int64_t)millisecs / 1000; + now->usec += (unsigned int)((millisecs % 1000) * 1000); - if (now->tv_usec >= 1000000) { - ++(now->tv_sec); - now->tv_usec -= 1000000; + if (now->usec >= 1000000) { + now->sec += now->usec / 1000000; + now->usec %= 1000000; } } @@ -191,7 +191,7 @@ static void processfds(ares_channel_t *channel, fd_set *read_fds, ares_socket_t read_fd, fd_set *write_fds, ares_socket_t write_fd) { - struct timeval now; + ares_timeval_t now; if (channel == NULL) { return; @@ -324,7 +324,7 @@ static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds, * a packet if we finish reading one. */ static void read_tcp_data(ares_channel_t *channel, - struct server_connection *conn, struct timeval *now) + struct server_connection *conn, ares_timeval_t *now) { ares_ssize_t count; struct server_state *server = conn->server; @@ -463,7 +463,7 @@ fail: /* If any UDP sockets select true for reading, process them. */ static void read_udp_packets_fd(ares_channel_t *channel, struct server_connection *conn, - struct timeval *now) + ares_timeval_t *now) { ares_ssize_t read_len; unsigned char buf[MAXENDSSZ + 1]; @@ -527,7 +527,7 @@ static void read_udp_packets_fd(ares_channel_t *channel, } static void read_packets(ares_channel_t *channel, fd_set *read_fds, - ares_socket_t read_fd, struct timeval *now) + ares_socket_t read_fd, ares_timeval_t *now) { size_t i; ares_socket_t *socketlist = NULL; @@ -594,7 +594,7 @@ static void read_packets(ares_channel_t *channel, fd_set *read_fds, } /* If any queries have timed out, note the timeout and move them on. */ -static void process_timeouts(ares_channel_t *channel, struct timeval *now) +static void process_timeouts(ares_channel_t *channel, ares_timeval_t *now) { ares__slist_node_t *node = ares__slist_node_first(channel->queries_by_timeout); @@ -667,7 +667,7 @@ done: static ares_status_t process_answer(ares_channel_t *channel, const unsigned char *abuf, size_t alen, struct server_connection *conn, - ares_bool_t tcp, struct timeval *now) + ares_bool_t tcp, ares_timeval_t *now) { struct query *query; /* Cache these as once ares__send_query() gets called, it may end up @@ -814,7 +814,7 @@ static void handle_conn_error(struct server_connection *conn, ares__close_connection(conn); } -ares_status_t ares__requeue_query(struct query *query, struct timeval *now) +ares_status_t ares__requeue_query(struct query *query, const ares_timeval_t *now) { ares_channel_t *channel = query->channel; size_t max_tries = ares__slist_len(channel->servers) * channel->tries; @@ -912,7 +912,7 @@ static struct server_state *ares__failover_server(ares_channel_t *channel) ares__rand_bytes(channel->rand_state, (unsigned char *)&r, sizeof(r)); if (r % channel->server_retry_chance == 0) { /* Select a suitable failed server to retry. */ - struct timeval now = ares__tvnow(); + ares_timeval_t now = ares__tvnow(); ares__slist_node_t *node; for (node = ares__slist_node_first(channel->servers); node != NULL; node = ares__slist_node_next(node)) { @@ -989,7 +989,7 @@ static size_t ares__calc_query_timeout(const struct query *query) return timeplus; } -ares_status_t ares__send_query(struct query *query, struct timeval *now) +ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now) { ares_channel_t *channel = query->channel; struct server_state *server; diff --git a/src/lib/ares_qcache.c b/src/lib/ares_qcache.c index 2af1125a..cf841dcb 100644 --- a/src/lib/ares_qcache.c +++ b/src/lib/ares_qcache.c @@ -137,7 +137,7 @@ fail: } static void ares__qcache_expire(ares__qcache_t *cache, - const struct timeval *now) + const ares_timeval_t *now) { ares__slist_node_t *node; @@ -147,7 +147,7 @@ static void ares__qcache_expire(ares__qcache_t *cache, while ((node = ares__slist_node_first(cache->expire)) != NULL) { const ares__qcache_entry_t *entry = ares__slist_node_val(node); - if (entry->expire_ts > now->tv_sec) { + if (entry->expire_ts > now->sec) { break; } @@ -158,7 +158,7 @@ static void ares__qcache_expire(ares__qcache_t *cache, void ares__qcache_flush(ares__qcache_t *cache) { - struct timeval now; + ares_timeval_t now; memset(&now, 0, sizeof(now)); ares__qcache_expire(cache, &now); } @@ -319,7 +319,7 @@ done: static ares_status_t ares__qcache_insert(ares__qcache_t *qcache, ares_dns_record_t *dnsrec, const unsigned char *qbuf, size_t qlen, - const struct timeval *now) + const ares_timeval_t *now) { ares__qcache_entry_t *entry; unsigned int ttl; @@ -362,8 +362,8 @@ static ares_status_t ares__qcache_insert(ares__qcache_t *qcache, } entry->dnsrec = dnsrec; - entry->expire_ts = now->tv_sec + (time_t)ttl; - entry->insert_ts = now->tv_sec; + entry->expire_ts = now->sec + (time_t)ttl; + entry->insert_ts = now->sec; /* We can't guarantee the server responded with the same flags as the * request had, so we have to re-parse the request in order to generate the @@ -394,7 +394,7 @@ fail: } ares_status_t ares_qcache_fetch(ares_channel_t *channel, - const struct timeval *now, + const ares_timeval_t *now, const ares_dns_record_t *dnsrec, const ares_dns_record_t **dnsrec_resp) { @@ -425,7 +425,7 @@ ares_status_t ares_qcache_fetch(ares_channel_t *channel, } ares_dns_record_write_ttl_decrement( - entry->dnsrec, (unsigned int)(now->tv_sec - entry->insert_ts)); + entry->dnsrec, (unsigned int)(now->sec - entry->insert_ts)); *dnsrec_resp = entry->dnsrec; @@ -435,7 +435,7 @@ done: } ares_status_t ares_qcache_insert(ares_channel_t *channel, - const struct timeval *now, + const ares_timeval_t *now, const struct query *query, ares_dns_record_t *dnsrec) { diff --git a/src/lib/ares_rand.c b/src/lib/ares_rand.c index a7a74c9a..bf3a695c 100644 --- a/src/lib/ares_rand.c +++ b/src/lib/ares_rand.c @@ -70,7 +70,7 @@ static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key, size_t i; size_t len = 0; unsigned int data; - struct timeval tv; + ares_timeval_t tv; if (key_len != ARES_RC4_KEY_LEN) { return; @@ -89,12 +89,12 @@ static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key, len += sizeof(data); tv = ares__tvnow(); - data = (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF); + data = (unsigned int)((tv.sec | tv.usec) & 0xFFFFFFFF); memcpy(key + len, &data, sizeof(data)); len += sizeof(data); srand(ares_u32_from_ptr(rc4_state) | ares_u32_from_ptr(&i) | - (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF)); + (unsigned int)((tv.sec | tv.usec) & 0xFFFFFFFF)); for (i = len; i < key_len; i++) { key[i] = (unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */ diff --git a/src/lib/ares_send.c b/src/lib/ares_send.c index d15a9b95..8bbc6e75 100644 --- a/src/lib/ares_send.c +++ b/src/lib/ares_send.c @@ -55,7 +55,7 @@ static ares_status_t ares_send_dnsrec_int(ares_channel_t *channel, { struct query *query; size_t packetsz; - struct timeval now = ares__tvnow(); + ares_timeval_t now = ares__tvnow(); ares_status_t status; unsigned short id = generate_unique_qid(channel); const ares_dns_record_t *dnsrec_resp = NULL; @@ -91,9 +91,9 @@ static ares_status_t ares_send_dnsrec_int(ares_channel_t *channel, return status; } - query->qid = id; - query->timeout.tv_sec = 0; - query->timeout.tv_usec = 0; + query->qid = id; + query->timeout.sec = 0; + query->timeout.usec = 0; /* Ignore first 2 bytes, assign our own query id */ query->qbuf[0] = (unsigned char)((id >> 8) & 0xFF); diff --git a/src/lib/ares_timeout.c b/src/lib/ares_timeout.c index 7e60acb2..cca681ae 100644 --- a/src/lib/ares_timeout.c +++ b/src/lib/ares_timeout.c @@ -34,62 +34,89 @@ #include "ares.h" #include "ares_private.h" -void ares__timeval_remaining(struct timeval *remaining, - const struct timeval *now, - const struct timeval *tout) +void ares__timeval_remaining(ares_timeval_t *remaining, + const ares_timeval_t *now, + const ares_timeval_t *tout) { memset(remaining, 0, sizeof(*remaining)); /* Expired! */ - if (tout->tv_sec < now->tv_sec || - (tout->tv_sec == now->tv_sec && tout->tv_usec < now->tv_usec)) { + if (tout->sec < now->sec || + (tout->sec == now->sec && tout->usec < now->usec)) { return; } - remaining->tv_sec = tout->tv_sec - now->tv_sec; - if (tout->tv_usec < now->tv_usec) { - remaining->tv_sec -= 1; - remaining->tv_usec = (tout->tv_usec + 1000000) - now->tv_usec; + remaining->sec = tout->sec - now->sec; + if (tout->usec < now->usec) { + remaining->sec -= 1; + remaining->usec = (tout->usec + 1000000) - now->usec; } else { - remaining->tv_usec = tout->tv_usec - now->tv_usec; + remaining->usec = tout->usec - now->usec; } } +static struct timeval ares_timeval_to_struct_timeval(const ares_timeval_t *atv) +{ + struct timeval tv; + + tv.tv_sec = (time_t)atv->sec; + tv.tv_usec = (int)atv->usec; + + return tv; +} + + +static ares_timeval_t struct_timeval_to_ares_timeval(const struct timeval *tv) +{ + ares_timeval_t atv; + + atv.sec = (ares_int64_t)tv->tv_sec; + atv.usec = (unsigned int)tv->tv_usec; + + return atv; +} + struct timeval *ares_timeout(const ares_channel_t *channel, struct timeval *maxtv, struct timeval *tvbuf) { const struct query *query; ares__slist_node_t *node; - struct timeval now; + ares_timeval_t now; + ares_timeval_t atvbuf; + ares_timeval_t amaxtv; /* The minimum timeout of all queries is always the first entry in * channel->queries_by_timeout */ node = ares__slist_node_first(channel->queries_by_timeout); /* no queries/timeout */ if (node == NULL) { - return maxtv; /* <-- maxtv can be null though, hrm */ + return maxtv; } query = ares__slist_node_val(node); now = ares__tvnow(); - ares__timeval_remaining(tvbuf, &now, &query->timeout); + ares__timeval_remaining(&atvbuf, &now, &query->timeout); + + *tvbuf = ares_timeval_to_struct_timeval(&atvbuf); if (maxtv == NULL) { return tvbuf; } /* Return the minimum time between maxtv and tvbuf */ + amaxtv = struct_timeval_to_ares_timeval(maxtv); - if (tvbuf->tv_sec > maxtv->tv_sec) { + if (atvbuf.sec > amaxtv.sec) { return maxtv; } - if (tvbuf->tv_sec < maxtv->tv_sec) { + + if (atvbuf.sec < amaxtv.sec) { return tvbuf; } - if (tvbuf->tv_usec > maxtv->tv_usec) { + if (atvbuf.usec > amaxtv.usec) { return maxtv; } diff --git a/src/lib/ares_update_servers.c b/src/lib/ares_update_servers.c index 847a78a6..a3e9f0d0 100644 --- a/src/lib/ares_update_servers.c +++ b/src/lib/ares_update_servers.c @@ -593,8 +593,8 @@ static ares_status_t ares__server_create(ares_channel_t *channel, server->udp_port = ares__sconfig_get_port(channel, sconfig, ARES_FALSE); server->tcp_port = ares__sconfig_get_port(channel, sconfig, ARES_TRUE); server->addr.family = sconfig->addr.family; - server->next_retry_time.tv_sec = 0; - server->next_retry_time.tv_usec = 0; + server->next_retry_time.sec = 0; + server->next_retry_time.usec = 0; if (sconfig->addr.family == AF_INET) { memcpy(&server->addr.addr.addr4, &sconfig->addr.addr.addr4, diff --git a/test/ares-test.cc b/test/ares-test.cc index 5b03c630..aa28b0df 100644 --- a/test/ares-test.cc +++ b/test/ares-test.cc @@ -257,13 +257,13 @@ void ProcessWork(ares_channel_t *channel, fd_set readers, writers; #ifndef CARES_SYMBOL_HIDING - struct timeval tv_begin = ares__tvnow(); - struct timeval tv_cancel = tv_begin; + ares_timeval_t tv_begin = ares__tvnow(); + ares_timeval_t tv_cancel = tv_begin; if (cancel_ms) { if (verbose) std::cerr << "ares_cancel will be called after " << cancel_ms << "ms" << std::endl; - tv_cancel.tv_sec += (cancel_ms / 1000); - tv_cancel.tv_usec += ((cancel_ms % 1000) * 1000); + tv_cancel.sec += (cancel_ms / 1000); + tv_cancel.usec += ((cancel_ms % 1000) * 1000); } #else if (cancel_ms) { @@ -274,8 +274,8 @@ void ProcessWork(ares_channel_t *channel, while (true) { #ifndef CARES_SYMBOL_HIDING - struct timeval tv_now = ares__tvnow(); - struct timeval tv_remaining; + ares_timeval_t tv_now = ares__tvnow(); + ares_timeval_t atv_remaining; #endif struct timeval tv; struct timeval *tv_select; @@ -305,15 +305,21 @@ void ProcessWork(ares_channel_t *channel, #ifndef CARES_SYMBOL_HIDING if (cancel_ms) { unsigned int remaining_ms; - ares__timeval_remaining(&tv_remaining, + ares__timeval_remaining(&atv_remaining, &tv_now, &tv_cancel); - remaining_ms = (unsigned int)((tv_remaining.tv_sec * 1000) + (tv_remaining.tv_usec / 1000)); + + remaining_ms = (unsigned int)((atv_remaining.sec * 1000) + (atv_remaining.usec / 1000)); if (remaining_ms == 0) { if (verbose) std::cerr << "Issuing ares_cancel()" << std::endl; ares_cancel(channel); cancel_ms = 0; /* Disable issuing cancel again */ } else { + struct timeval tv_remaining; + + tv_remaining.tv_sec = atv_remaining.sec; + tv_remaining.tv_usec = (int)atv_remaining.usec; + /* Recalculate proper timeout since we also have a cancel to wait on */ tv_select = ares_timeout(channel, &tv_remaining, &tv); } @@ -831,8 +837,8 @@ void MockEventThreadOptsTest::ProcessThread() { #ifndef CARES_SYMBOL_HIDING bool has_cancel_ms = false; - struct timeval tv_begin; - struct timeval tv_cancel; + ares_timeval_t tv_begin; + ares_timeval_t tv_cancel; #endif mutex.lock(); @@ -841,14 +847,14 @@ void MockEventThreadOptsTest::ProcessThread() { int nfds = 0; fd_set readers; #ifndef CARES_SYMBOL_HIDING - struct timeval tv_now = ares__tvnow(); - struct timeval tv_remaining; + ares_timeval_t tv_now = ares__tvnow(); + ares_timeval_t atv_remaining; if (cancel_ms_ && !has_cancel_ms) { tv_begin = ares__tvnow(); tv_cancel = tv_begin; if (verbose) std::cerr << "ares_cancel will be called after " << cancel_ms_ << "ms" << std::endl; - tv_cancel.tv_sec += (cancel_ms_ / 1000); - tv_cancel.tv_usec += ((cancel_ms_ % 1000) * 1000); + tv_cancel.sec += (cancel_ms_ / 1000); + tv_cancel.usec += ((cancel_ms_ % 1000) * 1000); has_cancel_ms = true; } #else @@ -873,10 +879,10 @@ void MockEventThreadOptsTest::ProcessThread() { #ifndef CARES_SYMBOL_HIDING if (has_cancel_ms) { unsigned int remaining_ms; - ares__timeval_remaining(&tv_remaining, + ares__timeval_remaining(&atv_remaining, &tv_now, &tv_cancel); - remaining_ms = (unsigned int)((tv_remaining.tv_sec * 1000) + (tv_remaining.tv_usec / 1000)); + remaining_ms = (unsigned int)((atv_remaining.sec * 1000) + (atv_remaining.usec / 1000)); if (remaining_ms == 0) { if (verbose) std::cerr << "Issuing ares_cancel()" << std::endl; ares_cancel(channel_);