]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
asyn-thread: do not allocate thread_data separately
authorDaniel Stenberg <daniel@haxx.se>
Thu, 6 Feb 2025 15:05:56 +0000 (16:05 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 13 Feb 2025 14:35:40 +0000 (15:35 +0100)
Put the full struct into Curl_async since it will be used for every name
resolve anyway.

Closes #16241

lib/asyn-ares.c
lib/asyn-thread.c
lib/asyn.h
lib/httpsrr.c
lib/urldata.h

index 640c8a9b653489ad0712a9b06860d356ef9a87f4..6caba3ceba8d9c3ee511f240539cc6d3daff3bb9 100644 (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,80 +594,77 @@ 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);
-      }
-    }
-    /* 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);
-
-      /* 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).
-
-         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);
+  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;
+
+  /* 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 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.
+
+       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
 /* c-ares 1.16.0 or later */
@@ -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;
+
+  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;
+  /* 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;
-
-      /* 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
+  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
 #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 */
 }
 
index f98941596eb0a61b1e51f6177b84c59323580d43..1fe88f9b0b4f8cc8ab553c9b74365d85ba73ca5c 100644 (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))
index 5a21329cf36bb60b60a24d664a7ee32048e228b0..d22378f06cdc7caa6df6aad7e8ae740d138537bd 100644 (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 */
index 9884b92580b43fa59b6b66dae2081fc6adc16239..3072f60bb1d0996290b7f59b8ca2b7b354c2d603 100644 (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
index d9acb2b7bf36a63aa00870a9bda9b3a81f9ab167..58b9d7983ae8fcd0b178b2134adb050b975ac444 100644 (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;