diff --git a/include/curl/curl.h b/include/curl/curl.h index 11574175d..3d91c85ff 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -488,6 +488,9 @@ typedef enum { */ CINIT(SSLENGINE_DEFAULT, LONG, 90), + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), + CURLOPT_LASTENTRY /* the last unusued */ } CURLoption; diff --git a/lib/easy.c b/lib/easy.c index c24eb9018..45de7e8d5 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -141,8 +141,6 @@ CURLcode curl_global_init(long flags) if (initialized) return CURLE_OK; - Curl_host_cache_init(); - if (flags & CURL_GLOBAL_SSL) Curl_SSL_init(); @@ -165,8 +163,8 @@ void curl_global_cleanup(void) if (!initialized) return; - Curl_host_cache_dtor(); - + Curl_global_host_cache_dtor(); + if (init_flags & CURL_GLOBAL_SSL) Curl_SSL_cleanup(); @@ -235,12 +233,24 @@ CURLcode curl_easy_perform(CURL *curl) { struct SessionHandle *data = (struct SessionHandle *)curl; + if (!data->hostcache) { + if (Curl_global_host_cache_use(data)) { + data->hostcache = Curl_global_host_cache_get(); + } + else { + data->hostcache = curl_hash_alloc(7, Curl_freeaddrinfo); + } + } + return Curl_perform(data); } void curl_easy_cleanup(CURL *curl) { struct SessionHandle *data = (struct SessionHandle *)curl; + if (!Curl_global_host_cache_use(data)) { + curl_hash_destroy(data->hostcache); + } Curl_close(data); } diff --git a/lib/hash.c b/lib/hash.c index c0680e488..1ed3cc21a 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -255,11 +255,22 @@ curl_hash_clean(curl_hash *h) h->table = NULL; } +size_t +curl_hash_count(curl_hash *h) +{ + return h->size; +} + void curl_hash_destroy(curl_hash *h) { + if (!h) { + return; + } + curl_hash_clean(h); free(h); + h = NULL; } /* diff --git a/lib/hash.h b/lib/hash.h index 420bb899f..66ef3dfeb 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -71,6 +71,7 @@ int curl_hash_extended_delete(curl_hash *h, char *str_key, unsigned int str_key_ int curl_hash_extended_find(curl_hash *h, char *str_key, unsigned int str_key_len, unsigned long num_key, void **p); void curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *)); +size_t curl_hash_count(curl_hash *h); void curl_hash_clean(curl_hash *h); void curl_hash_destroy(curl_hash *h); diff --git a/lib/hostip.c b/lib/hostip.c index db02b8681..791ee030c 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -70,17 +70,27 @@ #endif static curl_hash hostname_cache; +static int host_cache_initialized; -void Curl_host_cache_init(void) +void Curl_global_host_cache_init(void) { - curl_hash_init(&hostname_cache, 7, Curl_freeaddrinfo); + if (!host_cache_initialized) { + curl_hash_init(&hostname_cache, 7, Curl_freeaddrinfo); + host_cache_initialized = 1; + } } -void Curl_host_cache_dtor(void) +curl_hash *Curl_global_host_cache_get(void) { - curl_hash_clean(&hostname_cache); + return &hostname_cache; } +void Curl_global_host_cache_dtor(void) +{ + if (host_cache_initialized) { + curl_hash_clean(&hostname_cache); + } +} Curl_addrinfo *Curl_resolv(struct SessionHandle *data, char *hostname, @@ -90,14 +100,15 @@ Curl_addrinfo *Curl_resolv(struct SessionHandle *data, Curl_addrinfo *addr = NULL; size_t hostname_len = strlen(hostname)+1; - if (curl_hash_find(&hostname_cache, hostname, hostname_len, (void **) &addr)) + if (curl_hash_find(data->hostcache, hostname, hostname_len, (void **) &addr)) { return addr; - + } + addr = Curl_getaddrinfo(data, hostname, port, bufp); if (!addr) return NULL; - curl_hash_add(&hostname_cache, hostname, hostname_len, (const void *) addr); + curl_hash_add(data->hostcache, hostname, hostname_len, (const void *) addr); return addr; } @@ -405,3 +416,4 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, * vim600: fdm=marker * vim: et sw=2 ts=2 sts=2 tw=78 */ + diff --git a/lib/hostip.h b/lib/hostip.h index 97b50ae9d..0cc98b605 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -23,12 +23,17 @@ * $Id$ *****************************************************************************/ +#include "hash.h" + struct addrinfo; struct hostent; struct SessionHandle; -void Curl_host_cache_init(void); -void Curl_host_cache_dtor(void); +void Curl_global_host_cache_init(void); +void Curl_global_host_cache_dtor(void); +curl_hash *Curl_global_host_cache_get(void); + +#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache) Curl_addrinfo *Curl_resolv(struct SessionHandle *data, char *hostname, diff --git a/lib/multi.c b/lib/multi.c index b7ab209f5..bfd3949cb 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -82,7 +82,8 @@ struct Curl_multi { struct Curl_message *msgs; /* amount of messages in the queue */ int num_msgs; - + /* Hostname cache */ + curl_hash *hostcache; }; @@ -244,7 +245,6 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) easy=multi->easy.next; while(easy) { - switch(easy->state) { case CURLM_STATE_INIT: /* init this transfer. */ @@ -256,6 +256,17 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) } break; case CURLM_STATE_CONNECT: + if (Curl_global_host_cache_use(easy->easy_handle)) { + easy->easy_handle->hostcache = Curl_global_host_cache_get(); + } + else { + if (multi->hostcache == NULL) { + multi->hostcache = curl_hash_alloc(7, Curl_freeaddrinfo); + } + + easy->easy_handle->hostcache = multi->hostcache; + } + /* Connect. We get a connection identifier filled in. */ easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn); @@ -328,7 +339,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) struct Curl_multi *multi=(struct Curl_multi *)multi_handle; if(GOOD_MULTI_HANDLE(multi)) { multi->type = 0; /* not good anymore */ - + curl_hash_destroy(multi->hostcache); /* remove all easy handles */ free(multi); @@ -341,3 +352,10 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue); +/* + * local variables: + * eval: (load-file "../curl-mode.el") + * end: + * vim600: fdm=marker + * vim: et sw=2 ts=2 sts=2 tw=78 + */ diff --git a/lib/url.c b/lib/url.c index 5f7568005..56e7fa73f 100644 --- a/lib/url.c +++ b/lib/url.c @@ -284,6 +284,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) va_start(param, option); switch(option) { + case CURLOPT_DNS_USE_GLOBAL_CACHE: { + int use_cache = va_arg(param, int); + if (use_cache) { + Curl_global_host_cache_init(); + } + + data->set.global_dns_cache = use_cache; + } + break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ data->set.ssl.cipher_list = va_arg(param, char *); diff --git a/lib/urldata.h b/lib/urldata.h index b7f3a2f21..36358d60f 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -27,6 +27,7 @@ #include "setup.h" #include "hostip.h" +#include "hash.h" #define PORT_FTP 21 #define PORT_TELNET 23 @@ -644,6 +645,8 @@ struct UserDefined { bool reuse_fresh; /* do not re-use an existing connection */ bool expect100header; /* TRUE if we added Expect: 100-continue */ bool ftp_use_epsv; /* if EPSV is to be attempted or not */ + + bool global_dns_cache; }; /* @@ -658,6 +661,7 @@ struct UserDefined { * 'struct urlstate' instead. */ struct SessionHandle { + curl_hash *hostcache; struct UserDefined set; /* values set by the libcurl user */ struct DynamicStatic change; /* possibly modified userdefined data */