summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2021-03-15 08:11:26 +0100
committerDaniel Stenberg <daniel@haxx.se>2021-03-17 00:28:44 +0100
commite8e7ef3612d28e98b7b072f8d48c2a9f0b4662b5 (patch)
tree7f5ddb3b654eb81a4d5c2da631743b62b44b6355
parent2682e5f502679c7c6949b5e4a07f41e0b9c1510f (diff)
downloadcurl-bagder/timeleft.tar.gz
Curl_timeleft: check both timeouts during connectbagder/timeleft
The duration of a connect and the total transfer are calculated from two different time-stamps. It can end up with the total timeout triggering before the connect timeout expires and we should make sure to acknowledge whichever timeout that is reached first. This is especially notable when a transfer first sits in PENDING, as that time is counted in the total time but the connect timeout is based on the time since the handle changed to the CONNECT state. The CONNECTTIMEOUT is per connect attempt. The TIMEOUT is for the entire operation. Fixes #6744 Closes #6745 Reported-by: Andrei Bica Assisted-by: Jay Satiro
-rw-r--r--lib/connect.c78
1 files changed, 38 insertions, 40 deletions
diff --git a/lib/connect.c b/lib/connect.c
index f9dd415ba..296fb6250 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -171,65 +171,63 @@ singleipconnect(struct Curl_easy *data,
* infinite time left). If the value is negative, the timeout time has already
* elapsed.
*
- * The start time is stored in progress.t_startsingle - as set with
- * Curl_pgrsTime(..., TIMER_STARTSINGLE);
- *
* If 'nowp' is non-NULL, it points to the current time.
* 'duringconnect' is FALSE if not during a connect, as then of course the
* connect timeout is not taken into account!
*
* @unittest: 1303
*/
+
+#define TIMEOUT_CONNECT 1
+#define TIMEOUT_MAXTIME 2
+
timediff_t Curl_timeleft(struct Curl_easy *data,
struct curltime *nowp,
bool duringconnect)
{
- int timeout_set = 0;
- timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+ unsigned int timeout_set = 0;
+ timediff_t connect_timeout_ms = 0;
+ timediff_t maxtime_timeout_ms = 0;
+ timediff_t timeout_ms = 0;
struct curltime now;
- /* if a timeout is set, use the most restrictive one */
-
- if(data->set.timeout > 0)
- timeout_set |= 1;
- if(duringconnect && (data->set.connecttimeout > 0))
- timeout_set |= 2;
-
- switch(timeout_set) {
- case 1:
- timeout_ms = data->set.timeout;
- break;
- case 2:
- timeout_ms = data->set.connecttimeout;
- break;
- case 3:
- if(data->set.timeout < data->set.connecttimeout)
- timeout_ms = data->set.timeout;
- else
- timeout_ms = data->set.connecttimeout;
- break;
- default:
- /* use the default */
- if(!duringconnect)
- /* if we're not during connect, there's no default timeout so if we're
- at zero we better just return zero and not make it a negative number
- by the math below */
- return 0;
- break;
+ /* 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
+ before the connect timeout expires and we must acknowledge whichever
+ timeout that is reached first. The total timeout is set per entire
+ operation, while the connect timeout is set per connect. */
+
+ if(data->set.timeout > 0) {
+ timeout_set = TIMEOUT_MAXTIME;
+ maxtime_timeout_ms = data->set.timeout;
+ }
+ if(duringconnect) {
+ timeout_set |= TIMEOUT_CONNECT;
+ connect_timeout_ms = (data->set.connecttimeout > 0) ?
+ data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
}
+ if(!timeout_set)
+ /* no timeout */
+ return 0;
if(!nowp) {
now = Curl_now();
nowp = &now;
}
- /* subtract elapsed time */
- if(duringconnect)
- /* since this most recent connect started */
- timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
- else
- /* since the entire operation started */
- timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+ if(timeout_set & TIMEOUT_MAXTIME) {
+ maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+ timeout_ms = maxtime_timeout_ms;
+ }
+
+ if(timeout_set & TIMEOUT_CONNECT) {
+ connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
+
+ if(!(timeout_set & TIMEOUT_MAXTIME) ||
+ (connect_timeout_ms < maxtime_timeout_ms))
+ timeout_ms = connect_timeout_ms;
+ }
+
if(!timeout_ms)
/* avoid returning 0 as that means no timeout! */
return -1;