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)
{
if(async->tdata) {
struct thread_data *res = async->tdata;
if(res) {
if(res->temp_ai) {
Curl_freeaddrinfo(res->temp_ai);
res->temp_ai = NULL;
}
free(res);
}
async->tdata = NULL;
struct thread_data *res = &async->thdata;
if(res->temp_ai) {
Curl_freeaddrinfo(res->temp_ai);
res->temp_ai = 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,
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;
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
are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
expires. */
if(res
&& res->num_pending
if(res->num_pending
/* 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_usec)
@ -419,7 +413,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
}
#endif
if(res && !res->num_pending) {
if(!res->num_pending) {
(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
them */
@ -589,7 +583,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
struct hostent *hostent)
{
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
(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! */
return;
res = data->state.async.tdata;
if(res) {
res->num_pending--;
res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) {
struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
if(ai) {
compound_results(res, ai);
}
if(CURL_ASYNC_SUCCESS == status) {
struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
if(ai) {
compound_results(res, ai);
}
/* A successful result overwrites any previous error */
if(res->last_status != ARES_SUCCESS)
res->last_status = status;
}
/* A successful result overwrites any previous error */
if(res->last_status != ARES_SUCCESS)
res->last_status = status;
/* If there are responses still pending, we presume they must be the
complementary IPv4 or IPv6 lookups that we started in parallel in
Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a
"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. */
if(res->num_pending
/* Only these c-ares status values count as "definitive" for these
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
aggressive in our timeouts for the other response. Other errors are
either a result of bad input (which should affect all parallel
requests), local or network conditions, non-definitive server
responses, or us cancelling the request. */
&& (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
/* Right now, there can only be up to two parallel queries, so do not
bother handling any other cases. */
DEBUGASSERT(res->num_pending == 1);
/* If there are responses still pending, we presume they must be the
complementary IPv4 or IPv6 lookups that we started in parallel in
Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a
"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. */
if(res->num_pending
/* Only these c-ares status values count as "definitive" for these
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
aggressive in our timeouts for the other response. Other errors are
either a result of bad input (which should affect all parallel
requests), local or network conditions, non-definitive server
responses, or us cancelling the request. */
&& (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
/* Right now, there can only be up to two parallel queries, so do not
bother handling any other cases. */
DEBUGASSERT(res->num_pending == 1);
/* it is possible that one of these parallel queries could succeed
quickly, but the other could always fail or timeout (when we are
talking to a pool of DNS servers that can only successfully resolve
IPv4 address, for example).
/* it is possible that one of these parallel queries could succeed
quickly, but the other could always fail or timeout (when we are
talking to a pool of DNS servers that can only successfully resolve
IPv4 address, for example).
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
fulfill it successfully. But, to align with the philosophy of Happy
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
ones do).
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
fulfill it successfully. But, to align with the philosophy of Happy
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
ones do).
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
pending responses. Even though it is typical that this resolved
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
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
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
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
wait "too much longer" after we get a result.
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
pending responses. Even though it is typical that this resolved
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
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
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
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
wait "too much longer" after we get a result.
We simply wait an additional amount of time equal to the default
c-ares query timeout. That is enough time for a typical parallel
response to arrive without being "too long". Even on a network
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
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
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
timeout to prevent it. After all, we do not even know where in the
c-ares retry cycle each request is.
*/
res->happy_eyeballs_dns_time = Curl_now();
Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
EXPIRE_HAPPY_EYEBALLS_DNS);
}
We simply wait an additional amount of time equal to the default
c-ares query timeout. That is enough time for a typical parallel
response to arrive without being "too long". Even on a network
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
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
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
timeout to prevent it. After all, we do not even know where in the
c-ares retry cycle each request is.
*/
res->happy_eyeballs_dns_time = Curl_now();
Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
EXPIRE_HAPPY_EYEBALLS_DNS);
}
}
#else
@ -756,7 +747,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result)
{
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;
if(ARES_SUCCESS == status) {
res->temp_ai = ares2addr(result->nodes);
@ -781,87 +772,86 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port,
int *waitp)
{
struct thread_data *res = NULL;
size_t namelen = strlen(hostname);
struct thread_data *res = &data->state.async.thdata;
*waitp = 0; /* default to synchronous response */
res = calloc(1, sizeof(struct thread_data) + namelen);
if(res) {
strcpy(res->hostname, hostname);
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;
res->hostname = strdup(hostname);
if(!res->hostname)
return NULL;
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
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 */
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
#ifdef HAVE_CARES_GETADDRINFO
{
struct ares_addrinfo_hints hints;
char service[12];
int pf = PF_INET;
memset(&hints, 0, sizeof(hints));
{
struct ares_addrinfo_hints hints;
char service[12];
int pf = PF_INET;
memset(&hints, 0, sizeof(hints));
#ifdef CURLRES_IPV6
if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
Curl_ipv6works(data)) {
/* The stack seems to be IPv6-enabled */
if(data->conn->ip_version == CURL_IPRESOLVE_V6)
pf = PF_INET6;
else
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);
if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
Curl_ipv6works(data)) {
/* The stack seems to be IPv6-enabled */
if(data->conn->ip_version == CURL_IPRESOLVE_V6)
pf = PF_INET6;
else
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);
}
#else
#ifdef HAVE_CARES_IPV6
if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
/* The stack seems to be IPv6-enabled */
res->num_pending = 2;
if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
/* The stack seems to be IPv6-enabled */
res->num_pending = 2;
/* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
PF_INET, query_completed_cb, data);
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
PF_INET6, query_completed_cb, data);
}
else
/* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
PF_INET, query_completed_cb, data);
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
PF_INET6, query_completed_cb, data);
}
else
#endif
{
res->num_pending = 1;
{
res->num_pending = 1;
/* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->state.async.resolver,
hostname, PF_INET,
query_completed_cb, data);
}
/* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->state.async.resolver,
hostname, PF_INET,
query_completed_cb, data);
}
#endif
#ifdef USE_HTTPSRR_ARES
{
res->num_pending++; /* one more */
memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec((ares_channel)data->state.async.resolver,
hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS,
Curl_dnsrec_done_cb, data, NULL);
}
#endif
*waitp = 1; /* expect asynchronous response */
{
res->num_pending++; /* one more */
memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec((ares_channel)data->state.async.resolver,
hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS,
Curl_dnsrec_done_cb, data, NULL);
}
#endif
*waitp = 1; /* expect asynchronous response */
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)
{
return &(data->state.async.tdata->tsd);
return &(data->state.async.thdata.tsd);
}
/* Destroy resolver thread synchronization data */
@ -190,15 +190,15 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
/* Initialize resolver thread synchronization data */
static
int init_thread_sync_data(struct thread_data *td,
const char *hostname,
int port,
const struct addrinfo *hints)
const char *hostname,
int port,
const struct addrinfo *hints)
{
struct thread_sync_data *tsd = &td->tsd;
memset(tsd, 0, sizeof(*tsd));
tsd->td = td;
td->init = TRUE;
tsd->port = port;
/* Treat the request as done until the thread actually starts so any early
* cleanup gets done properly.
@ -278,8 +278,8 @@ unsigned int
#endif
CURL_STDCALL getaddrinfo_thread(void *arg)
{
struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
struct thread_data *td = tsd->td;
struct thread_data *td = arg;
struct thread_sync_data *tsd = &td->tsd;
char service[12];
int rc;
@ -301,7 +301,6 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
/* too late, gotta clean up the mess */
Curl_mutex_release(tsd->mtx);
destroy_thread_sync_data(tsd);
free(td);
}
else {
#ifndef CURL_DISABLE_SOCKETPAIR
@ -338,8 +337,8 @@ unsigned int
#endif
CURL_STDCALL gethostbyname_thread(void *arg)
{
struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
struct thread_data *td = tsd->td;
struct thread_data *td = arg;
struct thread_sync_data *tsd = &td->tsd;
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 */
Curl_mutex_release(tsd->mtx);
destroy_thread_sync_data(tsd);
free(td);
}
else {
tsd->done = TRUE;
@ -371,20 +369,19 @@ CURL_STDCALL gethostbyname_thread(void *arg)
*/
static void destroy_async_data(struct Curl_easy *data)
{
struct Curl_async *async;
DEBUGASSERT(data);
async = &data->state.async;
DEBUGASSERT(async);
if(async->tdata) {
struct thread_data *td = async->tdata;
struct Curl_async *async = &data->state.async;
struct thread_data *td = &async->thdata;
if(td->init) {
bool done;
#ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0];
#endif
#ifdef USE_HTTPSRR_ARES
if(data->state.async.tdata->channel)
ares_destroy(data->state.async.tdata->channel);
if(data->state.async.thdata.channel) {
ares_destroy(data->state.async.thdata.channel);
data->state.async.thdata.channel = NULL;
}
#endif
/*
* 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);
destroy_thread_sync_data(&td->tsd);
free(async->tdata);
}
#ifndef CURL_DISABLE_SOCKETPAIR
/*
@ -414,24 +409,23 @@ static void destroy_async_data(struct Curl_easy *data)
Curl_multi_closed(data, sock_rd);
wakeup_close(sock_rd);
#endif
}
async->tdata = NULL;
free(async->hostname);
async->hostname = NULL;
td->init = FALSE;
}
Curl_safefree(async->hostname);
}
#ifdef USE_HTTPSRR_ARES
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)
return CURLE_FAILED_INIT;
memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec(asp->tdata->channel,
asp->hostname, ARES_CLASS_IN,
memset(&async->thdata.hinfo, 0, sizeof(struct Curl_https_rrinfo));
ares_query_dnsrec(async->thdata.channel,
async->hostname, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS,
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 struct addrinfo *hints)
{
struct thread_data *td = calloc(1, sizeof(struct thread_data));
struct thread_data *td = &data->state.async.thdata;
int err = ENOMEM;
struct Curl_async *asp = &data->state.async;
struct Curl_async *async = &data->state.async;
data->state.async.tdata = td;
if(!td)
goto errno_exit;
asp->port = port;
asp->done = FALSE;
asp->status = 0;
asp->dns = NULL;
async->port = port;
async->done = FALSE;
async->status = 0;
async->dns = NULL;
td->thread_hnd = curl_thread_t_null;
if(!init_thread_sync_data(td, hostname, port, hints)) {
asp->tdata = NULL;
free(td);
goto errno_exit;
}
free(asp->hostname);
asp->hostname = strdup(hostname);
if(!asp->hostname)
free(async->hostname);
async->hostname = strdup(hostname);
if(!async->hostname)
goto err_exit;
/* The thread will set this TRUE when complete. */
td->tsd.done = FALSE;
#ifdef HAVE_GETADDRINFO
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, td);
#else
td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
td->thread_hnd = Curl_thread_create(gethostbyname_thread, td);
#endif
if(td->thread_hnd == curl_thread_t_null) {
@ -490,7 +479,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
goto err_exit;
}
#ifdef USE_HTTPSRR_ARES
if(resolve_httpsrr(data, asp))
if(resolve_httpsrr(data, async))
infof(data, "Failed HTTPS RR operation");
#endif
return TRUE;
@ -514,7 +503,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
td = data->state.async.tdata;
td = &data->state.async.thdata;
DEBUGASSERT(td);
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)
{
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,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */
if(td && td->thread_hnd != curl_thread_t_null
&& (data->set.quick_exit != 1L))
if((td->thread_hnd != curl_thread_t_null) && !data->set.quick_exit)
(void)thread_wait_resolv(data, NULL, FALSE);
else
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,
struct Curl_dns_entry **entry)
{
struct thread_data *td = data->state.async.tdata;
struct thread_data *td = &data->state.async.thdata;
bool done = FALSE;
DEBUGASSERT(entry);
@ -600,7 +588,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
return CURLE_COULDNT_RESOLVE_HOST;
}
#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;
#endif
@ -662,7 +650,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
timediff_t ms;
struct resdata *reslv = (struct resdata *)data->state.async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->state.async.tdata;
struct thread_data *td = &data->state.async.thdata;
#endif
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
int socketi = 0;
@ -671,8 +659,8 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
#endif
#ifdef USE_HTTPSRR_ARES
if(data->state.async.tdata && data->state.async.tdata->channel) {
ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks);
if(data->state.async.thdata.channel) {
ret_val = Curl_ares_getsock(data, data->state.async.thdata.channel, socks);
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
!ARES_GETSOCK_WRITABLE(ret_val, socketi))

View File

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

View File

@ -100,7 +100,7 @@ static void httpsrr_opt(struct Curl_easy *data,
size_t len = 0;
const unsigned char *val = NULL;
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;
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;
size_t i;
#ifdef CURLRES_ARES
struct thread_data *res = data->state.async.tdata;
struct thread_data *res = &data->state.async.thdata;
res->num_pending--;
#endif

View File

@ -568,7 +568,9 @@ struct hostname {
struct Curl_async {
char *hostname;
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 -
ares_channel e.g. */
int port;