diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 4ea2e0724c..007f1d7123 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -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 diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index 454e31b8b8..1ede868820 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -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! */ diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index 474769d1cb..b89ed80e55 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -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: diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 2a7311eb3b..273258feaf 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -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; diff --git a/lib/cfilters.c b/lib/cfilters.c index e3247f72c9..01f1e28218 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -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) { diff --git a/lib/cfilters.h b/lib/cfilters.h index b28ca998e0..39d906d673 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -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. diff --git a/lib/connect.c b/lib/connect.c index c894fe62b0..5d9486394a 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -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; } diff --git a/lib/ftp.c b/lib/ftp.c index 5e505887b1..06c486bc91 100644 --- 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; } diff --git a/lib/hostip6.c b/lib/hostip6.c index 35cc2d737b..ce7f5050ea 100644 --- a/lib/hostip6.c +++ b/lib/hostip6.c @@ -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 diff --git a/lib/http.c b/lib/http.c index 32e54c2683..e5a0696274 100644 --- a/lib/http.c +++ b/lib/http.c @@ -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; } diff --git a/lib/tftp.c b/lib/tftp.c index 5ed7258d38..5ea986dbb4 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -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=" that * we will try to get now! */ diff --git a/lib/url.c b/lib/url.c index 1f73c1e3ac..e4f250f54a 100644 --- 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); } } diff --git a/lib/urldata.h b/lib/urldata.h index 63bee65dc9..e54721dd98 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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. */ diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 1eb67f516f..691c0d3fa7 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -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; } diff --git a/lib/vquic/vquic.h b/lib/vquic/vquic.h index dbf63b1f6f..3577a857e3 100644 --- a/lib/vquic/vquic.h +++ b/lib/vquic/vquic.h @@ -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 */ diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 8005fa3f59..c3560e8b8d 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -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