From b73612392d7afbf9835a119446e2a58e72384b00 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 5 Aug 2003 14:40:59 +0000 Subject: ares awareness/usage/support added. If configure --enable-ares is used, we build libcurl to use ares for asynch name resolves. --- lib/url.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 136 insertions(+), 30 deletions(-) (limited to 'lib/url.c') diff --git a/lib/url.c b/lib/url.c index f1095bcee..84f3bbb0f 100644 --- a/lib/url.c +++ b/lib/url.c @@ -147,7 +147,11 @@ static unsigned int ConnectionStore(struct SessionHandle *data, struct connectdata *conn); static bool safe_strequal(char* str1, char* str2); -#if !defined(WIN32)||defined(__CYGWIN32__) +#ifndef USE_ARES +/* not for Win32, unless it is cygwin + not for ares builds */ +#if !defined(WIN32) || defined(__CYGWIN32__) + #ifndef RETSIGTYPE #define RETSIGTYPE void #endif @@ -165,6 +169,7 @@ RETSIGTYPE alarmfunc(int signal) return; } #endif +#endif /* USE_ARES */ void Curl_safefree(void *ptr) { @@ -1286,7 +1291,11 @@ CURLcode Curl_disconnect(struct connectdata *conn) Curl_safefree(conn->allocptr.host); Curl_safefree(conn->allocptr.cookiehost); Curl_safefree(conn->proxyhost); - +#ifdef USE_ARES + /* possible left-overs from the async name resolve */ + Curl_safefree(conn->async.hostname); +#endif + Curl_free_ssl_config(&conn->ssl_config); free(conn); /* free all the connection oriented data */ @@ -1632,7 +1641,15 @@ static int handleSock5Proxy( #ifndef ENABLE_IPV6 struct Curl_dns_entry *dns; Curl_addrinfo *hp=NULL; - dns = Curl_resolv(conn->data, conn->hostname, conn->remote_port); + int rc = Curl_resolv(conn, conn->hostname, conn->remote_port, &dns); + + if(rc == -1) + return CURLE_COULDNT_RESOLVE_HOST; + + if(rc == 1) + /* this requires that we're in "wait for resolve" state */ + rc = Curl_wait_for_resolv(conn, &dns); + /* * We cannot use 'hostent' as a struct that Curl_resolv() returns. It * returns a Curl_addrinfo pointer that may not always look the same. @@ -1841,8 +1858,19 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, return result; /* pass back status */ } +/* + * CreateConnection() 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. + */ + static CURLcode CreateConnection(struct SessionHandle *data, - struct connectdata **in_connect) + struct connectdata **in_connect, + struct Curl_dns_entry **addr, + bool *async) { char *tmp; CURLcode result=CURLE_OK; @@ -1859,7 +1887,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, char passwd[MAX_CURL_PASSWORD_LENGTH]; bool passwdgiven=FALSE; /* set TRUE if an application-provided password has been set */ - + int rc; #ifdef HAVE_SIGACTION struct sigaction keep_sigact; /* store the old struct here */ @@ -1870,6 +1898,9 @@ static CURLcode CreateConnection(struct SessionHandle *data, #endif #endif + *addr = NULL; /* nothing yet */ + *async = FALSE; + /************************************************************* * Check input data *************************************************************/ @@ -2875,8 +2906,10 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* else, no chunky upload */ FALSE; +#ifndef USE_ARES /************************************************************* - * Set timeout if that is being used + * 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) { /************************************************************* @@ -2919,7 +2952,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, has been done since then until now. */ #endif } - +#endif + /************************************************************* * Resolve the name of the server or proxy *************************************************************/ @@ -2935,9 +2969,11 @@ static CURLcode CreateConnection(struct SessionHandle *data, conn->port = conn->remote_port; /* it is the same port */ /* Resolve target host right on */ - hostaddr = Curl_resolv(data, conn->name, conn->port); + rc = Curl_resolv(conn, conn->name, conn->port, &hostaddr); + if(rc == 1) + *async = TRUE; - if(!hostaddr) { + else if(!hostaddr) { failf(data, "Couldn't resolve host '%s'", conn->name); result = CURLE_COULDNT_RESOLVE_HOST; /* don't return yet, we need to clean up the timeout first */ @@ -2947,15 +2983,19 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* This is a proxy that hasn't been resolved yet. */ /* resolve proxy */ - hostaddr = Curl_resolv(data, conn->proxyhost, conn->port); + rc = Curl_resolv(conn, conn->proxyhost, conn->port, &hostaddr); + + if(rc == 1) + *async = TRUE; - if(!hostaddr) { + else if(!hostaddr) { failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost); result = CURLE_COULDNT_RESOLVE_PROXY; /* don't return yet, we need to clean up the timeout first */ } } - Curl_pgrsTime(data, TIMER_NAMELOOKUP); + *addr = hostaddr; + #ifdef HAVE_ALARM if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) { #ifdef HAVE_SIGACTION @@ -2995,7 +3035,25 @@ static CURLcode CreateConnection(struct SessionHandle *data, alarm(0); /* just shut it off */ } #endif - if(result) + + return result; +} + +/* SetupConnection() should be called after the name resolve initiated in + * CreateConnection() is all done. + */ + +static CURLcode SetupConnection(struct connectdata *conn, + struct Curl_dns_entry *hostaddr) +{ + struct SessionHandle *data = conn->data; + CURLcode result=CURLE_OK; + + Curl_pgrsTime(data, TIMER_NAMELOOKUP); + + if(conn->protocol & PROT_FILE) + /* There's nothing in this function to setup if we're only doing + a file:// transfer */ return result; /************************************************************* @@ -3007,8 +3065,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, conn->proxyuser, conn->proxypasswd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { - if(conn->allocptr.proxyuserpwd) - free(conn->allocptr.proxyuserpwd); + Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = aprintf("Proxy-authorization: Basic %s\015\012", authorization); free(authorization); @@ -3022,16 +3079,14 @@ static CURLcode CreateConnection(struct SessionHandle *data, if((conn->protocol&PROT_HTTP) || (data->change.proxy && *data->change.proxy)) { if(data->set.useragent) { - if(conn->allocptr.uagent) - free(conn->allocptr.uagent); + Curl_safefree(conn->allocptr.uagent); conn->allocptr.uagent = aprintf("User-Agent: %s\015\012", data->set.useragent); } } if(data->set.encoding) { - if(conn->allocptr.accept_encoding) - free(conn->allocptr.accept_encoding); + Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = aprintf("Accept-Encoding: %s\015\012", data->set.encoding); } @@ -3083,26 +3138,60 @@ static CURLcode CreateConnection(struct SessionHandle *data, } CURLcode Curl_connect(struct SessionHandle *data, - struct connectdata **in_connect) + struct connectdata **in_connect, + bool *asyncp) { CURLcode code; - struct connectdata *conn; + struct Curl_dns_entry *dns; + *asyncp = FALSE; /* assume synchronous resolves by default */ + /* call the stuff that needs to be called */ - code = CreateConnection(data, in_connect); - + code = CreateConnection(data, in_connect, &dns, asyncp); + + if(CURLE_OK == code) { + /* no error */ + if(dns || !*asyncp) + /* If an address is available it means that we already have the name + resolved, OR it isn't async. + If so => continue connecting from here */ + code = SetupConnection(*in_connect, dns); + /* else + response will be received and treated async wise */ + } + if(CURLE_OK != code) { /* We're not allowed to return failure with memory left allocated in the connectdata struct, free those here */ - conn = (struct connectdata *)*in_connect; - if(conn) { - Curl_disconnect(conn); /* close the connection */ - *in_connect = NULL; /* return a NULL */ + if(*in_connect) { + Curl_disconnect(*in_connect); /* close the connection */ + *in_connect = NULL; /* return a NULL */ } } + return code; } +/* Call this function after Curl_connect() has returned async=TRUE and + then a successful name resolve has been received */ +CURLcode Curl_async_resolved(struct connectdata *conn) +{ +#ifdef USE_ARES + CURLcode code = SetupConnection(conn, conn->async.dns); + + if(code) + /* We're not allowed to return failure with memory left allocated + in the connectdata struct, free those here */ + Curl_disconnect(conn); /* close the connection */ + + return code; +#else + (void)conn; + return CURLE_OK; +#endif +} + + CURLcode Curl_done(struct connectdata *conn) { struct SessionHandle *data=conn->data; @@ -3179,11 +3268,28 @@ CURLcode Curl_do(struct connectdata **connp) conn->bits.close = TRUE; /* enforce close of this connetion */ result = Curl_done(conn); /* we are so done with this */ if(CURLE_OK == result) { + bool async; /* Now, redo the connect and get a new connection */ - result = Curl_connect(data, connp); - if(CURLE_OK == result) + result = Curl_connect(data, connp, &async); + if(CURLE_OK == result) { + /* We have connected or sent away a name resolve query fine */ + + if(async) { + /* Now, if async is TRUE here, we need to wait for the name + to resolve */ + result = Curl_wait_for_resolv(conn, NULL); + if(result) + return result; + + /* Resolved, continue with the connection */ + result = Curl_async_resolved(conn); + if(result) + return result; + } + /* ... finally back to actually retry the DO phase */ - result = conn->curl_do(*connp); + result = conn->curl_do(conn); + } } } } -- cgit v1.2.3