]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
multi: probe for IPv6 functionality in multi_init()
authorDaniel Stenberg <daniel@haxx.se>
Wed, 21 Jan 2026 08:14:40 +0000 (09:14 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 21 Jan 2026 08:38:31 +0000 (09:38 +0100)
In some legacy systems IPv6 might dynamically work/not work and thus
curl needs to check/probe to see if it should indeed be used.

This change moves the probe that checks for working IPv6 to the multi
handle setup function instead of delaying it to when the first name
resolve is performed. This avoids a later tricky error path if the
socket cannot be created due to OOM.

Closes #20383

lib/hostip.c
lib/hostip.h
lib/multi.c
lib/multihandle.h

index bd00efff6193791ec54ab625aab8f42acfd70cab..2ace940670c1c7aed0192cbca5aa9afcf58c5e9e 100644 (file)
@@ -741,36 +741,33 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
 }
 
 #ifdef USE_IPV6
+/* the nature of most systems is that IPv6 status does not come and go during a
+   program's lifetime so we only probe the first time and then we have the
+   info kept for fast reuse */
+CURLcode Curl_probeipv6(struct Curl_multi *multi)
+{
+  /* probe to see if we have a working IPv6 stack */
+  curl_socket_t s = CURL_SOCKET(PF_INET6, SOCK_DGRAM, 0);
+  multi->ipv6_works = FALSE;
+  if(s == CURL_SOCKET_BAD) {
+    if(SOCKERRNO == SOCKENOMEM)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    multi->ipv6_works = TRUE;
+    sclose(s);
+  }
+  return CURLE_OK;
+}
+
 /*
  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
  */
 bool Curl_ipv6works(struct Curl_easy *data)
 {
-  if(data) {
-    /* the nature of most system is that IPv6 status does not come and go
-       during a program's lifetime so we only probe the first time and then we
-       have the info kept for fast reuse */
-    DEBUGASSERT(data);
-    DEBUGASSERT(data->multi);
-    if(data->multi->ipv6_up == IPV6_UNKNOWN) {
-      bool works = Curl_ipv6works(NULL);
-      data->multi->ipv6_up = works ? IPV6_WORKS : IPV6_DEAD;
-    }
-    return data->multi->ipv6_up == IPV6_WORKS;
-  }
-  else {
-    int ipv6_works = -1;
-    /* probe to see if we have a working IPv6 stack */
-    curl_socket_t s = CURL_SOCKET(PF_INET6, SOCK_DGRAM, 0);
-    if(s == CURL_SOCKET_BAD)
-      /* an IPv6 address was requested but we cannot get/use one */
-      ipv6_works = 0;
-    else {
-      ipv6_works = 1;
-      sclose(s);
-    }
-    return ipv6_works > 0;
-  }
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  return data ? data->multi->ipv6_works : FALSE;
 }
 #endif /* USE_IPV6 */
 
index 45d63e97f3d07adc0acb571bb234dee87cb9f3c7..0257e4364546bb2228c936d9de7c465a51b77384 100644 (file)
@@ -48,6 +48,7 @@ struct Curl_easy;
 struct connectdata;
 struct easy_pollset;
 struct Curl_https_rrinfo;
+struct Curl_multi;
 
 enum alpnid {
   ALPN_none = 0,
@@ -104,11 +105,15 @@ CURLcode Curl_resolv_timeout(struct Curl_easy *data,
                              timediff_t timeoutms);
 
 #ifdef USE_IPV6
+
+/* probe if it seems to work */
+CURLcode Curl_probeipv6(struct Curl_multi *multi);
 /*
  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
  */
 bool Curl_ipv6works(struct Curl_easy *data);
 #else
+#define Curl_probeipv6(x) CURLE_OK
 #define Curl_ipv6works(x) FALSE
 #endif
 
index 477b0d224388e59605e721552012882f4b96cf8f..a7f0d24ee02c76256056ba44678a014f8781bd68 100644 (file)
@@ -300,6 +300,9 @@ struct Curl_multi *Curl_multi_handle(uint32_t xfer_table_size,
   }
 #endif
 
+  if(Curl_probeipv6(multi))
+    goto error;
+
   return multi;
 
 error:
index f66853f5f0f89ec3022b650e713acc6e52161e90..7a561124ae106971920c8dcb03fa7dca597776b9 100644 (file)
@@ -174,10 +174,7 @@ struct Curl_multi {
 #ifdef DEBUGBUILD
   unsigned int now_access_count;
 #endif
-#define IPV6_UNKNOWN 0
-#define IPV6_DEAD    1
-#define IPV6_WORKS   2
-  unsigned char ipv6_up;       /* IPV6_* defined */
+  BIT(ipv6_works);
   BIT(multiplexing);           /* multiplexing wanted */
   BIT(recheckstate);           /* see Curl_multi_connchanged */
   BIT(in_callback);            /* true while executing a callback */