diff --git a/include/curl/curl.h b/include/curl/curl.h index 3d91c85ffe0db7ca2176c6ff2351bc4d4c9e8a71..9059d14921d505326eb16b742f12c020cbe2d55c 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -491,6 +491,9 @@ typedef enum { /* Non-zero value means to use the global dns cache */ CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + CURLOPT_LASTENTRY /* the last unusued */ } CURLoption; diff --git a/lib/hostip.c b/lib/hostip.c index 9d0013ffe76b19b8f3d062aea35e6603b3b636aa..fc76242f7722d5829108e8f70febd4a61f45fc0b 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -93,24 +93,59 @@ void Curl_global_host_cache_dtor(void) } } +struct curl_dns_cache_entry { + Curl_addrinfo *addr; + int timestamp; +}; + Curl_addrinfo *Curl_resolv(struct SessionHandle *data, char *hostname, int port, char **bufp) { - Curl_addrinfo *addr = NULL; - size_t hostname_len = strlen(hostname)+1; + struct curl_dns_cache_entry *p = NULL; + size_t hostname_len; + time_t now; + + /* If the host cache timeout is 0, we don't do DNS cach'ing + so fall through */ + if (data->set.dns_cache_timeout == 0) { + return Curl_getaddrinfo(data, hostname, port, bufp); + } + + hostname_len = strlen(hostname)+1; + + time(&now); + /* See if its already in our dns cache */ + if (curl_hash_find(data->hostcache, hostname, hostname_len, (void **) &p)) { + /* Do we need to check for a cache timeout? */ + if (data->set.dns_cache_timeout != -1) { + /* Return if the entry has not timed out */ + if ((now - p->timestamp) < data->set.dns_cache_timeout) { + return p->addr; + } + } + else { + return p->addr; + } + } - if (curl_hash_find(data->hostcache, hostname, hostname_len, (void **) &addr)) { - return addr; + /* Create a new cache entry */ + p = (struct curl_dns_cache_entry *) malloc(sizeof(struct curl_dns_cache_entry)); + if (!p) { + return NULL; } - - addr = Curl_getaddrinfo(data, hostname, port, bufp); - if (!addr) + + p->addr = Curl_getaddrinfo(data, hostname, port, bufp); + if (!p->addr) { return NULL; + } + p->timestamp = now; - curl_hash_add(data->hostcache, hostname, hostname_len, (const void *) addr); - return addr; + /* Save it in our host cache */ + curl_hash_update(data->hostcache, hostname, hostname_len, (const void *) p); + + return p->addr; } /* @@ -120,11 +155,15 @@ Curl_addrinfo *Curl_resolv(struct SessionHandle *data, */ void Curl_freeaddrinfo(void *freethis) { + struct curl_dns_cache_entry *p = (struct curl_dns_cache_entry *) freethis; + #ifdef ENABLE_IPV6 - freeaddrinfo(freethis); + freeaddrinfo(p->addr); #else - free(freethis); + free(p->addr); #endif + + free(p); } /* --- resolve name or IP-number --- */ diff --git a/lib/url.c b/lib/url.c index 56e7fa73fbcd20e547f82944271ce80f6ad96b52..63d9ae56a81cda51ee7cafb0ed2c47a4c210c482 100644 --- a/lib/url.c +++ b/lib/url.c @@ -251,13 +251,15 @@ CURLcode Curl_open(struct SessionHandle **curl) data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */ data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ + data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + /* make libcurl quiet by default: */ data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ data->progress.flags |= PGRS_HIDE; /* Set the default size of the SSL session ID cache */ data->set.ssl.numsessions = 5; - + /* create an array with connection data struct pointers */ data->state.numconnects = 5; /* hard-coded right now */ data->state.connects = (struct connectdata **) @@ -284,7 +286,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) va_start(param, option); switch(option) { - case CURLOPT_DNS_USE_GLOBAL_CACHE: { + case CURLOPT_DNS_CACHE_TIMEOUT: + data->set.dns_cache_timeout = va_arg(param, int); + break; + case CURLOPT_DNS_USE_GLOBAL_CACHE: + { int use_cache = va_arg(param, int); if (use_cache) { Curl_global_host_cache_init(); diff --git a/lib/urldata.h b/lib/urldata.h index 36358d60f075436f38fc2f05002b431dbee32f30..64ee821ca697ee68663d423d10b16a0040f5bed8 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -647,6 +647,7 @@ struct UserDefined { bool ftp_use_epsv; /* if EPSV is to be attempted or not */ bool global_dns_cache; + bool dns_cache_timeout; }; /*