]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
Refactored create_conn by breaking it up into many smaller functions
authorDan Fandrich <dan@coneharvesters.com>
Fri, 1 Aug 2008 00:55:43 +0000 (00:55 +0000)
committerDan Fandrich <dan@coneharvesters.com>
Fri, 1 Aug 2008 00:55:43 +0000 (00:55 +0000)
lib/url.c

index abad3ba974f49fa292b1788325fb24911f174d1f..b53cc5053ebb204b79810fe1b4d93db356920c0a 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -2887,6 +2887,9 @@ static bool tld_check_name(struct SessionHandle *data,
 }
 #endif
 
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
 static void fix_hostname(struct SessionHandle *data,
                          struct connectdata *conn, struct hostname *host)
 {
@@ -2926,6 +2929,38 @@ static void fix_hostname(struct SessionHandle *data,
 #endif
 }
 
+/*
+ * Allocate and initialize a new connectdata object.
+ */
+static struct connectdata *allocate_conn(void)
+{
+  struct connectdata *conn;
+
+  conn = (struct connectdata *)calloc(1, sizeof(struct connectdata));
+  if(!conn)
+    return NULL;
+
+  conn->handler = &Curl_handler_dummy;  /* Be sure we have a handler defined
+                                           already from start to avoid NULL
+                                           situations and checks */
+
+  /* and we setup a few fields in case we end up actually using this struct */
+
+  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
+  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+  conn->connectindex = -1;    /* no index */
+
+  /* Default protocol-independent behavior doesn't support persistent
+     connections, so we set this to force-close. Protocols that support
+     this need to set this to FALSE in their "curl_do" functions. */
+  conn->bits.close = TRUE;
+
+  /* Store creation time to help future close decision making */
+  conn->created = Curl_tvnow();
+
+  return conn;
+}
+
 /*
  * Parse URL and fill in the relevant members of the connection struct.
  */
@@ -3128,12 +3163,12 @@ static void llist_dtor(void *user, void *element)
   /* Do nothing */
 }
 
+/*
+ * If we're doing a resumed transfer, we need to setup our stuff
+ * properly.
+ */
 static CURLcode setup_range(struct SessionHandle *data)
 {
-  /*
-   * If we're doing a resumed transfer, we need to setup our stuff
-   * properly.
-   */
   struct UrlState *s = &data->state;
   s->resume_from = data->set.set_resume_from;
   if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
@@ -3326,7 +3361,8 @@ static char *detect_proxy(struct connectdata *conn)
   return proxy;
 }
 
-/* If this is supposed to use a proxy, we need to figure out the proxy
+/*
+ * If this is supposed to use a proxy, we need to figure out the proxy
  * host name, so that we can re-use an existing connection
  * that may exist registered to the same proxy host.
  * proxy will be freed before this function returns.
@@ -3453,7 +3489,9 @@ static CURLcode parse_proxy(struct SessionHandle *data,
   return CURLE_OK;
 }
 
-/* Extract the user and password from the authentication string */
+/*
+ * Extract the user and password from the authentication string
+ */
 static CURLcode parse_proxy_auth(struct SessionHandle *data,
                                  struct connectdata *conn)
 {
@@ -3476,162 +3514,606 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
   return CURLE_OK;
 }
 
-/**
- * create_conn() sets up a new connectdata struct, or re-uses an already
- * existing one, and resolves host name.
+/*
  *
- * if this function returns CURLE_OK and *async is set to TRUE, the resolve
- * response will be coming asynchronously. If *async is FALSE, the name is
- * already resolved.
+ * Parse a user name and password in the URL and strip it out of the host name
  *
- * @param data The sessionhandle pointer
- * @param in_connect is set to the next connection data pointer
- * @param addr is set to the new dns entry for this connection. If this
- *        connection is re-used it will be NULL.
- * @param async is set TRUE/FALSE depending on the nature of this lookup
- * @return CURLcode
- * @see setup_conn()
+ * Inputs: data->set.use_netrc (CURLOPT_NETRC)
+ *         conn->host.name
  *
- * *NOTE* this function assigns the conn->data pointer!
+ * Outputs: (almost :- all currently undefined)
+ *          conn->bits.user_passwd  - non-zero if non-default passwords exist
+ *          user                    - non-zero length if defined
+ *          passwd                  -   ditto
+ *          conn->host.name         - remove user name and password
  */
-
-static CURLcode create_conn(struct SessionHandle *data,
-                                 struct connectdata **in_connect,
-                                 struct Curl_dns_entry **addr,
-                                 bool *async)
+static CURLcode parse_url_userpass(struct SessionHandle *data,
+                                   struct connectdata *conn,
+                                   char *user, char *passwd)
 {
+  /* At this point, we're hoping all the other special cases have
+   * been taken care of, so conn->host.name is at most
+   *    [user[:password]]@]hostname
+   *
+   * We need somewhere to put the embedded details, so do that first.
+   */
 
-  char *tmp;
-  CURLcode result=CURLE_OK;
-  struct connectdata *conn;
-  struct connectdata *conn_temp = NULL;
-  size_t urllen;
-  struct Curl_dns_entry *hostaddr;
-#if defined(HAVE_ALARM) && !defined(USE_ARES)
-  unsigned int prev_alarm=0;
-#endif
-  char endbracket;
-  char user[MAX_CURL_USER_LENGTH];
-  char passwd[MAX_CURL_PASSWORD_LENGTH];
-  int rc;
-  bool reuse;
-  char *proxy = NULL;
-
-#ifndef USE_ARES
-#ifdef SIGALRM
-#ifdef HAVE_SIGACTION
-  struct sigaction keep_sigact;   /* store the old struct here */
-  bool keep_copysig=FALSE;        /* did copy it? */
-#else
-#ifdef HAVE_SIGNAL
-  void (*keep_sigact)(int);       /* store the old handler here */
-#endif /* HAVE_SIGNAL */
-#endif /* HAVE_SIGACTION */
-#endif /* SIGALRM */
-#endif /* USE_ARES */
-
-  *addr = NULL; /* nothing yet */
-  *async = FALSE;
+  user[0] =0;   /* to make everything well-defined */
+  passwd[0]=0;
 
-  /*************************************************************
-   * Check input data
-   *************************************************************/
+  if(conn->protocol & (PROT_FTP|PROT_HTTP|PROT_SCP|PROT_SFTP)) {
+    /* This is a FTP, HTTP, SCP or SFTP URL, we will now try to extract the
+     * possible user+password pair in a string like:
+     * ftp://user:password@ftp.my.site:8021/README */
+    char *ptr=strchr(conn->host.name, '@');
+    char *userpass = conn->host.name;
+    if(ptr != NULL) {
+      /* there's a user+password given here, to the left of the @ */
 
-  if(!data->change.url)
-    return CURLE_URL_MALFORMAT;
+      conn->host.name = ++ptr;
 
-  /* First, split up the current URL in parts so that we can use the
-     parts for checking against the already present connections. In order
-     to not have to modify everything at once, we allocate a temporary
-     connection data struct and fill in for comparison purposes. */
+      /* So the hostname is sane.  Only bother interpreting the
+       * results if we could care.  It could still be wasted
+       * work because it might be overtaken by the programmatically
+       * set user/passwd, but doing that first adds more cases here :-(
+       */
 
-  conn = (struct connectdata *)calloc(1, sizeof(struct connectdata));
-  if(!conn) {
-    *in_connect = NULL; /* clear the pointer */
-    return CURLE_OUT_OF_MEMORY;
-  }
-  /* We must set the return variable as soon as possible, so that our
-     parent can cleanup any possible allocs we may have done before
-     any failure */
-  *in_connect = conn;
+      if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
+        /* We could use the one in the URL */
 
-  conn->handler = &Curl_handler_dummy;  /* Be sure we have a handler defined
-                                           already from start to avoid NULL
-                                           situations and checks */
+        conn->bits.user_passwd = 1; /* enable user+password */
 
-  /* and we setup a few fields in case we end up actually using this struct */
+        if(*userpass != ':') {
+          /* the name is given, get user+password */
+          sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:"
+                 "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
+                 user, passwd);
+        }
+        else
+          /* no name given, get the password only */
+          sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd);
 
-  conn->data = data; /* Setup the association between this connection
-                        and the SessionHandle */
+        if(user[0]) {
+          char *newname=curl_easy_unescape(data, user, 0, NULL);
+          if(!newname)
+            return CURLE_OUT_OF_MEMORY;
+          if(strlen(newname) < MAX_CURL_USER_LENGTH)
+            strcpy(user, newname);
 
-  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
-  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
-  conn->connectindex = -1;    /* no index */
+          /* if the new name is longer than accepted, then just use
+             the unconverted name, it'll be wrong but what the heck */
+          free(newname);
+        }
+        if(passwd[0]) {
+          /* we have a password found in the URL, decode it! */
+          char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL);
+          if(!newpasswd)
+            return CURLE_OUT_OF_MEMORY;
+          if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
+            strcpy(passwd, newpasswd);
 
-  conn->proxytype = data->set.proxytype; /* type */
-  conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
-                            *data->set.str[STRING_PROXY]);
-  conn->bits.httpproxy = (bool)(conn->bits.proxy
-                                && (conn->proxytype == CURLPROXY_HTTP));
+          free(newpasswd);
+        }
+      }
+    }
+  }
+  return CURLE_OK;
+}
 
+/*************************************************************
+ * Figure out the remote port number and fix it in the URL
+ *
+ * No matter if we use a proxy or not, we have to figure out the remote
+ * port number of various reasons.
+ *
+ * To be able to detect port number flawlessly, we must not confuse them
+ * IPv6-specified addresses in the [0::1] style. (RFC2732)
+ *
+ * The conn->host.name is currently [user:passwd@]host[:port] where host
+ * could be a hostname, IPv4 address or IPv6 address.
+ *
+ * The port number embedded in the URL is replaced, if necessary.
+ *************************************************************/
+static CURLcode parse_remote_port(struct SessionHandle *data,
+                                  struct connectdata *conn)
+{
+  char *portptr;
+  char endbracket;
 
-  /* Default protocol-independent behavior doesn't support persistent
-     connections, so we set this to force-close. Protocols that support
-     this need to set this to FALSE in their "curl_do" functions. */
-  conn->bits.close = TRUE;
+  if((1 == sscanf(conn->host.name, "[%*39[0123456789abcdefABCDEF:.%]%c", &endbracket)) &&
+     (']' == endbracket)) {
+    /* this is a RFC2732-style specified IP-address */
+    conn->bits.ipv6_ip = TRUE;
 
-  conn->readchannel_inuse = FALSE;
-  conn->writechannel_inuse = FALSE;
+    conn->host.name++; /* skip over the starting bracket */
+    portptr = strchr(conn->host.name, ']');
+    *portptr++ = 0; /* zero terminate, killing the bracket */
+    if(':' != *portptr)
+      portptr = NULL; /* no port number available */
+  }
+  else
+    portptr = strrchr(conn->host.name, ':');
 
-  conn->read_pos = 0;
-  conn->buf_len = 0;
+  if(data->set.use_port && data->state.allow_port) {
+    /* if set, we use this and ignore the port possibly given in the URL */
+    conn->remote_port = (unsigned short)data->set.use_port;
+    if(portptr)
+      *portptr = '\0'; /* cut off the name there anyway - if there was a port
+                      number - since the port number is to be ignored! */
+    if(conn->bits.httpproxy) {
+      /* we need to create new URL with the new port number */
+      char *url;
+      bool isftp = strequal("ftp", conn->protostr) || 
+                   strequal("ftps", conn->protostr);
 
-  /* Store creation time to help future close decision making */
-  conn->created = Curl_tvnow();
+      /*
+       * This synthesized URL isn't always right--suffixes like ;type=A
+       * are stripped off. It would be better to work directly from the
+       * original URL and simply replace the port part of it.
+       */
+      url = aprintf("%s://%s%s%s:%d%s%s", conn->protostr,
+             conn->bits.ipv6_ip?"[":"", conn->host.name,
+             conn->bits.ipv6_ip?"]":"", conn->remote_port, 
+             isftp?"/":"", data->state.path);
+      if(!url)
+        return CURLE_OUT_OF_MEMORY;
 
-  conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERPWD]);
-  conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERPWD]);
-  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
-  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
-  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
+      if(data->change.url_alloc)
+        free(data->change.url);
 
-  if(data->multi && Curl_multi_canPipeline(data->multi) &&
-      !conn->master_buffer) {
-    /* Allocate master_buffer to be used for pipelining */
-    conn->master_buffer = calloc(BUFSIZE, sizeof (char));
-    if(!conn->master_buffer)
-      return CURLE_OUT_OF_MEMORY;
+      data->change.url = url;
+      data->change.url_alloc = TRUE;
+    }
   }
+  else if(portptr) {
+    /* no CURLOPT_PORT given, extract the one from the URL */
 
-  /* Initialize the pipeline lists */
-  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
-  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
-  conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
-  if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe)
-    return CURLE_OUT_OF_MEMORY;
+    char *rest;
+    unsigned long port;
 
-  /* This initing continues below, see the comment "Continue connectdata
-   * initialization here" */
+    port=strtoul(portptr+1, &rest, 10);  /* Port number must be decimal */
 
-  /***********************************************************
-   * We need to allocate memory to store the path in. We get the size of the
-   * full URL to be sure, and we need to make it at least 256 bytes since
-   * other parts of the code will rely on this fact
-   ***********************************************************/
-#define LEAST_PATH_ALLOC 256
-  urllen=strlen(data->change.url);
-  if(urllen < LEAST_PATH_ALLOC)
-    urllen=LEAST_PATH_ALLOC;
+    if(rest != (portptr+1) && *rest == '\0') {
+      /* The colon really did have only digits after it,
+       * so it is either a port number or a mistake */
 
-  /* Free the old buffer */
-  Curl_safefree(data->state.pathbuffer);
+      if(port > 0xffff) {   /* Single unix standard says port numbers are
+                              * 16 bits long */
+        failf(data, "Port number too large: %lu", port);
+        return CURLE_URL_MALFORMAT;
+      }
 
-  /*
+      *portptr = '\0'; /* cut off the name there */
+      conn->remote_port = (unsigned short)port;
+    }
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Override a user name and password from the URL with that in the
+ * CURLOPT_USERPWD option or a .netrc file, if applicable.
+ */
+static void override_userpass(struct SessionHandle *data,
+                              struct connectdata *conn,
+                              char *user, char *passwd)
+{
+  if(data->set.str[STRING_USERPWD] != NULL) {
+    /* the name is given, get user+password */
+    sscanf(data->set.str[STRING_USERPWD],
+           "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
+           "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
+           user, passwd);
+  }
+
+  conn->bits.netrc = FALSE;
+  if(data->set.use_netrc != CURL_NETRC_IGNORED) {
+    if(Curl_parsenetrc(conn->host.name,
+                       user, passwd,
+                       data->set.str[STRING_NETRC_FILE])) {
+      infof(data, "Couldn't find host %s in the "
+            DOT_CHAR "netrc file; using defaults\n",
+            conn->host.name);
+    }
+    else {
+      /* set bits.netrc TRUE to remember that we got the name from a .netrc
+         file, so that it is safe to use even if we followed a Location: to a
+         different host or similar. */
+      conn->bits.netrc = TRUE;
+
+      conn->bits.user_passwd = 1; /* enable user+password */
+    }
+  }
+}
+
+/*
+ * Set password so it's available in the connection.
+ */
+static CURLcode set_userpass(struct connectdata *conn,
+                             const char *user, const char *passwd)
+{
+  /* If our protocol needs a password and we have none, use the defaults */
+  if( (conn->protocol & PROT_FTP) &&
+       !conn->bits.user_passwd) {
+
+    conn->user = strdup(CURL_DEFAULT_USER);
+    conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
+    /* This is the default password, so DON'T set conn->bits.user_passwd */
+  }
+  else {
+    /* store user + password, zero-length if not set */
+    conn->user = strdup(user);
+    conn->passwd = strdup(passwd);
+  }
+  if(!conn->user || !conn->passwd)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+/*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+static CURLcode resolve_server(struct SessionHandle *data,
+                               struct connectdata *conn,
+                               struct Curl_dns_entry **addr,
+                               bool *async)
+{
+  CURLcode result=CURLE_OK;
+#ifndef USE_ARES
+#ifdef SIGALRM
+#ifdef HAVE_SIGACTION
+  struct sigaction keep_sigact;   /* store the old struct here */
+  bool keep_copysig=FALSE;        /* did copy it? */
+#else
+#ifdef HAVE_SIGNAL
+  void (*keep_sigact)(int);       /* store the old handler here */
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+#endif /* SIGALRM */
+#endif /* USE_ARES */
+
+#if defined(HAVE_ALARM) && !defined(USE_ARES)
+  unsigned int prev_alarm=0;
+#endif
+
+#ifndef USE_ARES
+  /*************************************************************
+   * Set timeout if that is being used, and we're not using an asynchronous
+   * name resolve.
+   *************************************************************/
+  if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
+    /*************************************************************
+     * Set signal handler to catch SIGALRM
+     * Store the old value to be able to set it back later!
+     *************************************************************/
+
+#ifdef SIGALRM
+#ifdef HAVE_ALARM
+    long shortest;
+#endif
+#ifdef HAVE_SIGACTION
+    struct sigaction sigact;
+    sigaction(SIGALRM, NULL, &sigact);
+    keep_sigact = sigact;
+    keep_copysig = TRUE; /* yes, we have a copy */
+    sigact.sa_handler = alarmfunc;
+#ifdef SA_RESTART
+    /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+    sigact.sa_flags &= ~SA_RESTART;
+#endif
+    /* now set the new struct */
+    sigaction(SIGALRM, &sigact, NULL);
+#else /* HAVE_SIGACTION */
+    /* no sigaction(), revert to the much lamer signal() */
+#ifdef HAVE_SIGNAL
+    keep_sigact = signal(SIGALRM, alarmfunc);
+#endif
+#endif /* HAVE_SIGACTION */
+
+    /* We set the timeout on the name resolving phase first, separately from
+     * the download/upload part to allow a maximum time on everything. This is
+     * a signal-based timeout, why it won't work and shouldn't be used in
+     * multi-threaded environments. */
+
+#ifdef HAVE_ALARM
+    shortest = data->set.timeout; /* default to this timeout value */
+    if(shortest && data->set.connecttimeout &&
+       (data->set.connecttimeout < shortest))
+      /* if both are set, pick the shortest */
+      shortest = data->set.connecttimeout;
+    else if(!shortest)
+      /* if timeout is not set, use the connect timeout */
+      shortest = data->set.connecttimeout;
+
+    if(shortest < 1000)
+      /* the alarm() function only provide integer second resolution, so if
+         we want to wait less than one second we must bail out already now. */
+      return CURLE_OPERATION_TIMEDOUT;
+
+    /* alarm() makes a signal get sent when the timeout fires off, and that
+       will abort system calls */
+    prev_alarm = alarm((unsigned int) (shortest ? shortest/1000L : shortest));
+    /* We can expect the conn->created time to be "now", as that was just
+       recently set in the beginning of this function and nothing slow
+       has been done since then until now. */
+#endif
+#endif /* SIGALRM */
+  }
+#endif /* USE_ARES */
+
+  /*************************************************************
+   * Resolve the name of the server or proxy
+   *************************************************************/
+  if(conn->bits.reuse) {
+    /* re-used connection, no resolving is necessary */
+    *addr = NULL;
+    /* we'll need to clear conn->dns_entry later in Curl_disconnect() */
+
+    if(conn->bits.proxy)
+      fix_hostname(data, conn, &conn->host);
+  }
+  else {
+    /* this is a fresh connect */
+    int rc;
+    struct Curl_dns_entry *hostaddr;
+
+    /* set a pointer to the hostname we display */
+    fix_hostname(data, conn, &conn->host);
+
+    if(!conn->proxy.name || !*conn->proxy.name) {
+      /* If not connecting via a proxy, extract the port from the URL, if it is
+       * there, thus overriding any defaults that might have been set above. */
+      conn->port =  conn->remote_port; /* it is the same port */
+
+      /* Resolve target host right on */
+      rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr);
+      if(rc == CURLRESOLV_PENDING)
+        *async = TRUE;
+
+      else if(!hostaddr) {
+        failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
+        result =  CURLE_COULDNT_RESOLVE_HOST;
+        /* don't return yet, we need to clean up the timeout first */
+      }
+    }
+    else {
+      /* This is a proxy that hasn't been resolved yet. */
+
+      /* IDN-fix the proxy name */
+      fix_hostname(data, conn, &conn->proxy);
+
+      /* resolve proxy */
+      rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr);
+
+      if(rc == CURLRESOLV_PENDING)
+        *async = TRUE;
+
+      else if(!hostaddr) {
+        failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
+        result = CURLE_COULDNT_RESOLVE_PROXY;
+        /* don't return yet, we need to clean up the timeout first */
+      }
+    }
+    *addr = hostaddr;
+  }
+
+#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES)
+  if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
+#ifdef HAVE_SIGACTION
+    if(keep_copysig) {
+      /* we got a struct as it looked before, now put that one back nice
+         and clean */
+      sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
+    }
+#else
+#ifdef HAVE_SIGNAL
+    /* restore the previous SIGALRM handler */
+    signal(SIGALRM, keep_sigact);
+#endif
+#endif /* HAVE_SIGACTION */
+
+    /* switch back the alarm() to either zero or to what it was before minus
+       the time we spent until now! */
+    if(prev_alarm) {
+      /* there was an alarm() set before us, now put it back */
+      unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
+      unsigned long alarm_set;
+
+      /* the alarm period is counted in even number of seconds */
+      alarm_set = prev_alarm - elapsed_ms/1000;
+
+      if(!alarm_set ||
+         ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
+        /* if the alarm time-left reached zero or turned "negative" (counted
+           with unsigned values), we should fire off a SIGALRM here, but we
+           won't, and zero would be to switch it off so we never set it to
+           less than 1! */
+        alarm(1);
+        result = CURLE_OPERATION_TIMEDOUT;
+        failf(data, "Previous alarm fired off!");
+      }
+      else
+        alarm((unsigned int)alarm_set);
+    }
+    else
+      alarm(0); /* just shut it off */
+  }
+#endif
+  return result;
+}
+
+/*
+ * Cleanup the connection just allocated before we can move along and use the
+ * previously existing one.  All relevant data is copied over and old_conn is
+ * ready for freeing once this function returns.
+ */
+static void reuse_conn(struct connectdata *old_conn,
+                       struct connectdata *conn)
+{
+  if(old_conn->proxy.rawalloc)
+    free(old_conn->proxy.rawalloc);
+
+  /* free the SSL config struct from this connection struct as this was
+     allocated in vain and is targeted for destruction */
+  Curl_free_ssl_config(&old_conn->ssl_config);
+
+  conn->data = old_conn->data;
+
+  /* get the user+password information from the old_conn struct since it may
+   * be new for this request even when we re-use an existing connection */
+  conn->bits.user_passwd = old_conn->bits.user_passwd;
+  if(conn->bits.user_passwd) {
+    /* use the new user name and password though */
+    Curl_safefree(conn->user);
+    Curl_safefree(conn->passwd);
+    conn->user = old_conn->user;
+    conn->passwd = old_conn->passwd;
+    old_conn->user = NULL;
+    old_conn->passwd = NULL;
+  }
+
+  conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
+  if(conn->bits.proxy_user_passwd) {
+    /* use the new proxy user name and proxy password though */
+    Curl_safefree(conn->proxyuser);
+    Curl_safefree(conn->proxypasswd);
+    conn->proxyuser = old_conn->proxyuser;
+    conn->proxypasswd = old_conn->proxypasswd;
+    old_conn->proxyuser = NULL;
+    old_conn->proxypasswd = NULL;
+  }
+
+  /* host can change, when doing keepalive with a proxy ! */
+  if(conn->bits.proxy) {
+    free(conn->host.rawalloc);
+    conn->host=old_conn->host;
+  }
+  else
+    free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
+
+  /* re-use init */
+  conn->bits.reuse = TRUE; /* yes, we're re-using here */
+
+  Curl_safefree(old_conn->user);
+  Curl_safefree(old_conn->passwd);
+  Curl_safefree(old_conn->proxyuser);
+  Curl_safefree(old_conn->proxypasswd);
+  Curl_llist_destroy(old_conn->send_pipe, NULL);
+  Curl_llist_destroy(old_conn->recv_pipe, NULL);
+  Curl_llist_destroy(old_conn->pend_pipe, NULL);
+  Curl_safefree(old_conn->master_buffer);
+}
+
+/**
+ * create_conn() sets up a new connectdata struct, or re-uses an already
+ * existing one, and resolves host name.
+ *
+ * if this function returns CURLE_OK and *async is set to TRUE, the resolve
+ * response will be coming asynchronously. If *async is FALSE, the name is
+ * already resolved.
+ *
+ * @param data The sessionhandle pointer
+ * @param in_connect is set to the next connection data pointer
+ * @param addr is set to the new dns entry for this connection. If this
+ *        connection is re-used it will be NULL.
+ * @param async is set TRUE/FALSE depending on the nature of this lookup
+ * @return CURLcode
+ * @see setup_conn()
+ *
+ * *NOTE* this function assigns the conn->data pointer!
+ */
+
+static CURLcode create_conn(struct SessionHandle *data,
+                            struct connectdata **in_connect,
+                            struct Curl_dns_entry **addr,
+                            bool *async)
+{
+  CURLcode result=CURLE_OK;
+  struct connectdata *conn;
+  struct connectdata *conn_temp = NULL;
+  size_t urllen;
+  char user[MAX_CURL_USER_LENGTH];
+  char passwd[MAX_CURL_PASSWORD_LENGTH];
+  bool reuse;
+  char *proxy = NULL;
+
+  *addr = NULL; /* nothing yet */
+  *async = FALSE;
+
+  /*************************************************************
+   * Check input data
+   *************************************************************/
+
+  if(!data->change.url)
+    return CURLE_URL_MALFORMAT;
+
+  /* First, split up the current URL in parts so that we can use the
+     parts for checking against the already present connections. In order
+     to not have to modify everything at once, we allocate a temporary
+     connection data struct and fill in for comparison purposes. */
+
+  conn = allocate_conn();
+
+  /* We must set the return variable as soon as possible, so that our
+     parent can cleanup any possible allocs we may have done before
+     any failure */
+  *in_connect = conn;
+
+  if(!conn)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->data = data; /* Setup the association between this connection
+                        and the SessionHandle */
+
+  conn->proxytype = data->set.proxytype; /* type */
+  conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
+                            *data->set.str[STRING_PROXY]);
+  conn->bits.httpproxy = (bool)(conn->bits.proxy
+                                && (conn->proxytype == CURLPROXY_HTTP));
+
+
+  conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERPWD]);
+  conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERPWD]);
+  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
+  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
+  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
+
+  if(data->multi && Curl_multi_canPipeline(data->multi) &&
+      !conn->master_buffer) {
+    /* Allocate master_buffer to be used for pipelining */
+    conn->master_buffer = calloc(BUFSIZE, sizeof (char));
+    if(!conn->master_buffer)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Initialize the pipeline lists */
+  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* This initing continues below, see the comment "Continue connectdata
+   * initialization here" */
+
+  /***********************************************************
+   * We need to allocate memory to store the path in. We get the size of the
+   * full URL to be sure, and we need to make it at least 256 bytes since
+   * other parts of the code will rely on this fact
+   ***********************************************************/
+#define LEAST_PATH_ALLOC 256
+  urllen=strlen(data->change.url);
+  if(urllen < LEAST_PATH_ALLOC)
+    urllen=LEAST_PATH_ALLOC;
+
+  /*
    * We malloc() the buffers below urllen+2 to make room for to possibilities:
    * 1 - an extra terminating zero
    * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
    */
 
+  Curl_safefree(data->state.pathbuffer);
   data->state.pathbuffer=(char *)malloc(urllen+2);
   if(NULL == data->state.pathbuffer)
     return CURLE_OUT_OF_MEMORY; /* really bad error */
@@ -3650,7 +4132,7 @@ static CURLcode create_conn(struct SessionHandle *data,
   }
 
   /*************************************************************
-   * Take care of proxy authentication stuff
+   * Extract the user and password from the authentication string
    *************************************************************/
   if(conn->bits.proxy_user_passwd) {
     result = parse_proxy_auth(data, conn);
@@ -3722,7 +4204,6 @@ static CURLcode create_conn(struct SessionHandle *data,
       return result;
   }
 
-
   /***********************************************************************
    * file: is a special case in that it doesn't need a network connection
    ***********************************************************************/
@@ -3734,254 +4215,63 @@ static CURLcode create_conn(struct SessionHandle *data,
     DEBUGASSERT(conn->handler->connect_it);
     result = conn->handler->connect_it(conn, &done);
 
-    /* Setup a "faked" transfer that'll do nothing */
-    if(CURLE_OK == result) {
-      conn->data = data;
-      conn->bits.tcpconnect = TRUE; /* we are "connected */
-
-      ConnectionStore(data, conn);
-
-      result = setup_range(data);
-      if(result) {
-        DEBUGASSERT(conn->handler->done);
-        /* we ignore the return code for the protocol-specific DONE */
-        (void)conn->handler->done(conn, result, FALSE);
-        return result;
-      }
-
-      result = Curl_setup_transfer(conn, -1, -1, FALSE,
-                                   NULL, /* no download */
-                                   -1, NULL); /* no upload */
-    }
-
-    return result;
-  }
-#endif
-
-  /*************************************************************
-   * If the protocol is using SSL and HTTP proxy is used, we set
-   * the tunnel_proxy bit.
-   *************************************************************/
-  if((conn->protocol&PROT_SSL) && conn->bits.httpproxy)
-    conn->bits.tunnel_proxy = TRUE;
-
-  /*************************************************************
-   * Take care of user and password authentication stuff
-   *************************************************************/
-
-  /*
-   * Inputs: data->set.userpwd   (CURLOPT_USERPWD)
-   *         data->set.fpasswd   (CURLOPT_PASSWDFUNCTION)
-   *         data->set.use_netrc (CURLOPT_NETRC)
-   *         conn->host.name
-   *         netrc file
-   *         hard-coded defaults
-   *
-   * Outputs: (almost :- all currently undefined)
-   *          conn->bits.user_passwd  - non-zero if non-default passwords exist
-   *          conn->user              - non-zero length if defined
-   *          conn->passwd            -   ditto
-   *          conn->host.name          - remove user name and password
-   */
-
-  /* At this point, we're hoping all the other special cases have
-   * been taken care of, so conn->host.name is at most
-   *    [user[:password]]@]hostname
-   *
-   * We need somewhere to put the embedded details, so do that first.
-   */
-
-  user[0] =0;   /* to make everything well-defined */
-  passwd[0]=0;
-
-  if(conn->protocol & (PROT_FTP|PROT_HTTP|PROT_SCP|PROT_SFTP)) {
-    /* This is a FTP, HTTP, SCP or SFTP URL, we will now try to extract the
-     * possible user+password pair in a string like:
-     * ftp://user:password@ftp.my.site:8021/README */
-    char *ptr=strchr(conn->host.name, '@');
-    char *userpass = conn->host.name;
-    if(ptr != NULL) {
-      /* there's a user+password given here, to the left of the @ */
-
-      conn->host.name = ++ptr;
-
-      /* So the hostname is sane.  Only bother interpreting the
-       * results if we could care.  It could still be wasted
-       * work because it might be overtaken by the programmatically
-       * set user/passwd, but doing that first adds more cases here :-(
-       */
-
-      if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
-        /* We could use the one in the URL */
-
-        conn->bits.user_passwd = 1; /* enable user+password */
-
-        if(*userpass != ':') {
-          /* the name is given, get user+password */
-          sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:"
-                 "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
-                 user, passwd);
-        }
-        else
-          /* no name given, get the password only */
-          sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd);
-
-        if(user[0]) {
-          char *newname=curl_easy_unescape(data, user, 0, NULL);
-          if(!newname)
-            return CURLE_OUT_OF_MEMORY;
-          if(strlen(newname) < sizeof(user))
-            strcpy(user, newname);
-
-          /* if the new name is longer than accepted, then just use
-             the unconverted name, it'll be wrong but what the heck */
-          free(newname);
-        }
-        if(passwd[0]) {
-          /* we have a password found in the URL, decode it! */
-          char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL);
-          if(!newpasswd)
-            return CURLE_OUT_OF_MEMORY;
-          if(strlen(newpasswd) < sizeof(passwd))
-            strcpy(passwd, newpasswd);
-
-          free(newpasswd);
-        }
-      }
-    }
-  }
-
-  /*************************************************************
-   * Figure out the remote port number
-   *
-   * No matter if we use a proxy or not, we have to figure out the remote
-   * port number of various reasons.
-   *
-   * To be able to detect port number flawlessly, we must not confuse them
-   * IPv6-specified addresses in the [0::1] style. (RFC2732)
-   *
-   * The conn->host.name is currently [user:passwd@]host[:port] where host
-   * could be a hostname, IPv4 address or IPv6 address.
-   *************************************************************/
-  if((1 == sscanf(conn->host.name, "[%*39[0123456789abcdefABCDEF:.%]%c", &endbracket)) &&
-     (']' == endbracket)) {
-    /* this is a RFC2732-style specified IP-address */
-    conn->bits.ipv6_ip = TRUE;
-
-    conn->host.name++; /* skip over the starting bracket */
-    tmp = strchr(conn->host.name, ']');
-    *tmp++ = 0; /* zero terminate, killing the bracket */
-    if(':' != *tmp)
-      tmp = NULL; /* no port number available */
-  }
-  else
-    tmp = strrchr(conn->host.name, ':');
-
-  if(data->set.use_port && data->state.allow_port) {
-    /* if set, we use this and ignore the port possibly given in the URL */
-    conn->remote_port = (unsigned short)data->set.use_port;
-    if(tmp)
-      *tmp = '\0'; /* cut off the name there anyway - if there was a port
-                      number - since the port number is to be ignored! */
-    if(conn->bits.httpproxy) {
-      /* we need to create new URL with the new port number */
-      char *url;
-      bool isftp = strequal("ftp", conn->protostr) || 
-                   strequal("ftps", conn->protostr);
-
-      /*
-       * This synthesized URL isn't always right--suffixes like ;type=A
-       * are stripped off. It would be better to work directly from the
-       * original URL and simply replace the port part of it.
-       */
-      url = aprintf("%s://%s%s%s:%d%s%s", conn->protostr,
-             conn->bits.ipv6_ip?"[":"", conn->host.name,
-             conn->bits.ipv6_ip?"]":"", conn->remote_port, 
-             isftp?"/":"", data->state.path);
-      if(!url)
-        return CURLE_OUT_OF_MEMORY;
-
-      if(data->change.url_alloc)
-        free(data->change.url);
-
-      data->change.url = url;
-      data->change.url_alloc = TRUE;
-    }
-  }
-  else if(tmp) {
-    /* no CURLOPT_PORT given, extract the one from the URL */
-
-    char *rest;
-    unsigned long port;
-
-    port=strtoul(tmp+1, &rest, 10);  /* Port number must be decimal */
+    /* Setup a "faked" transfer that'll do nothing */
+    if(CURLE_OK == result) {
+      conn->data = data;
+      conn->bits.tcpconnect = TRUE; /* we are "connected */
 
-    if(rest != (tmp+1) && *rest == '\0') {
-      /* The colon really did have only digits after it,
-       * so it is either a port number or a mistake */
+      ConnectionStore(data, conn);
 
-      if(port > 0xffff) {   /* Single unix standard says port numbers are
-                              * 16 bits long */
-        failf(data, "Port number too large: %lu", port);
-        return CURLE_URL_MALFORMAT;
+      /*
+       * Setup whatever necessary for a resumed transfer
+       */
+      result = setup_range(data);
+      if(result) {
+        DEBUGASSERT(conn->handler->done);
+        /* we ignore the return code for the protocol-specific DONE */
+        (void)conn->handler->done(conn, result, FALSE);
+        return result;
       }
 
-      *tmp = '\0'; /* cut off the name there */
-      conn->remote_port = (unsigned short)port;
+      result = Curl_setup_transfer(conn, -1, -1, FALSE,
+                                   NULL, /* no download */
+                                   -1, NULL); /* no upload */
     }
-  }
 
-  /* Programmatically set password:
-   *   - always applies, if available
-   *   - takes precedence over the values we just set above
-   * so scribble it over the top.
-   * User-supplied passwords are assumed not to need unescaping.
-   *
-   * user_password is set in "inherit initial knowledge' above,
-   * so it doesn't have to be set in this block
-   */
-  if(data->set.str[STRING_USERPWD] != NULL) {
-    /* the name is given, get user+password */
-    sscanf(data->set.str[STRING_USERPWD],
-           "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
-           "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
-           user, passwd);
+    return result;
   }
+#endif
 
-  conn->bits.netrc = FALSE;
-  if(data->set.use_netrc != CURL_NETRC_IGNORED) {
-    if(Curl_parsenetrc(conn->host.name,
-                       user, passwd,
-                       data->set.str[STRING_NETRC_FILE])) {
-      infof(data, "Couldn't find host %s in the " DOT_CHAR
-            "netrc file, using defaults\n",
-            conn->host.name);
-    }
-    else {
-      /* set bits.netrc TRUE to remember that we got the name from a .netrc
-         file, so that it is safe to use even if we followed a Location: to a
-         different host or similar. */
-      conn->bits.netrc = TRUE;
+  /*************************************************************
+   * If the protocol is using SSL and HTTP proxy is used, we set
+   * the tunnel_proxy bit.
+   *************************************************************/
+  if((conn->protocol&PROT_SSL) && conn->bits.httpproxy)
+    conn->bits.tunnel_proxy = TRUE;
 
-      conn->bits.user_passwd = 1; /* enable user+password */
-    }
-  }
+  /*************************************************************
+   * Parse a user name and password in the URL and strip it out
+   * of the host name
+   *************************************************************/
+  result = parse_url_userpass(data, conn, user, passwd);
+  if(result != CURLE_OK)
+    return result;
 
-  /* If our protocol needs a password and we have none, use the defaults */
-  if( (conn->protocol & PROT_FTP) &&
-       !conn->bits.user_passwd) {
+  /*************************************************************
+   * Figure out the remote port number and fix it in the URL
+   *************************************************************/
+  result = parse_remote_port(data, conn);
+  if(result != CURLE_OK)
+    return result;
 
-    conn->user = strdup(CURL_DEFAULT_USER);
-    conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
-    /* This is the default password, so DON'T set conn->bits.user_passwd */
-  }
-  else {
-    /* store user + password, zero-length if not set */
-    conn->user = strdup(user);
-    conn->passwd = strdup(passwd);
-  }
-  if(!conn->user || !conn->passwd)
-    return CURLE_OUT_OF_MEMORY;
+  /*************************************************************
+   * Check for an overridden user name and password, then set it
+   * for use
+   *************************************************************/
+  override_userpass(data, conn, user, passwd);
+  result = set_userpass(conn, user, passwd);
+  if(result != CURLE_OK)
+    return result;
 
   /*************************************************************
    * Check the current list of connections to see if we can
@@ -4025,67 +4315,10 @@ static CURLcode create_conn(struct SessionHandle *data,
      * just allocated before we can move along and use the previously
      * existing one.
      */
-    struct connectdata *old_conn = conn;
-
-    if(old_conn->proxy.rawalloc)
-      free(old_conn->proxy.rawalloc);
-
-    /* free the SSL config struct from this connection struct as this was
-       allocated in vain and is targeted for destruction */
-    Curl_free_ssl_config(&conn->ssl_config);
-
-    conn = conn_temp;        /* use this connection from now on */
-
-    conn->data = old_conn->data;
-
-    /* get the user+password information from the old_conn struct since it may
-     * be new for this request even when we re-use an existing connection */
-    conn->bits.user_passwd = old_conn->bits.user_passwd;
-    if(conn->bits.user_passwd) {
-      /* use the new user namd and password though */
-      Curl_safefree(conn->user);
-      Curl_safefree(conn->passwd);
-      conn->user = old_conn->user;
-      conn->passwd = old_conn->passwd;
-      old_conn->user = NULL;
-      old_conn->passwd = NULL;
-    }
-
-    conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
-    if(conn->bits.proxy_user_passwd) {
-      /* use the new proxy user name and proxy password though */
-      Curl_safefree(conn->proxyuser);
-      Curl_safefree(conn->proxypasswd);
-      conn->proxyuser = old_conn->proxyuser;
-      conn->proxypasswd = old_conn->proxypasswd;
-      old_conn->proxyuser = NULL;
-      old_conn->proxypasswd = NULL;
-    }
-
-    /* host can change, when doing keepalive with a proxy ! */
-    if(conn->bits.proxy) {
-      free(conn->host.rawalloc);
-      conn->host=old_conn->host;
-    }
-    else
-      free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
-
-    /* re-use init */
-    conn->bits.reuse = TRUE; /* yes, we're re-using here */
-
-    Curl_safefree(old_conn->user);
-    Curl_safefree(old_conn->passwd);
-    Curl_safefree(old_conn->proxyuser);
-    Curl_safefree(old_conn->proxypasswd);
-    Curl_llist_destroy(old_conn->send_pipe, NULL);
-    Curl_llist_destroy(old_conn->recv_pipe, NULL);
-    Curl_llist_destroy(old_conn->pend_pipe, NULL);
-    Curl_safefree(old_conn->master_buffer);
-
-    free(old_conn);          /* we don't need this anymore */
-
-    *in_connect = conn;      /* return this instead! */
-
+    reuse_conn(conn, conn_temp);
+    free(conn);          /* we don't need this anymore */
+    conn = conn_temp;
+    *in_connect = conn;
     infof(data, "Re-using existing connection! (#%ld) with host %s\n",
           conn->connectindex,
           conn->proxy.name?conn->proxy.dispname:conn->host.dispname);
@@ -4098,6 +4331,9 @@ static CURLcode create_conn(struct SessionHandle *data,
     ConnectionStore(data, conn);
   }
 
+  /*
+   * Setup whatever necessary for a resumed transfer
+   */
   result = setup_range(data);
   if(result)
     return result;
@@ -4105,175 +4341,18 @@ static CURLcode create_conn(struct SessionHandle *data,
   /* Continue connectdata initialization here. */
 
   /*
-   *
    * Inherit the proper values from the urldata struct AFTER we have arranged
-   * the persistent connection stuff */
+   * the persistent connection stuff
+   */
   conn->fread_func = data->set.fread_func;
   conn->fread_in = data->set.in;
   conn->seek_func = data->set.seek_func;
   conn->seek_client = data->set.seek_client;
 
-#ifndef USE_ARES
-  /*************************************************************
-   * Set timeout if that is being used, and we're not using an asynchronous
-   * name resolve.
-   *************************************************************/
-  if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
-    /*************************************************************
-     * Set signal handler to catch SIGALRM
-     * Store the old value to be able to set it back later!
-     *************************************************************/
-
-#ifdef SIGALRM
-#ifdef HAVE_ALARM
-    long shortest;
-#endif
-#ifdef HAVE_SIGACTION
-    struct sigaction sigact;
-    sigaction(SIGALRM, NULL, &sigact);
-    keep_sigact = sigact;
-    keep_copysig = TRUE; /* yes, we have a copy */
-    sigact.sa_handler = alarmfunc;
-#ifdef SA_RESTART
-    /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
-    sigact.sa_flags &= ~SA_RESTART;
-#endif
-    /* now set the new struct */
-    sigaction(SIGALRM, &sigact, NULL);
-#else /* HAVE_SIGACTION */
-    /* no sigaction(), revert to the much lamer signal() */
-#ifdef HAVE_SIGNAL
-    keep_sigact = signal(SIGALRM, alarmfunc);
-#endif
-#endif /* HAVE_SIGACTION */
-
-    /* We set the timeout on the name resolving phase first, separately from
-     * the download/upload part to allow a maximum time on everything. This is
-     * a signal-based timeout, why it won't work and shouldn't be used in
-     * multi-threaded environments. */
-
-#ifdef HAVE_ALARM
-    shortest = data->set.timeout; /* default to this timeout value */
-    if(shortest && data->set.connecttimeout &&
-       (data->set.connecttimeout < shortest))
-      /* if both are set, pick the shortest */
-      shortest = data->set.connecttimeout;
-    else if(!shortest)
-      /* if timeout is not set, use the connect timeout */
-      shortest = data->set.connecttimeout;
-
-    if(shortest < 1000)
-      /* the alarm() function only provide integer second resolution, so if
-         we want to wait less than one second we must bail out already now. */
-      return CURLE_OPERATION_TIMEDOUT;
-
-    /* alarm() makes a signal get sent when the timeout fires off, and that
-       will abort system calls */
-    prev_alarm = alarm((unsigned int) (shortest ? shortest/1000L : shortest));
-    /* We can expect the conn->created time to be "now", as that was just
-       recently set in the beginning of this function and nothing slow
-       has been done since then until now. */
-#endif
-#endif /* SIGALRM */
-  }
-#endif /* USE_ARES */
-
   /*************************************************************
-   * Resolve the name of the server or proxy
+   * Resolve the address of the server or proxy
    *************************************************************/
-  if(conn->bits.reuse) {
-    /* re-used connection, no resolving is necessary */
-    hostaddr = NULL;
-    /* we'll need to clear conn->dns_entry later in Curl_disconnect() */
-
-    if(conn->bits.proxy)
-      fix_hostname(data, conn, &conn->host);
-  }
-  else {
-    /* this is a fresh connect */
-
-    /* set a pointer to the hostname we display */
-    fix_hostname(data, conn, &conn->host);
-
-    if(!conn->proxy.name || !*conn->proxy.name) {
-      /* If not connecting via a proxy, extract the port from the URL, if it is
-       * there, thus overriding any defaults that might have been set above. */
-      conn->port =  conn->remote_port; /* it is the same port */
-
-      /* Resolve target host right on */
-      rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr);
-      if(rc == CURLRESOLV_PENDING)
-        *async = TRUE;
-
-      else if(!hostaddr) {
-        failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
-        result =  CURLE_COULDNT_RESOLVE_HOST;
-        /* don't return yet, we need to clean up the timeout first */
-      }
-    }
-    else {
-      /* This is a proxy that hasn't been resolved yet. */
-
-      /* IDN-fix the proxy name */
-      fix_hostname(data, conn, &conn->proxy);
-
-      /* resolve proxy */
-      rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr);
-
-      if(rc == CURLRESOLV_PENDING)
-        *async = TRUE;
-
-      else if(!hostaddr) {
-        failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
-        result = CURLE_COULDNT_RESOLVE_PROXY;
-        /* don't return yet, we need to clean up the timeout first */
-      }
-    }
-  }
-  *addr = hostaddr;
-
-#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES)
-  if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
-#ifdef HAVE_SIGACTION
-    if(keep_copysig) {
-      /* we got a struct as it looked before, now put that one back nice
-         and clean */
-      sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
-    }
-#else
-#ifdef HAVE_SIGNAL
-    /* restore the previous SIGALRM handler */
-    signal(SIGALRM, keep_sigact);
-#endif
-#endif /* HAVE_SIGACTION */
-
-    /* switch back the alarm() to either zero or to what it was before minus
-       the time we spent until now! */
-    if(prev_alarm) {
-      /* there was an alarm() set before us, now put it back */
-      unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
-      unsigned long alarm_set;
-
-      /* the alarm period is counted in even number of seconds */
-      alarm_set = prev_alarm - elapsed_ms/1000;
-
-      if(!alarm_set ||
-         ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
-        /* if the alarm time-left reached zero or turned "negative" (counted
-           with unsigned values), we should fire off a SIGALRM here, but we
-           won't, and zero would be to switch it off so we never set it to
-           less than 1! */
-        alarm(1);
-        result = CURLE_OPERATION_TIMEDOUT;
-        failf(data, "Previous alarm fired off!");
-      }
-      else
-        alarm((unsigned int)alarm_set);
-    }
-    else
-      alarm(0); /* just shut it off */
-  }
-#endif
+  result = resolve_server(data, conn, addr, async);
 
   return result;
 }