113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#include "urldata.h" 3013498266Sopenharmony_ci#include <curl/curl.h> 3113498266Sopenharmony_ci#include "curl_trc.h" 3213498266Sopenharmony_ci#include "cfilters.h" 3313498266Sopenharmony_ci#include "connect.h" 3413498266Sopenharmony_ci#include "multiif.h" 3513498266Sopenharmony_ci#include "cf-https-connect.h" 3613498266Sopenharmony_ci#include "http2.h" 3713498266Sopenharmony_ci#include "vquic/vquic.h" 3813498266Sopenharmony_ci 3913498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 4013498266Sopenharmony_ci#include "curl_printf.h" 4113498266Sopenharmony_ci#include "curl_memory.h" 4213498266Sopenharmony_ci#include "memdebug.h" 4313498266Sopenharmony_ci 4413498266Sopenharmony_ci 4513498266Sopenharmony_citypedef enum { 4613498266Sopenharmony_ci CF_HC_INIT, 4713498266Sopenharmony_ci CF_HC_CONNECT, 4813498266Sopenharmony_ci CF_HC_SUCCESS, 4913498266Sopenharmony_ci CF_HC_FAILURE 5013498266Sopenharmony_ci} cf_hc_state; 5113498266Sopenharmony_ci 5213498266Sopenharmony_cistruct cf_hc_baller { 5313498266Sopenharmony_ci const char *name; 5413498266Sopenharmony_ci struct Curl_cfilter *cf; 5513498266Sopenharmony_ci CURLcode result; 5613498266Sopenharmony_ci struct curltime started; 5713498266Sopenharmony_ci int reply_ms; 5813498266Sopenharmony_ci bool enabled; 5913498266Sopenharmony_ci}; 6013498266Sopenharmony_ci 6113498266Sopenharmony_cistatic void cf_hc_baller_reset(struct cf_hc_baller *b, 6213498266Sopenharmony_ci struct Curl_easy *data) 6313498266Sopenharmony_ci{ 6413498266Sopenharmony_ci if(b->cf) { 6513498266Sopenharmony_ci Curl_conn_cf_close(b->cf, data); 6613498266Sopenharmony_ci Curl_conn_cf_discard_chain(&b->cf, data); 6713498266Sopenharmony_ci b->cf = NULL; 6813498266Sopenharmony_ci } 6913498266Sopenharmony_ci b->result = CURLE_OK; 7013498266Sopenharmony_ci b->reply_ms = -1; 7113498266Sopenharmony_ci} 7213498266Sopenharmony_ci 7313498266Sopenharmony_cistatic bool cf_hc_baller_is_active(struct cf_hc_baller *b) 7413498266Sopenharmony_ci{ 7513498266Sopenharmony_ci return b->enabled && b->cf && !b->result; 7613498266Sopenharmony_ci} 7713498266Sopenharmony_ci 7813498266Sopenharmony_cistatic bool cf_hc_baller_has_started(struct cf_hc_baller *b) 7913498266Sopenharmony_ci{ 8013498266Sopenharmony_ci return !!b->cf; 8113498266Sopenharmony_ci} 8213498266Sopenharmony_ci 8313498266Sopenharmony_cistatic int cf_hc_baller_reply_ms(struct cf_hc_baller *b, 8413498266Sopenharmony_ci struct Curl_easy *data) 8513498266Sopenharmony_ci{ 8613498266Sopenharmony_ci if(b->reply_ms < 0) 8713498266Sopenharmony_ci b->cf->cft->query(b->cf, data, CF_QUERY_CONNECT_REPLY_MS, 8813498266Sopenharmony_ci &b->reply_ms, NULL); 8913498266Sopenharmony_ci return b->reply_ms; 9013498266Sopenharmony_ci} 9113498266Sopenharmony_ci 9213498266Sopenharmony_cistatic bool cf_hc_baller_data_pending(struct cf_hc_baller *b, 9313498266Sopenharmony_ci const struct Curl_easy *data) 9413498266Sopenharmony_ci{ 9513498266Sopenharmony_ci return b->cf && !b->result && b->cf->cft->has_data_pending(b->cf, data); 9613498266Sopenharmony_ci} 9713498266Sopenharmony_ci 9813498266Sopenharmony_cistruct cf_hc_ctx { 9913498266Sopenharmony_ci cf_hc_state state; 10013498266Sopenharmony_ci const struct Curl_dns_entry *remotehost; 10113498266Sopenharmony_ci struct curltime started; /* when connect started */ 10213498266Sopenharmony_ci CURLcode result; /* overall result */ 10313498266Sopenharmony_ci struct cf_hc_baller h3_baller; 10413498266Sopenharmony_ci struct cf_hc_baller h21_baller; 10513498266Sopenharmony_ci int soft_eyeballs_timeout_ms; 10613498266Sopenharmony_ci int hard_eyeballs_timeout_ms; 10713498266Sopenharmony_ci}; 10813498266Sopenharmony_ci 10913498266Sopenharmony_cistatic void cf_hc_baller_init(struct cf_hc_baller *b, 11013498266Sopenharmony_ci struct Curl_cfilter *cf, 11113498266Sopenharmony_ci struct Curl_easy *data, 11213498266Sopenharmony_ci const char *name, 11313498266Sopenharmony_ci int transport) 11413498266Sopenharmony_ci{ 11513498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 11613498266Sopenharmony_ci struct Curl_cfilter *save = cf->next; 11713498266Sopenharmony_ci 11813498266Sopenharmony_ci b->name = name; 11913498266Sopenharmony_ci cf->next = NULL; 12013498266Sopenharmony_ci b->started = Curl_now(); 12113498266Sopenharmony_ci b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost, 12213498266Sopenharmony_ci transport, CURL_CF_SSL_ENABLE); 12313498266Sopenharmony_ci b->cf = cf->next; 12413498266Sopenharmony_ci cf->next = save; 12513498266Sopenharmony_ci} 12613498266Sopenharmony_ci 12713498266Sopenharmony_cistatic CURLcode cf_hc_baller_connect(struct cf_hc_baller *b, 12813498266Sopenharmony_ci struct Curl_cfilter *cf, 12913498266Sopenharmony_ci struct Curl_easy *data, 13013498266Sopenharmony_ci bool *done) 13113498266Sopenharmony_ci{ 13213498266Sopenharmony_ci struct Curl_cfilter *save = cf->next; 13313498266Sopenharmony_ci 13413498266Sopenharmony_ci cf->next = b->cf; 13513498266Sopenharmony_ci b->result = Curl_conn_cf_connect(cf->next, data, FALSE, done); 13613498266Sopenharmony_ci b->cf = cf->next; /* it might mutate */ 13713498266Sopenharmony_ci cf->next = save; 13813498266Sopenharmony_ci return b->result; 13913498266Sopenharmony_ci} 14013498266Sopenharmony_ci 14113498266Sopenharmony_cistatic void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data) 14213498266Sopenharmony_ci{ 14313498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 14413498266Sopenharmony_ci 14513498266Sopenharmony_ci if(ctx) { 14613498266Sopenharmony_ci cf_hc_baller_reset(&ctx->h3_baller, data); 14713498266Sopenharmony_ci cf_hc_baller_reset(&ctx->h21_baller, data); 14813498266Sopenharmony_ci ctx->state = CF_HC_INIT; 14913498266Sopenharmony_ci ctx->result = CURLE_OK; 15013498266Sopenharmony_ci ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout; 15113498266Sopenharmony_ci ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2; 15213498266Sopenharmony_ci } 15313498266Sopenharmony_ci} 15413498266Sopenharmony_ci 15513498266Sopenharmony_cistatic CURLcode baller_connected(struct Curl_cfilter *cf, 15613498266Sopenharmony_ci struct Curl_easy *data, 15713498266Sopenharmony_ci struct cf_hc_baller *winner) 15813498266Sopenharmony_ci{ 15913498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 16013498266Sopenharmony_ci CURLcode result = CURLE_OK; 16113498266Sopenharmony_ci 16213498266Sopenharmony_ci DEBUGASSERT(winner->cf); 16313498266Sopenharmony_ci if(winner != &ctx->h3_baller) 16413498266Sopenharmony_ci cf_hc_baller_reset(&ctx->h3_baller, data); 16513498266Sopenharmony_ci if(winner != &ctx->h21_baller) 16613498266Sopenharmony_ci cf_hc_baller_reset(&ctx->h21_baller, data); 16713498266Sopenharmony_ci 16813498266Sopenharmony_ci CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms", 16913498266Sopenharmony_ci winner->name, (int)Curl_timediff(Curl_now(), winner->started), 17013498266Sopenharmony_ci cf_hc_baller_reply_ms(winner, data)); 17113498266Sopenharmony_ci cf->next = winner->cf; 17213498266Sopenharmony_ci winner->cf = NULL; 17313498266Sopenharmony_ci 17413498266Sopenharmony_ci switch(cf->conn->alpn) { 17513498266Sopenharmony_ci case CURL_HTTP_VERSION_3: 17613498266Sopenharmony_ci infof(data, "using HTTP/3"); 17713498266Sopenharmony_ci break; 17813498266Sopenharmony_ci case CURL_HTTP_VERSION_2: 17913498266Sopenharmony_ci#ifdef USE_NGHTTP2 18013498266Sopenharmony_ci /* Using nghttp2, we add the filter "below" us, so when the conn 18113498266Sopenharmony_ci * closes, we tear it down for a fresh reconnect */ 18213498266Sopenharmony_ci result = Curl_http2_switch_at(cf, data); 18313498266Sopenharmony_ci if(result) { 18413498266Sopenharmony_ci ctx->state = CF_HC_FAILURE; 18513498266Sopenharmony_ci ctx->result = result; 18613498266Sopenharmony_ci return result; 18713498266Sopenharmony_ci } 18813498266Sopenharmony_ci#endif 18913498266Sopenharmony_ci infof(data, "using HTTP/2"); 19013498266Sopenharmony_ci break; 19113498266Sopenharmony_ci default: 19213498266Sopenharmony_ci infof(data, "using HTTP/1.x"); 19313498266Sopenharmony_ci break; 19413498266Sopenharmony_ci } 19513498266Sopenharmony_ci ctx->state = CF_HC_SUCCESS; 19613498266Sopenharmony_ci cf->connected = TRUE; 19713498266Sopenharmony_ci Curl_conn_cf_cntrl(cf->next, data, TRUE, 19813498266Sopenharmony_ci CF_CTRL_CONN_INFO_UPDATE, 0, NULL); 19913498266Sopenharmony_ci return result; 20013498266Sopenharmony_ci} 20113498266Sopenharmony_ci 20213498266Sopenharmony_ci 20313498266Sopenharmony_cistatic bool time_to_start_h21(struct Curl_cfilter *cf, 20413498266Sopenharmony_ci struct Curl_easy *data, 20513498266Sopenharmony_ci struct curltime now) 20613498266Sopenharmony_ci{ 20713498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 20813498266Sopenharmony_ci timediff_t elapsed_ms; 20913498266Sopenharmony_ci 21013498266Sopenharmony_ci if(!ctx->h21_baller.enabled || cf_hc_baller_has_started(&ctx->h21_baller)) 21113498266Sopenharmony_ci return FALSE; 21213498266Sopenharmony_ci 21313498266Sopenharmony_ci if(!ctx->h3_baller.enabled || !cf_hc_baller_is_active(&ctx->h3_baller)) 21413498266Sopenharmony_ci return TRUE; 21513498266Sopenharmony_ci 21613498266Sopenharmony_ci elapsed_ms = Curl_timediff(now, ctx->started); 21713498266Sopenharmony_ci if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) { 21813498266Sopenharmony_ci CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting h21", 21913498266Sopenharmony_ci ctx->hard_eyeballs_timeout_ms); 22013498266Sopenharmony_ci return TRUE; 22113498266Sopenharmony_ci } 22213498266Sopenharmony_ci 22313498266Sopenharmony_ci if(elapsed_ms >= ctx->soft_eyeballs_timeout_ms) { 22413498266Sopenharmony_ci if(cf_hc_baller_reply_ms(&ctx->h3_baller, data) < 0) { 22513498266Sopenharmony_ci CURL_TRC_CF(data, cf, "soft timeout of %dms reached, h3 has not " 22613498266Sopenharmony_ci "seen any data, starting h21", 22713498266Sopenharmony_ci ctx->soft_eyeballs_timeout_ms); 22813498266Sopenharmony_ci return TRUE; 22913498266Sopenharmony_ci } 23013498266Sopenharmony_ci /* set the effective hard timeout again */ 23113498266Sopenharmony_ci Curl_expire(data, ctx->hard_eyeballs_timeout_ms - elapsed_ms, 23213498266Sopenharmony_ci EXPIRE_ALPN_EYEBALLS); 23313498266Sopenharmony_ci } 23413498266Sopenharmony_ci return FALSE; 23513498266Sopenharmony_ci} 23613498266Sopenharmony_ci 23713498266Sopenharmony_cistatic CURLcode cf_hc_connect(struct Curl_cfilter *cf, 23813498266Sopenharmony_ci struct Curl_easy *data, 23913498266Sopenharmony_ci bool blocking, bool *done) 24013498266Sopenharmony_ci{ 24113498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 24213498266Sopenharmony_ci struct curltime now; 24313498266Sopenharmony_ci CURLcode result = CURLE_OK; 24413498266Sopenharmony_ci 24513498266Sopenharmony_ci (void)blocking; 24613498266Sopenharmony_ci if(cf->connected) { 24713498266Sopenharmony_ci *done = TRUE; 24813498266Sopenharmony_ci return CURLE_OK; 24913498266Sopenharmony_ci } 25013498266Sopenharmony_ci 25113498266Sopenharmony_ci *done = FALSE; 25213498266Sopenharmony_ci now = Curl_now(); 25313498266Sopenharmony_ci switch(ctx->state) { 25413498266Sopenharmony_ci case CF_HC_INIT: 25513498266Sopenharmony_ci DEBUGASSERT(!ctx->h3_baller.cf); 25613498266Sopenharmony_ci DEBUGASSERT(!ctx->h21_baller.cf); 25713498266Sopenharmony_ci DEBUGASSERT(!cf->next); 25813498266Sopenharmony_ci CURL_TRC_CF(data, cf, "connect, init"); 25913498266Sopenharmony_ci ctx->started = now; 26013498266Sopenharmony_ci if(ctx->h3_baller.enabled) { 26113498266Sopenharmony_ci cf_hc_baller_init(&ctx->h3_baller, cf, data, "h3", TRNSPRT_QUIC); 26213498266Sopenharmony_ci if(ctx->h21_baller.enabled) 26313498266Sopenharmony_ci Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS); 26413498266Sopenharmony_ci } 26513498266Sopenharmony_ci else if(ctx->h21_baller.enabled) 26613498266Sopenharmony_ci cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", 26713498266Sopenharmony_ci cf->conn->transport); 26813498266Sopenharmony_ci ctx->state = CF_HC_CONNECT; 26913498266Sopenharmony_ci FALLTHROUGH(); 27013498266Sopenharmony_ci 27113498266Sopenharmony_ci case CF_HC_CONNECT: 27213498266Sopenharmony_ci if(cf_hc_baller_is_active(&ctx->h3_baller)) { 27313498266Sopenharmony_ci result = cf_hc_baller_connect(&ctx->h3_baller, cf, data, done); 27413498266Sopenharmony_ci if(!result && *done) { 27513498266Sopenharmony_ci result = baller_connected(cf, data, &ctx->h3_baller); 27613498266Sopenharmony_ci goto out; 27713498266Sopenharmony_ci } 27813498266Sopenharmony_ci } 27913498266Sopenharmony_ci 28013498266Sopenharmony_ci if(time_to_start_h21(cf, data, now)) { 28113498266Sopenharmony_ci cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", 28213498266Sopenharmony_ci cf->conn->transport); 28313498266Sopenharmony_ci } 28413498266Sopenharmony_ci 28513498266Sopenharmony_ci if(cf_hc_baller_is_active(&ctx->h21_baller)) { 28613498266Sopenharmony_ci CURL_TRC_CF(data, cf, "connect, check h21"); 28713498266Sopenharmony_ci result = cf_hc_baller_connect(&ctx->h21_baller, cf, data, done); 28813498266Sopenharmony_ci if(!result && *done) { 28913498266Sopenharmony_ci result = baller_connected(cf, data, &ctx->h21_baller); 29013498266Sopenharmony_ci goto out; 29113498266Sopenharmony_ci } 29213498266Sopenharmony_ci } 29313498266Sopenharmony_ci 29413498266Sopenharmony_ci if((!ctx->h3_baller.enabled || ctx->h3_baller.result) && 29513498266Sopenharmony_ci (!ctx->h21_baller.enabled || ctx->h21_baller.result)) { 29613498266Sopenharmony_ci /* both failed or disabled. we give up */ 29713498266Sopenharmony_ci CURL_TRC_CF(data, cf, "connect, all failed"); 29813498266Sopenharmony_ci result = ctx->result = ctx->h3_baller.enabled? 29913498266Sopenharmony_ci ctx->h3_baller.result : ctx->h21_baller.result; 30013498266Sopenharmony_ci ctx->state = CF_HC_FAILURE; 30113498266Sopenharmony_ci goto out; 30213498266Sopenharmony_ci } 30313498266Sopenharmony_ci result = CURLE_OK; 30413498266Sopenharmony_ci *done = FALSE; 30513498266Sopenharmony_ci break; 30613498266Sopenharmony_ci 30713498266Sopenharmony_ci case CF_HC_FAILURE: 30813498266Sopenharmony_ci result = ctx->result; 30913498266Sopenharmony_ci cf->connected = FALSE; 31013498266Sopenharmony_ci *done = FALSE; 31113498266Sopenharmony_ci break; 31213498266Sopenharmony_ci 31313498266Sopenharmony_ci case CF_HC_SUCCESS: 31413498266Sopenharmony_ci result = CURLE_OK; 31513498266Sopenharmony_ci cf->connected = TRUE; 31613498266Sopenharmony_ci *done = TRUE; 31713498266Sopenharmony_ci break; 31813498266Sopenharmony_ci } 31913498266Sopenharmony_ci 32013498266Sopenharmony_ciout: 32113498266Sopenharmony_ci CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done); 32213498266Sopenharmony_ci return result; 32313498266Sopenharmony_ci} 32413498266Sopenharmony_ci 32513498266Sopenharmony_cistatic void cf_hc_adjust_pollset(struct Curl_cfilter *cf, 32613498266Sopenharmony_ci struct Curl_easy *data, 32713498266Sopenharmony_ci struct easy_pollset *ps) 32813498266Sopenharmony_ci{ 32913498266Sopenharmony_ci if(!cf->connected) { 33013498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 33113498266Sopenharmony_ci struct cf_hc_baller *ballers[2]; 33213498266Sopenharmony_ci size_t i; 33313498266Sopenharmony_ci 33413498266Sopenharmony_ci ballers[0] = &ctx->h3_baller; 33513498266Sopenharmony_ci ballers[1] = &ctx->h21_baller; 33613498266Sopenharmony_ci for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) { 33713498266Sopenharmony_ci struct cf_hc_baller *b = ballers[i]; 33813498266Sopenharmony_ci if(!cf_hc_baller_is_active(b)) 33913498266Sopenharmony_ci continue; 34013498266Sopenharmony_ci Curl_conn_cf_adjust_pollset(b->cf, data, ps); 34113498266Sopenharmony_ci } 34213498266Sopenharmony_ci CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num); 34313498266Sopenharmony_ci } 34413498266Sopenharmony_ci} 34513498266Sopenharmony_ci 34613498266Sopenharmony_cistatic bool cf_hc_data_pending(struct Curl_cfilter *cf, 34713498266Sopenharmony_ci const struct Curl_easy *data) 34813498266Sopenharmony_ci{ 34913498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 35013498266Sopenharmony_ci 35113498266Sopenharmony_ci if(cf->connected) 35213498266Sopenharmony_ci return cf->next->cft->has_data_pending(cf->next, data); 35313498266Sopenharmony_ci 35413498266Sopenharmony_ci CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending"); 35513498266Sopenharmony_ci return cf_hc_baller_data_pending(&ctx->h3_baller, data) 35613498266Sopenharmony_ci || cf_hc_baller_data_pending(&ctx->h21_baller, data); 35713498266Sopenharmony_ci} 35813498266Sopenharmony_ci 35913498266Sopenharmony_cistatic struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf, 36013498266Sopenharmony_ci struct Curl_easy *data, 36113498266Sopenharmony_ci int query) 36213498266Sopenharmony_ci{ 36313498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 36413498266Sopenharmony_ci struct Curl_cfilter *cfb; 36513498266Sopenharmony_ci struct curltime t, tmax; 36613498266Sopenharmony_ci 36713498266Sopenharmony_ci memset(&tmax, 0, sizeof(tmax)); 36813498266Sopenharmony_ci memset(&t, 0, sizeof(t)); 36913498266Sopenharmony_ci cfb = ctx->h21_baller.enabled? ctx->h21_baller.cf : NULL; 37013498266Sopenharmony_ci if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { 37113498266Sopenharmony_ci if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) 37213498266Sopenharmony_ci tmax = t; 37313498266Sopenharmony_ci } 37413498266Sopenharmony_ci memset(&t, 0, sizeof(t)); 37513498266Sopenharmony_ci cfb = ctx->h3_baller.enabled? ctx->h3_baller.cf : NULL; 37613498266Sopenharmony_ci if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { 37713498266Sopenharmony_ci if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) 37813498266Sopenharmony_ci tmax = t; 37913498266Sopenharmony_ci } 38013498266Sopenharmony_ci return tmax; 38113498266Sopenharmony_ci} 38213498266Sopenharmony_ci 38313498266Sopenharmony_cistatic CURLcode cf_hc_query(struct Curl_cfilter *cf, 38413498266Sopenharmony_ci struct Curl_easy *data, 38513498266Sopenharmony_ci int query, int *pres1, void *pres2) 38613498266Sopenharmony_ci{ 38713498266Sopenharmony_ci if(!cf->connected) { 38813498266Sopenharmony_ci switch(query) { 38913498266Sopenharmony_ci case CF_QUERY_TIMER_CONNECT: { 39013498266Sopenharmony_ci struct curltime *when = pres2; 39113498266Sopenharmony_ci *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); 39213498266Sopenharmony_ci return CURLE_OK; 39313498266Sopenharmony_ci } 39413498266Sopenharmony_ci case CF_QUERY_TIMER_APPCONNECT: { 39513498266Sopenharmony_ci struct curltime *when = pres2; 39613498266Sopenharmony_ci *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); 39713498266Sopenharmony_ci return CURLE_OK; 39813498266Sopenharmony_ci } 39913498266Sopenharmony_ci default: 40013498266Sopenharmony_ci break; 40113498266Sopenharmony_ci } 40213498266Sopenharmony_ci } 40313498266Sopenharmony_ci return cf->next? 40413498266Sopenharmony_ci cf->next->cft->query(cf->next, data, query, pres1, pres2) : 40513498266Sopenharmony_ci CURLE_UNKNOWN_OPTION; 40613498266Sopenharmony_ci} 40713498266Sopenharmony_ci 40813498266Sopenharmony_cistatic void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data) 40913498266Sopenharmony_ci{ 41013498266Sopenharmony_ci CURL_TRC_CF(data, cf, "close"); 41113498266Sopenharmony_ci cf_hc_reset(cf, data); 41213498266Sopenharmony_ci cf->connected = FALSE; 41313498266Sopenharmony_ci 41413498266Sopenharmony_ci if(cf->next) { 41513498266Sopenharmony_ci cf->next->cft->do_close(cf->next, data); 41613498266Sopenharmony_ci Curl_conn_cf_discard_chain(&cf->next, data); 41713498266Sopenharmony_ci } 41813498266Sopenharmony_ci} 41913498266Sopenharmony_ci 42013498266Sopenharmony_cistatic void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) 42113498266Sopenharmony_ci{ 42213498266Sopenharmony_ci struct cf_hc_ctx *ctx = cf->ctx; 42313498266Sopenharmony_ci 42413498266Sopenharmony_ci (void)data; 42513498266Sopenharmony_ci CURL_TRC_CF(data, cf, "destroy"); 42613498266Sopenharmony_ci cf_hc_reset(cf, data); 42713498266Sopenharmony_ci Curl_safefree(ctx); 42813498266Sopenharmony_ci} 42913498266Sopenharmony_ci 43013498266Sopenharmony_cistruct Curl_cftype Curl_cft_http_connect = { 43113498266Sopenharmony_ci "HTTPS-CONNECT", 43213498266Sopenharmony_ci 0, 43313498266Sopenharmony_ci CURL_LOG_LVL_NONE, 43413498266Sopenharmony_ci cf_hc_destroy, 43513498266Sopenharmony_ci cf_hc_connect, 43613498266Sopenharmony_ci cf_hc_close, 43713498266Sopenharmony_ci Curl_cf_def_get_host, 43813498266Sopenharmony_ci cf_hc_adjust_pollset, 43913498266Sopenharmony_ci cf_hc_data_pending, 44013498266Sopenharmony_ci Curl_cf_def_send, 44113498266Sopenharmony_ci Curl_cf_def_recv, 44213498266Sopenharmony_ci Curl_cf_def_cntrl, 44313498266Sopenharmony_ci Curl_cf_def_conn_is_alive, 44413498266Sopenharmony_ci Curl_cf_def_conn_keep_alive, 44513498266Sopenharmony_ci cf_hc_query, 44613498266Sopenharmony_ci}; 44713498266Sopenharmony_ci 44813498266Sopenharmony_cistatic CURLcode cf_hc_create(struct Curl_cfilter **pcf, 44913498266Sopenharmony_ci struct Curl_easy *data, 45013498266Sopenharmony_ci const struct Curl_dns_entry *remotehost, 45113498266Sopenharmony_ci bool try_h3, bool try_h21) 45213498266Sopenharmony_ci{ 45313498266Sopenharmony_ci struct Curl_cfilter *cf = NULL; 45413498266Sopenharmony_ci struct cf_hc_ctx *ctx; 45513498266Sopenharmony_ci CURLcode result = CURLE_OK; 45613498266Sopenharmony_ci 45713498266Sopenharmony_ci (void)data; 45813498266Sopenharmony_ci ctx = calloc(1, sizeof(*ctx)); 45913498266Sopenharmony_ci if(!ctx) { 46013498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 46113498266Sopenharmony_ci goto out; 46213498266Sopenharmony_ci } 46313498266Sopenharmony_ci ctx->remotehost = remotehost; 46413498266Sopenharmony_ci ctx->h3_baller.enabled = try_h3; 46513498266Sopenharmony_ci ctx->h21_baller.enabled = try_h21; 46613498266Sopenharmony_ci 46713498266Sopenharmony_ci result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx); 46813498266Sopenharmony_ci if(result) 46913498266Sopenharmony_ci goto out; 47013498266Sopenharmony_ci ctx = NULL; 47113498266Sopenharmony_ci cf_hc_reset(cf, data); 47213498266Sopenharmony_ci 47313498266Sopenharmony_ciout: 47413498266Sopenharmony_ci *pcf = result? NULL : cf; 47513498266Sopenharmony_ci free(ctx); 47613498266Sopenharmony_ci return result; 47713498266Sopenharmony_ci} 47813498266Sopenharmony_ci 47913498266Sopenharmony_cistatic CURLcode cf_http_connect_add(struct Curl_easy *data, 48013498266Sopenharmony_ci struct connectdata *conn, 48113498266Sopenharmony_ci int sockindex, 48213498266Sopenharmony_ci const struct Curl_dns_entry *remotehost, 48313498266Sopenharmony_ci bool try_h3, bool try_h21) 48413498266Sopenharmony_ci{ 48513498266Sopenharmony_ci struct Curl_cfilter *cf; 48613498266Sopenharmony_ci CURLcode result = CURLE_OK; 48713498266Sopenharmony_ci 48813498266Sopenharmony_ci DEBUGASSERT(data); 48913498266Sopenharmony_ci result = cf_hc_create(&cf, data, remotehost, try_h3, try_h21); 49013498266Sopenharmony_ci if(result) 49113498266Sopenharmony_ci goto out; 49213498266Sopenharmony_ci Curl_conn_cf_add(data, conn, sockindex, cf); 49313498266Sopenharmony_ciout: 49413498266Sopenharmony_ci return result; 49513498266Sopenharmony_ci} 49613498266Sopenharmony_ci 49713498266Sopenharmony_ciCURLcode Curl_cf_https_setup(struct Curl_easy *data, 49813498266Sopenharmony_ci struct connectdata *conn, 49913498266Sopenharmony_ci int sockindex, 50013498266Sopenharmony_ci const struct Curl_dns_entry *remotehost) 50113498266Sopenharmony_ci{ 50213498266Sopenharmony_ci bool try_h3 = FALSE, try_h21 = TRUE; /* defaults, for now */ 50313498266Sopenharmony_ci CURLcode result = CURLE_OK; 50413498266Sopenharmony_ci 50513498266Sopenharmony_ci (void)sockindex; 50613498266Sopenharmony_ci (void)remotehost; 50713498266Sopenharmony_ci 50813498266Sopenharmony_ci if(!conn->bits.tls_enable_alpn) 50913498266Sopenharmony_ci goto out; 51013498266Sopenharmony_ci 51113498266Sopenharmony_ci if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) { 51213498266Sopenharmony_ci result = Curl_conn_may_http3(data, conn); 51313498266Sopenharmony_ci if(result) /* can't do it */ 51413498266Sopenharmony_ci goto out; 51513498266Sopenharmony_ci try_h3 = TRUE; 51613498266Sopenharmony_ci try_h21 = FALSE; 51713498266Sopenharmony_ci } 51813498266Sopenharmony_ci else if(data->state.httpwant >= CURL_HTTP_VERSION_3) { 51913498266Sopenharmony_ci /* We assume that silently not even trying H3 is ok here */ 52013498266Sopenharmony_ci /* TODO: should we fail instead? */ 52113498266Sopenharmony_ci try_h3 = (Curl_conn_may_http3(data, conn) == CURLE_OK); 52213498266Sopenharmony_ci try_h21 = TRUE; 52313498266Sopenharmony_ci } 52413498266Sopenharmony_ci 52513498266Sopenharmony_ci result = cf_http_connect_add(data, conn, sockindex, remotehost, 52613498266Sopenharmony_ci try_h3, try_h21); 52713498266Sopenharmony_ciout: 52813498266Sopenharmony_ci return result; 52913498266Sopenharmony_ci} 53013498266Sopenharmony_ci 53113498266Sopenharmony_ci#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */ 532