quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

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