From 1b701c746f66b8fd5bf3017c36254dbde8456df2 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Thu, 7 Feb 2008 22:25:04 +0000
Subject: - Refactored a lot of timeout code into a few functions in an attempt
 to make   them all use the same (hopefully correct) logic to make it less
 error-prone   and easier to introduce library-wide where it should be used.

---
 lib/connect.c | 138 ++++++++++++++++++++++++++++++++++------------------------
 lib/connect.h |  14 ++++--
 lib/ftp.c     |  39 +++--------------
 lib/gtls.c    |  20 +--------
 lib/qssl.c    |  13 +-----
 lib/socks.c   |  26 +----------
 lib/ssluse.c  |  29 ++----------
 lib/tftp.c    |  17 +++++---
 8 files changed, 116 insertions(+), 180 deletions(-)

(limited to 'lib')

diff --git a/lib/connect.c b/lib/connect.c
index e9f9cf150..393c85603 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -101,6 +101,66 @@ singleipconnect(struct connectdata *conn,
                 long timeout_ms,
                 bool *connected);
 
+/*
+ * Curl_timeleft() returns the amount of milliseconds left allowed for the
+ * transfer/connection. If the value is negative, the timeout time has already
+ * elapsed.
+ *
+ * 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!
+ */
+long Curl_timeleft(struct connectdata *conn,
+                   struct timeval *nowp,
+                   bool duringconnect)
+{
+  struct SessionHandle *data = conn->data;
+  int timeout_set = 0;
+  long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+  struct timeval 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;
+  }
+
+  if(!nowp) {
+    now = Curl_tvnow();
+    nowp = &now;
+  }
+
+  /* substract elapsed time */
+  timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+
+  return timeout_ms;
+}
+
+
 /*
  * Curl_nonblock() set the given socket to either blocking or non-blocking
  * mode based on the 'nonblock' boolean argument. This function is highly
@@ -533,42 +593,33 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   CURLcode code = CURLE_OK;
   curl_socket_t sockfd = conn->sock[sockindex];
   long allow = DEFAULT_CONNECT_TIMEOUT;
-  long allow_total = 0;
-  long has_passed;
 
   DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
 
   *connected = FALSE; /* a very negative world view is best */
 
-  /* Evaluate in milliseconds how much time that has passed */
-  has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-
-  /* subtract the most strict timeout of the ones */
-  if(data->set.timeout && data->set.connecttimeout) {
-    if(data->set.timeout < data->set.connecttimeout)
-      allow_total = allow = data->set.timeout;
-    else
-      allow = data->set.connecttimeout;
-  }
-  else if(data->set.timeout) {
-    allow_total = allow = data->set.timeout;
-  }
-  else if(data->set.connecttimeout) {
-    allow = data->set.connecttimeout;
-  }
-
-  if(has_passed > allow ) {
-    /* time-out, bail out, go home */
-    failf(data, "Connection time-out after %ld ms", has_passed);
-    return CURLE_OPERATION_TIMEDOUT;
-  }
   if(conn->bits.tcpconnect) {
     /* we are connected already! */
+    long allow_total = 0;
+
+    /* subtract the most strict timeout of the ones */
+    if(data->set.timeout)
+      allow_total = data->set.timeout;
+
     Curl_expire(data, allow_total);
     *connected = TRUE;
     return CURLE_OK;
   }
 
+  /* figure out how long time we have left to connect */
+  allow = Curl_timeleft(conn, NULL, TRUE);
+
+  if(allow < 0) {
+    /* time-out, bail out, go home */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
   Curl_expire(data, allow);
 
   /* check for connect without timeout as we want to return immediately */
@@ -821,7 +872,6 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   int num_addr;
   Curl_addrinfo *ai;
   Curl_addrinfo *curr_addr;
-  int timeout_set = 0;
 
   struct timeval after;
   struct timeval before = Curl_tvnow();
@@ -834,39 +884,13 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
 
   *connected = FALSE; /* default to not connected */
 
-  /* if a timeout is set, use the most restrictive one */
-
-  if(data->set.timeout > 0)
-    timeout_set += 1;
-  if(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:
-    timeout_ms = DEFAULT_CONNECT_TIMEOUT;
-    break;
-  }
+  /* get the timeout left */
+  timeout_ms = Curl_timeleft(conn, &before, TRUE);
 
-  if(timeout_set > 0) {
-    /* if a timeout was already set, substract elapsed time */
-    timeout_ms -= Curl_tvdiff(before, data->progress.t_startsingle);
-    if(timeout_ms < 0) {
-      /* a precaution, no need to continue if time already is up */
-      failf(data, "Connection time-out");
-      return CURLE_OPERATION_TIMEDOUT;
-    }
+  if(timeout_ms < 0) {
+    /* a precaution, no need to continue if time already is up */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
   }
   Curl_expire(data, timeout_ms);
 
diff --git a/lib/connect.h b/lib/connect.h
index 3bfe722ea..78c0191ba 100644
--- a/lib/connect.h
+++ b/lib/connect.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2008, 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
@@ -31,14 +31,20 @@ CURLcode Curl_is_connected(struct connectdata *conn,
                            bool *connected);
 
 CURLcode Curl_connecthost(struct connectdata *conn,
-                          const struct Curl_dns_entry *host, /* connect to this */
+                          const struct Curl_dns_entry *host, /* connect to
+                                                                this */
                           curl_socket_t *sockconn, /* not set if error */
                           Curl_addrinfo **addr, /* the one we used */
-                          bool *connected /* truly connected? */
-                          );
+                          bool *connected); /* truly connected? */
 
 CURLcode Curl_store_ip_addr(struct connectdata *conn);
 
+/* generic function that returns how much time there's left to run, according
+   to the timeouts set */
+long Curl_timeleft(struct connectdata *conn,
+                   struct timeval *nowp,
+                   bool duringconnect);
+
 #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
 
 #endif
diff --git a/lib/ftp.c b/lib/ftp.c
index 5fc9669ab..061189c98 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -300,43 +300,14 @@ static bool isBadFtpString(const char *string)
  */
 static CURLcode AllowServerConnect(struct connectdata *conn)
 {
-  long timeout_ms;
   struct SessionHandle *data = conn->data;
   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
-  int timeout_set = 0;
+  long timeout_ms = Curl_timeleft(conn, NULL, TRUE);
 
-  /* if a timeout is set, use the most restrictive one */
-
-  if(data->set.timeout > 0)
-    timeout_set += 1;
-  if(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:
-    timeout_ms = 60000; /* 60 seconds default timeout */
-    break;
-  }
-
-  if(timeout_set > 0) {
-    /* if a timeout was already set, substract elapsed time */
-    timeout_ms -= Curl_tvdiff(Curl_tvnow(), conn->now);
-    if(timeout_ms < 0) {
-      failf(data, "Timed out before server could connect to us");
-      return CURLE_OPERATION_TIMEDOUT;
-    }
+  if(timeout_ms < 0) {
+    /* if a timeout was already reached, bail out */
+    failf(data, "Timed out before server could connect to us");
+    return CURLE_OPERATION_TIMEDOUT;
   }
 
   switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)timeout_ms)) {
diff --git a/lib/gtls.c b/lib/gtls.c
index 49b0fc739..d317d2bb0 100644
--- a/lib/gtls.c
+++ b/lib/gtls.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2008, 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
@@ -154,23 +154,7 @@ static CURLcode handshake(struct connectdata *conn,
     rc = gnutls_handshake(session);
 
     if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
-      long timeout_ms = DEFAULT_CONNECT_TIMEOUT;
-      long has_passed;
-
-      if(duringconnect && data->set.connecttimeout)
-        timeout_ms = data->set.connecttimeout;
-
-      if(data->set.timeout) {
-        /* get the strictest timeout of the ones converted to milliseconds */
-        if(data->set.timeout < timeout_ms)
-          timeout_ms = data->set.timeout;
-      }
-
-      /* Evaluate in milliseconds how much time that has passed */
-      has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-
-      /* subtract the passed time */
-      timeout_ms -= has_passed;
+      long timeout_ms = Curl_connecttimeleft(conn, NULL, duringconnect);
 
       if(timeout_ms < 0) {
         /* a precaution, no need to continue if time already is up */
diff --git a/lib/qssl.c b/lib/qssl.c
index 4ced8b744..e65a0e2f6 100644
--- a/lib/qssl.c
+++ b/lib/qssl.c
@@ -172,17 +172,8 @@ static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
   if(!data->set.ssl.verifyhost)
     h->exitPgm = Curl_qsossl_trap_cert;
 
-  if(data->set.connecttimeout) {
-    timeout_ms = data->set.connecttimeout;
-
-    if(data->set.timeout)
-      if(timeout_ms > data->set.timeout)
-        timeout_ms = data->set.timeout;
-    }
-  else if(data->set.timeout)
-    timeout_ms = data->set.timeout;
-  else
-    timeout_ms = DEFAULT_CONNECT_TIMEOUT;
+  /* figure out how long time we should wait at maximum */
+  timeout_ms = Curl_timeleft(conn, NULL, TRUE);
 
   /* SSL_Handshake() timeout resolution is second, so round up. */
 
diff --git a/lib/socks.c b/lib/socks.c
index dc159ad38..b78a04a45 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -138,18 +138,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
   struct SessionHandle *data = conn->data;
 
   /* get timeout */
-  if(data->set.timeout && data->set.connecttimeout) {
-    if(data->set.timeout < data->set.connecttimeout)
-      timeout = data->set.timeout;
-    else
-      timeout = data->set.connecttimeout;
-  }
-  else if(data->set.timeout)
-    timeout = data->set.timeout;
-  else if(data->set.connecttimeout)
-    timeout = data->set.connecttimeout;
-  else
-    timeout = DEFAULT_CONNECT_TIMEOUT;
+  timeout = Curl_timeleft(conn, NULL, TRUE);
 
   Curl_nonblock(sock, FALSE);
 
@@ -403,18 +392,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
   }
 
   /* get timeout */
-  if(data->set.timeout && data->set.connecttimeout) {
-    if(data->set.timeout < data->set.connecttimeout)
-      timeout = data->set.timeout;
-    else
-      timeout = data->set.connecttimeout;
-  }
-  else if(data->set.timeout)
-    timeout = data->set.timeout;
-  else if(data->set.connecttimeout)
-    timeout = data->set.connecttimeout;
-  else
-    timeout = DEFAULT_CONNECT_TIMEOUT;
+  timeout = Curl_timeleft(conn, NULL, TRUE);
 
   Curl_nonblock(sock, TRUE);
 
diff --git a/lib/ssluse.c b/lib/ssluse.c
index 0083a4153..e8a2e03c9 100644
--- a/lib/ssluse.c
+++ b/lib/ssluse.c
@@ -1448,40 +1448,17 @@ ossl_connect_step2(struct connectdata *conn,
 {
   struct SessionHandle *data = conn->data;
   int err;
-  long has_passed;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
              || ssl_connect_2_reading == connssl->connecting_state
              || ssl_connect_2_writing == connssl->connecting_state);
 
-  /* Find out if any timeout is set. If not, use 300 seconds.
-     Otherwise, figure out the most strict timeout of the two possible one
-     and then how much time that has elapsed to know how much time we
-     allow for the connect call */
-  if(data->set.timeout && data->set.connecttimeout) {
-    /* get the most strict timeout of the ones converted to milliseconds */
-    if(data->set.timeout<data->set.connecttimeout)
-      *timeout_ms = data->set.timeout;
-    else
-      *timeout_ms = data->set.connecttimeout;
-  }
-  else if(data->set.timeout)
-    *timeout_ms = data->set.timeout;
-  else if(data->set.connecttimeout)
-    *timeout_ms = data->set.connecttimeout;
-  else
-    /* no particular time-out has been set */
-    *timeout_ms = DEFAULT_CONNECT_TIMEOUT;
-
-  /* Evaluate in milliseconds how much time that has passed */
-  has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-
-  /* subtract the passed time */
-  *timeout_ms -= has_passed;
+  /* Find out how much more time we're allowed */
+  *timeout_ms = Curl_timeleft(conn, NULL, TRUE);
 
   if(*timeout_ms < 0) {
-    /* a precaution, no need to continue if time already is up */
+    /* no need to continue if time already is up */
     failf(data, "SSL connection timeout");
     return CURLE_OPERATION_TIMEDOUT;
   }
diff --git a/lib/tftp.c b/lib/tftp.c
index 94e5fc3fe..3f7d6442c 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -114,7 +114,7 @@ typedef enum {
   TFTP_ERR_ILLEGAL,
   TFTP_ERR_UNKNOWNID,
   TFTP_ERR_EXISTS,
-  TFTP_ERR_NOSUCHUSER,	/* This will never be triggered by this code */
+  TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
 
   /* The remaining error codes are internal to curl */
   TFTP_ERR_NONE = -100,
@@ -194,12 +194,14 @@ static void tftp_set_timeouts(tftp_state_data_t *state)
 
   struct SessionHandle *data = state->conn->data;
   time_t maxtime, timeout;
+  long timeout_ms;
 
   time(&state->start_time);
+
   if(state->state == TFTP_STATE_START) {
     /* Compute drop-dead time */
-    maxtime = (time_t)(data->set.connecttimeout/1000L?
-                       data->set.connecttimeout/1000L:30);
+    timeout_ms = Curl_timeleft(state->conn, NULL, TRUE);
+    maxtime = (time_t)(timeout_ms + 500) / 1000;
     state->max_time = state->start_time+maxtime;
 
     /* Set per-block timeout to total */
@@ -219,10 +221,13 @@ static void tftp_set_timeouts(tftp_state_data_t *state)
 
   }
   else {
-
     /* Compute drop-dead time */
-    maxtime = (time_t)(data->set.timeout/1000L?
-                       data->set.timeout/1000L:3600);
+    timeout_ms = Curl_timeleft(state->conn, NULL, TRUE);
+    if(timeout_ms > 0)
+      maxtime = (time_t)(timeout_ms + 500) / 1000;
+    else
+      maxtime = 3600;
+
     state->max_time = state->start_time+maxtime;
 
     /* Set per-block timeout to 10% of total */
-- 
cgit v1.2.3