void Curl_global_host_cache_dtor(void)
{
if(host_cache_initialized) {
- /* first make sure that any custom "CURLOPT_RESOLVE" names are
- cleared off */
- Curl_hostcache_clean(NULL, &hostname_cache);
- /* then free the remaining hash completely */
Curl_hash_clean(&hostname_cache);
host_cache_initialized = 0;
}
(struct hostcache_prune_data *) datap;
struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
- return !c->inuse && (data->now - c->timestamp >= data->cache_timeout);
+ return (0 != c->timestamp)
+ && (data->now - c->timestamp >= data->cache_timeout);
}
/*
{
struct hostcache_prune_data user;
- if(!dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache ||
- dns->inuse)
+ if(!dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
/* cache forever means never prune, and NULL hostcache means we can't do
- it, if it still is in use then we leave it */
+ it */
return 0;
time(&user.now);
return NULL;
}
- dns->inuse = 0; /* init to not used */
+ dns->inuse = 1; /* the cache has the first reference */
dns->addr = addr; /* this is the address(es) */
time(&dns->timestamp);
if(dns->timestamp == 0)
- dns->timestamp = 1; /* zero indicates that entry isn't in hash table */
+ dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */
/* Store the resolved data in our DNS cache. */
dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
*/
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
{
- DEBUGASSERT(dns && (dns->inuse>0));
-
if(data && data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- dns->inuse--;
- /* only free if nobody is using AND it is not in hostcache (timestamp ==
- 0) */
- if(dns->inuse == 0 && dns->timestamp == 0) {
- Curl_freeaddrinfo(dns->addr);
- free(dns);
- }
+ freednsentry(dns);
if(data && data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
/*
- * File-internal: free a cache dns entry.
+ * File-internal: release cache dns entry reference, free if inuse drops to 0
*/
static void freednsentry(void *freethis)
{
- struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
+ struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis;
+ DEBUGASSERT(dns && (dns->inuse>0));
- /* mark the entry as not in hostcache */
- p->timestamp = 0;
- if(p->inuse == 0) {
- Curl_freeaddrinfo(p->addr);
- free(p);
+ dns->inuse--;
+ if(dns->inuse == 0) {
+ Curl_freeaddrinfo(dns->addr);
+ free(dns);
}
}
return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
}
-static int hostcache_inuse(void *data, void *hc)
+static int free_all_entries(void *data, void *hc)
{
- struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
-
- if(c->inuse == 1)
- Curl_resolv_unlock(data, c);
-
+ (void)data;
+ (void)hc;
return 1; /* free all entries */
}
void Curl_hostcache_clean(struct SessionHandle *data,
struct curl_hash *hash)
{
- /* Entries added to the hostcache with the CURLOPT_RESOLVE function are
- * still present in the cache with the inuse counter set to 1. Detect them
- * and cleanup!
- */
- Curl_hash_clean_with_criterium(hash, data, hostcache_inuse);
+ if(data && data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ Curl_hash_clean_with_criterium(hash, NULL, free_all_entries);
+
+ if(data && data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
/* free the allocated entry_id again */
free(entry_id);
- if(!dns)
+ if(!dns) {
/* if not in the cache already, put this host in the cache */
dns = Curl_cache_addr(data, addr, hostname, port);
+ if(dns) {
+ dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
+ /* release the returned reference; the cache itself will keep the
+ * entry alive: */
+ dns->inuse--;
+ }
+ }
else
/* this is a duplicate, free it again */
Curl_freeaddrinfo(addr);