curl_ngtcp2.c (88489B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 #include "../curl_setup.h" 26 27 #if defined(USE_NGTCP2) && defined(USE_NGHTTP3) 28 #include <ngtcp2/ngtcp2.h> 29 #include <nghttp3/nghttp3.h> 30 31 #ifdef USE_OPENSSL 32 #include <openssl/err.h> 33 #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) 34 #include <ngtcp2/ngtcp2_crypto_boringssl.h> 35 #elif defined(OPENSSL_QUIC_API2) 36 #include <ngtcp2/ngtcp2_crypto_ossl.h> 37 #else 38 #include <ngtcp2/ngtcp2_crypto_quictls.h> 39 #endif 40 #include "../vtls/openssl.h" 41 #elif defined(USE_GNUTLS) 42 #include <ngtcp2/ngtcp2_crypto_gnutls.h> 43 #include "../vtls/gtls.h" 44 #elif defined(USE_WOLFSSL) 45 #include <ngtcp2/ngtcp2_crypto_wolfssl.h> 46 #include "../vtls/wolfssl.h" 47 #endif 48 49 #include "../urldata.h" 50 #include "../url.h" 51 #include "../uint-hash.h" 52 #include "../sendf.h" 53 #include "../strdup.h" 54 #include "../rand.h" 55 #include "../multiif.h" 56 #include "../cfilters.h" 57 #include "../cf-socket.h" 58 #include "../connect.h" 59 #include "../progress.h" 60 #include "../strerror.h" 61 #include "../curlx/dynbuf.h" 62 #include "../http1.h" 63 #include "../select.h" 64 #include "../curlx/inet_pton.h" 65 #include "../transfer.h" 66 #include "vquic.h" 67 #include "vquic_int.h" 68 #include "vquic-tls.h" 69 #include "../vtls/keylog.h" 70 #include "../vtls/vtls.h" 71 #include "../vtls/vtls_scache.h" 72 #include "curl_ngtcp2.h" 73 74 #include "../curlx/warnless.h" 75 76 /* The last 3 #include files should be in this order */ 77 #include "../curl_printf.h" 78 #include "../curl_memory.h" 79 #include "../memdebug.h" 80 81 82 #define QUIC_MAX_STREAMS (256*1024) 83 #define QUIC_MAX_DATA (1*1024*1024) 84 #define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS) 85 86 /* A stream window is the maximum amount we need to buffer for 87 * each active transfer. We use HTTP/3 flow control and only ACK 88 * when we take things out of the buffer. 89 * Chunk size is large enough to take a full DATA frame */ 90 #define H3_STREAM_WINDOW_SIZE (128 * 1024) 91 #define H3_STREAM_CHUNK_SIZE (16 * 1024) 92 #if H3_STREAM_CHUNK_SIZE < NGTCP2_MAX_UDP_PAYLOAD_SIZE 93 #error H3_STREAM_CHUNK_SIZE smaller than NGTCP2_MAX_UDP_PAYLOAD_SIZE 94 #endif 95 96 /* The pool keeps spares around and half of a full stream windows 97 * seems good. More does not seem to improve performance. 98 * The benefit of the pool is that stream buffer to not keep 99 * spares. Memory consumption goes down when streams run empty, 100 * have a large upload done, etc. */ 101 #define H3_STREAM_POOL_SPARES \ 102 (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2 103 /* Receive and Send max number of chunks just follows from the 104 * chunk size and window size */ 105 #define H3_STREAM_RECV_CHUNKS \ 106 (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) 107 #define H3_STREAM_SEND_CHUNKS \ 108 (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) 109 110 111 /* 112 * Store ngtcp2 version info in this buffer. 113 */ 114 void Curl_ngtcp2_ver(char *p, size_t len) 115 { 116 const ngtcp2_info *ng2 = ngtcp2_version(0); 117 const nghttp3_info *ht3 = nghttp3_version(0); 118 (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s", 119 ng2->version_str, ht3->version_str); 120 } 121 122 struct cf_ngtcp2_ctx { 123 struct cf_quic_ctx q; 124 struct ssl_peer peer; 125 struct curl_tls_ctx tls; 126 #ifdef OPENSSL_QUIC_API2 127 ngtcp2_crypto_ossl_ctx *ossl_ctx; 128 #endif 129 ngtcp2_path connected_path; 130 ngtcp2_conn *qconn; 131 ngtcp2_cid dcid; 132 ngtcp2_cid scid; 133 uint32_t version; 134 ngtcp2_settings settings; 135 ngtcp2_transport_params transport_params; 136 ngtcp2_ccerr last_error; 137 ngtcp2_crypto_conn_ref conn_ref; 138 struct cf_call_data call_data; 139 nghttp3_conn *h3conn; 140 nghttp3_settings h3settings; 141 struct curltime started_at; /* time the current attempt started */ 142 struct curltime handshake_at; /* time connect handshake finished */ 143 struct bufc_pool stream_bufcp; /* chunk pool for streams */ 144 struct dynbuf scratch; /* temp buffer for header construction */ 145 struct uint_hash streams; /* hash `data->mid` to `h3_stream_ctx` */ 146 size_t max_stream_window; /* max flow window for one stream */ 147 uint64_t used_bidi_streams; /* bidi streams we have opened */ 148 uint64_t max_bidi_streams; /* max bidi streams we can open */ 149 size_t earlydata_max; /* max amount of early data supported by 150 server on session reuse */ 151 size_t earlydata_skip; /* sending bytes to skip when earlydata 152 * is accepted by peer */ 153 CURLcode tls_vrfy_result; /* result of TLS peer verification */ 154 int qlogfd; 155 BIT(initialized); 156 BIT(tls_handshake_complete); /* TLS handshake is done */ 157 BIT(use_earlydata); /* Using 0RTT data */ 158 BIT(earlydata_accepted); /* 0RTT was acceptd by server */ 159 BIT(shutdown_started); /* queued shutdown packets */ 160 }; 161 162 /* How to access `call_data` from a cf_ngtcp2 filter */ 163 #undef CF_CTX_CALL_DATA 164 #define CF_CTX_CALL_DATA(cf) \ 165 ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data 166 167 static void h3_stream_hash_free(unsigned int id, void *stream); 168 169 static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx) 170 { 171 DEBUGASSERT(!ctx->initialized); 172 ctx->qlogfd = -1; 173 ctx->version = NGTCP2_PROTO_VER_MAX; 174 ctx->max_stream_window = H3_STREAM_WINDOW_SIZE; 175 Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE, 176 H3_STREAM_POOL_SPARES); 177 curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER); 178 Curl_uint_hash_init(&ctx->streams, 63, h3_stream_hash_free); 179 ctx->initialized = TRUE; 180 } 181 182 static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx) 183 { 184 if(ctx && ctx->initialized) { 185 Curl_vquic_tls_cleanup(&ctx->tls); 186 vquic_ctx_free(&ctx->q); 187 Curl_bufcp_free(&ctx->stream_bufcp); 188 curlx_dyn_free(&ctx->scratch); 189 Curl_uint_hash_destroy(&ctx->streams); 190 Curl_ssl_peer_cleanup(&ctx->peer); 191 } 192 free(ctx); 193 } 194 195 static void cf_ngtcp2_setup_keep_alive(struct Curl_cfilter *cf, 196 struct Curl_easy *data) 197 { 198 struct cf_ngtcp2_ctx *ctx = cf->ctx; 199 const ngtcp2_transport_params *rp; 200 /* Peer should have sent us its transport parameters. If it 201 * announces a positive `max_idle_timeout` it will close the 202 * connection when it does not hear from us for that time. 203 * 204 * Some servers use this as a keep-alive timer at a rather low 205 * value. We are doing HTTP/3 here and waiting for the response 206 * to a request may take a considerable amount of time. We need 207 * to prevent the peer's QUIC stack from closing in this case. 208 */ 209 if(!ctx->qconn) 210 return; 211 212 rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); 213 if(!rp || !rp->max_idle_timeout) { 214 ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX); 215 CURL_TRC_CF(data, cf, "no peer idle timeout, unset keep-alive"); 216 } 217 else if(!Curl_uint_hash_count(&ctx->streams)) { 218 ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX); 219 CURL_TRC_CF(data, cf, "no active streams, unset keep-alive"); 220 } 221 else { 222 ngtcp2_duration keep_ns; 223 keep_ns = (rp->max_idle_timeout > 1) ? (rp->max_idle_timeout / 2) : 1; 224 ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, keep_ns); 225 CURL_TRC_CF(data, cf, "peer idle timeout is %" FMT_PRIu64 "ms, " 226 "set keep-alive to %" FMT_PRIu64 " ms.", 227 (curl_uint64_t)(rp->max_idle_timeout / NGTCP2_MILLISECONDS), 228 (curl_uint64_t)(keep_ns / NGTCP2_MILLISECONDS)); 229 } 230 } 231 232 233 struct pkt_io_ctx; 234 static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, 235 struct Curl_easy *data, 236 struct pkt_io_ctx *pktx); 237 static CURLcode cf_progress_egress(struct Curl_cfilter *cf, 238 struct Curl_easy *data, 239 struct pkt_io_ctx *pktx); 240 241 /** 242 * All about the H3 internals of a stream 243 */ 244 struct h3_stream_ctx { 245 curl_int64_t id; /* HTTP/3 protocol identifier */ 246 struct bufq sendbuf; /* h3 request body */ 247 struct h1_req_parser h1; /* h1 request parsing */ 248 size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */ 249 curl_uint64_t error3; /* HTTP/3 stream error code */ 250 curl_off_t upload_left; /* number of request bytes left to upload */ 251 int status_code; /* HTTP status code */ 252 CURLcode xfer_result; /* result from xfer_resp_write(_hd) */ 253 BIT(resp_hds_complete); /* we have a complete, final response */ 254 BIT(closed); /* TRUE on stream close */ 255 BIT(reset); /* TRUE on stream reset */ 256 BIT(send_closed); /* stream is local closed */ 257 BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */ 258 }; 259 260 static void h3_stream_ctx_free(struct h3_stream_ctx *stream) 261 { 262 Curl_bufq_free(&stream->sendbuf); 263 Curl_h1_req_parse_free(&stream->h1); 264 free(stream); 265 } 266 267 static void h3_stream_hash_free(unsigned int id, void *stream) 268 { 269 (void)id; 270 DEBUGASSERT(stream); 271 h3_stream_ctx_free((struct h3_stream_ctx *)stream); 272 } 273 274 static CURLcode h3_data_setup(struct Curl_cfilter *cf, 275 struct Curl_easy *data) 276 { 277 struct cf_ngtcp2_ctx *ctx = cf->ctx; 278 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 279 280 if(!data) 281 return CURLE_FAILED_INIT; 282 283 if(stream) 284 return CURLE_OK; 285 286 stream = calloc(1, sizeof(*stream)); 287 if(!stream) 288 return CURLE_OUT_OF_MEMORY; 289 290 stream->id = -1; 291 /* on send, we control how much we put into the buffer */ 292 Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp, 293 H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE); 294 stream->sendbuf_len_in_flight = 0; 295 Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); 296 297 if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) { 298 h3_stream_ctx_free(stream); 299 return CURLE_OUT_OF_MEMORY; 300 } 301 302 if(Curl_uint_hash_count(&ctx->streams) == 1) 303 cf_ngtcp2_setup_keep_alive(cf, data); 304 305 return CURLE_OK; 306 } 307 308 static void cf_ngtcp2_stream_close(struct Curl_cfilter *cf, 309 struct Curl_easy *data, 310 struct h3_stream_ctx *stream) 311 { 312 struct cf_ngtcp2_ctx *ctx = cf->ctx; 313 DEBUGASSERT(data); 314 DEBUGASSERT(stream); 315 if(!stream->closed && ctx->qconn && ctx->h3conn) { 316 CURLcode result; 317 318 nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL); 319 ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL); 320 stream->closed = TRUE; 321 (void)ngtcp2_conn_shutdown_stream(ctx->qconn, 0, stream->id, 322 NGHTTP3_H3_REQUEST_CANCELLED); 323 result = cf_progress_egress(cf, data, NULL); 324 if(result) 325 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cancel stream -> %d", 326 stream->id, result); 327 } 328 } 329 330 static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) 331 { 332 struct cf_ngtcp2_ctx *ctx = cf->ctx; 333 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 334 (void)cf; 335 if(stream) { 336 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] easy handle is done", 337 stream->id); 338 cf_ngtcp2_stream_close(cf, data, stream); 339 Curl_uint_hash_remove(&ctx->streams, data->mid); 340 if(!Curl_uint_hash_count(&ctx->streams)) 341 cf_ngtcp2_setup_keep_alive(cf, data); 342 } 343 } 344 345 /* ngtcp2 default congestion controller does not perform pacing. Limit 346 the maximum packet burst to MAX_PKT_BURST packets. */ 347 #define MAX_PKT_BURST 10 348 349 struct pkt_io_ctx { 350 struct Curl_cfilter *cf; 351 struct Curl_easy *data; 352 ngtcp2_tstamp ts; 353 ngtcp2_path_storage ps; 354 }; 355 356 static void pktx_update_time(struct pkt_io_ctx *pktx, 357 struct Curl_cfilter *cf) 358 { 359 struct cf_ngtcp2_ctx *ctx = cf->ctx; 360 361 vquic_ctx_update_time(&ctx->q); 362 pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS + 363 (ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS; 364 } 365 366 static void pktx_init(struct pkt_io_ctx *pktx, 367 struct Curl_cfilter *cf, 368 struct Curl_easy *data) 369 { 370 pktx->cf = cf; 371 pktx->data = data; 372 ngtcp2_path_storage_zero(&pktx->ps); 373 pktx_update_time(pktx, cf); 374 } 375 376 static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, 377 uint64_t datalen, void *user_data, 378 void *stream_user_data); 379 380 static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) 381 { 382 struct Curl_cfilter *cf = conn_ref->user_data; 383 struct cf_ngtcp2_ctx *ctx = cf->ctx; 384 return ctx->qconn; 385 } 386 387 #ifdef DEBUG_NGTCP2 388 static void quic_printf(void *user_data, const char *fmt, ...) 389 { 390 struct Curl_cfilter *cf = user_data; 391 struct cf_ngtcp2_ctx *ctx = cf->ctx; 392 393 (void)ctx; /* need an easy handle to infof() message */ 394 va_list ap; 395 va_start(ap, fmt); 396 vfprintf(stderr, fmt, ap); 397 va_end(ap); 398 fprintf(stderr, "\n"); 399 } 400 #endif 401 402 static void qlog_callback(void *user_data, uint32_t flags, 403 const void *data, size_t datalen) 404 { 405 struct Curl_cfilter *cf = user_data; 406 struct cf_ngtcp2_ctx *ctx = cf->ctx; 407 (void)flags; 408 if(ctx->qlogfd != -1) { 409 ssize_t rc = write(ctx->qlogfd, data, datalen); 410 if(rc == -1) { 411 /* on write error, stop further write attempts */ 412 close(ctx->qlogfd); 413 ctx->qlogfd = -1; 414 } 415 } 416 417 } 418 419 static void quic_settings(struct cf_ngtcp2_ctx *ctx, 420 struct Curl_easy *data, 421 struct pkt_io_ctx *pktx) 422 { 423 ngtcp2_settings *s = &ctx->settings; 424 ngtcp2_transport_params *t = &ctx->transport_params; 425 426 ngtcp2_settings_default(s); 427 ngtcp2_transport_params_default(t); 428 #ifdef DEBUG_NGTCP2 429 s->log_printf = quic_printf; 430 #else 431 s->log_printf = NULL; 432 #endif 433 434 (void)data; 435 s->initial_ts = pktx->ts; 436 s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT; 437 s->max_window = 100 * ctx->max_stream_window; 438 s->max_stream_window = 10 * ctx->max_stream_window; 439 440 t->initial_max_data = 10 * ctx->max_stream_window; 441 t->initial_max_stream_data_bidi_local = ctx->max_stream_window; 442 t->initial_max_stream_data_bidi_remote = ctx->max_stream_window; 443 t->initial_max_stream_data_uni = ctx->max_stream_window; 444 t->initial_max_streams_bidi = QUIC_MAX_STREAMS; 445 t->initial_max_streams_uni = QUIC_MAX_STREAMS; 446 t->max_idle_timeout = 0; /* no idle timeout from our side */ 447 if(ctx->qlogfd != -1) { 448 s->qlog_write = qlog_callback; 449 } 450 } 451 452 static CURLcode init_ngh3_conn(struct Curl_cfilter *cf, 453 struct Curl_easy *data); 454 455 static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) 456 { 457 struct Curl_cfilter *cf = user_data; 458 struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL; 459 struct Curl_easy *data; 460 461 (void)tconn; 462 DEBUGASSERT(ctx); 463 data = CF_DATA_CURRENT(cf); 464 DEBUGASSERT(data); 465 if(!ctx || !data) 466 return NGHTTP3_ERR_CALLBACK_FAILURE; 467 468 ctx->handshake_at = curlx_now(); 469 ctx->tls_handshake_complete = TRUE; 470 cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ 471 Curl_vquic_report_handshake(&ctx->tls, cf, data); 472 473 ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf, 474 data, &ctx->peer); 475 CURL_TRC_CF(data, cf, "handshake complete after %dms", 476 (int)curlx_timediff(ctx->handshake_at, ctx->started_at)); 477 /* In case of earlydata, where we simulate being connected, update 478 * the handshake time when we really did connect */ 479 if(ctx->use_earlydata) 480 Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); 481 if(ctx->use_earlydata) { 482 #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA) 483 ctx->earlydata_accepted = 484 (SSL_get_early_data_status(ctx->tls.ossl.ssl) != 485 SSL_EARLY_DATA_REJECTED); 486 #endif 487 #ifdef USE_GNUTLS 488 int flags = gnutls_session_get_flags(ctx->tls.gtls.session); 489 ctx->earlydata_accepted = !!(flags & GNUTLS_SFLAGS_EARLY_DATA); 490 #endif 491 #ifdef USE_WOLFSSL 492 #ifdef WOLFSSL_EARLY_DATA 493 ctx->earlydata_accepted = 494 (wolfSSL_get_early_data_status(ctx->tls.wssl.ssl) != 495 WOLFSSL_EARLY_DATA_REJECTED); 496 #else 497 DEBUGASSERT(0); /* should not come here if ED is disabled. */ 498 ctx->earlydata_accepted = FALSE; 499 #endif /* WOLFSSL_EARLY_DATA */ 500 #endif 501 CURL_TRC_CF(data, cf, "server did%s accept %zu bytes of early data", 502 ctx->earlydata_accepted ? "" : " not", ctx->earlydata_skip); 503 Curl_pgrsEarlyData(data, ctx->earlydata_accepted ? 504 (curl_off_t)ctx->earlydata_skip : 505 -(curl_off_t)ctx->earlydata_skip); 506 } 507 return 0; 508 } 509 510 static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf, 511 struct Curl_easy *data); 512 513 static bool cf_ngtcp2_err_is_fatal(int code) 514 { 515 return (NGTCP2_ERR_FATAL >= code) || 516 (NGTCP2_ERR_DROP_CONN == code) || 517 (NGTCP2_ERR_IDLE_CLOSE == code); 518 } 519 520 static void cf_ngtcp2_err_set(struct Curl_cfilter *cf, 521 struct Curl_easy *data, int code) 522 { 523 struct cf_ngtcp2_ctx *ctx = cf->ctx; 524 if(!ctx->last_error.error_code) { 525 if(NGTCP2_ERR_CRYPTO == code) { 526 ngtcp2_ccerr_set_tls_alert(&ctx->last_error, 527 ngtcp2_conn_get_tls_alert(ctx->qconn), 528 NULL, 0); 529 } 530 else { 531 ngtcp2_ccerr_set_liberr(&ctx->last_error, code, NULL, 0); 532 } 533 } 534 if(cf_ngtcp2_err_is_fatal(code)) 535 cf_ngtcp2_conn_close(cf, data); 536 } 537 538 static bool cf_ngtcp2_h3_err_is_fatal(int code) 539 { 540 return (NGHTTP3_ERR_FATAL >= code) || 541 (NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM == code); 542 } 543 544 static void cf_ngtcp2_h3_err_set(struct Curl_cfilter *cf, 545 struct Curl_easy *data, int code) 546 { 547 struct cf_ngtcp2_ctx *ctx = cf->ctx; 548 if(!ctx->last_error.error_code) { 549 ngtcp2_ccerr_set_application_error(&ctx->last_error, 550 nghttp3_err_infer_quic_app_error_code(code), NULL, 0); 551 } 552 if(cf_ngtcp2_h3_err_is_fatal(code)) 553 cf_ngtcp2_conn_close(cf, data); 554 } 555 556 static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags, 557 int64_t sid, uint64_t offset, 558 const uint8_t *buf, size_t buflen, 559 void *user_data, void *stream_user_data) 560 { 561 struct Curl_cfilter *cf = user_data; 562 struct cf_ngtcp2_ctx *ctx = cf->ctx; 563 curl_int64_t stream_id = (curl_int64_t)sid; 564 nghttp3_ssize nconsumed; 565 int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0; 566 struct Curl_easy *data = stream_user_data; 567 (void)offset; 568 (void)data; 569 570 nconsumed = 571 nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin); 572 if(!data) 573 data = CF_DATA_CURRENT(cf); 574 if(data) 575 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read_stream(len=%zu) -> %zd", 576 stream_id, buflen, nconsumed); 577 if(nconsumed < 0) { 578 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 579 if(data && stream) { 580 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] error on known stream, " 581 "reset=%d, closed=%d", 582 stream_id, stream->reset, stream->closed); 583 } 584 return NGTCP2_ERR_CALLBACK_FAILURE; 585 } 586 587 /* number of bytes inside buflen which consists of framing overhead 588 * including QPACK HEADERS. In other words, it does not consume payload of 589 * DATA frame. */ 590 ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, (uint64_t)nconsumed); 591 ngtcp2_conn_extend_max_offset(tconn, (uint64_t)nconsumed); 592 593 return 0; 594 } 595 596 static int 597 cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id, 598 uint64_t offset, uint64_t datalen, void *user_data, 599 void *stream_user_data) 600 { 601 struct Curl_cfilter *cf = user_data; 602 struct cf_ngtcp2_ctx *ctx = cf->ctx; 603 int rv; 604 (void)stream_id; 605 (void)tconn; 606 (void)offset; 607 (void)datalen; 608 (void)stream_user_data; 609 610 rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen); 611 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { 612 return NGTCP2_ERR_CALLBACK_FAILURE; 613 } 614 615 return 0; 616 } 617 618 static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags, 619 int64_t sid, uint64_t app_error_code, 620 void *user_data, void *stream_user_data) 621 { 622 struct Curl_cfilter *cf = user_data; 623 struct cf_ngtcp2_ctx *ctx = cf->ctx; 624 struct Curl_easy *data = stream_user_data; 625 curl_int64_t stream_id = (curl_int64_t)sid; 626 int rv; 627 628 (void)tconn; 629 /* stream is closed... */ 630 if(!data) 631 data = CF_DATA_CURRENT(cf); 632 if(!data) 633 return NGTCP2_ERR_CALLBACK_FAILURE; 634 635 if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) { 636 app_error_code = NGHTTP3_H3_NO_ERROR; 637 } 638 639 rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, app_error_code); 640 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] quic close(app_error=%" 641 FMT_PRIu64 ") -> %d", stream_id, (curl_uint64_t)app_error_code, 642 rv); 643 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { 644 cf_ngtcp2_h3_err_set(cf, data, rv); 645 return NGTCP2_ERR_CALLBACK_FAILURE; 646 } 647 648 return 0; 649 } 650 651 static int cb_stream_reset(ngtcp2_conn *tconn, int64_t sid, 652 uint64_t final_size, uint64_t app_error_code, 653 void *user_data, void *stream_user_data) 654 { 655 struct Curl_cfilter *cf = user_data; 656 struct cf_ngtcp2_ctx *ctx = cf->ctx; 657 curl_int64_t stream_id = (curl_int64_t)sid; 658 struct Curl_easy *data = stream_user_data; 659 int rv; 660 (void)tconn; 661 (void)final_size; 662 (void)app_error_code; 663 (void)data; 664 665 rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id); 666 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv); 667 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { 668 return NGTCP2_ERR_CALLBACK_FAILURE; 669 } 670 671 return 0; 672 } 673 674 static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id, 675 uint64_t app_error_code, void *user_data, 676 void *stream_user_data) 677 { 678 struct Curl_cfilter *cf = user_data; 679 struct cf_ngtcp2_ctx *ctx = cf->ctx; 680 int rv; 681 (void)tconn; 682 (void)app_error_code; 683 (void)stream_user_data; 684 685 rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id); 686 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { 687 return NGTCP2_ERR_CALLBACK_FAILURE; 688 } 689 690 return 0; 691 } 692 693 static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn, 694 uint64_t max_streams, 695 void *user_data) 696 { 697 struct Curl_cfilter *cf = user_data; 698 struct cf_ngtcp2_ctx *ctx = cf->ctx; 699 struct Curl_easy *data = CF_DATA_CURRENT(cf); 700 701 (void)tconn; 702 ctx->max_bidi_streams = max_streams; 703 if(data) 704 CURL_TRC_CF(data, cf, "max bidi streams now %" FMT_PRIu64 705 ", used %" FMT_PRIu64, (curl_uint64_t)ctx->max_bidi_streams, 706 (curl_uint64_t)ctx->used_bidi_streams); 707 return 0; 708 } 709 710 static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id, 711 uint64_t max_data, void *user_data, 712 void *stream_user_data) 713 { 714 struct Curl_cfilter *cf = user_data; 715 struct cf_ngtcp2_ctx *ctx = cf->ctx; 716 struct Curl_easy *s_data = stream_user_data; 717 struct h3_stream_ctx *stream; 718 int rv; 719 (void)tconn; 720 (void)max_data; 721 722 rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id); 723 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { 724 return NGTCP2_ERR_CALLBACK_FAILURE; 725 } 726 stream = H3_STREAM_CTX(ctx, s_data); 727 if(stream && stream->quic_flow_blocked) { 728 CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow", 729 (curl_int64_t)stream_id); 730 stream->quic_flow_blocked = FALSE; 731 Curl_multi_mark_dirty(s_data); 732 } 733 return 0; 734 } 735 736 static void cb_rand(uint8_t *dest, size_t destlen, 737 const ngtcp2_rand_ctx *rand_ctx) 738 { 739 CURLcode result; 740 (void)rand_ctx; 741 742 result = Curl_rand(NULL, dest, destlen); 743 if(result) { 744 /* cb_rand is only used for non-cryptographic context. If Curl_rand 745 failed, just fill 0 and call it *random*. */ 746 memset(dest, 0, destlen); 747 } 748 } 749 750 static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, 751 uint8_t *token, size_t cidlen, 752 void *user_data) 753 { 754 CURLcode result; 755 (void)tconn; 756 (void)user_data; 757 758 result = Curl_rand(NULL, cid->data, cidlen); 759 if(result) 760 return NGTCP2_ERR_CALLBACK_FAILURE; 761 cid->datalen = cidlen; 762 763 result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN); 764 if(result) 765 return NGTCP2_ERR_CALLBACK_FAILURE; 766 767 return 0; 768 } 769 770 static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level, 771 void *user_data) 772 { 773 struct Curl_cfilter *cf = user_data; 774 struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL; 775 struct Curl_easy *data = CF_DATA_CURRENT(cf); 776 (void)tconn; 777 778 if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT) 779 return 0; 780 781 DEBUGASSERT(ctx); 782 DEBUGASSERT(data); 783 if(ctx && data && !ctx->h3conn) { 784 if(init_ngh3_conn(cf, data)) 785 return NGTCP2_ERR_CALLBACK_FAILURE; 786 } 787 return 0; 788 } 789 790 #if defined(_MSC_VER) && defined(_DLL) 791 # pragma warning(push) 792 # pragma warning(disable:4232) /* MSVC extension, dllimport identity */ 793 #endif 794 795 static ngtcp2_callbacks ng_callbacks = { 796 ngtcp2_crypto_client_initial_cb, 797 NULL, /* recv_client_initial */ 798 ngtcp2_crypto_recv_crypto_data_cb, 799 cf_ngtcp2_handshake_completed, 800 NULL, /* recv_version_negotiation */ 801 ngtcp2_crypto_encrypt_cb, 802 ngtcp2_crypto_decrypt_cb, 803 ngtcp2_crypto_hp_mask_cb, 804 cb_recv_stream_data, 805 cb_acked_stream_data_offset, 806 NULL, /* stream_open */ 807 cb_stream_close, 808 NULL, /* recv_stateless_reset */ 809 ngtcp2_crypto_recv_retry_cb, 810 cb_extend_max_local_streams_bidi, 811 NULL, /* extend_max_local_streams_uni */ 812 cb_rand, 813 cb_get_new_connection_id, 814 NULL, /* remove_connection_id */ 815 ngtcp2_crypto_update_key_cb, /* update_key */ 816 NULL, /* path_validation */ 817 NULL, /* select_preferred_addr */ 818 cb_stream_reset, 819 NULL, /* extend_max_remote_streams_bidi */ 820 NULL, /* extend_max_remote_streams_uni */ 821 cb_extend_max_stream_data, 822 NULL, /* dcid_status */ 823 NULL, /* handshake_confirmed */ 824 NULL, /* recv_new_token */ 825 ngtcp2_crypto_delete_crypto_aead_ctx_cb, 826 ngtcp2_crypto_delete_crypto_cipher_ctx_cb, 827 NULL, /* recv_datagram */ 828 NULL, /* ack_datagram */ 829 NULL, /* lost_datagram */ 830 ngtcp2_crypto_get_path_challenge_data_cb, 831 cb_stream_stop_sending, 832 NULL, /* version_negotiation */ 833 cb_recv_rx_key, 834 NULL, /* recv_tx_key */ 835 NULL, /* early_data_rejected */ 836 }; 837 838 #if defined(_MSC_VER) && defined(_DLL) 839 # pragma warning(pop) 840 #endif 841 842 /** 843 * Connection maintenance like timeouts on packet ACKs etc. are done by us, not 844 * the OS like for TCP. POLL events on the socket therefore are not 845 * sufficient. 846 * ngtcp2 tells us when it wants to be invoked again. We handle that via 847 * the `Curl_expire()` mechanisms. 848 */ 849 static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, 850 struct Curl_easy *data, 851 struct pkt_io_ctx *pktx) 852 { 853 struct cf_ngtcp2_ctx *ctx = cf->ctx; 854 struct pkt_io_ctx local_pktx; 855 ngtcp2_tstamp expiry; 856 857 if(!pktx) { 858 pktx_init(&local_pktx, cf, data); 859 pktx = &local_pktx; 860 } 861 else { 862 pktx_update_time(pktx, cf); 863 } 864 865 expiry = ngtcp2_conn_get_expiry(ctx->qconn); 866 if(expiry != UINT64_MAX) { 867 if(expiry <= pktx->ts) { 868 CURLcode result; 869 int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts); 870 if(rv) { 871 failf(data, "ngtcp2_conn_handle_expiry returned error: %s", 872 ngtcp2_strerror(rv)); 873 cf_ngtcp2_err_set(cf, data, rv); 874 return CURLE_SEND_ERROR; 875 } 876 result = cf_progress_ingress(cf, data, pktx); 877 if(result) 878 return result; 879 result = cf_progress_egress(cf, data, pktx); 880 if(result) 881 return result; 882 /* ask again, things might have changed */ 883 expiry = ngtcp2_conn_get_expiry(ctx->qconn); 884 } 885 886 if(expiry > pktx->ts) { 887 ngtcp2_duration timeout = expiry - pktx->ts; 888 if(timeout % NGTCP2_MILLISECONDS) { 889 timeout += NGTCP2_MILLISECONDS; 890 } 891 Curl_expire(data, (timediff_t)(timeout / NGTCP2_MILLISECONDS), 892 EXPIRE_QUIC); 893 } 894 } 895 return CURLE_OK; 896 } 897 898 static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf, 899 struct Curl_easy *data, 900 struct easy_pollset *ps) 901 { 902 struct cf_ngtcp2_ctx *ctx = cf->ctx; 903 bool want_recv, want_send; 904 905 if(!ctx->qconn) 906 return; 907 908 Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); 909 if(!want_send && !Curl_bufq_is_empty(&ctx->q.sendbuf)) 910 want_send = TRUE; 911 912 if(want_recv || want_send) { 913 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 914 struct cf_call_data save; 915 bool c_exhaust, s_exhaust; 916 917 CF_DATA_SAVE(save, cf, data); 918 c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) || 919 !ngtcp2_conn_get_max_data_left(ctx->qconn)); 920 s_exhaust = want_send && stream && stream->id >= 0 && 921 stream->quic_flow_blocked; 922 want_recv = (want_recv || c_exhaust || s_exhaust); 923 want_send = (!s_exhaust && want_send) || 924 !Curl_bufq_is_empty(&ctx->q.sendbuf); 925 926 Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); 927 CF_DATA_RESTORE(cf, save); 928 } 929 } 930 931 static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid, 932 uint64_t app_error_code, void *user_data, 933 void *stream_user_data) 934 { 935 struct Curl_cfilter *cf = user_data; 936 struct cf_ngtcp2_ctx *ctx = cf->ctx; 937 struct Curl_easy *data = stream_user_data; 938 curl_int64_t stream_id = (curl_int64_t)sid; 939 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 940 (void)conn; 941 (void)stream_id; 942 943 /* we might be called by nghttp3 after we already cleaned up */ 944 if(!stream) 945 return 0; 946 947 stream->closed = TRUE; 948 stream->error3 = (curl_uint64_t)app_error_code; 949 if(stream->error3 != NGHTTP3_H3_NO_ERROR) { 950 stream->reset = TRUE; 951 stream->send_closed = TRUE; 952 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] RESET: error %" FMT_PRIu64, 953 stream->id, stream->error3); 954 } 955 else { 956 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->id); 957 } 958 Curl_multi_mark_dirty(data); 959 return 0; 960 } 961 962 static void h3_xfer_write_resp_hd(struct Curl_cfilter *cf, 963 struct Curl_easy *data, 964 struct h3_stream_ctx *stream, 965 const char *buf, size_t blen, bool eos) 966 { 967 968 /* If we already encountered an error, skip further writes */ 969 if(!stream->xfer_result) { 970 stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos); 971 if(stream->xfer_result) 972 CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu " 973 "bytes of headers", stream->id, stream->xfer_result, blen); 974 } 975 } 976 977 static void h3_xfer_write_resp(struct Curl_cfilter *cf, 978 struct Curl_easy *data, 979 struct h3_stream_ctx *stream, 980 const char *buf, size_t blen, bool eos) 981 { 982 983 /* If we already encountered an error, skip further writes */ 984 if(!stream->xfer_result) { 985 stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos); 986 /* If the transfer write is errored, we do not want any more data */ 987 if(stream->xfer_result) { 988 CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu bytes " 989 "of data", stream->id, stream->xfer_result, blen); 990 } 991 } 992 } 993 994 static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, 995 const uint8_t *buf, size_t blen, 996 void *user_data, void *stream_user_data) 997 { 998 struct Curl_cfilter *cf = user_data; 999 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1000 struct Curl_easy *data = stream_user_data; 1001 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1002 1003 (void)conn; 1004 (void)stream3_id; 1005 1006 if(!stream) 1007 return NGHTTP3_ERR_CALLBACK_FAILURE; 1008 1009 h3_xfer_write_resp(cf, data, stream, (const char *)buf, blen, FALSE); 1010 if(blen) { 1011 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] ACK %zu bytes of DATA", 1012 stream->id, blen); 1013 ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen); 1014 ngtcp2_conn_extend_max_offset(ctx->qconn, blen); 1015 } 1016 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu", stream->id, blen); 1017 return 0; 1018 } 1019 1020 static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream3_id, 1021 size_t consumed, void *user_data, 1022 void *stream_user_data) 1023 { 1024 struct Curl_cfilter *cf = user_data; 1025 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1026 (void)conn; 1027 (void)stream_user_data; 1028 1029 /* nghttp3 has consumed bytes on the QUIC stream and we need to 1030 * tell the QUIC connection to increase its flow control */ 1031 ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream3_id, consumed); 1032 ngtcp2_conn_extend_max_offset(ctx->qconn, consumed); 1033 return 0; 1034 } 1035 1036 static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid, 1037 int fin, void *user_data, void *stream_user_data) 1038 { 1039 struct Curl_cfilter *cf = user_data; 1040 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1041 struct Curl_easy *data = stream_user_data; 1042 curl_int64_t stream_id = (curl_int64_t)sid; 1043 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1044 (void)conn; 1045 (void)stream_id; 1046 (void)fin; 1047 (void)cf; 1048 1049 if(!stream) 1050 return 0; 1051 /* add a CRLF only if we have received some headers */ 1052 h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed); 1053 1054 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] end_headers, status=%d", 1055 stream_id, stream->status_code); 1056 if(stream->status_code / 100 != 1) { 1057 stream->resp_hds_complete = TRUE; 1058 } 1059 Curl_multi_mark_dirty(data); 1060 return 0; 1061 } 1062 1063 static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid, 1064 int32_t token, nghttp3_rcbuf *name, 1065 nghttp3_rcbuf *value, uint8_t flags, 1066 void *user_data, void *stream_user_data) 1067 { 1068 struct Curl_cfilter *cf = user_data; 1069 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1070 curl_int64_t stream_id = (curl_int64_t)sid; 1071 nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name); 1072 nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value); 1073 struct Curl_easy *data = stream_user_data; 1074 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1075 CURLcode result = CURLE_OK; 1076 (void)conn; 1077 (void)stream_id; 1078 (void)token; 1079 (void)flags; 1080 (void)cf; 1081 1082 /* we might have cleaned up this transfer already */ 1083 if(!stream) 1084 return 0; 1085 1086 if(token == NGHTTP3_QPACK_TOKEN__STATUS) { 1087 1088 result = Curl_http_decode_status(&stream->status_code, 1089 (const char *)h3val.base, h3val.len); 1090 if(result) 1091 return -1; 1092 curlx_dyn_reset(&ctx->scratch); 1093 result = curlx_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 ")); 1094 if(!result) 1095 result = curlx_dyn_addn(&ctx->scratch, 1096 (const char *)h3val.base, h3val.len); 1097 if(!result) 1098 result = curlx_dyn_addn(&ctx->scratch, STRCONST(" \r\n")); 1099 if(!result) 1100 h3_xfer_write_resp_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch), 1101 curlx_dyn_len(&ctx->scratch), FALSE); 1102 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s", 1103 stream_id, curlx_dyn_ptr(&ctx->scratch)); 1104 if(result) { 1105 return -1; 1106 } 1107 } 1108 else { 1109 /* store as an HTTP1-style header */ 1110 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] header: %.*s: %.*s", 1111 stream_id, (int)h3name.len, h3name.base, 1112 (int)h3val.len, h3val.base); 1113 curlx_dyn_reset(&ctx->scratch); 1114 result = curlx_dyn_addn(&ctx->scratch, 1115 (const char *)h3name.base, h3name.len); 1116 if(!result) 1117 result = curlx_dyn_addn(&ctx->scratch, STRCONST(": ")); 1118 if(!result) 1119 result = curlx_dyn_addn(&ctx->scratch, 1120 (const char *)h3val.base, h3val.len); 1121 if(!result) 1122 result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n")); 1123 if(!result) 1124 h3_xfer_write_resp_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch), 1125 curlx_dyn_len(&ctx->scratch), FALSE); 1126 } 1127 return 0; 1128 } 1129 1130 static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id, 1131 uint64_t app_error_code, void *user_data, 1132 void *stream_user_data) 1133 { 1134 struct Curl_cfilter *cf = user_data; 1135 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1136 int rv; 1137 (void)conn; 1138 (void)stream_user_data; 1139 1140 rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id, 1141 app_error_code); 1142 if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { 1143 return NGHTTP3_ERR_CALLBACK_FAILURE; 1144 } 1145 1146 return 0; 1147 } 1148 1149 static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid, 1150 uint64_t app_error_code, void *user_data, 1151 void *stream_user_data) { 1152 struct Curl_cfilter *cf = user_data; 1153 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1154 curl_int64_t stream_id = (curl_int64_t)sid; 1155 struct Curl_easy *data = stream_user_data; 1156 int rv; 1157 (void)conn; 1158 (void)data; 1159 1160 rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id, 1161 app_error_code); 1162 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv); 1163 if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { 1164 return NGHTTP3_ERR_CALLBACK_FAILURE; 1165 } 1166 1167 return 0; 1168 } 1169 1170 static nghttp3_callbacks ngh3_callbacks = { 1171 cb_h3_acked_req_body, /* acked_stream_data */ 1172 cb_h3_stream_close, 1173 cb_h3_recv_data, 1174 cb_h3_deferred_consume, 1175 NULL, /* begin_headers */ 1176 cb_h3_recv_header, 1177 cb_h3_end_headers, 1178 NULL, /* begin_trailers */ 1179 cb_h3_recv_header, 1180 NULL, /* end_trailers */ 1181 cb_h3_stop_sending, 1182 NULL, /* end_stream */ 1183 cb_h3_reset_stream, 1184 NULL, /* shutdown */ 1185 NULL /* recv_settings */ 1186 }; 1187 1188 static CURLcode init_ngh3_conn(struct Curl_cfilter *cf, 1189 struct Curl_easy *data) 1190 { 1191 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1192 int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id; 1193 int rc; 1194 1195 if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) { 1196 failf(data, "QUIC connection lacks 3 uni streams to run HTTP/3"); 1197 return CURLE_QUIC_CONNECT_ERROR; 1198 } 1199 1200 nghttp3_settings_default(&ctx->h3settings); 1201 1202 rc = nghttp3_conn_client_new(&ctx->h3conn, 1203 &ngh3_callbacks, 1204 &ctx->h3settings, 1205 nghttp3_mem_default(), 1206 cf); 1207 if(rc) { 1208 failf(data, "error creating nghttp3 connection instance"); 1209 return CURLE_OUT_OF_MEMORY; 1210 } 1211 1212 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &ctrl_stream_id, NULL); 1213 if(rc) { 1214 failf(data, "error creating HTTP/3 control stream: %s", 1215 ngtcp2_strerror(rc)); 1216 return CURLE_QUIC_CONNECT_ERROR; 1217 } 1218 1219 rc = nghttp3_conn_bind_control_stream(ctx->h3conn, ctrl_stream_id); 1220 if(rc) { 1221 failf(data, "error binding HTTP/3 control stream: %s", 1222 ngtcp2_strerror(rc)); 1223 return CURLE_QUIC_CONNECT_ERROR; 1224 } 1225 1226 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_enc_stream_id, NULL); 1227 if(rc) { 1228 failf(data, "error creating HTTP/3 qpack encoding stream: %s", 1229 ngtcp2_strerror(rc)); 1230 return CURLE_QUIC_CONNECT_ERROR; 1231 } 1232 1233 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_dec_stream_id, NULL); 1234 if(rc) { 1235 failf(data, "error creating HTTP/3 qpack decoding stream: %s", 1236 ngtcp2_strerror(rc)); 1237 return CURLE_QUIC_CONNECT_ERROR; 1238 } 1239 1240 rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id, 1241 qpack_dec_stream_id); 1242 if(rc) { 1243 failf(data, "error binding HTTP/3 qpack streams: %s", 1244 ngtcp2_strerror(rc)); 1245 return CURLE_QUIC_CONNECT_ERROR; 1246 } 1247 1248 return CURLE_OK; 1249 } 1250 1251 static ssize_t recv_closed_stream(struct Curl_cfilter *cf, 1252 struct Curl_easy *data, 1253 struct h3_stream_ctx *stream, 1254 CURLcode *err) 1255 { 1256 ssize_t nread = -1; 1257 1258 (void)cf; 1259 if(stream->reset) { 1260 failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id); 1261 *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3; 1262 goto out; 1263 } 1264 else if(!stream->resp_hds_complete) { 1265 failf(data, 1266 "HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before " 1267 "getting all response header fields, treated as error", 1268 stream->id); 1269 *err = CURLE_HTTP3; 1270 goto out; 1271 } 1272 *err = CURLE_OK; 1273 nread = 0; 1274 1275 out: 1276 return nread; 1277 } 1278 1279 /* incoming data frames on the h3 stream */ 1280 static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, 1281 char *buf, size_t blen, size_t *pnread) 1282 { 1283 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1284 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1285 struct cf_call_data save; 1286 struct pkt_io_ctx pktx; 1287 CURLcode result = CURLE_OK; 1288 1289 (void)ctx; 1290 (void)buf; 1291 1292 CF_DATA_SAVE(save, cf, data); 1293 DEBUGASSERT(cf->connected); 1294 DEBUGASSERT(ctx); 1295 DEBUGASSERT(ctx->qconn); 1296 DEBUGASSERT(ctx->h3conn); 1297 *pnread = 0; 1298 1299 /* handshake verification failed in callback, do not recv anything */ 1300 if(ctx->tls_vrfy_result) 1301 return ctx->tls_vrfy_result; 1302 1303 pktx_init(&pktx, cf, data); 1304 1305 if(!stream || ctx->shutdown_started) { 1306 result = CURLE_RECV_ERROR; 1307 goto out; 1308 } 1309 1310 if(cf_progress_ingress(cf, data, &pktx)) { 1311 result = CURLE_RECV_ERROR; 1312 goto out; 1313 } 1314 1315 if(stream->xfer_result) { 1316 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id); 1317 cf_ngtcp2_stream_close(cf, data, stream); 1318 result = stream->xfer_result; 1319 goto out; 1320 } 1321 else if(stream->closed) { 1322 ssize_t nread = recv_closed_stream(cf, data, stream, &result); 1323 if(nread > 0) 1324 *pnread = (size_t)nread; 1325 goto out; 1326 } 1327 result = CURLE_AGAIN; 1328 1329 out: 1330 result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx)); 1331 result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); 1332 1333 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu", 1334 1335 stream ? stream->id : -1, blen, result, *pnread); 1336 CF_DATA_RESTORE(cf, save); 1337 return result; 1338 } 1339 1340 static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, 1341 uint64_t datalen, void *user_data, 1342 void *stream_user_data) 1343 { 1344 struct Curl_cfilter *cf = user_data; 1345 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1346 struct Curl_easy *data = stream_user_data; 1347 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1348 size_t skiplen; 1349 1350 (void)cf; 1351 if(!stream) 1352 return 0; 1353 /* The server acknowledged `datalen` of bytes from our request body. 1354 * This is a delta. We have kept this data in `sendbuf` for 1355 * re-transmissions and can free it now. */ 1356 if(datalen >= (uint64_t)stream->sendbuf_len_in_flight) 1357 skiplen = stream->sendbuf_len_in_flight; 1358 else 1359 skiplen = (size_t)datalen; 1360 Curl_bufq_skip(&stream->sendbuf, skiplen); 1361 stream->sendbuf_len_in_flight -= skiplen; 1362 1363 /* Resume upload processing if we have more data to send */ 1364 if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) { 1365 int rv = nghttp3_conn_resume_stream(conn, stream_id); 1366 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) { 1367 return NGHTTP3_ERR_CALLBACK_FAILURE; 1368 } 1369 } 1370 return 0; 1371 } 1372 1373 static nghttp3_ssize 1374 cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, 1375 nghttp3_vec *vec, size_t veccnt, 1376 uint32_t *pflags, void *user_data, 1377 void *stream_user_data) 1378 { 1379 struct Curl_cfilter *cf = user_data; 1380 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1381 struct Curl_easy *data = stream_user_data; 1382 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1383 ssize_t nwritten = 0; 1384 size_t nvecs = 0; 1385 (void)cf; 1386 (void)conn; 1387 (void)stream_id; 1388 (void)user_data; 1389 (void)veccnt; 1390 1391 if(!stream) 1392 return NGHTTP3_ERR_CALLBACK_FAILURE; 1393 /* nghttp3 keeps references to the sendbuf data until it is ACKed 1394 * by the server (see `cb_h3_acked_req_body()` for updates). 1395 * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf` 1396 * that we have already passed to nghttp3, but which have not been 1397 * ACKed yet. 1398 * Any amount beyond `sendbuf_len_in_flight` we need still to pass 1399 * to nghttp3. Do that now, if we can. */ 1400 if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) { 1401 nvecs = 0; 1402 while(nvecs < veccnt && 1403 Curl_bufq_peek_at(&stream->sendbuf, 1404 stream->sendbuf_len_in_flight, 1405 CURL_UNCONST(&vec[nvecs].base), 1406 &vec[nvecs].len)) { 1407 stream->sendbuf_len_in_flight += vec[nvecs].len; 1408 nwritten += vec[nvecs].len; 1409 ++nvecs; 1410 } 1411 DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */ 1412 } 1413 1414 if(nwritten > 0 && stream->upload_left != -1) 1415 stream->upload_left -= nwritten; 1416 1417 /* When we stopped sending and everything in `sendbuf` is "in flight", 1418 * we are at the end of the request body. */ 1419 if(stream->upload_left == 0) { 1420 *pflags = NGHTTP3_DATA_FLAG_EOF; 1421 stream->send_closed = TRUE; 1422 } 1423 else if(!nwritten) { 1424 /* Not EOF, and nothing to give, we signal WOULDBLOCK. */ 1425 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN", 1426 stream->id); 1427 return NGHTTP3_ERR_WOULDBLOCK; 1428 } 1429 1430 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> " 1431 "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")", 1432 stream->id, (int)nvecs, 1433 *pflags == NGHTTP3_DATA_FLAG_EOF ? " EOF" : "", 1434 nwritten, Curl_bufq_len(&stream->sendbuf), 1435 stream->upload_left); 1436 return (nghttp3_ssize)nvecs; 1437 } 1438 1439 /* Index where :authority header field will appear in request header 1440 field list. */ 1441 #define AUTHORITY_DST_IDX 3 1442 1443 static CURLcode h3_stream_open(struct Curl_cfilter *cf, 1444 struct Curl_easy *data, 1445 const void *buf, size_t len, 1446 size_t *pnwritten) 1447 { 1448 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1449 struct h3_stream_ctx *stream = NULL; 1450 int64_t sid; 1451 struct dynhds h2_headers; 1452 size_t nheader; 1453 nghttp3_nv *nva = NULL; 1454 int rc = 0; 1455 unsigned int i; 1456 ssize_t nwritten = -1; 1457 nghttp3_data_reader reader; 1458 nghttp3_data_reader *preader = NULL; 1459 CURLcode result; 1460 1461 *pnwritten = 0; 1462 Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); 1463 1464 result = h3_data_setup(cf, data); 1465 if(result) 1466 goto out; 1467 stream = H3_STREAM_CTX(ctx, data); 1468 DEBUGASSERT(stream); 1469 if(!stream) { 1470 result = CURLE_FAILED_INIT; 1471 goto out; 1472 } 1473 1474 nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result); 1475 if(nwritten < 0) 1476 goto out; 1477 *pnwritten = (size_t)nwritten; 1478 1479 if(!stream->h1.done) { 1480 /* need more data */ 1481 goto out; 1482 } 1483 DEBUGASSERT(stream->h1.req); 1484 1485 result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); 1486 if(result) 1487 goto out; 1488 1489 /* no longer needed */ 1490 Curl_h1_req_parse_free(&stream->h1); 1491 1492 nheader = Curl_dynhds_count(&h2_headers); 1493 nva = malloc(sizeof(nghttp3_nv) * nheader); 1494 if(!nva) { 1495 result = CURLE_OUT_OF_MEMORY; 1496 goto out; 1497 } 1498 1499 for(i = 0; i < nheader; ++i) { 1500 struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i); 1501 nva[i].name = (unsigned char *)e->name; 1502 nva[i].namelen = e->namelen; 1503 nva[i].value = (unsigned char *)e->value; 1504 nva[i].valuelen = e->valuelen; 1505 nva[i].flags = NGHTTP3_NV_FLAG_NONE; 1506 } 1507 1508 rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data); 1509 if(rc) { 1510 failf(data, "can get bidi streams"); 1511 result = CURLE_SEND_ERROR; 1512 goto out; 1513 } 1514 stream->id = (curl_int64_t)sid; 1515 ++ctx->used_bidi_streams; 1516 1517 switch(data->state.httpreq) { 1518 case HTTPREQ_POST: 1519 case HTTPREQ_POST_FORM: 1520 case HTTPREQ_POST_MIME: 1521 case HTTPREQ_PUT: 1522 /* known request body size or -1 */ 1523 if(data->state.infilesize != -1) 1524 stream->upload_left = data->state.infilesize; 1525 else 1526 /* data sending without specifying the data amount up front */ 1527 stream->upload_left = -1; /* unknown */ 1528 break; 1529 default: 1530 /* there is not request body */ 1531 stream->upload_left = 0; /* no request body */ 1532 break; 1533 } 1534 1535 stream->send_closed = (stream->upload_left == 0); 1536 if(!stream->send_closed) { 1537 reader.read_data = cb_h3_read_req_body; 1538 preader = &reader; 1539 } 1540 1541 rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id, 1542 nva, nheader, preader, data); 1543 if(rc) { 1544 switch(rc) { 1545 case NGHTTP3_ERR_CONN_CLOSING: 1546 CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send, " 1547 "connection is closing", stream->id); 1548 break; 1549 default: 1550 CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send -> " 1551 "%d (%s)", stream->id, rc, nghttp3_strerror(rc)); 1552 break; 1553 } 1554 result = CURLE_SEND_ERROR; 1555 goto out; 1556 } 1557 1558 if(Curl_trc_is_verbose(data)) { 1559 infof(data, "[HTTP/3] [%" FMT_PRId64 "] OPENED stream for %s", 1560 stream->id, data->state.url); 1561 for(i = 0; i < nheader; ++i) { 1562 infof(data, "[HTTP/3] [%" FMT_PRId64 "] [%.*s: %.*s]", stream->id, 1563 (int)nva[i].namelen, nva[i].name, 1564 (int)nva[i].valuelen, nva[i].value); 1565 } 1566 } 1567 1568 out: 1569 free(nva); 1570 Curl_dynhds_free(&h2_headers); 1571 return result; 1572 } 1573 1574 static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, 1575 const void *buf, size_t len, bool eos, 1576 size_t *pnwritten) 1577 { 1578 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1579 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1580 struct cf_call_data save; 1581 struct pkt_io_ctx pktx; 1582 CURLcode result = CURLE_OK; 1583 1584 CF_DATA_SAVE(save, cf, data); 1585 DEBUGASSERT(cf->connected); 1586 DEBUGASSERT(ctx->qconn); 1587 DEBUGASSERT(ctx->h3conn); 1588 pktx_init(&pktx, cf, data); 1589 *pnwritten = 0; 1590 1591 /* handshake verification failed in callback, do not send anything */ 1592 if(ctx->tls_vrfy_result) 1593 return ctx->tls_vrfy_result; 1594 1595 (void)eos; /* use for stream EOF and block handling */ 1596 result = cf_progress_ingress(cf, data, &pktx); 1597 if(result) 1598 goto out; 1599 1600 if(!stream || stream->id < 0) { 1601 if(ctx->shutdown_started) { 1602 CURL_TRC_CF(data, cf, "cannot open stream on closed connection"); 1603 result = CURLE_SEND_ERROR; 1604 goto out; 1605 } 1606 result = h3_stream_open(cf, data, buf, len, pnwritten); 1607 if(result) { 1608 CURL_TRC_CF(data, cf, "failed to open stream -> %d", result); 1609 goto out; 1610 } 1611 stream = H3_STREAM_CTX(ctx, data); 1612 } 1613 else if(stream->xfer_result) { 1614 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id); 1615 cf_ngtcp2_stream_close(cf, data, stream); 1616 result = stream->xfer_result; 1617 goto out; 1618 } 1619 else if(stream->closed) { 1620 if(stream->resp_hds_complete) { 1621 /* Server decided to close the stream after having sent us a final 1622 * response. This is valid if it is not interested in the request 1623 * body. This happens on 30x or 40x responses. 1624 * We silently discard the data sent, since this is not a transport 1625 * error situation. */ 1626 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data" 1627 "on closed stream with response", stream->id); 1628 result = CURLE_OK; 1629 *pnwritten = len; 1630 goto out; 1631 } 1632 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) " 1633 "-> stream closed", stream->id, len); 1634 result = CURLE_HTTP3; 1635 goto out; 1636 } 1637 else if(ctx->shutdown_started) { 1638 CURL_TRC_CF(data, cf, "cannot send on closed connection"); 1639 result = CURLE_SEND_ERROR; 1640 goto out; 1641 } 1642 else { 1643 result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten); 1644 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to " 1645 "sendbuf(len=%zu) -> %d, %zu", 1646 stream->id, len, result, *pnwritten); 1647 if(result) 1648 goto out; 1649 (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); 1650 } 1651 1652 if(*pnwritten > 0 && !ctx->tls_handshake_complete && ctx->use_earlydata) 1653 ctx->earlydata_skip += *pnwritten; 1654 1655 DEBUGASSERT(!result); 1656 result = cf_progress_egress(cf, data, &pktx); 1657 1658 out: 1659 result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); 1660 1661 CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu", 1662 stream ? stream->id : -1, len, result, *pnwritten); 1663 CF_DATA_RESTORE(cf, save); 1664 return result; 1665 } 1666 1667 static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, 1668 struct sockaddr_storage *remote_addr, 1669 socklen_t remote_addrlen, int ecn, 1670 void *userp) 1671 { 1672 struct pkt_io_ctx *pktx = userp; 1673 struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx; 1674 ngtcp2_pkt_info pi; 1675 ngtcp2_path path; 1676 int rv; 1677 1678 ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr, 1679 (socklen_t)ctx->q.local_addrlen); 1680 ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr, 1681 remote_addrlen); 1682 pi.ecn = (uint8_t)ecn; 1683 1684 rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts); 1685 if(rv) { 1686 CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)", 1687 ngtcp2_strerror(rv), rv); 1688 cf_ngtcp2_err_set(pktx->cf, pktx->data, rv); 1689 1690 if(rv == NGTCP2_ERR_CRYPTO) 1691 /* this is a "TLS problem", but a failed certificate verification 1692 is a common reason for this */ 1693 return CURLE_PEER_FAILED_VERIFICATION; 1694 return CURLE_RECV_ERROR; 1695 } 1696 1697 return CURLE_OK; 1698 } 1699 1700 static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, 1701 struct Curl_easy *data, 1702 struct pkt_io_ctx *pktx) 1703 { 1704 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1705 struct pkt_io_ctx local_pktx; 1706 CURLcode result = CURLE_OK; 1707 1708 if(!pktx) { 1709 pktx_init(&local_pktx, cf, data); 1710 pktx = &local_pktx; 1711 } 1712 1713 result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data); 1714 if(result) 1715 return result; 1716 1717 return vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, pktx); 1718 } 1719 1720 /** 1721 * Read a network packet to send from ngtcp2 into `buf`. 1722 * Return number of bytes written or -1 with *err set. 1723 */ 1724 static CURLcode read_pkt_to_send(void *userp, 1725 unsigned char *buf, size_t buflen, 1726 size_t *pnread) 1727 { 1728 struct pkt_io_ctx *x = userp; 1729 struct cf_ngtcp2_ctx *ctx = x->cf->ctx; 1730 nghttp3_vec vec[16]; 1731 nghttp3_ssize veccnt; 1732 ngtcp2_ssize ndatalen; 1733 uint32_t flags; 1734 int64_t stream_id; 1735 int fin; 1736 ssize_t n; 1737 1738 *pnread = 0; 1739 veccnt = 0; 1740 stream_id = -1; 1741 fin = 0; 1742 1743 /* ngtcp2 may want to put several frames from different streams into 1744 * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so. 1745 * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make 1746 * another iteration. 1747 * When ngtcp2 is happy (because it has no other frame that would fit 1748 * or it has nothing more to send), it returns the total length 1749 * of the assembled packet. This may be 0 if there was nothing to send. */ 1750 for(;;) { 1751 1752 if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) { 1753 veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec, 1754 CURL_ARRAYSIZE(vec)); 1755 if(veccnt < 0) { 1756 failf(x->data, "nghttp3_conn_writev_stream returned error: %s", 1757 nghttp3_strerror((int)veccnt)); 1758 cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt); 1759 return CURLE_SEND_ERROR; 1760 } 1761 } 1762 1763 flags = NGTCP2_WRITE_STREAM_FLAG_MORE | 1764 (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); 1765 n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path, 1766 NULL, buf, buflen, 1767 &ndatalen, flags, stream_id, 1768 (const ngtcp2_vec *)vec, veccnt, x->ts); 1769 if(n == 0) { 1770 /* nothing to send */ 1771 return CURLE_AGAIN; 1772 } 1773 else if(n < 0) { 1774 switch(n) { 1775 case NGTCP2_ERR_STREAM_DATA_BLOCKED: { 1776 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data); 1777 DEBUGASSERT(ndatalen == -1); 1778 nghttp3_conn_block_stream(ctx->h3conn, stream_id); 1779 CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] block quic flow", 1780 (curl_int64_t)stream_id); 1781 DEBUGASSERT(stream); 1782 if(stream) 1783 stream->quic_flow_blocked = TRUE; 1784 n = 0; 1785 break; 1786 } 1787 case NGTCP2_ERR_STREAM_SHUT_WR: 1788 DEBUGASSERT(ndatalen == -1); 1789 nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id); 1790 n = 0; 1791 break; 1792 case NGTCP2_ERR_WRITE_MORE: 1793 /* ngtcp2 wants to send more. update the flow of the stream whose data 1794 * is in the buffer and continue */ 1795 DEBUGASSERT(ndatalen >= 0); 1796 n = 0; 1797 break; 1798 default: 1799 DEBUGASSERT(ndatalen == -1); 1800 failf(x->data, "ngtcp2_conn_writev_stream returned error: %s", 1801 ngtcp2_strerror((int)n)); 1802 cf_ngtcp2_err_set(x->cf, x->data, (int)n); 1803 return CURLE_SEND_ERROR; 1804 } 1805 } 1806 1807 if(ndatalen >= 0) { 1808 /* we add the amount of data bytes to the flow windows */ 1809 int rv = nghttp3_conn_add_write_offset(ctx->h3conn, stream_id, ndatalen); 1810 if(rv) { 1811 failf(x->data, "nghttp3_conn_add_write_offset returned error: %s\n", 1812 nghttp3_strerror(rv)); 1813 return CURLE_SEND_ERROR; 1814 } 1815 } 1816 1817 if(n > 0) { 1818 /* packet assembled, leave */ 1819 *pnread = (size_t)n; 1820 return CURLE_OK; 1821 } 1822 } 1823 } 1824 1825 static CURLcode cf_progress_egress(struct Curl_cfilter *cf, 1826 struct Curl_easy *data, 1827 struct pkt_io_ctx *pktx) 1828 { 1829 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1830 size_t nread; 1831 size_t max_payload_size, path_max_payload_size, max_pktcnt; 1832 size_t pktcnt = 0; 1833 size_t gsolen = 0; /* this disables gso until we have a clue */ 1834 CURLcode curlcode; 1835 struct pkt_io_ctx local_pktx; 1836 1837 if(!pktx) { 1838 pktx_init(&local_pktx, cf, data); 1839 pktx = &local_pktx; 1840 } 1841 else { 1842 pktx_update_time(pktx, cf); 1843 ngtcp2_path_storage_zero(&pktx->ps); 1844 } 1845 1846 curlcode = vquic_flush(cf, data, &ctx->q); 1847 if(curlcode) { 1848 if(curlcode == CURLE_AGAIN) { 1849 Curl_expire(data, 1, EXPIRE_QUIC); 1850 return CURLE_OK; 1851 } 1852 return curlcode; 1853 } 1854 1855 /* In UDP, there is a maximum theoretical packet payload length and 1856 * a minimum payload length that is "guaranteed" to work. 1857 * To detect if this minimum payload can be increased, ngtcp2 sends 1858 * now and then a packet payload larger than the minimum. It that 1859 * is ACKed by the peer, both parties know that it works and 1860 * the subsequent packets can use a larger one. 1861 * This is called PMTUD (Path Maximum Transmission Unit Discovery). 1862 * Since a PMTUD might be rejected right on send, we do not want it 1863 * be followed by other packets of lesser size. Because those would 1864 * also fail then. So, if we detect a PMTUD while buffering, we flush. 1865 */ 1866 max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn); 1867 path_max_payload_size = 1868 ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn); 1869 /* maximum number of packets buffered before we flush to the socket */ 1870 max_pktcnt = CURLMIN(MAX_PKT_BURST, 1871 ctx->q.sendbuf.chunk_size / max_payload_size); 1872 1873 for(;;) { 1874 /* add the next packet to send, if any, to our buffer */ 1875 curlcode = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, 1876 read_pkt_to_send, pktx, &nread); 1877 if(curlcode) { 1878 if(curlcode != CURLE_AGAIN) 1879 return curlcode; 1880 /* Nothing more to add, flush and leave */ 1881 curlcode = vquic_send(cf, data, &ctx->q, gsolen); 1882 if(curlcode) { 1883 if(curlcode == CURLE_AGAIN) { 1884 Curl_expire(data, 1, EXPIRE_QUIC); 1885 return CURLE_OK; 1886 } 1887 return curlcode; 1888 } 1889 goto out; 1890 } 1891 1892 DEBUGASSERT(nread > 0); 1893 if(pktcnt == 0) { 1894 /* first packet in buffer. This is either of a known, "good" 1895 * payload size or it is a PMTUD. We will see. */ 1896 gsolen = nread; 1897 } 1898 else if(nread > gsolen || 1899 (gsolen > path_max_payload_size && nread != gsolen)) { 1900 /* The just added packet is a PMTUD *or* the one(s) before the 1901 * just added were PMTUD and the last one is smaller. 1902 * Flush the buffer before the last add. */ 1903 curlcode = vquic_send_tail_split(cf, data, &ctx->q, 1904 gsolen, nread, nread); 1905 if(curlcode) { 1906 if(curlcode == CURLE_AGAIN) { 1907 Curl_expire(data, 1, EXPIRE_QUIC); 1908 return CURLE_OK; 1909 } 1910 return curlcode; 1911 } 1912 pktcnt = 0; 1913 continue; 1914 } 1915 1916 if(++pktcnt >= max_pktcnt || nread < gsolen) { 1917 /* Reached MAX_PKT_BURST *or* 1918 * the capacity of our buffer *or* 1919 * last add was shorter than the previous ones, flush */ 1920 curlcode = vquic_send(cf, data, &ctx->q, gsolen); 1921 if(curlcode) { 1922 if(curlcode == CURLE_AGAIN) { 1923 Curl_expire(data, 1, EXPIRE_QUIC); 1924 return CURLE_OK; 1925 } 1926 return curlcode; 1927 } 1928 /* pktbuf has been completely sent */ 1929 pktcnt = 0; 1930 } 1931 } 1932 1933 out: 1934 return CURLE_OK; 1935 } 1936 1937 static CURLcode h3_data_pause(struct Curl_cfilter *cf, 1938 struct Curl_easy *data, 1939 bool pause) 1940 { 1941 /* There seems to exist no API in ngtcp2 to shrink/enlarge the streams 1942 * windows. As we do in HTTP/2. */ 1943 (void)cf; 1944 if(!pause) 1945 Curl_multi_mark_dirty(data); 1946 return CURLE_OK; 1947 } 1948 1949 static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, 1950 struct Curl_easy *data, 1951 int event, int arg1, void *arg2) 1952 { 1953 struct cf_ngtcp2_ctx *ctx = cf->ctx; 1954 CURLcode result = CURLE_OK; 1955 struct cf_call_data save; 1956 1957 CF_DATA_SAVE(save, cf, data); 1958 (void)arg1; 1959 (void)arg2; 1960 switch(event) { 1961 case CF_CTRL_DATA_SETUP: 1962 break; 1963 case CF_CTRL_DATA_PAUSE: 1964 result = h3_data_pause(cf, data, (arg1 != 0)); 1965 break; 1966 case CF_CTRL_DATA_DONE: 1967 h3_data_done(cf, data); 1968 break; 1969 case CF_CTRL_DATA_DONE_SEND: { 1970 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1971 if(stream && !stream->send_closed) { 1972 stream->send_closed = TRUE; 1973 stream->upload_left = Curl_bufq_len(&stream->sendbuf) - 1974 stream->sendbuf_len_in_flight; 1975 (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); 1976 } 1977 break; 1978 } 1979 case CF_CTRL_DATA_IDLE: { 1980 struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); 1981 CURL_TRC_CF(data, cf, "data idle"); 1982 if(stream && !stream->closed) { 1983 result = check_and_set_expiry(cf, data, NULL); 1984 if(result) 1985 CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result); 1986 } 1987 break; 1988 } 1989 default: 1990 break; 1991 } 1992 CF_DATA_RESTORE(cf, save); 1993 return result; 1994 } 1995 1996 static void cf_ngtcp2_ctx_close(struct cf_ngtcp2_ctx *ctx) 1997 { 1998 struct cf_call_data save = ctx->call_data; 1999 2000 if(!ctx->initialized) 2001 return; 2002 if(ctx->qlogfd != -1) { 2003 close(ctx->qlogfd); 2004 } 2005 ctx->qlogfd = -1; 2006 Curl_vquic_tls_cleanup(&ctx->tls); 2007 vquic_ctx_free(&ctx->q); 2008 if(ctx->h3conn) { 2009 nghttp3_conn_del(ctx->h3conn); 2010 ctx->h3conn = NULL; 2011 } 2012 if(ctx->qconn) { 2013 ngtcp2_conn_del(ctx->qconn); 2014 ctx->qconn = NULL; 2015 } 2016 #ifdef OPENSSL_QUIC_API2 2017 if(ctx->ossl_ctx) { 2018 ngtcp2_crypto_ossl_ctx_del(ctx->ossl_ctx); 2019 ctx->ossl_ctx = NULL; 2020 } 2021 #endif 2022 ctx->call_data = save; 2023 } 2024 2025 static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf, 2026 struct Curl_easy *data, bool *done) 2027 { 2028 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2029 struct cf_call_data save; 2030 struct pkt_io_ctx pktx; 2031 CURLcode result = CURLE_OK; 2032 2033 if(cf->shutdown || !ctx->qconn) { 2034 *done = TRUE; 2035 return CURLE_OK; 2036 } 2037 2038 CF_DATA_SAVE(save, cf, data); 2039 *done = FALSE; 2040 pktx_init(&pktx, cf, data); 2041 2042 if(!ctx->shutdown_started) { 2043 char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE]; 2044 ngtcp2_ssize nwritten; 2045 2046 if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) { 2047 CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf"); 2048 result = cf_progress_egress(cf, data, &pktx); 2049 if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) { 2050 CURL_TRC_CF(data, cf, "sending shutdown packets blocked"); 2051 result = CURLE_OK; 2052 goto out; 2053 } 2054 else if(result) { 2055 CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result); 2056 *done = TRUE; 2057 goto out; 2058 } 2059 } 2060 2061 DEBUGASSERT(Curl_bufq_is_empty(&ctx->q.sendbuf)); 2062 ctx->shutdown_started = TRUE; 2063 nwritten = ngtcp2_conn_write_connection_close( 2064 ctx->qconn, NULL, /* path */ 2065 NULL, /* pkt_info */ 2066 (uint8_t *)buffer, sizeof(buffer), 2067 &ctx->last_error, pktx.ts); 2068 CURL_TRC_CF(data, cf, "start shutdown(err_type=%d, err_code=%" 2069 FMT_PRIu64 ") -> %d", ctx->last_error.type, 2070 (curl_uint64_t)ctx->last_error.error_code, (int)nwritten); 2071 /* there are cases listed in ngtcp2 documentation where this call 2072 * may fail. Since we are doing a connection shutdown as graceful 2073 * as we can, such an error is ignored here. */ 2074 if(nwritten > 0) { 2075 /* Ignore amount written. sendbuf was empty and has always room for 2076 * NGTCP2_MAX_UDP_PAYLOAD_SIZE. It can only completely fail, in which 2077 * case `result` is set non zero. */ 2078 size_t n; 2079 result = Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer, 2080 (size_t)nwritten, &n); 2081 if(result) { 2082 CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, " 2083 "aborting shutdown", result); 2084 goto out; 2085 } 2086 2087 ctx->q.no_gso = TRUE; 2088 ctx->q.gsolen = (size_t)nwritten; 2089 ctx->q.split_len = 0; 2090 } 2091 } 2092 2093 if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) { 2094 CURL_TRC_CF(data, cf, "shutdown, flushing egress"); 2095 result = vquic_flush(cf, data, &ctx->q); 2096 if(result == CURLE_AGAIN) { 2097 CURL_TRC_CF(data, cf, "sending shutdown packets blocked"); 2098 result = CURLE_OK; 2099 goto out; 2100 } 2101 else if(result) { 2102 CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result); 2103 *done = TRUE; 2104 goto out; 2105 } 2106 } 2107 2108 if(Curl_bufq_is_empty(&ctx->q.sendbuf)) { 2109 /* Sent everything off. ngtcp2 seems to have no support for graceful 2110 * shutdowns. So, we are done. */ 2111 CURL_TRC_CF(data, cf, "shutdown completely sent off, done"); 2112 *done = TRUE; 2113 result = CURLE_OK; 2114 } 2115 out: 2116 CF_DATA_RESTORE(cf, save); 2117 return result; 2118 } 2119 2120 static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf, 2121 struct Curl_easy *data) 2122 { 2123 bool done; 2124 cf_ngtcp2_shutdown(cf, data, &done); 2125 } 2126 2127 static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data) 2128 { 2129 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2130 struct cf_call_data save; 2131 2132 CF_DATA_SAVE(save, cf, data); 2133 if(ctx && ctx->qconn) { 2134 cf_ngtcp2_conn_close(cf, data); 2135 cf_ngtcp2_ctx_close(ctx); 2136 CURL_TRC_CF(data, cf, "close"); 2137 } 2138 cf->connected = FALSE; 2139 CF_DATA_RESTORE(cf, save); 2140 } 2141 2142 static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) 2143 { 2144 CURL_TRC_CF(data, cf, "destroy"); 2145 if(cf->ctx) { 2146 cf_ngtcp2_close(cf, data); 2147 cf_ngtcp2_ctx_free(cf->ctx); 2148 cf->ctx = NULL; 2149 } 2150 } 2151 2152 #ifdef USE_OPENSSL 2153 /* The "new session" callback must return zero if the session can be removed 2154 * or non-zero if the session has been put into the session cache. 2155 */ 2156 static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) 2157 { 2158 struct Curl_cfilter *cf; 2159 struct cf_ngtcp2_ctx *ctx; 2160 struct Curl_easy *data; 2161 ngtcp2_crypto_conn_ref *cref; 2162 2163 cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl); 2164 cf = cref ? cref->user_data : NULL; 2165 ctx = cf ? cf->ctx : NULL; 2166 data = cf ? CF_DATA_CURRENT(cf) : NULL; 2167 if(cf && data && ctx) { 2168 unsigned char *quic_tp = NULL; 2169 size_t quic_tp_len = 0; 2170 #ifdef HAVE_OPENSSL_EARLYDATA 2171 ngtcp2_ssize tplen; 2172 uint8_t tpbuf[256]; 2173 2174 tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf, 2175 sizeof(tpbuf)); 2176 if(tplen < 0) 2177 CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s", 2178 ngtcp2_strerror((int)tplen)); 2179 else { 2180 quic_tp = (unsigned char *)tpbuf; 2181 quic_tp_len = (size_t)tplen; 2182 } 2183 #endif 2184 Curl_ossl_add_session(cf, data, ctx->peer.scache_key, ssl_sessionid, 2185 SSL_version(ssl), "h3", quic_tp, quic_tp_len); 2186 return 1; 2187 } 2188 return 0; 2189 } 2190 #endif /* USE_OPENSSL */ 2191 2192 #ifdef USE_GNUTLS 2193 2194 static const char *gtls_hs_msg_name(int mtype) 2195 { 2196 switch(mtype) { 2197 case 1: return "ClientHello"; 2198 case 2: return "ServerHello"; 2199 case 4: return "SessionTicket"; 2200 case 8: return "EncryptedExtensions"; 2201 case 11: return "Certificate"; 2202 case 13: return "CertificateRequest"; 2203 case 15: return "CertificateVerify"; 2204 case 20: return "Finished"; 2205 case 24: return "KeyUpdate"; 2206 case 254: return "MessageHash"; 2207 } 2208 return "Unknown"; 2209 } 2210 2211 static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype, 2212 unsigned when, unsigned int incoming, 2213 const gnutls_datum_t *msg) 2214 { 2215 ngtcp2_crypto_conn_ref *conn_ref = gnutls_session_get_ptr(session); 2216 struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL; 2217 struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL; 2218 2219 (void)msg; 2220 (void)incoming; 2221 if(when && cf && ctx) { /* after message has been processed */ 2222 struct Curl_easy *data = CF_DATA_CURRENT(cf); 2223 DEBUGASSERT(data); 2224 if(!data) 2225 return 0; 2226 CURL_TRC_CF(data, cf, "SSL message: %s %s [%d]", 2227 incoming ? "<-" : "->", gtls_hs_msg_name(htype), htype); 2228 switch(htype) { 2229 case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: { 2230 ngtcp2_ssize tplen; 2231 uint8_t tpbuf[256]; 2232 unsigned char *quic_tp = NULL; 2233 size_t quic_tp_len = 0; 2234 2235 tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf, 2236 sizeof(tpbuf)); 2237 if(tplen < 0) 2238 CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s", 2239 ngtcp2_strerror((int)tplen)); 2240 else { 2241 quic_tp = (unsigned char *)tpbuf; 2242 quic_tp_len = (size_t)tplen; 2243 } 2244 (void)Curl_gtls_cache_session(cf, data, ctx->peer.scache_key, 2245 session, 0, "h3", quic_tp, quic_tp_len); 2246 break; 2247 } 2248 default: 2249 break; 2250 } 2251 } 2252 return 0; 2253 } 2254 #endif /* USE_GNUTLS */ 2255 2256 #ifdef USE_WOLFSSL 2257 static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session) 2258 { 2259 ngtcp2_crypto_conn_ref *conn_ref = wolfSSL_get_app_data(ssl); 2260 struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL; 2261 2262 DEBUGASSERT(cf != NULL); 2263 if(cf && session) { 2264 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2265 struct Curl_easy *data = CF_DATA_CURRENT(cf); 2266 DEBUGASSERT(data); 2267 if(data && ctx) { 2268 ngtcp2_ssize tplen; 2269 uint8_t tpbuf[256]; 2270 unsigned char *quic_tp = NULL; 2271 size_t quic_tp_len = 0; 2272 2273 tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf, 2274 sizeof(tpbuf)); 2275 if(tplen < 0) 2276 CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s", 2277 ngtcp2_strerror((int)tplen)); 2278 else { 2279 quic_tp = (unsigned char *)tpbuf; 2280 quic_tp_len = (size_t)tplen; 2281 } 2282 (void)Curl_wssl_cache_session(cf, data, ctx->peer.scache_key, 2283 session, wolfSSL_version(ssl), 2284 "h3", quic_tp, quic_tp_len); 2285 } 2286 } 2287 return 0; 2288 } 2289 #endif /* USE_WOLFSSL */ 2290 2291 static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf, 2292 struct Curl_easy *data, 2293 void *user_data) 2294 { 2295 struct curl_tls_ctx *ctx = user_data; 2296 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); 2297 2298 #ifdef USE_OPENSSL 2299 #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) 2300 if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx) 2301 != 0) { 2302 failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed"); 2303 return CURLE_FAILED_INIT; 2304 } 2305 #elif defined(OPENSSL_QUIC_API2) 2306 /* nothing to do */ 2307 #else 2308 if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) { 2309 failf(data, "ngtcp2_crypto_quictls_configure_client_context failed"); 2310 return CURLE_FAILED_INIT; 2311 } 2312 #endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */ 2313 if(ssl_config->primary.cache_session) { 2314 /* Enable the session cache because it is a prerequisite for the 2315 * "new session" callback. Use the "external storage" mode to prevent 2316 * OpenSSL from creating an internal session cache. 2317 */ 2318 SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx, 2319 SSL_SESS_CACHE_CLIENT | 2320 SSL_SESS_CACHE_NO_INTERNAL); 2321 SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb); 2322 } 2323 2324 #elif defined(USE_GNUTLS) 2325 if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) { 2326 failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed"); 2327 return CURLE_FAILED_INIT; 2328 } 2329 if(ssl_config->primary.cache_session) { 2330 gnutls_handshake_set_hook_function(ctx->gtls.session, 2331 GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, 2332 quic_gtls_handshake_cb); 2333 } 2334 2335 #elif defined(USE_WOLFSSL) 2336 if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ssl_ctx) != 0) { 2337 failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed"); 2338 return CURLE_FAILED_INIT; 2339 } 2340 if(ssl_config->primary.cache_session) { 2341 /* Register to get notified when a new session is received */ 2342 wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ssl_ctx, wssl_quic_new_session_cb); 2343 } 2344 #endif 2345 return CURLE_OK; 2346 } 2347 2348 static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf, 2349 struct Curl_easy *data, 2350 struct alpn_spec *alpns, 2351 struct Curl_ssl_session *scs, 2352 bool *do_early_data) 2353 { 2354 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2355 CURLcode result = CURLE_OK; 2356 2357 *do_early_data = FALSE; 2358 #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA) 2359 ctx->earlydata_max = scs->earlydata_max; 2360 #endif 2361 #ifdef USE_GNUTLS 2362 ctx->earlydata_max = 2363 gnutls_record_get_max_early_data_size(ctx->tls.gtls.session); 2364 #endif 2365 #ifdef USE_WOLFSSL 2366 #ifdef WOLFSSL_EARLY_DATA 2367 ctx->earlydata_max = scs->earlydata_max; 2368 #else 2369 ctx->earlydata_max = 0; 2370 #endif /* WOLFSSL_EARLY_DATA */ 2371 #endif 2372 #if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \ 2373 (defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)) 2374 if((!ctx->earlydata_max)) { 2375 CURL_TRC_CF(data, cf, "SSL session does not allow earlydata"); 2376 } 2377 else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) { 2378 CURL_TRC_CF(data, cf, "SSL session from different ALPN, no early data"); 2379 } 2380 else if(!scs->quic_tp || !scs->quic_tp_len) { 2381 CURL_TRC_CF(data, cf, "no 0RTT transport parameters, no early data, "); 2382 } 2383 else { 2384 int rv; 2385 rv = ngtcp2_conn_decode_and_set_0rtt_transport_params( 2386 ctx->qconn, (const uint8_t *)scs->quic_tp, scs->quic_tp_len); 2387 if(rv) 2388 CURL_TRC_CF(data, cf, "no early data, failed to set 0RTT transport " 2389 "parameters: %s", ngtcp2_strerror(rv)); 2390 else { 2391 infof(data, "SSL session allows %zu bytes of early data, " 2392 "reusing ALPN '%s'", ctx->earlydata_max, scs->alpn); 2393 result = init_ngh3_conn(cf, data); 2394 if(!result) { 2395 ctx->use_earlydata = TRUE; 2396 cf->connected = TRUE; 2397 *do_early_data = TRUE; 2398 } 2399 } 2400 } 2401 #else /* not supported in the TLS backend */ 2402 (void)data; 2403 (void)ctx; 2404 (void)scs; 2405 (void)alpns; 2406 #endif 2407 return result; 2408 } 2409 2410 /* 2411 * Might be called twice for happy eyeballs. 2412 */ 2413 static CURLcode cf_connect_start(struct Curl_cfilter *cf, 2414 struct Curl_easy *data, 2415 struct pkt_io_ctx *pktx) 2416 { 2417 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2418 int rc; 2419 int rv; 2420 CURLcode result; 2421 const struct Curl_sockaddr_ex *sockaddr = NULL; 2422 int qfd; 2423 static const struct alpn_spec ALPN_SPEC_H3 = { 2424 { "h3", "h3-29" }, 2 2425 }; 2426 2427 DEBUGASSERT(ctx->initialized); 2428 ctx->dcid.datalen = NGTCP2_MAX_CIDLEN; 2429 result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN); 2430 if(result) 2431 return result; 2432 2433 ctx->scid.datalen = NGTCP2_MAX_CIDLEN; 2434 result = Curl_rand(data, ctx->scid.data, NGTCP2_MAX_CIDLEN); 2435 if(result) 2436 return result; 2437 2438 (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd); 2439 ctx->qlogfd = qfd; /* -1 if failure above */ 2440 quic_settings(ctx, data, pktx); 2441 2442 result = vquic_ctx_init(&ctx->q); 2443 if(result) 2444 return result; 2445 2446 Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL); 2447 if(!sockaddr) 2448 return CURLE_QUIC_CONNECT_ERROR; 2449 ctx->q.local_addrlen = sizeof(ctx->q.local_addr); 2450 rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr, 2451 &ctx->q.local_addrlen); 2452 if(rv == -1) 2453 return CURLE_QUIC_CONNECT_ERROR; 2454 2455 ngtcp2_addr_init(&ctx->connected_path.local, 2456 (struct sockaddr *)&ctx->q.local_addr, 2457 ctx->q.local_addrlen); 2458 ngtcp2_addr_init(&ctx->connected_path.remote, 2459 &sockaddr->curl_sa_addr, (socklen_t)sockaddr->addrlen); 2460 2461 rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid, 2462 &ctx->connected_path, 2463 NGTCP2_PROTO_VER_V1, &ng_callbacks, 2464 &ctx->settings, &ctx->transport_params, 2465 NULL, cf); 2466 if(rc) 2467 return CURLE_QUIC_CONNECT_ERROR; 2468 2469 ctx->conn_ref.get_conn = get_conn; 2470 ctx->conn_ref.user_data = cf; 2471 2472 result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, &ALPN_SPEC_H3, 2473 cf_ngtcp2_tls_ctx_setup, &ctx->tls, 2474 &ctx->conn_ref, 2475 cf_ngtcp2_on_session_reuse); 2476 if(result) 2477 return result; 2478 2479 #if defined(USE_OPENSSL) && defined(OPENSSL_QUIC_API2) 2480 if(ngtcp2_crypto_ossl_ctx_new(&ctx->ossl_ctx, ctx->tls.ossl.ssl) != 0) { 2481 failf(data, "ngtcp2_crypto_ossl_ctx_new failed"); 2482 return CURLE_FAILED_INIT; 2483 } 2484 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->ossl_ctx); 2485 if(ngtcp2_crypto_ossl_configure_client_session(ctx->tls.ossl.ssl) != 0) { 2486 failf(data, "ngtcp2_crypto_ossl_configure_client_session failed"); 2487 return CURLE_FAILED_INIT; 2488 } 2489 #elif defined(USE_OPENSSL) 2490 SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0); 2491 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl); 2492 #elif defined(USE_GNUTLS) 2493 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session); 2494 #elif defined(USE_WOLFSSL) 2495 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.ssl); 2496 #else 2497 #error "ngtcp2 TLS backend not defined" 2498 #endif 2499 2500 ngtcp2_ccerr_default(&ctx->last_error); 2501 2502 return CURLE_OK; 2503 } 2504 2505 static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, 2506 struct Curl_easy *data, 2507 bool *done) 2508 { 2509 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2510 CURLcode result = CURLE_OK; 2511 struct cf_call_data save; 2512 struct curltime now; 2513 struct pkt_io_ctx pktx; 2514 2515 if(cf->connected) { 2516 *done = TRUE; 2517 return CURLE_OK; 2518 } 2519 2520 /* Connect the UDP filter first */ 2521 if(!cf->next->connected) { 2522 result = Curl_conn_cf_connect(cf->next, data, done); 2523 if(result || !*done) 2524 return result; 2525 } 2526 2527 *done = FALSE; 2528 now = curlx_now(); 2529 pktx_init(&pktx, cf, data); 2530 2531 CF_DATA_SAVE(save, cf, data); 2532 2533 if(!ctx->qconn) { 2534 ctx->started_at = now; 2535 result = cf_connect_start(cf, data, &pktx); 2536 if(result) 2537 goto out; 2538 if(cf->connected) { 2539 cf->conn->alpn = CURL_HTTP_VERSION_3; 2540 *done = TRUE; 2541 goto out; 2542 } 2543 result = cf_progress_egress(cf, data, &pktx); 2544 /* we do not expect to be able to recv anything yet */ 2545 goto out; 2546 } 2547 2548 result = cf_progress_ingress(cf, data, &pktx); 2549 if(result) 2550 goto out; 2551 2552 result = cf_progress_egress(cf, data, &pktx); 2553 if(result) 2554 goto out; 2555 2556 if(ngtcp2_conn_get_handshake_completed(ctx->qconn)) { 2557 result = ctx->tls_vrfy_result; 2558 if(!result) { 2559 CURL_TRC_CF(data, cf, "peer verified"); 2560 cf->connected = TRUE; 2561 cf->conn->alpn = CURL_HTTP_VERSION_3; 2562 *done = TRUE; 2563 connkeep(cf->conn, "HTTP/3 default"); 2564 } 2565 } 2566 2567 out: 2568 if(result == CURLE_RECV_ERROR && ctx->qconn && 2569 ngtcp2_conn_in_draining_period(ctx->qconn)) { 2570 /* When a QUIC server instance is shutting down, it may send us a 2571 * CONNECTION_CLOSE right away. Our connection then enters the DRAINING 2572 * state. The CONNECT may work in the near future again. Indicate 2573 * that as a "weird" reply. */ 2574 result = CURLE_WEIRD_SERVER_REPLY; 2575 } 2576 2577 #ifndef CURL_DISABLE_VERBOSE_STRINGS 2578 if(result) { 2579 struct ip_quadruple ip; 2580 2581 Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip); 2582 infof(data, "QUIC connect to %s port %u failed: %s", 2583 ip.remote_ip, ip.remote_port, curl_easy_strerror(result)); 2584 } 2585 #endif 2586 if(!result && ctx->qconn) { 2587 result = check_and_set_expiry(cf, data, &pktx); 2588 } 2589 if(result || *done) 2590 CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done); 2591 CF_DATA_RESTORE(cf, save); 2592 return result; 2593 } 2594 2595 static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, 2596 struct Curl_easy *data, 2597 int query, int *pres1, void *pres2) 2598 { 2599 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2600 struct cf_call_data save; 2601 2602 switch(query) { 2603 case CF_QUERY_MAX_CONCURRENT: { 2604 DEBUGASSERT(pres1); 2605 CF_DATA_SAVE(save, cf, data); 2606 /* Set after transport params arrived and continually updated 2607 * by callback. QUIC counts the number over the lifetime of the 2608 * connection, ever increasing. 2609 * We count the *open* transfers plus the budget for new ones. */ 2610 if(!ctx->qconn || ctx->shutdown_started) { 2611 *pres1 = 0; 2612 } 2613 else if(ctx->max_bidi_streams) { 2614 uint64_t avail_bidi_streams = 0; 2615 uint64_t max_streams = CONN_ATTACHED(cf->conn); 2616 if(ctx->max_bidi_streams > ctx->used_bidi_streams) 2617 avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams; 2618 max_streams += avail_bidi_streams; 2619 *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams; 2620 } 2621 else /* transport params not arrived yet? take our default. */ 2622 *pres1 = (int)Curl_multi_max_concurrent_streams(data->multi); 2623 CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: " 2624 "MAX_CONCURRENT -> %d (%u in use)", 2625 cf->conn->connection_id, *pres1, CONN_ATTACHED(cf->conn)); 2626 CF_DATA_RESTORE(cf, save); 2627 return CURLE_OK; 2628 } 2629 case CF_QUERY_CONNECT_REPLY_MS: 2630 if(ctx->q.got_first_byte) { 2631 timediff_t ms = curlx_timediff(ctx->q.first_byte_at, ctx->started_at); 2632 *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX; 2633 } 2634 else 2635 *pres1 = -1; 2636 return CURLE_OK; 2637 case CF_QUERY_TIMER_CONNECT: { 2638 struct curltime *when = pres2; 2639 if(ctx->q.got_first_byte) 2640 *when = ctx->q.first_byte_at; 2641 return CURLE_OK; 2642 } 2643 case CF_QUERY_TIMER_APPCONNECT: { 2644 struct curltime *when = pres2; 2645 if(cf->connected) 2646 *when = ctx->handshake_at; 2647 return CURLE_OK; 2648 } 2649 case CF_QUERY_HTTP_VERSION: 2650 *pres1 = 30; 2651 return CURLE_OK; 2652 case CF_QUERY_SSL_INFO: 2653 case CF_QUERY_SSL_CTX_INFO: { 2654 struct curl_tlssessioninfo *info = pres2; 2655 if(Curl_vquic_tls_get_ssl_info(&ctx->tls, 2656 (query == CF_QUERY_SSL_INFO), info)) 2657 return CURLE_OK; 2658 break; 2659 } 2660 default: 2661 break; 2662 } 2663 return cf->next ? 2664 cf->next->cft->query(cf->next, data, query, pres1, pres2) : 2665 CURLE_UNKNOWN_OPTION; 2666 } 2667 2668 static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, 2669 struct Curl_easy *data, 2670 bool *input_pending) 2671 { 2672 struct cf_ngtcp2_ctx *ctx = cf->ctx; 2673 bool alive = FALSE; 2674 const ngtcp2_transport_params *rp; 2675 struct cf_call_data save; 2676 2677 CF_DATA_SAVE(save, cf, data); 2678 *input_pending = FALSE; 2679 if(!ctx->qconn || ctx->shutdown_started) 2680 goto out; 2681 2682 /* We do not announce a max idle timeout, but when the peer does 2683 * it will close the connection when it expires. */ 2684 rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn); 2685 if(rp && rp->max_idle_timeout) { 2686 timediff_t idletime = curlx_timediff(curlx_now(), ctx->q.last_io); 2687 if(idletime > 0 && (uint64_t)idletime > rp->max_idle_timeout) 2688 goto out; 2689 } 2690 2691 if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) 2692 goto out; 2693 2694 alive = TRUE; 2695 if(*input_pending) { 2696 CURLcode result; 2697 /* This happens before we have sent off a request and the connection is 2698 not in use by any other transfer, there should not be any data here, 2699 only "protocol frames" */ 2700 *input_pending = FALSE; 2701 result = cf_progress_ingress(cf, data, NULL); 2702 CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result); 2703 alive = result ? FALSE : TRUE; 2704 } 2705 2706 out: 2707 CF_DATA_RESTORE(cf, save); 2708 return alive; 2709 } 2710 2711 struct Curl_cftype Curl_cft_http3 = { 2712 "HTTP/3", 2713 CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX | CF_TYPE_HTTP, 2714 0, 2715 cf_ngtcp2_destroy, 2716 cf_ngtcp2_connect, 2717 cf_ngtcp2_close, 2718 cf_ngtcp2_shutdown, 2719 cf_ngtcp2_adjust_pollset, 2720 Curl_cf_def_data_pending, 2721 cf_ngtcp2_send, 2722 cf_ngtcp2_recv, 2723 cf_ngtcp2_data_event, 2724 cf_ngtcp2_conn_is_alive, 2725 Curl_cf_def_conn_keep_alive, 2726 cf_ngtcp2_query, 2727 }; 2728 2729 CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, 2730 struct Curl_easy *data, 2731 struct connectdata *conn, 2732 const struct Curl_addrinfo *ai) 2733 { 2734 struct cf_ngtcp2_ctx *ctx = NULL; 2735 struct Curl_cfilter *cf = NULL, *udp_cf = NULL; 2736 CURLcode result; 2737 2738 (void)data; 2739 ctx = calloc(1, sizeof(*ctx)); 2740 if(!ctx) { 2741 result = CURLE_OUT_OF_MEMORY; 2742 goto out; 2743 } 2744 cf_ngtcp2_ctx_init(ctx); 2745 2746 result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); 2747 if(result) 2748 goto out; 2749 2750 result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC); 2751 if(result) 2752 goto out; 2753 2754 cf->conn = conn; 2755 udp_cf->conn = cf->conn; 2756 udp_cf->sockindex = cf->sockindex; 2757 cf->next = udp_cf; 2758 2759 out: 2760 *pcf = (!result) ? cf : NULL; 2761 if(result) { 2762 if(udp_cf) 2763 Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE); 2764 Curl_safefree(cf); 2765 cf_ngtcp2_ctx_free(ctx); 2766 } 2767 return result; 2768 } 2769 2770 bool Curl_conn_is_ngtcp2(const struct Curl_easy *data, 2771 const struct connectdata *conn, 2772 int sockindex) 2773 { 2774 struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; 2775 2776 (void)data; 2777 for(; cf; cf = cf->next) { 2778 if(cf->cft == &Curl_cft_http3) 2779 return TRUE; 2780 if(cf->cft->flags & CF_TYPE_IP_CONNECT) 2781 return FALSE; 2782 } 2783 return FALSE; 2784 } 2785 2786 #endif