From b9d25f9a6b3ca791385b80a6a3c3fa5ae113e1e0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 23 Oct 2017 12:05:49 +0200 Subject: [PATCH] timediff: return timediff_t from the time diff functions ... to cater for systems with unsigned time_t variables. - Renamed the functions to curlx_timediff and Curl_timediff_us. - Added overflow protection for both of them in either direction for both 32 bit and 64 bit time_ts - Reprefixed the curlx_time functions to use Curl_* Reported-by: Peter Piekarski Fixes #2004 Closes #2005 --- lib/asyn-ares.c | 2 +- lib/asyn-thread.c | 3 +- lib/connect.c | 8 +-- lib/easy.c | 12 ++--- lib/ftp.c | 2 +- lib/hostip.c | 4 +- lib/multi.c | 24 +++++---- lib/pingpong.c | 4 +- lib/progress.c | 18 +++---- lib/rand.c | 2 +- lib/select.c | 8 +-- lib/speedcheck.c | 2 +- lib/telnet.c | 4 +- lib/timeval.c | 55 +++++++++---------- lib/timeval.h | 27 +++++----- lib/transfer.c | 9 ++-- lib/url.c | 14 ++--- lib/vtls/openssl.c | 8 +-- tests/server/Makefile.inc | 2 - tests/server/util.c | 111 ++++++++++++++++++++++++++++++++++++-- tests/server/util.h | 3 +- tests/unit/unit1323.c | 2 +- 22 files changed, 214 insertions(+), 110 deletions(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 87e70b4d9..0fbf321b9 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -401,7 +401,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, result = CURLE_ABORTED_BY_CALLBACK; else { struct curltime now2 = Curl_tvnow(); - time_t timediff = Curl_tvdiff(now2, now); /* spent time */ + timediff_t timediff = Curl_timediff(now2, now); /* spent time */ if(timediff <= 0) timeout -= 1; /* always deduct at least 1 */ else if(timediff > timeout) diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index a86772965..96babb728 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -535,7 +535,8 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, } else { /* poll for name lookup done with exponential backoff up to 250ms */ - time_t elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + timediff_t elapsed = Curl_timediff(Curl_tvnow(), + data->progress.t_startsingle); if(elapsed < 0) elapsed = 0; diff --git a/lib/connect.c b/lib/connect.c index b7d10af55..7bf82d14a 100755 --- a/lib/connect.c +++ b/lib/connect.c @@ -225,10 +225,10 @@ time_t Curl_timeleft(struct Curl_easy *data, /* subtract elapsed time */ if(duringconnect) /* since this most recent connect started */ - timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle); + timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle); else /* since the entire operation started */ - timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop); + timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop); if(!timeout_ms) /* avoid returning 0 as that means no timeout! */ return -1; @@ -765,7 +765,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, if(rc == 0) { /* no connection yet */ error = 0; - if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { + if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) { infof(data, "After %ldms connect time, move on!\n", conn->timeoutms_per_addr); error = ETIMEDOUT; @@ -773,7 +773,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, /* should we try another protocol family? */ if(i == 0 && conn->tempaddr[1] == NULL && - curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) { + Curl_timediff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) { trynextip(conn, sockindex, 1); } } diff --git a/lib/easy.c b/lib/easy.c index 5328f9c2d..212d6f3da 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -586,12 +586,12 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) } /* get the time stamp to use to figure out how long poll takes */ - before = curlx_tvnow(); + before = Curl_tvnow(); /* wait for activity or timeout */ pollrc = Curl_poll(fds, numfds, (int)ev->ms); - after = curlx_tvnow(); + after = Curl_tvnow(); ev->msbump = FALSE; /* reset here */ @@ -619,7 +619,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) /* If nothing updated the timeout, we decrease it by the spent time. * If it was updated, it has the new timeout time stored already. */ - time_t timediff = curlx_tvdiff(after, before); + timediff_t timediff = Curl_timediff(after, before); if(timediff > 0) { if(timediff > ev->ms) ev->ms = 0; @@ -680,17 +680,17 @@ static CURLcode easy_transfer(struct Curl_multi *multi) int still_running = 0; int rc; - before = curlx_tvnow(); + before = Curl_tvnow(); mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc); if(!mcode) { if(!rc) { - struct curltime after = curlx_tvnow(); + struct curltime after = Curl_tvnow(); /* If it returns without any filedescriptor instantly, we need to avoid busy-looping during periods where it has nothing particular to wait for */ - if(curlx_tvdiff(after, before) <= 10) { + if(Curl_timediff(after, before) <= 10) { without_fds++; if(without_fds > 2) { int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000; diff --git a/lib/ftp.c b/lib/ftp.c index edcfd5f80..905728778 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -351,7 +351,7 @@ static time_t ftp_timeleft_accept(struct Curl_easy *data) timeout_ms = other; else { /* subtract elapsed time */ - timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata); + timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata); if(!timeout_ms) /* avoid returning 0 as that means no timeout! */ return -1; diff --git a/lib/hostip.c b/lib/hostip.c index 1a18a3ed7..1f988e9ac 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -688,8 +688,8 @@ clean_up: the time we spent until now! */ if(prev_alarm) { /* there was an alarm() set before us, now put it back */ - unsigned long elapsed_secs = (unsigned long) (Curl_tvdiff(Curl_tvnow(), - conn->created) / 1000); + timediff_t elapsed_secs = Curl_timediff(Curl_tvnow(), + conn->created) / 1000; /* the alarm period is counted in even number of seconds */ unsigned long alarm_set = prev_alarm - elapsed_secs; diff --git a/lib/multi.c b/lib/multi.c index caceaf589..eb6a633a3 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1380,23 +1380,23 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Handle timed out */ if(data->mstate == CURLM_STATE_WAITRESOLVE) failf(data, "Resolving timed out after %ld milliseconds", - Curl_tvdiff(now, data->progress.t_startsingle)); + Curl_timediff(now, data->progress.t_startsingle)); else if(data->mstate == CURLM_STATE_WAITCONNECT) failf(data, "Connection timed out after %ld milliseconds", - Curl_tvdiff(now, data->progress.t_startsingle)); + Curl_timediff(now, data->progress.t_startsingle)); else { k = &data->req; if(k->size != -1) { failf(data, "Operation timed out after %ld milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(now, data->progress.t_startsingle), + Curl_timediff(now, data->progress.t_startsingle), k->bytecount, k->size); } else { failf(data, "Operation timed out after %ld milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(now, data->progress.t_startsingle), + Curl_timediff(now, data->progress.t_startsingle), k->bytecount); } } @@ -2514,9 +2514,9 @@ static CURLMcode add_next_timeout(struct curltime now, timeout in *tv */ for(e = list->head; e;) { struct curl_llist_element *n = e->next; - time_t diff; + timediff_t diff; node = (struct time_node *)e->ptr; - diff = curlx_tvdiff(node->time, now); + diff = Curl_timediff(node->time, now); if(diff <= 0) /* remove outdated entry */ Curl_llist_remove(list, e, NULL); @@ -2790,8 +2790,8 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) { /* some time left before expiration */ - *timeout_ms = (long)curlx_tvdiff(multi->timetree->key, now); - if(!*timeout_ms) + timediff_t diff = Curl_timediff(multi->timetree->key, now); + if(diff <= 0) /* * Since we only provide millisecond resolution on the returned value * and the diff might be less than one millisecond here, we don't @@ -2800,6 +2800,10 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, * millisecond! instead we return 1 until the time is ripe. */ *timeout_ms = 1; + else + /* this should be safe even on 64 bit archs, as we don't use that + overly long timeouts */ + *timeout_ms = (long)diff; } else /* 0 means immediately */ @@ -2906,7 +2910,7 @@ multi_addtimeout(struct Curl_easy *data, /* find the correct spot in the list */ for(e = timeoutlist->head; e; e = e->next) { struct time_node *check = (struct time_node *)e->ptr; - time_t diff = curlx_tvdiff(check->time, node->time); + timediff_t diff = Curl_timediff(check->time, node->time); if(diff > 0) break; prev = e; @@ -2965,7 +2969,7 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id) /* This means that the struct is added as a node in the splay tree. Compare if the new time is earlier, and only remove-old/add-new if it is. */ - time_t diff = curlx_tvdiff(set, *nowp); + timediff_t diff = Curl_timediff(set, *nowp); if(diff > 0) { /* The current splay tree entry is sooner than this new expiry time. diff --git a/lib/pingpong.c b/lib/pingpong.c index ef865ae54..278405f72 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -61,12 +61,12 @@ time_t Curl_pp_state_timeout(struct pingpong *pp) /* Without a requested timeout, we only wait 'response_time' seconds for the full response to arrive before we bail out */ timeout_ms = response_time - - Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */ + Curl_timediff(Curl_tvnow(), pp->response); /* spent time */ if(data->set.timeout) { /* if timeout is requested, find out how much remaining time we have */ timeout2_ms = data->set.timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ + Curl_timediff(Curl_tvnow(), conn->now); /* spent time */ /* pick the lowest number */ timeout_ms = CURLMIN(timeout_ms, timeout2_ms); diff --git a/lib/progress.c b/lib/progress.c index 00609d9ee..03ab43c1c 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -212,13 +212,13 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer) /* this is the normal end-of-transfer thing */ break; case TIMER_REDIRECT: - data->progress.t_redirect = Curl_tvdiff_us(now, data->progress.start); + data->progress.t_redirect = Curl_timediff_us(now, data->progress.start); break; } if(delta) { - time_t us = Curl_tvdiff_us(now, data->progress.t_startsingle); - if(!us) - us++; /* make sure at least one microsecond passed */ + timediff_t us = Curl_timediff_us(now, data->progress.t_startsingle); + if(us < 1) + us = 1; /* make sure at least one microsecond passed */ *delta += us; } } @@ -274,7 +274,7 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize, return -1; minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit); - actual = Curl_tvdiff(now, start); + actual = Curl_timediff(now, start); if(actual < minimum) /* this is a conversion on some systems (64bit time_t => 32bit long) */ @@ -373,7 +373,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) now = Curl_tvnow(); /* what time is it */ /* The time spent so far (from the start) */ - data->progress.timespent = Curl_tvdiff_us(now, data->progress.start); + data->progress.timespent = Curl_timediff_us(now, data->progress.start); timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */ /* The average download speed this far */ @@ -413,7 +413,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) /* first of all, we don't do this if there's no counted seconds yet */ if(countindex) { - time_t span_ms; + timediff_t span_ms; /* Get the index position to compare with the 'nowindex' position. Get the oldest entry possible. While we have less than CURR_TIME @@ -422,8 +422,8 @@ int Curl_pgrsUpdate(struct connectdata *conn) data->progress.speeder_c%CURR_TIME:0; /* Figure out the exact time for the time span */ - span_ms = Curl_tvdiff(now, - data->progress.speeder_time[checkindex]); + span_ms = Curl_timediff(now, + data->progress.speeder_time[checkindex]); if(0 == span_ms) span_ms = 1; /* at least one millisecond MUST have passed */ diff --git a/lib/rand.c b/lib/rand.c index 2713a0aa3..2b08caf8c 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -86,7 +86,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) #endif if(!seeded) { - struct curltime now = curlx_tvnow(); + struct curltime now = Curl_tvnow(); infof(data, "WARNING: Using weak random seed\n"); randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; randseed = randseed * 1103515245 + 12345; diff --git a/lib/select.c b/lib/select.c index f6fecaf51..e21fff1f0 100644 --- a/lib/select.c +++ b/lib/select.c @@ -51,7 +51,7 @@ #include "warnless.h" /* Convenience local macros */ -#define ELAPSED_MS() (int)curlx_tvdiff(curlx_tvnow(), initial_tv) +#define ELAPSED_MS() (int)Curl_timediff(Curl_tvnow(), initial_tv) int Curl_ack_eintr = 0; #define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR) @@ -96,7 +96,7 @@ int Curl_wait_ms(int timeout_ms) Sleep(timeout_ms); #else pending_ms = timeout_ms; - initial_tv = curlx_tvnow(); + initial_tv = Curl_tvnow(); do { #if defined(HAVE_POLL_FINE) r = poll(NULL, 0, pending_ms); @@ -184,7 +184,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(timeout_ms > 0) { pending_ms = (int)timeout_ms; - initial_tv = curlx_tvnow(); + initial_tv = Curl_tvnow(); } #ifdef HAVE_POLL_FINE @@ -425,7 +425,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(timeout_ms > 0) { pending_ms = timeout_ms; - initial_tv = curlx_tvnow(); + initial_tv = Curl_tvnow(); } #ifdef HAVE_POLL_FINE diff --git a/lib/speedcheck.c b/lib/speedcheck.c index fe669f11a..3aeea9111 100644 --- a/lib/speedcheck.c +++ b/lib/speedcheck.c @@ -46,7 +46,7 @@ CURLcode Curl_speedcheck(struct Curl_easy *data, data->state.keeps_speed = now; else { /* how long has it been under the limit */ - time_t howlong = Curl_tvdiff(now, data->state.keeps_speed); + timediff_t howlong = Curl_timediff(now, data->state.keeps_speed); if(howlong >= data->set.low_speed_time * 1000) { /* too long */ diff --git a/lib/telnet.c b/lib/telnet.c index a7bed3da1..a5f87d81d 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -1561,7 +1561,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(data->set.timeout) { now = Curl_tvnow(); - if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { + if(Curl_timediff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; @@ -1679,7 +1679,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(data->set.timeout) { now = Curl_tvnow(); - if(Curl_tvdiff(now, conn->created) >= data->set.timeout) { + if(Curl_timediff(now, conn->created) >= data->set.timeout) { failf(data, "Time-out"); result = CURLE_OPERATION_TIMEDOUT; keepon = FALSE; diff --git a/lib/timeval.c b/lib/timeval.c index d7207b3a2..6ed79ec60 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -24,7 +24,7 @@ #if defined(WIN32) && !defined(MSDOS) -struct curltime curlx_tvnow(void) +struct curltime Curl_tvnow(void) { /* ** GetTickCount() is available on _all_ Windows versions from W95 up @@ -48,7 +48,7 @@ struct curltime curlx_tvnow(void) #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) -struct curltime curlx_tvnow(void) +struct curltime Curl_tvnow(void) { /* ** clock_gettime() is granted to be increased monotonically when the @@ -86,7 +86,7 @@ struct curltime curlx_tvnow(void) #elif defined(HAVE_GETTIMEOFDAY) -struct curltime curlx_tvnow(void) +struct curltime Curl_tvnow(void) { /* ** gettimeofday() is not granted to be increased monotonically, due to @@ -103,7 +103,7 @@ struct curltime curlx_tvnow(void) #else -struct curltime curlx_tvnow(void) +struct curltime Curl_tvnow(void) { /* ** time() returns the value of time in seconds since the Epoch. @@ -116,6 +116,14 @@ struct curltime curlx_tvnow(void) #endif +#if SIZEOF_TIME_T < 8 +#define TIME_MAX INT_MAX +#define TIME_MIN INT_MIN +#else +#define TIME_MAX 9223372036854775807LL +#define TIME_MIN -9223372036854775807LL +#endif + /* * Make sure that the first argument is the more recent time, as otherwise * we'll get a weird negative time-diff back... @@ -125,17 +133,15 @@ struct curltime curlx_tvnow(void) * * @unittest: 1323 */ -time_t curlx_tvdiff(struct curltime newer, struct curltime older) +timediff_t Curl_timediff(struct curltime newer, struct curltime older) { -#if SIZEOF_TIME_T < 8 - /* for 32bit time_t systems, add a precaution to avoid overflow for really - big time differences */ - time_t diff = newer.tv_sec-older.tv_sec; - if(diff >= (0x7fffffff/1000)) - return 0x7fffffff; -#endif - return (newer.tv_sec-older.tv_sec)*1000+ - (int)(newer.tv_usec-older.tv_usec)/1000; + timediff_t diff = newer.tv_sec-older.tv_sec; + if(diff >= (TIME_MAX/1000)) + return TIME_MAX; + else if(diff <= (TIME_MIN/1000)) + return TIME_MIN; + return (timediff_t)(newer.tv_sec-older.tv_sec)*1000+ + (timediff_t)(newer.tv_usec-older.tv_usec)/1000; } /* @@ -145,18 +151,13 @@ time_t curlx_tvdiff(struct curltime newer, struct curltime older) * Returns: the time difference in number of microseconds. For too large diffs * it returns max value. */ -time_t Curl_tvdiff_us(struct curltime newer, struct curltime older) +timediff_t Curl_timediff_us(struct curltime newer, struct curltime older) { - time_t diff = newer.tv_sec-older.tv_sec; -#if SIZEOF_TIME_T < 8 - /* for 32bit time_t systems */ - if(diff >= (0x7fffffff/1000000)) - return 0x7fffffff; -#else - /* for 64bit time_t systems */ - if(diff >= (0x7fffffffffffffffLL/1000000)) - return 0x7fffffffffffffffLL; -#endif - return (newer.tv_sec-older.tv_sec)*1000000+ - (int)(newer.tv_usec-older.tv_usec); + timediff_t diff = newer.tv_sec-older.tv_sec; + if(diff >= (TIME_MAX/1000000)) + return TIME_MAX; + else if(diff <= (TIME_MIN/1000000)) + return TIME_MIN; + return (timediff_t)(newer.tv_sec-older.tv_sec)*1000000+ + (timediff_t)(newer.tv_usec-older.tv_usec); } diff --git a/lib/timeval.h b/lib/timeval.h index 1ee4b3044..b2f0e0d97 100644 --- a/lib/timeval.h +++ b/lib/timeval.h @@ -22,19 +22,21 @@ * ***************************************************************************/ -/* - * CAUTION: this header is designed to work when included by the app-side - * as well as the library. Do not mix with library internals! - */ - #include "curl_setup.h" +#if SIZEOF_TIME_T < 8 +typedef int timediff_t; +#else +typedef ssize_t timediff_t; +#endif + + struct curltime { - time_t tv_sec; /* seconds */ - unsigned int tv_usec; /* microseconds */ + time_t tv_sec; /* seconds */ + int tv_usec; /* microseconds */ }; -struct curltime curlx_tvnow(void); +struct curltime Curl_tvnow(void); /* * Make sure that the first argument (t1) is the more recent time and t2 is @@ -42,7 +44,7 @@ struct curltime curlx_tvnow(void); * * Returns: the time difference in number of milliseconds. */ -time_t curlx_tvdiff(struct curltime t1, struct curltime t2); +timediff_t Curl_timediff(struct curltime t1, struct curltime t2); /* * Make sure that the first argument (t1) is the more recent time and t2 is @@ -50,12 +52,7 @@ time_t curlx_tvdiff(struct curltime t1, struct curltime t2); * * Returns: the time difference in number of microseconds. */ -time_t Curl_tvdiff_us(struct curltime newer, struct curltime older); - -/* These two defines below exist to provide the older API for library - internals only. */ -#define Curl_tvnow() curlx_tvnow() -#define Curl_tvdiff(x,y) curlx_tvdiff(x,y) +timediff_t Curl_timediff_us(struct curltime newer, struct curltime older); #endif /* HEADER_CURL_TIMEVAL_H */ diff --git a/lib/transfer.c b/lib/transfer.c index 8e66d0d80..4bdbd5e18 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1174,7 +1174,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, */ - time_t ms = Curl_tvdiff(k->now, k->start100); + timediff_t ms = Curl_timediff(k->now, k->start100); if(ms >= data->set.expect_100_timeout) { /* we've waited long enough, continue anyway */ k->exp100 = EXP100_SEND_DATA; @@ -1198,13 +1198,14 @@ CURLcode Curl_readwrite(struct connectdata *conn, failf(data, "Operation timed out after %ld milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount, - k->size); + Curl_timediff(k->now, data->progress.t_startsingle), + k->bytecount, k->size); } else { failf(data, "Operation timed out after %ld milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount); + Curl_timediff(k->now, data->progress.t_startsingle), + k->bytecount); } return CURLE_OPERATION_TIMEDOUT; } diff --git a/lib/url.c b/lib/url.c index 76c09c72a..594160898 100644 --- a/lib/url.c +++ b/lib/url.c @@ -3459,8 +3459,8 @@ Curl_oldest_idle_connection(struct Curl_easy *data) struct curl_hash_iterator iter; struct curl_llist_element *curr; struct curl_hash_element *he; - time_t highscore =- 1; - time_t score; + timediff_t highscore =- 1; + timediff_t score; struct curltime now; struct connectdata *conn_candidate = NULL; struct connectbundle *bundle; @@ -3481,7 +3481,7 @@ Curl_oldest_idle_connection(struct Curl_easy *data) if(!conn->inuse) { /* Set higher score for the age passed since the connection was used */ - score = Curl_tvdiff(now, conn->now); + score = Curl_timediff(now, conn->now); if(score > highscore) { highscore = score; @@ -3522,8 +3522,8 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy *data, struct connectbundle *bundle) { struct curl_llist_element *curr; - time_t highscore = -1; - time_t score; + timediff_t highscore = -1; + timediff_t score; struct curltime now; struct connectdata *conn_candidate = NULL; struct connectdata *conn; @@ -3538,7 +3538,7 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy *data, if(!conn->inuse) { /* Set higher score for the age passed since the connection was used */ - score = Curl_tvdiff(now, conn->now); + score = Curl_timediff(now, conn->now); if(score > highscore) { highscore = score; @@ -3613,7 +3613,7 @@ static int call_disconnect_if_dead(struct connectdata *conn, static void prune_dead_connections(struct Curl_easy *data) { struct curltime now = Curl_tvnow(); - time_t elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup); + time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup); if(elapsed >= 1000L) { Curl_conncache_foreach(data->state.conn_cache, data, diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index f94415222..96374dc10 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -446,14 +446,14 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data) size_t len = sizeof(randb); size_t i, i_max; for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) { - struct curltime tv = curlx_tvnow(); + struct curltime tv = Curl_tvnow(); Curl_wait_ms(1); tv.tv_sec *= i + 1; tv.tv_usec *= (unsigned int)i + 2; - tv.tv_sec ^= ((curlx_tvnow().tv_sec + curlx_tvnow().tv_usec) * + tv.tv_sec ^= ((Curl_tvnow().tv_sec + Curl_tvnow().tv_usec) * (i + 3)) << 8; - tv.tv_usec ^= (unsigned int) ((curlx_tvnow().tv_sec + - curlx_tvnow().tv_usec) * + tv.tv_usec ^= (unsigned int) ((Curl_tvnow().tv_sec + + Curl_tvnow().tv_usec) * (i + 4)) << 16; memcpy(&randb[i * sizeof(struct curltime)], &tv, sizeof(struct curltime)); diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index c3ea664b6..208aa0fc8 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -4,14 +4,12 @@ CURLX_SRCS = \ ../../lib/mprintf.c \ ../../lib/nonblock.c \ ../../lib/strtoofft.c \ - ../../lib/timeval.c \ ../../lib/warnless.c CURLX_HDRS = \ ../../lib/curlx.h \ ../../lib/nonblock.h \ ../../lib/strtoofft.h \ - ../../lib/timeval.h \ ../../lib/warnless.h USEFUL = \ diff --git a/tests/server/util.c b/tests/server/util.c index 1bbd89a3c..fdbd71f0f 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -67,6 +67,8 @@ const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }}; #endif /* w32api < 3.6 */ #endif /* ENABLE_IPV6 && __MINGW32__*/ +static struct timeval tvnow(void); + /* This function returns a pointer to STATIC memory. It converts the given * binary lump to a hex formatted string usable for output in logs or * whatever. @@ -100,7 +102,7 @@ void logmsg(const char *msg, ...) char buffer[2048 + 1]; FILE *logfp; int error; - struct curltime tv; + struct timeval tv; time_t sec; struct tm *now; char timebuf[20]; @@ -112,7 +114,7 @@ void logmsg(const char *msg, ...) return; } - tv = curlx_tvnow(); + tv = tvnow(); if(!known_offset) { epoch_offset = time(NULL) - tv.tv_sec; known_offset = 1; @@ -213,7 +215,7 @@ int wait_ms(int timeout_ms) #ifndef HAVE_POLL_FINE struct timeval pending_tv; #endif - struct curltime initial_tv; + struct timeval initial_tv; int pending_ms; int error; #endif @@ -231,7 +233,7 @@ int wait_ms(int timeout_ms) Sleep(timeout_ms); #else pending_ms = timeout_ms; - initial_tv = curlx_tvnow(); + initial_tv = tvnow(); do { #if defined(HAVE_POLL_FINE) r = poll(NULL, 0, pending_ms); @@ -245,7 +247,7 @@ int wait_ms(int timeout_ms) error = errno; if(error && (error != EINTR)) break; - pending_ms = timeout_ms - (int)curlx_tvdiff(curlx_tvnow(), initial_tv); + pending_ms = timeout_ms - (int)timediff(tvnow(), initial_tv); if(pending_ms <= 0) break; } while(r == -1); @@ -397,3 +399,102 @@ int strncasecompare(const char *first, const char *second, size_t max) return raw_toupper(*first) == raw_toupper(*second); } + +#if defined(WIN32) && !defined(MSDOS) + +static struct timeval 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. + ** + ** GetTickCount64() is available on Windows version from Windows Vista + ** and Windows Server 2008 up to nowadays. The resolution of the + ** function is limited to the resolution of the system timer, which + ** is typically in the range of 10 milliseconds to 16 milliseconds. + */ + struct timeval now; +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) + ULONGLONG milliseconds = GetTickCount64(); +#else + DWORD milliseconds = GetTickCount(); +#endif + now.tv_sec = (long)(milliseconds / 1000); + now.tv_usec = (milliseconds % 1000) * 1000; + return now; +} + +#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) + +static struct timeval 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; + struct timespec tsnow; + if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) { + now.tv_sec = tsnow.tv_sec; + now.tv_usec = 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); +#else + else { + now.tv_sec = (long)time(NULL); + now.tv_usec = 0; + } +#endif + return now; +} + +#elif defined(HAVE_GETTIMEOFDAY) + +static struct timeval 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); + return now; +} + +#else + +static struct timeval 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; +} + +#endif + +long timediff(struct timeval newer, struct timeval older) +{ + timediff_t diff = newer.tv_sec-older.tv_sec; + if(diff >= (LONG_MAX/1000)) + return LONG_MAX; + else if(diff <= (LONG_MIN/1000)) + return LONG_MIN; + return (long)(newer.tv_sec-older.tv_sec)*1000+ + (long)(newer.tv_usec-older.tv_usec)/1000; +} diff --git a/tests/server/util.h b/tests/server/util.h index a2a56badd..7b4ec1626 100644 --- a/tests/server/util.h +++ b/tests/server/util.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,6 +25,7 @@ char *data_to_hex(char *data, size_t len); void logmsg(const char *msg, ...); +long timediff(struct timeval newer, struct timeval older); #define TEST_DATA_PATH "%s/data/test%ld" diff --git a/tests/unit/unit1323.c b/tests/unit/unit1323.c index 7bb4cca40..1adb27494 100644 --- a/tests/unit/unit1323.c +++ b/tests/unit/unit1323.c @@ -50,7 +50,7 @@ UNITTEST_START size_t i; for(i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { - time_t result = curlx_tvdiff(tests[i].first, tests[i].second); + timediff_t result = Curl_timediff(tests[i].first, tests[i].second); if(result != tests[i].result) { printf("%d.%06u to %d.%06u got %d, but expected %d\n", tests[i].first.tv_sec,