summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/hostip.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2015-08-12 19:43:52 (GMT)
committerBrad King <brad.king@kitware.com>2015-08-12 19:43:52 (GMT)
commit91e8d35ab8ec2d62478a42eff10af88713497fad (patch)
treeff8cd1bd1ce3c42ef56c76b5ab471831a80c4665 /Utilities/cmcurl/lib/hostip.c
parent602cdc06a01b7c5c0eb444111382b09040f677ee (diff)
parent706542615828488a5ad197d0ef3dd5e42eb739c4 (diff)
downloadCMake-91e8d35ab8ec2d62478a42eff10af88713497fad.zip
CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.gz
CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.bz2
Merge branch 'curl-upstream' into update-curl
Resolve conflicts by taking upstream side when possible and otherwise integrating the changes from both sides. Be carful in CMakeLists.txt where the OPENSSL code block that we modified previously has moved, and preserve our previous modifications in the new location.
Diffstat (limited to 'Utilities/cmcurl/lib/hostip.c')
-rw-r--r--Utilities/cmcurl/lib/hostip.c287
1 files changed, 155 insertions, 132 deletions
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index 73b3f82..82f3897 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, 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
@@ -56,10 +56,7 @@
#include "url.h"
#include "inet_ntop.h"
#include "warnless.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
+#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
@@ -98,8 +95,8 @@
* hostip.c - method-independent resolver functions and utility functions
* hostasyn.c - functions for asynchronous name resolves
* hostsyn.c - functions for synchronous name resolves
- * hostip4.c - ipv4-specific functions
- * hostip6.c - ipv6-specific functions
+ * hostip4.c - IPv4 specific functions
+ * hostip6.c - IPv6 specific functions
*
* The two asynchronous name resolver backends are implemented in:
* asyn-ares.c - functions for ares-using name resolves
@@ -140,11 +137,7 @@ struct curl_hash *Curl_global_host_cache_init(void)
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);
+ Curl_hash_destroy(&hostname_cache);
host_cache_initialized = 0;
}
}
@@ -237,7 +230,8 @@ hostcache_timestamp_remove(void *datap, void *hc)
(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);
}
/*
@@ -283,40 +277,54 @@ void Curl_hostcache_prune(struct SessionHandle *data)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
-/*
- * Check if the entry should be pruned. Assumes a locked cache.
- */
-static int
-remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
+#ifdef HAVE_SIGSETJMP
+/* Beware this is a global and unique instance. This is used to store the
+ return address that we can jump back to from inside a signal handler. This
+ is not thread-safe stuff. */
+sigjmp_buf curl_jmpenv;
+#endif
+
+/* lookup address, returns entry if found and not stale */
+static struct Curl_dns_entry *
+fetch_addr(struct connectdata *conn,
+ const char *hostname,
+ int port)
{
- struct hostcache_prune_data user;
+ char *entry_id = NULL;
+ struct Curl_dns_entry *dns = NULL;
+ size_t entry_len;
+ struct SessionHandle *data = conn->data;
- if(!dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache ||
- dns->inuse)
- /* cache forever means never prune, and NULL hostcache means we can't do
- it, if it still is in use then we leave it */
- return 0;
+ /* 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;
- time(&user.now);
- user.cache_timeout = data->set.dns_cache_timeout;
+ entry_len = strlen(entry_id);
- if(!hostcache_timestamp_remove(&user,dns) )
- return 0;
+ /* See if its already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
- Curl_hash_clean_with_criterium(data->dns.hostcache,
- (void *) &user,
- hostcache_timestamp_remove);
+ if(dns && (data->set.dns_cache_timeout != -1)) {
+ /* See whether the returned entry is stale. Done before we release lock */
+ struct hostcache_prune_data user;
- return 1;
-}
+ time(&user.now);
+ user.cache_timeout = data->set.dns_cache_timeout;
+ if(hostcache_timestamp_remove(&user, dns)) {
+ infof(data, "Hostname in DNS cache was stale, zapped\n");
+ dns = NULL; /* the memory deallocation is being handled by the hash */
+ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+ }
+ }
-#ifdef HAVE_SIGSETJMP
-/* Beware this is a global and unique instance. This is used to store the
- return address that we can jump back to from inside a signal handler. This
- is not thread-safe stuff. */
-sigjmp_buf curl_jmpenv;
-#endif
+ /* free the allocated entry_id again */
+ free(entry_id);
+
+ return dns;
+}
/*
* Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
@@ -328,35 +336,27 @@ sigjmp_buf curl_jmpenv;
* lookups for the same hostname requested by different handles.
*
* Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
*/
struct Curl_dns_entry *
Curl_fetch_addr(struct connectdata *conn,
const char *hostname,
- int port, int *stale)
+ int port)
{
- char *entry_id = NULL;
- struct Curl_dns_entry *dns = NULL;
- size_t entry_len;
struct SessionHandle *data = conn->data;
+ struct Curl_dns_entry *dns = 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 dns;
-
- 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);
+ dns = fetch_addr(conn, hostname, port);
- /* free the allocated entry_id again */
- free(entry_id);
+ if(dns) dns->inuse++; /* we use it! */
- /* 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 */
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
return dns;
}
@@ -395,11 +395,11 @@ Curl_cache_addr(struct SessionHandle *data,
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,
@@ -448,21 +448,17 @@ int Curl_resolv(struct connectdata *conn,
struct Curl_dns_entry *dns = NULL;
struct SessionHandle *data = conn->data;
CURLcode result;
- int stale, rc = CURLRESOLV_ERROR; /* default to failure */
+ int rc = CURLRESOLV_ERROR; /* default to failure */
*entry = NULL;
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- dns = Curl_fetch_addr(conn, hostname, port, &stale);
-
- 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 = fetch_addr(conn, hostname, port);
if(dns) {
+ infof(data, "Hostname %s was found in DNS cache\n", hostname);
dns->inuse++; /* we use it! */
rc = CURLRESOLV_RESOLVED;
}
@@ -611,32 +607,6 @@ int Curl_resolv_timeout(struct connectdata *conn,
we want to wait less than one second we must bail out already now. */
return CURLRESOLV_TIMEDOUT;
- /*************************************************************
- * Set signal handler to catch SIGALRM
- * Store the old value to be able to set it back later!
- *************************************************************/
-#ifdef HAVE_SIGACTION
- sigaction(SIGALRM, NULL, &sigact);
- keep_sigact = sigact;
- keep_copysig = TRUE; /* yes, we have a copy */
- sigact.sa_handler = alarmfunc;
-#ifdef SA_RESTART
- /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
- sigact.sa_flags &= ~SA_RESTART;
-#endif
- /* now set the new struct */
- sigaction(SIGALRM, &sigact, NULL);
-#else /* HAVE_SIGACTION */
- /* no sigaction(), revert to the much lamer signal() */
-#ifdef HAVE_SIGNAL
- keep_sigact = signal(SIGALRM, alarmfunc);
-#endif
-#endif /* HAVE_SIGACTION */
-
- /* alarm() makes a signal get sent when the timeout fires off, and that
- will abort system calls */
- prev_alarm = alarm(curlx_sltoui(timeout/1000L));
-
/* This allows us to time-out from the name resolver, as the timeout
will generate a signal and we will siglongjmp() from that here.
This technique has problems (see alarmfunc).
@@ -649,6 +619,33 @@ int Curl_resolv_timeout(struct connectdata *conn,
rc = CURLRESOLV_ERROR;
goto clean_up;
}
+ else {
+ /*************************************************************
+ * Set signal handler to catch SIGALRM
+ * Store the old value to be able to set it back later!
+ *************************************************************/
+#ifdef HAVE_SIGACTION
+ sigaction(SIGALRM, NULL, &sigact);
+ keep_sigact = sigact;
+ keep_copysig = TRUE; /* yes, we have a copy */
+ sigact.sa_handler = alarmfunc;
+#ifdef SA_RESTART
+ /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+ sigact.sa_flags &= ~SA_RESTART;
+#endif
+ /* now set the new struct */
+ sigaction(SIGALRM, &sigact, NULL);
+#else /* HAVE_SIGACTION */
+ /* no sigaction(), revert to the much lamer signal() */
+#ifdef HAVE_SIGNAL
+ keep_sigact = signal(SIGALRM, alarmfunc);
+#endif
+#endif /* HAVE_SIGACTION */
+
+ /* alarm() makes a signal get sent when the timeout fires off, and that
+ will abort system calls */
+ prev_alarm = alarm(curlx_sltoui(timeout/1000L));
+ }
#else
#ifndef CURLRES_ASYNCH
@@ -720,54 +717,37 @@ clean_up:
*/
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);
}
}
/*
- * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
+ * Curl_mk_dnscache() inits a new DNS cache and returns success/failure.
*/
-struct curl_hash *Curl_mk_dnscache(void)
+int Curl_mk_dnscache(struct curl_hash *hash)
{
- return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
-}
-
-static int hostcache_inuse(void *data, void *hc)
-{
- struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
-
- if(c->inuse == 1)
- Curl_resolv_unlock(data, c);
-
- return 1; /* free all entries */
+ return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
+ freednsentry);
}
/*
@@ -780,11 +760,13 @@ static int hostcache_inuse(void *data, void *hc)
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(hash);
+
+ if(data && data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
@@ -799,18 +781,52 @@ CURLcode Curl_loadhostpairs(struct SessionHandle *data)
if(!hostp->data)
continue;
if(hostp->data[0] == '-') {
- /* TODO: mark an entry for removal */
+ char *entry_id;
+ size_t entry_len;
+
+ if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
+ infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n",
+ hostp->data);
+ continue;
+ }
+
+ /* 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 CURLE_OUT_OF_MEMORY;
+ }
+
+ entry_len = strlen(entry_id);
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* delete entry, ignore if it didn't exist */
+ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ /* free the allocated entry_id again */
+ free(entry_id);
}
- else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
- address)) {
+ else {
struct Curl_dns_entry *dns;
Curl_addrinfo *addr;
char *entry_id;
size_t entry_len;
+ if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
+ address)) {
+ infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
+ hostp->data);
+ continue;
+ }
+
addr = Curl_str2addr(address, port);
if(!addr) {
- infof(data, "Resolve %s found illegal!\n", hostp->data);
+ infof(data, "Address in '%s' found illegal!\n", hostp->data);
continue;
}
@@ -833,9 +849,16 @@ CURLcode Curl_loadhostpairs(struct SessionHandle *data)
/* 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);