diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index ed574ea9b6..e77badec1d 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -652,26 +652,6 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf, return FALSE; } -static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf, - struct Curl_easy *data, - int query) -{ - struct cf_hc_ctx *ctx = cf->ctx; - struct curltime t, tmax; - size_t i; - - memset(&tmax, 0, sizeof(tmax)); - for(i = 0; i < ctx->baller_count; i++) { - struct Curl_cfilter *cfb = ctx->ballers[i].cf; - memset(&t, 0, sizeof(t)); - if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { - if((t.tv_sec || t.tv_usec) && curlx_ptimediff_us(&t, &tmax) > 0) - tmax = t; - } - } - return tmax; -} - static CURLcode cf_hc_query(struct Curl_cfilter *cf, struct Curl_easy *data, int query, int *pres1, void *pres2) @@ -681,16 +661,6 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf, if(!cf->connected) { switch(query) { - case CF_QUERY_TIMER_CONNECT: { - struct curltime *when = pres2; - *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); - return CURLE_OK; - } - case CF_QUERY_TIMER_APPCONNECT: { - struct curltime *when = pres2; - *when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); - return CURLE_OK; - } case CF_QUERY_NEED_FLUSH: { for(i = 0; i < ctx->baller_count; i++) if(cf_hc_baller_needs_flush(&ctx->ballers[i], data)) { @@ -717,12 +687,26 @@ static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf, size_t i; if(!cf->connected) { - for(i = 0; i < ctx->baller_count; i++) { - result = cf_hc_baller_cntrl(&ctx->ballers[i], data, event, arg1, arg2); - if(result && (result != CURLE_AGAIN)) - goto out; + switch(event) { + case CF_CTRL_REPORT_STATS: + for(i = 0; i < ctx->baller_count; i++) { + /* Make the first baller that connected at network level report */ + if(Curl_conn_cf_is_ip_connected(ctx->ballers[i].cf, data)) { + Curl_conn_cf_cntrl(ctx->ballers[i].cf, data, TRUE, + event, arg1, arg2); + break; + } + } + break; + default: + for(i = 0; i < ctx->baller_count; i++) { + result = cf_hc_baller_cntrl(&ctx->ballers[i], data, event, arg1, arg2); + if(result && (result != CURLE_AGAIN)) + goto out; + } + result = CURLE_OK; + break; } - result = CURLE_OK; } out: return result; diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 3f52ee78ac..fa7104ffca 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -645,24 +645,6 @@ static bool cf_ip_ballers_pending(struct cf_ip_ballers *bs, return FALSE; } -static struct curltime cf_ip_ballers_max_time(struct cf_ip_ballers *bs, - struct Curl_easy *data, - int query) -{ - struct curltime t, tmax; - struct cf_ip_attempt *a; - - memset(&tmax, 0, sizeof(tmax)); - for(a = bs->running; a; a = a->next) { - memset(&t, 0, sizeof(t)); - if(a->cf && !a->cf->cft->query(a->cf, data, query, NULL, &t)) { - if((t.tv_sec || t.tv_usec) && curlx_ptimediff_us(&t, &tmax) > 0) - tmax = t; - } - } - return tmax; -} - static int cf_ip_ballers_min_reply_ms(struct cf_ip_ballers *bs, struct Curl_easy *data) { @@ -940,18 +922,6 @@ static CURLcode cf_ip_happy_query(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1); return CURLE_OK; } - case CF_QUERY_TIMER_CONNECT: { - struct curltime *when = pres2; - *when = cf_ip_ballers_max_time(&ctx->ballers, data, - CF_QUERY_TIMER_CONNECT); - return CURLE_OK; - } - case CF_QUERY_TIMER_APPCONNECT: { - struct curltime *when = pres2; - *when = cf_ip_ballers_max_time(&ctx->ballers, data, - CF_QUERY_TIMER_APPCONNECT); - return CURLE_OK; - } default: break; } diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 1511d6f036..c72c30f7b7 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -988,6 +988,7 @@ struct cf_socket_ctx { BIT(accepted); /* socket was accepted, not connected */ BIT(sock_connected); /* socket is "connected", e.g. in UDP */ BIT(active); + BIT(stats_reported); }; static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx, @@ -1729,6 +1730,26 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf, case CF_CTRL_FORGET_SOCKET: ctx->sock = CURL_SOCKET_BAD; break; + case CF_CTRL_REPORT_STATS: + if(cf->connected && !ctx->stats_reported) { + struct curltime *ts = NULL; + switch(ctx->transport) { + case TRNSPRT_UDP: + case TRNSPRT_QUIC: + /* Since UDP connected sockets work different from TCP, we use the + * time of the first byte from the peer as the "connect" time. */ + if(ctx->got_first_byte) + ts = &ctx->first_byte_at; + break; + default: + ts = &ctx->connected_at; + break; + } + if(ts) { + Curl_pgrsTimeWas(data, TIMER_CONNECT, *ts); + ctx->stats_reported = TRUE; + } + } } return CURLE_OK; } @@ -1799,24 +1820,6 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf, else *pres1 = -1; return CURLE_OK; - case CF_QUERY_TIMER_CONNECT: { - struct curltime *when = pres2; - switch(ctx->transport) { - case TRNSPRT_UDP: - case TRNSPRT_QUIC: - /* Since UDP connected sockets work different from TCP, we use the - * time of the first byte from the peer as the "connect" time. */ - if(ctx->got_first_byte) { - *when = ctx->first_byte_at; - break; - } - FALLTHROUGH(); - default: - *when = ctx->connected_at; - break; - } - return CURLE_OK; - } case CF_QUERY_IP_INFO: #ifdef USE_IPV6 *pres1 = (ctx->addr.family == AF_INET6); @@ -1825,6 +1828,12 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf, #endif *(struct ip_quadruple *)pres2 = ctx->ip; return CURLE_OK; + case CF_QUERY_REALLY_CONNECTED: + if(cf->cft != &Curl_cft_udp) + *pres1 = cf->connected; + else + *pres1 = ctx->got_first_byte; + return CURLE_OK; default: break; } diff --git a/lib/cfilters.c b/lib/cfilters.c index ecfab014a0..8875473fb3 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -462,12 +462,32 @@ static CURLcode cf_cntrl_all(struct connectdata *conn, return result; } +bool Curl_conn_cf_is_ip_connected(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + if(cf) { + int value = 0; + if(!cf->cft->query(cf, data, CF_QUERY_REALLY_CONNECTED, &value, NULL)) + return !!value; + } + return FALSE; +} + void Curl_conn_cntrl_update_info(struct Curl_easy *data, struct connectdata *conn) { cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL); } +void Curl_conn_cntrl_report_stats(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + if((unsigned)sockindex < CURL_ARRAYSIZE(conn->cfilter)) + (void)Curl_conn_cf_cntrl(conn->cfilter[sockindex], data, TRUE, + CF_CTRL_REPORT_STATS, 0, NULL); +} + void Curl_conn_remove_setup_filters(struct Curl_easy *data, int8_t sockindex) { diff --git a/lib/cfilters.h b/lib/cfilters.h index b977039c85..979275b729 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -121,6 +121,7 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf, #define CF_CTRL_CONN_INFO_UPDATE (256 + 0) /* 0 NULL ignored */ #define CF_CTRL_FORGET_SOCKET (256 + 1) /* 0 NULL ignored */ #define CF_CTRL_FLUSH (256 + 2) /* 0 NULL first fail */ +#define CF_CTRL_REPORT_STATS (256 + 3) /* 0 NULL ignored */ /** * Handle event/control for the filter. @@ -156,13 +157,17 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, null-terminated string or NULL if none selected/handshake not done. Implemented by filter types CF_TYPE_SSL or CF_TYPE_IP_CONNECT. + * - CF_QUERY_REALLY_CONNECTED: implemented in socket filters to return + * if a reply from a server has really arrived. For + * non-UDP sockets this is TRUE when the socket became + * writable. For UDP sockets, this is TRUE when the + * first byte from the peer was received. */ /* query res1 res2 */ #define CF_QUERY_MAX_CONCURRENT 1 /* number - */ #define CF_QUERY_CONNECT_REPLY_MS 2 /* number - */ #define CF_QUERY_SOCKET 3 /* - curl_socket_t */ -#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */ -#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */ +/* unused 4 + 5 */ #define CF_QUERY_STREAM_ERROR 6 /* error code - */ #define CF_QUERY_NEED_FLUSH 7 /* TRUE/FALSE - */ #define CF_QUERY_IP_INFO 8 /* TRUE/FALSE struct ip_quadruple */ @@ -175,6 +180,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, #define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */ #define CF_QUERY_TRANSPORT 14 /* TRNSPRT_* - * */ #define CF_QUERY_ALPN_NEGOTIATED 15 /* - const char * */ +#define CF_QUERY_REALLY_CONNECTED 16 /* TRUE/FALSE - */ /** * Query the cfilter for properties. Filters ignorant of a query will @@ -343,6 +349,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); +bool Curl_conn_cf_is_ip_connected(struct Curl_cfilter *cf, + struct Curl_easy *data); + unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, struct Curl_easy *data); @@ -422,6 +431,10 @@ const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data, void Curl_conn_cntrl_update_info(struct Curl_easy *data, struct connectdata *conn); +void Curl_conn_cntrl_report_stats(struct Curl_easy *data, + struct connectdata *conn, + int sockindex); + void Curl_conn_remove_setup_filters(struct Curl_easy *data, int8_t sockindex); diff --git a/lib/connect.c b/lib/connect.c index df7a02463d..e669f7630d 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -306,22 +306,11 @@ static CURLcode conn_connect_trace(struct Curl_easy *data, /** * Update connection statistics */ -static void conn_report_connect_stats(struct Curl_cfilter *cf, - struct Curl_easy *data) +static void conn_report_stats(struct Curl_easy *data, int sockindex) { - if(cf && (cf->sockindex == FIRSTSOCKET)) { - struct curltime connected; - struct curltime appconnected; - - memset(&connected, 0, sizeof(connected)); - cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected); - if(connected.tv_sec || connected.tv_usec) - Curl_pgrsTimeWas(data, TIMER_CONNECT, connected); - - memset(&appconnected, 0, sizeof(appconnected)); - cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected); - if(appconnected.tv_sec || appconnected.tv_usec) - Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected); + /* We do gather stats for the second socket...yet */ + if(sockindex == FIRSTSOCKET) { + Curl_conn_cntrl_report_stats(data, data->conn, sockindex); } } @@ -384,7 +373,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, * persist information at the connection. E.g. cf-socket sets the * socket and ip related information. */ Curl_conn_cntrl_update_info(data, data->conn); - conn_report_connect_stats(cf, data); + conn_report_stats(data, sockindex); data->conn->lastupkeep = *Curl_pgrs_now(data); VERBOSE(result = conn_connect_trace(data, cf)); VERBOSE(Curl_conn_trc_filters(data, sockindex, "connected")); @@ -396,7 +385,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d", (int)result); VERBOSE(Curl_conn_trc_filters(data, sockindex, "failed to connect")); - conn_report_connect_stats(cf, data); + conn_report_stats(data, sockindex); goto out; } diff --git a/lib/vquic/cf-ngtcp2-cmn.c b/lib/vquic/cf-ngtcp2-cmn.c index 771b77b434..6446581ebf 100644 --- a/lib/vquic/cf-ngtcp2-cmn.c +++ b/lib/vquic/cf-ngtcp2-cmn.c @@ -267,8 +267,11 @@ static int cb_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) /* In case of earlydata, where we simulate being connected, update * the handshake time when we really did connect */ - if(ctx->use_earlydata) + if(ctx->use_earlydata && !ctx->stats_reported && + !(cf->cft->flags & CF_TYPE_PROXY)) { Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); + ctx->stats_reported = TRUE; + } if(ctx->use_earlydata) { #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA) ctx->earlydata_accepted = @@ -2008,4 +2011,65 @@ CURLcode Curl_cf_ngtcp2_h3_init_ctrls(struct cf_ngtcp2_ctx *ctx, return CURLE_OK; } + +CURLcode Curl_cf_ngtcp2_cmn_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + + switch(query) { + case CF_QUERY_CONNECT_REPLY_MS: + if((ctx->q.sockfd != CURL_SOCKET_BAD) && ctx->q.got_first_byte) { + timediff_t ms = curlx_ptimediff_ms(&ctx->q.first_byte_at, + &ctx->started_at); + *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX; + return CURLE_OK; + } + break; + case CF_QUERY_REALLY_CONNECTED: + if(ctx->q.sockfd != CURL_SOCKET_BAD) { + *pres1 = ctx->q.got_first_byte; + return CURLE_OK; + } + break; + default: + break; + } + return cf->next ? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +CURLcode Curl_cf_ngtcp2_cmn_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct cf_ngtcp2_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + (void)arg1; + (void)arg2; + switch(event) { + case CF_CTRL_REPORT_STATS: + if(cf->connected && !ctx->stats_reported) { + if((cf->cft->flags & CF_TYPE_PROXY) && + (ctx->q.sockfd != CURL_SOCKET_BAD) && ctx->q.got_first_byte) { + Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->q.first_byte_at); + ctx->stats_reported = TRUE; + } + else if(ctx->handshake_at.tv_sec || ctx->handshake_at.tv_usec) { + if(ctx->q.sockfd != CURL_SOCKET_BAD) + Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->q.first_byte_at); + Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); + ctx->stats_reported = TRUE; + } + } + break; + default: + break; + } + return result; +} + #endif /* !CURL_DISABLE_HTTP && USE_NGTCP2 && USE_NGHTTP3 */ diff --git a/lib/vquic/cf-ngtcp2-cmn.h b/lib/vquic/cf-ngtcp2-cmn.h index 88554edfb6..f4dd9158ec 100644 --- a/lib/vquic/cf-ngtcp2-cmn.h +++ b/lib/vquic/cf-ngtcp2-cmn.h @@ -142,6 +142,7 @@ struct cf_ngtcp2_ctx { BIT(use_earlydata); /* Using 0RTT data */ BIT(earlydata_accepted); /* 0RTT was accepted by server */ BIT(shutdown_started); /* queued shutdown packets */ + BIT(stats_reported); /* connect statistics reported */ }; /* How to access `call_data` from a cf_ngtcp2 filter */ @@ -234,6 +235,14 @@ bool Curl_cf_ngtcp2_cmn_conn_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, bool *input_pending); +CURLcode Curl_cf_ngtcp2_cmn_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2); + +CURLcode Curl_cf_ngtcp2_cmn_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2); + #endif /* !CURL_DISABLE_HTTP && USE_NGTCP2 && USE_NGHTTP3 */ #endif /* HEADER_CURL_VQUIC_CF_NGTCP2_CMN_H */ diff --git a/lib/vquic/cf-ngtcp2-proxy.c b/lib/vquic/cf-ngtcp2-proxy.c index f5c967c5b1..5e85c80594 100644 --- a/lib/vquic/cf-ngtcp2-proxy.c +++ b/lib/vquic/cf-ngtcp2-proxy.c @@ -1229,7 +1229,7 @@ struct Curl_cftype Curl_cft_h3_proxy = { Curl_cf_def_cntrl, Curl_cf_ngtcp2_cmn_conn_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + Curl_cf_ngtcp2_cmn_query, }; CURLcode Curl_cf_ngtcp2_proxy_create(struct Curl_cfilter **pcf, diff --git a/lib/vquic/cf-ngtcp2.c b/lib/vquic/cf-ngtcp2.c index e97a3d8271..f6fd6c55fc 100644 --- a/lib/vquic/cf-ngtcp2.c +++ b/lib/vquic/cf-ngtcp2.c @@ -911,8 +911,6 @@ static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, struct cf_call_data save; CF_DATA_SAVE(save, cf, data); - (void)arg1; - (void)arg2; switch(event) { case CF_CTRL_DATA_SETUP: break; @@ -939,6 +937,7 @@ static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, } break; default: + result = Curl_cf_ngtcp2_cmn_cntrl(cf, data, event, arg1, arg2); break; } CF_DATA_RESTORE(cf, save); @@ -1035,27 +1034,6 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, CF_DATA_RESTORE(cf, save); return CURLE_OK; } - case CF_QUERY_CONNECT_REPLY_MS: - if(ctx->q.got_first_byte) { - timediff_t ms = curlx_ptimediff_ms(&ctx->q.first_byte_at, - &ctx->started_at); - *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX; - } - else - *pres1 = -1; - return CURLE_OK; - case CF_QUERY_TIMER_CONNECT: { - struct curltime *when = pres2; - if(ctx->q.got_first_byte) - *when = ctx->q.first_byte_at; - return CURLE_OK; - } - case CF_QUERY_TIMER_APPCONNECT: { - struct curltime *when = pres2; - if(cf->connected) - *when = ctx->handshake_at; - return CURLE_OK; - } case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; @@ -1076,9 +1054,7 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, default: break; } - return cf->next ? - cf->next->cft->query(cf->next, data, query, pres1, pres2) : - CURLE_UNKNOWN_OPTION; + return Curl_cf_ngtcp2_cmn_query(cf, data, query, pres1, pres2); } struct Curl_cftype Curl_cft_http3 = { diff --git a/lib/vquic/cf-quiche.c b/lib/vquic/cf-quiche.c index fa33675497..52dad536b6 100644 --- a/lib/vquic/cf-quiche.c +++ b/lib/vquic/cf-quiche.c @@ -94,6 +94,7 @@ struct cf_quiche_ctx { BIT(goaway); /* got GOAWAY from server */ BIT(x509_store_setup); /* if x509 store has been set up */ BIT(shutdown_started); /* queued shutdown packets */ + BIT(stats_reported); /* connect statistics reported */ }; #ifdef DEBUG_QUICHE @@ -1254,6 +1255,14 @@ static CURLcode cf_quiche_cntrl(struct Curl_cfilter *cf, Curl_conn_set_multiplex(cf->conn); } break; + case CF_CTRL_REPORT_STATS: + if(cf->connected && !ctx->stats_reported && + (ctx->handshake_at.tv_sec || ctx->handshake_at.tv_usec)) { + Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->q.first_byte_at); + Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); + ctx->stats_reported = TRUE; + } + break; default: break; } @@ -1550,18 +1559,6 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, else *pres1 = -1; return CURLE_OK; - case CF_QUERY_TIMER_CONNECT: { - struct curltime *when = pres2; - if(ctx->q.got_first_byte) - *when = ctx->q.first_byte_at; - return CURLE_OK; - } - case CF_QUERY_TIMER_APPCONNECT: { - struct curltime *when = pres2; - if(cf->connected) - *when = ctx->handshake_at; - return CURLE_OK; - } case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c index 2d2484957b..eb13abad73 100644 --- a/lib/vquic/vquic.c +++ b/lib/vquic/vquic.c @@ -24,6 +24,7 @@ #include "curl_setup.h" #include "urldata.h" #include "vquic/vquic.h" +#include "vtls/vtls.h" #include "curl_trc.h" diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 3782238636..c1504fad3b 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1064,7 +1064,10 @@ static CURLcode ssl_cf_connect_deferred(struct Curl_cfilter *cf, result = ssl_cf_connect(cf, data, done); if(!result && *done) { - Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done); + if(!connssl->stats_reported && (cf->cft == &Curl_cft_ssl)) { + Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done); + connssl->stats_reported = TRUE; + } switch(connssl->earlydata_state) { case ssl_earlydata_none: break; @@ -1232,12 +1235,6 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, struct ssl_connect_data *connssl = cf->ctx; switch(query) { - case CF_QUERY_TIMER_APPCONNECT: { - struct curltime *when = pres2; - if(cf->connected && !Curl_ssl_cf_is_proxy(cf)) - *when = connssl->handshake_done; - return CURLE_OK; - } case CF_QUERY_SSL_INFO: case CF_QUERY_SSL_CTX_INFO: if(!Curl_ssl_cf_is_proxy(cf)) { @@ -1287,6 +1284,14 @@ static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, cf->conn->httpversion_seen = 30; } break; + case CF_CTRL_REPORT_STATS: + if(cf->connected && !connssl->stats_reported && + (cf->cft == &Curl_cft_ssl) && + (connssl->handshake_done.tv_sec || connssl->handshake_done.tv_usec)) { + Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done); + connssl->stats_reported = TRUE; + } + break; } return CURLE_OK; } diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h index 330d8427ca..7c1881b8d8 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -132,6 +132,7 @@ struct ssl_connect_data { BIT(peer_closed); /* peer has closed connection */ BIT(prefs_checked); /* SSL preferences have been checked */ BIT(input_pending); /* data for SSL_read() may be available */ + BIT(stats_reported); /* connect times have been reported */ }; /* Definitions for SSL Implementations */