summaryrefslogtreecommitdiff
path: root/lib/hostip.c
diff options
context:
space:
mode:
authorMichael Wallner <mike@php.net>2014-08-20 23:31:53 +0200
committerDaniel Stenberg <daniel@haxx.se>2014-08-31 10:49:40 +0200
commit09b5a99816a24a12f769f61db5f7eafd4bc32795 (patch)
tree1b91304501ae6eed8c832ec140acce4dfceeb4ab /lib/hostip.c
parent2434a4e88de35a0c7eced46f010292e2b4bfb851 (diff)
downloadcurl-09b5a99816a24a12f769f61db5f7eafd4bc32795.tar.gz
resolve: cache lookup for async resolvers
While waiting for a host resolve, check if the host cache may have gotten the name already (by someone else), for when the same name is resolved by several simultanoues requests. The resolver thread occasionally gets stuck in getaddrinfo() when the DNS or anything else is crappy or slow, so when a host is found in the DNS cache, leave the thread alone and let itself cleanup the mess.
Diffstat (limited to 'lib/hostip.c')
-rw-r--r--lib/hostip.c71
1 files changed, 48 insertions, 23 deletions
diff --git a/lib/hostip.c b/lib/hostip.c
index 61d238acd..73b3f8201 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -318,6 +318,48 @@ remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
sigjmp_buf curl_jmpenv;
#endif
+/*
+ * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
+ *
+ * Curl_resolv() checks initially and multi_runsingle() checks each time
+ * it discovers the handle in the state WAITRESOLVE whether the hostname
+ * has already been resolved and the address has already been stored in
+ * the DNS cache. This short circuits waiting for a lot of pending
+ * lookups for the same hostname requested by different handles.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
+ */
+struct Curl_dns_entry *
+Curl_fetch_addr(struct connectdata *conn,
+ const char *hostname,
+ int port, int *stale)
+{
+ char *entry_id = NULL;
+ struct Curl_dns_entry *dns = NULL;
+ size_t entry_len;
+ struct SessionHandle *data = conn->data;
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id)
+ return dns;
+
+ entry_len = strlen(entry_id);
+
+ /* See if its already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+
+ /* free the allocated entry_id again */
+ free(entry_id);
+
+ /* See whether the returned entry is stale. Done before we release lock */
+ *stale = remove_entry_if_stale(data, dns);
+ if(*stale)
+ dns = NULL; /* the memory deallocation is being handled by the hash */
+
+ return dns;
+}
/*
* Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
@@ -403,39 +445,22 @@ int Curl_resolv(struct connectdata *conn,
int port,
struct Curl_dns_entry **entry)
{
- char *entry_id = NULL;
struct Curl_dns_entry *dns = NULL;
- size_t entry_len;
struct SessionHandle *data = conn->data;
CURLcode result;
- int rc = CURLRESOLV_ERROR; /* default to failure */
+ int stale, rc = CURLRESOLV_ERROR; /* default to failure */
*entry = NULL;
- /* Create an entry id, based upon the hostname and port */
- entry_id = create_hostcache_id(hostname, port);
- /* If we can't create the entry id, fail */
- if(!entry_id)
- return rc;
-
- entry_len = strlen(entry_id);
-
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- /* See if its already in our dns cache */
- dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
-
- /* free the allocated entry_id again */
- free(entry_id);
-
- infof(data, "Hostname was %sfound in DNS cache\n", dns?"":"NOT ");
+ dns = Curl_fetch_addr(conn, hostname, port, &stale);
- /* See whether the returned entry is stale. Done before we release lock */
- if(remove_entry_if_stale(data, dns)) {
+ infof(data, "Hostname was %sfound in DNS cache\n", dns||stale?"":"NOT ");
+ if(stale)
infof(data, "Hostname in DNS cache was stale, zapped\n");
- dns = NULL; /* the memory deallocation is being handled by the hash */
- }
+
if(dns) {
dns->inuse++; /* we use it! */