Commit 1b701c74 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

- 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.
parent 15bf1685
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -6,6 +6,11 @@

                                  Changelog

Daniel S (7 Feb 2008)
- 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.

Yang Tse (6 Feb 2008)
- Fix an issue in strdup replacement function when dealing with absolutely
  huge strings. Only systems without a standard strdup would be affected.
+2 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ New curl mirrors:
This release would not have looked like this without help, code, reports and
advice from friends like these:

 Michal Marek, Dmitry Kurochkin, Niklas Angebrand
 Michal Marek, Dmitry Kurochkin, Niklas Angebrand, Günter Knauf, Yang Tse,
 Dan Fandrich

        Thanks! (and sorry if I forgot to mention someone)
+81 −57
Original line number Diff line number Diff line
@@ -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);
  if(conn->bits.tcpconnect) {
    /* we are connected already! */
    long allow_total = 0;

    /* 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(data->set.timeout)
      allow_total = data->set.timeout;

  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! */
    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,40 +884,14 @@ 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;
  /* get the timeout left */
  timeout_ms = Curl_timeleft(conn, &before, TRUE);

  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;
  }

  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;
  }
  }
  Curl_expire(data, timeout_ms);

  /* Max time for each address */
+10 −4
Original line number Diff line number Diff line
@@ -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
+5 −34
Original line number Diff line number Diff line
@@ -300,44 +300,15 @@ 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) {
    /* 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)) {
  case -1: /* error */
Loading