Lines Matching +full:ngtcp2 +full:- +full:version
21 * SPDX-License-Identifier: curl
28 #include <ngtcp2/ngtcp2.h>
34 #include <ngtcp2/ngtcp2_crypto_boringssl.h>
36 #include <ngtcp2/ngtcp2_crypto_quictls.h>
40 #include <ngtcp2/ngtcp2_crypto_gnutls.h>
43 #include <ngtcp2/ngtcp2_crypto_wolfssl.h>
54 #include "cf-socket.h"
65 #include "vquic-tls.h"
104 * Store ngtcp2 version info in this buffer.
110 (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s", in Curl_ngtcp2_ver()
111 ng2->version_str, ht3->version_str); in Curl_ngtcp2_ver()
122 uint32_t version; member
135 struct Curl_hash streams; /* hash `data->id` to `h3_stream_ctx` */
147 ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
178 data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
180 Curl_hash_offt_get(&(ctx)->streams, (id))))
184 Curl_bufq_free(&stream->sendbuf); in h3_stream_ctx_free()
185 Curl_h1_req_parse_free(&stream->h1); in h3_stream_ctx_free()
198 struct cf_ngtcp2_ctx *ctx = cf->ctx; in h3_data_setup()
201 if(!data || !data->req.p.http) { in h3_data_setup()
213 stream->id = -1; in h3_data_setup()
215 Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, in h3_data_setup()
217 stream->sendbuf_len_in_flight = 0; in h3_data_setup()
218 Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); in h3_data_setup()
220 if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) { in h3_data_setup()
232 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_stream_close()
235 if(!stream->closed && ctx->qconn && ctx->h3conn) { in cf_ngtcp2_stream_close()
238 nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL); in cf_ngtcp2_stream_close()
239 ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL); in cf_ngtcp2_stream_close()
240 stream->closed = TRUE; in cf_ngtcp2_stream_close()
241 (void)ngtcp2_conn_shutdown_stream(ctx->qconn, 0, stream->id, in cf_ngtcp2_stream_close()
245 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cancel stream -> %d", in cf_ngtcp2_stream_close()
246 stream->id, result); in cf_ngtcp2_stream_close()
252 struct cf_ngtcp2_ctx *ctx = cf->ctx; in h3_data_done()
257 stream->id); in h3_data_done()
259 Curl_hash_offt_remove(&ctx->streams, data->id); in h3_data_done()
268 struct cf_ngtcp2_ctx *ctx = cf->ctx; in get_stream_easy()
274 if(stream && stream->id == stream_id) { in get_stream_easy()
279 DEBUGASSERT(data->multi); in get_stream_easy()
280 for(sdata = data->multi->easyp; sdata; sdata = sdata->next) { in get_stream_easy()
281 if(sdata->conn != data->conn) in get_stream_easy()
284 if(stream && stream->id == stream_id) { in get_stream_easy()
297 struct cf_ngtcp2_ctx *ctx = cf->ctx; in h3_drain_stream()
303 if(stream && stream->upload_left && !stream->send_closed) in h3_drain_stream()
305 if(data->state.select_bits != bits) { in h3_drain_stream()
306 data->state.select_bits = bits; in h3_drain_stream()
311 /* ngtcp2 default congestion controller does not perform pacing. Limit
326 struct cf_ngtcp2_ctx *ctx = cf->ctx; in pktx_update_time()
328 vquic_ctx_update_time(&ctx->q); in pktx_update_time()
329 pktx->ts = ctx->q.last_op.tv_sec * NGTCP2_SECONDS + in pktx_update_time()
330 ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS; in pktx_update_time()
337 pktx->cf = cf; in pktx_init()
338 pktx->data = data; in pktx_init()
339 pktx->pkt_count = 0; in pktx_init()
340 ngtcp2_path_storage_zero(&pktx->ps); in pktx_init()
350 struct Curl_cfilter *cf = conn_ref->user_data; in get_conn()
351 struct cf_ngtcp2_ctx *ctx = cf->ctx; in get_conn()
352 return ctx->qconn; in get_conn()
359 struct cf_ngtcp2_ctx *ctx = cf->ctx; in quic_printf()
374 struct cf_ngtcp2_ctx *ctx = cf->ctx; in qlog_callback()
376 if(ctx->qlogfd != -1) { in qlog_callback()
377 ssize_t rc = write(ctx->qlogfd, data, datalen); in qlog_callback()
378 if(rc == -1) { in qlog_callback()
380 close(ctx->qlogfd); in qlog_callback()
381 ctx->qlogfd = -1; in qlog_callback()
391 ngtcp2_settings *s = &ctx->settings; in quic_settings()
392 ngtcp2_transport_params *t = &ctx->transport_params; in quic_settings()
397 s->log_printf = quic_printf; in quic_settings()
399 s->log_printf = NULL; in quic_settings()
403 s->initial_ts = pktx->ts; in quic_settings()
404 s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT; in quic_settings()
405 s->max_window = 100 * ctx->max_stream_window; in quic_settings()
406 s->max_stream_window = ctx->max_stream_window; in quic_settings()
408 t->initial_max_data = 10 * ctx->max_stream_window; in quic_settings()
409 t->initial_max_stream_data_bidi_local = ctx->max_stream_window; in quic_settings()
410 t->initial_max_stream_data_bidi_remote = ctx->max_stream_window; in quic_settings()
411 t->initial_max_stream_data_uni = ctx->max_stream_window; in quic_settings()
412 t->initial_max_streams_bidi = QUIC_MAX_STREAMS; in quic_settings()
413 t->initial_max_streams_uni = QUIC_MAX_STREAMS; in quic_settings()
414 t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS); in quic_settings()
415 if(ctx->qlogfd != -1) { in quic_settings()
416 s->qlog_write = qlog_callback; in quic_settings()
442 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_err_set()
443 if(!ctx->last_error.error_code) { in cf_ngtcp2_err_set()
445 ngtcp2_ccerr_set_tls_alert(&ctx->last_error, in cf_ngtcp2_err_set()
446 ngtcp2_conn_get_tls_alert(ctx->qconn), in cf_ngtcp2_err_set()
450 ngtcp2_ccerr_set_liberr(&ctx->last_error, code, NULL, 0); in cf_ngtcp2_err_set()
466 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_h3_err_set()
467 if(!ctx->last_error.error_code) { in cf_ngtcp2_h3_err_set()
468 ngtcp2_ccerr_set_application_error(&ctx->last_error, in cf_ngtcp2_h3_err_set()
481 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_recv_stream_data()
490 nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin); in cb_recv_stream_data()
494 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read_stream(len=%zu) -> %zd", in cb_recv_stream_data()
501 stream_id, stream->reset, stream->closed); in cb_recv_stream_data()
521 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_acked_stream_data_offset()
529 rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen); in cb_acked_stream_data_offset()
542 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_stream_close()
558 rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, app_error_code); in cb_stream_close()
560 CURL_PRIu64 ") -> %d", stream_id, (curl_uint64_t)app_error_code, in cb_stream_close()
575 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_stream_reset()
584 rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id); in cb_stream_reset()
585 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv); in cb_stream_reset()
598 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_stream_stop_sending()
604 rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id); in cb_stream_stop_sending()
617 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_extend_max_local_streams_bidi()
621 ctx->max_bidi_streams = max_streams; in cb_extend_max_local_streams_bidi()
624 ", used %" CURL_PRIu64, (curl_uint64_t)ctx->max_bidi_streams, in cb_extend_max_local_streams_bidi()
625 (curl_uint64_t)ctx->used_bidi_streams); in cb_extend_max_local_streams_bidi()
634 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_extend_max_stream_data()
644 rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id); in cb_extend_max_stream_data()
649 if(s_data && stream && stream->quic_flow_blocked) { in cb_extend_max_stream_data()
652 stream->quic_flow_blocked = FALSE; in cb_extend_max_stream_data()
666 /* cb_rand is only used for non-cryptographic context. If Curl_rand in cb_rand()
680 result = Curl_rand(NULL, cid->data, cidlen); in cb_get_new_connection_id()
683 cid->datalen = cidlen; in cb_get_new_connection_id()
756 * ngtcp2 tells us when it wants to be invoked again. We handle that via
763 struct cf_ngtcp2_ctx *ctx = cf->ctx; in check_and_set_expiry()
775 expiry = ngtcp2_conn_get_expiry(ctx->qconn); in check_and_set_expiry()
777 if(expiry <= pktx->ts) { in check_and_set_expiry()
779 int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts); in check_and_set_expiry()
793 expiry = ngtcp2_conn_get_expiry(ctx->qconn); in check_and_set_expiry()
796 if(expiry > pktx->ts) { in check_and_set_expiry()
797 ngtcp2_duration timeout = expiry - pktx->ts; in check_and_set_expiry()
811 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_adjust_pollset()
814 if(!ctx->qconn) in cf_ngtcp2_adjust_pollset()
817 Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); in cf_ngtcp2_adjust_pollset()
824 c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) || in cf_ngtcp2_adjust_pollset()
825 !ngtcp2_conn_get_max_data_left(ctx->qconn)); in cf_ngtcp2_adjust_pollset()
826 s_exhaust = want_send && stream && stream->id >= 0 && in cf_ngtcp2_adjust_pollset()
827 stream->quic_flow_blocked; in cf_ngtcp2_adjust_pollset()
830 !Curl_bufq_is_empty(&ctx->q.sendbuf); in cf_ngtcp2_adjust_pollset()
832 Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); in cf_ngtcp2_adjust_pollset()
842 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_stream_close()
853 stream->closed = TRUE; in cb_h3_stream_close()
854 stream->error3 = (curl_uint64_t)app_error_code; in cb_h3_stream_close()
855 if(stream->error3 != NGHTTP3_H3_NO_ERROR) { in cb_h3_stream_close()
856 stream->reset = TRUE; in cb_h3_stream_close()
857 stream->send_closed = TRUE; in cb_h3_stream_close()
859 stream->id, stream->error3); in cb_h3_stream_close()
862 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] CLOSED", stream->id); in cb_h3_stream_close()
875 if(!stream->xfer_result) { in h3_xfer_write_resp_hd()
876 stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos); in h3_xfer_write_resp_hd()
877 if(stream->xfer_result) in h3_xfer_write_resp_hd()
879 "bytes of headers", stream->id, stream->xfer_result, blen); in h3_xfer_write_resp_hd()
890 if(!stream->xfer_result) { in h3_xfer_write_resp()
891 stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos); in h3_xfer_write_resp()
893 if(stream->xfer_result) { in h3_xfer_write_resp()
895 "of data", stream->id, stream->xfer_result, blen); in h3_xfer_write_resp()
905 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_recv_data()
918 stream->id, blen); in cb_h3_recv_data()
919 ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen); in cb_h3_recv_data()
920 ngtcp2_conn_extend_max_offset(ctx->qconn, blen); in cb_h3_recv_data()
922 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] DATA len=%zu", stream->id, blen); in cb_h3_recv_data()
931 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_deferred_consume()
937 ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream3_id, consumed); in cb_h3_deferred_consume()
938 ngtcp2_conn_extend_max_offset(ctx->qconn, consumed); in cb_h3_deferred_consume()
946 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_end_headers()
958 h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed); in cb_h3_end_headers()
961 stream_id, stream->status_code); in cb_h3_end_headers()
962 if(stream->status_code / 100 != 1) { in cb_h3_end_headers()
963 stream->resp_hds_complete = TRUE; in cb_h3_end_headers()
975 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_recv_header()
994 result = Curl_http_decode_status(&stream->status_code, in cb_h3_recv_header()
997 return -1; in cb_h3_recv_header()
998 Curl_dyn_reset(&ctx->scratch); in cb_h3_recv_header()
999 result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 ")); in cb_h3_recv_header()
1001 result = Curl_dyn_addn(&ctx->scratch, in cb_h3_recv_header()
1004 result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n")); in cb_h3_recv_header()
1006 h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch), in cb_h3_recv_header()
1007 Curl_dyn_len(&ctx->scratch), FALSE); in cb_h3_recv_header()
1009 stream_id, Curl_dyn_ptr(&ctx->scratch)); in cb_h3_recv_header()
1011 return -1; in cb_h3_recv_header()
1015 /* store as an HTTP1-style header */ in cb_h3_recv_header()
1019 Curl_dyn_reset(&ctx->scratch); in cb_h3_recv_header()
1020 result = Curl_dyn_addn(&ctx->scratch, in cb_h3_recv_header()
1023 result = Curl_dyn_addn(&ctx->scratch, STRCONST(": ")); in cb_h3_recv_header()
1025 result = Curl_dyn_addn(&ctx->scratch, in cb_h3_recv_header()
1028 result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n")); in cb_h3_recv_header()
1030 h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch), in cb_h3_recv_header()
1031 Curl_dyn_len(&ctx->scratch), FALSE); in cb_h3_recv_header()
1041 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_stop_sending()
1046 rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id, in cb_h3_stop_sending()
1059 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_reset_stream()
1066 rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id, in cb_h3_reset_stream()
1068 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv); in cb_h3_reset_stream()
1096 struct cf_ngtcp2_ctx *ctx = cf->ctx; in init_ngh3_conn()
1101 if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) { in init_ngh3_conn()
1105 nghttp3_settings_default(&ctx->h3settings); in init_ngh3_conn()
1107 rc = nghttp3_conn_client_new(&ctx->h3conn, in init_ngh3_conn()
1109 &ctx->h3settings, in init_ngh3_conn()
1117 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &ctrl_stream_id, NULL); in init_ngh3_conn()
1123 rc = nghttp3_conn_bind_control_stream(ctx->h3conn, ctrl_stream_id); in init_ngh3_conn()
1129 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_enc_stream_id, NULL); in init_ngh3_conn()
1135 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_dec_stream_id, NULL); in init_ngh3_conn()
1141 rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id, in init_ngh3_conn()
1159 ssize_t nread = -1; in recv_closed_stream()
1162 if(stream->reset) { in recv_closed_stream()
1164 "HTTP/3 stream %" CURL_PRId64 " reset by server", stream->id); in recv_closed_stream()
1165 *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3; in recv_closed_stream()
1168 else if(!stream->resp_hds_complete) { in recv_closed_stream()
1172 stream->id); in recv_closed_stream()
1187 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_recv()
1189 ssize_t nread = -1; in cf_ngtcp2_recv()
1197 DEBUGASSERT(cf->connected); in cf_ngtcp2_recv()
1199 DEBUGASSERT(ctx->qconn); in cf_ngtcp2_recv()
1200 DEBUGASSERT(ctx->h3conn); in cf_ngtcp2_recv()
1205 if(!stream || ctx->conn_closed) { in cf_ngtcp2_recv()
1212 nread = -1; in cf_ngtcp2_recv()
1216 if(stream->xfer_result) { in cf_ngtcp2_recv()
1217 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id); in cf_ngtcp2_recv()
1219 *err = stream->xfer_result; in cf_ngtcp2_recv()
1220 nread = -1; in cf_ngtcp2_recv()
1223 else if(stream->closed) { in cf_ngtcp2_recv()
1228 nread = -1; in cf_ngtcp2_recv()
1233 nread = -1; in cf_ngtcp2_recv()
1239 nread = -1; in cf_ngtcp2_recv()
1242 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_recv(blen=%zu) -> %zd, %d", in cf_ngtcp2_recv()
1243 stream? stream->id : -1, blen, nread, *err); in cf_ngtcp2_recv()
1253 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_acked_req_body()
1263 * re-transmissions and can free it now. */ in cb_h3_acked_req_body()
1264 if(datalen >= (uint64_t)stream->sendbuf_len_in_flight) in cb_h3_acked_req_body()
1265 skiplen = stream->sendbuf_len_in_flight; in cb_h3_acked_req_body()
1268 Curl_bufq_skip(&stream->sendbuf, skiplen); in cb_h3_acked_req_body()
1269 stream->sendbuf_len_in_flight -= skiplen; in cb_h3_acked_req_body()
1272 if(!stream->sendbuf_len_in_flight) { in cb_h3_acked_req_body()
1288 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cb_h3_read_req_body()
1308 if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) { in cb_h3_read_req_body()
1311 Curl_bufq_peek_at(&stream->sendbuf, in cb_h3_read_req_body()
1312 stream->sendbuf_len_in_flight, in cb_h3_read_req_body()
1315 stream->sendbuf_len_in_flight += vec[nvecs].len; in cb_h3_read_req_body()
1322 if(nwritten > 0 && stream->upload_left != -1) in cb_h3_read_req_body()
1323 stream->upload_left -= nwritten; in cb_h3_read_req_body()
1327 if(stream->upload_left == 0) { in cb_h3_read_req_body()
1329 stream->send_closed = TRUE; in cb_h3_read_req_body()
1333 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> AGAIN", in cb_h3_read_req_body()
1334 stream->id); in cb_h3_read_req_body()
1338 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> " in cb_h3_read_req_body()
1341 stream->id, (int)nvecs, in cb_h3_read_req_body()
1343 nwritten, Curl_bufq_len(&stream->sendbuf), in cb_h3_read_req_body()
1344 stream->upload_left); in cb_h3_read_req_body()
1357 struct cf_ngtcp2_ctx *ctx = cf->ctx; in h3_stream_open()
1365 ssize_t nwritten = -1; in h3_stream_open()
1381 nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); in h3_stream_open()
1384 if(!stream->h1.done) { in h3_stream_open()
1388 DEBUGASSERT(stream->h1.req); in h3_stream_open()
1390 *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); in h3_stream_open()
1392 nwritten = -1; in h3_stream_open()
1396 Curl_h1_req_parse_free(&stream->h1); in h3_stream_open()
1402 nwritten = -1; in h3_stream_open()
1408 nva[i].name = (unsigned char *)e->name; in h3_stream_open()
1409 nva[i].namelen = e->namelen; in h3_stream_open()
1410 nva[i].value = (unsigned char *)e->value; in h3_stream_open()
1411 nva[i].valuelen = e->valuelen; in h3_stream_open()
1415 rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data); in h3_stream_open()
1419 nwritten = -1; in h3_stream_open()
1422 stream->id = (curl_int64_t)sid; in h3_stream_open()
1423 ++ctx->used_bidi_streams; in h3_stream_open()
1425 switch(data->state.httpreq) { in h3_stream_open()
1430 /* known request body size or -1 */ in h3_stream_open()
1431 if(data->state.infilesize != -1) in h3_stream_open()
1432 stream->upload_left = data->state.infilesize; in h3_stream_open()
1435 stream->upload_left = -1; /* unknown */ in h3_stream_open()
1439 stream->upload_left = 0; /* no request body */ in h3_stream_open()
1443 stream->send_closed = (stream->upload_left == 0); in h3_stream_open()
1444 if(!stream->send_closed) { in h3_stream_open()
1449 rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id, in h3_stream_open()
1455 "connection is closing", stream->id); in h3_stream_open()
1458 CURL_TRC_CF(data, cf, "h3sid[%" CURL_PRId64 "] failed to send -> " in h3_stream_open()
1459 "%d (%s)", stream->id, rc, ngtcp2_strerror(rc)); in h3_stream_open()
1463 nwritten = -1; in h3_stream_open()
1469 stream->id, data->state.url); in h3_stream_open()
1471 infof(data, "[HTTP/3] [%" CURL_PRId64 "] [%.*s: %.*s]", stream->id, in h3_stream_open()
1486 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_send()
1494 DEBUGASSERT(cf->connected); in cf_ngtcp2_send()
1495 DEBUGASSERT(ctx->qconn); in cf_ngtcp2_send()
1496 DEBUGASSERT(ctx->h3conn); in cf_ngtcp2_send()
1503 sent = -1; in cf_ngtcp2_send()
1506 if(!stream || stream->id < 0) { in cf_ngtcp2_send()
1507 if(ctx->conn_closed) { in cf_ngtcp2_send()
1510 sent = -1; in cf_ngtcp2_send()
1515 CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err); in cf_ngtcp2_send()
1520 else if(stream->xfer_result) { in cf_ngtcp2_send()
1521 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id); in cf_ngtcp2_send()
1523 *err = stream->xfer_result; in cf_ngtcp2_send()
1524 sent = -1; in cf_ngtcp2_send()
1527 else if(stream->upload_blocked_len) { in cf_ngtcp2_send()
1530 DEBUGASSERT(len >= stream->upload_blocked_len); in cf_ngtcp2_send()
1531 if(len < stream->upload_blocked_len) { in cf_ngtcp2_send()
1536 sent = -1; in cf_ngtcp2_send()
1539 sent = (ssize_t)stream->upload_blocked_len; in cf_ngtcp2_send()
1540 stream->upload_blocked_len = 0; in cf_ngtcp2_send()
1542 else if(stream->closed) { in cf_ngtcp2_send()
1543 if(stream->resp_hds_complete) { in cf_ngtcp2_send()
1550 "on closed stream with response", stream->id); in cf_ngtcp2_send()
1556 "-> stream closed", stream->id, len); in cf_ngtcp2_send()
1558 sent = -1; in cf_ngtcp2_send()
1561 else if(ctx->conn_closed) { in cf_ngtcp2_send()
1564 sent = -1; in cf_ngtcp2_send()
1568 sent = Curl_bufq_write(&stream->sendbuf, buf, len, err); in cf_ngtcp2_send()
1570 "sendbuf(len=%zu) -> %zd, %d", in cf_ngtcp2_send()
1571 stream->id, len, sent, *err); in cf_ngtcp2_send()
1576 (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); in cf_ngtcp2_send()
1582 sent = -1; in cf_ngtcp2_send()
1585 if(stream && sent > 0 && stream->sendbuf_len_in_flight) { in cf_ngtcp2_send()
1589 stream->upload_blocked_len = sent; in cf_ngtcp2_send()
1591 "%zu bytes in flight -> EGAIN", stream->id, len, in cf_ngtcp2_send()
1592 stream->sendbuf_len_in_flight); in cf_ngtcp2_send()
1594 sent = -1; in cf_ngtcp2_send()
1601 sent = -1; in cf_ngtcp2_send()
1603 CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d", in cf_ngtcp2_send()
1604 stream? stream->id : -1, len, sent, *err); in cf_ngtcp2_send()
1612 struct cf_ngtcp2_ctx *ctx = cf->ctx; in qng_verify_peer()
1614 cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ in qng_verify_peer()
1615 cf->conn->httpversion = 30; in qng_verify_peer()
1616 cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX; in qng_verify_peer()
1618 return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); in qng_verify_peer()
1627 struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx; in recv_pkt()
1632 ++pktx->pkt_count; in recv_pkt()
1633 ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr, in recv_pkt()
1634 ctx->q.local_addrlen); in recv_pkt()
1639 rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts); in recv_pkt()
1641 CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)", in recv_pkt()
1643 cf_ngtcp2_err_set(pktx->cf, pktx->data, rv); in recv_pkt()
1659 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_progress_ingress()
1672 result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); in cf_progress_ingress()
1679 pktx->pkt_count = 0; in cf_progress_ingress()
1680 result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk, in cf_progress_ingress()
1682 if(result || !pktx->pkt_count) /* error or got nothing */ in cf_progress_ingress()
1689 * Read a network packet to send from ngtcp2 into `buf`.
1690 * Return number of bytes written or -1 with *err set.
1697 struct cf_ngtcp2_ctx *ctx = x->cf->ctx; in read_pkt_to_send()
1706 stream_id = -1; in read_pkt_to_send()
1709 /* ngtcp2 may want to put several frames from different streams into in read_pkt_to_send()
1713 * When ngtcp2 is happy (because it has no other frame that would fit in read_pkt_to_send()
1720 if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) { in read_pkt_to_send()
1721 veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec, in read_pkt_to_send()
1724 failf(x->data, "nghttp3_conn_writev_stream returned error: %s", in read_pkt_to_send()
1726 cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt); in read_pkt_to_send()
1728 return -1; in read_pkt_to_send()
1734 n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path, in read_pkt_to_send()
1737 (const ngtcp2_vec *)vec, veccnt, x->ts); in read_pkt_to_send()
1741 nwritten = -1; in read_pkt_to_send()
1747 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data); in read_pkt_to_send()
1748 DEBUGASSERT(ndatalen == -1); in read_pkt_to_send()
1749 nghttp3_conn_block_stream(ctx->h3conn, stream_id); in read_pkt_to_send()
1750 CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRId64 "] block quic flow", in read_pkt_to_send()
1754 stream->quic_flow_blocked = TRUE; in read_pkt_to_send()
1759 DEBUGASSERT(ndatalen == -1); in read_pkt_to_send()
1760 nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id); in read_pkt_to_send()
1764 /* ngtcp2 wants to send more. update the flow of the stream whose data in read_pkt_to_send()
1770 DEBUGASSERT(ndatalen == -1); in read_pkt_to_send()
1771 failf(x->data, "ngtcp2_conn_writev_stream returned error: %s", in read_pkt_to_send()
1773 cf_ngtcp2_err_set(x->cf, x->data, (int)n); in read_pkt_to_send()
1775 nwritten = -1; in read_pkt_to_send()
1782 int rv = nghttp3_conn_add_write_offset(ctx->h3conn, stream_id, ndatalen); in read_pkt_to_send()
1784 failf(x->data, "nghttp3_conn_add_write_offset returned error: %s\n", in read_pkt_to_send()
1804 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_progress_egress()
1818 ngtcp2_path_storage_zero(&pktx->ps); in cf_progress_egress()
1821 curlcode = vquic_flush(cf, data, &ctx->q); in cf_progress_egress()
1832 * To detect if this minimum payload can be increased, ngtcp2 sends in cf_progress_egress()
1841 max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn); in cf_progress_egress()
1843 ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn); in cf_progress_egress()
1846 ctx->q.sendbuf.chunk_size / max_payload_size); in cf_progress_egress()
1850 nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, in cf_progress_egress()
1856 curlcode = vquic_send(cf, data, &ctx->q, gsolen); in cf_progress_egress()
1878 curlcode = vquic_send_tail_split(cf, data, &ctx->q, in cf_progress_egress()
1895 curlcode = vquic_send(cf, data, &ctx->q, gsolen); in cf_progress_egress()
1928 /* TODO: there seems right now no API in ngtcp2 to shrink/enlarge in h3_data_pause()
1941 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_data_event()
1962 if(stream && !stream->send_closed) { in cf_ngtcp2_data_event()
1963 stream->send_closed = TRUE; in cf_ngtcp2_data_event()
1964 stream->upload_left = Curl_bufq_len(&stream->sendbuf); in cf_ngtcp2_data_event()
1965 (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); in cf_ngtcp2_data_event()
1972 if(stream && !stream->closed) { in cf_ngtcp2_data_event()
1975 CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result); in cf_ngtcp2_data_event()
1988 struct cf_call_data save = ctx->call_data; in cf_ngtcp2_ctx_clear()
1990 if(ctx->qlogfd != -1) { in cf_ngtcp2_ctx_clear()
1991 close(ctx->qlogfd); in cf_ngtcp2_ctx_clear()
1993 Curl_vquic_tls_cleanup(&ctx->tls); in cf_ngtcp2_ctx_clear()
1994 vquic_ctx_free(&ctx->q); in cf_ngtcp2_ctx_clear()
1995 if(ctx->h3conn) in cf_ngtcp2_ctx_clear()
1996 nghttp3_conn_del(ctx->h3conn); in cf_ngtcp2_ctx_clear()
1997 if(ctx->qconn) in cf_ngtcp2_ctx_clear()
1998 ngtcp2_conn_del(ctx->qconn); in cf_ngtcp2_ctx_clear()
1999 Curl_bufcp_free(&ctx->stream_bufcp); in cf_ngtcp2_ctx_clear()
2000 Curl_dyn_free(&ctx->scratch); in cf_ngtcp2_ctx_clear()
2001 Curl_hash_clean(&ctx->streams); in cf_ngtcp2_ctx_clear()
2002 Curl_hash_destroy(&ctx->streams); in cf_ngtcp2_ctx_clear()
2003 Curl_ssl_peer_cleanup(&ctx->peer); in cf_ngtcp2_ctx_clear()
2006 ctx->qlogfd = -1; in cf_ngtcp2_ctx_clear()
2007 ctx->call_data = save; in cf_ngtcp2_ctx_clear()
2013 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_conn_close()
2014 if(ctx && ctx->qconn && !ctx->conn_closed) { in cf_ngtcp2_conn_close()
2019 ctx->conn_closed = TRUE; in cf_ngtcp2_conn_close()
2021 rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */ in cf_ngtcp2_conn_close()
2024 &ctx->last_error, pktx.ts); in cf_ngtcp2_conn_close()
2026 CURL_PRIu64 ") -> %d", ctx->last_error.type, in cf_ngtcp2_conn_close()
2027 (curl_uint64_t)ctx->last_error.error_code, (int)rc); in cf_ngtcp2_conn_close()
2029 while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) && in cf_ngtcp2_conn_close()
2037 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_close()
2041 if(ctx && ctx->qconn) { in cf_ngtcp2_close()
2046 cf->connected = FALSE; in cf_ngtcp2_close()
2052 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_destroy()
2061 cf->ctx = NULL; in cf_ngtcp2_destroy()
2068 * or non-zero if the session has been put into the session cache.
2078 cf = cref? cref->user_data : NULL; in quic_ossl_new_session_cb()
2079 ctx = cf? cf->ctx : NULL; in quic_ossl_new_session_cb()
2082 Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid); in quic_ossl_new_session_cb()
2097 if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx) in tls_ctx_setup()
2103 if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) { in tls_ctx_setup()
2112 SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx, in tls_ctx_setup()
2115 SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb); in tls_ctx_setup()
2118 if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) { in tls_ctx_setup()
2123 if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) { in tls_ctx_setup()
2138 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_connect_start()
2145 ctx->version = NGTCP2_PROTO_VER_MAX; in cf_connect_start()
2146 ctx->max_stream_window = H3_STREAM_WINDOW_SIZE; in cf_connect_start()
2147 ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS; in cf_connect_start()
2148 Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, in cf_connect_start()
2150 Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); in cf_connect_start()
2151 Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free); in cf_connect_start()
2153 result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC); in cf_connect_start()
2157 #define H3_ALPN "\x2h3\x5h3-29" in cf_connect_start()
2158 result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, in cf_connect_start()
2159 H3_ALPN, sizeof(H3_ALPN) - 1, in cf_connect_start()
2160 tls_ctx_setup, &ctx->tls, &ctx->conn_ref); in cf_connect_start()
2165 SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0); in cf_connect_start()
2168 ctx->dcid.datalen = NGTCP2_MAX_CIDLEN; in cf_connect_start()
2169 result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN); in cf_connect_start()
2173 ctx->scid.datalen = NGTCP2_MAX_CIDLEN; in cf_connect_start()
2174 result = Curl_rand(data, ctx->scid.data, NGTCP2_MAX_CIDLEN); in cf_connect_start()
2178 (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd); in cf_connect_start()
2179 ctx->qlogfd = qfd; /* -1 if failure above */ in cf_connect_start()
2182 result = vquic_ctx_init(&ctx->q); in cf_connect_start()
2186 Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL); in cf_connect_start()
2189 ctx->q.local_addrlen = sizeof(ctx->q.local_addr); in cf_connect_start()
2190 rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, in cf_connect_start()
2191 &ctx->q.local_addrlen); in cf_connect_start()
2192 if(rv == -1) in cf_connect_start()
2195 ngtcp2_addr_init(&ctx->connected_path.local, in cf_connect_start()
2196 (struct sockaddr *)&ctx->q.local_addr, in cf_connect_start()
2197 ctx->q.local_addrlen); in cf_connect_start()
2198 ngtcp2_addr_init(&ctx->connected_path.remote, in cf_connect_start()
2199 &sockaddr->sa_addr, sockaddr->addrlen); in cf_connect_start()
2201 rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid, in cf_connect_start()
2202 &ctx->connected_path, in cf_connect_start()
2204 &ctx->settings, &ctx->transport_params, in cf_connect_start()
2210 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl); in cf_connect_start()
2212 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session); in cf_connect_start()
2214 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl); in cf_connect_start()
2217 ngtcp2_ccerr_default(&ctx->last_error); in cf_connect_start()
2219 ctx->conn_ref.get_conn = get_conn; in cf_connect_start()
2220 ctx->conn_ref.user_data = cf; in cf_connect_start()
2229 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_connect()
2235 if(cf->connected) { in cf_ngtcp2_connect()
2241 if(!cf->next->connected) { in cf_ngtcp2_connect()
2242 result = Curl_conn_cf_connect(cf->next, data, blocking, done); in cf_ngtcp2_connect()
2253 if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) { in cf_ngtcp2_connect()
2259 if(!ctx->qconn) { in cf_ngtcp2_connect()
2260 ctx->started_at = now; in cf_ngtcp2_connect()
2277 if(ngtcp2_conn_get_handshake_completed(ctx->qconn)) { in cf_ngtcp2_connect()
2278 ctx->handshake_at = now; in cf_ngtcp2_connect()
2280 (int)Curl_timediff(now, ctx->started_at)); in cf_ngtcp2_connect()
2284 cf->connected = TRUE; in cf_ngtcp2_connect()
2285 cf->conn->alpn = CURL_HTTP_VERSION_3; in cf_ngtcp2_connect()
2287 connkeep(cf->conn, "HTTP/3 default"); in cf_ngtcp2_connect()
2292 if(result == CURLE_RECV_ERROR && ctx->qconn && in cf_ngtcp2_connect()
2293 ngtcp2_conn_in_draining_period(ctx->qconn)) { in cf_ngtcp2_connect()
2305 Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); in cf_ngtcp2_connect()
2310 if(!result && ctx->qconn) { in cf_ngtcp2_connect()
2314 CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done); in cf_ngtcp2_connect()
2323 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_query()
2334 if(!ctx->qconn || ctx->conn_closed) { in cf_ngtcp2_query()
2337 else if(ctx->max_bidi_streams) { in cf_ngtcp2_query()
2339 uint64_t max_streams = CONN_INUSE(cf->conn); in cf_ngtcp2_query()
2340 if(ctx->max_bidi_streams > ctx->used_bidi_streams) in cf_ngtcp2_query()
2341 avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams; in cf_ngtcp2_query()
2346 *pres1 = Curl_multi_max_concurrent_streams(data->multi); in cf_ngtcp2_query()
2348 "MAX_CONCURRENT -> %d (%zu in use)", in cf_ngtcp2_query()
2349 cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn)); in cf_ngtcp2_query()
2354 if(ctx->q.got_first_byte) { in cf_ngtcp2_query()
2355 timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at); in cf_ngtcp2_query()
2359 *pres1 = -1; in cf_ngtcp2_query()
2363 if(ctx->q.got_first_byte) in cf_ngtcp2_query()
2364 *when = ctx->q.first_byte_at; in cf_ngtcp2_query()
2369 if(cf->connected) in cf_ngtcp2_query()
2370 *when = ctx->handshake_at; in cf_ngtcp2_query()
2376 return cf->next? in cf_ngtcp2_query()
2377 cf->next->cft->query(cf->next, data, query, pres1, pres2) : in cf_ngtcp2_query()
2385 struct cf_ngtcp2_ctx *ctx = cf->ctx; in cf_ngtcp2_conn_is_alive()
2392 if(!ctx->qconn || ctx->conn_closed) in cf_ngtcp2_conn_is_alive()
2400 rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); in cf_ngtcp2_conn_is_alive()
2403 uint64_t idle_ms = ctx->max_idle_ms; in cf_ngtcp2_conn_is_alive()
2405 if(rp->max_idle_timeout && in cf_ngtcp2_conn_is_alive()
2406 (rp->max_idle_timeout / NGTCP2_MILLISECONDS) < idle_ms) in cf_ngtcp2_conn_is_alive()
2407 idle_ms = (rp->max_idle_timeout / NGTCP2_MILLISECONDS); in cf_ngtcp2_conn_is_alive()
2408 idletime = Curl_timediff(Curl_now(), ctx->q.last_io); in cf_ngtcp2_conn_is_alive()
2413 if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) in cf_ngtcp2_conn_is_alive()
2424 CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result); in cf_ngtcp2_conn_is_alive()
2466 ctx->qlogfd = -1; in Curl_cf_ngtcp2_create()
2477 cf->conn = conn; in Curl_cf_ngtcp2_create()
2478 udp_cf->conn = cf->conn; in Curl_cf_ngtcp2_create()
2479 udp_cf->sockindex = cf->sockindex; in Curl_cf_ngtcp2_create()
2480 cf->next = udp_cf; in Curl_cf_ngtcp2_create()
2497 struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL; in Curl_conn_is_ngtcp2()
2500 for(; cf; cf = cf->next) { in Curl_conn_is_ngtcp2()
2501 if(cf->cft == &Curl_cft_http3) in Curl_conn_is_ngtcp2()
2503 if(cf->cft->flags & CF_TYPE_IP_CONNECT) in Curl_conn_is_ngtcp2()