]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
urldata: move async resolver state from easy handle to connectdata
authorStefan Eissing <stefan@eissing.org>
Wed, 25 Oct 2023 10:31:34 +0000 (12:31 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 26 Oct 2023 15:29:17 +0000 (17:29 +0200)
- 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

lib/asyn-ares.c
lib/asyn-thread.c
lib/doh.c
lib/easy.c
lib/hostasyn.c
lib/hostip.c
lib/multi.c
lib/socks.c
lib/url.c
lib/urldata.h

index e73e41dab9fe35a3a48ecfc1d24d6acbed363a82..1da190127811be430fb9d532f0fdf03406371209 100644 (file)
@@ -228,9 +228,9 @@ static void destroy_async_data(struct Curl_async *async);
 void Curl_resolver_cancel(struct Curl_easy *data)
 {
   DEBUGASSERT(data);
-  if(data->state.async.resolver)
-    ares_cancel((ares_channel)data->state.async.resolver);
-  destroy_async_data(&data->state.async);
+  if(data->conn->resolve_async.resolver)
+    ares_cancel((ares_channel)data->conn->resolve_async.resolver);
+  destroy_async_data(&data->conn->resolve_async);
 }
 
 /*
@@ -278,14 +278,14 @@ int Curl_resolver_getsock(struct Curl_easy *data,
   struct timeval timebuf;
   struct timeval *timeout;
   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);
 
   maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
   maxtime.tv_usec = 0;
 
-  timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
-                         &timebuf);
+  timeout = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
+                         &maxtime, &timebuf);
   milli = (long)curlx_tvtoms(timeout);
   if(milli == 0)
     milli += 10;
@@ -313,8 +313,8 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
   int i;
   int num = 0;
 
-  bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
-                         ARES_GETSOCK_MAXNUM);
+  bitmask = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
+                         socks, ARES_GETSOCK_MAXNUM);
 
   for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
     pfd[i].events = 0;
@@ -344,12 +344,12 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
   if(!nfds)
     /* Call ares_process() unconditionally here, even if we simply timed out
        above, as otherwise the ares name resolve won't timeout! */
-    ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
-                    ARES_SOCKET_BAD);
+    ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
+                    ARES_SOCKET_BAD, ARES_SOCKET_BAD);
   else {
     /* move through the descriptors and ask for processing on them */
     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].fd:ARES_SOCKET_BAD,
                       (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,
                                    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;
 
   DEBUGASSERT(dns);
@@ -397,7 +397,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
        ARES_ECANCELLED synchronously for all pending responses.  This will
        leave us with res->num_pending == 0, which is perfect for the next
        block. */
-    ares_cancel((ares_channel)data->state.async.resolver);
+    ares_cancel((ares_channel)data->conn->resolve_async.resolver);
     DEBUGASSERT(res->num_pending == 0);
   }
 #endif
@@ -408,12 +408,12 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
        them */
     res->temp_ai = NULL;
 
-    if(!data->state.async.dns)
+    if(!data->conn->resolve_async.dns)
       result = Curl_resolver_error(data);
     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;
@@ -464,7 +464,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
     store.tv_sec = itimeout/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
        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;
     result = Curl_resolver_is_resolved(data, entry);
 
-    if(result || data->state.async.done)
+    if(result || data->conn->resolve_async.done)
       break;
 
     if(Curl_pgrsUpdate(data))
@@ -499,12 +500,12 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
   }
   if(result)
     /* 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
      in the cache. */
   if(entry)
-    *entry = data->state.async.dns;
+    *entry = data->conn->resolve_async.dns;
 
   if(result)
     /* 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! */
     return;
 
-  res = data->state.async.tdata;
+  res = data->conn->resolve_async.tdata;
   if(res) {
     res->num_pending--;
 
     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) {
         compound_results(res, ai);
       }
@@ -727,7 +729,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->conn->resolve_async.tdata;
   (void)timeouts;
   if(ARES_SUCCESS == status) {
     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);
   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;
+    data->conn->resolve_async.hostname = res->hostname;
+    data->conn->resolve_async.port = port;
+    data->conn->resolve_async.done = FALSE;   /* not done */
+    data->conn->resolve_async.status = 0;     /* clear */
+    data->conn->resolve_async.dns = NULL;     /* clear */
+    data->conn->resolve_async.tdata = res;
 
     /* initial status - failed */
     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;
       msnprintf(service, sizeof(service), "%d", port);
       res->num_pending = 1;
-      ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
-                       service, &hints, addrinfo_cb, data);
+      ares_getaddrinfo((ares_channel)data->conn->resolve_async.resolver,
+                       hostname, service, &hints, addrinfo_cb, data);
     }
 #else
 
@@ -804,10 +806,10 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
       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);
+      ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
+                          hostname, PF_INET, query_completed_cb, data);
+      ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
+                          hostname, PF_INET6, query_completed_cb, data);
     }
     else
 #endif
@@ -815,7 +817,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
       res->num_pending = 1;
 
       /* 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,
                          query_completed_cb, data);
     }
@@ -829,6 +831,7 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
                               char *servers)
 {
   CURLcode result = CURLE_NOT_BUILT_IN;
+  ares_channel channel, lchannel = NULL;
   int ares_result;
 
   /* 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;
 
 #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
-  ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
-                                           servers);
+  ares_result = ares_set_servers_ports_csv(channel, servers);
 #else
-  ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
+  ares_result = ares_set_servers_csv(channel, servers);
 #endif
   switch(ares_result) {
   case ARES_SUCCESS:
@@ -861,6 +876,9 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
     result = CURLE_BAD_FUNCTION_ARGUMENT;
     break;
   }
+out:
+  if(lchannel)
+    Curl_resolver_cleanup(lchannel);
 #else /* too old c-ares version! */
   (void)data;
   (void)(ares_result);
@@ -872,11 +890,14 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
                                 const char *interf)
 {
 #ifdef HAVE_CARES_LOCAL_DEV
-  if(!interf)
-    interf = "";
-
-  ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
+  if(data->conn) {
+    /* not a setopt test run, set the value */
+    if(!interf)
+      interf = "";
 
+    ares_set_local_dev((ares_channel)data->conn->resolve_async.resolver,
+                       interf);
+  }
   return CURLE_OK;
 #else /* c-ares version too old! */
   (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,
-                     ntohl(a4.s_addr));
+  if(data->conn) {
+    /* 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;
 #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;
 #else /* c-ares version too old! */
index a48f3f4ef0a945e786a911e494ea3ee27633605a..63414b6174612f4a094990b453a8d08b63d8f2b8 100644 (file)
@@ -136,7 +136,7 @@ static void destroy_async_data(struct Curl_async *);
  */
 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 */
@@ -173,7 +173,7 @@ struct thread_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 */
@@ -428,9 +428,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
 {
   struct thread_data *td = calloc(1, sizeof(struct thread_data));
   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)
     goto errno_exit;
 
@@ -488,7 +488,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  td = data->state.async.tdata;
+  td = data->conn->resolve_async.tdata;
   DEBUGASSERT(td);
   DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
 
@@ -500,18 +500,18 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
   else
     DEBUGASSERT(0);
 
-  data->state.async.done = TRUE;
+  data->conn->resolve_async.done = TRUE;
 
   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 */
     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");
 
   return result;
@@ -524,7 +524,7 @@ 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->conn->resolve_async.tdata;
 
   /* 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
@@ -563,7 +563,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->conn->resolve_async.tdata;
   int done = 0;
 
   DEBUGASSERT(entry);
@@ -581,13 +581,13 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
   if(done) {
     getaddrinfo_complete(data);
 
-    if(!data->state.async.dns) {
+    if(!data->conn->resolve_async.dns) {
       CURLcode result = Curl_resolver_error(data);
-      destroy_async_data(&data->state.async);
+      destroy_async_data(&data->conn->resolve_async);
       return result;
     }
-    destroy_async_data(&data->state.async);
-    *entry = data->state.async.dns;
+    destroy_async_data(&data->conn->resolve_async);
+    *entry = data->conn->resolve_async.dns;
   }
   else {
     /* 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;
   timediff_t milli;
   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
-  struct thread_data *td = data->state.async.tdata;
+  struct thread_data *td = data->conn->resolve_async.tdata;
 #else
   (void)socks;
 #endif
@@ -662,7 +662,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 int port,
                                                 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 */
 
@@ -691,7 +691,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
 {
   struct addrinfo hints;
   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 */
 
index 475095985570e2bd50683ae56ac6a983a27f9b2b..0c218535952aaf02d6deed128c266a74cfd38ce4 100644 (file)
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -901,6 +901,7 @@ UNITTEST void de_cleanup(struct dohentry *d)
 CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                               struct Curl_dns_entry **dnsp)
 {
+  struct connectdata *conn = data->conn;
   CURLcode result;
   struct dohdata *dohp = data->req.doh;
   *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 &&
      !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:
       CURLE_COULDNT_RESOLVE_HOST;
   }
@@ -970,7 +971,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
         Curl_freeaddrinfo(ai);
       }
       else {
-        data->state.async.dns = dns;
+        conn->resolve_async.dns = dns;
         *dnsp = dns;
         result = CURLE_OK;      /* address resolution OK */
       }
index a8d9b590d7a2ea8a72001a03ca36ddefa6b1d363..f3aa6729a2f951e311545d59c9686aca8dd1ca85 100644 (file)
@@ -968,33 +968,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
     (void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
   }
 #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);
 
index 2f6762ca4e1f9fcae6450fb596b35cae94c02931..faf01c5f4c030a8fa9b56d7328ea38274fff8deb 100644 (file)
@@ -67,10 +67,11 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
                                 int status,
                                 struct Curl_addrinfo *ai)
 {
+  struct connectdata *conn = data->conn;
   struct Curl_dns_entry *dns = NULL;
   CURLcode result = CURLE_OK;
 
-  data->state.async.status = status;
+  conn->resolve_async.status = status;
 
   if(CURL_ASYNC_SUCCESS == status) {
     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);
 
       dns = Curl_cache_addr(data, ai,
-                            data->state.async.hostname, 0,
-                            data->state.async.port);
+                            conn->resolve_async.hostname, 0,
+                            conn->resolve_async.port);
       if(data->share)
         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-
     threaded and once this is TRUE the other thread may read fields from the
     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
      this function */
index 28464ba87a61194f5b4fc2d799befd4312752fdb..b2690fef4e45ae8e8c43800871bab69a77eba555 100644 (file)
@@ -741,7 +741,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
       Curl_set_in_callback(data, true);
       st = data->set.resolver_start(
 #ifdef USE_CURL_ASYNC
-        data->state.async.resolver,
+        conn->resolve_async.resolver,
 #else
         NULL,
 #endif
@@ -1413,9 +1413,9 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
   struct connectdata *conn = data->conn;
 
 #ifdef USE_CURL_ASYNC
-  if(data->state.async.dns) {
-    conn->dns_entry = data->state.async.dns;
-    data->state.async.dns = NULL;
+  if(conn->resolve_async.dns) {
+    conn->dns_entry = conn->resolve_async.dns;
+    conn->resolve_async.dns = NULL;
   }
 #endif
 
@@ -1437,11 +1437,11 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
 #ifdef USE_CURL_ASYNC
 CURLcode Curl_resolver_error(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   const char *host_or_proxy;
   CURLcode result;
 
 #ifndef CURL_DISABLE_PROXY
-  struct connectdata *conn = data->conn;
   if(conn->bits.httpproxy) {
     host_or_proxy = "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,
-        data->state.async.hostname);
+        conn->resolve_async.hostname);
 
   return result;
 }
index 296f459ee30962a63e5fa063738b6f7c6f8ca6c9..a6423f63383af67462a2b733471c4443165157e9 100644 (file)
@@ -1986,8 +1986,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 
       if(dns) {
 #ifdef CURLRES_ASYNCH
-        data->state.async.dns = dns;
-        data->state.async.done = TRUE;
+        conn->resolve_async.dns = dns;
+        conn->resolve_async.done = TRUE;
 #endif
         result = CURLE_OK;
         infof(data, "Hostname '%s' was found in DNS cache", hostname);
index 9bb9436c7a0a9ffa3fd74d227d46ea635c4f3c68..30909f82fa258fa436a11dfc2440ec137c9b5ff0 100644 (file)
@@ -339,8 +339,8 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
 
     if(dns) {
 #ifdef CURLRES_ASYNCH
-      data->state.async.dns = dns;
-      data->state.async.done = TRUE;
+      conn->resolve_async.dns = dns;
+      conn->resolve_async.done = TRUE;
 #endif
       infof(data, "Hostname '%s' was found", sx->hostname);
       sxstate(sx, data, CONNECT_RESOLVED);
@@ -806,8 +806,8 @@ CONNECT_REQ_INIT:
 
     if(dns) {
 #ifdef CURLRES_ASYNCH
-      data->state.async.dns = dns;
-      data->state.async.done = TRUE;
+      conn->resolve_async.dns = dns;
+      conn->resolve_async.done = TRUE;
 #endif
       infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
     }
index 0eb14263a13a4a70fbf524e522d8617175cc84aa..f3ca694d5971874f9ff66330c1b1772d0af08fde 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -422,10 +422,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
   Curl_safefree(data->info.contenttype);
   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);
 
   /* No longer a dirty share, if it exists */
@@ -652,13 +648,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
 
   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);
   if(!result) {
     Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
@@ -675,7 +664,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
   }
 
   if(result) {
-    Curl_resolver_cleanup(data->state.async.resolver);
     Curl_dyn_free(&data->state.headerb);
     Curl_freeset(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_resolver_cleanup(conn->resolve_async.resolver);
   Curl_free_idnconverted_hostname(&conn->host);
   Curl_free_idnconverted_hostname(&conn->conn_to_host);
 #ifndef CURL_DISABLE_PROXY
@@ -809,6 +798,7 @@ void Curl_disconnect(struct Curl_easy *data,
     conn->handler->disconnect(data, conn, dead_connection);
 
   conn_shutdown(data);
+  Curl_resolver_cancel(data);
 
   /* detach it again */
   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
        * 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);
+
+#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);
       if(result)
         goto out;
index e81dab1bb7aad7ef85cd141d8720cd6045189072..2f927a393ef57d2c53225ed9ee0237ab1a0d661a 100644 (file)
@@ -917,6 +917,9 @@ struct connectdata {
      multi_done(). This entry will be NULL if the connection is reused as then
      there is no name resolve done. */
   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
    * and NULLed by the connected socket filter (if there is one). */
@@ -1374,9 +1377,6 @@ struct UrlState {
 #endif
   struct auth authhost;  /* auth details for host */
   struct auth authproxy; /* auth details for proxy */
-#ifdef USE_CURL_ASYNC
-  struct Curl_async async;  /* asynchronous name resolver data */
-#endif
 
 #if defined(USE_OPENSSL)
   /* void instead of ENGINE to avoid bleeding OpenSSL into this header */