diff options
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | RELEASE-NOTES | 3 | ||||
-rw-r--r-- | lib/hash.c | 9 | ||||
-rw-r--r-- | lib/hostip.c | 46 | ||||
-rw-r--r-- | lib/hostip.h | 2 |
5 files changed, 44 insertions, 22 deletions
@@ -7,6 +7,12 @@ 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 diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 08d7215d8..89549d72e 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -16,6 +16,7 @@ This release includes the following bugfixes: 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: @@ -24,6 +25,6 @@ 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) diff --git a/lib/hash.c b/lib/hash.c index 6ca7431ce..bcd144a11 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -140,8 +140,8 @@ mk_hash_element(const void *key, size_t key_len, const void *p) #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) { @@ -152,8 +152,9 @@ 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; } } diff --git a/lib/hostip.c b/lib/hostip.c index 2ccb201c8..e40f1f11b 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -123,6 +123,10 @@ static struct curl_hash hostname_cache; static int host_cache_initialized; +#ifdef CURLDEBUG +static int ndns = 0; +#endif + static void freednsentry(void *freethis); /* @@ -232,14 +236,7 @@ hostcache_timestamp_remove(void *datap, void *hc) (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); } /* @@ -339,7 +336,6 @@ Curl_cache_addr(struct SessionHandle *data, 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); @@ -357,23 +353,22 @@ Curl_cache_addr(struct SessionHandle *data, 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); @@ -436,6 +431,7 @@ int Curl_resolv(struct connectdata *conn, if(dns) { dns->inuse++; /* we use it! */ + DEBUGF(ndns++); rc = CURLRESOLV_RESOLVED; } @@ -688,6 +684,13 @@ void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) 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); @@ -700,12 +703,21 @@ static void freednsentry(void *freethis) { 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. */ diff --git a/lib/hostip.h b/lib/hostip.h index 8b6bb76fb..b6aef623a 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -121,6 +121,8 @@ void Curl_global_host_cache_dtor(void); 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 */ |