Changelog
Daniel Stenberg (11 Nov 2009)
+- Constantine Sapuntzakis posted bug #2891595
+ (http://curl.haxx.se/bug/view.cgi?id=2891595) which identified how an entry
+ in the DNS cache would linger too long if the request that added it was in
+ use that long. He also provided the patch that now makes libcurl capable of
+ still doing a request while the DNS hash entry may get timed out.
+
- Christian Schmitz noticed that the progress meter/callback was not properly
used during the FTP connection phase (after the actual TCP connect), while
it of course should be. I also made the speed check get called correctly so
o progress meter percentage and transfer time estimates fixes
o portability enhancement for OS's without orthogonal directory tree structure
o progress meter/callback during FTP connection
+ o DNS cache timeout while transfer in progress
This release includes the following known bugs:
This release would not have looked like this without help, code, reports and
advice from friends like these:
- Yang Tse, Kamil Dudka, Christian Schmitz
+ Yang Tse, Kamil Dudka, Christian Schmitz, Constantine Sapuntzakis
Thanks! (and sorry if I forgot to mention someone)
#define FETCH_LIST(x,y,z) x->table[x->hash_func(y, z, x->slots)]
-/* Return the data in the hash. If there already was a match in the hash,
- that data is returned. */
+/* Insert the data in the hash. If there already was a match in the hash,
+ that data is replaced. */
void *
Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
{
for (le = l->head; le; le = le->next) {
he = (struct curl_hash_element *) le->ptr;
if(h->comp_func(he->key, he->key_len, key, key_len)) {
- h->dtor(p); /* remove the NEW entry */
- return he->ptr; /* return the EXISTING entry */
+ Curl_llist_remove(l, le, (void *)h);
+ --h->size;
+ break;
}
}
static struct curl_hash hostname_cache;
static int host_cache_initialized;
+#ifdef CURLDEBUG
+static int ndns = 0;
+#endif
+
static void freednsentry(void *freethis);
/*
(struct hostcache_prune_data *) datap;
struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
- if((data->now - c->timestamp < data->cache_timeout) ||
- c->inuse) {
- /* please don't remove */
- return 0;
- }
-
- /* fine, remove */
- return 1;
+ return (data->now - c->timestamp >= data->cache_timeout);
}
/*
size_t entry_len;
struct Curl_dns_entry *dns;
struct Curl_dns_entry *dns2;
- time_t now;
/* Create an entry id, based upon the hostname and port */
entry_id = create_hostcache_id(hostname, port);
dns->inuse = 0; /* init to not used */
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 */
- /* Store the resolved data in our DNS cache. This function may return a
- pointer to an existing struct already present in the hash, and it may
- return the same argument we pass in. Make no assumptions. */
+ /* Store the resolved data in our DNS cache. */
dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
(void *)dns);
if(!dns2) {
- /* Major badness, run away. */
free(dns);
free(entry_id);
return NULL;
}
- time(&now);
- dns = dns2;
- dns->timestamp = now; /* used now */
+ dns = dns2;
dns->inuse++; /* mark entry as in-use */
+ DEBUGF(ndns++);
/* free the allocated entry_id again */
free(entry_id);
if(dns) {
dns->inuse++; /* we use it! */
+ DEBUGF(ndns++);
rc = CURLRESOLV_RESOLVED;
}
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns->inuse--;
+ DEBUGF(ndns--);
+ /* 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);
+ }
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
{
struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
- if(p) {
+ /* mark the entry as not in hostcache */
+ p->timestamp = 0;
+ if (p->inuse == 0) {
Curl_freeaddrinfo(p->addr);
free(p);
}
}
+#ifdef CURLDEBUG
+int curl_get_ndns(void)
+{
+ return ndns;
+}
+#endif
+
/*
* Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
*/
struct Curl_dns_entry {
Curl_addrinfo *addr;
+ /* timestamp == 0 -- entry not in hostcache
+ timestamp != 0 -- entry is in hostcache */
time_t timestamp;
long inuse; /* use-counter, make very sure you decrease this
when you're done using the address you received */