diff options
| author | Vsevolod Novikov <novikov@doroga.tv> | 2011-01-29 20:12:10 +0100 | 
|---|---|---|
| committer | Daniel Stenberg <daniel@haxx.se> | 2011-04-25 19:47:16 +0200 | 
| commit | ca015f1a45c68aa1d641678cfc13ce0df0c58fe0 (patch) | |
| tree | 7e74d24a9eec1aeb541c84359257326b5f938ff4 | |
| parent | 722f286f801e456c790cec0ea10306220d4969e2 (diff) | |
asynch resolvers: unified
Introducing an internal API for handling of different async resolver
backends.
| -rw-r--r-- | lib/easy.c | 19 | ||||
| -rw-r--r-- | lib/hostares.c | 227 | ||||
| -rw-r--r-- | lib/hostasyn.c | 75 | ||||
| -rw-r--r-- | lib/hostip.h | 79 | ||||
| -rw-r--r-- | lib/hostip4.c | 1 | ||||
| -rw-r--r-- | lib/hostsyn.c | 55 | ||||
| -rw-r--r-- | lib/hostthre.c | 75 | ||||
| -rw-r--r-- | lib/url.c | 27 | ||||
| -rw-r--r-- | lib/urldata.h | 14 | ||||
| -rw-r--r-- | lib/version.c | 2 | 
10 files changed, 393 insertions, 181 deletions
diff --git a/lib/easy.c b/lib/easy.c index 05d8ded9d..9ce80d086 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -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)) { @@ -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(); @@ -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)) -    goto fail; -#endif +  /* Clone the resolver handle, if present, for the new handle */ +  if( Curl_resolver_duphandle(&outcurl->state.resolver, data->state.resolver) != CURLE_OK ) +   goto fail;    Curl_convert_setup(outcurl); diff --git a/lib/hostares.c b/lib/hostares.c index a165cb91f..1b6978d51 100644 --- a/lib/hostares.c +++ b/lib/hostares.c @@ -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" @@ -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 @@ -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)); @@ -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; @@ -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)? @@ -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)); @@ -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) @@ -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 @@ -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; @@ -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;      }    } @@ -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(), @@ -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 +  /* 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;  }  /* @@ -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);      } diff --git a/lib/hostasyn.c b/lib/hostasyn.c index 710ff50b7..5269c08dc 100644 --- a/lib/hostasyn.c +++ b/lib/hostasyn.c @@ -73,20 +73,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!).   * @@ -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); @@ -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; diff --git a/lib/hostip.h b/lib/hostip.h index a7c334568..70ce7cd74 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -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 @@ -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 @@ -129,6 +105,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   * name resolve layers (selected at build-time). They all take this same set @@ -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, @@ -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 diff --git a/lib/hostip4.c b/lib/hostip4.c index 6dc525765..67aefda29 100644 --- a/lib/hostip4.c +++ b/lib/hostip4.c @@ -87,6 +87,7 @@ bool Curl_ipvalid(struct connectdata *conn)  }  #ifdef CURLRES_SYNCH +  /*   * Curl_getaddrinfo() - the ipv4 synchronous version.   * diff --git a/lib/hostsyn.c b/lib/hostsyn.c index b68e4702e..799aa6991 100644 --- a/lib/hostsyn.c +++ b/lib/hostsyn.c @@ -73,6 +73,61 @@  #ifdef CURLRES_SYNCH  /* + * Curl_resolver_global_init() - the generic low-level name resolve API. + * Called from curl_global_init() to initialize global resolver environment. + * Does nothing here. + */ +int Curl_resolver_global_init() +{ +  return CURLE_OK; +} + +/* + * Curl_resolver_global_cleanup() - the generic low-level name resolve API. + * Called from curl_global_cleanup() to destroy global resolver environment. + * Does nothing here. + */ +void Curl_resolver_global_cleanup() +{ +} + +/* + * 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). + * Does nothing here. + */ +int Curl_resolver_init(void **resolver) +{ +  (void)resolver; +  return CURLE_OK; +} + +/* + * 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). + * Does nothing here. + */ +void Curl_resolver_cleanup(void *resolver) +{ +  (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). + * Does nothing here. + */ +int Curl_resolver_duphandle(void **to, void *from) +{ +  (void)to; +  (void)from; +  return CURLE_OK; +} + +/*   * Curl_wait_for_resolv() for synch-builds.  Curl_resolv() can never return   * wait==TRUE, so this function will never be called. If it still gets called,   * we return failure at once. diff --git a/lib/hostthre.c b/lib/hostthre.c index dc8e4af74..d91a5d77c 100644 --- a/lib/hostthre.c +++ b/lib/hostthre.c @@ -88,6 +88,70 @@   **********************************************************************/  #ifdef CURLRES_THREADED +/* + * Curl_resolver_global_init() - the generic low-level name resolve API. + * Called from curl_global_init() to initialize global resolver environment. + * Does nothing here. + */ +int Curl_resolver_global_init() +{ +  return CURLE_OK; +} + +/* + * Curl_resolver_global_cleanup() - the generic low-level name resolve API. + * Called from curl_global_cleanup() to destroy global resolver environment. + * Does nothing here. + */ +void Curl_resolver_global_cleanup() +{ +} + +/* + * 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). + * Does nothing here. + */ +int Curl_resolver_init(void **resolver) +{ +  (void)resolver; +  return CURLE_OK; +} + +/* + * 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). + * Does nothing here. + */ +void Curl_resolver_cleanup(void *resolver) +{ +  (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). + * Does nothing here. + */ +int Curl_resolver_duphandle(void **to, void *from) +{ +  (void)to; +  (void)from; +  return CURLE_OK; +} + +static void destroy_async_data(struct Curl_async *); +/* + * Cancel all possibly still on-going resolves for this connection. + */ +void Curl_async_cancel(struct connectdata *conn) +{ +  destroy_async_data(&conn->async); +} +  /* This function is used to init a threaded resolve */  static bool init_resolve_thread(struct connectdata *conn,                                  const char *hostname, int port, @@ -253,10 +317,9 @@ static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)  #endif /* HAVE_GETADDRINFO */  /* - * Curl_destroy_thread_data() cleans up async resolver data and thread handle. - * Complementary of ares_destroy. + * destroy_async_data() cleans up async resolver data and thread handle.   */ -void Curl_destroy_thread_data (struct Curl_async *async) +static void destroy_async_data (struct Curl_async *async)  {    if(async->hostname)      free(async->hostname); @@ -336,7 +399,7 @@ static bool init_resolve_thread (struct connectdata *conn,    return TRUE;   err_exit: -  Curl_destroy_thread_data(&conn->async); +  destroy_async_data(&conn->async);    SET_ERRNO(err); @@ -386,7 +449,7 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,      }    } -  Curl_destroy_thread_data(&conn->async); +  destroy_async_data(&conn->async);    if(!conn->async.dns)      conn->bits.close = TRUE; @@ -419,7 +482,7 @@ CURLcode Curl_is_resolved(struct connectdata *conn,    if (done) {      getaddrinfo_complete(conn); -    Curl_destroy_thread_data(&conn->async); +    destroy_async_data(&conn->async);      if(!conn->async.dns) {        failf(data, "Could not resolve host: %s; %s", @@ -526,7 +526,7 @@ CURLcode Curl_close(struct SessionHandle *data)    Curl_safefree(data->info.wouldredirect);    /* this destroys the channel and we cannot use it anymore after this */ -  ares_destroy(data->state.areschannel); +  Curl_resolver_cleanup(data->state.resolver);    Curl_convert_close(data); @@ -766,9 +766,7 @@ CURLcode Curl_open(struct SessionHandle **curl)  {    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)); @@ -780,18 +778,11 @@ CURLcode Curl_open(struct SessionHandle **curl)    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")); +  if( (status=Curl_resolver_init(&data->state.resolver)) != CURLE_OK ) { +    DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));      free(data); -    if(status == ARES_ENOMEM) -      return CURLE_OUT_OF_MEMORY; -    else -      return CURLE_FAILED_INIT; +    return status;    } -  /* 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 */ @@ -823,7 +814,7 @@ CURLcode Curl_open(struct SessionHandle **curl)    }    if(res) { -    ares_destroy(data->state.areschannel); +    Curl_resolver_cleanup(data->state.resolver);      if(data->state.headerbuff)        free(data->state.headerbuff);      Curl_freeset(data); @@ -2521,6 +2512,11 @@ static void conn_free(struct connectdata *conn)    if(!conn)      return; +  /* possible left-overs from the async name resolvers */ +#if defined(CURLRES_ASYNCH) +  Curl_async_cancel(conn); +#endif +    /* close the SSL stuff before we close any sockets since they will/may       write to the sockets */    Curl_ssl_close(conn, FIRSTSOCKET); @@ -2564,6 +2560,7 @@ static void conn_free(struct connectdata *conn)    Curl_safefree(conn->async.os_specific);  #endif    Curl_safefree(conn->localdev); +    Curl_free_ssl_config(&conn->ssl_config);    free(conn); /* free all the connection oriented data */ @@ -5195,7 +5192,9 @@ CURLcode Curl_done(struct connectdata **connp,      data->req.location = NULL;    } +#if defined(CURLRES_ASYNCH)    Curl_async_cancel(conn); +#endif    if(conn->dns_entry) {      Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ diff --git a/lib/urldata.h b/lib/urldata.h index c77cc34da..01f4ffddf 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -145,14 +145,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 */ @@ -508,8 +500,6 @@ struct Curl_async {    bool done;  /* set TRUE when the lookup is complete */    int status; /* if done is TRUE, this is the status from the callback */    void *os_specific;  /* 'struct thread_data' for Windows */ -  int num_pending; /* number of ares_gethostbyname() requests */ -  Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */  };  #endif @@ -1153,9 +1143,7 @@ struct UrlState {    bool authproblem; /* TRUE if there's some problem authenticating */ -#ifdef USE_ARES -  ares_channel areschannel; /* for name resolves */ -#endif +  void *resolver; /* resolver state, if it is used in the URL state - ares_channel f.e. */  #if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)    ENGINE *engine; diff --git a/lib/version.c b/lib/version.c index 97dd16395..7c19c9c80 100644 --- a/lib/version.c +++ b/lib/version.c @@ -33,7 +33,7 @@  #include <curl/mprintf.h>  #ifdef USE_ARES -#include <ares_version.h> +#include <ares.h>  #endif  #ifdef USE_LIBIDN  | 
