diff --git a/lib/hash.c b/lib/hash.c index dd2f00b6a..a262b2a44 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -249,6 +249,26 @@ curl_hash_clean(curl_hash *h) } /* }}} */ +/* {{{ void curl_hash_clean_with_criterium (curl_hash *, void *, int (*)(void *, void *)) + */ +void +curl_hash_clean_with_criterium(curl_hash *h, void *user, int (*comp)(void *, void *)) +{ + curl_llist_element *le; + int i; + + for (i = 0; i < h->slots; ++i) { + for (le = CURL_LLIST_HEAD(h->table[i]); + le != NULL; + le = CURL_LLIST_NEXT(le)) { + if (comp(user, ((curl_hash_element *) CURL_LLIST_VALP(le))->ptr)) { + curl_llist_remove(h->table[i], le, (void *) h); + --h->size; + } + } + } +} + /* {{{ int curl_hash_count (curl_hash *) */ int diff --git a/lib/hash.h b/lib/hash.h index 6c74ed2d3..9f4557639 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -53,6 +53,7 @@ int curl_hash_find(curl_hash *, char *, size_t, void **p); void curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *)); int curl_hash_count(curl_hash *h); void curl_hash_clean(curl_hash *h); +void curl_hash_clean_with_criterium(curl_hash *h, void *user, int (*comp)(void *, void *)); void curl_hash_destroy(curl_hash *h); #define curl_hash_update curl_hash_add diff --git a/lib/hostip.c b/lib/hostip.c index 356b93015..e3daab1ff 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -152,6 +152,38 @@ _create_hostcache_id(char *server, int port, ssize_t *entry_len) return id; } +struct _curl_hostcache_prune_data { + int cache_timeout; + int now; +}; + +static int +_curl_hostcache_timestamp_remove(void *datap, void *hc) +{ + struct _curl_hostcache_prune_data *data = + (struct _curl_hostcache_prune_data *) datap; + struct curl_dns_cache_entry *c = (struct curl_dns_cache_entry *) hc; + + if (data->now - c->timestamp < data->cache_timeout) { + return 0; + } + + return 1; +} + +static void +_curl_hostcache_prune(curl_hash *hostcache, int cache_timeout, int now) +{ + struct _curl_hostcache_prune_data user; + + user.cache_timeout = cache_timeout; + user.now = now; + + curl_hash_clean_with_criterium(hostcache, + (void *) &user, + _curl_hostcache_timestamp_remove); +} + /* Macro to save redundant free'ing of entry_id */ #define _hostcache_return(__v) \ { \ @@ -175,6 +207,13 @@ Curl_addrinfo *Curl_resolv(struct SessionHandle *data, return Curl_getaddrinfo(data, hostname, port, bufp); } + time(&now); + + /* Remove outdated entries from the hostcache */ + _curl_hostcache_prune(data->hostcache, + data->set.dns_cache_timeout, + now); + /* Create an entry id, based upon the hostname and port */ entry_len = strlen(hostname); entry_id = _create_hostcache_id(hostname, port, &entry_len); @@ -184,19 +223,9 @@ Curl_addrinfo *Curl_resolv(struct SessionHandle *data, return Curl_getaddrinfo(data, hostname, port, bufp); } - time(&now); /* See if its already in our dns cache */ if (entry_id && curl_hash_find(data->hostcache, entry_id, entry_len+1, (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) { - _hostcache_return(p->addr); - } - } - else { - _hostcache_return(p->addr); - } + _hostcache_return(p->addr); } /* Create a new cache entry */