]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
connection: clarify `transport`
authorStefan Eissing <stefan@eissing.org>
Mon, 14 Jul 2025 09:41:59 +0000 (11:41 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 14 Jul 2025 12:33:18 +0000 (14:33 +0200)
The `transport` to use for a transfer, e.g. TCP/QUIC/UNIX/UDP, is
initially selected by options and protocol used. This is set at the
`struct connectdata` as `transport` member.

During connection establishment, this transport may change due to
Alt-Svc or Happy-Eyeballing. Most common is the switch from TCP to QUIC.

Rename the connection member to `transport_wanted` and add a way to
query the connection for the transport in use via a new connection
filter query.

The filter query can also be used in the happy eyeballing attempts when
code needs to know which transport is used by the "filter below". This
happens in wolfssl initialization, as one example.

Closes #17923

16 files changed:
lib/asyn-ares.c
lib/asyn-thrdd.c
lib/cf-https-connect.c
lib/cf-socket.c
lib/cfilters.c
lib/cfilters.h
lib/connect.c
lib/ftp.c
lib/hostip6.c
lib/http.c
lib/tftp.c
lib/url.c
lib/urldata.h
lib/vquic/vquic.c
lib/vquic/vquic.h
lib/vtls/wolfssl.c

index 4ea2e0724c1218f3f10148cf85f41a3ed2d4bf0b..007f1d7123c77a5212816e24a59ef8eb95183e95 100644 (file)
@@ -48,6 +48,7 @@
 #endif
 
 #include "urldata.h"
+#include "cfilters.h"
 #include "sendf.h"
 #include "hostip.h"
 #include "hash.h"
@@ -757,7 +758,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
                  (pf == PF_UNSPEC) ? "A+AAAA" :
                  ((pf == PF_INET) ? "A" : "AAAA"));
     hints.ai_family = pf;
-    hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+    hints.ai_socktype =
+      (Curl_conn_get_transport(data, data->conn) == 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
index 454e31b8b816939d1a765e3409d1a9e66f1ee6a6..1ede86882066f1ecbbcb8eed7fbe3dd26ed016de 100644 (file)
@@ -55,6 +55,7 @@
 #endif
 
 #include "urldata.h"
+#include "cfilters.h"
 #include "sendf.h"
 #include "hostip.h"
 #include "hash.h"
@@ -741,7 +742,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+  hints.ai_socktype =
+    (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
     SOCK_STREAM : SOCK_DGRAM;
 
   /* fire up a new resolver thread! */
index 474769d1cbb430257ab93d7a19ba4a2c72b4a8bb..b89ed80e553647fc1fa4475c96f64fdcc90bbdee 100644 (file)
@@ -55,6 +55,7 @@ struct cf_hc_baller {
   CURLcode result;
   struct curltime started;
   int reply_ms;
+  unsigned char transport;
   enum alpnid alpn_id;
   BIT(shutdown);
 };
@@ -122,12 +123,15 @@ struct cf_hc_ctx {
 };
 
 static void cf_hc_baller_assign(struct cf_hc_baller *b,
-                                enum alpnid alpn_id)
+                                enum alpnid alpn_id,
+                                unsigned char def_transport)
 {
   b->alpn_id = alpn_id;
+  b->transport = def_transport;
   switch(b->alpn_id) {
   case ALPN_h3:
     b->name = "h3";
+    b->transport = TRNSPRT_QUIC;
     break;
   case ALPN_h2:
     b->name = "h2";
@@ -218,6 +222,7 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
                 winner->name, (int)curlx_timediff(curlx_now(),
                                                   winner->started));
 
+  /* install the winning filter below this one. */
   cf->next = winner->cf;
   winner->cf = NULL;
 
@@ -312,7 +317,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
       DEBUGASSERT(!ctx->ballers[i].cf);
     CURL_TRC_CF(data, cf, "connect, init");
     ctx->started = now;
-    cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport);
+    cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport);
     if(ctx->baller_count > 1) {
       Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
       CURL_TRC_CF(data, cf, "set next attempt to start in %" FMT_TIMEDIFF_T
@@ -331,7 +336,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
     }
 
     if(time_to_start_next(cf, data, 1, now)) {
-      cf_hc_baller_init(&ctx->ballers[1], cf, data, cf->conn->transport);
+      cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport);
     }
 
     if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) {
@@ -574,7 +579,8 @@ struct Curl_cftype Curl_cft_http_connect = {
 
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
                              struct Curl_easy *data,
-                             enum alpnid *alpnids, size_t alpn_count)
+                             enum alpnid *alpnids, size_t alpn_count,
+                             unsigned char def_transport)
 {
   struct Curl_cfilter *cf = NULL;
   struct cf_hc_ctx *ctx;
@@ -596,7 +602,7 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
     goto out;
   }
   for(i = 0; i < alpn_count; ++i)
-    cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
+    cf_hc_baller_assign(&ctx->ballers[i], alpnids[i], def_transport);
   for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
     ctx->ballers[i].alpn_id = ALPN_none;
   ctx->baller_count = alpn_count;
@@ -616,13 +622,14 @@ out:
 static CURLcode cf_http_connect_add(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     int sockindex,
-                                    enum alpnid *alpn_ids, size_t alpn_count)
+                                    enum alpnid *alpn_ids, size_t alpn_count,
+                                    unsigned char def_transport)
 {
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_hc_create(&cf, data, alpn_ids, alpn_count);
+  result = cf_hc_create(&cf, data, alpn_ids, alpn_count, def_transport);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -679,7 +686,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
           continue;
         switch(alpn) {
         case ALPN_h3:
-          if(Curl_conn_may_http3(data, conn))
+          if(Curl_conn_may_http3(data, conn, conn->transport_wanted))
             break;  /* not possible */
           if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
             CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
@@ -708,7 +715,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
     if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
        (data->state.http_neg.wanted & CURL_HTTP_V3x) &&
        !cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
-      result = Curl_conn_may_http3(data, conn);
+      result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
       if(!result) {
         CURL_TRC_CF(data, cf, "adding wanted h3");
         alpn_ids[alpn_count++] = ALPN_h3;
@@ -733,7 +740,9 @@ 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, alpn_ids, alpn_count);
+    result = cf_http_connect_add(data, conn, sockindex,
+                                 alpn_ids, alpn_count,
+                                 conn->transport_wanted);
   }
 
 out:
index 2a7311eb3bd7be1be076e4cb35b98f7189315ccc..273258feaf24083446a994ceb9c0e4ab9e72b45e 100644 (file)
@@ -1683,6 +1683,10 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
     DEBUGASSERT(pres2);
     *((curl_socket_t *)pres2) = ctx->sock;
     return CURLE_OK;
+  case CF_QUERY_TRANSPORT:
+    DEBUGASSERT(pres1);
+    *pres1 = ctx->transport;
+    return CURLE_OK;
   case CF_QUERY_REMOTE_ADDR:
     DEBUGASSERT(pres2);
     *((const struct Curl_sockaddr_ex **)pres2) = cf->connected ?
@@ -2193,7 +2197,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
-  ctx->transport = conn->transport;
+  ctx->transport = TRNSPRT_TCP;
   ctx->sock = *s;
   ctx->listening = TRUE;
   ctx->accepted = FALSE;
index e3247f72c9367c6dc7398aec0eb36e3680ba18f9..01f1e282183f31079a019081eb0daffb455db8c0 100644 (file)
@@ -606,6 +606,13 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
   return FALSE;
 }
 
+unsigned char Curl_conn_get_transport(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
+  return Curl_conn_cf_get_transport(cf, data);
+}
+
 unsigned char Curl_conn_http_version(struct Curl_easy *data,
                                      struct connectdata *conn)
 {
@@ -794,6 +801,15 @@ curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
   return CURL_SOCKET_BAD;
 }
 
+unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data)
+{
+  int transport = 0;
+  if(cf && !cf->cft->query(cf, data, CF_QUERY_TRANSPORT, &transport, NULL))
+    return (unsigned char)transport;
+  return (unsigned char)(data->conn ? data->conn->transport_wanted : 0);
+}
+
 static const struct Curl_sockaddr_ex *
 cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
index b28ca998e007f5801734795a891b7857d651ac6d..39d906d673b120f05ade63aca2de125a614819ec 100644 (file)
@@ -175,6 +175,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
 #define CF_QUERY_HOST_PORT         11  /* port       const char * */
 #define CF_QUERY_SSL_INFO          12  /* -    struct curl_tlssessioninfo * */
 #define CF_QUERY_SSL_CTX_INFO      13  /* -    struct curl_tlssessioninfo * */
+#define CF_QUERY_TRANSPORT         14  /* TRNSPRT_*  - * */
 
 /**
  * Query the cfilter for properties. Filters ignorant of a query will
@@ -350,6 +351,9 @@ CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
 bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
                               struct Curl_easy *data);
 
+unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data);
+
 #define CURL_CF_SSL_DEFAULT  -1
 #define CURL_CF_SSL_DISABLE  0
 #define CURL_CF_SSL_ENABLE   1
@@ -410,6 +414,10 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
 unsigned char Curl_conn_http_version(struct Curl_easy *data,
                                      struct connectdata *conn);
 
+/* Get the TRNSPRT_* the connection is using */
+unsigned char Curl_conn_get_transport(struct Curl_easy *data,
+                                      struct connectdata *conn);
+
 /**
  * Close the filter chain at `sockindex` for connection `data->conn`.
   * Filters remain in place and may be connected again afterwards.
index c894fe62b033e239a8471275c1e2d9c1b972e183..5d9486394ae0e485b22479972f360cee1a447454 100644 (file)
@@ -1515,7 +1515,8 @@ 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, conn->transport, ssl_mode);
+    result = cf_setup_add(data, conn, sockindex,
+                          conn->transport_wanted, ssl_mode);
     if(result)
       goto out;
   }
index 5e505887b17e06216d53a3b289b7d3804ee6afb0..06c486bc91753da09696fbc380865c19a3766a9f 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1065,7 +1065,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
   /* step 2, create a socket for the requested address */
   error = 0;
   for(ai = res; ai; ai = ai->ai_next) {
-    if(Curl_socket_open(data, ai, NULL, conn->transport, &portsock)) {
+    if(Curl_socket_open(data, ai, NULL,
+                        Curl_conn_get_transport(data, conn), &portsock)) {
       error = SOCKERRNO;
       continue;
     }
index 35cc2d737bb37e3c6fa5b19d6c8d3552590d3592..ce7f5050ea8bb8d49998b1783730c48d59cb27e3 100644 (file)
@@ -44,6 +44,7 @@
 #endif
 
 #include "urldata.h"
+#include "cfilters.h"
 #include "sendf.h"
 #include "hostip.h"
 #include "hash.h"
@@ -104,7 +105,8 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data,
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+  hints.ai_socktype =
+    (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
     SOCK_STREAM : SOCK_DGRAM;
 
 #ifndef USE_RESOLVE_ON_IPS
index 32e54c2683ae344bcb5efc9bafd98ef1d1248877..e5a0696274fcbbd6900aa9593d3083806189ad70 100644 (file)
@@ -232,7 +232,7 @@ CURLcode Curl_http_setup_conn(struct Curl_easy *data,
   connkeep(conn, "HTTP default");
   if(data->state.http_neg.wanted == CURL_HTTP_V3x) {
     /* only HTTP/3, needs to work */
-    CURLcode result = Curl_conn_may_http3(data, conn);
+    CURLcode result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
     if(result)
       return result;
   }
index 5ed7258d38e1a6c0c024a4db9dea3f9c421fc59e..5ea986dbb4b01adc29f28a931823364b9d04e032 100644 (file)
@@ -1369,7 +1369,7 @@ static CURLcode tftp_setup_connection(struct Curl_easy *data,
 {
   char *type;
 
-  conn->transport = TRNSPRT_UDP;
+  conn->transport_wanted = TRNSPRT_UDP;
 
   /* TFTP URLs support an extension like ";mode=<typecode>" that
    * we will try to get now! */
index 1f73c1e3ac3a85ee9daf41b97d3399cb4999403c..e4f250f54ae0b56cc1bf0326dac7f3f3d306e96e 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1464,7 +1464,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
 #endif
   conn->ip_version = data->set.ipver;
   conn->connect_only = data->set.connect_only;
-  conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
+  conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
 
   /* Initialize the attached xfers bitset */
   Curl_uint_spbset_init(&conn->xfers_attached);
@@ -3235,7 +3235,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
           neg->wanted = neg->allowed = CURL_HTTP_V2x;
           break;
         case ALPN_h3:
-          conn->transport = TRNSPRT_QUIC;
+          conn->transport_wanted = TRNSPRT_QUIC;
           neg->wanted = neg->allowed = CURL_HTTP_V3x;
           break;
         default: /* should not be possible */
@@ -3312,7 +3312,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
 
     if(unix_path) {
       /* This only works if previous transport is TRNSPRT_TCP. Check it? */
-      conn->transport = TRNSPRT_UNIX;
+      conn->transport_wanted = TRNSPRT_UNIX;
       return resolve_unix(data, conn, unix_path, pdns);
     }
   }
index 63bee65dc9d26d0de01650f19cba128b1ccf02d0..e54721dd983eee8732c9c82be3759641b95046fe 100644 (file)
@@ -785,7 +785,10 @@ struct connectdata {
 #ifndef CURL_DISABLE_PROXY
   unsigned char proxy_alpn; /* APLN of proxy tunnel, CURL_HTTP_VERSION* */
 #endif
-  unsigned char transport; /* one of the TRNSPRT_* defines */
+  unsigned char transport_wanted; /* one of the TRNSPRT_* defines. Not
+   necessarily the transport the connection ends using due to Alt-Svc
+   and happy eyeballing. Use `Curl_conn_get_transport() for actual value
+   once the connection is set up. */
   unsigned char ip_version; /* copied from the Curl_easy at creation time */
   /* HTTP version last responded with by the server.
    * 0 at start, then one of 09, 10, 11, etc. */
index 1eb67f516f3914df353e27dd1b7f398f94d2462f..691c0d3fa73a115b7586f571697830e0ad8b3817 100644 (file)
@@ -703,9 +703,10 @@ CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
 }
 
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
-                             const struct connectdata *conn)
+                             const struct connectdata *conn,
+                             unsigned char transport)
 {
-  if(conn->transport == TRNSPRT_UNIX) {
+  if(transport == TRNSPRT_UNIX) {
     /* cannot do QUIC over a Unix domain socket */
     return CURLE_QUIC_CONNECT_ERROR;
   }
@@ -730,10 +731,12 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
 #else /* USE_HTTP3 */
 
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
-                             const struct connectdata *conn)
+                             const struct connectdata *conn,
+                             unsigned char transport)
 {
   (void)conn;
   (void)data;
+  (void)transport;
   DEBUGF(infof(data, "QUIC is not supported in this build"));
   return CURLE_NOT_BUILT_IN;
 }
index dbf63b1f6fe0a19b2b6a511728df53561f18a10a..3577a857e33911f35716320747acf563e015c345 100644 (file)
@@ -54,6 +54,7 @@ extern struct Curl_cftype Curl_cft_http3;
 #endif /* !USE_HTTP3 */
 
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
-                             const struct connectdata *conn);
+                             const struct connectdata *conn,
+                             unsigned char transport);
 
 #endif /* HEADER_CURL_VQUIC_QUIC_H */
index 8005fa3f59b46af170ec23a4e481e935a049f788..c3560e8b8d12e83041a45d3bebbc7bd86041ed9d 100644 (file)
@@ -964,6 +964,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
   size_t idx = 0;
 #endif
   CURLcode result = CURLE_FAILED_INIT;
+  unsigned char transport;
 
   DEBUGASSERT(!wctx->ssl_ctx);
   DEBUGASSERT(!wctx->ssl);
@@ -973,6 +974,8 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
     goto out;
   }
   Curl_alpn_copy(&alpns, alpns_requested);
+  DEBUGASSERT(cf->next);
+  transport = Curl_conn_cf_get_transport(cf->next, data);
 
 #if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
   req_method = wolfSSLv23_client_method();
@@ -1103,7 +1106,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
 #endif
 
   curves = conn_config->curves;
-  if(!curves && cf->conn->transport == TRNSPRT_QUIC)
+  if(!curves && (transport == TRNSPRT_QUIC))
     curves = (char *)CURL_UNCONST(QUIC_GROUPS);
 
   if(curves) {
@@ -1244,8 +1247,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
   }
 #endif
 
-  if(ssl_config->primary.cache_session &&
-     cf->conn->transport != TRNSPRT_QUIC) {
+  if(ssl_config->primary.cache_session && (transport != TRNSPRT_QUIC)) {
     /* Register to get notified when a new session is received */
     wolfSSL_CTX_sess_set_new_cb(wctx->ssl_ctx, wssl_vtls_new_session_cb);
   }
@@ -1291,7 +1293,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
 
   wolfSSL_set_app_data(wctx->ssl, ssl_user_data);
 #ifdef WOLFSSL_QUIC
-  if(cf->conn->transport == TRNSPRT_QUIC)
+  if(transport == TRNSPRT_QUIC)
     wolfSSL_set_quic_use_legacy_codepoint(wctx->ssl, 0);
 #endif