urldata: move async resolver state from easy handle to connectdata

- resolving is done for a connection, not for every transfer
- save create/dup/free of a cares channel for each transfer
- check values of setopt calls against a local channel if no
  connection has been attached yet, when needed.

Closes #12198
This commit is contained in:
Stefan Eissing 2023-10-25 12:31:34 +02:00 committed by Daniel Stenberg
parent 910f740ce2
commit 56a4db2e4e
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
10 changed files with 147 additions and 127 deletions

View File

@ -228,9 +228,9 @@ static void destroy_async_data(struct Curl_async *async);
void Curl_resolver_cancel(struct Curl_easy *data) void Curl_resolver_cancel(struct Curl_easy *data)
{ {
DEBUGASSERT(data); DEBUGASSERT(data);
if(data->state.async.resolver) if(data->conn->resolve_async.resolver)
ares_cancel((ares_channel)data->state.async.resolver); ares_cancel((ares_channel)data->conn->resolve_async.resolver);
destroy_async_data(&data->state.async); destroy_async_data(&data->conn->resolve_async);
} }
/* /*
@ -278,14 +278,14 @@ int Curl_resolver_getsock(struct Curl_easy *data,
struct timeval timebuf; struct timeval timebuf;
struct timeval *timeout; struct timeval *timeout;
long milli; long milli;
int max = ares_getsock((ares_channel)data->state.async.resolver, int max = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
(ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
maxtime.tv_usec = 0; maxtime.tv_usec = 0;
timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime, timeout = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
&timebuf); &maxtime, &timebuf);
milli = (long)curlx_tvtoms(timeout); milli = (long)curlx_tvtoms(timeout);
if(milli == 0) if(milli == 0)
milli += 10; milli += 10;
@ -313,8 +313,8 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
int i; int i;
int num = 0; int num = 0;
bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks, bitmask = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
ARES_GETSOCK_MAXNUM); socks, ARES_GETSOCK_MAXNUM);
for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
pfd[i].events = 0; pfd[i].events = 0;
@ -344,12 +344,12 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
if(!nfds) if(!nfds)
/* Call ares_process() unconditionally here, even if we simply timed out /* Call ares_process() unconditionally here, even if we simply timed out
above, as otherwise the ares name resolve won't timeout! */ above, as otherwise the ares name resolve won't timeout! */
ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD, ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
ARES_SOCKET_BAD); ARES_SOCKET_BAD, ARES_SOCKET_BAD);
else { else {
/* move through the descriptors and ask for processing on them */ /* move through the descriptors and ask for processing on them */
for(i = 0; i < num; i++) for(i = 0; i < num; i++)
ares_process_fd((ares_channel)data->state.async.resolver, ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
(pfd[i].revents & (POLLRDNORM|POLLIN))? (pfd[i].revents & (POLLRDNORM|POLLIN))?
pfd[i].fd:ARES_SOCKET_BAD, pfd[i].fd:ARES_SOCKET_BAD,
(pfd[i].revents & (POLLWRNORM|POLLOUT))? (pfd[i].revents & (POLLWRNORM|POLLOUT))?
@ -368,7 +368,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns) struct Curl_dns_entry **dns)
{ {
struct thread_data *res = data->state.async.tdata; struct thread_data *res = data->conn->resolve_async.tdata;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
DEBUGASSERT(dns); DEBUGASSERT(dns);
@ -397,7 +397,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
ARES_ECANCELLED synchronously for all pending responses. This will ARES_ECANCELLED synchronously for all pending responses. This will
leave us with res->num_pending == 0, which is perfect for the next leave us with res->num_pending == 0, which is perfect for the next
block. */ block. */
ares_cancel((ares_channel)data->state.async.resolver); ares_cancel((ares_channel)data->conn->resolve_async.resolver);
DEBUGASSERT(res->num_pending == 0); DEBUGASSERT(res->num_pending == 0);
} }
#endif #endif
@ -408,12 +408,12 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
them */ them */
res->temp_ai = NULL; res->temp_ai = NULL;
if(!data->state.async.dns) if(!data->conn->resolve_async.dns)
result = Curl_resolver_error(data); result = Curl_resolver_error(data);
else else
*dns = data->state.async.dns; *dns = data->conn->resolve_async.dns;
destroy_async_data(&data->state.async); destroy_async_data(&data->conn->resolve_async);
} }
return result; return result;
@ -464,7 +464,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
store.tv_sec = itimeout/1000; store.tv_sec = itimeout/1000;
store.tv_usec = (itimeout%1000)*1000; store.tv_usec = (itimeout%1000)*1000;
tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv); tvp = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
&store, &tv);
/* use the timeout period ares returned to us above if less than one /* use the timeout period ares returned to us above if less than one
second is left, otherwise just use 1000ms to make sure the progress second is left, otherwise just use 1000ms to make sure the progress
@ -478,7 +479,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
return CURLE_UNRECOVERABLE_POLL; return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry); result = Curl_resolver_is_resolved(data, entry);
if(result || data->state.async.done) if(result || data->conn->resolve_async.done)
break; break;
if(Curl_pgrsUpdate(data)) if(Curl_pgrsUpdate(data))
@ -499,12 +500,12 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
} }
if(result) if(result)
/* failure, so we cancel the ares operation */ /* failure, so we cancel the ares operation */
ares_cancel((ares_channel)data->state.async.resolver); ares_cancel((ares_channel)data->conn->resolve_async.resolver);
/* Operation complete, if the lookup was successful we now have the entry /* Operation complete, if the lookup was successful we now have the entry
in the cache. */ in the cache. */
if(entry) if(entry)
*entry = data->state.async.dns; *entry = data->conn->resolve_async.dns;
if(result) if(result)
/* close the connection, since we can't return failure here without /* close the connection, since we can't return failure here without
@ -571,12 +572,13 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
be valid so only defer it when we know the 'status' says its fine! */ be valid so only defer it when we know the 'status' says its fine! */
return; return;
res = data->state.async.tdata; res = data->conn->resolve_async.tdata;
if(res) { if(res) {
res->num_pending--; res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) { if(CURL_ASYNC_SUCCESS == status) {
struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port); struct Curl_addrinfo *ai = Curl_he2ai(hostent,
data->conn->resolve_async.port);
if(ai) { if(ai) {
compound_results(res, ai); compound_results(res, ai);
} }
@ -727,7 +729,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result) struct ares_addrinfo *result)
{ {
struct Curl_easy *data = (struct Curl_easy *)arg; struct Curl_easy *data = (struct Curl_easy *)arg;
struct thread_data *res = data->state.async.tdata; struct thread_data *res = data->conn->resolve_async.tdata;
(void)timeouts; (void)timeouts;
if(ARES_SUCCESS == status) { if(ARES_SUCCESS == status) {
res->temp_ai = ares2addr(result->nodes); res->temp_ai = ares2addr(result->nodes);
@ -758,12 +760,12 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res = calloc(sizeof(struct thread_data) + namelen, 1); res = calloc(sizeof(struct thread_data) + namelen, 1);
if(res) { if(res) {
strcpy(res->hostname, hostname); strcpy(res->hostname, hostname);
data->state.async.hostname = res->hostname; data->conn->resolve_async.hostname = res->hostname;
data->state.async.port = port; data->conn->resolve_async.port = port;
data->state.async.done = FALSE; /* not done */ data->conn->resolve_async.done = FALSE; /* not done */
data->state.async.status = 0; /* clear */ data->conn->resolve_async.status = 0; /* clear */
data->state.async.dns = NULL; /* clear */ data->conn->resolve_async.dns = NULL; /* clear */
data->state.async.tdata = res; data->conn->resolve_async.tdata = res;
/* initial status - failed */ /* initial status - failed */
res->last_status = ARES_ENOTFOUND; res->last_status = ARES_ENOTFOUND;
@ -793,8 +795,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
hints.ai_flags = ARES_AI_NUMERICSERV; hints.ai_flags = ARES_AI_NUMERICSERV;
msnprintf(service, sizeof(service), "%d", port); msnprintf(service, sizeof(service), "%d", port);
res->num_pending = 1; res->num_pending = 1;
ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, ares_getaddrinfo((ares_channel)data->conn->resolve_async.resolver,
service, &hints, addrinfo_cb, data); hostname, service, &hints, addrinfo_cb, data);
} }
#else #else
@ -804,10 +806,10 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 2; res->num_pending = 2;
/* areschannel is already setup in the Curl_open() function */ /* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
PF_INET, query_completed_cb, data); hostname, PF_INET, query_completed_cb, data);
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
PF_INET6, query_completed_cb, data); hostname, PF_INET6, query_completed_cb, data);
} }
else else
#endif #endif
@ -815,7 +817,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 1; res->num_pending = 1;
/* areschannel is already setup in the Curl_open() function */ /* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->state.async.resolver, ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
hostname, PF_INET, hostname, PF_INET,
query_completed_cb, data); query_completed_cb, data);
} }
@ -829,6 +831,7 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
char *servers) char *servers)
{ {
CURLcode result = CURLE_NOT_BUILT_IN; CURLcode result = CURLE_NOT_BUILT_IN;
ares_channel channel, lchannel = NULL;
int ares_result; int ares_result;
/* If server is NULL or empty, this would purge all DNS servers /* If server is NULL or empty, this would purge all DNS servers
@ -841,11 +844,23 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
return CURLE_OK; return CURLE_OK;
#ifdef HAVE_CARES_SERVERS_CSV #ifdef HAVE_CARES_SERVERS_CSV
if(data->conn)
channel = data->conn->resolve_async.resolver;
else {
/* we are called by setopt on a data without a connection (yet). In that
* case we set the value on a local instance for checking.
* The configured data options are set when the connection for this
* transfer is created. */
result = Curl_resolver_init(data, (void **)&lchannel);
if(result)
goto out;
channel = lchannel;
}
#ifdef HAVE_CARES_PORTS_CSV #ifdef HAVE_CARES_PORTS_CSV
ares_result = ares_set_servers_ports_csv(data->state.async.resolver, ares_result = ares_set_servers_ports_csv(channel, servers);
servers);
#else #else
ares_result = ares_set_servers_csv(data->state.async.resolver, servers); ares_result = ares_set_servers_csv(channel, servers);
#endif #endif
switch(ares_result) { switch(ares_result) {
case ARES_SUCCESS: case ARES_SUCCESS:
@ -861,6 +876,9 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
result = CURLE_BAD_FUNCTION_ARGUMENT; result = CURLE_BAD_FUNCTION_ARGUMENT;
break; break;
} }
out:
if(lchannel)
Curl_resolver_cleanup(lchannel);
#else /* too old c-ares version! */ #else /* too old c-ares version! */
(void)data; (void)data;
(void)(ares_result); (void)(ares_result);
@ -872,11 +890,14 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
const char *interf) const char *interf)
{ {
#ifdef HAVE_CARES_LOCAL_DEV #ifdef HAVE_CARES_LOCAL_DEV
if(!interf) if(data->conn) {
interf = ""; /* not a setopt test run, set the value */
if(!interf)
ares_set_local_dev((ares_channel)data->state.async.resolver, interf); interf = "";
ares_set_local_dev((ares_channel)data->conn->resolve_async.resolver,
interf);
}
return CURLE_OK; return CURLE_OK;
#else /* c-ares version too old! */ #else /* c-ares version too old! */
(void)data; (void)data;
@ -900,8 +921,11 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
} }
} }
ares_set_local_ip4((ares_channel)data->state.async.resolver, if(data->conn) {
ntohl(a4.s_addr)); /* not a setopt test run, set the value */
ares_set_local_ip4((ares_channel)data->conn->resolve_async.resolver,
ntohl(a4.s_addr));
}
return CURLE_OK; return CURLE_OK;
#else /* c-ares version too old! */ #else /* c-ares version too old! */
@ -927,7 +951,10 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
} }
} }
ares_set_local_ip6((ares_channel)data->state.async.resolver, a6); if(data->conn) {
/* not a setopt test run, set the value */
ares_set_local_ip6((ares_channel)data->conn->resolve_async.resolver, a6);
}
return CURLE_OK; return CURLE_OK;
#else /* c-ares version too old! */ #else /* c-ares version too old! */

View File

@ -136,7 +136,7 @@ static void destroy_async_data(struct Curl_async *);
*/ */
void Curl_resolver_cancel(struct Curl_easy *data) void Curl_resolver_cancel(struct Curl_easy *data)
{ {
destroy_async_data(&data->state.async); destroy_async_data(&data->conn->resolve_async);
} }
/* This function is used to init a threaded resolve */ /* This function is used to init a threaded resolve */
@ -173,7 +173,7 @@ struct thread_data {
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data) static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{ {
return &(data->state.async.tdata->tsd); return &(data->conn->resolve_async.tdata->tsd);
} }
/* Destroy resolver thread synchronization data */ /* Destroy resolver thread synchronization data */
@ -428,9 +428,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
{ {
struct thread_data *td = calloc(1, sizeof(struct thread_data)); struct thread_data *td = calloc(1, sizeof(struct thread_data));
int err = ENOMEM; int err = ENOMEM;
struct Curl_async *asp = &data->state.async; struct Curl_async *asp = &data->conn->resolve_async;
data->state.async.tdata = td; data->conn->resolve_async.tdata = td;
if(!td) if(!td)
goto errno_exit; goto errno_exit;
@ -488,7 +488,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
DEBUGASSERT(data); DEBUGASSERT(data);
td = data->state.async.tdata; td = data->conn->resolve_async.tdata;
DEBUGASSERT(td); DEBUGASSERT(td);
DEBUGASSERT(td->thread_hnd != curl_thread_t_null); DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
@ -500,18 +500,18 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
else else
DEBUGASSERT(0); DEBUGASSERT(0);
data->state.async.done = TRUE; data->conn->resolve_async.done = TRUE;
if(entry) if(entry)
*entry = data->state.async.dns; *entry = data->conn->resolve_async.dns;
if(!data->state.async.dns && report) if(!data->conn->resolve_async.dns && report)
/* a name was not resolved, report error */ /* a name was not resolved, report error */
result = Curl_resolver_error(data); result = Curl_resolver_error(data);
destroy_async_data(&data->state.async); destroy_async_data(&data->conn->resolve_async);
if(!data->state.async.dns && report) if(!data->conn->resolve_async.dns && report)
connclose(data->conn, "asynch resolve failed"); connclose(data->conn, "asynch resolve failed");
return result; return result;
@ -524,7 +524,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
*/ */
void Curl_resolver_kill(struct Curl_easy *data) void Curl_resolver_kill(struct Curl_easy *data)
{ {
struct thread_data *td = data->state.async.tdata; struct thread_data *td = data->conn->resolve_async.tdata;
/* If we're still resolving, we must wait for the threads to fully clean up, /* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver unfortunately. Otherwise, we can simply cancel to clean up any resolver
@ -563,7 +563,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry) struct Curl_dns_entry **entry)
{ {
struct thread_data *td = data->state.async.tdata; struct thread_data *td = data->conn->resolve_async.tdata;
int done = 0; int done = 0;
DEBUGASSERT(entry); DEBUGASSERT(entry);
@ -581,13 +581,13 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
if(done) { if(done) {
getaddrinfo_complete(data); getaddrinfo_complete(data);
if(!data->state.async.dns) { if(!data->conn->resolve_async.dns) {
CURLcode result = Curl_resolver_error(data); CURLcode result = Curl_resolver_error(data);
destroy_async_data(&data->state.async); destroy_async_data(&data->conn->resolve_async);
return result; return result;
} }
destroy_async_data(&data->state.async); destroy_async_data(&data->conn->resolve_async);
*entry = data->state.async.dns; *entry = data->conn->resolve_async.dns;
} }
else { else {
/* poll for name lookup done with exponential backoff up to 250ms */ /* poll for name lookup done with exponential backoff up to 250ms */
@ -619,9 +619,9 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
int ret_val = 0; int ret_val = 0;
timediff_t milli; timediff_t milli;
timediff_t ms; timediff_t ms;
struct resdata *reslv = (struct resdata *)data->state.async.resolver; struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR #ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->state.async.tdata; struct thread_data *td = data->conn->resolve_async.tdata;
#else #else
(void)socks; (void)socks;
#endif #endif
@ -662,7 +662,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port, int port,
int *waitp) int *waitp)
{ {
struct resdata *reslv = (struct resdata *)data->state.async.resolver; struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
*waitp = 0; /* default to synchronous response */ *waitp = 0; /* default to synchronous response */
@ -691,7 +691,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
{ {
struct addrinfo hints; struct addrinfo hints;
int pf = PF_INET; int pf = PF_INET;
struct resdata *reslv = (struct resdata *)data->state.async.resolver; struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
*waitp = 0; /* default to synchronous response */ *waitp = 0; /* default to synchronous response */

View File

@ -901,6 +901,7 @@ UNITTEST void de_cleanup(struct dohentry *d)
CURLcode Curl_doh_is_resolved(struct Curl_easy *data, CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp) struct Curl_dns_entry **dnsp)
{ {
struct connectdata *conn = data->conn;
CURLcode result; CURLcode result;
struct dohdata *dohp = data->req.doh; struct dohdata *dohp = data->req.doh;
*dnsp = NULL; /* defaults to no response */ *dnsp = NULL; /* defaults to no response */
@ -909,7 +910,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy && if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
!dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) { !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
failf(data, "Could not DoH-resolve: %s", data->state.async.hostname); failf(data, "Could not DoH-resolve: %s", conn->resolve_async.hostname);
return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY: return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST; CURLE_COULDNT_RESOLVE_HOST;
} }
@ -970,7 +971,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
Curl_freeaddrinfo(ai); Curl_freeaddrinfo(ai);
} }
else { else {
data->state.async.dns = dns; conn->resolve_async.dns = dns;
*dnsp = dns; *dnsp = dns;
result = CURLE_OK; /* address resolution OK */ result = CURLE_OK; /* address resolution OK */
} }

View File

@ -968,33 +968,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
(void)Curl_hsts_loadcb(outcurl, outcurl->hsts); (void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
} }
#endif #endif
/* Clone the resolver handle, if present, for the new handle */
if(Curl_resolver_duphandle(outcurl,
&outcurl->state.async.resolver,
data->state.async.resolver))
goto fail;
#ifdef USE_ARES
{
CURLcode rc;
rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
}
#endif /* USE_ARES */
Curl_initinfo(outcurl); Curl_initinfo(outcurl);

View File

@ -67,10 +67,11 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
int status, int status,
struct Curl_addrinfo *ai) struct Curl_addrinfo *ai)
{ {
struct connectdata *conn = data->conn;
struct Curl_dns_entry *dns = NULL; struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
data->state.async.status = status; conn->resolve_async.status = status;
if(CURL_ASYNC_SUCCESS == status) { if(CURL_ASYNC_SUCCESS == status) {
if(ai) { if(ai) {
@ -78,8 +79,8 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai, dns = Curl_cache_addr(data, ai,
data->state.async.hostname, 0, conn->resolve_async.hostname, 0,
data->state.async.port); conn->resolve_async.port);
if(data->share) if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS); Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@ -94,12 +95,12 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
} }
} }
data->state.async.dns = dns; conn->resolve_async.dns = dns;
/* Set async.done TRUE last in this function since it may be used multi- /* Set async.done TRUE last in this function since it may be used multi-
threaded and once this is TRUE the other thread may read fields from the threaded and once this is TRUE the other thread may read fields from the
async struct */ async struct */
data->state.async.done = TRUE; conn->resolve_async.done = TRUE;
/* IPv4: The input hostent struct will be freed by ares when we return from /* IPv4: The input hostent struct will be freed by ares when we return from
this function */ this function */

View File

@ -741,7 +741,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
Curl_set_in_callback(data, true); Curl_set_in_callback(data, true);
st = data->set.resolver_start( st = data->set.resolver_start(
#ifdef USE_CURL_ASYNC #ifdef USE_CURL_ASYNC
data->state.async.resolver, conn->resolve_async.resolver,
#else #else
NULL, NULL,
#endif #endif
@ -1413,9 +1413,9 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
#ifdef USE_CURL_ASYNC #ifdef USE_CURL_ASYNC
if(data->state.async.dns) { if(conn->resolve_async.dns) {
conn->dns_entry = data->state.async.dns; conn->dns_entry = conn->resolve_async.dns;
data->state.async.dns = NULL; conn->resolve_async.dns = NULL;
} }
#endif #endif
@ -1437,11 +1437,11 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
#ifdef USE_CURL_ASYNC #ifdef USE_CURL_ASYNC
CURLcode Curl_resolver_error(struct Curl_easy *data) CURLcode Curl_resolver_error(struct Curl_easy *data)
{ {
struct connectdata *conn = data->conn;
const char *host_or_proxy; const char *host_or_proxy;
CURLcode result; CURLcode result;
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
struct connectdata *conn = data->conn;
if(conn->bits.httpproxy) { if(conn->bits.httpproxy) {
host_or_proxy = "proxy"; host_or_proxy = "proxy";
result = CURLE_COULDNT_RESOLVE_PROXY; result = CURLE_COULDNT_RESOLVE_PROXY;
@ -1454,7 +1454,7 @@ CURLcode Curl_resolver_error(struct Curl_easy *data)
} }
failf(data, "Could not resolve %s: %s", host_or_proxy, failf(data, "Could not resolve %s: %s", host_or_proxy,
data->state.async.hostname); conn->resolve_async.hostname);
return result; return result;
} }

View File

@ -1986,8 +1986,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) { if(dns) {
#ifdef CURLRES_ASYNCH #ifdef CURLRES_ASYNCH
data->state.async.dns = dns; conn->resolve_async.dns = dns;
data->state.async.done = TRUE; conn->resolve_async.done = TRUE;
#endif #endif
result = CURLE_OK; result = CURLE_OK;
infof(data, "Hostname '%s' was found in DNS cache", hostname); infof(data, "Hostname '%s' was found in DNS cache", hostname);

View File

@ -339,8 +339,8 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
if(dns) { if(dns) {
#ifdef CURLRES_ASYNCH #ifdef CURLRES_ASYNCH
data->state.async.dns = dns; conn->resolve_async.dns = dns;
data->state.async.done = TRUE; conn->resolve_async.done = TRUE;
#endif #endif
infof(data, "Hostname '%s' was found", sx->hostname); infof(data, "Hostname '%s' was found", sx->hostname);
sxstate(sx, data, CONNECT_RESOLVED); sxstate(sx, data, CONNECT_RESOLVED);
@ -806,8 +806,8 @@ CONNECT_REQ_INIT:
if(dns) { if(dns) {
#ifdef CURLRES_ASYNCH #ifdef CURLRES_ASYNCH
data->state.async.dns = dns; conn->resolve_async.dns = dns;
data->state.async.done = TRUE; conn->resolve_async.done = TRUE;
#endif #endif
infof(data, "SOCKS5: hostname '%s' found", sx->hostname); infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
} }

View File

@ -422,10 +422,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->info.contenttype); Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect); Curl_safefree(data->info.wouldredirect);
/* this destroys the channel and we cannot use it anymore after this */
Curl_resolver_cancel(data);
Curl_resolver_cleanup(data->state.async.resolver);
data_priority_cleanup(data); data_priority_cleanup(data);
/* No longer a dirty share, if it exists */ /* No longer a dirty share, if it exists */
@ -652,13 +648,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER; data->magic = CURLEASY_MAGIC_NUMBER;
result = Curl_resolver_init(data, &data->state.async.resolver);
if(result) {
DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
free(data);
return result;
}
result = Curl_init_userdefined(data); result = Curl_init_userdefined(data);
if(!result) { if(!result) {
Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER); Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
@ -675,7 +664,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
} }
if(result) { if(result) {
Curl_resolver_cleanup(data->state.async.resolver);
Curl_dyn_free(&data->state.headerb); Curl_dyn_free(&data->state.headerb);
Curl_freeset(data); Curl_freeset(data);
free(data); free(data);
@ -709,6 +697,7 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_conn_cf_discard_all(data, conn, (int)i); Curl_conn_cf_discard_all(data, conn, (int)i);
} }
Curl_resolver_cleanup(conn->resolve_async.resolver);
Curl_free_idnconverted_hostname(&conn->host); Curl_free_idnconverted_hostname(&conn->host);
Curl_free_idnconverted_hostname(&conn->conn_to_host); Curl_free_idnconverted_hostname(&conn->conn_to_host);
#ifndef CURL_DISABLE_PROXY #ifndef CURL_DISABLE_PROXY
@ -809,6 +798,7 @@ void Curl_disconnect(struct Curl_easy *data,
conn->handler->disconnect(data, conn, dead_connection); conn->handler->disconnect(data, conn, dead_connection);
conn_shutdown(data); conn_shutdown(data);
Curl_resolver_cancel(data);
/* detach it again */ /* detach it again */
Curl_detach_connection(data); Curl_detach_connection(data);
@ -3791,7 +3781,35 @@ static CURLcode create_conn(struct Curl_easy *data,
* This is a brand new connection, so let's store it in the connection * This is a brand new connection, so let's store it in the connection
* cache of ours! * cache of ours!
*/ */
result = Curl_resolver_init(data, &conn->resolve_async.resolver);
if(result) {
DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
goto out;
}
Curl_attach_connection(data, conn); Curl_attach_connection(data, conn);
#ifdef USE_ARES
result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
if(result && result != CURLE_NOT_BUILT_IN)
goto out;
result = Curl_set_dns_interface(data,
data->set.str[STRING_DNS_INTERFACE]);
if(result && result != CURLE_NOT_BUILT_IN)
goto out;
result = Curl_set_dns_local_ip4(data,
data->set.str[STRING_DNS_LOCAL_IP4]);
if(result && result != CURLE_NOT_BUILT_IN)
goto out;
result = Curl_set_dns_local_ip6(data,
data->set.str[STRING_DNS_LOCAL_IP6]);
if(result && result != CURLE_NOT_BUILT_IN)
goto out;
#endif /* USE_ARES */
result = Curl_conncache_add_conn(data); result = Curl_conncache_add_conn(data);
if(result) if(result)
goto out; goto out;

View File

@ -917,6 +917,9 @@ struct connectdata {
multi_done(). This entry will be NULL if the connection is reused as then multi_done(). This entry will be NULL if the connection is reused as then
there is no name resolve done. */ there is no name resolve done. */
struct Curl_dns_entry *dns_entry; struct Curl_dns_entry *dns_entry;
#ifdef USE_CURL_ASYNC
struct Curl_async resolve_async; /* asynchronous name resolver data */
#endif
/* 'remote_addr' is the particular IP we connected to. it is owned, set /* 'remote_addr' is the particular IP we connected to. it is owned, set
* and NULLed by the connected socket filter (if there is one). */ * and NULLed by the connected socket filter (if there is one). */
@ -1374,9 +1377,6 @@ struct UrlState {
#endif #endif
struct auth authhost; /* auth details for host */ struct auth authhost; /* auth details for host */
struct auth authproxy; /* auth details for proxy */ struct auth authproxy; /* auth details for proxy */
#ifdef USE_CURL_ASYNC
struct Curl_async async; /* asynchronous name resolver data */
#endif
#if defined(USE_OPENSSL) #if defined(USE_OPENSSL)
/* void instead of ENGINE to avoid bleeding OpenSSL into this header */ /* void instead of ENGINE to avoid bleeding OpenSSL into this header */