diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 9ef399a8a1..475da9c65e 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -679,12 +679,13 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, conn->ip_version = ipver; if(h) { + int h_af = h->addr->ai_family; /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ Curl_printable_address(h->addr, myhost, sizeof(myhost)); infof(data, "Name '%s' family %i resolved to '%s' family %i", - host, af, myhost, h->addr->ai_family); - Curl_resolv_unlock(data, h); - if(af != h->addr->ai_family) { + host, af, myhost, h_af); + Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */ + if(af != h_af) { /* bad IP version combo, signal the caller to try another address family if available */ return CURLE_UNSUPPORTED_PROTOCOL; diff --git a/lib/conncache.c b/lib/conncache.c index 92fd60c4df..5de10de914 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -772,10 +772,8 @@ static void connc_run_conn_shutdown_handler(struct Curl_easy *data, struct connectdata *conn) { if(!conn->bits.shutdown_handler) { - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); - conn->dns_entry = NULL; - } + if(conn->dns_entry) + Curl_resolv_unlink(data, &conn->dns_entry); /* Cleanup NTLM connection-related data */ Curl_http_auth_cleanup_ntlm(conn); @@ -1178,7 +1176,7 @@ void Curl_conncache_print(struct conncache *connc) while(curr) { conn = curr->ptr; - fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); + fprintf(stderr, " [%p %d]", (void *)conn, conn->refcount); curr = curr->next; } fprintf(stderr, "\n"); diff --git a/lib/doh.c b/lib/doh.c index 0dcca17ccd..ecb8cbe646 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -1360,7 +1360,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ - dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port); + dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port, FALSE); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); diff --git a/lib/ftp.c b/lib/ftp.c index ae340c44af..2f5748df7f 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1042,7 +1042,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, int error; char *host = NULL; char *string_ftpport = data->set.str[STRING_FTPPORT]; - struct Curl_dns_entry *h = NULL; + struct Curl_dns_entry *dns_entry = NULL; unsigned short port_min = 0; unsigned short port_max = 0; unsigned short port; @@ -1178,15 +1178,12 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, } /* resolv ip/host to ip */ - rc = Curl_resolv(data, host, 0, FALSE, &h); + rc = Curl_resolv(data, host, 0, FALSE, &dns_entry); if(rc == CURLRESOLV_PENDING) - (void)Curl_resolver_wait_resolv(data, &h); - if(h) { - res = h->addr; - /* when we return from this function, we can forget about this entry - to we can unlock it now already */ - Curl_resolv_unlock(data, h); - } /* (h) */ + (void)Curl_resolver_wait_resolv(data, &dns_entry); + if(dns_entry) { + res = dns_entry->addr; + } else res = NULL; /* failure! */ @@ -1381,6 +1378,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, ftp_state(data, FTP_PORT); out: + /* If we looked up a dns_entry, now is the time to safely release it */ + if(dns_entry) + Curl_resolv_unlink(data, &dns_entry); if(result) { ftp_state(data, FTP_STOP); } @@ -2098,7 +2098,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE); if(result) { - Curl_resolv_unlock(data, addr); /* we are done using this address */ + Curl_resolv_unlink(data, &addr); /* we are done using this address */ if(ftpc->count1 == 0 && ftpcode == 229) return ftp_epsv_disable(data, conn); @@ -2116,7 +2116,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, /* this just dumps information about this second connection */ ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport); - Curl_resolv_unlock(data, addr); /* we are done using this address */ + Curl_resolv_unlink(data, &addr); /* we are done using this address */ Curl_safefree(conn->secondaryhostname); conn->secondary_port = ftpc->newport; diff --git a/lib/hostasyn.c b/lib/hostasyn.c index 2f6762ca4e..4d6a8e8596 100644 --- a/lib/hostasyn.c +++ b/lib/hostasyn.c @@ -79,7 +79,7 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data, dns = Curl_cache_addr(data, ai, data->state.async.hostname, 0, - data->state.async.port); + data->state.async.port, FALSE); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); diff --git a/lib/hostip.c b/lib/hostip.c index 2c1f08e744..cdda8308ba 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -115,7 +115,7 @@ * CURLRES_* defines based on the config*.h and curl_setup.h defines. */ -static void freednsentry(void *freethis); +static void hostcache_unlink_entry(void *entry); #ifndef CURL_DISABLE_VERBOSE_STRINGS static void show_resolve_info(struct Curl_easy *data, @@ -178,7 +178,7 @@ create_hostcache_id(const char *name, struct hostcache_prune_data { time_t now; time_t oldest; /* oldest time in cache not pruned. */ - int cache_timeout; + int max_age_sec; }; /* @@ -189,16 +189,16 @@ struct hostcache_prune_data { * cache. */ static int -hostcache_timestamp_remove(void *datap, void *hc) +hostcache_entry_is_stale(void *datap, void *hc) { struct hostcache_prune_data *prune = (struct hostcache_prune_data *) datap; - struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; + struct Curl_dns_entry *dns = (struct Curl_dns_entry *) hc; - if(c->timestamp) { + if(dns->timestamp) { /* age in seconds */ - time_t age = prune->now - c->timestamp; - if(age >= prune->cache_timeout) + time_t age = prune->now - dns->timestamp; + if(age >= prune->max_age_sec) return TRUE; if(age > prune->oldest) prune->oldest = age; @@ -216,13 +216,13 @@ hostcache_prune(struct Curl_hash *hostcache, int cache_timeout, { struct hostcache_prune_data user; - user.cache_timeout = cache_timeout; + user.max_age_sec = cache_timeout; user.now = now; user.oldest = 0; Curl_hash_clean_with_criterium(hostcache, (void *) &user, - hostcache_timestamp_remove); + hostcache_entry_is_stale); return user.oldest; } @@ -299,10 +299,10 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, struct hostcache_prune_data user; user.now = time(NULL); - user.cache_timeout = data->set.dns_cache_timeout; + user.max_age_sec = data->set.dns_cache_timeout; user.oldest = 0; - if(hostcache_timestamp_remove(&user, dns)) { + if(hostcache_entry_is_stale(&user, dns)) { infof(data, "Hostname in DNS cache was stale, zapped"); dns = NULL; /* the memory deallocation is being handled by the hash */ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); @@ -348,7 +348,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, * * 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 + * The returned data *MUST* be "released" with Curl_resolv_unlink() after * use, or we will leak memory! */ struct Curl_dns_entry * @@ -364,7 +364,7 @@ Curl_fetch_addr(struct Curl_easy *data, dns = fetch_addr(data, hostname, port); if(dns) - dns->inuse++; /* we use it! */ + dns->refcount++; /* we use it! */ if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -468,7 +468,8 @@ Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, const char *hostname, size_t hostlen, /* length or zero */ - int port) + int port, + bool permanent) { char entry_id[MAX_HOSTCACHE_LEN]; size_t entry_len; @@ -496,11 +497,15 @@ Curl_cache_addr(struct Curl_easy *data, entry_len = create_hostcache_id(hostname, hostlen, port, entry_id, sizeof(entry_id)); - dns->inuse = 1; /* the cache has the first reference */ + dns->refcount = 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 permanent CURLOPT_RESOLVE entry */ + if(permanent) + dns->timestamp = 0; /* an entry that never goes stale */ + else { + dns->timestamp = time(NULL); + if(dns->timestamp == 0) + dns->timestamp = 1; + } dns->hostport = port; if(hostlen) memcpy(dns->hostname, hostname, hostlen); @@ -514,7 +519,7 @@ Curl_cache_addr(struct Curl_easy *data, } dns = dns2; - dns->inuse++; /* mark entry as in-use */ + dns->refcount++; /* mark entry as in-use */ return dns; } @@ -666,8 +671,8 @@ static bool tailmatch(const char *full, const char *part) * resolves. See the return codes. * * The cache entry we return will get its 'inuse' counter increased when this - * function is used. You MUST call Curl_resolv_unlock() later (when you are - * done using this struct) to decrease the counter again. + * function is used. You MUST call Curl_resolv_unlink() later (when you are + * done using this struct) to decrease the reference counter again. * * Return codes: * @@ -708,7 +713,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, if(dns) { infof(data, "Hostname %s was found in DNS cache", hostname); - dns->inuse++; /* we use it! */ + dns->refcount++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } @@ -828,7 +833,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ - dns = Curl_cache_addr(data, addr, hostname, 0, port); + dns = Curl_cache_addr(data, addr, hostname, 0, port, FALSE); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -868,8 +873,8 @@ void alarmfunc(int sig) * resolves. See the return codes. * * The cache entry we return will get its 'inuse' counter increased when this - * function is used. You MUST call Curl_resolv_unlock() later (when you are - * done using this struct) to decrease the counter again. + * function is used. You MUST call Curl_resolv_unlink() later (when you are + * done using this struct) to decrease the reference counter again. * * If built with a synchronous resolver and use of signals is not * disabled by the application, then a nonzero timeout will cause a @@ -1037,18 +1042,20 @@ clean_up: } /* - * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been - * made, the struct may be destroyed due to pruning. It is important that only - * one unlock is made for each Curl_resolv() call. + * Curl_resolv_unlink() releases a reference to the given cached DNS entry. + * When the reference count reaches 0, the entry is destroyed. It is important + * that only one unlink is made for each Curl_resolv() call. * * May be called with 'data' == NULL for global cache. */ -void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) +void Curl_resolv_unlink(struct Curl_easy *data, struct Curl_dns_entry **pdns) { + struct Curl_dns_entry *dns = *pdns; + *pdns = NULL; if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - freednsentry(dns); + hostcache_unlink_entry(dns); if(data && data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -1057,13 +1064,13 @@ void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) /* * File-internal: release cache dns entry reference, free if inuse drops to 0 */ -static void freednsentry(void *freethis) +static void hostcache_unlink_entry(void *entry) { - struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis; - DEBUGASSERT(dns && (dns->inuse>0)); + struct Curl_dns_entry *dns = (struct Curl_dns_entry *) entry; + DEBUGASSERT(dns && (dns->refcount>0)); - dns->inuse--; - if(dns->inuse == 0) { + dns->refcount--; + if(dns->refcount == 0) { Curl_freeaddrinfo(dns->addr); #ifdef USE_HTTPSRR if(dns->hinfo) { @@ -1092,7 +1099,7 @@ static void freednsentry(void *freethis) void Curl_init_dnscache(struct Curl_hash *hash, size_t size) { Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare, - freednsentry); + hostcache_unlink_entry); } /* @@ -1285,13 +1292,11 @@ err: } /* put this new host in the cache */ - dns = Curl_cache_addr(data, head, host_begin, hlen, port); + dns = Curl_cache_addr(data, head, host_begin, hlen, port, permanent); if(dns) { - if(permanent) - dns->timestamp = 0; /* mark as permanent */ /* release the returned reference; the cache itself will keep the * entry alive: */ - dns->inuse--; + dns->refcount--; } if(data->share) diff --git a/lib/hostip.h b/lib/hostip.h index c85a688db6..fff1c066b4 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -99,8 +99,8 @@ struct Curl_dns_entry { #endif /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */ time_t timestamp; - /* use-counter, use Curl_resolv_unlock to release reference */ - long inuse; + /* reference counter, entry is freed on reaching 0 */ + size_t refcount; /* hostname port number that resolved to addr. */ int hostport; /* hostname that resolved to addr. may be NULL (unix domain sockets). */ @@ -113,7 +113,7 @@ bool Curl_host_is_ipnum(const char *hostname); * Curl_resolv() returns an entry with the info for the specified host * and port. * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * The returned data *MUST* be "released" with Curl_resolv_unlink() after * use, or we will leak memory! */ /* return codes */ @@ -161,9 +161,9 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, int *waitp); -/* unlock a previously resolved dns entry */ -void Curl_resolv_unlock(struct Curl_easy *data, - struct Curl_dns_entry *dns); +/* unlink a dns entry, potentially shared with a cache */ +void Curl_resolv_unlink(struct Curl_easy *data, + struct Curl_dns_entry **pdns); /* init a new dns cache */ void Curl_init_dnscache(struct Curl_hash *hash, size_t hashsize); @@ -199,7 +199,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ip, * * 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 + * The returned data *MUST* be "released" with Curl_resolv_unlink() after * use, or we will leak memory! */ struct Curl_dns_entry * @@ -209,12 +209,13 @@ Curl_fetch_addr(struct Curl_easy *data, /* * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. - * + * @param permanent iff TRUE, entry will never become stale * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, - const char *hostname, size_t hostlen, int port); + const char *hostname, size_t hostlen, int port, + bool permanent); #ifndef INADDR_NONE #define CURL_INADDR_NONE (in_addr_t) ~0 diff --git a/lib/multi.c b/lib/multi.c index 4a787f0059..954a495fa4 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -742,10 +742,8 @@ static CURLcode multi_done(struct Curl_easy *data, data->state.done = TRUE; /* called just now! */ - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; - } + if(conn->dns_entry) + Curl_resolv_unlink(data, &conn->dns_entry); /* done with this */ Curl_hostcache_prune(data); /* if data->set.reuse_forbid is TRUE, it means the libcurl client has diff --git a/lib/socks.c b/lib/socks.c index 094ff42cd7..4d6a00cf56 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -388,7 +388,7 @@ CONNECT_RESOLVED: infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf); - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ } else failf(data, "SOCKS4 connection to %s not supported", sx->hostname); @@ -893,7 +893,7 @@ CONNECT_RESOLVED: failf(data, "SOCKS5 connection to %s not supported", dest); } - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ goto CONNECT_REQ_SEND; } CONNECT_RESOLVE_REMOTE: diff --git a/lib/url.c b/lib/url.c index 914b5b653c..017846a4e8 100644 --- a/lib/url.c +++ b/lib/url.c @@ -637,10 +637,8 @@ void Curl_disconnect(struct Curl_easy *data, return; } - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); - conn->dns_entry = NULL; - } + if(conn->dns_entry) + Curl_resolv_unlink(data, &conn->dns_entry); /* Cleanup NTLM connection-related data */ Curl_http_auth_cleanup_ntlm(conn); @@ -3101,118 +3099,12 @@ static CURLcode resolve_unix(struct Curl_easy *data, return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY; } - hostaddr->inuse++; + hostaddr->refcount = 1; /* connection is the only one holding this */ conn->dns_entry = hostaddr; return CURLE_OK; } #endif -#ifndef CURL_DISABLE_PROXY -static CURLcode resolve_proxy(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - struct Curl_dns_entry *hostaddr = NULL; - struct hostname *host; - timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - int rc; - - DEBUGASSERT(conn->dns_entry == NULL); - - host = conn->bits.socksproxy ? &conn->socks_proxy.host : - &conn->http_proxy.host; - - conn->hostname_resolve = strdup(host->name); - if(!conn->hostname_resolve) - return CURLE_OUT_OF_MEMORY; - - rc = Curl_resolv_timeout(data, conn->hostname_resolve, - conn->primary.remote_port, &hostaddr, timeout_ms); - conn->dns_entry = hostaddr; - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - else if(rc == CURLRESOLV_TIMEDOUT) - return CURLE_OPERATION_TIMEDOUT; - else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", host->dispname); - return CURLE_COULDNT_RESOLVE_PROXY; - } - - return CURLE_OK; -} -#endif - -static CURLcode resolve_host(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - struct Curl_dns_entry *hostaddr = NULL; - struct hostname *connhost; - timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - int rc; - - DEBUGASSERT(conn->dns_entry == NULL); - - connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; - - /* If not connecting via a proxy, extract the port from the URL, if it is - * there, thus overriding any defaults that might have been set above. */ - conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port; - - /* Resolve target host right on */ - conn->hostname_resolve = strdup(connhost->name); - if(!conn->hostname_resolve) - return CURLE_OUT_OF_MEMORY; - - rc = Curl_resolv_timeout(data, conn->hostname_resolve, - conn->primary.remote_port, &hostaddr, timeout_ms); - conn->dns_entry = hostaddr; - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - else if(rc == CURLRESOLV_TIMEDOUT) { - failf(data, "Failed to resolve host '%s' with timeout after %" - CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname, - Curl_timediff(Curl_now(), data->progress.t_startsingle)); - return CURLE_OPERATION_TIMEDOUT; - } - else if(!hostaddr) { - failf(data, "Could not resolve host: %s", connhost->dispname); - return CURLE_COULDNT_RESOLVE_HOST; - } - - return CURLE_OK; -} - -/* Perform a fresh resolve */ -static CURLcode resolve_fresh(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ -#ifdef USE_UNIX_SOCKETS - char *unix_path = conn->unix_domain_socket; - -#ifndef CURL_DISABLE_PROXY - if(!unix_path && conn->socks_proxy.host.name && - !strncmp(UNIX_SOCKET_PREFIX"/", - conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) - unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; -#endif - - if(unix_path) { - conn->transport = TRNSPRT_UNIX; - return resolve_unix(data, conn, unix_path); - } -#endif - -#ifndef CURL_DISABLE_PROXY - if(CONN_IS_PROXIED(conn)) - return resolve_proxy(data, conn, async); -#endif - - return resolve_host(data, conn, async); -} - /************************************************************* * Resolve the address of the server or proxy *************************************************************/ @@ -3220,19 +3112,67 @@ static CURLcode resolve_server(struct Curl_easy *data, struct connectdata *conn, bool *async) { - DEBUGASSERT(conn); - DEBUGASSERT(data); + struct hostname *ehost; + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + const char *peertype = "host"; + int rc; +#ifdef USE_UNIX_SOCKETS + char *unix_path = conn->unix_domain_socket; - /* Resolve the name of the server or proxy */ - if(conn->bits.reuse) { - /* We are reusing the connection - no need to resolve anything, and - idnconvert_hostname() was called already in create_conn() for the reuse - case. */ - *async = FALSE; - return CURLE_OK; +#ifndef CURL_DISABLE_PROXY + if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name && + !strncmp(UNIX_SOCKET_PREFIX"/", + conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) + unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; +#endif + + if(unix_path) { + /* TODO, this only works if previous transport is TRNSPRT_TCP. Check it? */ + conn->transport = TRNSPRT_UNIX; + return resolve_unix(data, conn, unix_path); + } +#endif + + DEBUGASSERT(conn->dns_entry == NULL); + +#ifndef CURL_DISABLE_PROXY + if(CONN_IS_PROXIED(conn)) { + ehost = conn->bits.socksproxy ? &conn->socks_proxy.host : + &conn->http_proxy.host; + peertype = "proxy"; + } + else +#endif + { + ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; + /* If not connecting via a proxy, extract the port from the URL, if it is + * there, thus overriding any defaults that might have been set above. */ + conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; } - return resolve_fresh(data, conn, async); + /* Resolve target host right on */ + conn->hostname_resolve = strdup(ehost->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + + rc = Curl_resolv_timeout(data, conn->hostname_resolve, + conn->primary.remote_port, + &conn->dns_entry, timeout_ms); + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + else if(rc == CURLRESOLV_TIMEDOUT) { + failf(data, "Failed to resolve %s '%s' with timeout after %" + CURL_FORMAT_TIMEDIFF_T " ms", peertype, ehost->dispname, + Curl_timediff(Curl_now(), data->progress.t_startsingle)); + return CURLE_OPERATION_TIMEDOUT; + } + else if(!conn->dns_entry) { + failf(data, "Could not resolve %s: %s", peertype, ehost->dispname); + return CURLE_COULDNT_RESOLVE_HOST; + } + + return CURLE_OK; } /* @@ -3708,12 +3648,20 @@ static CURLcode create_conn(struct Curl_easy *data, /* Continue connectdata initialization here. */ - /************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ - result = resolve_server(data, conn, async); - if(result) - goto out; + if(conn->bits.reuse) { + /* We are reusing the connection - no need to resolve anything, and + idnconvert_hostname() was called already in create_conn() for the reuse + case. */ + *async = FALSE; + } + else { + /************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ + result = resolve_server(data, conn, async); + if(result) + goto out; + } /* Everything general done, inform filters that they need * to prepare for a data transfer. diff --git a/lib/urldata.h b/lib/urldata.h index aab5748b04..117167c2dc 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -831,7 +831,8 @@ struct connectdata { struct proxy_info http_proxy; #endif /* 'primary' and 'secondary' get filled with IP quadruple - (local/remote numerical ip address and port) whenever a is *attempted*. + (local/remote numerical ip address and port) whenever a connect is + *attempted*. When more than one address is tried for a connection these will hold data for the last attempt. When the connection is actually established these are updated with data which comes directly from the socket. */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 8a65491b22..45bbf92563 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3897,7 +3897,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, if(data->set.tls_ech & CURLECH_HARD) return CURLE_SSL_CONNECT_ERROR; } - Curl_resolv_unlock(data, dns); + Curl_resolv_unlink(data, &dns); } } # ifdef OPENSSL_IS_BORINGSSL diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 2b467c9350..e45ee5bab3 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -988,7 +988,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(data->set.tls_ech & CURLECH_HARD) return CURLE_SSL_CONNECT_ERROR; } - Curl_resolv_unlock(data, dns); + Curl_resolv_unlink(data, &dns); } } diff --git a/tests/unit/unit1305.c b/tests/unit/unit1305.c index 19cc62c44a..c446d8fe6a 100644 --- a/tests/unit/unit1305.c +++ b/tests/unit/unit1305.c @@ -122,7 +122,7 @@ UNITTEST_START abort_unless(rc == CURLE_OK, "data node creation failed"); key_len = strlen(data_key); - data_node->inuse = 1; /* hash will hold the reference */ + data_node->refcount = 1; /* hash will hold the reference */ nodep = Curl_hash_add(&hp, data_key, key_len + 1, data_node); abort_unless(nodep, "insertion into hash failed"); /* Freeing will now be done by Curl_hash_destroy */