asyn-thread: do not allocate thread_data separately

Put the full struct into Curl_async since it will be used for every name
resolve anyway.

Closes #16241
This commit is contained in:
Daniel Stenberg 2025-02-06 16:05:56 +01:00
parent 48f6bfa8c7
commit d9fc64d3ab
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
5 changed files with 188 additions and 208 deletions

View File

@ -351,17 +351,12 @@ void Curl_resolver_kill(struct Curl_easy *data)
*/ */
static void destroy_async_data(struct Curl_async *async) static void destroy_async_data(struct Curl_async *async)
{ {
if(async->tdata) { struct thread_data *res = &async->thdata;
struct thread_data *res = async->tdata; if(res->temp_ai) {
if(res) { Curl_freeaddrinfo(res->temp_ai);
if(res->temp_ai) { res->temp_ai = NULL;
Curl_freeaddrinfo(res->temp_ai);
res->temp_ai = NULL;
}
free(res);
}
async->tdata = NULL;
} }
Curl_safefree(res->hostname);
} }
/* /*
@ -385,7 +380,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
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->state.async.thdata;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
DEBUGASSERT(dns); DEBUGASSERT(dns);
@ -398,8 +393,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
/* Now that we have checked for any last minute results above, see if there /* Now that we have checked for any last minute results above, see if there
are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
expires. */ expires. */
if(res if(res->num_pending
&& res->num_pending
/* This is only set to non-zero if the timer was started. */ /* This is only set to non-zero if the timer was started. */
&& (res->happy_eyeballs_dns_time.tv_sec && (res->happy_eyeballs_dns_time.tv_sec
|| res->happy_eyeballs_dns_time.tv_usec) || res->happy_eyeballs_dns_time.tv_usec)
@ -419,7 +413,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
} }
#endif #endif
if(res && !res->num_pending) { if(!res->num_pending) {
(void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai); (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
/* temp_ai ownership is moved to the connection, so we need not free-up /* temp_ai ownership is moved to the connection, so we need not free-up
them */ them */
@ -589,7 +583,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
struct hostent *hostent) struct hostent *hostent)
{ {
struct Curl_easy *data = (struct Curl_easy *)arg; struct Curl_easy *data = (struct Curl_easy *)arg;
struct thread_data *res; struct thread_data *res = &data->state.async.thdata;
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
(void)timeouts; /* ignored */ (void)timeouts; /* ignored */
@ -600,79 +594,76 @@ 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->num_pending--;
if(res) {
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->state.async.port);
if(ai) { if(ai) {
compound_results(res, ai); compound_results(res, ai);
}
} }
/* A successful result overwrites any previous error */ }
if(res->last_status != ARES_SUCCESS) /* A successful result overwrites any previous error */
res->last_status = status; if(res->last_status != ARES_SUCCESS)
res->last_status = status;
/* If there are responses still pending, we presume they must be the /* If there are responses still pending, we presume they must be the
complementary IPv4 or IPv6 lookups that we started in parallel in complementary IPv4 or IPv6 lookups that we started in parallel in
Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a
"definitive" response from one of a set of parallel queries, we need to "definitive" response from one of a set of parallel queries, we need to
think about how long we are willing to wait for more responses. */ think about how long we are willing to wait for more responses. */
if(res->num_pending if(res->num_pending
/* Only these c-ares status values count as "definitive" for these /* Only these c-ares status values count as "definitive" for these
purposes. For example, ARES_ENODATA is what we expect when there is purposes. For example, ARES_ENODATA is what we expect when there is
no IPv6 entry for a domain name, and that is not a reason to get more no IPv6 entry for a domain name, and that is not a reason to get more
aggressive in our timeouts for the other response. Other errors are aggressive in our timeouts for the other response. Other errors are
either a result of bad input (which should affect all parallel either a result of bad input (which should affect all parallel
requests), local or network conditions, non-definitive server requests), local or network conditions, non-definitive server
responses, or us cancelling the request. */ responses, or us cancelling the request. */
&& (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) { && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
/* Right now, there can only be up to two parallel queries, so do not /* Right now, there can only be up to two parallel queries, so do not
bother handling any other cases. */ bother handling any other cases. */
DEBUGASSERT(res->num_pending == 1); DEBUGASSERT(res->num_pending == 1);
/* it is possible that one of these parallel queries could succeed /* it is possible that one of these parallel queries could succeed
quickly, but the other could always fail or timeout (when we are quickly, but the other could always fail or timeout (when we are
talking to a pool of DNS servers that can only successfully resolve talking to a pool of DNS servers that can only successfully resolve
IPv4 address, for example). IPv4 address, for example).
it is also possible that the other request could always just take it is also possible that the other request could always just take
longer because it needs more time or only the second DNS server can longer because it needs more time or only the second DNS server can
fulfill it successfully. But, to align with the philosophy of Happy fulfill it successfully. But, to align with the philosophy of Happy
Eyeballs, we do not want to wait _too_ long or users will think Eyeballs, we do not want to wait _too_ long or users will think
requests are slow when IPv6 lookups do not actually work (but IPv4 requests are slow when IPv6 lookups do not actually work (but IPv4
ones do). ones do).
So, now that we have a usable answer (some IPv4 addresses, some IPv6 So, now that we have a usable answer (some IPv4 addresses, some IPv6
addresses, or "no such domain"), we start a timeout for the remaining addresses, or "no such domain"), we start a timeout for the remaining
pending responses. Even though it is typical that this resolved pending responses. Even though it is typical that this resolved
request came back quickly, that needn't be the case. It might be that request came back quickly, that needn't be the case. It might be that
this completing request did not get a result from the first DNS this completing request did not get a result from the first DNS
server or even the first round of the whole DNS server pool. So it server or even the first round of the whole DNS server pool. So it
could already be quite some time after we issued the DNS queries in could already be quite some time after we issued the DNS queries in
the first place. Without modifying c-ares, we cannot know exactly the first place. Without modifying c-ares, we cannot know exactly
where in its retry cycle we are. We could guess based on how much where in its retry cycle we are. We could guess based on how much
time has gone by, but it does not really matter. Happy Eyeballs tells time has gone by, but it does not really matter. Happy Eyeballs tells
us that, given usable information in hand, we simply do not want to us that, given usable information in hand, we simply do not want to
wait "too much longer" after we get a result. wait "too much longer" after we get a result.
We simply wait an additional amount of time equal to the default We simply wait an additional amount of time equal to the default
c-ares query timeout. That is enough time for a typical parallel c-ares query timeout. That is enough time for a typical parallel
response to arrive without being "too long". Even on a network response to arrive without being "too long". Even on a network
where one of the two types of queries is failing or timing out where one of the two types of queries is failing or timing out
constantly, this will usually mean we wait a total of the default constantly, this will usually mean we wait a total of the default
c-ares timeout (5 seconds) plus the round trip time for the successful c-ares timeout (5 seconds) plus the round trip time for the successful
request, which seems bearable. The downside is that c-ares might race request, which seems bearable. The downside is that c-ares might race
with us to issue one more retry just before we give up, but it seems with us to issue one more retry just before we give up, but it seems
better to "waste" that request instead of trying to guess the perfect better to "waste" that request instead of trying to guess the perfect
timeout to prevent it. After all, we do not even know where in the timeout to prevent it. After all, we do not even know where in the
c-ares retry cycle each request is. c-ares retry cycle each request is.
*/ */
res->happy_eyeballs_dns_time = Curl_now(); res->happy_eyeballs_dns_time = Curl_now();
Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT, Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
EXPIRE_HAPPY_EYEBALLS_DNS); EXPIRE_HAPPY_EYEBALLS_DNS);
}
} }
} }
#else #else
@ -756,7 +747,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->state.async.thdata;
(void)timeouts; (void)timeouts;
if(ARES_SUCCESS == status) { if(ARES_SUCCESS == status) {
res->temp_ai = ares2addr(result->nodes); res->temp_ai = ares2addr(result->nodes);
@ -781,87 +772,86 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port, int port,
int *waitp) int *waitp)
{ {
struct thread_data *res = NULL; struct thread_data *res = &data->state.async.thdata;
size_t namelen = strlen(hostname);
*waitp = 0; /* default to synchronous response */ *waitp = 0; /* default to synchronous response */
res = calloc(1, sizeof(struct thread_data) + namelen); res->hostname = strdup(hostname);
if(res) { if(!res->hostname)
strcpy(res->hostname, hostname); return NULL;
data->state.async.hostname = res->hostname;
data->state.async.port = port;
data->state.async.done = FALSE; /* not done */
data->state.async.status = 0; /* clear */
data->state.async.dns = NULL; /* clear */
data->state.async.tdata = res;
/* initial status - failed */ data->state.async.hostname = res->hostname;
res->last_status = ARES_ENOTFOUND; data->state.async.port = port;
data->state.async.done = FALSE; /* not done */
data->state.async.status = 0; /* clear */
data->state.async.dns = NULL; /* clear */
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
#ifdef HAVE_CARES_GETADDRINFO #ifdef HAVE_CARES_GETADDRINFO
{ {
struct ares_addrinfo_hints hints; struct ares_addrinfo_hints hints;
char service[12]; char service[12];
int pf = PF_INET; int pf = PF_INET;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
#ifdef CURLRES_IPV6 #ifdef CURLRES_IPV6
if((data->conn->ip_version != CURL_IPRESOLVE_V4) && if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
Curl_ipv6works(data)) { Curl_ipv6works(data)) {
/* The stack seems to be IPv6-enabled */ /* The stack seems to be IPv6-enabled */
if(data->conn->ip_version == CURL_IPRESOLVE_V6) if(data->conn->ip_version == CURL_IPRESOLVE_V6)
pf = PF_INET6; pf = PF_INET6;
else else
pf = PF_UNSPEC; pf = PF_UNSPEC;
}
#endif /* CURLRES_IPV6 */
hints.ai_family = pf;
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
/* Since the service is a numerical one, set the hint flags
* accordingly to save a call to getservbyname in inside C-Ares
*/
hints.ai_flags = ARES_AI_NUMERICSERV;
msnprintf(service, sizeof(service), "%d", port);
res->num_pending = 1;
ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
service, &hints, addrinfo_cb, data);
} }
#endif /* CURLRES_IPV6 */
hints.ai_family = pf;
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
/* Since the service is a numerical one, set the hint flags
* accordingly to save a call to getservbyname in inside C-Ares
*/
hints.ai_flags = ARES_AI_NUMERICSERV;
msnprintf(service, sizeof(service), "%d", port);
res->num_pending = 1;
ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
service, &hints, addrinfo_cb, data);
}
#else #else
#ifdef HAVE_CARES_IPV6 #ifdef HAVE_CARES_IPV6
if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
/* The stack seems to be IPv6-enabled */ /* The stack seems to be IPv6-enabled */
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->state.async.resolver, hostname,
PF_INET, query_completed_cb, data); PF_INET, query_completed_cb, data);
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
PF_INET6, query_completed_cb, data); PF_INET6, query_completed_cb, data);
} }
else else
#endif #endif
{ {
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->state.async.resolver,
hostname, PF_INET, hostname, PF_INET,
query_completed_cb, data); query_completed_cb, data);
} }
#endif #endif
#ifdef USE_HTTPSRR_ARES #ifdef USE_HTTPSRR_ARES
{ {
res->num_pending++; /* one more */ res->num_pending++; /* one more */
memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo)); memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec((ares_channel)data->state.async.resolver, ares_query_dnsrec((ares_channel)data->state.async.resolver,
hostname, ARES_CLASS_IN, hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS, ARES_REC_TYPE_HTTPS,
Curl_dnsrec_done_cb, data, NULL); Curl_dnsrec_done_cb, data, NULL);
}
#endif
*waitp = 1; /* expect asynchronous response */
} }
#endif
*waitp = 1; /* expect asynchronous response */
return NULL; /* no struct yet */ return NULL; /* no struct yet */
} }

View File

@ -156,7 +156,7 @@ static bool init_resolve_thread(struct Curl_easy *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->state.async.thdata.tsd);
} }
/* Destroy resolver thread synchronization data */ /* Destroy resolver thread synchronization data */
@ -190,15 +190,15 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
/* Initialize resolver thread synchronization data */ /* Initialize resolver thread synchronization data */
static static
int init_thread_sync_data(struct thread_data *td, int init_thread_sync_data(struct thread_data *td,
const char *hostname, const char *hostname,
int port, int port,
const struct addrinfo *hints) const struct addrinfo *hints)
{ {
struct thread_sync_data *tsd = &td->tsd; struct thread_sync_data *tsd = &td->tsd;
memset(tsd, 0, sizeof(*tsd)); memset(tsd, 0, sizeof(*tsd));
tsd->td = td; td->init = TRUE;
tsd->port = port; tsd->port = port;
/* Treat the request as done until the thread actually starts so any early /* Treat the request as done until the thread actually starts so any early
* cleanup gets done properly. * cleanup gets done properly.
@ -278,8 +278,8 @@ unsigned int
#endif #endif
CURL_STDCALL getaddrinfo_thread(void *arg) CURL_STDCALL getaddrinfo_thread(void *arg)
{ {
struct thread_sync_data *tsd = (struct thread_sync_data *)arg; struct thread_data *td = arg;
struct thread_data *td = tsd->td; struct thread_sync_data *tsd = &td->tsd;
char service[12]; char service[12];
int rc; int rc;
@ -301,7 +301,6 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
/* too late, gotta clean up the mess */ /* too late, gotta clean up the mess */
Curl_mutex_release(tsd->mtx); Curl_mutex_release(tsd->mtx);
destroy_thread_sync_data(tsd); destroy_thread_sync_data(tsd);
free(td);
} }
else { else {
#ifndef CURL_DISABLE_SOCKETPAIR #ifndef CURL_DISABLE_SOCKETPAIR
@ -338,8 +337,8 @@ unsigned int
#endif #endif
CURL_STDCALL gethostbyname_thread(void *arg) CURL_STDCALL gethostbyname_thread(void *arg)
{ {
struct thread_sync_data *tsd = (struct thread_sync_data *)arg; struct thread_data *td = arg;
struct thread_data *td = tsd->td; struct thread_sync_data *tsd = &td->tsd;
tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port); tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
@ -354,7 +353,6 @@ CURL_STDCALL gethostbyname_thread(void *arg)
/* too late, gotta clean up the mess */ /* too late, gotta clean up the mess */
Curl_mutex_release(tsd->mtx); Curl_mutex_release(tsd->mtx);
destroy_thread_sync_data(tsd); destroy_thread_sync_data(tsd);
free(td);
} }
else { else {
tsd->done = TRUE; tsd->done = TRUE;
@ -371,20 +369,19 @@ CURL_STDCALL gethostbyname_thread(void *arg)
*/ */
static void destroy_async_data(struct Curl_easy *data) static void destroy_async_data(struct Curl_easy *data)
{ {
struct Curl_async *async; struct Curl_async *async = &data->state.async;
DEBUGASSERT(data); struct thread_data *td = &async->thdata;
async = &data->state.async; if(td->init) {
DEBUGASSERT(async);
if(async->tdata) {
struct thread_data *td = async->tdata;
bool done; bool done;
#ifndef CURL_DISABLE_SOCKETPAIR #ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0]; curl_socket_t sock_rd = td->tsd.sock_pair[0];
#endif #endif
#ifdef USE_HTTPSRR_ARES #ifdef USE_HTTPSRR_ARES
if(data->state.async.tdata->channel) if(data->state.async.thdata.channel) {
ares_destroy(data->state.async.tdata->channel); ares_destroy(data->state.async.thdata.channel);
data->state.async.thdata.channel = NULL;
}
#endif #endif
/* /*
* if the thread is still blocking in the resolve syscall, detach it and * if the thread is still blocking in the resolve syscall, detach it and
@ -403,8 +400,6 @@ static void destroy_async_data(struct Curl_easy *data)
Curl_thread_join(&td->thread_hnd); Curl_thread_join(&td->thread_hnd);
destroy_thread_sync_data(&td->tsd); destroy_thread_sync_data(&td->tsd);
free(async->tdata);
} }
#ifndef CURL_DISABLE_SOCKETPAIR #ifndef CURL_DISABLE_SOCKETPAIR
/* /*
@ -414,24 +409,23 @@ static void destroy_async_data(struct Curl_easy *data)
Curl_multi_closed(data, sock_rd); Curl_multi_closed(data, sock_rd);
wakeup_close(sock_rd); wakeup_close(sock_rd);
#endif #endif
}
async->tdata = NULL;
free(async->hostname); td->init = FALSE;
async->hostname = NULL; }
Curl_safefree(async->hostname);
} }
#ifdef USE_HTTPSRR_ARES #ifdef USE_HTTPSRR_ARES
static CURLcode resolve_httpsrr(struct Curl_easy *data, static CURLcode resolve_httpsrr(struct Curl_easy *data,
struct Curl_async *asp) struct Curl_async *async)
{ {
int status = ares_init_options(&asp->tdata->channel, NULL, 0); int status = ares_init_options(&async->thdata.channel, NULL, 0);
if(status != ARES_SUCCESS) if(status != ARES_SUCCESS)
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo)); memset(&async->thdata.hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec(asp->tdata->channel, ares_query_dnsrec(async->thdata.channel,
asp->hostname, ARES_CLASS_IN, async->hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS, ARES_REC_TYPE_HTTPS,
Curl_dnsrec_done_cb, data, NULL); Curl_dnsrec_done_cb, data, NULL);
@ -449,38 +443,33 @@ static bool init_resolve_thread(struct Curl_easy *data,
const char *hostname, int port, const char *hostname, int port,
const struct addrinfo *hints) const struct addrinfo *hints)
{ {
struct thread_data *td = calloc(1, sizeof(struct thread_data)); struct thread_data *td = &data->state.async.thdata;
int err = ENOMEM; int err = ENOMEM;
struct Curl_async *asp = &data->state.async; struct Curl_async *async = &data->state.async;
data->state.async.tdata = td; async->port = port;
if(!td) async->done = FALSE;
goto errno_exit; async->status = 0;
async->dns = NULL;
asp->port = port;
asp->done = FALSE;
asp->status = 0;
asp->dns = NULL;
td->thread_hnd = curl_thread_t_null; td->thread_hnd = curl_thread_t_null;
if(!init_thread_sync_data(td, hostname, port, hints)) { if(!init_thread_sync_data(td, hostname, port, hints)) {
asp->tdata = NULL;
free(td); free(td);
goto errno_exit; goto errno_exit;
} }
free(asp->hostname); free(async->hostname);
asp->hostname = strdup(hostname); async->hostname = strdup(hostname);
if(!asp->hostname) if(!async->hostname)
goto err_exit; goto err_exit;
/* The thread will set this TRUE when complete. */ /* The thread will set this TRUE when complete. */
td->tsd.done = FALSE; td->tsd.done = FALSE;
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd); td->thread_hnd = Curl_thread_create(getaddrinfo_thread, td);
#else #else
td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd); td->thread_hnd = Curl_thread_create(gethostbyname_thread, td);
#endif #endif
if(td->thread_hnd == curl_thread_t_null) { if(td->thread_hnd == curl_thread_t_null) {
@ -490,7 +479,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
goto err_exit; goto err_exit;
} }
#ifdef USE_HTTPSRR_ARES #ifdef USE_HTTPSRR_ARES
if(resolve_httpsrr(data, asp)) if(resolve_httpsrr(data, async))
infof(data, "Failed HTTPS RR operation"); infof(data, "Failed HTTPS RR operation");
#endif #endif
return TRUE; return TRUE;
@ -514,7 +503,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->state.async.thdata;
DEBUGASSERT(td); DEBUGASSERT(td);
DEBUGASSERT(td->thread_hnd != curl_thread_t_null); DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
@ -550,13 +539,12 @@ 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->state.async.thdata;
/* If we are still resolving, we must wait for the threads to fully clean up, /* If we are 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
data. */ data. */
if(td && td->thread_hnd != curl_thread_t_null if((td->thread_hnd != curl_thread_t_null) && !data->set.quick_exit)
&& (data->set.quick_exit != 1L))
(void)thread_wait_resolv(data, NULL, FALSE); (void)thread_wait_resolv(data, NULL, FALSE);
else else
Curl_resolver_cancel(data); Curl_resolver_cancel(data);
@ -589,7 +577,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->state.async.thdata;
bool done = FALSE; bool done = FALSE;
DEBUGASSERT(entry); DEBUGASSERT(entry);
@ -600,7 +588,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
return CURLE_COULDNT_RESOLVE_HOST; return CURLE_COULDNT_RESOLVE_HOST;
} }
#ifdef USE_HTTPSRR_ARES #ifdef USE_HTTPSRR_ARES
if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0) if(Curl_ares_perform(data->state.async.thdata.channel, 0) < 0)
return CURLE_UNRECOVERABLE_POLL; return CURLE_UNRECOVERABLE_POLL;
#endif #endif
@ -662,7 +650,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
timediff_t ms; timediff_t ms;
struct resdata *reslv = (struct resdata *)data->state.async.resolver; struct resdata *reslv = (struct resdata *)data->state.async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR #ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->state.async.tdata; struct thread_data *td = &data->state.async.thdata;
#endif #endif
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES) #if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
int socketi = 0; int socketi = 0;
@ -671,8 +659,8 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
#endif #endif
#ifdef USE_HTTPSRR_ARES #ifdef USE_HTTPSRR_ARES
if(data->state.async.tdata && data->state.async.tdata->channel) { if(data->state.async.thdata.channel) {
ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks); ret_val = Curl_ares_getsock(data, data->state.async.thdata.channel, socks);
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++) for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
if(!ARES_GETSOCK_READABLE(ret_val, socketi) && if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
!ARES_GETSOCK_WRITABLE(ret_val, socketi)) !ARES_GETSOCK_WRITABLE(ret_val, socketi))

View File

@ -49,7 +49,6 @@ struct thread_sync_data {
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
struct addrinfo hints; struct addrinfo hints;
#endif #endif
struct thread_data *td; /* for thread-self cleanup */
int port; int port;
int sock_error; int sock_error;
bool done; bool done;
@ -64,6 +63,7 @@ struct thread_data {
struct Curl_https_rrinfo hinfo; struct Curl_https_rrinfo hinfo;
ares_channel channel; ares_channel channel;
#endif #endif
bool init;
}; };
#elif defined(CURLRES_ARES) /* CURLRES_THREADED */ #elif defined(CURLRES_ARES) /* CURLRES_THREADED */
@ -79,7 +79,7 @@ struct thread_data {
#ifdef USE_HTTPSRR #ifdef USE_HTTPSRR
struct Curl_https_rrinfo hinfo; struct Curl_https_rrinfo hinfo;
#endif #endif
char hostname[1]; char *hostname;
}; };
#endif /* CURLRES_ARES */ #endif /* CURLRES_ARES */

View File

@ -100,7 +100,7 @@ static void httpsrr_opt(struct Curl_easy *data,
size_t len = 0; size_t len = 0;
const unsigned char *val = NULL; const unsigned char *val = NULL;
unsigned short code; unsigned short code;
struct thread_data *res = data->state.async.tdata; struct thread_data *res = &data->state.async.thdata;
struct Curl_https_rrinfo *hi = &res->hinfo; struct Curl_https_rrinfo *hi = &res->hinfo;
code = ares_dns_rr_get_opt(rr, key, idx, &val, &len); code = ares_dns_rr_get_opt(rr, key, idx, &val, &len);
@ -138,7 +138,7 @@ void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
struct Curl_easy *data = arg; struct Curl_easy *data = arg;
size_t i; size_t i;
#ifdef CURLRES_ARES #ifdef CURLRES_ARES
struct thread_data *res = data->state.async.tdata; struct thread_data *res = &data->state.async.thdata;
res->num_pending--; res->num_pending--;
#endif #endif

View File

@ -568,7 +568,9 @@ struct hostname {
struct Curl_async { struct Curl_async {
char *hostname; char *hostname;
struct Curl_dns_entry *dns; struct Curl_dns_entry *dns;
struct thread_data *tdata; #ifdef CURLRES_ASYNCH
struct thread_data thdata;
#endif
void *resolver; /* resolver state, if it is used in the URL state - void *resolver; /* resolver state, if it is used in the URL state -
ares_channel e.g. */ ares_channel e.g. */
int port; int port;