From 7de2f9271c68c10ee7057c10741b0406bca6c156 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 31 Jan 2011 00:10:35 +0100 Subject: async resolvers: further cleanups asyn-ares.c and asyn-thread.c are two separate backends that implement the same (internal) async resolver API for libcurl to use. Backend is specified at build time. The internal resolver API is defined in asyn.h for asynch resolvers. --- lib/asyn-ares.c | 610 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 610 insertions(+) create mode 100644 lib/asyn-ares.c (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c new file mode 100644 index 000000000..6b71e0384 --- /dev/null +++ b/lib/asyn-ares.c @@ -0,0 +1,610 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "setup.h" + +#include + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* required for free() prototypes */ +#endif +#ifdef HAVE_UNISTD_H +#include /* for the close() proto */ +#endif +#ifdef __VMS +#include +#include +#include +#endif + +#ifdef HAVE_PROCESS_H +#include +#endif + +#if (defined(NETWARE) && defined(__NOVELL_LIBC__)) +#undef in_addr_t +#define in_addr_t unsigned long +#endif + +/*********************************************************************** + * Only for ares-enabled builds + * And only for functions that fulfill the asynch resolver backend API + * as defined in asyn.h, nothing else belongs in this file! + **********************************************************************/ + +#ifdef CURLRES_ARES + +#include "urldata.h" +#include "sendf.h" +#include "hostip.h" +#include "hash.h" +#include "share.h" +#include "strerror.h" +#include "url.h" +#include "multiif.h" +#include "inet_pton.h" +#include "connect.h" +#include "select.h" +#include "progress.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ + (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) +# define CARES_STATICLIB +# endif +# include + +#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" + +struct ResolverResults { + int num_pending; /* number of ares_gethostbyname() requests */ + Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ + int last_status; +}; + +/* + * 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(void) +{ +#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() + * + * Called from curl_global_cleanup() to destroy global resolver environment. + * Deinitializes ares library. + */ +void Curl_resolver_global_cleanup(void) +{ +#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP + ares_library_cleanup(); +#endif +} + +/* + * Curl_resolver_init() + * + * 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() + * + * 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() + * + * 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_resolver_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_resolver_fdset() is called when someone from the outside world (using + * curl_multi_fdset()) wants to get our fd_set setup and we're talking with + * ares. The caller must make sure that this function is only called when we + * have a working ares channel. + * + * Returns: CURLE_OK always! + */ + +int Curl_resolver_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) + +{ + struct timeval maxtime; + struct timeval timebuf; + struct timeval *timeout; + 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((ares_channel)conn->data->state.resolver, &maxtime, + &timebuf); + + Curl_expire(conn->data, + (timeout->tv_sec * 1000) + (timeout->tv_usec/1000)); + + return max; +} + +/* + * waitperform() + * + * 1) Ask ares what sockets it currently plays with, then + * 2) wait for the timeout period to check for action on ares' sockets. + * 3) tell ares to act on all the sockets marked as "with action" + * + * return number of sockets it worked on + */ + +static int waitperform(struct connectdata *conn, int timeout_ms) +{ + struct SessionHandle *data = conn->data; + int nfds; + int bitmask; + ares_socket_t socks[ARES_GETSOCK_MAXNUM]; + struct pollfd pfd[ARES_GETSOCK_MAXNUM]; + int i; + int num = 0; + + bitmask = ares_getsock((ares_channel)data->state.resolver, socks, + ARES_GETSOCK_MAXNUM); + + for(i=0; i < ARES_GETSOCK_MAXNUM; i++) { + pfd[i].events = 0; + pfd[i].revents = 0; + if(ARES_GETSOCK_READABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLRDNORM|POLLIN; + } + if(ARES_GETSOCK_WRITABLE(bitmask, i)) { + pfd[i].fd = socks[i]; + pfd[i].events |= POLLWRNORM|POLLOUT; + } + if(pfd[i].events != 0) + num++; + else + break; + } + + if(num) + nfds = Curl_poll(pfd, num, timeout_ms); + else + nfds = 0; + + 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((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((ares_channel)data->state.resolver, + pfd[i].revents & (POLLRDNORM|POLLIN)? + pfd[i].fd:ARES_SOCKET_BAD, + pfd[i].revents & (POLLWRNORM|POLLOUT)? + pfd[i].fd:ARES_SOCKET_BAD); + } + return nfds; +} + +/* + * Curl_resolver_is_resolved() is called repeatedly to check if a previous + * name resolve request has completed. It should also make sure to time-out if + * the operation seems to take too long. + * + * Returns normal CURLcode errors. + */ +CURLcode Curl_resolver_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( 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)); + return CURLE_COULDNT_RESOLVE_HOST; + } + *dns = conn->async.dns; + } + + return CURLE_OK; +} + +/* + * Curl_resolver_wait_resolv() + * + * waits for a resolve to finish. This function should be avoided since using + * this risk getting the multi interface to "hang". + * + * If 'entry' is non-NULL, make it point to the resolved dns entry + * + * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and + * CURLE_OPERATION_TIMEDOUT if a time-out occurred. + */ +CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, + struct Curl_dns_entry **entry) +{ + CURLcode rc=CURLE_OK; + 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) + timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ + + /* Wait for the name resolve query to complete. */ + for(;;) { + struct timeval *tvp, tv, store; + long timediff; + int itimeout; + int timeout_ms; + + itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout; + + store.tv_sec = itimeout/1000; + store.tv_usec = (itimeout%1000)*1000; + + 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 + callback gets called frequent enough */ + if(!tvp->tv_sec) + timeout_ms = (int)(tvp->tv_usec/1000); + else + timeout_ms = 1000; + + waitperform(conn, timeout_ms); + Curl_resolver_is_resolved(conn,&temp_entry); + + if(conn->async.done) + break; + + if(Curl_pgrsUpdate(conn)) { + rc = CURLE_ABORTED_BY_CALLBACK; + timeout = -1; /* trigger the cancel below */ + } + else { + struct timeval now2 = Curl_tvnow(); + timediff = Curl_tvdiff(now2, now); /* spent time */ + timeout -= timediff?timediff:1; /* always deduct at least 1 */ + now = now2; /* for next loop */ + } + if(timeout < 0) { + /* our timeout, so we cancel the ares operation */ + ares_cancel((ares_channel)data->state.resolver); + break; + } + } + + /* Operation complete, if the lookup was successful we now have the entry + in the cache. */ + + if(entry) + *entry = conn->async.dns; + + if(!conn->async.dns) { + /* a name was not resolved */ + if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { + if (conn->bits.httpproxy) { + failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname); + rc = CURLE_COULDNT_RESOLVE_PROXY; + } + else { + failf(data, "Resolving host timed out: %s", conn->host.dispname); + rc = CURLE_COULDNT_RESOLVE_HOST; + } + } + else if(conn->async.done) { + if (conn->bits.httpproxy) { + failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname, + ares_strerror(conn->async.status)); + rc = CURLE_COULDNT_RESOLVE_PROXY; + } + else { + failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, + ares_strerror(conn->async.status)); + rc = CURLE_COULDNT_RESOLVE_HOST; + } + } + else + rc = CURLE_OPERATION_TIMEDOUT; + + /* close the connection, since we can't return failure here without + cleaning up this connection properly */ + conn->bits.close = TRUE; + } + + return rc; +} + +/* Connects results to the list */ +static void 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(), + * when using ares, is completed either successfully or with failure. + */ +static void query_completed_cb(void *arg, /* (struct connectdata *) */ + int status, +#ifdef HAVE_CARES_CALLBACK_TIMEOUTS + int timeouts, +#endif + struct hostent *hostent) +{ + struct connectdata *conn = (struct connectdata *)arg; + struct ResolverResults *res; + +#ifdef HAVE_CARES_CALLBACK_TIMEOUTS + (void)timeouts; /* ignored */ +#endif + + if(ARES_EDESTRUCTION == status) + /* when this ares handle is getting destroyed, the 'arg' pointer may not + be valid so only defer it when we know the 'status' says its fine! */ + return; + + res = (struct ResolverResults *)conn->async.os_specific; + res->num_pending--; + + if(CURL_ASYNC_SUCCESS == status) { + Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port); + if(ai) { + compound_results(res, ai); + } + } + /* A successful result overwrites any previous error */ + if( res->last_status != ARES_SUCCESS ) + res->last_status = status; +} + +/* + * Curl_resolver_getaddrinfo() - when using ares + * + * Returns name information about the given hostname and port number. If + * successful, the 'hostent' is returned and the forth argument will point to + * memory we need to free after use. That memory *MUST* be freed with + * Curl_freeaddrinfo(), nothing else. + */ +Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, + const char *hostname, + int port, + int *waitp) +{ + char *bufp; + struct SessionHandle *data = conn->data; + struct in_addr in; + int family = PF_INET; +#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ + struct in6_addr in6; +#endif /* CURLRES_IPV6 */ + + *waitp = 0; /* default to synchronous response */ + + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) { + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(AF_INET, &in, hostname, port); + } + +#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ + /* Otherwise, check if this is an IPv6 address string */ + if (Curl_inet_pton (AF_INET6, hostname, &in6) > 0) { + /* This must be an IPv6 address literal. */ + return Curl_ip2addr(AF_INET6, &in6, hostname, port); + } + + switch(conn->ip_version) { + default: +#if ARES_VERSION >= 0x010601 + family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older + c-ares versions this just falls through and defaults + to PF_INET */ + break; +#endif + case CURL_IPRESOLVE_V4: + family = PF_INET; + break; + case CURL_IPRESOLVE_V6: + family = PF_INET6; + break; + } +#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 */ + 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) { + res->num_pending = 2; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET, + query_completed_cb, conn); + ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET6, + query_completed_cb, conn); + } + else +#endif /* CURLRES_IPV6 */ + { + res->num_pending = 1; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.resolver, hostname, family, + query_completed_cb, conn); + } + + *waitp = 1; /* expect asynchronous response */ + } + return NULL; /* no struct yet */ +} +#endif /* CURLRES_ARES */ -- cgit v1.2.1 From b903186fa0189ff241d756d25d07fdfe9885ae49 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 20 Apr 2011 15:17:42 +0200 Subject: source cleanup: unify look, style and indent levels By the use of a the new lib/checksrc.pl script that checks that our basic source style rules are followed. --- lib/asyn-ares.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 6b71e0384..308ebdc4f 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -424,7 +424,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, if(!conn->async.dns) { /* a name was not resolved */ if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { - if (conn->bits.httpproxy) { + if(conn->bits.httpproxy) { failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname); rc = CURLE_COULDNT_RESOLVE_PROXY; } @@ -434,7 +434,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, } } else if(conn->async.done) { - if (conn->bits.httpproxy) { + if(conn->bits.httpproxy) { failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname, ares_strerror(conn->async.status)); rc = CURLE_COULDNT_RESOLVE_PROXY; @@ -542,10 +542,9 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ /* Otherwise, check if this is an IPv6 address string */ - if (Curl_inet_pton (AF_INET6, hostname, &in6) > 0) { + if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) /* This must be an IPv6 address literal. */ return Curl_ip2addr(AF_INET6, &in6, hostname, port); - } switch(conn->ip_version) { default: -- cgit v1.2.1 From 889d1e973fb718a77c5000141d724ce03863af23 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 22 Apr 2011 23:01:30 +0200 Subject: whitespace cleanup: no space first in conditionals "if(a)" is our style, not "if( a )" --- lib/asyn-ares.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 308ebdc4f..5710400bc 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -188,7 +188,7 @@ static void destroy_async_data (struct Curl_async *async); */ void Curl_resolver_cancel(struct connectdata *conn) { - if( conn && conn->data && conn->data->state.resolver ) + if(conn && conn->data && conn->data->state.resolver) ares_cancel((ares_channel)conn->data->state.resolver); destroy_async_data(&conn->async); } @@ -203,8 +203,8 @@ static void destroy_async_data (struct Curl_async *async) if(async->os_specific) { struct ResolverResults *res = (struct ResolverResults *)async->os_specific; - if( res ) { - if( res->temp_ai ) { + if(res) { + if(res->temp_ai) { Curl_freeaddrinfo(res->temp_ai); res->temp_ai = NULL; } @@ -329,7 +329,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, waitperform(conn, 0); - if( res && !res->num_pending ) { + 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 */ @@ -465,7 +465,7 @@ static void compound_results(struct ResolverResults *res, return; ai_tail = ai; - while (ai_tail->ai_next) + while(ai_tail->ai_next) ai_tail = ai_tail->ai_next; /* Add the new results to the list of old results. */ @@ -507,7 +507,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */ } } /* A successful result overwrites any previous error */ - if( res->last_status != ARES_SUCCESS ) + if(res->last_status != ARES_SUCCESS) res->last_status = status; } @@ -573,7 +573,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, conn->async.status = 0; /* clear */ conn->async.dns = NULL; /* clear */ res = (struct ResolverResults *)calloc(sizeof(struct ResolverResults),1); - if( !res ) { + if(!res) { Curl_safefree(conn->async.hostname); conn->async.hostname = NULL; return NULL; @@ -587,10 +587,10 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, res->num_pending = 2; /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET, - query_completed_cb, conn); - ares_gethostbyname((ares_channel)data->state.resolver, hostname, PF_INET6, - query_completed_cb, conn); + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET, query_completed_cb, conn); + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET6, query_completed_cb, conn); } else #endif /* CURLRES_IPV6 */ -- cgit v1.2.1 From fce7276f5446e7fc1003b98a9a752a3a42a0a247 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Sat, 21 May 2011 14:10:17 +0200 Subject: compiler warning: fix Fix compiler warning: enumerated type mixed with another type --- lib/asyn-ares.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 5710400bc..6027cc7ba 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -140,7 +140,7 @@ void Curl_resolver_global_cleanup(void) * 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) +CURLcode Curl_resolver_init(void **resolver) { int status = ares_init((ares_channel*)resolver); if(status != ARES_SUCCESS) { -- cgit v1.2.1 From 65a9fa59dcb442a23a8e01cdd1ee86d03f0b6957 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Thu, 2 Jun 2011 19:42:24 +0200 Subject: Remove unnecessary typecast --- lib/asyn-ares.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 6027cc7ba..4165a451d 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -572,7 +572,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, conn->async.done = FALSE; /* not done */ conn->async.status = 0; /* clear */ conn->async.dns = NULL; /* clear */ - res = (struct ResolverResults *)calloc(sizeof(struct ResolverResults),1); + res = calloc(sizeof(struct ResolverResults),1); if(!res) { Curl_safefree(conn->async.hostname); conn->async.hostname = NULL; -- cgit v1.2.1 From f1586cb4775681810afd8e6626e7842d459f3b85 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Tue, 26 Jul 2011 17:23:27 +0200 Subject: stdio.h, stdlib.h, string.h, stdarg.h and ctype.h inclusion done in setup_once.h --- lib/asyn-ares.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 4165a451d..7f3bdf8a2 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -22,8 +22,6 @@ #include "setup.h" -#include - #ifdef HAVE_LIMITS_H #include #endif @@ -39,16 +37,12 @@ #ifdef HAVE_ARPA_INET_H #include #endif -#ifdef HAVE_STDLIB_H -#include /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include /* for the close() proto */ #endif #ifdef __VMS #include #include -#include #endif #ifdef HAVE_PROCESS_H -- cgit v1.2.1 From 8d0a504f0d34c2471393ef23fb2345c73c5d4746 Mon Sep 17 00:00:00 2001 From: Jason Glasgow Date: Tue, 12 Apr 2011 11:34:28 -0400 Subject: CURLOPT_DNS_SERVERS: set name servers if possible --- lib/asyn-ares.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 7f3bdf8a2..7c2c372c3 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -600,4 +600,30 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, } return NULL; /* no struct yet */ } + +CURLcode Curl_set_dns_servers(struct SessionHandle *data, + char *servers) +{ + CURLcode result = CURLE_NOT_BUILT_IN; +#if (ARES_VERSION >= 0x010704) + int ares_result = ares_set_servers_csv(data->state.resolver, servers); + switch(ares_result) { + case ARES_SUCCESS: + break; + case ARES_ENOMEM: + result = CURLE_OUT_OF_MEMORY; + break; + case ARES_ENOTINITIALIZED: + case ARES_ENODATA: + case ARES_EBADSTR: + default: + result = CURLE_BAD_FUNCTION_ARGUMENT; + break; + } +#else /* too old c-ares version! */ + (void)data; + (void)servers; +#endif + return result; +} #endif /* CURLRES_ARES */ -- cgit v1.2.1 From adc88ca203bbb602cc9a1726669526fa7b3723ef Mon Sep 17 00:00:00 2001 From: Jason Glasgow Date: Wed, 30 Nov 2011 15:23:44 -0500 Subject: multi: handle timeouts on DNS servers by checking for new sockets If the first name server is not available, the multi interface does not invoke the socket_cb when the DNS request to the first name server timesout. Ensure that the list of sockets are always updated after calling Curl_resolver_is_resolved. This bug can be reproduced if Curl is complied with --enable_ares and your code uses the multi socket interfaces and the CURLMOPT_SOCKETFUNCTION option. To test try: iptables -I INPUT \ -s $(sed -n -e '/name/{s/.* //p;q}' /etc/resolv.conf)/32 \ -j REJECT and then run a program which uses the multi-interface. --- lib/asyn-ares.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 7c2c372c3..0b454849d 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -227,18 +227,19 @@ int Curl_resolver_getsock(struct connectdata *conn, struct timeval maxtime; struct timeval timebuf; struct timeval *timeout; + long milli; 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((ares_channel)conn->data->state.resolver, &maxtime, &timebuf); - - Curl_expire(conn->data, - (timeout->tv_sec * 1000) + (timeout->tv_usec/1000)); + milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000); + if(milli == 0) + milli += 10; + Curl_expire(conn->data, milli); return max; } -- cgit v1.2.1 From 62d3652b43124cb1d9b962acba05b41cd61f9343 Mon Sep 17 00:00:00 2001 From: Jason Glasgow Date: Wed, 30 Nov 2011 23:39:02 -0500 Subject: CURLOPT_DNS_SERVERS: set name servers if possible (fix) Ensure that CURLE_OK is returned if setting the name servers is successfull. --- lib/asyn-ares.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 0b454849d..1028583ca 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -610,6 +610,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, int ares_result = ares_set_servers_csv(data->state.resolver, servers); switch(ares_result) { case ARES_SUCCESS: + result = CURLE_OK; break; case ARES_ENOMEM: result = CURLE_OUT_OF_MEMORY; -- cgit v1.2.1 From 0cf05af744a76f2411ea907d8ec4e929bd945245 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 5 Dec 2011 12:41:38 +0100 Subject: c-ares: return proxy failure for all proxy types When making a distinction which return code to return, the code previously only regarded HTTP proxies to be proxies and thus return host-related errors for failures on other proxy types than HTTP. Now all proxy types will be considered proxies... --- lib/asyn-ares.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 1028583ca..f08a4d884 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -419,7 +419,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, if(!conn->async.dns) { /* a name was not resolved */ if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { - if(conn->bits.httpproxy) { + if(conn->bits.proxy) { failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname); rc = CURLE_COULDNT_RESOLVE_PROXY; } @@ -429,7 +429,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, } } else if(conn->async.done) { - if(conn->bits.httpproxy) { + if(conn->bits.proxy) { failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname, ares_strerror(conn->async.status)); rc = CURLE_COULDNT_RESOLVE_PROXY; -- cgit v1.2.1 From c50dbf670f5780db7658bb15f5d24c8706202584 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 5 Dec 2011 12:44:55 +0100 Subject: Curl_resolver_is_resolved: differentiate between host/proxy errors As there are different return codes for host vs proxy errors, this function now properly returns the code properly depending on what was attempted to get resolved. Bug: http://curl.haxx.se/mail/archive-2011-12/0010.html Reported by: Jason Liu --- lib/asyn-ares.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index f08a4d884..9f16e39f1 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -331,9 +331,12 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, res->temp_ai = NULL; destroy_async_data(&conn->async); if(!conn->async.dns) { - failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, + failf(data, "Could not resolve %s: %s (%s)", + conn->bits.proxy?"proxy":"host", + conn->host.dispname, ares_strerror(conn->async.status)); - return CURLE_COULDNT_RESOLVE_HOST; + return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: + CURLE_COULDNT_RESOLVE_HOST; } *dns = conn->async.dns; } -- cgit v1.2.1 From 97386c3c84251ca6a185916b28e61c100a901c1a Mon Sep 17 00:00:00 2001 From: Maxim Prohorov Date: Tue, 13 Mar 2012 22:52:39 +0100 Subject: resolve with c-ares: don't resolve IPv6 when not working If the Curl_ipv6works() function says no, there is no reason to try AAAA names even if libcurl was built with IPv6 support enabled. Bug: http://curl.haxx.se/mail/lib-2012-03/0045.html --- lib/asyn-ares.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 9f16e39f1..5b760128e 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -582,13 +582,22 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, res->last_status = ARES_ENOTFOUND; #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ if(family == PF_UNSPEC) { - res->num_pending = 2; + if(Curl_ipv6works()) { + res->num_pending = 2; + + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET, query_completed_cb, conn); + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET6, query_completed_cb, conn); + } + else { + res->num_pending = 1; - /* areschannel is already setup in the Curl_open() function */ - ares_gethostbyname((ares_channel)data->state.resolver, hostname, - PF_INET, query_completed_cb, conn); - ares_gethostbyname((ares_channel)data->state.resolver, hostname, - PF_INET6, query_completed_cb, conn); + /* areschannel is already setup in the Curl_open() function */ + ares_gethostbyname((ares_channel)data->state.resolver, hostname, + PF_INET, query_completed_cb, conn); + } } else #endif /* CURLRES_IPV6 */ -- cgit v1.2.1 From d1c769877a3eab3c88b5f3f55501d3c505e247c8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 23 Oct 2012 23:06:38 +0200 Subject: asyn-ares: restore working with c-ares < 1.6.1 Back in those days the public ares.h header didn't include the ares_version.h header so it needs to be included here. Bug: http://curl.haxx.se/bug/view.cgi?id=3577710 --- lib/asyn-ares.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/asyn-ares.c') diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 5b760128e..ee8050a6b 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -83,6 +83,8 @@ # define CARES_STATICLIB # endif # include +# include /* really old c-ares didn't include this by + itself */ #if ARES_VERSION >= 0x010500 /* c-ares 1.5.0 or later, the callback proto is modified */ -- cgit v1.2.1