From 3bc0eb8ceff7a7c0331aa90baa12186c3e5e4c4f Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Thu, 15 May 2014 20:43:32 +0200
Subject: [PATCH] timers: fix timer regression involving redirects / reconnects

In commit 0b3750b5c23c25f (released in 7.36.0) we fixed a timeout issue
but instead broke the timings.

To fix this, I introduce a new timestamp to use for the timeouts and
restored the previous timestamp and timestamp position so that the old
timer functionality is restored.

In addition to that, that change also broke connection timeouts for when
more than one connect was used (as it would then count the total time
from the first connect and not for the most recent one). Now
Curl_timeleft() has been modified so that it checks against different
start times depending on which timeout it checks.

Test 1303 is updated accordingly.

Bug: http://curl.haxx.se/mail/lib-2014-05/0147.html
Reported-by: Ryan Braud
---
 lib/connect.c         | 7 ++++++-
 lib/multi.c           | 3 ++-
 lib/progress.c        | 8 ++++++--
 lib/progress.h        | 5 +++--
 lib/urldata.h         | 1 +
 tests/unit/unit1303.c | 4 +++-
 6 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/lib/connect.c b/lib/connect.c
index b35c36c..ca6e346 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -222,11 +222,16 @@ long Curl_timeleft(struct SessionHandle *data,
     now = Curl_tvnow();
     nowp = &now;
   }
 
   /* subtract elapsed time */
-  timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+  if(duringconnect)
+    /* since this most recent connect started */
+    timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+  else
+    /* since the entire operation started */
+    timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop);
   if(!timeout_ms)
     /* avoid returning 0 as that means no timeout! */
     return -1;
 
   return timeout_ms;
diff --git a/lib/multi.c b/lib/multi.c
index c52db96..72fde74 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1024,11 +1024,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       data->result=Curl_pretransfer(data);
 
       if(CURLE_OK == data->result) {
         /* after init, go CONNECT */
         multistate(data, CURLM_STATE_CONNECT);
-        Curl_pgrsTime(data, TIMER_STARTSINGLE);
+        Curl_pgrsTime(data, TIMER_STARTOP);
         result = CURLM_CALL_MULTI_PERFORM;
       }
       break;
 
     case CURLM_STATE_CONNECT_PEND:
@@ -1036,10 +1036,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
          we try again in the CURLM_STATE_CONNECT state. */
       break;
 
     case CURLM_STATE_CONNECT:
       /* Connect. We want to get a connection identifier filled in. */
+      Curl_pgrsTime(data, TIMER_STARTSINGLE);
       data->result = Curl_connect(data, &data->easy_conn,
                                   &async, &protocol_connect);
       if(CURLE_NO_CONNECTION_AVAILABLE == data->result) {
         /* There was no connection available. We will go to the pending
            state and wait for an available connection. */
diff --git a/lib/progress.c b/lib/progress.c
index a242f8b..e6a8d82 100644
--- a/lib/progress.c
+++ b/lib/progress.c
@@ -3,11 +3,11 @@
  *  Project                     ___| | | |  _ \| |
  *                             / __| | | | |_) | |
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
  *
@@ -170,12 +170,16 @@ void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
   switch(timer) {
   default:
   case TIMER_NONE:
     /* mistake filter */
     break;
+  case TIMER_STARTOP:
+    /* This is set at the start of a transfer */
+    data->progress.t_startop = now;
+    break;
   case TIMER_STARTSINGLE:
-    /* This is set at the start of a single fetch */
+    /* This is set at the start of each single fetch */
     data->progress.t_startsingle = now;
     break;
 
   case TIMER_STARTACCEPT:
     data->progress.t_acceptdata = Curl_tvnow();
diff --git a/lib/progress.h b/lib/progress.h
index f97fef9..a1e6f1a 100644
--- a/lib/progress.h
+++ b/lib/progress.h
@@ -5,11 +5,11 @@
  *  Project                     ___| | | |  _ \| |
  *                             / __| | | | |_) | |
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
  *
@@ -25,17 +25,18 @@
 #include "timeval.h"
 
 
 typedef enum {
   TIMER_NONE,
+  TIMER_STARTOP,
+  TIMER_STARTSINGLE,
   TIMER_NAMELOOKUP,
   TIMER_CONNECT,
   TIMER_APPCONNECT,
   TIMER_PRETRANSFER,
   TIMER_STARTTRANSFER,
   TIMER_POSTRANSFER,
-  TIMER_STARTSINGLE,
   TIMER_STARTACCEPT,
   TIMER_REDIRECT,
   TIMER_LAST /* must be last */
 } timerid;
 
diff --git a/lib/urldata.h b/lib/urldata.h
index e62ea19..640cbb1 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1133,10 +1133,11 @@ struct Progress {
   double t_starttransfer;
   double t_redirect;
 
   struct timeval start;
   struct timeval t_startsingle;
+  struct timeval t_startop;
   struct timeval t_acceptdata;
 #define CURR_TIME (5+1) /* 6 entries for 5 seconds */
 
   curl_off_t speeder[ CURR_TIME ];
   struct timeval speeder_time[ CURR_TIME ];
diff --git a/tests/unit/unit1303.c b/tests/unit/unit1303.c
index 2e4f230..b48a625 100644
--- a/tests/unit/unit1303.c
+++ b/tests/unit/unit1303.c
@@ -3,11 +3,11 @@
  *  Project                     ___| | | |  _ \| |
  *                             / __| | | | |_) | |
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * are also available at http://curl.haxx.se/docs/copyright.html.
  *
@@ -129,10 +129,12 @@ const struct timetest run[] = {
 };
 
 /* this is the pretended start time of the transfer */
 data->progress.t_startsingle.tv_sec = BASE;
 data->progress.t_startsingle.tv_usec = 0;
+data->progress.t_startop.tv_sec = BASE;
+data->progress.t_startop.tv_usec = 0;
 
 for(i=0; i < sizeof(run)/sizeof(run[0]); i++) {
   NOW(run[i].now_s, run[i].now_us);
   TIMEOUTS(run[i].timeout_ms, run[i].connecttimeout_ms);
   timeout =  Curl_timeleft(data, &now, run[i].connecting);
-- 
2.0.0.rc2

