lib: keep timestamp in easy handle

Use `data->progress.now` as the timestamp of proecssing a transfer.
Update it on significant events and refrain from calling `curlx_now()`
in many places.

The problem this addresses is
a) calling curlx_now() has costs, depending on platform. Calling it
   every time results in 25% increase `./runtest` duration on macOS.
b) we used to pass a `struct curltime *` around to save on calls, but
   when some method directly use `curx_now()` and some use the passed
   pointer, the transfer experienes non-linear time. This results in
   timeline checks to report events in the wrong order.

By keeping a timestamp in the easy handle and updating it there, no
longer invoking `curlx_now()` in the "lower" methods, the transfer
can observer a steady clock progression.

Add documentation in docs/internals/TIME-KEEPING.md

Reported-by: Viktor Szakats
Fixes #19935
Closes #19961
This commit is contained in:
Stefan Eissing 2025-12-15 14:28:09 +01:00 committed by Daniel Stenberg
parent 425a2aa1af
commit 2de22a00c7
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
67 changed files with 598 additions and 458 deletions

View file

@ -311,7 +311,7 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
/* This is only set to non-zero if the timer was started. */
(ares->happy_eyeballs_dns_time.tv_sec ||
ares->happy_eyeballs_dns_time.tv_usec) &&
(curlx_timediff_ms(curlx_now(), ares->happy_eyeballs_dns_time) >=
(curlx_timediff_ms(data->progress.now, ares->happy_eyeballs_dns_time) >=
HAPPY_EYEBALLS_DNS_TIMEOUT)) {
/* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
running. */
@ -390,12 +390,11 @@ CURLcode Curl_async_await(struct Curl_easy *data,
struct async_ares_ctx *ares = &data->state.async.ares;
CURLcode result = CURLE_OK;
timediff_t timeout_ms;
struct curltime now = curlx_now();
DEBUGASSERT(entry);
*entry = NULL; /* clear on entry */
timeout_ms = Curl_timeleft_ms(data, &now, TRUE);
timeout_ms = Curl_timeleft_ms(data, TRUE);
if(timeout_ms < 0) {
/* already expired! */
connclose(data->conn, "Timed out before name resolve started");
@ -439,15 +438,15 @@ CURLcode Curl_async_await(struct Curl_easy *data,
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else {
struct curltime now2 = curlx_now();
timediff_t elapsed_ms = curlx_timediff_ms(now2, now); /* spent time */
struct curltime now = curlx_now(); /* update in loop */
timediff_t elapsed_ms = curlx_timediff_ms(now, data->progress.now);
if(elapsed_ms <= 0)
timeout_ms -= 1; /* always deduct at least 1 */
else if(elapsed_ms > timeout_ms)
timeout_ms = -1;
else
timeout_ms -= elapsed_ms;
now = now2; /* for next loop */
Curl_pgrs_now_at_least(data, &now);
}
if(timeout_ms < 0)
result = CURLE_OPERATION_TIMEDOUT;
@ -583,7 +582,7 @@ static void async_ares_hostbyname_cb(void *user_data,
timeout to prevent it. After all, we do not even know where in the
c-ares retry cycle each request is.
*/
ares->happy_eyeballs_dns_time = curlx_now();
ares->happy_eyeballs_dns_time = data->progress.now;
Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS_DNS);
}
}

View file

@ -442,7 +442,7 @@ static bool async_thrdd_init(struct Curl_easy *data,
/* passing addr_ctx to the thread adds a reference */
addr_ctx->ref_count = 2;
addr_ctx->start = curlx_now();
addr_ctx->start = data->progress.now;
#ifdef HAVE_GETADDRINFO
addr_ctx->thread_hnd = Curl_thread_create(getaddrinfo_thread, addr_ctx);
@ -655,7 +655,7 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
else {
/* poll for name lookup done with exponential backoff up to 250ms */
/* should be fine even if this converts to 32-bit */
timediff_t elapsed = curlx_timediff_ms(curlx_now(),
timediff_t elapsed = curlx_timediff_ms(data->progress.now,
data->progress.t_startsingle);
if(elapsed < 0)
elapsed = 0;
@ -706,7 +706,7 @@ CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]);
#else
timediff_t milli;
timediff_t ms = curlx_timediff_ms(curlx_now(), thrdd->addr->start);
timediff_t ms = curlx_timediff_ms(data->progress.now, thrdd->addr->start);
if(ms < 3)
milli = 0;
else if(ms <= 50)

View file

@ -528,7 +528,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
do {
if(Curl_timeleft_ms(data, NULL, TRUE) < 0) {
if(Curl_timeleft_ms(data, TRUE) < 0) {
failf(data, "Proxy CONNECT aborted due to timeout");
result = CURLE_OPERATION_TIMEDOUT;
goto out;

View file

@ -1088,7 +1088,7 @@ static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
}
DEBUGASSERT(ts->authority);
if(Curl_timeleft_ms(data, NULL, TRUE) < 0) {
if(Curl_timeleft_ms(data, TRUE) < 0) {
failf(data, "Proxy CONNECT aborted due to timeout");
result = CURLE_OPERATION_TIMEDOUT;
goto out;

View file

@ -149,7 +149,7 @@ static void cf_hc_baller_init(struct cf_hc_baller *b,
struct Curl_cfilter *save = cf->next;
cf->next = NULL;
b->started = curlx_now();
b->started = data->progress.now;
switch(b->alpn_id) {
case ALPN_h3:
transport = TRNSPRT_QUIC;
@ -212,11 +212,11 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
if(reply_ms >= 0)
CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
winner->name,
(int)curlx_timediff_ms(curlx_now(),
(int)curlx_timediff_ms(data->progress.now,
winner->started), reply_ms);
else
CURL_TRC_CF(data, cf, "deferred handshake %s: %dms",
winner->name, (int)curlx_timediff_ms(curlx_now(),
winner->name, (int)curlx_timediff_ms(data->progress.now,
winner->started));
/* install the winning filter below this one. */
@ -293,7 +293,6 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
bool *done)
{
struct cf_hc_ctx *ctx = cf->ctx;
struct curltime now;
CURLcode result = CURLE_OK;
size_t i, failed_ballers;
@ -303,14 +302,13 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
now = curlx_now();
switch(ctx->state) {
case CF_HC_INIT:
DEBUGASSERT(!cf->next);
for(i = 0; i < ctx->baller_count; i++)
DEBUGASSERT(!ctx->ballers[i].cf);
CURL_TRC_CF(data, cf, "connect, init");
ctx->started = now;
ctx->started = data->progress.now;
cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport);
if(ctx->baller_count > 1) {
Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
@ -329,7 +327,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
}
if(time_to_start_next(cf, data, 1, now)) {
if(time_to_start_next(cf, data, 1, data->progress.now)) {
cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport);
}

View file

@ -353,7 +353,6 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs,
CURLcode result = CURLE_OK;
struct cf_ip_attempt *a = NULL, **panchor;
bool do_more;
struct curltime now;
timediff_t next_expire_ms;
int i, inconclusive, ongoing;
@ -361,7 +360,6 @@ static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs,
return CURLE_OK;
evaluate:
now = curlx_now();
ongoing = inconclusive = 0;
/* check if a running baller connects now */
@ -398,7 +396,7 @@ evaluate:
/* no attempt connected yet, start another one? */
if(!ongoing) {
if(!bs->started.tv_sec && !bs->started.tv_usec)
bs->started = now;
bs->started = data->progress.now;
do_more = TRUE;
}
else {
@ -408,8 +406,8 @@ evaluate:
more_possible = cf_ai_iter_has_more(&bs->ipv6_iter);
#endif
do_more = more_possible &&
(curlx_timediff_ms(now, bs->last_attempt_started) >=
bs->attempt_delay_ms);
(curlx_timediff_ms(data->progress.now, bs->last_attempt_started) >=
bs->attempt_delay_ms);
if(do_more)
CURL_TRC_CF(data, cf, "happy eyeballs timeout expired, "
"start next attempt");
@ -447,7 +445,7 @@ evaluate:
while(*panchor)
panchor = &((*panchor)->next);
*panchor = a;
bs->last_attempt_started = now;
bs->last_attempt_started = data->progress.now;
bs->last_attempt_ai_family = ai_family;
/* and run everything again */
goto evaluate;
@ -455,7 +453,8 @@ evaluate:
else if(inconclusive) {
/* tried all addresses, no success but some where inconclusive.
* Let's restart the inconclusive ones. */
timediff_t since_ms = curlx_timediff_ms(now, bs->last_attempt_started);
timediff_t since_ms =
curlx_timediff_ms(data->progress.now, bs->last_attempt_started);
timediff_t delay_ms = bs->attempt_delay_ms - since_ms;
if(delay_ms <= 0) {
CURL_TRC_CF(data, cf, "all attempts inconclusive, restarting one");
@ -468,7 +467,7 @@ evaluate:
CURL_TRC_CF(data, cf, "restarted baller %d -> %d", i, result);
if(result) /* serious failure */
goto out;
bs->last_attempt_started = now;
bs->last_attempt_started = data->progress.now;
goto evaluate;
}
DEBUGASSERT(0); /* should not come here */
@ -500,10 +499,10 @@ out:
bool more_possible;
/* when do we need to be called again? */
next_expire_ms = Curl_timeleft_ms(data, &now, TRUE);
next_expire_ms = Curl_timeleft_ms(data, TRUE);
if(next_expire_ms <= 0) {
failf(data, "Connection timeout after %" FMT_OFF_T " ms",
curlx_timediff_ms(now, data->progress.t_startsingle));
curlx_timediff_ms(data->progress.now, data->progress.t_startsingle));
return CURLE_OPERATION_TIMEDOUT;
}
@ -514,7 +513,8 @@ out:
#endif
if(more_possible) {
timediff_t expire_ms, elapsed_ms;
elapsed_ms = curlx_timediff_ms(now, bs->last_attempt_started);
elapsed_ms =
curlx_timediff_ms(data->progress.now, bs->last_attempt_started);
expire_ms = CURLMAX(bs->attempt_delay_ms - elapsed_ms, 0);
next_expire_ms = CURLMIN(next_expire_ms, expire_ms);
if(next_expire_ms <= 0) {
@ -675,7 +675,7 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
proxy_name ? "via " : "",
proxy_name ? proxy_name : "",
proxy_name ? " " : "",
curlx_timediff_ms(curlx_now(), data->progress.t_startsingle),
curlx_timediff_ms(data->progress.now, data->progress.t_startsingle),
curl_easy_strerror(result));
}
@ -700,14 +700,14 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
if(!dns)
return CURLE_FAILED_INIT;
if(Curl_timeleft_ms(data, NULL, TRUE) < 0) {
if(Curl_timeleft_ms(data, TRUE) < 0) {
/* a precaution, no need to continue if time already is up */
failf(data, "Connection time-out");
return CURLE_OPERATION_TIMEDOUT;
}
CURL_TRC_CF(data, cf, "init ip ballers for transport %u", ctx->transport);
ctx->started = curlx_now();
ctx->started = data->progress.now;
return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version,
dns->addr, ctx->cf_create, ctx->transport,
data->set.happy_eyeballs_timeout);

View file

@ -1074,7 +1074,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
ctx->started_at = curlx_now();
ctx->started_at = data->progress.now;
#ifdef SOCK_NONBLOCK
/* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
* because we would not know how socketype is about to be used in the
@ -1201,7 +1201,7 @@ out:
}
else if(isconnected) {
set_local_ip(cf, data);
ctx->connected_at = curlx_now();
ctx->connected_at = data->progress.now;
cf->connected = TRUE;
}
CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
@ -1320,7 +1320,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
if(verifyconnect(ctx->sock, &ctx->error)) {
/* we are connected with TCP, awesome! */
ctx->connected_at = curlx_now();
ctx->connected_at = data->progress.now;
set_local_ip(cf, data);
*done = TRUE;
cf->connected = TRUE;
@ -1396,13 +1396,13 @@ static CURLcode cf_socket_adjust_pollset(struct Curl_cfilter *cf,
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif
static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
static void win_update_sndbuf_size(struct Curl_easy *data,
struct cf_socket_ctx *ctx)
{
ULONG ideal;
DWORD ideallen;
struct curltime n = curlx_now();
if(curlx_timediff_ms(n, ctx->last_sndbuf_query_at) > 1000) {
if(curlx_timediff_ms(data->progress.now, ctx->last_sndbuf_query_at) > 1000) {
if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
&ideal, sizeof(ideal), &ideallen, 0, 0) &&
ideal != ctx->sndbuf_size &&
@ -1410,7 +1410,7 @@ static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
(const char *)&ideal, sizeof(ideal))) {
ctx->sndbuf_size = ideal;
}
ctx->last_sndbuf_query_at = n;
ctx->last_sndbuf_query_at = data->progress.now;
}
}
@ -1491,7 +1491,7 @@ static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef USE_WINSOCK
if(!result)
win_update_sndbuf_size(ctx);
win_update_sndbuf_size(data, ctx);
#endif
CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, %zu",
@ -1557,7 +1557,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread);
if(!result && !ctx->got_first_byte) {
ctx->first_byte_at = curlx_now();
ctx->first_byte_at = data->progress.now;
ctx->got_first_byte = TRUE;
}
return result;
@ -1990,23 +1990,21 @@ static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
timediff_t other_ms;
struct curltime now;
#ifndef CURL_DISABLE_FTP
if(data->set.accepttimeout > 0)
timeout_ms = data->set.accepttimeout;
#endif
now = curlx_now();
/* check if the generic timeout possibly is set shorter */
other_ms = Curl_timeleft_ms(data, &now, FALSE);
other_ms = Curl_timeleft_ms(data, FALSE);
if(other_ms && (other_ms < timeout_ms))
/* note that this also works fine for when other_ms happens to be negative
due to it already having elapsed */
timeout_ms = other_ms;
else {
/* subtract elapsed time */
timeout_ms -= curlx_timediff_ms(now, ctx->started_at);
timeout_ms -= curlx_timediff_ms(data->progress.now, ctx->started_at);
if(!timeout_ms)
/* avoid returning 0 as that means no timeout! */
timeout_ms = -1;
@ -2142,7 +2140,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
cf_tcp_set_accepted_remote_ip(cf, data);
set_local_ip(cf, data);
ctx->active = TRUE;
ctx->connected_at = curlx_now();
ctx->connected_at = data->progress.now;
cf->connected = TRUE;
CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
", remote=%s port=%d)",
@ -2208,7 +2206,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
ctx->started_at = curlx_now();
ctx->started_at = data->progress.now;
conn->sock[sockindex] = ctx->sock;
set_local_ip(cf, data);
CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T

View file

@ -169,7 +169,6 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
timediff_t timeout_ms;
struct curltime now;
DEBUGASSERT(data->conn);
@ -187,14 +186,13 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
}
*done = FALSE;
now = curlx_now();
if(!Curl_shutdown_started(data, sockindex)) {
CURL_TRC_M(data, "shutdown start on%s connection",
sockindex ? " secondary" : "");
Curl_shutdown_start(data, sockindex, 0, &now);
Curl_shutdown_start(data, sockindex, 0);
}
else {
timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
timeout_ms = Curl_shutdown_timeleft(data, data->conn, sockindex);
if(timeout_ms < 0) {
/* info message, since this might be regarded as acceptable */
infof(data, "shutdown timeout");
@ -504,7 +502,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
* socket and ip related information. */
cf_cntrl_update_info(data, data->conn);
conn_report_connect_stats(cf, data);
data->conn->keepalive = curlx_now();
data->conn->keepalive = data->progress.now;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
result = cf_verboseconnect(data, cf);
#endif
@ -520,7 +518,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
goto out;
else {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft_ms(data, NULL, TRUE);
const timediff_t timeout_ms = Curl_timeleft_ms(data, TRUE);
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
int rc;

View file

@ -208,6 +208,7 @@ void Curl_cpool_destroy(struct cpool *cpool)
cpool->share ? "[SHARE] " : "", cpool->num_conn);
/* Move all connections to the shutdown list */
sigpipe_init(&pipe_st);
Curl_pgrs_now_set(cpool->idata);
CPOOL_LOCK(cpool, cpool->idata);
conn = cpool_get_first(cpool);
while(conn) {
@ -275,23 +276,22 @@ static struct cpool_bundle *cpool_add_bundle(struct cpool *cpool,
}
static struct connectdata *
cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle,
struct curltime *pnow)
{
struct Curl_llist_node *curr;
timediff_t highscore = -1;
timediff_t score;
struct curltime now;
struct connectdata *oldest_idle = NULL;
struct connectdata *conn;
now = curlx_now();
curr = Curl_llist_head(&bundle->conns);
while(curr) {
conn = Curl_node_elem(curr);
if(!CONN_INUSE(conn)) {
/* Set higher score for the age passed since the connection was used */
score = curlx_timediff_ms(now, conn->lastused);
score = curlx_timediff_ms(*pnow, conn->lastused);
if(score > highscore) {
highscore = score;
@ -303,18 +303,17 @@ cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
return oldest_idle;
}
static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool)
static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool,
struct curltime *pnow)
{
struct Curl_hash_iterator iter;
struct Curl_llist_node *curr;
struct Curl_hash_element *he;
struct connectdata *oldest_idle = NULL;
struct cpool_bundle *bundle;
struct curltime now;
timediff_t highscore = -1;
timediff_t score;
now = curlx_now();
Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
for(he = Curl_hash_next_element(&iter); he;
@ -328,7 +327,7 @@ static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool)
if(CONN_INUSE(conn) || conn->bits.close || conn->connect_only)
continue;
/* Set higher score for the age passed since the connection was used */
score = curlx_timediff_ms(now, conn->lastused);
score = curlx_timediff_ms(*pnow, conn->lastused);
if(score > highscore) {
highscore = score;
oldest_idle = conn;
@ -359,6 +358,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!dest_limit && !total_limit)
return CPOOL_LIMIT_OK;
Curl_pgrs_now_update(cpool->idata, data);
CPOOL_LOCK(cpool, cpool->idata);
if(dest_limit) {
size_t live;
@ -378,7 +378,8 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
struct connectdata *oldest_idle = NULL;
/* The bundle is full. Extract the oldest connection that may
* be removed now, if there is one. */
oldest_idle = cpool_bundle_get_oldest_idle(bundle);
oldest_idle = cpool_bundle_get_oldest_idle(bundle,
&data->progress.now);
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
@ -409,7 +410,8 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
break;
}
else {
struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool);
struct connectdata *oldest_idle =
cpool_get_oldest_idle(cpool, &data->progress.now);
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
@ -429,6 +431,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
out:
CPOOL_UNLOCK(cpool, cpool->idata);
Curl_pgrs_now_update(data, cpool->idata);
return result;
}
@ -538,7 +541,7 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
maxconnects = data->multi->maxconnects;
}
conn->lastused = curlx_now(); /* it was used up until now */
conn->lastused = data->progress.now; /* it was used up until now */
if(cpool && maxconnects) {
/* may be called form a callback already under lock */
bool do_lock = !CPOOL_IS_LOCKED(cpool);
@ -548,7 +551,7 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
infof(data, "Connection pool is full, closing the oldest of %zu/%u",
cpool->num_conn, maxconnects);
oldest_idle = cpool_get_oldest_idle(cpool);
oldest_idle = cpool_get_oldest_idle(cpool, &data->progress.now);
kept = (oldest_idle != conn);
if(oldest_idle) {
Curl_conn_terminate(data, oldest_idle, FALSE);
@ -635,6 +638,7 @@ static void cpool_discard_conn(struct cpool *cpool,
* If we do a shutdown for an aborted transfer, the server might think
* it was successful otherwise (for example an ftps: upload). This is
* not what we want. */
Curl_pgrs_now_update(cpool->idata, data);
if(aborted)
done = TRUE;
if(!done) {
@ -700,16 +704,12 @@ void Curl_conn_terminate(struct Curl_easy *data,
CPOOL_UNLOCK(cpool, data);
}
struct cpool_reaper_ctx {
struct curltime now;
};
static int cpool_reap_dead_cb(struct Curl_easy *data,
struct connectdata *conn, void *param)
{
struct cpool_reaper_ctx *rctx = param;
(void)param;
if((!CONN_INUSE(conn) && conn->bits.no_reuse) ||
Curl_conn_seems_dead(conn, data, &rctx->now)) {
Curl_conn_seems_dead(conn, data)) {
/* stop the iteration here, pass back the connection that was pruned */
Curl_conn_terminate(data, conn, FALSE);
return 1;
@ -727,20 +727,18 @@ static int cpool_reap_dead_cb(struct Curl_easy *data,
void Curl_cpool_prune_dead(struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
struct cpool_reaper_ctx rctx;
timediff_t elapsed;
if(!cpool)
return;
rctx.now = curlx_now();
CPOOL_LOCK(cpool, data);
elapsed = curlx_timediff_ms(rctx.now, cpool->last_cleanup);
elapsed = curlx_timediff_ms(data->progress.now, cpool->last_cleanup);
if(elapsed >= 1000L) {
while(cpool_foreach(data, cpool, &rctx, cpool_reap_dead_cb))
while(cpool_foreach(data, cpool, NULL, cpool_reap_dead_cb))
;
cpool->last_cleanup = rctx.now;
cpool->last_cleanup = data->progress.now;
}
CPOOL_UNLOCK(cpool, data);
}
@ -754,16 +752,15 @@ static int conn_upkeep(struct Curl_easy *data,
return 0; /* continue iteration */
}
CURLcode Curl_cpool_upkeep(void *data)
CURLcode Curl_cpool_upkeep(struct Curl_easy *data)
{
struct cpool *cpool = cpool_get_instance(data);
struct curltime now = curlx_now();
if(!cpool)
return CURLE_OK;
CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, &now, conn_upkeep);
cpool_foreach(data, cpool, &data->progress.now, conn_upkeep);
CPOOL_UNLOCK(cpool, data);
return CURLE_OK;
}

View file

@ -139,7 +139,7 @@ void Curl_cpool_prune_dead(struct Curl_easy *data);
/**
* Perform upkeep actions on connections in the transfer's pool.
*/
CURLcode Curl_cpool_upkeep(void *data);
CURLcode Curl_cpool_upkeep(struct Curl_easy *data);
typedef void Curl_cpool_conn_do_cb(struct connectdata *conn,
struct Curl_easy *data,

View file

@ -109,18 +109,15 @@ enum alpnid Curl_str2alpnid(const struct Curl_str *cstr)
* infinite time left). If the value is negative, the timeout time has already
* elapsed.
* @param data the transfer to check on
* @param nowp timestamp to use for calculation, NULL to use curlx_now()
* @param duringconnect TRUE iff connect timeout is also taken into account.
* @unittest: 1303
*/
timediff_t Curl_timeleft_ms(struct Curl_easy *data,
struct curltime *nowp,
bool duringconnect)
{
timediff_t timeleft_ms = 0;
timediff_t ctimeleft_ms = 0;
timediff_t ctimeout_ms;
struct curltime now;
/* The duration of a connect and the total transfer are calculated from two
different time-stamps. It can end up with the total timeout being reached
@ -130,14 +127,9 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data,
if((!data->set.timeout || data->set.connect_only) && !duringconnect)
return 0; /* no timeout in place or checked, return "no limit" */
if(!nowp) {
now = curlx_now();
nowp = &now;
}
if(data->set.timeout) {
timeleft_ms = data->set.timeout -
curlx_timediff_ms(*nowp, data->progress.t_startop);
curlx_timediff_ms(data->progress.now, data->progress.t_startop);
if(!timeleft_ms)
timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
}
@ -147,7 +139,7 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data,
ctimeout_ms = (data->set.connecttimeout > 0) ?
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
ctimeleft_ms = ctimeout_ms -
curlx_timediff_ms(*nowp, data->progress.t_startsingle);
curlx_timediff_ms(data->progress.now, data->progress.t_startsingle);
if(!ctimeleft_ms)
ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
if(!timeleft_ms)
@ -158,61 +150,47 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data,
}
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
int timeout_ms, struct curltime *nowp)
int timeout_ms)
{
struct curltime now;
struct connectdata *conn = data->conn;
DEBUGASSERT(conn);
if(!nowp) {
now = curlx_now();
nowp = &now;
}
conn->shutdown.start[sockindex] = *nowp;
conn->shutdown.start[sockindex] = data->progress.now;
conn->shutdown.timeout_ms = (timeout_ms > 0) ?
(timediff_t)timeout_ms :
((data->set.shutdowntimeout > 0) ?
data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
/* Set a timer, unless we operate on the admin handle */
if(data->mid)
Curl_expire_ex(data, nowp, conn->shutdown.timeout_ms,
EXPIRE_SHUTDOWN);
Curl_expire_ex(data, conn->shutdown.timeout_ms, EXPIRE_SHUTDOWN);
}
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
struct curltime *nowp)
timediff_t Curl_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
{
struct curltime now;
timediff_t left_ms;
if(!conn->shutdown.start[sockindex].tv_sec ||
(conn->shutdown.timeout_ms <= 0))
return 0; /* not started or no limits */
if(!nowp) {
now = curlx_now();
nowp = &now;
}
left_ms = conn->shutdown.timeout_ms -
curlx_timediff_ms(*nowp, conn->shutdown.start[sockindex]);
curlx_timediff_ms(data->progress.now,
conn->shutdown.start[sockindex]);
return left_ms ? left_ms : -1;
}
timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
struct curltime *nowp)
timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn)
{
timediff_t left_ms = 0, ms;
struct curltime now;
int i;
for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
if(!conn->shutdown.start[i].tv_sec)
continue;
if(!nowp) {
now = curlx_now();
nowp = &now;
}
ms = Curl_shutdown_timeleft(conn, i, nowp);
ms = Curl_shutdown_timeleft(data, conn, i);
if(ms && (!left_ms || ms < left_ms))
left_ms = ms;
}

View file

@ -39,7 +39,6 @@ enum alpnid Curl_str2alpnid(const struct Curl_str *str);
/* generic function that returns how much time there is left to run, according
to the timeouts set */
timediff_t Curl_timeleft_ms(struct Curl_easy *data,
struct curltime *nowp,
bool duringconnect);
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
@ -47,17 +46,18 @@ timediff_t Curl_timeleft_ms(struct Curl_easy *data,
#define DEFAULT_SHUTDOWN_TIMEOUT_MS (2 * 1000)
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
int timeout_ms, struct curltime *nowp);
int timeout_ms);
/* return how much time there is left to shutdown the connection at
* sockindex. Returns 0 if there is no limit or shutdown has not started. */
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
struct curltime *nowp);
timediff_t Curl_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
/* return how much time there is left to shutdown the connection.
* Returns 0 if there is no limit or shutdown has not started. */
timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
struct curltime *nowp);
timediff_t Curl_conn_shutdown_timeleft(struct Curl_easy *data,
struct connectdata *conn);
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex);

View file

@ -232,8 +232,6 @@ static void cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
struct Curl_llist_node *enext;
struct connectdata *conn;
struct curltime *nowp = NULL;
struct curltime now;
timediff_t next_expire_ms = 0, ms;
bool done;
@ -253,11 +251,7 @@ static void cshutdn_perform(struct cshutdn *cshutdn,
else {
/* idata has one timer list, but maybe more than one connection.
* Set EXPIRE_SHUTDOWN to the smallest time left for all. */
if(!nowp) {
now = curlx_now();
nowp = &now;
}
ms = Curl_conn_shutdown_timeleft(conn, nowp);
ms = Curl_conn_shutdown_timeleft(data, conn);
if(ms && ms < next_expire_ms)
next_expire_ms = ms;
}
@ -265,14 +259,14 @@ static void cshutdn_perform(struct cshutdn *cshutdn,
}
if(next_expire_ms)
Curl_expire_ex(data, nowp, next_expire_ms, EXPIRE_SHUTDOWN);
Curl_expire_ex(data, next_expire_ms, EXPIRE_SHUTDOWN);
}
static void cshutdn_terminate_all(struct cshutdn *cshutdn,
struct Curl_easy *data,
int timeout_ms)
{
struct curltime started = curlx_now();
struct curltime started = data->progress.now;
struct Curl_llist_node *e;
SIGPIPE_VARIABLE(pipe_st);
@ -295,7 +289,8 @@ static void cshutdn_terminate_all(struct cshutdn *cshutdn,
}
/* wait for activity, timeout or "nothing" */
spent_ms = curlx_timediff_ms(curlx_now(), started);
Curl_pgrs_now_set(data); /* update in loop */
spent_ms = curlx_timediff_ms(data->progress.now, started);
if(spent_ms >= (timediff_t)timeout_ms) {
CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, %s",
(timeout_ms > 0) ? "timeout" : "best effort done");

View file

@ -314,12 +314,11 @@ void Curl_trc_easy_timers(struct Curl_easy *data)
if(CURL_TRC_TIMER_is_verbose(data)) {
struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist);
if(e) {
struct curltime now = curlx_now();
while(e) {
struct time_node *n = Curl_node_elem(e);
e = Curl_node_next(e);
CURL_TRC_TIMER(data, n->eid, "expires in %" FMT_TIMEDIFF_T "ns",
curlx_timediff_us(n->time, now));
curlx_timediff_us(n->time, data->progress.now));
}
}
}

View file

@ -307,7 +307,7 @@ static CURLcode doh_probe_run(struct Curl_easy *data,
goto error;
}
timeout_ms = Curl_timeleft_ms(data, NULL, TRUE);
timeout_ms = Curl_timeleft_ms(data, TRUE);
if(timeout_ms <= 0) {
result = CURLE_OPERATION_TIMEDOUT;
goto error;

View file

@ -996,6 +996,7 @@ CURL *curl_easy_duphandle(CURL *d)
if(dupset(outcurl, data))
goto fail;
Curl_pgrs_now_set(outcurl); /* start of API call */
outcurl->progress.hide = data->progress.hide;
outcurl->progress.callback = data->progress.callback;
@ -1155,6 +1156,7 @@ CURLcode curl_easy_pause(CURL *d, int action)
if(Curl_is_in_callback(data))
recursive = TRUE;
Curl_pgrs_now_set(data); /* start of API call */
recv_paused = Curl_xfer_recv_is_paused(data);
recv_paused_new = (action & CURLPAUSE_RECV);
send_paused = Curl_xfer_send_is_paused(data);
@ -1179,7 +1181,7 @@ CURLcode curl_easy_pause(CURL *d, int action)
Curl_multi_mark_dirty(data); /* make it run */
/* On changes, tell application to update its timers. */
if(changed) {
if(Curl_update_timer(data->multi) && !result)
if(Curl_update_timer(data->multi, &data->progress.now) && !result)
result = CURLE_ABORTED_BY_CALLBACK;
}
}

View file

@ -315,7 +315,6 @@ static CURLcode file_upload(struct Curl_easy *data,
CURLcode result = CURLE_OK;
char *xfer_ulbuf;
size_t xfer_ulblen;
curl_off_t bytecount = 0;
struct_stat file_stat;
const char *sendbuf;
bool eos = FALSE;
@ -405,9 +404,7 @@ static CURLcode file_upload(struct Curl_easy *data,
result = CURLE_SEND_ERROR;
break;
}
bytecount += nwritten;
Curl_pgrsSetUploadCounter(data, bytecount);
Curl_pgrs_upload_inc(data, nwritten);
result = Curl_pgrsCheck(data);
}

View file

@ -3178,7 +3178,7 @@ static CURLcode ftp_connect(struct Curl_easy *data,
conn->bits.ftp_use_control_ssl = TRUE;
}
Curl_pp_init(pp); /* once per transfer */
Curl_pp_init(pp, &data->progress.now); /* once per transfer */
/* When we connect, we start in the state where we await the 220
response */
@ -3314,7 +3314,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
* data has been transferred. This happens when doing through NATs etc that
* abandon old silent connections.
*/
pp->response = curlx_now(); /* timeout relative now */
pp->response = data->progress.now; /* timeout relative now */
result = getftpresponse(data, &nread, &ftpcode);
if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
@ -3434,7 +3434,7 @@ static CURLcode ftp_sendquote(struct Curl_easy *data,
result = Curl_pp_sendf(data, &ftpc->pp, "%s", cmd);
if(!result) {
pp->response = curlx_now(); /* timeout relative now */
pp->response = data->progress.now; /* timeout relative now */
result = getftpresponse(data, &nread, &ftpcode);
}
if(result)

View file

@ -195,7 +195,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
else
break;
timeout_ms = Curl_timeleft_ms(data, NULL, FALSE);
timeout_ms = Curl_timeleft_ms(data, FALSE);
if(timeout_ms < 0) {
result = CURLE_OPERATION_TIMEDOUT;
break;

View file

@ -253,7 +253,6 @@ static void dnscache_unlock(struct Curl_easy *data,
void Curl_dnscache_prune(struct Curl_easy *data)
{
struct Curl_dnscache *dnscache = dnscache_get(data);
struct curltime now;
/* the timeout may be set -1 (forever) */
timediff_t timeout_ms = data->set.dns_cache_timeout_ms;
@ -263,11 +262,10 @@ void Curl_dnscache_prune(struct Curl_easy *data)
dnscache_lock(data, dnscache);
now = curlx_now();
do {
/* Remove outdated and unused entries from the hostcache */
timediff_t oldest_ms = dnscache_prune(&dnscache->entries, timeout_ms, now);
timediff_t oldest_ms =
dnscache_prune(&dnscache->entries, timeout_ms, data->progress.now);
if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE)
/* prune the ones over half this age */
@ -333,7 +331,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
/* See whether the returned entry is stale. Done before we release lock */
struct dnscache_prune_data user;
user.now = curlx_now();
user.now = data->progress.now;
user.max_age_ms = data->set.dns_cache_timeout_ms;
user.oldest_ms = 0;
@ -522,7 +520,7 @@ Curl_dnscache_mk_entry(struct Curl_easy *data,
dns->timestamp.tv_usec = 0; /* an entry that never goes stale */
}
else {
dns->timestamp = curlx_now();
dns->timestamp = data->progress.now;
}
dns->hostport = port;
if(hostlen)
@ -1138,7 +1136,7 @@ clean_up:
the time we spent until now! */
if(prev_alarm) {
/* there was an alarm() set before us, now put it back */
timediff_t elapsed_secs = curlx_timediff_ms(curlx_now(),
timediff_t elapsed_secs = curlx_timediff_ms(data->progress.now,
data->conn->created) / 1000;
/* the alarm period is counted in even number of seconds */

View file

@ -4949,7 +4949,7 @@ static CURLcode cr_exp100_read(struct Curl_easy *data,
DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE, "
"timeout %dms", data->set.expect_100_timeout));
ctx->state = EXP100_AWAITING_CONTINUE;
ctx->start = curlx_now();
ctx->start = data->progress.now;
Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
*nread = 0;
*eos = FALSE;
@ -4960,7 +4960,7 @@ static CURLcode cr_exp100_read(struct Curl_easy *data,
*eos = FALSE;
return CURLE_READ_ERROR;
case EXP100_AWAITING_CONTINUE:
ms = curlx_timediff_ms(curlx_now(), ctx->start);
ms = curlx_timediff_ms(data->progress.now, ctx->start);
if(ms < data->set.expect_100_timeout) {
DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
*nread = 0;

View file

@ -37,6 +37,7 @@
#include "select.h"
#include "curlx/base64.h"
#include "multiif.h"
#include "progress.h"
#include "url.h"
#include "urlapi-int.h"
#include "cfilters.h"
@ -305,7 +306,8 @@ static void h2_stream_hash_free(unsigned int id, void *stream)
static int32_t cf_h2_get_desired_local_win(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
curl_off_t avail = Curl_rlimit_avail(&data->progress.dl.rlimit, curlx_now());
curl_off_t avail =
Curl_rlimit_avail(&data->progress.dl.rlimit, &data->progress.now);
(void)cf;
if(avail < CURL_OFF_T_MAX) { /* limit in place */
@ -1422,7 +1424,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
struct Curl_cfilter *cf = userp;
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
struct Curl_easy *data_s, *calling = CF_DATA_CURRENT(cf);
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@ -1443,6 +1445,8 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
stream = H2_STREAM_CTX(ctx, data_s);
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
if(calling)
Curl_pgrs_now_update(data_s, calling);
h2_xfer_write_resp(cf, data_s, stream, (const char *)mem, len, FALSE);

View file

@ -1995,7 +1995,7 @@ static CURLcode imap_setup_connection(struct Curl_easy *data,
Curl_sasl_init(&imapc->sasl, data, &saslimap);
curlx_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
Curl_pp_init(pp);
Curl_pp_init(pp, &data->progress.now);
if(Curl_conn_meta_set(conn, CURL_META_IMAP_CONN, imapc, imap_conn_dtor))
return CURLE_OUT_OF_MEMORY;

View file

@ -186,7 +186,7 @@ static CURLcode mqtt_send(struct Curl_easy *data,
result = Curl_xfer_send(data, buf, len, FALSE, &n);
if(result)
return result;
mq->lastTime = curlx_now();
mq->lastTime = data->progress.now;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, n);
if(len != n) {
size_t nsend = len - n;
@ -770,7 +770,7 @@ MQTT_SUBACK_COMING:
}
/* we received something */
mq->lastTime = curlx_now();
mq->lastTime = data->progress.now;
/* if QoS is set, message contains packet id */
result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread);
@ -800,7 +800,7 @@ static CURLcode mqtt_do(struct Curl_easy *data, bool *done)
if(!mq)
return CURLE_FAILED_INIT;
mq->lastTime = curlx_now();
mq->lastTime = data->progress.now;
mq->pingsent = FALSE;
result = mqtt_connect(data);
@ -839,7 +839,7 @@ static CURLcode mqtt_ping(struct Curl_easy *data)
if(mqtt->state == MQTT_FIRST &&
!mq->pingsent &&
data->set.upkeep_interval_ms > 0) {
struct curltime t = curlx_now();
struct curltime t = data->progress.now;
timediff_t diff = curlx_timediff_ms(t, mq->lastTime);
if(diff > data->set.upkeep_interval_ms) {
@ -898,7 +898,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
Curl_debug(data, CURLINFO_HEADER_IN, (const char *)&mq->firstbyte, 1);
/* we received something */
mq->lastTime = curlx_now();
mq->lastTime = data->progress.now;
/* remember the first byte */
mq->npacket = 0;

View file

@ -99,6 +99,7 @@ static CURLMcode add_next_timeout(struct curltime now,
struct Curl_multi *multi,
struct Curl_easy *d);
static void multi_timeout(struct Curl_multi *multi,
struct curltime *pnow,
struct curltime *expire_time,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
@ -165,6 +166,8 @@ static void mstate(struct Curl_easy *data, CURLMstate state
CURL_TRC_M(data, "-> [%s]", CURL_MSTATE_NAME(state));
#endif
/* really switching state */
Curl_pgrs_now_set(data);
data->mstate = state;
switch(state) {
case MSTATE_DONE:
@ -414,6 +417,7 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d)
CURLMcode rc;
struct Curl_multi *multi = m;
struct Curl_easy *data = d;
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@ -445,6 +449,7 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d)
Curl_uint32_bset_clear(&multi->msgsent);
}
Curl_pgrs_now_set(data); /* start of API call */
if(data->multi_easy) {
/* if this easy handle was previously used for curl_easy_perform(), there
is a private multi handle here that we can kill */
@ -498,7 +503,7 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d)
/* Necessary in event based processing, where dirty handles trigger
* a timeout callback invocation. */
rc = Curl_update_timer(multi);
rc = Curl_update_timer(multi, &data->progress.now);
if(rc) {
data->multi = NULL; /* not anymore */
Curl_uint32_tbl_remove(&multi->xfers, data->mid);
@ -779,6 +784,7 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
Curl_pgrs_now_set(data); /* start of API call */
premature = (data->mstate < MSTATE_COMPLETED);
/* If the 'state' is not INIT or COMPLETED, we might need to do something
@ -877,7 +883,7 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
process_pending_handles(multi);
if(removed_timer) {
rc = Curl_update_timer(multi);
rc = Curl_update_timer(multi, &data->progress.now);
if(rc)
return rc;
}
@ -945,11 +951,11 @@ static CURLcode multi_adjust_pollset(struct Curl_easy *data,
CURLcode result = CURLE_OK;
if(ps->n) {
struct curltime now = curlx_now();
bool send_blocked, recv_blocked;
bool send_blocked =
(Curl_rlimit_avail(&data->progress.dl.rlimit, &data->progress.now) <= 0);
bool recv_blocked =
(Curl_rlimit_avail(&data->progress.ul.rlimit, &data->progress.now) <= 0);
recv_blocked = (Curl_rlimit_avail(&data->progress.dl.rlimit, now) <= 0);
send_blocked = (Curl_rlimit_avail(&data->progress.ul.rlimit, now) <= 0);
if(send_blocked || recv_blocked) {
int i;
for(i = 0; i <= SECONDARYSOCKET; ++i) {
@ -1220,6 +1226,7 @@ CURLMcode curl_multi_fdset(CURLM *m,
struct Curl_multi *multi = m;
struct easy_pollset ps;
unsigned int i, mid;
struct curltime now = curlx_now(); /* start of API call */
(void)exc_fd_set;
if(!GOOD_MULTI_HANDLE(multi))
@ -1238,6 +1245,7 @@ CURLMcode curl_multi_fdset(CURLM *m,
continue;
}
Curl_pgrs_now_at_least(data, &now);
Curl_multi_pollset(data, &ps);
for(i = 0; i < ps.n; i++) {
if(!FDSET_SOCK(ps.sockets[i]))
@ -1279,6 +1287,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
struct Curl_multi *multi = m;
struct easy_pollset ps;
unsigned int need = 0, mid;
struct curltime now = curlx_now(); /* start of API call */
if(!ufds && (size || !fd_count))
return CURLM_BAD_FUNCTION_ARGUMENT;
@ -1300,6 +1309,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
Curl_uint32_bset_remove(&multi->dirty, mid);
continue;
}
Curl_pgrs_now_at_least(data, &now);
Curl_multi_pollset(data, &ps);
need += Curl_waitfds_add_ps(&cwfds, &ps);
} while(Curl_uint32_bset_next(&multi->process, mid, &mid));
@ -1353,6 +1363,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
struct Curl_easy *data = NULL;
CURLMcode result = CURLM_OK;
struct curltime now = curlx_now(); /* start of API call */
uint32_t mid;
#ifdef USE_WINSOCK
@ -1385,11 +1396,13 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
Curl_uint32_bset_remove(&multi->dirty, mid);
continue;
}
Curl_pgrs_now_at_least(data, &now);
Curl_multi_pollset(data, &ps);
if(Curl_pollfds_add_ps(&cpfds, &ps)) {
result = CURLM_OUT_OF_MEMORY;
goto out;
}
now = data->progress.now;
} while(Curl_uint32_bset_next(&multi->process, mid, &mid));
}
@ -1450,7 +1463,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
* poll. Collecting the sockets may install new timers by protocols
* and connection filters.
* Use the shorter one of the internal and the caller requested timeout. */
multi_timeout(multi, &expire_time, &timeout_internal);
multi_timeout(multi, &now, &expire_time, &timeout_internal);
if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
timeout_ms = (int)timeout_internal;
@ -1571,7 +1584,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
long sleep_ms = 0;
/* Avoid busy-looping when there is nothing particular to wait for */
multi_timeout(multi, &expire_time, &sleep_ms);
multi_timeout(multi, &now, &expire_time, &sleep_ms);
if(sleep_ms) {
if(sleep_ms > timeout_ms)
sleep_ms = timeout_ms;
@ -1764,12 +1777,12 @@ static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
* Check whether a timeout occurred, and handle it if it did
*/
static bool multi_handle_timeout(struct Curl_easy *data,
struct curltime *now,
bool *stream_error,
CURLcode *result)
{
bool connect_timeout = data->mstate < MSTATE_DO;
timediff_t timeout_ms = Curl_timeleft_ms(data, now, connect_timeout);
timediff_t timeout_ms =
Curl_timeleft_ms(data, connect_timeout);
if(timeout_ms < 0) {
/* Handle timed out */
struct curltime since;
@ -1779,22 +1792,23 @@ static bool multi_handle_timeout(struct Curl_easy *data,
since = data->progress.t_startop;
if(data->mstate == MSTATE_RESOLVING)
failf(data, "Resolving timed out after %" FMT_TIMEDIFF_T
" milliseconds", curlx_timediff_ms(*now, since));
" milliseconds", curlx_timediff_ms(data->progress.now, since));
else if(data->mstate == MSTATE_CONNECTING)
failf(data, "Connection timed out after %" FMT_TIMEDIFF_T
" milliseconds", curlx_timediff_ms(*now, since));
" milliseconds", curlx_timediff_ms(data->progress.now, since));
else {
struct SingleRequest *k = &data->req;
if(k->size != -1) {
failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
" milliseconds with %" FMT_OFF_T " out of %"
FMT_OFF_T " bytes received",
curlx_timediff_ms(*now, since), k->bytecount, k->size);
curlx_timediff_ms(data->progress.now, since),
k->bytecount, k->size);
}
else {
failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
" milliseconds with %" FMT_OFF_T " bytes received",
curlx_timediff_ms(*now, since), k->bytecount);
curlx_timediff_ms(data->progress.now, since), k->bytecount);
}
}
*result = CURLE_OPERATION_TIMEDOUT;
@ -1920,14 +1934,16 @@ static CURLcode multi_follow(struct Curl_easy *data,
return CURLE_TOO_MANY_REDIRECTS;
}
static CURLcode mspeed_check(struct Curl_easy *data, struct curltime now)
static CURLcode mspeed_check(struct Curl_easy *data)
{
timediff_t recv_wait_ms = 0;
timediff_t send_wait_ms = 0;
/* check if our send/recv limits require idle waits */
send_wait_ms = Curl_rlimit_wait_ms(&data->progress.ul.rlimit, now);
recv_wait_ms = Curl_rlimit_wait_ms(&data->progress.dl.rlimit, now);
send_wait_ms =
Curl_rlimit_wait_ms(&data->progress.ul.rlimit, &data->progress.now);
recv_wait_ms =
Curl_rlimit_wait_ms(&data->progress.dl.rlimit, &data->progress.now);
if(send_wait_ms || recv_wait_ms) {
if(data->mstate != MSTATE_RATELIMITING) {
@ -1947,7 +1963,6 @@ static CURLcode mspeed_check(struct Curl_easy *data, struct curltime now)
}
static CURLMcode state_performing(struct Curl_easy *data,
struct curltime *nowp,
bool *stream_errorp,
CURLcode *resultp)
{
@ -1957,11 +1972,11 @@ static CURLMcode state_performing(struct Curl_easy *data,
CURLcode result = *resultp = CURLE_OK;
*stream_errorp = FALSE;
if(mspeed_check(data, *nowp) == CURLE_AGAIN)
if(mspeed_check(data) == CURLE_AGAIN)
return CURLM_OK;
/* read/write data if it is ready to do so */
result = Curl_sendrecv(data, nowp);
result = Curl_sendrecv(data);
if(data->req.done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
@ -2079,8 +2094,7 @@ static CURLMcode state_performing(struct Curl_easy *data,
}
}
else { /* not errored, not done */
*nowp = curlx_now();
mspeed_check(data, *nowp);
mspeed_check(data);
}
curlx_free(newurl);
*resultp = result;
@ -2225,7 +2239,6 @@ end:
}
static CURLMcode state_ratelimiting(struct Curl_easy *data,
struct curltime *nowp,
CURLcode *resultp)
{
CURLcode result = CURLE_OK;
@ -2243,7 +2256,7 @@ static CURLMcode state_ratelimiting(struct Curl_easy *data,
multi_done(data, result, TRUE);
}
else {
if(!mspeed_check(data, *nowp))
if(!mspeed_check(data))
rc = CURLM_CALL_MULTI_PERFORM;
}
*resultp = result;
@ -2302,7 +2315,6 @@ static CURLMcode state_resolving(struct Curl_multi *multi,
static CURLMcode state_connect(struct Curl_multi *multi,
struct Curl_easy *data,
struct curltime *nowp,
CURLcode *resultp)
{
/* Connect. We want to get a connection identifier filled in. This state can
@ -2326,7 +2338,6 @@ static CURLMcode state_connect(struct Curl_multi *multi,
process_pending_handles(data->multi);
if(!result) {
*nowp = curlx_now();
if(async)
/* We are now waiting for an asynchronous name lookup */
multistate(data, MSTATE_RESOLVING);
@ -2354,7 +2365,6 @@ static CURLMcode state_connect(struct Curl_multi *multi,
}
static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct curltime *nowp,
struct Curl_easy *data)
{
struct Curl_message *msg = NULL;
@ -2393,8 +2403,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
(HTTP/2), or the full connection for older protocols */
bool stream_error = FALSE;
rc = CURLM_OK;
/* update at start for continuous increase when looping */
*nowp = curlx_now();
if(multi_ischanged(multi, TRUE)) {
CURL_TRC_M(data, "multi changed, check CONNECT_PEND queue");
@ -2412,7 +2420,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Wait for the connect state as only then is the start time stored, but
we must not check already completed handles */
if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
multi_handle_timeout(data, nowp, &stream_error, &result))
multi_handle_timeout(data, &stream_error, &result))
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
@ -2432,7 +2440,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case MSTATE_SETUP:
/* Transitional state. Setup things for a new transfer. The handle
can come back to this state on a redirect. */
*nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
Curl_pgrsTime(data, TIMER_STARTSINGLE);
if(data->set.timeout)
Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
if(data->set.connecttimeout)
@ -2445,7 +2453,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
FALLTHROUGH();
case MSTATE_CONNECT:
rc = state_connect(multi, data, nowp, &result);
rc = state_connect(multi, data, &result);
break;
case MSTATE_RESOLVING:
@ -2596,11 +2604,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
rc = state_ratelimiting(data, nowp, &result);
rc = state_ratelimiting(data, &result);
break;
case MSTATE_PERFORMING:
rc = state_performing(data, nowp, &stream_error, &result);
rc = state_performing(data, &stream_error, &result);
break;
case MSTATE_DONE:
@ -2655,7 +2663,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
* declaring the connection timed out as we may almost have a completed
* connection. */
multi_handle_timeout(data, nowp, &stream_error, &result);
multi_handle_timeout(data, &stream_error, &result);
}
statemachine_end:
@ -2756,18 +2764,15 @@ statemachine_end:
return rc;
}
CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
static CURLMcode multi_perform(struct Curl_multi *multi,
struct curltime *pnow,
int *running_handles)
{
CURLMcode returncode = CURLM_OK;
struct Curl_tree *t = NULL;
struct curltime now = curlx_now();
struct Curl_multi *multi = m;
uint32_t mid;
SIGPIPE_VARIABLE(pipe_st);
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
@ -2788,15 +2793,17 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
continue;
}
sigpipe_apply(data, &pipe_st);
result = multi_runsingle(multi, &now, data);
Curl_pgrs_now_at_least(data, pnow);
result = multi_runsingle(multi, data);
*pnow = data->progress.now; /* in case transfer updated */
if(result)
returncode = result;
} while(Curl_uint32_bset_next(&multi->process, mid, &mid));
}
sigpipe_restore(&pipe_st);
if(multi_ischanged(m, TRUE))
process_pending_handles(m);
if(multi_ischanged(multi, TRUE))
process_pending_handles(multi);
if(!returncode)
returncode = Curl_mntfy_dispatch_all(multi);
@ -2812,15 +2819,15 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
* been handled!
*/
do {
multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
multi->timetree = Curl_splaygetbest(*pnow, multi->timetree, &t);
if(t) {
/* the removed may have another timeout in queue */
struct Curl_easy *data = Curl_splayget(t);
(void)add_next_timeout(now, multi, data);
(void)add_next_timeout(*pnow, multi, data);
if(data->mstate == MSTATE_PENDING) {
bool stream_unused;
CURLcode result_unused;
if(multi_handle_timeout(data, &now, &stream_unused, &result_unused)) {
if(multi_handle_timeout(data, &stream_unused, &result_unused)) {
infof(data, "PENDING handle timeout");
move_pending_to_connect(multi, data);
}
@ -2834,11 +2841,22 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
}
if(CURLM_OK >= returncode)
returncode = Curl_update_timer(multi);
returncode = Curl_update_timer(multi, pnow);
return returncode;
}
CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
{
struct curltime now = curlx_now(); /* start of API call */
struct Curl_multi *multi = m;
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
multi = m;
return multi_perform(multi, &now, running_handles);
}
CURLMcode curl_multi_cleanup(CURLM *m)
{
struct Curl_multi *multi = m;
@ -3103,7 +3121,9 @@ static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc)
mrc->run_xfers++;
sigpipe_apply(data, &mrc->pipe_st);
/* runsingle() clears the dirty mid */
result = multi_runsingle(multi, &mrc->now, data);
Curl_pgrs_now_at_least(data, &mrc->now);
result = multi_runsingle(multi, data);
mrc->now = data->progress.now; /* in case transfer updated */
if(CURLM_OK >= result) {
/* reassess event handling of data */
@ -3135,16 +3155,17 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
(void)ev_bitmask;
memset(&mrc, 0, sizeof(mrc));
mrc.multi = multi;
mrc.now = curlx_now();
mrc.now = curlx_now(); /* start of API call */
sigpipe_init(&mrc.pipe_st);
if(checkall) {
/* *perform() deals with running_handles on its own */
result = curl_multi_perform(multi, running_handles);
result = multi_perform(multi, &mrc.now, running_handles);
if(result != CURLM_BAD_HANDLE) {
/* Reassess event status of all active transfers */
result = Curl_multi_ev_assess_xfer_bset(multi, &multi->process);
result = Curl_multi_ev_assess_xfer_bset(multi, &multi->process,
&mrc.now);
}
goto out;
}
@ -3173,7 +3194,6 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
* to set a 0 timeout and call us again, we run them here.
* Do that only once or it might be unfair to transfers on other
* sockets. */
mrc.now = curlx_now();
multi_mark_expired_as_dirty(&mrc);
result = multi_run_dirty(&mrc);
}
@ -3193,7 +3213,7 @@ out:
}
if(CURLM_OK >= result)
result = Curl_update_timer(multi);
result = Curl_update_timer(multi, &mrc.now);
return result;
}
@ -3346,6 +3366,7 @@ static bool multi_has_dirties(struct Curl_multi *multi)
}
static void multi_timeout(struct Curl_multi *multi,
struct curltime *pnow,
struct curltime *expire_time,
long *timeout_ms)
{
@ -3360,14 +3381,11 @@ static void multi_timeout(struct Curl_multi *multi,
}
if(multi_has_dirties(multi)) {
*expire_time = curlx_now();
*expire_time = *pnow;
*timeout_ms = 0;
return;
}
else if(multi->timetree) {
/* we have a tree of expire times */
struct curltime now = curlx_now();
/* splay the lowest to the bottom */
multi->timetree = Curl_splay(tv_zero, multi->timetree);
/* this will not return NULL from a non-empty tree, but some compilers
@ -3377,9 +3395,9 @@ static void multi_timeout(struct Curl_multi *multi,
/* 'multi->timetree' will be non-NULL here but the compilers sometimes
yell at us if we assume so */
if(multi->timetree &&
curlx_timediff_us(multi->timetree->key, now) > 0) {
curlx_timediff_us(multi->timetree->key, *pnow) > 0) {
/* some time left before expiration */
timediff_t diff_ms = curlx_timediff_ceil_ms(multi->timetree->key, now);
timediff_t diff_ms = curlx_timediff_ceil_ms(multi->timetree->key, *pnow);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
data = Curl_splayget(multi->timetree);
#endif
@ -3419,6 +3437,7 @@ CURLMcode curl_multi_timeout(CURLM *m,
{
struct curltime expire_time;
struct Curl_multi *multi = m;
struct curltime now = curlx_now(); /* start of API call */
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
@ -3427,7 +3446,7 @@ CURLMcode curl_multi_timeout(CURLM *m,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
multi_timeout(multi, &expire_time, timeout_ms);
multi_timeout(multi, &now, &expire_time, timeout_ms);
return CURLM_OK;
}
@ -3435,7 +3454,8 @@ CURLMcode curl_multi_timeout(CURLM *m,
* Tell the application it should update its timers, if it subscribes to the
* update timer callback.
*/
CURLMcode Curl_update_timer(struct Curl_multi *multi)
CURLMcode Curl_update_timer(struct Curl_multi *multi,
struct curltime *pnow)
{
struct curltime expire_ts;
long timeout_ms;
@ -3444,7 +3464,7 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi)
if(!multi->timer_cb || multi->dead)
return CURLM_OK;
multi_timeout(multi, &expire_ts, &timeout_ms);
multi_timeout(multi, pnow, &expire_ts, &timeout_ms);
if(timeout_ms < 0 && multi->last_timeout_ms < 0) {
/* nothing to do */
@ -3552,7 +3572,6 @@ static CURLMcode multi_addtimeout(struct Curl_easy *data,
}
void Curl_expire_ex(struct Curl_easy *data,
const struct curltime *nowp,
timediff_t milli, expire_id id)
{
struct Curl_multi *multi = data->multi;
@ -3566,7 +3585,7 @@ void Curl_expire_ex(struct Curl_easy *data,
DEBUGASSERT(id < EXPIRE_LAST);
set = *nowp;
set = data->progress.now;
set.tv_sec += (time_t)(milli / 1000); /* may be a 64 to 32-bit conversion */
set.tv_usec += (int)(milli % 1000) * 1000;
@ -3580,7 +3599,7 @@ void Curl_expire_ex(struct Curl_easy *data,
/* Add it to the timer list. It must stay in the list until it has expired
in case we need to recompute the minimum timer later. */
multi_addtimeout(data, &set, id, nowp);
multi_addtimeout(data, &set, id, &data->progress.now);
if(curr_expire->tv_sec || curr_expire->tv_usec) {
/* This means that the struct is added as a node in the splay tree.
@ -3624,8 +3643,7 @@ void Curl_expire_ex(struct Curl_easy *data,
*/
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
{
struct curltime now = curlx_now();
Curl_expire_ex(data, &now, milli, id);
Curl_expire_ex(data, milli, id);
}
/*

View file

@ -33,6 +33,7 @@
#include "multiif.h"
#include "curlx/timeval.h"
#include "multi_ev.h"
#include "progress.h"
#include "select.h"
#include "uint-bset.h"
#include "uint-spbset.h"
@ -480,7 +481,8 @@ static struct easy_pollset *mev_get_last_pollset(struct Curl_easy *data,
return NULL;
}
static CURLMcode mev_assess(struct Curl_multi *multi, struct Curl_easy *data,
static CURLMcode mev_assess(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn)
{
struct easy_pollset ps, *last_ps;
@ -536,7 +538,8 @@ CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi,
}
CURLMcode Curl_multi_ev_assess_xfer_bset(struct Curl_multi *multi,
struct uint32_bset *set)
struct uint32_bset *set,
struct curltime *pnow)
{
uint32_t mid;
CURLMcode result = CURLM_OK;
@ -544,8 +547,10 @@ CURLMcode Curl_multi_ev_assess_xfer_bset(struct Curl_multi *multi,
if(multi && multi->socket_cb && Curl_uint32_bset_first(set, &mid)) {
do {
struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
if(data)
if(data) {
Curl_pgrs_now_at_least(data, pnow);
result = Curl_multi_ev_assess_xfer(multi, data);
}
} while(!result && Curl_uint32_bset_next(set, mid, &mid));
}
return result;

View file

@ -55,7 +55,8 @@ CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,
struct Curl_easy *data);
/* Assess all easy handles on the list */
CURLMcode Curl_multi_ev_assess_xfer_bset(struct Curl_multi *multi,
struct uint32_bset *set);
struct uint32_bset *set,
struct curltime *pnow);
/* Assess the connection by getting its current pollset */
CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi,
struct Curl_easy *data,

View file

@ -30,11 +30,11 @@
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id);
void Curl_expire_ex(struct Curl_easy *data,
const struct curltime *nowp,
timediff_t milli, expire_id id);
bool Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
CURLMcode Curl_update_timer(struct Curl_multi *multi,
struct curltime *pnow) WARN_UNUSED_RESULT;
void Curl_attach_connection(struct Curl_easy *data,
struct connectdata *conn);
void Curl_detach_connection(struct Curl_easy *data);

View file

@ -47,26 +47,30 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
timediff_t timeout_ms; /* in milliseconds */
timediff_t response_time = data->set.server_response_timeout ?
data->set.server_response_timeout : RESP_TIMEOUT;
struct curltime now = curlx_now();
/* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
supposed to govern the response for any given server response, not for
the time from connect to the given server response. */
/* pingpong can spend some time processing, always update
* the transfer timestamp before checking timeouts. */
Curl_pgrs_now_set(data);
/* Without a requested timeout, we only wait 'response_time' seconds for the
full response to arrive before we bail out */
timeout_ms = response_time - curlx_timediff_ms(now, pp->response);
timeout_ms = response_time -
curlx_timediff_ms(data->progress.now, pp->response);
if(data->set.timeout && !disconnecting) {
/* if timeout is requested, find out how much overall remains */
timediff_t timeout2_ms = Curl_timeleft_ms(data, &now, FALSE);
timediff_t timeout2_ms = Curl_timeleft_ms(data, FALSE);
/* pick the lowest number */
timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
}
if(disconnecting) {
timediff_t total_left_ms = Curl_timeleft_ms(data, NULL, FALSE);
timediff_t total_left_ms = Curl_timeleft_ms(data, FALSE);
timeout_ms = CURLMIN(timeout_ms, CURLMAX(total_left_ms, 0));
}
@ -135,11 +139,11 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
}
/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct pingpong *pp)
void Curl_pp_init(struct pingpong *pp, struct curltime *pnow)
{
DEBUGASSERT(!pp->initialised);
pp->nread_resp = 0;
pp->response = curlx_now(); /* start response time-out now! */
pp->response = *pnow; /* start response time-out */
pp->pending_resp = TRUE;
curlx_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
curlx_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD);
@ -208,7 +212,7 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
else {
pp->sendthis = NULL;
pp->sendleft = pp->sendsize = 0;
pp->response = curlx_now();
pp->response = data->progress.now;
}
return CURLE_OK;
@ -399,7 +403,7 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
else {
pp->sendthis = NULL;
pp->sendleft = pp->sendsize = 0;
pp->response = curlx_now();
pp->response = data->progress.now;
}
return CURLE_OK;
}

View file

@ -87,7 +87,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
bool block, bool disconnecting);
/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct pingpong *pp);
void Curl_pp_init(struct pingpong *pp, struct curltime *pnow);
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */

View file

@ -1297,7 +1297,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
/* Initialise the pingpong layer */
Curl_pp_init(pp);
Curl_pp_init(pp, &data->progress.now);
/* Parse the URL options */
result = pop3_parse_url_options(conn);

View file

@ -141,6 +141,25 @@ UNITTEST CURLcode pgrs_speedcheck(struct Curl_easy *data,
return CURLE_OK;
}
void Curl_pgrs_now_set(struct Curl_easy *data)
{
data->progress.now = curlx_now();
}
void Curl_pgrs_now_at_least(struct Curl_easy *data, struct curltime *pts)
{
if((pts->tv_sec > data->progress.now.tv_sec) ||
((pts->tv_sec == data->progress.now.tv_sec) &&
(pts->tv_usec > data->progress.now.tv_usec))) {
data->progress.now = *pts;
}
}
void Curl_pgrs_now_update(struct Curl_easy *data, struct Curl_easy *other)
{
Curl_pgrs_now_at_least(data, &other->progress.now);
}
/*
New proposed interface, 9th of February 2000:
@ -174,7 +193,7 @@ int Curl_pgrsDone(struct Curl_easy *data)
void Curl_pgrsReset(struct Curl_easy *data)
{
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
data->progress.dl.cur_size = 0;
Curl_pgrsSetUploadSize(data, -1);
Curl_pgrsSetDownloadSize(data, -1);
data->progress.speeder_c = 0; /* reset speed records */
@ -288,19 +307,17 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
*
* @unittest: 1399
*/
struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer)
void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
{
struct curltime now = curlx_now();
Curl_pgrsTimeWas(data, timer, now);
return now;
Curl_pgrs_now_set(data); /* update on real progress */
Curl_pgrsTimeWas(data, timer, data->progress.now);
}
void Curl_pgrsStartNow(struct Curl_easy *data)
{
struct Progress *p = &data->progress;
p->speeder_c = 0; /* reset the progress meter display */
p->start = curlx_now();
p->start = data->progress.now;
p->is_t_startransfer_set = FALSE;
p->dl.cur_size = 0;
p->ul.cur_size = 0;
@ -309,12 +326,20 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
p->ul_size_known = FALSE;
}
/*
* Set the number of downloaded bytes so far.
*/
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
void Curl_pgrs_download_inc(struct Curl_easy *data, size_t delta)
{
data->progress.dl.cur_size = size;
if(delta) {
data->progress.dl.cur_size += delta;
Curl_rlimit_drain(&data->progress.dl.rlimit, delta, &data->progress.now);
}
}
void Curl_pgrs_upload_inc(struct Curl_easy *data, size_t delta)
{
if(delta) {
data->progress.ul.cur_size += delta;
Curl_rlimit_drain(&data->progress.ul.rlimit, delta, &data->progress.now);
}
}
/*
@ -618,18 +643,16 @@ static CURLcode pgrs_update(struct Curl_easy *data, struct curltime *pnow)
CURLcode Curl_pgrsUpdate(struct Curl_easy *data)
{
struct curltime now = curlx_now(); /* what time is it */
return pgrs_update(data, &now);
return pgrs_update(data, &data->progress.now);
}
CURLcode Curl_pgrsCheck(struct Curl_easy *data)
{
struct curltime now = curlx_now();
CURLcode result;
result = pgrs_update(data, &now);
result = pgrs_update(data, &data->progress.now);
if(!result && !data->req.done)
result = pgrs_speedcheck(data, &now);
result = pgrs_speedcheck(data, &data->progress.now);
return result;
}
@ -638,6 +661,5 @@ CURLcode Curl_pgrsCheck(struct Curl_easy *data)
*/
void Curl_pgrsUpdate_nometer(struct Curl_easy *data)
{
struct curltime now = curlx_now(); /* what time is it */
(void)progress_calc(data, &now);
(void)progress_calc(data, &data->progress.now);
}

View file

@ -44,12 +44,24 @@ typedef enum {
TIMER_LAST /* must be last */
} timerid;
#define CURL_PGRS_NOW_MONOTONIC
/* Set current time in data->progress.now */
void Curl_pgrs_now_set(struct Curl_easy *data);
/* Advance `now` timestamp at least to given timestamp.
* No effect it data's `now` is already later than `pts`. */
void Curl_pgrs_now_at_least(struct Curl_easy *data, struct curltime *pts);
/* `data` progressing continues after `other` processing. Advance `data`s
* now timestamp to at least `other's` timestamp. */
void Curl_pgrs_now_update(struct Curl_easy *data, struct Curl_easy *other);
int Curl_pgrsDone(struct Curl_easy *data);
void Curl_pgrsStartNow(struct Curl_easy *data);
void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_pgrs_download_inc(struct Curl_easy *data, size_t delta);
void Curl_pgrs_upload_inc(struct Curl_easy *data, size_t delta);
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
/* perform progress update, invoking callbacks at intervals */
@ -68,7 +80,7 @@ void Curl_pgrsReset(struct Curl_easy *data);
/* Reset sizes for up- and download. */
void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
/**
* Update progress timer with the elapsed time from its start to `timestamp`.
* This allows updating timers later and is used by happy eyeballing, where

View file

@ -35,12 +35,13 @@
void Curl_rlimit_init(struct Curl_rlimit *r,
curl_off_t rate_per_s,
curl_off_t burst_per_s,
struct curltime ts)
struct curltime *pts)
{
curl_off_t rate_steps;
DEBUGASSERT(rate_per_s >= 0);
DEBUGASSERT(burst_per_s >= rate_per_s || !burst_per_s);
DEBUGASSERT(pts);
r->step_us = CURL_US_PER_SEC;
r->rate_per_step = rate_per_s;
r->burst_per_step = burst_per_s;
@ -57,15 +58,15 @@ void Curl_rlimit_init(struct Curl_rlimit *r,
}
r->tokens = r->rate_per_step;
r->spare_us = 0;
r->ts = ts;
r->ts = *pts;
r->blocked = FALSE;
}
void Curl_rlimit_start(struct Curl_rlimit *r, struct curltime ts)
void Curl_rlimit_start(struct Curl_rlimit *r, struct curltime *pts)
{
r->tokens = r->rate_per_step;
r->spare_us = 0;
r->ts = ts;
r->ts = *pts;
}
bool Curl_rlimit_active(struct Curl_rlimit *r)
@ -79,16 +80,16 @@ bool Curl_rlimit_is_blocked(struct Curl_rlimit *r)
}
static void ratelimit_update(struct Curl_rlimit *r,
struct curltime ts)
struct curltime *pts)
{
timediff_t elapsed_us, elapsed_steps;
curl_off_t token_gain;
DEBUGASSERT(r->rate_per_step);
if((r->ts.tv_sec == ts.tv_sec) && (r->ts.tv_usec == ts.tv_usec))
if((r->ts.tv_sec == pts->tv_sec) && (r->ts.tv_usec == pts->tv_usec))
return;
elapsed_us = curlx_timediff_us(ts, r->ts);
elapsed_us = curlx_timediff_us(*pts, r->ts);
if(elapsed_us < 0) { /* not going back in time */
DEBUGASSERT(0);
return;
@ -99,7 +100,7 @@ static void ratelimit_update(struct Curl_rlimit *r,
return;
/* we do the update */
r->ts = ts;
r->ts = *pts;
elapsed_steps = elapsed_us / r->step_us;
r->spare_us = elapsed_us % r->step_us;
@ -119,12 +120,12 @@ static void ratelimit_update(struct Curl_rlimit *r,
}
curl_off_t Curl_rlimit_avail(struct Curl_rlimit *r,
struct curltime ts)
struct curltime *pts)
{
if(r->blocked)
return 0;
else if(r->rate_per_step) {
ratelimit_update(r, ts);
ratelimit_update(r, pts);
return r->tokens;
}
else
@ -133,12 +134,12 @@ curl_off_t Curl_rlimit_avail(struct Curl_rlimit *r,
void Curl_rlimit_drain(struct Curl_rlimit *r,
size_t tokens,
struct curltime ts)
struct curltime *pts)
{
if(r->blocked || !r->rate_per_step)
return;
ratelimit_update(r, ts);
ratelimit_update(r, pts);
#if SIZEOF_CURL_OFF_T <= SIZEOF_SIZE_T
if(tokens > CURL_OFF_T_MAX) {
r->tokens = CURL_OFF_T_MIN;
@ -156,13 +157,13 @@ void Curl_rlimit_drain(struct Curl_rlimit *r,
}
timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r,
struct curltime ts)
struct curltime *pts)
{
timediff_t wait_us, elapsed_us;
if(r->blocked || !r->rate_per_step)
return 0;
ratelimit_update(r, ts);
ratelimit_update(r, pts);
if(r->tokens > 0)
return 0;
@ -171,7 +172,7 @@ timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r,
wait_us = (1 + (-r->tokens / r->rate_per_step)) * r->step_us;
wait_us -= r->spare_us;
elapsed_us = curlx_timediff_us(ts, r->ts);
elapsed_us = curlx_timediff_us(*pts, r->ts);
if(elapsed_us >= wait_us)
return 0;
wait_us -= elapsed_us;
@ -180,17 +181,17 @@ timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r,
void Curl_rlimit_block(struct Curl_rlimit *r,
bool activate,
struct curltime ts)
struct curltime *pts)
{
if(!activate == !r->blocked)
return;
r->ts = ts;
r->ts = *pts;
r->blocked = activate;
if(!r->blocked) {
/* Start rate limiting fresh. The amount of time this was blocked
* does not generate extra tokens. */
Curl_rlimit_start(r, ts);
Curl_rlimit_start(r, pts);
}
else {
r->tokens = 0;

View file

@ -62,14 +62,14 @@ struct Curl_rlimit {
void Curl_rlimit_init(struct Curl_rlimit *r,
curl_off_t rate_per_s,
curl_off_t burst_per_s,
struct curltime ts);
struct curltime *pts);
/* Start ratelimiting with the given timestamp. Resets available tokens. */
void Curl_rlimit_start(struct Curl_rlimit *r, struct curltime ts);
void Curl_rlimit_start(struct Curl_rlimit *r, struct curltime *pts);
/* How many milliseconds to wait until token are available again. */
timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r,
struct curltime ts);
struct curltime *pts);
/* Return if rate limiting of tokens is active */
bool Curl_rlimit_active(struct Curl_rlimit *r);
@ -77,16 +77,16 @@ bool Curl_rlimit_is_blocked(struct Curl_rlimit *r);
/* Return how many tokens are available to spend, may be negative */
curl_off_t Curl_rlimit_avail(struct Curl_rlimit *r,
struct curltime ts);
struct curltime *pts);
/* Drain tokens from the ratelimit, return how many are now available. */
void Curl_rlimit_drain(struct Curl_rlimit *r,
size_t tokens,
struct curltime ts);
struct curltime *pts);
/* Block/unblock ratelimiting. A blocked ratelimit has 0 tokens available. */
void Curl_rlimit_block(struct Curl_rlimit *r,
bool activate,
struct curltime ts);
struct curltime *pts);
#endif /* HEADER_Curl_rlimit_H */

View file

@ -90,7 +90,7 @@ CURLcode Curl_req_soft_reset(struct SingleRequest *req,
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data)
{
req->start = curlx_now();
req->start = data->progress.now;
return Curl_req_soft_reset(req, data);
}
@ -219,7 +219,7 @@ static CURLcode xfer_send(struct Curl_easy *data,
size_t body_len = *pnwritten - hds_len;
Curl_debug(data, CURLINFO_DATA_OUT, buf + hds_len, body_len);
data->req.writebytecount += body_len;
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
Curl_pgrs_upload_inc(data, body_len);
}
}
}

View file

@ -230,7 +230,7 @@ static CURLcode cw_download_write(struct Curl_easy *data,
if(!ctx->started_response &&
!(type & (CLIENTWRITE_INFO | CLIENTWRITE_CONNECT))) {
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
Curl_rlimit_start(&data->progress.dl.rlimit, curlx_now());
Curl_rlimit_start(&data->progress.dl.rlimit, &data->progress.now);
ctx->started_response = TRUE;
}
@ -303,9 +303,10 @@ static CURLcode cw_download_write(struct Curl_easy *data,
}
/* Update stats, write and report progress */
Curl_rlimit_drain(&data->progress.dl.rlimit, nwrite, curlx_now());
data->req.bytecount += nwrite;
Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
if(nwrite) {
data->req.bytecount += nwrite;
Curl_pgrs_download_inc(data, nwrite);
}
if(excess_len) {
if(!data->req.ignorebody) {
@ -1201,13 +1202,13 @@ CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
DEBUGASSERT(data->req.reader_stack);
}
if(!data->req.reader_started) {
Curl_rlimit_start(&data->progress.ul.rlimit, curlx_now());
Curl_rlimit_start(&data->progress.ul.rlimit, &data->progress.now);
data->req.reader_started = TRUE;
}
if(Curl_rlimit_active(&data->progress.ul.rlimit)) {
curl_off_t ul_avail =
Curl_rlimit_avail(&data->progress.ul.rlimit, curlx_now());
Curl_rlimit_avail(&data->progress.ul.rlimit, &data->progress.now);
if(ul_avail <= 0) {
result = CURLE_OK;
*eos = FALSE;
@ -1218,8 +1219,6 @@ CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
}
result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
nread, eos);
if(!result)
Curl_rlimit_drain(&data->progress.ul.rlimit, *nread, curlx_now());
out:
CURL_TRC_READ(data, "client_read(len=%zu) -> %d, nread=%zu, eos=%d",

View file

@ -2813,7 +2813,8 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option,
if(offt < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
s->max_send_speed = offt;
Curl_rlimit_init(&data->progress.ul.rlimit, offt, offt, curlx_now());
Curl_rlimit_init(&data->progress.ul.rlimit, offt, offt,
&data->progress.now);
break;
case CURLOPT_MAX_RECV_SPEED_LARGE:
/*
@ -2823,7 +2824,8 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option,
if(offt < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
s->max_recv_speed = offt;
Curl_rlimit_init(&data->progress.dl.rlimit, offt, offt, curlx_now());
Curl_rlimit_init(&data->progress.dl.rlimit, offt, offt,
&data->progress.now);
break;
case CURLOPT_RESUME_FROM_LARGE:
/*

View file

@ -1146,7 +1146,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
sizeof(struct smb_header) + 5);
data->req.bytecount += len;
data->req.offset += len;
Curl_pgrsSetUploadCounter(data, data->req.bytecount);
Curl_pgrs_upload_inc(data, len);
if(data->req.bytecount >= data->req.size)
next_state = SMB_CLOSE;
else

View file

@ -1441,7 +1441,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */
Curl_pp_init(&smtpc->pp);
Curl_pp_init(&smtpc->pp, &data->progress.now);
/* Parse the URL options */
result = smtp_parse_url_options(data->conn, smtpc);

View file

@ -133,7 +133,7 @@ CURLcode Curl_blockread_all(struct Curl_cfilter *cf,
*pnread = 0;
for(;;) {
timediff_t timeout_ms = Curl_timeleft_ms(data, NULL, TRUE);
timediff_t timeout_ms = Curl_timeleft_ms(data, TRUE);
if(timeout_ms < 0) {
/* we already got the timeout */
return CURLE_OPERATION_TIMEDOUT;

View file

@ -1325,11 +1325,8 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
timediff_t interval_ms;
struct pollfd pfd[2];
int poll_cnt;
curl_off_t total_dl = 0;
curl_off_t total_ul = 0;
ssize_t snread;
#endif
struct curltime now;
bool keepon = TRUE;
char buffer[4 * 1024];
struct TELNET *tn;
@ -1511,8 +1508,9 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
} /* switch */
if(data->set.timeout) {
now = curlx_now();
if(curlx_timediff_ms(now, conn->created) >= data->set.timeout) {
Curl_pgrs_now_set(data);
if(curlx_timediff_ms(data->progress.now, conn->created) >=
data->set.timeout) {
failf(data, "Time-out");
result = CURLE_OPERATION_TIMEDOUT;
keepon = FALSE;
@ -1581,8 +1579,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
break;
}
total_dl += nread;
Curl_pgrsSetDownloadCounter(data, total_dl);
Curl_pgrs_download_inc(data, nread);
result = telrcv(data, tn, (unsigned char *)buffer, nread);
if(result) {
keepon = FALSE;
@ -1622,8 +1619,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
keepon = FALSE;
break;
}
total_ul += snread;
Curl_pgrsSetUploadCounter(data, total_ul);
Curl_pgrs_upload_inc(data, (size_t)snread);
}
else if(snread < 0)
keepon = FALSE;
@ -1632,8 +1628,9 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
} /* poll switch statement */
if(data->set.timeout) {
now = curlx_now();
if(curlx_timediff_ms(now, conn->created) >= data->set.timeout) {
Curl_pgrs_now_set(data);
if(curlx_timediff_ms(data->progress.now, conn->created) >=
data->set.timeout) {
failf(data, "Time-out");
result = CURLE_OPERATION_TIMEDOUT;
keepon = FALSE;

View file

@ -205,7 +205,7 @@ static CURLcode tftp_set_timeouts(struct tftp_conn *state)
bool start = (state->state == TFTP_STATE_START);
/* Compute drop-dead time */
timeout_ms = Curl_timeleft_ms(state->data, NULL, start);
timeout_ms = Curl_timeleft_ms(state->data, start);
if(timeout_ms < 0) {
/* time-out, bail out, go home */
@ -793,7 +793,7 @@ static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event)
}
/* Update the progress meter */
k->writebytecount += state->sbytes;
Curl_pgrsSetUploadCounter(data, k->writebytecount);
Curl_pgrs_upload_inc(data, state->sbytes);
break;
case TFTP_EVENT_TIMEOUT:
@ -1192,7 +1192,7 @@ static timediff_t tftp_state_timeout(struct tftp_conn *state,
if(event)
*event = TFTP_EVENT_NONE;
timeout_ms = Curl_timeleft_ms(state->data, NULL,
timeout_ms = Curl_timeleft_ms(state->data,
(state->state == TFTP_STATE_START));
if(timeout_ms < 0) {
state->error = TFTP_ERR_TIMEOUT;

View file

@ -261,7 +261,7 @@ static CURLcode sendrecv_dl(struct Curl_easy *data,
if(bytestoread && Curl_rlimit_active(&data->progress.dl.rlimit)) {
curl_off_t dl_avail = Curl_rlimit_avail(&data->progress.dl.rlimit,
curlx_now());
&data->progress.now);
/* DEBUGF(infof(data, "dl_rlimit, available=%" FMT_OFF_T, dl_avail));
*/
/* In case of rate limited downloads: if this loop already got
@ -364,12 +364,11 @@ static CURLcode sendrecv_ul(struct Curl_easy *data)
* Curl_sendrecv() is the low-level function to be called when data is to
* be read and written to/from the connection.
*/
CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp)
CURLcode Curl_sendrecv(struct Curl_easy *data)
{
struct SingleRequest *k = &data->req;
CURLcode result = CURLE_OK;
DEBUGASSERT(nowp);
if(Curl_xfer_is_blocked(data)) {
result = CURLE_OK;
goto out;
@ -395,18 +394,20 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp)
goto out;
if(k->keepon) {
if(Curl_timeleft_ms(data, nowp, FALSE) < 0) {
if(Curl_timeleft_ms(data, FALSE) < 0) {
if(k->size != -1) {
failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
" milliseconds with %" FMT_OFF_T " out of %"
FMT_OFF_T " bytes received",
curlx_timediff_ms(*nowp, data->progress.t_startsingle),
curlx_timediff_ms(data->progress.now,
data->progress.t_startsingle),
k->bytecount, k->size);
}
else {
failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
" milliseconds with %" FMT_OFF_T " bytes received",
curlx_timediff_ms(*nowp, data->progress.t_startsingle),
curlx_timediff_ms(data->progress.now,
data->progress.t_startsingle),
k->bytecount);
}
result = CURLE_OPERATION_TIMEDOUT;
@ -902,7 +903,7 @@ bool Curl_xfer_recv_is_paused(struct Curl_easy *data)
CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable)
{
CURLcode result = CURLE_OK;
Curl_rlimit_block(&data->progress.ul.rlimit, enable, curlx_now());
Curl_rlimit_block(&data->progress.ul.rlimit, enable, &data->progress.now);
if(!enable && Curl_creader_is_paused(data))
result = Curl_creader_unpause(data);
Curl_pgrsSendPause(data, enable);
@ -912,7 +913,7 @@ CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable)
CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable)
{
CURLcode result = CURLE_OK;
Curl_rlimit_block(&data->progress.dl.rlimit, enable, curlx_now());
Curl_rlimit_block(&data->progress.dl.rlimit, enable, &data->progress.now);
if(!enable && Curl_cwriter_is_paused(data))
result = Curl_cwriter_unpause(data);
Curl_conn_ev_data_pause(data, enable);

View file

@ -34,7 +34,7 @@ void Curl_init_CONNECT(struct Curl_easy *data);
CURLcode Curl_pretransfer(struct Curl_easy *data);
CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp);
CURLcode Curl_sendrecv(struct Curl_easy *data);
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);

View file

@ -514,6 +514,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
#endif
Curl_netrc_init(&data->state.netrc);
Curl_init_userdefined(data);
Curl_pgrs_now_set(data); /* on easy handle create */
*curl = data;
return CURLE_OK;
@ -664,21 +665,15 @@ static bool conn_maxage(struct Curl_easy *data,
* Return TRUE iff the given connection is considered dead.
*/
bool Curl_conn_seems_dead(struct connectdata *conn,
struct Curl_easy *data,
struct curltime *pnow)
struct Curl_easy *data)
{
DEBUGASSERT(!data->conn);
if(!CONN_INUSE(conn)) {
/* The check for a dead socket makes sense only if the connection is not in
use */
bool dead;
struct curltime now;
if(!pnow) {
now = curlx_now();
pnow = &now;
}
if(conn_maxage(data, conn, *pnow)) {
if(conn_maxage(data, conn, data->progress.now)) {
/* avoid check if already too old */
dead = TRUE;
}
@ -1241,7 +1236,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
if(!url_match_multiplex_limits(conn, m))
return FALSE;
if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data, NULL)) {
if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data)) {
/* remove and disconnect. */
Curl_conn_terminate(m->data, conn, FALSE);
return FALSE;
@ -1346,7 +1341,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->remote_port = -1; /* unknown at this point */
/* Store creation time to help future close decision making */
conn->created = curlx_now();
conn->created = data->progress.now;
/* Store current time to give a baseline to keepalive connection times. */
conn->keepalive = conn->created;
@ -3208,7 +3203,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
{
struct hostname *ehost;
int eport;
timediff_t timeout_ms = Curl_timeleft_ms(data, NULL, TRUE);
timediff_t timeout_ms = Curl_timeleft_ms(data, TRUE);
const char *peertype = "host";
CURLcode result;
@ -3266,7 +3261,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
else if(result == CURLE_OPERATION_TIMEDOUT) {
failf(data, "Failed to resolve %s '%s' with timeout after %"
FMT_TIMEDIFF_T " ms", peertype, ehost->dispname,
curlx_timediff_ms(curlx_now(), data->progress.t_startsingle));
curlx_timediff_ms(data->progress.now, data->progress.t_startsingle));
return CURLE_OPERATION_TIMEDOUT;
}
else if(result) {

View file

@ -84,8 +84,7 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
* @param nowp NULL or pointer to time being checked against.
*/
bool Curl_conn_seems_dead(struct connectdata *conn,
struct Curl_easy *data,
struct curltime *nowp);
struct Curl_easy *data);
/**
* Perform upkeep operations on the connection.

View file

@ -802,6 +802,7 @@ struct pgrs_dir {
};
struct Progress {
struct curltime now; /* current time of processing */
time_t lastshow; /* time() of the last displayed progress meter or NULL to
force redraw at next call */
struct pgrs_dir ul;

View file

@ -384,12 +384,13 @@ struct pkt_io_ctx {
ngtcp2_path_storage ps;
};
static void pktx_update_time(struct pkt_io_ctx *pktx,
static void pktx_update_time(struct Curl_easy *data,
struct pkt_io_ctx *pktx,
struct Curl_cfilter *cf)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
vquic_ctx_update_time(&ctx->q);
vquic_ctx_update_time(data, &ctx->q);
pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
(ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
}
@ -398,10 +399,14 @@ static void pktx_init(struct pkt_io_ctx *pktx,
struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
pktx->cf = cf;
pktx->data = data;
ngtcp2_path_storage_zero(&pktx->ps);
pktx_update_time(pktx, cf);
vquic_ctx_set_time(data, &ctx->q);
pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
(ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
}
static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
@ -500,7 +505,8 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data)
if(!ctx || !data)
return NGHTTP3_ERR_CALLBACK_FAILURE;
ctx->handshake_at = curlx_now();
Curl_pgrs_now_set(data); /* real change */
ctx->handshake_at = data->progress.now;
ctx->tls_handshake_complete = TRUE;
Curl_vquic_report_handshake(&ctx->tls, cf, data);
@ -900,7 +906,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
pktx = &local_pktx;
}
else {
pktx_update_time(pktx, cf);
pktx_update_time(data, pktx, cf);
}
expiry = ngtcp2_conn_get_expiry(ctx->qconn);
@ -1046,14 +1052,13 @@ static void cf_ngtcp2_ack_stream(struct Curl_cfilter *cf,
struct h3_stream_ctx *stream)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct curltime now = curlx_now();
curl_off_t avail;
uint64_t ack_len = 0;
/* How many byte to ack on the stream? */
/* how much does rate limiting allow us to acknowledge? */
avail = Curl_rlimit_avail(&data->progress.dl.rlimit, now);
avail = Curl_rlimit_avail(&data->progress.dl.rlimit, &data->progress.now);
if(avail == CURL_OFF_T_MAX) { /* no rate limit, ack all */
ack_len = stream->download_unacked;
}
@ -1077,6 +1082,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
struct Curl_easy *calling = CF_DATA_CURRENT(cf);
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)conn;
@ -1084,6 +1090,8 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
if(!stream)
return NGHTTP3_ERR_CALLBACK_FAILURE;
if(calling)
Curl_pgrs_now_update(data, calling);
h3_xfer_write_resp(cf, data, stream, (const char *)buf, blen, FALSE);
CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, blen);
@ -1740,19 +1748,30 @@ denied:
return result;
}
struct cf_ngtcp2_recv_ctx {
struct pkt_io_ctx *pktx;
size_t pkt_count;
};
static CURLcode cf_ngtcp2_recv_pkts(const unsigned char *buf, size_t buflen,
size_t gso_size,
struct sockaddr_storage *remote_addr,
socklen_t remote_addrlen, int ecn,
void *userp)
{
struct pkt_io_ctx *pktx = userp;
struct cf_ngtcp2_recv_ctx *rctx = userp;
struct pkt_io_ctx *pktx = rctx->pktx;
struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
ngtcp2_pkt_info pi;
ngtcp2_path path;
size_t offset, pktlen;
int rv;
if(!rctx->pkt_count) {
pktx_update_time(pktx->data, pktx, pktx->cf);
ngtcp2_path_storage_zero(&pktx->ps);
}
if(ecn)
CURL_TRC_CF(pktx->data, pktx->cf, "vquic_recv(len=%zu, gso=%zu, ecn=%x)",
buflen, gso_size, ecn);
@ -1763,6 +1782,7 @@ static CURLcode cf_ngtcp2_recv_pkts(const unsigned char *buf, size_t buflen,
pi.ecn = (uint8_t)ecn;
for(offset = 0; offset < buflen; offset += gso_size) {
rctx->pkt_count++;
pktlen = ((offset + gso_size) <= buflen) ? gso_size : (buflen - offset);
rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi,
buf + offset, pktlen, pktx->ts);
@ -1787,23 +1807,22 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct pkt_io_ctx local_pktx;
struct cf_ngtcp2_recv_ctx rctx;
CURLcode result = CURLE_OK;
if(!pktx) {
pktx_init(&local_pktx, cf, data);
pktx = &local_pktx;
}
else {
pktx_update_time(pktx, cf);
ngtcp2_path_storage_zero(&pktx->ps);
}
result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
if(result)
return result;
rctx.pktx = pktx;
rctx.pkt_count = 0;
return vquic_recv_packets(cf, data, &ctx->q, 1000,
cf_ngtcp2_recv_pkts, pktx);
cf_ngtcp2_recv_pkts, &rctx);
}
/**
@ -1929,7 +1948,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
pktx = &local_pktx;
}
else {
pktx_update_time(pktx, cf);
pktx_update_time(data, pktx, cf);
ngtcp2_path_storage_zero(&pktx->ps);
}
@ -2016,7 +2035,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
}
return curlcode;
}
pktx_update_time(pktx, cf);
pktx_update_time(data, pktx, cf);
ngtcp2_conn_update_pkt_tx_time(ctx->qconn, pktx->ts);
}
return CURLE_OK;
@ -2529,7 +2548,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
ctx->qlogfd = qfd; /* -1 if failure above */
quic_settings(ctx, data, pktx);
result = vquic_ctx_init(&ctx->q);
result = vquic_ctx_init(data, &ctx->q);
if(result)
return result;
@ -2598,7 +2617,6 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
struct cf_ngtcp2_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
struct cf_call_data save;
struct curltime now;
struct pkt_io_ctx pktx;
if(cf->connected) {
@ -2614,13 +2632,12 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
now = curlx_now();
pktx_init(&pktx, cf, data);
CF_DATA_SAVE(save, cf, data);
if(!ctx->qconn) {
ctx->started_at = now;
ctx->started_at = data->progress.now;
result = cf_connect_start(cf, data, &pktx);
if(result)
goto out;
@ -2794,7 +2811,8 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
* it will close the connection when it expires. */
rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
if(rp && rp->max_idle_timeout) {
timediff_t idletime_ms = curlx_timediff_ms(curlx_now(), ctx->q.last_io);
timediff_t idletime_ms =
curlx_timediff_ms(data->progress.now, ctx->q.last_io);
if(idletime_ms > 0) {
uint64_t max_idle_ms =
(uint64_t)(rp->max_idle_timeout / NGTCP2_MILLISECONDS);

View file

@ -1161,7 +1161,7 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
if(result)
goto out;
result = vquic_ctx_init(&ctx->q);
result = vquic_ctx_init(data, &ctx->q);
if(result)
goto out;
@ -1748,7 +1748,6 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
struct cf_call_data save;
struct curltime now;
int err;
if(cf->connected) {
@ -1764,11 +1763,10 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
now = curlx_now();
CF_DATA_SAVE(save, cf, data);
if(!ctx->tls.ossl.ssl) {
ctx->started_at = now;
ctx->started_at = data->progress.now;
result = cf_osslq_ctx_start(cf, data);
if(result)
goto out;
@ -1778,7 +1776,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
int readable = SOCKET_READABLE(ctx->q.sockfd, 0);
if(readable > 0 && (readable & CURL_CSELECT_IN)) {
ctx->got_first_byte = TRUE;
ctx->first_byte_at = curlx_now();
ctx->first_byte_at = data->progress.now;
}
}
@ -1799,14 +1797,14 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
/* if not recorded yet, take the timestamp before we called
* SSL_do_handshake() as the time we received the first packet. */
ctx->got_first_byte = TRUE;
ctx->first_byte_at = now;
ctx->first_byte_at = data->progress.now;
}
/* Record the handshake complete with a new time stamp. */
now = curlx_now();
ctx->handshake_at = now;
ctx->q.last_io = now;
Curl_pgrs_now_set(data);
ctx->handshake_at = data->progress.now;
ctx->q.last_io = data->progress.now;
CURL_TRC_CF(data, cf, "handshake complete after %" FMT_TIMEDIFF_T "ms",
curlx_timediff_ms(now, ctx->started_at));
curlx_timediff_ms(data->progress.now, ctx->started_at));
result = cf_osslq_verify_peer(cf, data);
if(!result) {
CURL_TRC_CF(data, cf, "peer verified");
@ -1818,17 +1816,17 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
int detail = SSL_get_error(ctx->tls.ossl.ssl, err);
switch(detail) {
case SSL_ERROR_WANT_READ:
ctx->q.last_io = now;
ctx->q.last_io = data->progress.now;
CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV");
goto out;
case SSL_ERROR_WANT_WRITE:
ctx->q.last_io = now;
ctx->q.last_io = data->progress.now;
CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND");
result = CURLE_OK;
goto out;
#ifdef SSL_ERROR_WANT_ASYNC
case SSL_ERROR_WANT_ASYNC:
ctx->q.last_io = now;
ctx->q.last_io = data->progress.now;
CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC");
result = CURLE_OK;
goto out;
@ -2242,7 +2240,7 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
goto out;
}
CURL_TRC_CF(data, cf, "negotiated idle timeout: %" PRIu64 "ms", idle_ms);
idletime = curlx_timediff_ms(curlx_now(), ctx->q.last_io);
idletime = curlx_timediff_ms(data->progress.now, ctx->q.last_io);
if(idle_ms && idletime > 0 && (uint64_t)idletime > idle_ms)
goto out;
}

View file

@ -499,6 +499,7 @@ static void cf_quiche_recv_body(struct Curl_cfilter *cf,
}
static void cf_quiche_process_ev(struct Curl_cfilter *cf,
struct Curl_easy *calling,
struct Curl_easy *data,
struct h3_stream_ctx *stream,
quiche_h3_event *ev)
@ -506,6 +507,7 @@ static void cf_quiche_process_ev(struct Curl_cfilter *cf,
if(!stream)
return;
Curl_pgrs_now_update(data, calling);
switch(quiche_h3_event_type(ev)) {
case QUICHE_H3_EVENT_HEADERS: {
struct cb_ctx cb_ctx;
@ -561,6 +563,7 @@ struct cf_quich_disp_ctx {
uint64_t stream_id;
struct Curl_cfilter *cf;
struct Curl_multi *multi;
struct Curl_easy *calling;
quiche_h3_event *ev;
};
@ -572,7 +575,7 @@ static bool cf_quiche_disp_event(uint32_t mid, void *val, void *user_data)
if(stream->id == dctx->stream_id) {
struct Curl_easy *sdata = Curl_multi_get_easy(dctx->multi, mid);
if(sdata)
cf_quiche_process_ev(dctx->cf, sdata, stream, dctx->ev);
cf_quiche_process_ev(dctx->cf, dctx->calling, sdata, stream, dctx->ev);
return FALSE; /* stop iterating */
}
return TRUE;
@ -599,7 +602,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
stream = H3_STREAM_CTX(ctx, data);
if(stream && stream->id == (uint64_t)rv) {
/* event for calling transfer */
cf_quiche_process_ev(cf, data, stream, ev);
cf_quiche_process_ev(cf, data, data, stream, ev);
quiche_h3_event_free(ev);
if(stream->xfer_result)
return stream->xfer_result;
@ -610,6 +613,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
struct cf_quich_disp_ctx dctx;
dctx.stream_id = (uint64_t)rv;
dctx.cf = cf;
dctx.calling = data;
dctx.multi = data->multi;
dctx.ev = ev;
Curl_uint32_hash_visit(&ctx->streams, cf_quiche_disp_event, &dctx);
@ -865,7 +869,7 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
*pnread = 0;
(void)buf;
(void)blen;
vquic_ctx_update_time(&ctx->q);
vquic_ctx_update_time(data, &ctx->q);
if(!stream)
return CURLE_RECV_ERROR;
@ -1075,7 +1079,7 @@ static CURLcode cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURLcode result;
*pnwritten = 0;
vquic_ctx_update_time(&ctx->q);
vquic_ctx_update_time(data, &ctx->q);
result = cf_process_ingress(cf, data);
if(result)
@ -1233,7 +1237,7 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
DEBUGASSERT(ctx->initialized);
result = vquic_ctx_init(&ctx->q);
result = vquic_ctx_init(data, &ctx->q);
if(result)
return result;
@ -1352,7 +1356,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
vquic_ctx_update_time(&ctx->q);
vquic_ctx_update_time(data, &ctx->q);
if(!ctx->qconn) {
result = cf_quiche_ctx_open(cf, data);
@ -1434,7 +1438,7 @@ static CURLcode cf_quiche_shutdown(struct Curl_cfilter *cf,
int err;
ctx->shutdown_started = TRUE;
vquic_ctx_update_time(&ctx->q);
vquic_ctx_update_time(data, &ctx->q);
err = quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);
if(err) {
CURL_TRC_CF(data, cf, "error %d adding shutdown packet, "

View file

@ -41,6 +41,7 @@
#include "curl_osslq.h"
#include "curl_quiche.h"
#include "../multiif.h"
#include "../progress.h"
#include "../rand.h"
#include "vquic.h"
#include "vquic_int.h"
@ -75,7 +76,8 @@ void Curl_quic_ver(char *p, size_t len)
#endif
}
CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx)
CURLcode vquic_ctx_init(struct Curl_easy *data,
struct cf_quic_ctx *qctx)
{
Curl_bufq_init2(&qctx->sendbuf, NW_CHUNK_SIZE, NW_SEND_CHUNKS,
BUFQ_OPT_SOFT_LIMIT);
@ -94,7 +96,7 @@ CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx)
}
}
#endif
vquic_ctx_update_time(qctx);
vquic_ctx_set_time(data, qctx);
return CURLE_OK;
}
@ -104,9 +106,17 @@ void vquic_ctx_free(struct cf_quic_ctx *qctx)
Curl_bufq_free(&qctx->sendbuf);
}
void vquic_ctx_update_time(struct cf_quic_ctx *qctx)
void vquic_ctx_set_time(struct Curl_easy *data,
struct cf_quic_ctx *qctx)
{
qctx->last_op = curlx_now();
qctx->last_op = data->progress.now;
}
void vquic_ctx_update_time(struct Curl_easy *data,
struct cf_quic_ctx *qctx)
{
Curl_pgrs_now_set(data);
qctx->last_op = data->progress.now;
}
static CURLcode send_packet_no_gso(struct Curl_cfilter *cf,

View file

@ -54,10 +54,15 @@ struct cf_quic_ctx {
#define H3_STREAM_CTX(ctx, data) \
(data ? Curl_uint32_hash_get(&(ctx)->streams, (data)->mid) : NULL)
CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx);
CURLcode vquic_ctx_init(struct Curl_easy *data,
struct cf_quic_ctx *qctx);
void vquic_ctx_free(struct cf_quic_ctx *qctx);
void vquic_ctx_update_time(struct cf_quic_ctx *qctx);
void vquic_ctx_set_time(struct Curl_easy *data,
struct cf_quic_ctx *qctx);
void vquic_ctx_update_time(struct Curl_easy *data,
struct cf_quic_ctx *qctx);
void vquic_push_blocked_pkt(struct Curl_cfilter *cf,
struct cf_quic_ctx *qctx,

View file

@ -2500,7 +2500,7 @@ static CURLcode myssh_block_statemach(struct Curl_easy *data,
if(result)
break;
left_ms = Curl_timeleft_ms(data, NULL, FALSE);
left_ms = Curl_timeleft_ms(data, FALSE);
if(left_ms < 0) {
failf(data, "Operation timed out");
return CURLE_OPERATION_TIMEDOUT;

View file

@ -3121,13 +3121,13 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data,
bool disconnect)
{
CURLcode result = CURLE_OK;
struct curltime dis = curlx_now();
struct curltime start = data->progress.now;
while((sshc->state != SSH_STOP) && !result) {
bool block;
timediff_t left_ms = 1000;
struct curltime now = curlx_now();
Curl_pgrs_now_set(data); /* timeout disconnect */
result = ssh_statemachine(data, sshc, sshp, &block);
if(result)
break;
@ -3137,13 +3137,13 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data,
if(result)
break;
left_ms = Curl_timeleft_ms(data, NULL, FALSE);
left_ms = Curl_timeleft_ms(data, FALSE);
if(left_ms < 0) {
failf(data, "Operation timed out");
return CURLE_OPERATION_TIMEDOUT;
}
}
else if(curlx_timediff_ms(now, dis) > 1000) {
else if(curlx_timediff_ms(data->progress.now, start) > 1000) {
/* disconnect timeout */
failf(data, "Disconnect timed out");
result = CURLE_OK;

View file

@ -411,7 +411,7 @@ CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data,
}
shared->refcount = 1;
shared->time = curlx_now();
shared->time = data->progress.now;
*pcreds = shared;
return CURLE_OK;
}
@ -562,8 +562,7 @@ static bool gtls_shared_creds_expired(const struct Curl_easy *data,
const struct gtls_shared_creds *sc)
{
const struct ssl_general_config *cfg = &data->set.general_ssl;
struct curltime now = curlx_now();
timediff_t elapsed_ms = curlx_timediff_ms(now, sc->time);
timediff_t elapsed_ms = curlx_timediff_ms(data->progress.now, sc->time);
timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms < 0)

View file

@ -3219,8 +3219,7 @@ static bool ossl_cached_x509_store_expired(const struct Curl_easy *data,
if(cfg->ca_cache_timeout < 0)
return FALSE;
else {
struct curltime now = curlx_now();
timediff_t elapsed_ms = curlx_timediff_ms(now, mb->time);
timediff_t elapsed_ms = curlx_timediff_ms(data->progress.now, mb->time);
timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
return elapsed_ms >= timeout_ms;
@ -3305,7 +3304,7 @@ static void ossl_set_cached_x509_store(struct Curl_cfilter *cf,
curlx_free(share->CAfile);
}
share->time = curlx_now();
share->time = data->progress.now;
share->store = store;
share->store_is_empty = is_empty;
share->CAfile = CAfile;

View file

@ -1806,7 +1806,7 @@ schannel_recv_renegotiate(struct Curl_cfilter *cf, struct Curl_easy *data,
remaining = MAX_RENEG_BLOCK_TIME - elapsed;
if(blocking) {
timeout_ms = Curl_timeleft_ms(data, NULL, FALSE);
timeout_ms = Curl_timeleft_ms(data, FALSE);
if(timeout_ms < 0) {
result = CURLE_OPERATION_TIMEDOUT;
@ -1959,7 +1959,7 @@ static CURLcode schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
while(len > *pnwritten) {
size_t this_write = 0;
int what;
timediff_t timeout_ms = Curl_timeleft_ms(data, NULL, FALSE);
timediff_t timeout_ms = Curl_timeleft_ms(data, FALSE);
if(timeout_ms < 0) {
/* we already got the timeout */
failf(data, "schannel: timed out sending data "

View file

@ -1370,8 +1370,10 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
if(!result && *done) {
cf->connected = TRUE;
if(connssl->state == ssl_connection_complete)
connssl->handshake_done = curlx_now();
if(connssl->state == ssl_connection_complete) {
Curl_pgrs_now_set(data);
connssl->handshake_done = data->progress.now;
}
/* Connection can be deferred when sending early data */
DEBUGASSERT(connssl->state == ssl_connection_complete ||
connssl->state == ssl_connection_deferred);
@ -1839,7 +1841,7 @@ static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
*done = FALSE;
while(!result && !*done && loop--) {
timeout_ms = Curl_shutdown_timeleft(cf->conn, cf->sockindex, NULL);
timeout_ms = Curl_shutdown_timeleft(data, cf->conn, cf->sockindex);
if(timeout_ms < 0) {
/* no need to continue if time is already up */
@ -1886,7 +1888,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
if(cf->cft == &Curl_cft_ssl) {
bool done;
CURL_TRC_CF(data, cf, "shutdown and remove SSL, start");
Curl_shutdown_start(data, sockindex, 0, NULL);
Curl_shutdown_start(data, sockindex, 0);
result = vtls_shutdown_blocking(cf, data, send_shutdown, &done);
Curl_shutdown_clear(data, sockindex);
if(!result && !done) /* blocking failed? */

View file

@ -727,8 +727,7 @@ static bool wssl_cached_x509_store_expired(const struct Curl_easy *data,
const struct wssl_x509_share *mb)
{
const struct ssl_general_config *cfg = &data->set.general_ssl;
struct curltime now = curlx_now();
timediff_t elapsed_ms = curlx_timediff_ms(now, mb->time);
timediff_t elapsed_ms = curlx_timediff_ms(data->progress.now, mb->time);
timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms < 0)
@ -811,7 +810,7 @@ static void wssl_set_cached_x509_store(struct Curl_cfilter *cf,
curlx_free(share->CAfile);
}
share->time = curlx_now();
share->time = data->progress.now;
share->store = store;
share->CAfile = CAfile;
}

View file

@ -1696,7 +1696,7 @@ static CURLcode ws_send_raw_blocking(struct Curl_easy *data,
CURL_TRC_WS(data, "ws_send_raw_blocking() partial, %zu left to send",
buflen);
left_ms = Curl_timeleft_ms(data, NULL, FALSE);
left_ms = Curl_timeleft_ms(data, FALSE);
if(left_ms < 0) {
failf(data, "[WS] Timeout waiting for socket becoming writable");
return CURLE_SEND_ERROR;