]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
dns_entry: move from conn to data->state
authorStefan Eissing <stefan@eissing.org>
Mon, 19 May 2025 10:25:58 +0000 (12:25 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 20 May 2025 12:49:17 +0000 (14:49 +0200)
The `struct Curl_dns_entry *` used to established a connection
do not have the connection's lifetime, but the transfer's lifetime
(of the transfer that initiates the connect).

`Curl_dns_entry *` is reference counted with the "dns cache". That
cache might be owned by the multi or the transfer's share. In the
share, the reference count needs updating under lock.

Therefore, the dns entry can only be kept *and* released using the
same transfer it was initially looked up from. But a connection is
often discarded using another transfer.

So far, the problem of this has been avoided in clearing the connection's
dns entries in the "multi_don()" handling. So, connections had NULL
dns entries after the initial transfers and its connect had been handled.

Keeping the dns entries in data->state seems therefore a better choice.

Also: remove the `struct Curl_dns_entry *` from the connect filters
contexts. Use `data->state.dns` every time instead and fail correctly
when not present and needed.

Closes #17383

14 files changed:
lib/cf-https-connect.c
lib/cf-https-connect.h
lib/connect.c
lib/connect.h
lib/cshutdn.c
lib/easy.c
lib/ftp.c
lib/hostip.c
lib/hostip.h
lib/multi.c
lib/setopt.c
lib/url.c
lib/url.h
lib/urldata.h

index 53dae9900d559d6062e8d2fa7ca069818e3509e3..c677f12f7bbf7fa402d96512335b51455d3dbd37 100644 (file)
@@ -113,7 +113,6 @@ static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
 
 struct cf_hc_ctx {
   cf_hc_state state;
-  const struct Curl_dns_entry *remotehost;
   struct curltime started;  /* when connect started */
   CURLcode result;          /* overall result */
   struct cf_hc_baller ballers[2];
@@ -147,7 +146,6 @@ static void cf_hc_baller_init(struct cf_hc_baller *b,
                               struct Curl_easy *data,
                               int transport)
 {
-  struct cf_hc_ctx *ctx = cf->ctx;
   struct Curl_cfilter *save = cf->next;
 
   cf->next = NULL;
@@ -161,8 +159,8 @@ static void cf_hc_baller_init(struct cf_hc_baller *b,
   }
 
   if(!b->result)
-    b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
-                                           transport, CURL_CF_SSL_ENABLE);
+    b->result = Curl_cf_setup_insert_after(cf, data, transport,
+                                           CURL_CF_SSL_ENABLE);
   b->cf = cf->next;
   cf->next = save;
 }
@@ -576,7 +574,6 @@ struct Curl_cftype Curl_cft_http_connect = {
 
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
                              struct Curl_easy *data,
-                             const struct Curl_dns_entry *remotehost,
                              enum alpnid *alpnids, size_t alpn_count)
 {
   struct Curl_cfilter *cf = NULL;
@@ -598,7 +595,6 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
-  ctx->remotehost = remotehost;
   for(i = 0; i < alpn_count; ++i)
     cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
   for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
@@ -620,14 +616,13 @@ out:
 static CURLcode cf_http_connect_add(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     int sockindex,
-                                    const struct Curl_dns_entry *remotehost,
                                     enum alpnid *alpn_ids, size_t alpn_count)
 {
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_hc_create(&cf, data, remotehost, alpn_ids, alpn_count);
+  result = cf_hc_create(&cf, data, alpn_ids, alpn_count);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -648,8 +643,7 @@ static bool cf_https_alpns_contain(enum alpnid id,
 
 CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              struct connectdata *conn,
-                             int sockindex,
-                             const struct Curl_dns_entry *remotehost)
+                             int sockindex)
 {
   enum alpnid alpn_ids[2];
   size_t alpn_count = 0;
@@ -657,7 +651,6 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
   struct Curl_cfilter cf_fake, *cf = NULL;
 
   (void)sockindex;
-  (void)remotehost;
   /* we want to log for the filter before we create it, fake it. */
   memset(&cf_fake, 0, sizeof(cf_fake));
   cf_fake.cft = &Curl_cft_http_connect;
@@ -669,7 +662,8 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
      * We are here after having selected a connection to a host+port and
      * can no longer change that. Any HTTPSRR advice for other hosts and ports
      * we need to ignore. */
-    struct Curl_https_rrinfo *rr = remotehost ? remotehost->hinfo : NULL;
+    struct Curl_dns_entry *dns = data->state.dns[sockindex];
+    struct Curl_https_rrinfo *rr = dns ? dns->hinfo : NULL;
     if(rr && !rr->no_def_alpn &&  /* ALPNs are defaults */
        (!rr->target ||      /* for same host */
         !rr->target[0] ||
@@ -739,8 +733,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
   /* If we identified ALPNs to use, install our filter. Otherwise,
    * install nothing, so our call will use a default connect setup. */
   if(alpn_count) {
-    result = cf_http_connect_add(data, conn, sockindex, remotehost,
-                                 alpn_ids, alpn_count);
+    result = cf_http_connect_add(data, conn, sockindex, alpn_ids, alpn_count);
   }
 
 out:
index 4ff9ef8d37f866aa886415adde0594b6ae144db0..c36726f0a222d4b619d578dbc1eee2e9b6820001 100644 (file)
@@ -38,20 +38,17 @@ extern struct Curl_cftype Curl_cft_http_connect;
 CURLcode Curl_cf_http_connect_add(struct Curl_easy *data,
                                   struct connectdata *conn,
                                   int sockindex,
-                                  const struct Curl_dns_entry *remotehost,
                                   bool try_h3, bool try_h21);
 
 CURLcode
 Curl_cf_http_connect_insert_after(struct Curl_cfilter *cf_at,
                                   struct Curl_easy *data,
-                                  const struct Curl_dns_entry *remotehost,
                                   bool try_h3, bool try_h21);
 
 
 CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              struct connectdata *conn,
-                             int sockindex,
-                             const struct Curl_dns_entry *remotehost);
+                             int sockindex);
 
 
 #endif /* !defined(CURL_DISABLE_HTTP) */
index 2ae87bc0c12dc61474454848551034d22510a9e9..1dcdde3fc5a8c224e39ee995a55099bddf7bc190 100644 (file)
@@ -408,7 +408,6 @@ typedef enum {
 struct cf_he_ctx {
   int transport;
   cf_ip_connect_create *cf_create;
-  const struct Curl_dns_entry *remotehost;
   cf_connect_state state;
   struct eyeballer *baller[2];
   struct eyeballer *winner;
@@ -782,8 +781,7 @@ evaluate:
  * There might be more than one IP address to try out.
  */
 static CURLcode start_connect(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              const struct Curl_dns_entry *remotehost)
+                              struct Curl_easy *data)
 {
   struct cf_he_ctx *ctx = cf->ctx;
   struct connectdata *conn = cf->conn;
@@ -791,6 +789,10 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
   int ai_family0 = 0, ai_family1 = 0;
   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
   const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
+  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
+
+  if(!dns)
+    return CURLE_FAILED_INIT;
 
   if(timeout_ms < 0) {
     /* a precaution, no need to continue if time already is up */
@@ -800,7 +802,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
 
   ctx->started = curlx_now();
 
-  /* remotehost->addr is the list of addresses from the resolver, each
+  /* dns->addr is the list of addresses from the resolver, each
    * with an address family. The list has at least one entry, possibly
    * many more.
    * We try at most 2 at a time, until we either get a connection or
@@ -812,27 +814,27 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
   if(conn->ip_version == CURL_IPRESOLVE_V6) {
 #ifdef USE_IPV6
     ai_family0 = AF_INET6;
-    addr0 = addr_first_match(remotehost->addr, ai_family0);
+    addr0 = addr_first_match(dns->addr, ai_family0);
 #endif
   }
   else if(conn->ip_version == CURL_IPRESOLVE_V4) {
     ai_family0 = AF_INET;
-    addr0 = addr_first_match(remotehost->addr, ai_family0);
+    addr0 = addr_first_match(dns->addr, ai_family0);
   }
   else {
     /* no user preference, we try ipv6 always first when available */
 #ifdef USE_IPV6
     ai_family0 = AF_INET6;
-    addr0 = addr_first_match(remotehost->addr, ai_family0);
+    addr0 = addr_first_match(dns->addr, ai_family0);
 #endif
     /* next candidate is ipv4 */
     ai_family1 = AF_INET;
-    addr1 = addr_first_match(remotehost->addr, ai_family1);
+    addr1 = addr_first_match(dns->addr, ai_family1);
     /* no ip address families, probably AF_UNIX or something, use the
      * address family given to us */
-    if(!addr1  && !addr0 && remotehost->addr) {
-      ai_family0 = remotehost->addr->ai_family;
-      addr0 = addr_first_match(remotehost->addr, ai_family0);
+    if(!addr1  && !addr0 && dns->addr) {
+      ai_family0 = dns->addr->ai_family;
+      addr0 = addr_first_match(dns->addr, ai_family0);
     }
   }
 
@@ -966,7 +968,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
     case SCFST_INIT:
       DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data));
       DEBUGASSERT(!cf->connected);
-      result = start_connect(cf, data, ctx->remotehost);
+      result = start_connect(cf, data);
       if(result)
         return result;
       ctx->state = SCFST_WAITING;
@@ -1158,7 +1160,6 @@ cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
                          struct Curl_easy *data,
                          struct connectdata *conn,
                          cf_ip_connect_create *cf_create,
-                         const struct Curl_dns_entry *remotehost,
                          int transport)
 {
   struct cf_he_ctx *ctx = NULL;
@@ -1174,14 +1175,13 @@ cf_happy_eyeballs_create(struct Curl_cfilter **pcf,
   }
   ctx->transport = transport;
   ctx->cf_create = cf_create;
-  ctx->remotehost = remotehost;
 
   result = Curl_cf_create(pcf, &Curl_cft_happy_eyeballs, ctx);
 
 out:
   if(result) {
     Curl_safefree(*pcf);
-    Curl_safefree(ctx);
+    free(ctx);
   }
   return result;
 }
@@ -1220,7 +1220,6 @@ static cf_ip_connect_create *get_cf_create(int transport)
 
 static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
                                    struct Curl_easy *data,
-                                   const struct Curl_dns_entry *remotehost,
                                    int transport)
 {
   cf_ip_connect_create *cf_create;
@@ -1235,8 +1234,7 @@ static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
     return CURLE_UNSUPPORTED_PROTOCOL;
   }
   result = cf_happy_eyeballs_create(&cf, data, cf_at->conn,
-                                    cf_create, remotehost,
-                                    transport);
+                                    cf_create, transport);
   if(result)
     return result;
 
@@ -1256,7 +1254,6 @@ typedef enum {
 
 struct cf_setup_ctx {
   cf_setup_state state;
-  const struct Curl_dns_entry *remotehost;
   int ssl_mode;
   int transport;
 };
@@ -1267,6 +1264,7 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
 {
   struct cf_setup_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
+  struct Curl_dns_entry *dns = data->state.dns[cf->sockindex];
 
   if(cf->connected) {
     *done = TRUE;
@@ -1275,6 +1273,9 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
 
   /* connect current sub-chain */
 connect_sub_chain:
+  if(!dns)
+    return CURLE_FAILED_INIT;
+
   if(cf->next && !cf->next->connected) {
     result = Curl_conn_cf_connect(cf->next, data, done);
     if(result || !*done)
@@ -1282,7 +1283,7 @@ connect_sub_chain:
   }
 
   if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
-    result = cf_he_insert_after(cf, data, ctx->remotehost, ctx->transport);
+    result = cf_he_insert_after(cf, data, ctx->transport);
     if(result)
       return result;
     ctx->state = CF_SETUP_CNNCT_EYEBALLS;
@@ -1410,7 +1411,6 @@ struct Curl_cftype Curl_cft_setup = {
 
 static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
                                 struct Curl_easy *data,
-                                const struct Curl_dns_entry *remotehost,
                                 int transport,
                                 int ssl_mode)
 {
@@ -1425,7 +1425,6 @@ static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
     goto out;
   }
   ctx->state = CF_SETUP_INIT;
-  ctx->remotehost = remotehost;
   ctx->ssl_mode = ssl_mode;
   ctx->transport = transport;
 
@@ -1436,14 +1435,15 @@ static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
 
 out:
   *pcf = result ? NULL : cf;
-  free(ctx);
+  if(ctx) {
+    free(ctx);
+  }
   return result;
 }
 
 static CURLcode cf_setup_add(struct Curl_easy *data,
                              struct connectdata *conn,
                              int sockindex,
-                             const struct Curl_dns_entry *remotehost,
                              int transport,
                              int ssl_mode)
 {
@@ -1451,7 +1451,7 @@ static CURLcode cf_setup_add(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+  result = cf_setup_create(&cf, data, transport, ssl_mode);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -1476,7 +1476,6 @@ void Curl_debug_set_transport_provider(int transport,
 
 CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
                                     struct Curl_easy *data,
-                                    const struct Curl_dns_entry *remotehost,
                                     int transport,
                                     int ssl_mode)
 {
@@ -1484,7 +1483,7 @@ CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
   CURLcode result;
 
   DEBUGASSERT(data);
-  result = cf_setup_create(&cf, data, remotehost, transport, ssl_mode);
+  result = cf_setup_create(&cf, data, transport, ssl_mode);
   if(result)
     goto out;
   Curl_conn_cf_insert_after(cf_at, cf);
@@ -1495,19 +1494,23 @@ out:
 CURLcode Curl_conn_setup(struct Curl_easy *data,
                          struct connectdata *conn,
                          int sockindex,
-                         const struct Curl_dns_entry *remotehost,
+                         struct Curl_dns_entry *dns,
                          int ssl_mode)
 {
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
   DEBUGASSERT(conn->handler);
+  DEBUGASSERT(dns);
+
+  Curl_resolv_unlink(data, &data->state.dns[sockindex]);
+  data->state.dns[sockindex] = dns;
 
 #if !defined(CURL_DISABLE_HTTP)
   if(!conn->cfilter[sockindex] &&
      conn->handler->protocol == CURLPROTO_HTTPS) {
     DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
-    result = Curl_cf_https_setup(data, conn, sockindex, remotehost);
+    result = Curl_cf_https_setup(data, conn, sockindex);
     if(result)
       goto out;
   }
@@ -1515,13 +1518,14 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
 
   /* Still no cfilter set, apply default. */
   if(!conn->cfilter[sockindex]) {
-    result = cf_setup_add(data, conn, sockindex, remotehost,
-                          conn->transport, ssl_mode);
+    result = cf_setup_add(data, conn, sockindex, conn->transport, ssl_mode);
     if(result)
       goto out;
   }
 
   DEBUGASSERT(conn->cfilter[sockindex]);
 out:
+  if(result)
+    Curl_resolv_unlink(data, &data->state.dns[sockindex]);
   return result;
 }
index 81391aa430e6ad1a06e4bb952eebdfcf9145438a..120338eb99fb96a9c921bdcae63a913c09dd2899 100644 (file)
@@ -126,7 +126,6 @@ typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
 
 CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
                                     struct Curl_easy *data,
-                                    const struct Curl_dns_entry *remotehost,
                                     int transport,
                                     int ssl_mode);
 
@@ -138,7 +137,7 @@ CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
 CURLcode Curl_conn_setup(struct Curl_easy *data,
                          struct connectdata *conn,
                          int sockindex,
-                         const struct Curl_dns_entry *remotehost,
+                         struct Curl_dns_entry *dns,
                          int ssl_mode);
 
 extern struct Curl_cftype Curl_cft_happy_eyeballs;
index 46c93689f64b8722db6b11538a26b1df11083c4c..f05b87d277af8cc4d8a7e10f916cdbf8390e164f 100644 (file)
@@ -53,8 +53,6 @@ static void cshutdn_run_conn_handler(struct Curl_easy *data,
                                      struct connectdata *conn)
 {
   if(!conn->bits.shutdown_handler) {
-    if(conn->dns_entry)
-      Curl_resolv_unlink(data, &conn->dns_entry);
 
     /* Cleanup NTLM connection-related data */
     Curl_http_auth_cleanup_ntlm(conn);
index 4dab47284a0ec67cbd2a4d31b18415a512d4464f..9d824244e9bce665508555a8f5ee6dc7005c6f68 100644 (file)
@@ -1084,8 +1084,10 @@ void curl_easy_reset(CURL *d)
 
   /* clear all meta data */
   Curl_meta_reset(data);
-  /* clear any async resolve data */
+  /* clear any resolve data */
   Curl_async_shutdown(data);
+  Curl_resolv_unlink(data, &data->state.dns[0]);
+  Curl_resolv_unlink(data, &data->state.dns[1]);
   /* zero out UserDefined data: */
   Curl_freeset(data);
   memset(&data->set, 0, sizeof(struct UserDefined));
index b47406f8c225e63078b7174b6c3b97d93baa05b3..e28236da01f34727d03ce5fc5bf514e7ccdc79d6 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1941,7 +1941,6 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
                            CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
 
   if(result) {
-    Curl_resolv_unlink(data, &dns); /* we are done using this dns entry */
     if(ftpc->count1 == 0 && ftpcode == 229)
       return ftp_epsv_disable(data, ftpc, conn);
 
@@ -1959,8 +1958,6 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     /* this just dumps information about this second connection */
     ftp_pasv_verbose(data, dns->addr, ftpc->newhost, connectport);
 
-  Curl_resolv_unlink(data, &dns); /* we are done using this address */
-
   free(conn->secondaryhostname);
   conn->secondary_port = ftpc->newport;
   conn->secondaryhostname = strdup(ftpc->newhost);
index 6cb695f3c4ae1bf1d1905adc639e721c35267d5d..ca6724ed55dcf64b215be2489176f4c24559fb8b 100644 (file)
@@ -1534,19 +1534,21 @@ int Curl_resolv_getsock(struct Curl_easy *data,
 
    Note: this function disconnects and frees the conn data in case of
    resolve failure */
-CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
+CURLcode Curl_once_resolved(struct Curl_easy *data,
+                            struct Curl_dns_entry *dns,
+                            bool *protocol_done)
 {
   CURLcode result;
   struct connectdata *conn = data->conn;
 
 #ifdef USE_CURL_ASYNC
   if(data->state.async.dns) {
-    conn->dns_entry = data->state.async.dns;
+    DEBUGASSERT(data->state.async.dns == dns);
     data->state.async.dns = NULL;
   }
 #endif
 
-  result = Curl_setup_conn(data, protocol_done);
+  result = Curl_setup_conn(data, dns, protocol_done);
 
   if(result) {
     Curl_detach_connection(data);
index 4b652c87a08b1c1ae248fe63f616271220e66c4f..cd3d957e1e7a5be121df01e4b8e97657f3f039fe 100644 (file)
@@ -133,7 +133,9 @@ void Curl_dnscache_prune(struct Curl_easy *data);
 /* IPv4 threadsafe resolve function used for synch and asynch builds */
 struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
 
-CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_connect);
+CURLcode Curl_once_resolved(struct Curl_easy *data,
+                            struct Curl_dns_entry *dns,
+                            bool *protocol_connect);
 
 /*
  * Curl_printable_address() returns a printable version of the 1st address
index f71d7a88f3fa36ad07d3ac9b1fbb2ae2a722616e..79c8975e4b2f64ca96f60f626156658064eeb315 100644 (file)
@@ -521,8 +521,8 @@ static void multi_done_locked(struct connectdata *conn,
   data->state.done = TRUE; /* called just now! */
   data->state.recent_conn_id = conn->connection_id;
 
-  if(conn->dns_entry)
-    Curl_resolv_unlink(data, &conn->dns_entry); /* done with this */
+  Curl_resolv_unlink(data, &data->state.dns[0]); /* done with this */
+  Curl_resolv_unlink(data, &data->state.dns[1]);
   Curl_dnscache_prune(data);
 
   /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
@@ -2165,7 +2165,7 @@ static CURLMcode state_resolving(struct Curl_multi *multi,
     bool connected;
     /* Perform the next step in the connection phase, and then move on to the
        WAITCONNECT state */
-    result = Curl_once_resolved(data, &connected);
+    result = Curl_once_resolved(data, dns, &connected);
 
     if(result)
       /* if Curl_once_resolved() returns failure, the connection struct is
index efa604e040d7930b4d111dbe3d0805c0c76e4934..61153f3f92f113a18695968afcde823831a99c47 100644 (file)
@@ -45,6 +45,7 @@
 #include "vtls/vtls.h"
 #include "curlx/warnless.h"
 #include "sendf.h"
+#include "hostip.h"
 #include "http2.h"
 #include "setopt.h"
 #include "multiif.h"
@@ -1602,6 +1603,10 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option,
       if(data->psl == &data->share->psl)
         data->psl = data->multi ? &data->multi->psl : NULL;
 #endif
+      if(data->share->specifier & (1 << CURL_LOCK_DATA_DNS)) {
+        Curl_resolv_unlink(data, &data->state.dns[0]);
+        Curl_resolv_unlink(data, &data->state.dns[1]);
+      }
 
       data->share->dirty--;
 
index aac9c2e84fcd60289ceecb12e2602025c6160de1..1a95267ab2adbe4157e842988bfa65420f874f88 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -291,7 +291,10 @@ CURLcode Curl_close(struct Curl_easy **datap)
   Curl_safefree(data->info.contenttype);
   Curl_safefree(data->info.wouldredirect);
 
+  /* release any resolve information this transfer kept */
   Curl_async_destroy(data);
+  Curl_resolv_unlink(data, &data->state.dns[0]); /* done with this */
+  Curl_resolv_unlink(data, &data->state.dns[1]);
 
   data_priority_cleanup(data);
 
@@ -3143,13 +3146,14 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
 #ifdef USE_UNIX_SOCKETS
 static CURLcode resolve_unix(struct Curl_easy *data,
                              struct connectdata *conn,
-                             char *unix_path)
+                             char *unix_path,
+                             struct Curl_dns_entry **pdns)
 {
-  struct Curl_dns_entry *hostaddr = NULL;
+  struct Curl_dns_entry *hostaddr;
   bool longpath = FALSE;
 
   DEBUGASSERT(unix_path);
-  DEBUGASSERT(conn->dns_entry == NULL);
+  *pdns = NULL;
 
   /* Unix domain sockets are local. The host gets ignored, just use the
    * specified domain socket address. Do not cache "DNS entries". There is
@@ -3169,7 +3173,7 @@ static CURLcode resolve_unix(struct Curl_easy *data,
   }
 
   hostaddr->refcount = 1; /* connection is the only one holding this */
-  conn->dns_entry = hostaddr;
+  *pdns = hostaddr;
   return CURLE_OK;
 }
 #endif
@@ -3179,31 +3183,35 @@ static CURLcode resolve_unix(struct Curl_easy *data,
  *************************************************************/
 static CURLcode resolve_server(struct Curl_easy *data,
                                struct connectdata *conn,
-                               bool *async)
+                               bool *async,
+                               struct Curl_dns_entry **pdns)
 {
   struct hostname *ehost;
   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
   const char *peertype = "host";
   CURLcode result;
+
+  *pdns = NULL;
+
 #ifdef USE_UNIX_SOCKETS
-  char *unix_path = conn->unix_domain_socket;
+  {
+    char *unix_path = conn->unix_domain_socket;
 
 #ifndef CURL_DISABLE_PROXY
-  if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
-     !strncmp(UNIX_SOCKET_PREFIX"/",
-              conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
-    unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
+    if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
+       !strncmp(UNIX_SOCKET_PREFIX"/",
+                conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
+      unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
 #endif
 
-  if(unix_path) {
-    /* This only works if previous transport is TRNSPRT_TCP. Check it? */
-    conn->transport = TRNSPRT_UNIX;
-    return resolve_unix(data, conn, unix_path);
+    if(unix_path) {
+      /* This only works if previous transport is TRNSPRT_TCP. Check it? */
+      conn->transport = TRNSPRT_UNIX;
+      return resolve_unix(data, conn, unix_path, pdns);
+    }
   }
 #endif
 
-  DEBUGASSERT(conn->dns_entry == NULL);
-
 #ifndef CURL_DISABLE_PROXY
   if(CONN_IS_PROXIED(conn)) {
     ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
@@ -3227,9 +3235,9 @@ static CURLcode resolve_server(struct Curl_easy *data,
 
   result = Curl_resolv_timeout(data, conn->hostname_resolve,
                                conn->primary.remote_port, conn->ip_version,
-                               &conn->dns_entry, timeout_ms);
+                               pdns, timeout_ms);
+  DEBUGASSERT(!result || !*pdns);
   if(result == CURLE_AGAIN) {
-    DEBUGASSERT(!conn->dns_entry);
     *async = TRUE;
     return CURLE_OK;
   }
@@ -3243,7 +3251,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
     failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
     return result;
   }
-  DEBUGASSERT(conn->dns_entry);
+  DEBUGASSERT(*pdns);
   return CURLE_OK;
 }
 
@@ -3348,7 +3356,7 @@ static void conn_meta_freeentry(void *p)
 
 static CURLcode create_conn(struct Curl_easy *data,
                             struct connectdata **in_connect,
-                            bool *async)
+                            bool *reusedp)
 {
   CURLcode result = CURLE_OK;
   struct connectdata *conn;
@@ -3358,7 +3366,7 @@ static CURLcode create_conn(struct Curl_easy *data,
   bool force_reuse = FALSE;
   bool waitpipe = FALSE;
 
-  *async = FALSE;
+  *reusedp = FALSE;
   *in_connect = NULL;
 
   /*************************************************************
@@ -3718,15 +3726,7 @@ static CURLcode create_conn(struct Curl_easy *data,
     /* We are reusing the connection - no need to resolve anything, and
        idnconvert_hostname() was called already in create_conn() for the reuse
        case. */
-    *async = FALSE;
-  }
-  else {
-    /*************************************************************
-     * Resolve the address of the server or proxy
-     *************************************************************/
-    result = resolve_server(data, conn, async);
-    if(result)
-      goto out;
+    *reusedp = TRUE;
   }
 
   /* persist the scheme and handler the transfer is using */
@@ -3755,21 +3755,17 @@ out:
  * Curl_setup_conn() also handles reused connections
  */
 CURLcode Curl_setup_conn(struct Curl_easy *data,
+                         struct Curl_dns_entry *dns,
                          bool *protocol_done)
 {
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
+  DEBUGASSERT(dns);
   Curl_pgrsTime(data, TIMER_NAMELOOKUP);
 
-  if(conn->handler->flags & PROTOPT_NONETWORK) {
-    /* nothing to setup when not using a network */
-    *protocol_done = TRUE;
-    return result;
-  }
-
   if(!conn->bits.reuse)
-    result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
+    result = Curl_conn_setup(data, conn, FIRSTSOCKET, dns,
                              CURL_CF_SSL_DEFAULT);
   if(!result)
     result = Curl_headers_init(data);
@@ -3785,31 +3781,52 @@ CURLcode Curl_connect(struct Curl_easy *data,
 {
   CURLcode result;
   struct connectdata *conn;
+  bool reused = FALSE;
 
   *asyncp = FALSE; /* assume synchronous resolves by default */
+  *protocol_done = FALSE;
 
   /* Set the request to virgin state based on transfer settings */
   Curl_req_hard_reset(&data->req, data);
 
   /* call the stuff that needs to be called */
-  result = create_conn(data, &conn, asyncp);
+  result = create_conn(data, &conn, &reused);
+
+  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
+    DEBUGASSERT(!conn);
+    return result;
+  }
 
   if(!result) {
-    if(CONN_ATTACHED(conn) > 1)
-      /* multiplexed */
+    DEBUGASSERT(conn);
+    if(reused) {
+      if(CONN_ATTACHED(conn) > 1)
+        /* multiplexed */
+        *protocol_done = TRUE;
+    }
+    else if(conn->handler->flags & PROTOPT_NONETWORK) {
+      *asyncp = FALSE;
+      Curl_pgrsTime(data, TIMER_NAMELOOKUP);
       *protocol_done = TRUE;
-    else if(!*asyncp) {
-      /* DNS resolution is done: that is either because this is a reused
-         connection, in which case DNS was unnecessary, or because DNS
-         really did finish already (synch resolver/fast async resolve) */
-      result = Curl_setup_conn(data, protocol_done);
+    }
+    else {
+      /*************************************************************
+       * Resolve the address of the server or proxy
+       *************************************************************/
+      struct Curl_dns_entry *dns;
+      result = resolve_server(data, conn, asyncp, &dns);
+      if(!result) {
+        *asyncp = !dns;
+        if(dns)
+          /* DNS resolution is done: that is either because this is a reused
+             connection, in which case DNS was unnecessary, or because DNS
+             really did finish already (synch resolver/fast async resolve) */
+          result = Curl_setup_conn(data, dns, protocol_done);
+      }
     }
   }
 
-  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
-    return result;
-  }
-  else if(result && conn) {
+  if(result && conn) {
     /* We are not allowed to return failure with memory left allocated in the
        connectdata struct, free those here */
     Curl_detach_connection(data);
index 76a935eceea3490816179f8ef809db49651d06eb..7aba98dbb93686824e90e395701b3e68d7c2431a 100644 (file)
--- a/lib/url.h
+++ b/lib/url.h
@@ -38,6 +38,7 @@ CURLcode Curl_uc_to_curlcode(CURLUcode uc);
 CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
 CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
 CURLcode Curl_setup_conn(struct Curl_easy *data,
+                         struct Curl_dns_entry *dns,
                          bool *protocol_done);
 void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn);
 CURLcode Curl_parse_login_details(const char *login, const size_t len,
index 9cba2c25b19bb2194a632e965335835fedc7a529..96af33dcedde1a0454d00101798aa0cf1cfd8b2a 100644 (file)
@@ -753,12 +753,6 @@ struct connectdata {
    * the connection is cleaned up (see Curl_hash_add2()).*/
   struct Curl_hash meta_hash;
 
-  /* 'dns_entry' is the particular host we use. This points to an entry in the
-     DNS cache and it will not get pruned while locked. It gets unlocked in
-     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;
-
   /* 'remote_addr' is the particular IP we connected to. it is owned, set
    * and NULLed by the connected socket filter (if there is one). */
   const struct Curl_sockaddr_ex *remote_addr;
@@ -1150,6 +1144,8 @@ struct UrlState {
 #endif
   struct auth authhost;  /* auth details for host */
   struct auth authproxy; /* auth details for proxy */
+
+  struct Curl_dns_entry *dns[2]; /* DNS to connect FIRST/SECONDARY */
 #ifdef USE_CURL_ASYNC
   struct Curl_async async;  /* asynchronous name resolver data */
 #endif