← Commit list

567803db79

Stefan Eissing
Stefan Eissing
2026-04-08
SUCCESS Duration: 245s

Subject

dns: https-eyeballing async

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/cf-dns.c+24 -0
@@ -509,6 +509,30 @@ cf_dns_get_nth_ai(const struct Curl_addrinfo *ai,
return NULL;
}
+bool Curl_conn_dns_has_any_ai(struct Curl_easy *data, int sockindex)
+{
+ struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
+
+ (void)data;
+ for(; cf; cf = cf->next) {
+ if(cf->cft == &Curl_cft_dns) {
+ struct cf_dns_ctx *ctx = cf->ctx;
+ if(ctx->resolv_result)
+ return FALSE;
+ else if(ctx->dns)
+ return !!ctx->dns->addr;
+ else
+#ifdef USE_IPV6
+ return Curl_resolv_get_ai(data, ctx->resolv_id, AF_INET, 0) ||
+ Curl_resolv_get_ai(data, ctx->resolv_id, AF_INET6, 0);
+#else
+ return !!Curl_resolv_get_ai(data, ctx->resolv_id, AF_INET, 0);
+#endif
+ }
+ }
+ return FALSE;
+}
+
/* Return the addrinfo at `index` for the given `family` from the
* first "resolve" filter underneath `cf`. If the DNS resolving is
* not done yet or if no address for the family exists, returns NULL.
lib/cf-dns.h+3 -0
@@ -47,6 +47,9 @@ CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex);
CURLcode Curl_cf_dns_result(struct Curl_cfilter *cf);
+/* Returns TRUE if any addressinfo is available via
+ * `Curl_conn_dns_get_ai()`. */
+bool Curl_conn_dns_has_any_ai(struct Curl_easy *data, int sockindex);
const struct Curl_addrinfo *
Curl_conn_dns_get_ai(struct Curl_easy *data,
lib/cf-https-connect.c+254 -235
@@ -58,19 +58,17 @@ struct cf_hc_baller {
BIT(shutdown);
};
-static void cf_hc_baller_reset(struct cf_hc_baller *b,
- struct Curl_easy *data)
+static void cf_hc_baller_discard(struct cf_hc_baller *b,
+ struct Curl_easy *data)
{
if(b->cf) {
Curl_conn_cf_close(b->cf, data);
Curl_conn_cf_discard_chain(&b->cf, data);
b->cf = NULL;
}
- b->result = CURLE_OK;
- b->reply_ms = -1;
}
-static bool cf_hc_baller_is_active(struct cf_hc_baller *b)
+static bool cf_hc_baller_is_connecting(struct cf_hc_baller *b)
{
return b->cf && !b->result;
}
@@ -114,24 +112,24 @@ struct cf_hc_ctx {
cf_hc_state state;
struct curltime started; /* when connect started */
CURLcode result; /* overall result */
+ CURLcode check_h3_result;
struct cf_hc_baller ballers[2];
size_t baller_count;
timediff_t soft_eyeballs_timeout_ms;
timediff_t hard_eyeballs_timeout_ms;
uint8_t def_transport;
+ BIT(httpsrr_resolved);
+ BIT(checked_h3);
+ BIT(ballers_complete);
};
-static void cf_hc_ctx_reset(struct Curl_easy *data,
+static void cf_hc_ctx_close(struct Curl_easy *data,
struct cf_hc_ctx *ctx)
{
if(ctx) {
size_t i;
for(i = 0; i < ctx->baller_count; ++i)
- cf_hc_baller_reset(&ctx->ballers[i], data);
- ctx->state = CF_HC_RESOLV;
- ctx->result = CURLE_OK;
- ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
- ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 4;
+ cf_hc_baller_discard(&ctx->ballers[i], data);
}
}
@@ -139,7 +137,7 @@ static void cf_hc_ctx_destroy(struct Curl_easy *data,
struct cf_hc_ctx *ctx)
{
if(ctx) {
- cf_hc_ctx_reset(data, ctx);
+ cf_hc_ctx_close(data, ctx);
curlx_free(ctx);
}
}
@@ -150,6 +148,10 @@ static void cf_hc_baller_assign(struct cf_hc_baller *b,
{
b->alpn_id = alpn_id;
b->transport = def_transport;
+ b->cf = NULL;
+ b->result = CURLE_OK;
+ b->reply_ms = -1;
+ b->shutdown = FALSE;
switch(b->alpn_id) {
case ALPN_h3:
b->name = "h3";
@@ -172,24 +174,14 @@ static void cf_hc_baller_assign(struct cf_hc_baller *b,
static void cf_hc_baller_init(struct cf_hc_baller *b,
struct Curl_cfilter *cf,
- struct Curl_easy *data,
- uint8_t transport)
+ struct Curl_easy *data)
{
struct Curl_cfilter *save = cf->next;
cf->next = NULL;
b->started = *Curl_pgrs_now(data);
- switch(b->alpn_id) {
- case ALPN_h3:
- transport = TRNSPRT_QUIC;
- break;
- default:
- break;
- }
-
- if(!b->result)
- b->result = Curl_cf_setup_insert_after(cf, data, transport,
- CURL_CF_SSL_ENABLE);
+ b->result = Curl_cf_setup_insert_after(cf, data, b->transport,
+ CURL_CF_SSL_ENABLE);
b->cf = cf->next;
cf->next = save;
}
@@ -213,39 +205,34 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
struct cf_hc_baller *winner)
{
struct cf_hc_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
- int reply_ms;
- size_t i;
- DEBUGASSERT(winner->cf);
- for(i = 0; i < ctx->baller_count; ++i)
- if(winner != &ctx->ballers[i])
- cf_hc_baller_reset(&ctx->ballers[i], data);
-
- reply_ms = cf_hc_baller_reply_ms(winner, data);
- if(reply_ms >= 0)
- CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
- winner->name,
- (int)curlx_ptimediff_ms(Curl_pgrs_now(data),
- &winner->started), reply_ms);
- else
- CURL_TRC_CF(data, cf, "deferred handshake %s: %dms",
- winner->name, (int)curlx_ptimediff_ms(Curl_pgrs_now(data),
- &winner->started));
-
- /* install the winning filter below this one. */
+ /* Make the winner's connection filter out own sub-filter, check, move,
+ * close all remaining. */
+ if(cf->next) {
+ DEBUGASSERT(0);
+ return CURLE_FAILED_INIT;
+ }
+ if(!winner->cf) {
+ DEBUGASSERT(0);
+ return CURLE_FAILED_INIT;
+ }
+
cf->next = winner->cf;
winner->cf = NULL;
- /* whatever errors where reported by ballers, clear our errorbuf */
+ ctx->state = CF_HC_SUCCESS;
+ cf->connected = TRUE;
+
+ cf_hc_ctx_close(data, ctx);
+ /* ballers may have failf()'d, the winner resets it, so our
+ * errorbuf is clean again. */
Curl_reset_fail(data);
#ifdef USE_NGHTTP2
{
- /* Using nghttp2, we add the filter "below" us, so when the conn
- * closes, we tear it down for a fresh reconnect */
+ /* For a negotiated HTTP/2 connection insert the h2 filter. */
const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data);
if(alpn && !strcmp("h2", alpn)) {
- result = Curl_http2_switch_at(cf, data);
+ CURLcode result = Curl_http2_switch_at(cf, data);
if(result) {
ctx->state = CF_HC_FAILURE;
ctx->result = result;
@@ -254,198 +241,235 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
}
}
#endif
-
- ctx->state = CF_HC_SUCCESS;
- cf->connected = TRUE;
- return result;
+ return CURLE_OK;
}
-static bool time_to_start_next(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- size_t idx, struct curltime now)
+static bool time_to_start_baller2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct cf_hc_ctx *ctx = cf->ctx;
timediff_t elapsed_ms;
- size_t i;
- if(idx >= ctx->baller_count)
+ if(ctx->baller_count < 2)
return FALSE;
- if(cf_hc_baller_has_started(&ctx->ballers[idx]))
+ else if(cf_hc_baller_has_started(&ctx->ballers[1]))
return FALSE;
- for(i = 0; i < idx; i++) {
- if(!ctx->ballers[i].result)
- break;
- }
- if(i == idx) {
- CURL_TRC_CF(data, cf, "all previous attempts failed, starting %s",
- ctx->ballers[idx].name);
+ else if(ctx->ballers[0].result) {
+ CURL_TRC_CF(data, cf, "%s baller failed, starting %s",
+ ctx->ballers[0].name, ctx->ballers[1].name);
return TRUE;
}
- elapsed_ms = curlx_ptimediff_ms(&now, &ctx->started);
+
+ elapsed_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->started);
if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
- CURL_TRC_CF(data, cf, "hard timeout of %" FMT_TIMEDIFF_T "ms reached, "
- "starting %s",
- ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name);
+ CURL_TRC_CF(data, cf, "%s inconclusive after %" FMT_TIMEDIFF_T ", "
+ "starting %s", ctx->ballers[0].name,
+ ctx->hard_eyeballs_timeout_ms, ctx->ballers[1].name);
return TRUE;
}
-
- if((idx > 0) && (elapsed_ms >= ctx->soft_eyeballs_timeout_ms)) {
- if(cf_hc_baller_reply_ms(&ctx->ballers[idx - 1], data) < 0) {
- CURL_TRC_CF(data, cf, "soft timeout of %" FMT_TIMEDIFF_T "ms reached, "
- "%s has not seen any data, starting %s",
- ctx->soft_eyeballs_timeout_ms,
- ctx->ballers[idx - 1].name, ctx->ballers[idx].name);
+ else if(elapsed_ms >= ctx->soft_eyeballs_timeout_ms) {
+ if(cf_hc_baller_reply_ms(&ctx->ballers[0], data) < 0) {
+ CURL_TRC_CF(data, cf, "%s has not seen any data after %"
+ FMT_TIMEDIFF_T "ms, starting %s",
+ ctx->ballers[0].name, ctx->soft_eyeballs_timeout_ms,
+ ctx->ballers[1].name);
return TRUE;
}
- /* set the effective hard timeout again */
- Curl_expire(data, ctx->hard_eyeballs_timeout_ms - elapsed_ms,
- EXPIRE_ALPN_EYEBALLS);
}
return FALSE;
}
-static bool cf_https_alpns_contain(enum alpnid id,
- enum alpnid *list, size_t len)
+static bool cf_hc_may_h3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- size_t i;
- for(i = 0; i < len; ++i) {
- if(id == list[i])
- return TRUE;
+ struct cf_hc_ctx *ctx = cf->ctx;
+ if(!ctx->checked_h3) {
+ ctx->check_h3_result =
+ Curl_conn_may_http3(data, cf->conn, ctx->def_transport);
+ ctx->checked_h3 = TRUE;
}
- return FALSE;
+ return !ctx->check_h3_result;
}
-static CURLcode cf_hc_resolv(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static enum alpnid cf_hc_get_httpsrr_alpn(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ enum alpnid not_this_one)
{
- struct cf_hc_ctx *ctx = cf->ctx;
- enum alpnid alpn_ids[2];
- size_t alpn_count = 0, i;
- CURLcode result = CURLE_OK;
-
- if(cf->conn->bits.tls_enable_alpn) {
#ifdef USE_HTTPSRR
- /* Is there an HTTPSRR use its ALPNs here.
- * 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. */
- const struct Curl_https_rrinfo *rr;
-
- /* Do we have HTTPS-RR information? */
- rr = Curl_conn_dns_get_https(data, cf->sockindex);
-
- if(rr && !rr->no_def_alpn && /* ALPNs are defaults */
- (!rr->target || /* for same host */
- !rr->target[0] ||
- (rr->target[0] == '.' &&
- !rr->target[1])) &&
- (!rr->port_set || /* for same port */
- rr->port == cf->conn->remote_port)) {
- for(i = 0; i < CURL_ARRAYSIZE(rr->alpns) &&
- alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
- enum alpnid alpn = (enum alpnid)rr->alpns[i];
- if(cf_https_alpns_contain(alpn, alpn_ids, alpn_count))
- continue;
- switch(alpn) {
- case ALPN_h3:
- if(Curl_conn_may_http3(data, cf->conn, ctx->def_transport))
- break; /* not possible */
- if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
- CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
- alpn_ids[alpn_count++] = alpn;
- }
- break;
- case ALPN_h2:
- if(data->state.http_neg.allowed & CURL_HTTP_V2x) {
- CURL_TRC_CF(data, cf, "adding h2 via HTTPS-RR");
- alpn_ids[alpn_count++] = alpn;
- }
- break;
- case ALPN_h1:
- if(data->state.http_neg.allowed & CURL_HTTP_V1x) {
- CURL_TRC_CF(data, cf, "adding h1 via HTTPS-RR");
- alpn_ids[alpn_count++] = alpn;
- }
- break;
- default: /* ignore */
- break;
- }
- }
- }
-#endif
+ /* Is there an HTTPSRR use its ALPNs here.
+ * 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. */
+ const struct Curl_https_rrinfo *rr;
+ size_t i;
- /* Add preferred HTTP version ALPN first */
- if(data->state.http_neg.preferred &&
- (alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
- (data->state.http_neg.preferred & data->state.http_neg.allowed)) {
- enum alpnid alpn_pref = ALPN_none;
- switch(data->state.http_neg.preferred) {
- case CURL_HTTP_V3x:
- if(!Curl_conn_may_http3(data, cf->conn, ctx->def_transport))
- alpn_pref = ALPN_h3;
+ /* Do we have HTTPS-RR information? */
+ rr = Curl_conn_dns_get_https(data, cf->sockindex);
+
+ if(rr && !rr->no_def_alpn && /* ALPNs are defaults */
+ (!rr->target || /* for same host */
+ !rr->target[0] ||
+ (rr->target[0] == '.' &&
+ !rr->target[1])) &&
+ (!rr->port_set || /* for same port */
+ rr->port == cf->conn->remote_port)) {
+ for(i = 0; i < CURL_ARRAYSIZE(rr->alpns); ++i) {
+ enum alpnid alpn_rr = (enum alpnid)rr->alpns[i];
+ if(alpn_rr == not_this_one) /* don't want this one */
+ continue;
+ switch(alpn_rr) {
+ case ALPN_h3:
+ if((data->state.http_neg.allowed & CURL_HTTP_V3x) &&
+ cf_hc_may_h3(cf, data)) {
+ return alpn_rr;
+ }
break;
- case CURL_HTTP_V2x:
- alpn_pref = ALPN_h2;
+ case ALPN_h2:
+ if(data->state.http_neg.allowed & CURL_HTTP_V2x) {
+ return alpn_rr;
+ }
break;
- case CURL_HTTP_V1x:
- alpn_pref = ALPN_h1;
+ case ALPN_h1:
+ if(data->state.http_neg.allowed & CURL_HTTP_V1x) {
+ return alpn_rr;
+ }
break;
- default:
+ default: /* ignore */
break;
}
- if(alpn_pref &&
- !cf_https_alpns_contain(alpn_pref, alpn_ids, alpn_count)) {
- alpn_ids[alpn_count++] = alpn_pref;
- }
}
+ }
+#else
+ (void)cf;
+ (void)data;
+ (void)not_this_one;
+#endif
+ return ALPN_none;
+}
- 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, cf->conn, ctx->def_transport);
- if(!result) {
- CURL_TRC_CF(data, cf, "adding wanted h3");
- alpn_ids[alpn_count++] = ALPN_h3;
- }
- else if(data->state.http_neg.wanted == CURL_HTTP_V3x)
- goto out; /* only h3 allowed, not possible, error out */
- }
- if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
- (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
- !cf_https_alpns_contain(ALPN_h2, alpn_ids, alpn_count)) {
- CURL_TRC_CF(data, cf, "adding wanted h2");
- alpn_ids[alpn_count++] = ALPN_h2;
- }
- else if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
- (data->state.http_neg.wanted & CURL_HTTP_V1x) &&
- !cf_https_alpns_contain(ALPN_h1, alpn_ids, alpn_count)) {
- CURL_TRC_CF(data, cf, "adding wanted h1");
- alpn_ids[alpn_count++] = ALPN_h1;
+static enum alpnid cf_hc_get_pref_alpn(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ enum alpnid not_this_one)
+{
+ if((data->state.http_neg.preferred & data->state.http_neg.allowed)) {
+ switch(data->state.http_neg.preferred) {
+ case CURL_HTTP_V3x:
+ if(cf_hc_may_h3(cf, data) && (ALPN_h3 != not_this_one))
+ return ALPN_h3;
+ break;
+ case CURL_HTTP_V2x:
+ if(ALPN_h2 != not_this_one)
+ return ALPN_h2;
+ break;
+ case CURL_HTTP_V1x:
+ /* If we are trying h2 already, h1 is already used as fallback */
+ if((ALPN_h1 != not_this_one) && (ALPN_h2 != not_this_one))
+ return ALPN_h1;
+ break;
+ default:
+ break;
}
}
+ return ALPN_none;
+}
- if(!alpn_count) {
- alpn_ids[0] = ALPN_none;
- alpn_count = 1;
+static enum alpnid cf_hc_get_first_alpn(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ http_majors choices,
+ enum alpnid not_this_one)
+{
+ if((ALPN_h3 != not_this_one) && (choices & CURL_HTTP_V3x) &&
+ cf_hc_may_h3(cf, data)) {
+ return ALPN_h3;
+ }
+ if((ALPN_h2 != not_this_one) && (choices & CURL_HTTP_V2x)) {
+ return ALPN_h2;
}
+ /* If we are trying h2 already, h1 is already used as fallback */
+ if((ALPN_h1 != not_this_one) && (ALPN_h2 != not_this_one) &&
+ (choices & CURL_HTTP_V1x)) {
+ return ALPN_h1;
+ }
+ return ALPN_none;
+}
- /* Install ballers for the ALPNs we selected. */
- DEBUGASSERT(alpn_count <= CURL_ARRAYSIZE(ctx->ballers));
- if(!alpn_count || (alpn_count > CURL_ARRAYSIZE(ctx->ballers))) {
- failf(data, "https-connect filter create with unsupported %zu ALPN ids",
- alpn_count);
- result = CURLE_FAILED_INIT;
- goto out;
+static CURLcode cf_hc_set_baller1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_hc_ctx *ctx = cf->ctx;
+ enum alpnid alpn1 = ALPN_none;
+ VERBOSE(const char *source = "HTTPS-RR");
+
+ DEBUGASSERT(cf->conn->bits.tls_enable_alpn);
+
+ alpn1 = cf_hc_get_httpsrr_alpn(cf, data, ALPN_none);
+ if(alpn1 == ALPN_none) {
+ /* preference is configured and allowed, can we use it? */
+ VERBOSE(source = "preferred version");
+ alpn1 = cf_hc_get_pref_alpn(cf, data, ALPN_none);
+ }
+ if(alpn1 == ALPN_none) {
+ VERBOSE(source = "wanted versions");
+ alpn1 = cf_hc_get_first_alpn(cf, data,
+ data->state.http_neg.wanted,
+ ALPN_none);
+ }
+ if(alpn1 == ALPN_none) {
+ VERBOSE(source = "allowed versions");
+ alpn1 = cf_hc_get_first_alpn(cf, data,
+ data->state.http_neg.allowed,
+ ALPN_none);
}
- for(i = 0; i < alpn_count; ++i)
- cf_hc_baller_assign(&ctx->ballers[i], alpn_ids[i], ctx->def_transport);
- for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
- ctx->ballers[i].alpn_id = ALPN_none;
- ctx->baller_count = alpn_count;
+ if(alpn1 == ALPN_none) {
+ /* None of the wanted/allowed HTTP versions could be chosen */
+ if(ctx->check_h3_result) {
+ CURL_TRC_CF(data, cf, "unable to use HTTP/3");
+ return ctx->check_h3_result;
+ }
+ CURL_TRC_CF(data, cf, "unable to select HTTP version");
+ return CURLE_FAILED_INIT;
+ }
-out:
- return result;
+ cf_hc_baller_assign(&ctx->ballers[0], alpn1, ctx->def_transport);
+ ctx->baller_count = 1;
+ CURL_TRC_CF(data, cf, "1st attempt uses %s from %s",
+ ctx->ballers[0].name, source);
+ return CURLE_OK;
+}
+
+static void cf_hc_set_baller2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_hc_ctx *ctx = cf->ctx;
+ enum alpnid alpn2 = ALPN_none, alpn1 = ctx->ballers[0].alpn_id;
+ VERBOSE(const char *source = "HTTPS-RR");
+
+ if(ctx->ballers_complete)
+ return; /* already done */
+ if(!ctx->httpsrr_resolved)
+ return; /* HTTPS-RR pending */
+
+ alpn2 = cf_hc_get_httpsrr_alpn(cf, data, alpn1);
+ if(alpn2 == ALPN_none) {
+ /* preference is configured and allowed, can we use it? */
+ VERBOSE(source = "preferred version");
+ alpn2 = cf_hc_get_pref_alpn(cf, data, alpn1);
+ }
+ if(alpn2 == ALPN_none) {
+ VERBOSE(source = "wanted versions");
+ alpn2 = cf_hc_get_first_alpn(cf, data,
+ data->state.http_neg.wanted,
+ alpn1);
+ }
+
+ if(alpn2 != ALPN_none) {
+ cf_hc_baller_assign(&ctx->ballers[1], alpn2, ctx->def_transport);
+ ctx->baller_count = 2;
+ CURL_TRC_CF(data, cf, "2nd attempt uses %s from %s",
+ ctx->ballers[1].name, source);
+ }
+ ctx->ballers_complete = TRUE;
}
static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
@@ -454,7 +478,6 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
{
struct cf_hc_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
- size_t i, failed_ballers;
if(cf->connected) {
*done = TRUE;
@@ -462,35 +485,41 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
+
+ if(!ctx->httpsrr_resolved)
+ ctx->httpsrr_resolved = Curl_conn_dns_resolved_https(data, cf->sockindex);
+
switch(ctx->state) {
case CF_HC_RESOLV:
- result = cf_hc_resolv(cf, data);
- if(result) {
- if(result == CURLE_AGAIN)
- result = CURLE_OK;
- goto out;
- }
- DEBUGASSERT(ctx->baller_count);
+ /* Without any addressinfo, delay the start of balling. */
+ if(!Curl_conn_dns_has_any_ai(data, cf->sockindex))
+ return CURLE_OK;
ctx->state = CF_HC_INIT;
FALLTHROUGH();
case CF_HC_INIT:
DEBUGASSERT(!cf->next);
- for(i = 0; i < ctx->baller_count; i++)
- DEBUGASSERT(!ctx->ballers[i].cf);
CURL_TRC_CF(data, cf, "connect, init");
+ result = cf_hc_set_baller1(cf, data);
+ if(result) {
+ ctx->result = result;
+ ctx->state = CF_HC_FAILURE;
+ goto out;
+ }
+ cf_hc_set_baller2(cf, data);
ctx->started = *Curl_pgrs_now(data);
- cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport);
- if(ctx->baller_count > 1) {
+ cf_hc_baller_init(&ctx->ballers[0], cf, data);
+ if((ctx->baller_count > 1) || !ctx->ballers_complete) {
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
- "ms", ctx->soft_eyeballs_timeout_ms);
}
ctx->state = CF_HC_CONNECT;
FALLTHROUGH();
case CF_HC_CONNECT:
- if(cf_hc_baller_is_active(&ctx->ballers[0])) {
+ if(!ctx->ballers_complete)
+ cf_hc_set_baller2(cf, data);
+
+ if(cf_hc_baller_is_connecting(&ctx->ballers[0])) {
result = cf_hc_baller_connect(&ctx->ballers[0], cf, data, done);
if(!result && *done) {
result = baller_connected(cf, data, &ctx->ballers[0]);
@@ -498,12 +527,11 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
}
- if(time_to_start_next(cf, data, 1, *Curl_pgrs_now(data))) {
- cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport);
+ if(time_to_start_baller2(cf, data)) {
+ cf_hc_baller_init(&ctx->ballers[1], cf, data);
}
- if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) {
- CURL_TRC_CF(data, cf, "connect, check %s", ctx->ballers[1].name);
+ if(cf_hc_baller_is_connecting(&ctx->ballers[1])) {
result = cf_hc_baller_connect(&ctx->ballers[1], cf, data, done);
if(!result && *done) {
result = baller_connected(cf, data, &ctx->ballers[1]);
@@ -511,21 +539,12 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
}
- failed_ballers = 0;
- for(i = 0; i < ctx->baller_count; i++) {
- if(ctx->ballers[i].result)
- ++failed_ballers;
- }
-
- if(failed_ballers == ctx->baller_count) {
+ if(ctx->ballers[0].result &&
+ (ctx->ballers[1].result ||
+ (ctx->ballers_complete && (ctx->baller_count < 2)))) {
/* all have failed. we give up */
CURL_TRC_CF(data, cf, "connect, all attempts failed");
- for(i = 0; i < ctx->baller_count; i++) {
- if(ctx->ballers[i].result) {
- result = ctx->ballers[i].result;
- break;
- }
- }
+ ctx->result = result = ctx->ballers[0].result;
ctx->state = CF_HC_FAILURE;
goto out;
}
@@ -569,7 +588,7 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
for(i = 0; i < ctx->baller_count; i++) {
struct cf_hc_baller *b = &ctx->ballers[i];
bool bdone = FALSE;
- if(!cf_hc_baller_is_active(b) || b->shutdown)
+ if(!cf_hc_baller_is_connecting(b) || b->shutdown)
continue;
b->result = b->cf->cft->do_shutdown(b->cf, data, &bdone);
if(b->result || bdone)
@@ -602,7 +621,7 @@ static CURLcode cf_hc_adjust_pollset(struct Curl_cfilter *cf,
for(i = 0; (i < ctx->baller_count) && !result; i++) {
struct cf_hc_baller *b = &ctx->ballers[i];
- if(!cf_hc_baller_is_active(b))
+ if(!cf_hc_baller_is_connecting(b))
continue;
result = Curl_conn_cf_adjust_pollset(b->cf, data, ps);
}
@@ -705,7 +724,7 @@ out:
static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "close");
- cf_hc_ctx_reset(data, cf->ctx);
+ cf_hc_ctx_close(data, cf->ctx);
cf->connected = FALSE;
if(cf->next) {
lib/vquic/vquic.c+1 -1
@@ -725,7 +725,7 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
unsigned char transport)
{
if(transport == TRNSPRT_UNIX) {
- /* cannot do QUIC over a Unix domain socket */
+ failf(data, "HTTP/3 cannot be used over UNIX domain sockets");
return CURLE_QUIC_CONNECT_ERROR;
}
if(!(conn->scheme->flags & PROTOPT_SSL)) {