Loading lib/easy.c +6 −13 Original line number Diff line number Diff line Loading @@ -269,12 +269,10 @@ CURLcode curl_global_init(long flags) idna_init(); #endif #ifdef CARES_HAVE_ARES_LIBRARY_INIT if(ares_library_init(ARES_LIB_INIT_ALL)) { DEBUGF(fprintf(stderr, "Error: ares_library_init failed\n")); if( Curl_resolver_global_init() != CURLE_OK ) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); return CURLE_FAILED_INIT; } #endif #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT) if(libssh2_init(0)) { Loading Loading @@ -340,9 +338,7 @@ void curl_global_cleanup(void) if(init_flags & CURL_GLOBAL_SSL) Curl_ssl_cleanup(); #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP ares_library_cleanup(); #endif Curl_resolver_global_cleanup(); if(init_flags & CURL_GLOBAL_WIN32) win32_cleanup(); Loading Loading @@ -676,12 +672,9 @@ CURL *curl_easy_duphandle(CURL *incurl) outcurl->change.referer_alloc = TRUE; } #ifdef USE_ARES /* If we use ares, we clone the ares channel for the new handle */ if(ARES_SUCCESS != ares_dup(&outcurl->state.areschannel, data->state.areschannel)) /* Clone the resolver handle, if present, for the new handle */ if( Curl_resolver_duphandle(&outcurl->state.resolver, data->state.resolver) != CURLE_OK ) goto fail; #endif Curl_convert_setup(outcurl); Loading lib/hostares.c +199 −28 Original line number Diff line number Diff line Loading @@ -60,6 +60,12 @@ #define in_addr_t unsigned long #endif /*********************************************************************** * Only for ares-enabled builds **********************************************************************/ #ifdef CURLRES_ARES #include "urldata.h" #include "sendf.h" #include "hostip.h" Loading @@ -76,15 +82,132 @@ #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) # define CARES_STATICLIB # endif # include <ares.h> #if ARES_VERSION >= 0x010500 /* c-ares 1.5.0 or later, the callback proto is modified */ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** * Only for ares-enabled builds **********************************************************************/ struct ResolverResults { int num_pending; /* number of ares_gethostbyname() requests */ Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ int last_status; }; #ifdef CURLRES_ARES /* * Curl_resolver_global_init() - the generic low-level asynchronous name resolve API. * Called from curl_global_init() to initialize global resolver environment. * Initializes ares library. */ int Curl_resolver_global_init() { #ifdef CARES_HAVE_ARES_LIBRARY_INIT if(ares_library_init(ARES_LIB_INIT_ALL)) { return CURLE_FAILED_INIT; } #endif return CURLE_OK; } /* * Curl_resolver_global_cleanup() - the generic low-level asynchronous name resolve API. * Called from curl_global_cleanup() to destroy global resolver environment. * Deinitializes ares library. */ void Curl_resolver_global_cleanup() { #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP ares_library_cleanup(); #endif } /* * Curl_resolver_init() - the generic low-level name resolve API. * Called from curl_easy_init() -> Curl_open() to initialize resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Fills the passed pointer by the initialized ares_channel. */ int Curl_resolver_init(void **resolver) { int status = ares_init((ares_channel*)resolver); if(status != ARES_SUCCESS) { if(status == ARES_ENOMEM) return CURLE_OUT_OF_MEMORY; else return CURLE_FAILED_INIT; } return CURLE_OK; /* make sure that all other returns from this function should destroy the ares channel before returning error! */ } /* * Curl_resolver_cleanup() - the generic low-level name resolve API. * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Destroys the ares channel. */ void Curl_resolver_cleanup(void *resolver) { ares_destroy((ares_channel)resolver); } /* * Curl_resolver_duphandle() - the generic low-level name resolve API. * Called from curl_easy_duphandle() to duplicate resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Duplicates the 'from' ares channel and passes the resulting channel to the 'to' pointer. */ int Curl_resolver_duphandle(void **to, void *from) { /* Clone the ares channel for the new handle */ if(ARES_SUCCESS != ares_dup((ares_channel*)to,(ares_channel)from)) return CURLE_FAILED_INIT; return CURLE_OK; } static void destroy_async_data (struct Curl_async *async); /* * Cancel all possibly still on-going resolves for this connection. */ void Curl_async_cancel(struct connectdata *conn) { if( conn && conn->data && conn->data->state.resolver ) ares_cancel((ares_channel)conn->data->state.resolver); destroy_async_data(&conn->async); } /* * destroy_async_data() cleans up async resolver data. */ static void destroy_async_data (struct Curl_async *async) { if(async->hostname) free(async->hostname); if(async->os_specific) { struct ResolverResults *res = (struct ResolverResults *)async->os_specific; if( res ) { if( res->temp_ai ) { Curl_freeaddrinfo(res->temp_ai); res->temp_ai = NULL; } free(res); } async->os_specific = NULL; } async->hostname = NULL; } /* * Curl_resolv_fdset() is called when someone from the outside world (using Loading @@ -103,14 +226,14 @@ int Curl_resolv_getsock(struct connectdata *conn, struct timeval maxtime; struct timeval timebuf; struct timeval *timeout; int max = ares_getsock(conn->data->state.areschannel, int max = ares_getsock((ares_channel)conn->data->state.resolver, (ares_socket_t *)socks, numsocks); maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; maxtime.tv_usec = 0; timeout = ares_timeout(conn->data->state.areschannel, &maxtime, &timebuf); timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime, &timebuf); Curl_expire(conn->data, (timeout->tv_sec * 1000) + (timeout->tv_usec/1000)); Loading Loading @@ -138,7 +261,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms) int i; int num = 0; bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM); bitmask = ares_getsock((ares_channel)data->state.resolver, socks, ARES_GETSOCK_MAXNUM); for(i=0; i < ARES_GETSOCK_MAXNUM; i++) { pfd[i].events = 0; Loading @@ -165,11 +288,11 @@ static int waitperform(struct connectdata *conn, int timeout_ms) if(!nfds) /* Call ares_process() unconditonally here, even if we simply timed out above, as otherwise the ares name resolve won't timeout! */ ares_process_fd(data->state.areschannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD, ARES_SOCKET_BAD); else { /* move through the descriptors and ask for processing on them */ for(i=0; i < num; i++) ares_process_fd(data->state.areschannel, ares_process_fd((ares_channel)data->state.resolver, pfd[i].revents & (POLLRDNORM|POLLIN)? pfd[i].fd:ARES_SOCKET_BAD, pfd[i].revents & (POLLWRNORM|POLLOUT)? Loading @@ -189,13 +312,17 @@ CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns) { struct SessionHandle *data = conn->data; struct ResolverResults *res = (struct ResolverResults *)conn->async.os_specific; *dns = NULL; waitperform(conn, 0); if(conn->async.done) { /* we're done, kill the ares handle */ if( res && !res->num_pending ) { (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai); /* temp_ai ownership is moved to the connection, so we need not free-up them */ res->temp_ai = NULL; destroy_async_data(&conn->async); if(!conn->async.dns) { failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, ares_strerror(conn->async.status)); Loading Loading @@ -223,6 +350,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, struct SessionHandle *data = conn->data; long timeout; struct timeval now = Curl_tvnow(); struct Curl_dns_entry *temp_entry; timeout = Curl_timeleft(data, &now, TRUE); if(!timeout) Loading @@ -240,7 +368,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, store.tv_sec = itimeout/1000; store.tv_usec = (itimeout%1000)*1000; tvp = ares_timeout(data->state.areschannel, &store, &tv); tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv); /* use the timeout period ares returned to us above if less than one second is left, otherwise just use 1000ms to make sure the progress Loading @@ -251,6 +379,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, timeout_ms = 1000; waitperform(conn, timeout_ms); Curl_is_resolved(conn,&temp_entry); if(conn->async.done) break; Loading @@ -267,7 +396,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, } if(timeout < 0) { /* our timeout, so we cancel the ares operation */ ares_cancel(data->state.areschannel); ares_cancel((ares_channel)data->state.resolver); break; } } Loading Loading @@ -313,6 +442,22 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, return rc; } /* Connects results to the list */ static void ares_compound_results(struct ResolverResults *res, Curl_addrinfo *ai) { Curl_addrinfo *ai_tail; if( !ai ) return; ai_tail = ai; while (ai_tail->ai_next) ai_tail = ai_tail->ai_next; /* Add the new results to the list of old results. */ ai_tail->ai_next = res->temp_ai; res->temp_ai = ai; } /* * ares_query_completed_cb() is the callback that ares will call when * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), Loading @@ -326,26 +471,44 @@ static void ares_query_completed_cb(void *arg, /* (struct connectdata *) */ struct hostent *hostent) { struct connectdata *conn = (struct connectdata *)arg; struct Curl_addrinfo * ai = NULL; struct ResolverResults *res = (struct ResolverResults *)conn->async.os_specific; if( !conn->data ) { /* Immediately return just because the handle is destroying */ return; } if( !conn->data->magic ) { /* Immediately return just because the handle is destroying */ return; } if( !res ) { /* Immediately return just because the results are destroyed for some reason */ return; } #ifdef HAVE_CARES_CALLBACK_TIMEOUTS (void)timeouts; /* ignored */ #endif res->num_pending--; switch(status) { case CURL_ASYNC_SUCCESS: ai = Curl_he2ai(hostent, conn->async.port); ares_compound_results(res,Curl_he2ai(hostent, conn->async.port)); break; case ARES_EDESTRUCTION: /* this ares handle is getting destroyed, the 'arg' pointer may not be valid! */ return; /* conn->magic check instead case ARES_EDESTRUCTION: return; */ default: /* do nothing */ break; } (void)Curl_addrinfo_callback(arg, status, ai); /* The successfull result empties any error */ if( res->last_status != ARES_SUCCESS ) res->last_status = status; } /* Loading Loading @@ -402,33 +565,41 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, #endif /* CURLRES_IPV6 */ bufp = strdup(hostname); if(bufp) { struct ResolverResults *res = NULL; Curl_safefree(conn->async.hostname); conn->async.hostname = bufp; conn->async.port = port; conn->async.done = FALSE; /* not done */ conn->async.status = 0; /* clear */ conn->async.dns = NULL; /* clear */ conn->async.temp_ai = NULL; /* clear */ res = (struct ResolverResults *)calloc(sizeof(struct ResolverResults),1); if( !res ) { Curl_safefree(conn->async.hostname); conn->async.hostname = NULL; return NULL; } conn->async.os_specific = res; /* initial status - failed */ res->last_status = ARES_ENOTFOUND; #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ if(family == PF_UNSPEC) { conn->async.num_pending = 2; res->num_pending = 2; /* areschannel is already setup in the Curl_open() function */ ares_gethostbyname(data->state.areschannel, hostname, PF_INET, ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET, ares_query_completed_cb, conn); ares_gethostbyname(data->state.areschannel, hostname, PF_INET6, ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET6, ares_query_completed_cb, conn); } else #endif /* CURLRES_IPV6 */ { conn->async.num_pending = 1; res->num_pending = 1; /* areschannel is already setup in the Curl_open() function */ ares_gethostbyname(data->state.areschannel, hostname, family, ares_gethostbyname((ares_channel)data->state.resolver, hostname, family, ares_query_completed_cb, conn); } Loading lib/hostasyn.c +0 −75 Original line number Diff line number Diff line Loading @@ -72,20 +72,6 @@ **********************************************************************/ #ifdef CURLRES_ASYNCH /* * Cancel all possibly still on-going resolves for this connection. */ void Curl_async_cancel(struct connectdata *conn) { /* If we have a "half" response already received, we first clear that off so that nothing is tempted to use it */ if(conn->async.temp_ai) { Curl_freeaddrinfo(conn->async.temp_ai); conn->async.temp_ai = NULL; } } /* * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread() * or getaddrinfo_thread() when we got the name resolved (or not!). Loading @@ -109,24 +95,6 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, if(ai) { struct SessionHandle *data = conn->data; #if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ Curl_addrinfo *ai_tail = ai; while (ai_tail->ai_next) ai_tail = ai_tail->ai_next; /* Add the new results to the list of old results. */ ai_tail->ai_next = conn->async.temp_ai; conn->async.temp_ai = ai; if(--conn->async.num_pending > 0) /* We are not done yet. Just return. */ return CURLE_OK; /* make sure the temp pointer is cleared and isn't pointing to something we take care of below */ conn->async.temp_ai = NULL; #endif if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); Loading @@ -143,52 +111,9 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } else { #if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ if(--conn->async.num_pending > 0) { /* We are not done yet. Clean up and return. This function will be called again. */ if(conn->async.temp_ai) { Curl_freeaddrinfo(conn->async.temp_ai); conn->async.temp_ai = NULL; } return CURLE_OUT_OF_MEMORY; } #endif rc = CURLE_OUT_OF_MEMORY; } } #if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ else { if(--conn->async.num_pending > 0) /* We are not done yet. Just return. */ return CURLE_OK; if(conn->async.temp_ai) { /* We are done, and while this latest request failed, some previous results exist. */ struct SessionHandle *data = conn->data; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = Curl_cache_addr(data, conn->async.temp_ai, conn->async.hostname, conn->async.port); if(!dns) { /* failed to store, cleanup and return error */ Curl_freeaddrinfo(conn->async.temp_ai); rc = CURLE_OUT_OF_MEMORY; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); /* make sure the temp pointer is cleared and isn't pointing to something we've taken care of already */ conn->async.temp_ai = NULL; } } #endif conn->async.dns = dns; Loading lib/hostip.h +48 −31 Original line number Diff line number Diff line Loading @@ -35,14 +35,6 @@ #define in_addr_t unsigned long #endif /* * Comfortable CURLRES_* definitions are included from setup.h */ #ifdef USE_ARES #include <ares_version.h> #endif /* Allocate enough memory to hold the full name information structs and * everything. OSF1 is known to require at least 8872 bytes. The buffer * required for storing all possible aliases and IP numbers is according to Loading @@ -53,29 +45,13 @@ #define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this many seconds for a name resolve */ #ifdef CURLRES_ARES #define CURL_ASYNC_SUCCESS ARES_SUCCESS #if ARES_VERSION >= 0x010500 /* c-ares 1.5.0 or later, the callback proto is modified */ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif #else #define CURL_ASYNC_SUCCESS CURLE_OK #define ares_cancel(x) do {} while(0) #define ares_destroy(x) do {} while(0) #endif struct addrinfo; struct hostent; struct SessionHandle; struct connectdata; #ifdef CURLRES_ASYNCH void Curl_async_cancel(struct connectdata *conn); #else #define Curl_async_cancel(x) do {} while(0) #endif /* * Curl_global_host_cache_init() initializes and sets up a global DNS cache. * Global DNS cache is general badness. Do not use. This will be removed in Loading Loading @@ -128,6 +104,45 @@ bool Curl_ipv6works(void); */ bool Curl_ipvalid(struct connectdata *conn); /* * Curl_resolver_global_init() - the generic low-level name resolver API. * Called from curl_global_init() to initialize global resolver environment. * Returning anything else than CURLE_OK fails curl_global_init(). */ int Curl_resolver_global_init(void); /* * Curl_resolver_global_cleanup() - the generic low-level name resolver API. * Called from curl_global_cleanup() to destroy global resolver environment. */ void Curl_resolver_global_cleanup(void); /* * Curl_resolver_init() - the generic low-level name resolve API. * Called from curl_easy_init() -> Curl_open() to initialize resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Should fill the passed pointer by the initialized handler. * Returning anything else than CURLE_OK fails curl_easy_init() with the correspondent code. */ int Curl_resolver_init(void **resolver); /* * Curl_resolver_cleanup() - the generic low-level name resolve API. * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Should destroy the handler and free all resources connected to it. */ void Curl_resolver_cleanup(void *resolver); /* * Curl_resolver_duphandle() - the generic low-level name resolve API. * Called from curl_easy_duphandle() to duplicate resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Should duplicate the 'from' handle and pass the resulting handle to the 'to' pointer. * Returning anything else than CURLE_OK causes failed curl_easy_duphandle() call. */ int Curl_resolver_duphandle(void **to, void *from); /* * Curl_getaddrinfo() is the generic low-level name resolve API within this * source file. There are several versions of this function - for different Loading @@ -139,6 +154,15 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, int port, int *waitp); #ifdef CURLRES_ASYNCH /* * Curl_async_cancel() is the generic low-level asynchronous name resolve API. * It is called from inside other functions to cancel currently performing resolver * request. Should also free any temporary resources allocated to perform a request. */ void Curl_async_cancel(struct connectdata *conn); #endif CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns); CURLcode Curl_wait_for_resolv(struct connectdata *conn, Loading Loading @@ -209,13 +233,6 @@ struct Curl_dns_entry * Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr, const char *hostname, int port); /* * Curl_destroy_thread_data() cleans up async resolver data. * Complementary of ares_destroy. */ struct Curl_async; /* forward-declaration */ void Curl_destroy_thread_data(struct Curl_async *async); #ifndef INADDR_NONE #define CURL_INADDR_NONE (in_addr_t) ~0 #else Loading lib/hostip4.c +1 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ bool Curl_ipvalid(struct connectdata *conn) } #ifdef CURLRES_SYNCH /* * Curl_getaddrinfo() - the ipv4 synchronous version. * Loading Loading
lib/easy.c +6 −13 Original line number Diff line number Diff line Loading @@ -269,12 +269,10 @@ CURLcode curl_global_init(long flags) idna_init(); #endif #ifdef CARES_HAVE_ARES_LIBRARY_INIT if(ares_library_init(ARES_LIB_INIT_ALL)) { DEBUGF(fprintf(stderr, "Error: ares_library_init failed\n")); if( Curl_resolver_global_init() != CURLE_OK ) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); return CURLE_FAILED_INIT; } #endif #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT) if(libssh2_init(0)) { Loading Loading @@ -340,9 +338,7 @@ void curl_global_cleanup(void) if(init_flags & CURL_GLOBAL_SSL) Curl_ssl_cleanup(); #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP ares_library_cleanup(); #endif Curl_resolver_global_cleanup(); if(init_flags & CURL_GLOBAL_WIN32) win32_cleanup(); Loading Loading @@ -676,12 +672,9 @@ CURL *curl_easy_duphandle(CURL *incurl) outcurl->change.referer_alloc = TRUE; } #ifdef USE_ARES /* If we use ares, we clone the ares channel for the new handle */ if(ARES_SUCCESS != ares_dup(&outcurl->state.areschannel, data->state.areschannel)) /* Clone the resolver handle, if present, for the new handle */ if( Curl_resolver_duphandle(&outcurl->state.resolver, data->state.resolver) != CURLE_OK ) goto fail; #endif Curl_convert_setup(outcurl); Loading
lib/hostares.c +199 −28 Original line number Diff line number Diff line Loading @@ -60,6 +60,12 @@ #define in_addr_t unsigned long #endif /*********************************************************************** * Only for ares-enabled builds **********************************************************************/ #ifdef CURLRES_ARES #include "urldata.h" #include "sendf.h" #include "hostip.h" Loading @@ -76,15 +82,132 @@ #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) # define CARES_STATICLIB # endif # include <ares.h> #if ARES_VERSION >= 0x010500 /* c-ares 1.5.0 or later, the callback proto is modified */ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** * Only for ares-enabled builds **********************************************************************/ struct ResolverResults { int num_pending; /* number of ares_gethostbyname() requests */ Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ int last_status; }; #ifdef CURLRES_ARES /* * Curl_resolver_global_init() - the generic low-level asynchronous name resolve API. * Called from curl_global_init() to initialize global resolver environment. * Initializes ares library. */ int Curl_resolver_global_init() { #ifdef CARES_HAVE_ARES_LIBRARY_INIT if(ares_library_init(ARES_LIB_INIT_ALL)) { return CURLE_FAILED_INIT; } #endif return CURLE_OK; } /* * Curl_resolver_global_cleanup() - the generic low-level asynchronous name resolve API. * Called from curl_global_cleanup() to destroy global resolver environment. * Deinitializes ares library. */ void Curl_resolver_global_cleanup() { #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP ares_library_cleanup(); #endif } /* * Curl_resolver_init() - the generic low-level name resolve API. * Called from curl_easy_init() -> Curl_open() to initialize resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Fills the passed pointer by the initialized ares_channel. */ int Curl_resolver_init(void **resolver) { int status = ares_init((ares_channel*)resolver); if(status != ARES_SUCCESS) { if(status == ARES_ENOMEM) return CURLE_OUT_OF_MEMORY; else return CURLE_FAILED_INIT; } return CURLE_OK; /* make sure that all other returns from this function should destroy the ares channel before returning error! */ } /* * Curl_resolver_cleanup() - the generic low-level name resolve API. * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Destroys the ares channel. */ void Curl_resolver_cleanup(void *resolver) { ares_destroy((ares_channel)resolver); } /* * Curl_resolver_duphandle() - the generic low-level name resolve API. * Called from curl_easy_duphandle() to duplicate resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Duplicates the 'from' ares channel and passes the resulting channel to the 'to' pointer. */ int Curl_resolver_duphandle(void **to, void *from) { /* Clone the ares channel for the new handle */ if(ARES_SUCCESS != ares_dup((ares_channel*)to,(ares_channel)from)) return CURLE_FAILED_INIT; return CURLE_OK; } static void destroy_async_data (struct Curl_async *async); /* * Cancel all possibly still on-going resolves for this connection. */ void Curl_async_cancel(struct connectdata *conn) { if( conn && conn->data && conn->data->state.resolver ) ares_cancel((ares_channel)conn->data->state.resolver); destroy_async_data(&conn->async); } /* * destroy_async_data() cleans up async resolver data. */ static void destroy_async_data (struct Curl_async *async) { if(async->hostname) free(async->hostname); if(async->os_specific) { struct ResolverResults *res = (struct ResolverResults *)async->os_specific; if( res ) { if( res->temp_ai ) { Curl_freeaddrinfo(res->temp_ai); res->temp_ai = NULL; } free(res); } async->os_specific = NULL; } async->hostname = NULL; } /* * Curl_resolv_fdset() is called when someone from the outside world (using Loading @@ -103,14 +226,14 @@ int Curl_resolv_getsock(struct connectdata *conn, struct timeval maxtime; struct timeval timebuf; struct timeval *timeout; int max = ares_getsock(conn->data->state.areschannel, int max = ares_getsock((ares_channel)conn->data->state.resolver, (ares_socket_t *)socks, numsocks); maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; maxtime.tv_usec = 0; timeout = ares_timeout(conn->data->state.areschannel, &maxtime, &timebuf); timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime, &timebuf); Curl_expire(conn->data, (timeout->tv_sec * 1000) + (timeout->tv_usec/1000)); Loading Loading @@ -138,7 +261,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms) int i; int num = 0; bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM); bitmask = ares_getsock((ares_channel)data->state.resolver, socks, ARES_GETSOCK_MAXNUM); for(i=0; i < ARES_GETSOCK_MAXNUM; i++) { pfd[i].events = 0; Loading @@ -165,11 +288,11 @@ static int waitperform(struct connectdata *conn, int timeout_ms) if(!nfds) /* Call ares_process() unconditonally here, even if we simply timed out above, as otherwise the ares name resolve won't timeout! */ ares_process_fd(data->state.areschannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD, ARES_SOCKET_BAD); else { /* move through the descriptors and ask for processing on them */ for(i=0; i < num; i++) ares_process_fd(data->state.areschannel, ares_process_fd((ares_channel)data->state.resolver, pfd[i].revents & (POLLRDNORM|POLLIN)? pfd[i].fd:ARES_SOCKET_BAD, pfd[i].revents & (POLLWRNORM|POLLOUT)? Loading @@ -189,13 +312,17 @@ CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns) { struct SessionHandle *data = conn->data; struct ResolverResults *res = (struct ResolverResults *)conn->async.os_specific; *dns = NULL; waitperform(conn, 0); if(conn->async.done) { /* we're done, kill the ares handle */ if( res && !res->num_pending ) { (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai); /* temp_ai ownership is moved to the connection, so we need not free-up them */ res->temp_ai = NULL; destroy_async_data(&conn->async); if(!conn->async.dns) { failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, ares_strerror(conn->async.status)); Loading Loading @@ -223,6 +350,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, struct SessionHandle *data = conn->data; long timeout; struct timeval now = Curl_tvnow(); struct Curl_dns_entry *temp_entry; timeout = Curl_timeleft(data, &now, TRUE); if(!timeout) Loading @@ -240,7 +368,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, store.tv_sec = itimeout/1000; store.tv_usec = (itimeout%1000)*1000; tvp = ares_timeout(data->state.areschannel, &store, &tv); tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv); /* use the timeout period ares returned to us above if less than one second is left, otherwise just use 1000ms to make sure the progress Loading @@ -251,6 +379,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, timeout_ms = 1000; waitperform(conn, timeout_ms); Curl_is_resolved(conn,&temp_entry); if(conn->async.done) break; Loading @@ -267,7 +396,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, } if(timeout < 0) { /* our timeout, so we cancel the ares operation */ ares_cancel(data->state.areschannel); ares_cancel((ares_channel)data->state.resolver); break; } } Loading Loading @@ -313,6 +442,22 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn, return rc; } /* Connects results to the list */ static void ares_compound_results(struct ResolverResults *res, Curl_addrinfo *ai) { Curl_addrinfo *ai_tail; if( !ai ) return; ai_tail = ai; while (ai_tail->ai_next) ai_tail = ai_tail->ai_next; /* Add the new results to the list of old results. */ ai_tail->ai_next = res->temp_ai; res->temp_ai = ai; } /* * ares_query_completed_cb() is the callback that ares will call when * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), Loading @@ -326,26 +471,44 @@ static void ares_query_completed_cb(void *arg, /* (struct connectdata *) */ struct hostent *hostent) { struct connectdata *conn = (struct connectdata *)arg; struct Curl_addrinfo * ai = NULL; struct ResolverResults *res = (struct ResolverResults *)conn->async.os_specific; if( !conn->data ) { /* Immediately return just because the handle is destroying */ return; } if( !conn->data->magic ) { /* Immediately return just because the handle is destroying */ return; } if( !res ) { /* Immediately return just because the results are destroyed for some reason */ return; } #ifdef HAVE_CARES_CALLBACK_TIMEOUTS (void)timeouts; /* ignored */ #endif res->num_pending--; switch(status) { case CURL_ASYNC_SUCCESS: ai = Curl_he2ai(hostent, conn->async.port); ares_compound_results(res,Curl_he2ai(hostent, conn->async.port)); break; case ARES_EDESTRUCTION: /* this ares handle is getting destroyed, the 'arg' pointer may not be valid! */ return; /* conn->magic check instead case ARES_EDESTRUCTION: return; */ default: /* do nothing */ break; } (void)Curl_addrinfo_callback(arg, status, ai); /* The successfull result empties any error */ if( res->last_status != ARES_SUCCESS ) res->last_status = status; } /* Loading Loading @@ -402,33 +565,41 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, #endif /* CURLRES_IPV6 */ bufp = strdup(hostname); if(bufp) { struct ResolverResults *res = NULL; Curl_safefree(conn->async.hostname); conn->async.hostname = bufp; conn->async.port = port; conn->async.done = FALSE; /* not done */ conn->async.status = 0; /* clear */ conn->async.dns = NULL; /* clear */ conn->async.temp_ai = NULL; /* clear */ res = (struct ResolverResults *)calloc(sizeof(struct ResolverResults),1); if( !res ) { Curl_safefree(conn->async.hostname); conn->async.hostname = NULL; return NULL; } conn->async.os_specific = res; /* initial status - failed */ res->last_status = ARES_ENOTFOUND; #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ if(family == PF_UNSPEC) { conn->async.num_pending = 2; res->num_pending = 2; /* areschannel is already setup in the Curl_open() function */ ares_gethostbyname(data->state.areschannel, hostname, PF_INET, ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET, ares_query_completed_cb, conn); ares_gethostbyname(data->state.areschannel, hostname, PF_INET6, ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET6, ares_query_completed_cb, conn); } else #endif /* CURLRES_IPV6 */ { conn->async.num_pending = 1; res->num_pending = 1; /* areschannel is already setup in the Curl_open() function */ ares_gethostbyname(data->state.areschannel, hostname, family, ares_gethostbyname((ares_channel)data->state.resolver, hostname, family, ares_query_completed_cb, conn); } Loading
lib/hostasyn.c +0 −75 Original line number Diff line number Diff line Loading @@ -72,20 +72,6 @@ **********************************************************************/ #ifdef CURLRES_ASYNCH /* * Cancel all possibly still on-going resolves for this connection. */ void Curl_async_cancel(struct connectdata *conn) { /* If we have a "half" response already received, we first clear that off so that nothing is tempted to use it */ if(conn->async.temp_ai) { Curl_freeaddrinfo(conn->async.temp_ai); conn->async.temp_ai = NULL; } } /* * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread() * or getaddrinfo_thread() when we got the name resolved (or not!). Loading @@ -109,24 +95,6 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, if(ai) { struct SessionHandle *data = conn->data; #if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ Curl_addrinfo *ai_tail = ai; while (ai_tail->ai_next) ai_tail = ai_tail->ai_next; /* Add the new results to the list of old results. */ ai_tail->ai_next = conn->async.temp_ai; conn->async.temp_ai = ai; if(--conn->async.num_pending > 0) /* We are not done yet. Just return. */ return CURLE_OK; /* make sure the temp pointer is cleared and isn't pointing to something we take care of below */ conn->async.temp_ai = NULL; #endif if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); Loading @@ -143,52 +111,9 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, Curl_share_unlock(data, CURL_LOCK_DATA_DNS); } else { #if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ if(--conn->async.num_pending > 0) { /* We are not done yet. Clean up and return. This function will be called again. */ if(conn->async.temp_ai) { Curl_freeaddrinfo(conn->async.temp_ai); conn->async.temp_ai = NULL; } return CURLE_OUT_OF_MEMORY; } #endif rc = CURLE_OUT_OF_MEMORY; } } #if defined(ENABLE_IPV6) && defined(CURLRES_ARES) /* CURLRES_IPV6 */ else { if(--conn->async.num_pending > 0) /* We are not done yet. Just return. */ return CURLE_OK; if(conn->async.temp_ai) { /* We are done, and while this latest request failed, some previous results exist. */ struct SessionHandle *data = conn->data; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = Curl_cache_addr(data, conn->async.temp_ai, conn->async.hostname, conn->async.port); if(!dns) { /* failed to store, cleanup and return error */ Curl_freeaddrinfo(conn->async.temp_ai); rc = CURLE_OUT_OF_MEMORY; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); /* make sure the temp pointer is cleared and isn't pointing to something we've taken care of already */ conn->async.temp_ai = NULL; } } #endif conn->async.dns = dns; Loading
lib/hostip.h +48 −31 Original line number Diff line number Diff line Loading @@ -35,14 +35,6 @@ #define in_addr_t unsigned long #endif /* * Comfortable CURLRES_* definitions are included from setup.h */ #ifdef USE_ARES #include <ares_version.h> #endif /* Allocate enough memory to hold the full name information structs and * everything. OSF1 is known to require at least 8872 bytes. The buffer * required for storing all possible aliases and IP numbers is according to Loading @@ -53,29 +45,13 @@ #define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this many seconds for a name resolve */ #ifdef CURLRES_ARES #define CURL_ASYNC_SUCCESS ARES_SUCCESS #if ARES_VERSION >= 0x010500 /* c-ares 1.5.0 or later, the callback proto is modified */ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif #else #define CURL_ASYNC_SUCCESS CURLE_OK #define ares_cancel(x) do {} while(0) #define ares_destroy(x) do {} while(0) #endif struct addrinfo; struct hostent; struct SessionHandle; struct connectdata; #ifdef CURLRES_ASYNCH void Curl_async_cancel(struct connectdata *conn); #else #define Curl_async_cancel(x) do {} while(0) #endif /* * Curl_global_host_cache_init() initializes and sets up a global DNS cache. * Global DNS cache is general badness. Do not use. This will be removed in Loading Loading @@ -128,6 +104,45 @@ bool Curl_ipv6works(void); */ bool Curl_ipvalid(struct connectdata *conn); /* * Curl_resolver_global_init() - the generic low-level name resolver API. * Called from curl_global_init() to initialize global resolver environment. * Returning anything else than CURLE_OK fails curl_global_init(). */ int Curl_resolver_global_init(void); /* * Curl_resolver_global_cleanup() - the generic low-level name resolver API. * Called from curl_global_cleanup() to destroy global resolver environment. */ void Curl_resolver_global_cleanup(void); /* * Curl_resolver_init() - the generic low-level name resolve API. * Called from curl_easy_init() -> Curl_open() to initialize resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Should fill the passed pointer by the initialized handler. * Returning anything else than CURLE_OK fails curl_easy_init() with the correspondent code. */ int Curl_resolver_init(void **resolver); /* * Curl_resolver_cleanup() - the generic low-level name resolve API. * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Should destroy the handler and free all resources connected to it. */ void Curl_resolver_cleanup(void *resolver); /* * Curl_resolver_duphandle() - the generic low-level name resolve API. * Called from curl_easy_duphandle() to duplicate resolver URL-state specific environment * ('resolver' member of the UrlState structure). * Should duplicate the 'from' handle and pass the resulting handle to the 'to' pointer. * Returning anything else than CURLE_OK causes failed curl_easy_duphandle() call. */ int Curl_resolver_duphandle(void **to, void *from); /* * Curl_getaddrinfo() is the generic low-level name resolve API within this * source file. There are several versions of this function - for different Loading @@ -139,6 +154,15 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, int port, int *waitp); #ifdef CURLRES_ASYNCH /* * Curl_async_cancel() is the generic low-level asynchronous name resolve API. * It is called from inside other functions to cancel currently performing resolver * request. Should also free any temporary resources allocated to perform a request. */ void Curl_async_cancel(struct connectdata *conn); #endif CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns); CURLcode Curl_wait_for_resolv(struct connectdata *conn, Loading Loading @@ -209,13 +233,6 @@ struct Curl_dns_entry * Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr, const char *hostname, int port); /* * Curl_destroy_thread_data() cleans up async resolver data. * Complementary of ares_destroy. */ struct Curl_async; /* forward-declaration */ void Curl_destroy_thread_data(struct Curl_async *async); #ifndef INADDR_NONE #define CURL_INADDR_NONE (in_addr_t) ~0 #else Loading
lib/hostip4.c +1 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ bool Curl_ipvalid(struct connectdata *conn) } #ifdef CURLRES_SYNCH /* * Curl_getaddrinfo() - the ipv4 synchronous version. * Loading