Patch for 7.21.3 is applied. All available tests for asynch resolvers
are passed on my host (Linux Ubuntu), threaded as well as c-ares. Now
the only few files depend on c-ares, and all of them are really depend
on it, like version.c f.e. ... except easy.c, which contains
never-evaluated #ifdef. Anyway, resolver customizing can now be isolated
in curl_config.h, setup.h, and host....c files.
Probably more intensive memory-loss and early-stage-request-cancelation
tests are required ...
Regards,
Vsevolod
10.01.2011 11:24, Daniel Stenberg пишет:
On Mon, 10 Jan 2011, Vsevolod Novikov wrote:
Suggestions.
Thank you!
[cut]
Yes, by making a (cleaner) internal API for async resolvers we could
indeed make it much easier for people such as you to add custom ones.
Your suggestion seems fair and even if I didn't review all the
details, I think I agree with the general concept.
Of course, this is just a theory exercise until somebody actually
steps up and produces code that adapts what we have to this/a new
internal API. We did a cleanup of the SSL backend situation a while
back in a similar spirit and that cleaned up a lot.
We don't have any outstanding bugs in our resolver code, for any of
the backends, and we have very few users wanting to use a custom one
so there's not a large push to make this happen.
Feel free to start working on this overhaul, I will certainly assist
and review code and whatever as much as I can.
diff -r -u curl-7.21.3.orig/lib/easy.c curl-7.21.3/lib/easy.c
--- curl-7.21.3.orig/lib/easy.c 2010-12-07 16:52:44.000000000 +0300
+++ curl-7.21.3/lib/easy.c 2011-01-22 17:38:30.000000000 +0300
@@ -692,13 +692,6 @@
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))
- goto fail;
-#endif
-
#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
CURL_ICONV_CODESET_OF_NETWORK);
diff -r -u curl-7.21.3.orig/lib/hostares.c curl-7.21.3/lib/hostares.c
--- curl-7.21.3.orig/lib/hostares.c 2010-12-06 01:17:39.000000000 +0300
+++ curl-7.21.3/lib/hostares.c 2011-01-22 17:45:44.000000000 +0300
@@ -86,6 +86,55 @@
#ifdef CURLRES_ARES
+#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
+
+struct ares_data {
+ ares_channel areschannel;
+};
+
+static struct ares_data * conn_ares_data(struct connectdata *conn)
+{
+ return (struct ares_data *)conn->async.os_specific;
+}
+
+static ares_channel conn_ares_channel(struct connectdata *conn)
+{
+ return conn_ares_data(conn)->areschannel;
+}
+
+/* Destroy ares data */
+static
+void destroy_ares_data(struct ares_data * tsd)
+{
+ if (tsd->areschannel)
+ ares_destroy(tsd->areschannel);
+
+ memset(tsd,0,sizeof(*tsd));
+}
+
+/* Initialize ares resolver data */
+static
+int init_ares_data(struct ares_data * tsd)
+{
+ int status;
+ memset(tsd, 0, sizeof(*tsd));
+ if((status = ares_init(&tsd->areschannel)) != ARES_SUCCESS) {
+ DEBUGF(fprintf(stderr, "Error: ares_init failed\n"));
+ if(status == ARES_ENOMEM)
+ return CURLE_OUT_OF_MEMORY;
+ else
+ return CURLE_FAILED_INIT;
+ }
+
+ return CURLE_OK;
+}
+
/*
* Curl_resolv_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
@@ -103,14 +152,14 @@
struct timeval maxtime;
struct timeval timebuf;
struct timeval *timeout;
- int max = ares_getsock(conn->data->state.areschannel,
+ int max = ares_getsock(conn_ares_channel(conn),
(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(conn_ares_channel(conn), &maxtime, &timebuf);
Curl_expire(conn->data,
(timeout->tv_sec * 1000) + (timeout->tv_usec/1000));
@@ -130,7 +179,6 @@
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];
@@ -138,7 +186,7 @@
int i;
int num = 0;
- bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM);
+ bitmask = ares_getsock(conn_ares_channel(conn), socks, ARES_GETSOCK_MAXNUM);
for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
pfd[i].events = 0;
@@ -165,11 +213,11 @@
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(conn_ares_channel(conn), 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(conn_ares_channel(conn),
pfd[i].revents & (POLLRDNORM|POLLIN)?
pfd[i].fd:ARES_SOCKET_BAD,
pfd[i].revents & (POLLWRNORM|POLLOUT)?
@@ -196,6 +244,7 @@
if(conn->async.done) {
/* we're done, kill the ares handle */
+ Curl_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));
@@ -208,6 +257,24 @@
}
/*
+ * Curl_destroy_async_data() cleans up async resolver data and thread handle.
+ * Complementary of ares_destroy.
+ */
+void Curl_destroy_async_data (struct Curl_async *async)
+{
+ if(async->hostname)
+ free(async->hostname);
+
+ if(async->os_specific) {
+ destroy_ares_data(async->os_specific);
+ free(async->os_specific);
+ }
+
+ async->hostname = NULL;
+ async->os_specific = NULL;
+}
+
+/*
* Curl_wait_for_resolv() waits for a resolve to finish. This function should
* be avoided since using this risk getting the multi interface to "hang".
*
@@ -240,7 +307,7 @@
store.tv_sec = itimeout/1000;
store.tv_usec = (itimeout%1000)*1000;
- tvp = ares_timeout(data->state.areschannel, &store, &tv);
+ tvp = ares_timeout(conn_ares_channel(conn), &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
@@ -267,11 +334,13 @@
}
if(timeout < 0) {
/* our timeout, so we cancel the ares operation */
- ares_cancel(data->state.areschannel);
+ ares_cancel(conn_ares_channel(conn));
break;
}
}
+ Curl_destroy_async_data(&conn->async);
+
/* Operation complete, if the lookup was successful we now have the entry
in the cache. */
@@ -353,7 +422,6 @@
int *waitp)
{
char *bufp;
- struct SessionHandle *data = conn->data;
struct in_addr in;
int family = PF_INET;
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
@@ -402,8 +470,10 @@
conn->async.status = 0; /* clear */
conn->async.dns = NULL; /* clear */
- /* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname(data->state.areschannel, hostname, family,
+ /* areschannel is NOT setup in the Curl_open() function NOW !!! */
+ conn->async.os_specific = calloc(1,sizeof(struct ares_data));
+ init_ares_data(conn->async.os_specific);
+ ares_gethostbyname(conn_ares_channel(conn), hostname, family,
(ares_host_callback)ares_query_completed_cb, conn);
*waitp = 1; /* expect asynchronous response */
diff -r -u curl-7.21.3.orig/lib/hostip.h curl-7.21.3/lib/hostip.h
--- curl-7.21.3.orig/lib/hostip.h 2010-11-11 17:16:21.000000000 +0300
+++ curl-7.21.3/lib/hostip.h 2011-01-22 17:38:58.000000000 +0300
@@ -39,10 +39,6 @@
* 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
@@ -53,16 +49,8 @@
#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
+#ifdef CURLRES_ASYNCH
#define CURL_ASYNC_SUCCESS CURLE_OK
-#define ares_cancel(x) do {} while(0)
-#define ares_destroy(x) do {} while(0)
#endif
struct addrinfo;
@@ -195,11 +183,10 @@
const char *hostname, int port);
/*
- * Curl_destroy_thread_data() cleans up async resolver data.
- * Complementary of ares_destroy.
+ * Curl_destroy_async_data() cleans up async resolver data.
*/
struct Curl_async; /* forward-declaration */
-void Curl_destroy_thread_data(struct Curl_async *async);
+void Curl_destroy_async_data(struct Curl_async *async);
#ifndef INADDR_NONE
#define CURL_INADDR_NONE (in_addr_t) ~0
diff -r -u curl-7.21.3.orig/lib/hostthre.c curl-7.21.3/lib/hostthre.c
--- curl-7.21.3.orig/lib/hostthre.c 2010-11-11 17:16:21.000000000 +0300
+++ curl-7.21.3/lib/hostthre.c 2011-01-22 13:21:23.000000000 +0300
@@ -253,10 +253,10 @@
#endif /* HAVE_GETADDRINFO */
/*
- * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
+ * Curl_destroy_async_data() cleans up async resolver data and thread handle.
* Complementary of ares_destroy.
*/
-void Curl_destroy_thread_data (struct Curl_async *async)
+void Curl_destroy_async_data (struct Curl_async *async)
{
if(async->hostname)
free(async->hostname);
@@ -336,7 +336,7 @@
return TRUE;
err_exit:
- Curl_destroy_thread_data(&conn->async);
+ Curl_destroy_async_data(&conn->async);
SET_ERRNO(err);
@@ -386,7 +386,7 @@
}
}
- Curl_destroy_thread_data(&conn->async);
+ Curl_destroy_async_data(&conn->async);
if(!conn->async.dns)
conn->bits.close = TRUE;
@@ -419,7 +419,7 @@
if (done) {
getaddrinfo_complete(conn);
- Curl_destroy_thread_data(&conn->async);
+ Curl_destroy_async_data(&conn->async);
if(!conn->async.dns) {
failf(data, "Could not resolve host: %s; %s",
diff -r -u curl-7.21.3.orig/lib/url.c curl-7.21.3/lib/url.c
--- curl-7.21.3.orig/lib/url.c 2010-12-15 12:04:43.000000000 +0300
+++ curl-7.21.3/lib/url.c 2011-01-22 17:52:04.000000000 +0300
@@ -555,9 +555,6 @@
Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect);
- /* this destroys the channel and we cannot use it anymore after this */
- ares_destroy(data->state.areschannel);
-
#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
/* close iconv conversion descriptors */
if(data->inbound_cd != (iconv_t)-1) {
@@ -804,9 +801,6 @@
{
CURLcode res = CURLE_OK;
struct SessionHandle *data;
-#ifdef USE_ARES
- int status;
-#endif
/* Very simple start-up: alloc the struct, init it with zeroes and return */
data = calloc(1, sizeof(struct SessionHandle));
@@ -818,19 +812,6 @@
data->magic = CURLEASY_MAGIC_NUMBER;
-#ifdef USE_ARES
- if((status = ares_init(&data->state.areschannel)) != ARES_SUCCESS) {
- DEBUGF(fprintf(stderr, "Error: ares_init failed\n"));
- free(data);
- if(status == ARES_ENOMEM)
- return CURLE_OUT_OF_MEMORY;
- else
- return CURLE_FAILED_INIT;
- }
- /* make sure that all other returns from this function should destroy the
- ares channel before returning error! */
-#endif
-
/* We do some initial setup here, all those fields that can't be just 0 */
data->state.headerbuff = malloc(HEADERSIZE);
@@ -866,7 +847,6 @@
}
if(res) {
- ares_destroy(data->state.areschannel);
if(data->state.headerbuff)
free(data->state.headerbuff);
Curl_freeset(data);
@@ -2575,11 +2555,8 @@
Curl_llist_destroy(conn->done_pipe, NULL);
/* possible left-overs from the async name resolvers */
-#if defined(CURLRES_THREADED)
- Curl_destroy_thread_data(&conn->async);
-#elif defined(CURLRES_ASYNCH)
- Curl_safefree(conn->async.hostname);
- Curl_safefree(conn->async.os_specific);
+#if defined(CURLRES_ASYNCH)
+ Curl_destroy_async_data(&conn->async);
#endif
Curl_free_ssl_config(&conn->ssl_config);
@@ -5210,10 +5187,6 @@
data->state.tempwrite = NULL;
}
- /* for ares-using, make sure all possible outstanding requests are properly
- cancelled before we proceed */
- ares_cancel(data->state.areschannel);
-
/* if data->set.reuse_forbid is TRUE, it means the libcurl client has
forced us to close this no matter what we think.
diff -r -u curl-7.21.3.orig/lib/urldata.h curl-7.21.3/lib/urldata.h
--- curl-7.21.3.orig/lib/urldata.h 2010-12-15 16:49:10.000000000 +0300
+++ curl-7.21.3/lib/urldata.h 2011-01-22 17:41:15.000000000 +0300
@@ -134,14 +134,6 @@
#endif
#endif
-#ifdef USE_ARES
-# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
- (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
-# define CARES_STATICLIB
-# endif
-# include <ares.h>
-#endif
-
#include <curl/curl.h>
#include "http_chunks.h" /* for the structs and enum stuff */
@@ -1115,10 +1107,6 @@
bool authproblem; /* TRUE if there's some problem authenticating */
-#ifdef USE_ARES
- ares_channel areschannel; /* for name resolves */
-#endif
-
#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
ENGINE *engine;
#endif /* USE_SSLEAY */
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html