}
#endif
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
static void fix_hostname(struct SessionHandle *data,
struct connectdata *conn, struct hostname *host)
{
#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.
*/
/* 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]) {
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.
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)
{
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 */
}
/*************************************************************
- * 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);
return result;
}
-
/***********************************************************************
* file: is a special case in that it doesn't need a network connection
***********************************************************************/
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
* 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);
ConnectionStore(data, conn);
}
+ /*
+ * Setup whatever necessary for a resumed transfer
+ */
result = setup_range(data);
if(result)
return result;
/* 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;
}