Coverage Report

Created: 2026-10-15 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/vquic/cf-ngtcp2-cmn.c
Line
Count
Source
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
#include "curl_setup.h"
25
26
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGTCP2) && defined(USE_NGHTTP3)
27
28
#include <ngtcp2/ngtcp2.h>
29
30
#ifdef USE_OPENSSL
31
#include <openssl/err.h>
32
#if defined(OPENSSL_IS_AWSLC) || defined(OPENSSL_IS_BORINGSSL)
33
#include <ngtcp2/ngtcp2_crypto_boringssl.h>
34
#elif defined(OPENSSL_QUIC_API2)
35
#include <ngtcp2/ngtcp2_crypto_ossl.h>
36
#else
37
#include <ngtcp2/ngtcp2_crypto_quictls.h>
38
#endif
39
#include "vtls/openssl.h"
40
#elif defined(USE_GNUTLS)
41
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
42
#include "vtls/gtls.h"
43
#elif defined(USE_WOLFSSL)
44
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
45
#include "vtls/wolfssl.h"
46
#endif
47
48
#include <nghttp3/nghttp3.h>
49
50
#include "urldata.h"
51
#include "url.h"
52
#include "u32_ptrset.h"
53
#include "curl_trc.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 "curlx/win32-fopen.h"
61
#include "curlx/dynbuf.h"
62
#include "http1.h"
63
#include "select.h"
64
#include "sockaddr.h"
65
#include "transfer.h"
66
#include "bufref.h"
67
#include "vdns/cf-dns.h"
68
#include "vquic/vquic.h"
69
#include "vquic/vquic_int.h"
70
#include "vquic/vquic-tls.h"
71
#include "vtls/vtls.h"
72
#include "vtls/vtls_scache.h"
73
#include "vquic/cf-ngtcp2-cmn.h"
74
75
/*
76
 * Store ngtcp2 version info in this buffer.
77
 */
78
void Curl_ngtcp2_ver(char *p, size_t len)
79
0
{
80
0
  const ngtcp2_info *ng2 = ngtcp2_version(0);
81
0
  const nghttp3_info *ht3 = nghttp3_version(0);
82
0
  (void)curl_msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
83
0
                       ng2->version_str, ht3->version_str);
84
0
}
85
86
void Curl_cf_ngtcp2_h3_stream_ctx_free(struct h3_stream_ctx *stream)
87
4.36k
{
88
4.36k
  Curl_bufq_free(&stream->sendbuf);
89
4.36k
  Curl_h1_req_parse_free(&stream->h1);
90
4.36k
  curlx_free(stream);
91
4.36k
}
92
93
static void h3_stream_set_free(uint32_t id, void *stream)
94
4.36k
{
95
4.36k
  (void)id;
96
4.36k
  DEBUGASSERT(stream);
97
4.36k
  Curl_cf_ngtcp2_h3_stream_ctx_free((struct h3_stream_ctx *)stream);
98
4.36k
}
99
100
static bool cf_ngtcp2_h3_err_is_fatal(int code)
101
5
{
102
5
  return (NGHTTP3_ERR_FATAL >= code) ||
103
5
         (NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM == code);
104
5
}
105
106
void Curl_cf_ngtcp2_h3_err_set(struct Curl_cfilter *cf,
107
                               struct Curl_easy *data, int code)
108
5
{
109
5
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
110
5
  if(!ctx->last_error.error_code) {
111
5
    ngtcp2_ccerr_set_application_error(&ctx->last_error,
112
5
      nghttp3_err_infer_quic_app_error_code(code), NULL, 0);
113
5
  }
114
5
  if(cf_ngtcp2_h3_err_is_fatal(code))
115
5
    Curl_cf_ngtcp2_cmn_conn_close(cf, data);
116
5
}
117
118
CURLcode Curl_cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx,
119
                                 struct Curl_peer *origin,
120
                                 struct Curl_peer *peer,
121
                                 struct ssl_filter_config *sslc,
122
                                 cf_ngtcp2_init_h3_conn *init_h3_conn_cb)
123
5.78k
{
124
5.78k
  DEBUGASSERT(!ctx->initialized);
125
5.78k
  ctx->qlogfd = -1;
126
5.78k
  ctx->tunnel_inbuf = NULL;
127
5.78k
  ctx->tunnel_inbuf_len = 0;
128
5.78k
  ctx->version = NGTCP2_PROTO_VER_MAX;
129
5.78k
  Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
130
5.78k
                  H3_STREAM_POOL_SPARES);
131
5.78k
  curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
132
5.78k
  Curl_u32_ptrset_init(&ctx->streams, h3_stream_set_free);
133
5.78k
  ctx->init_h3_conn_cb = init_h3_conn_cb;
134
5.78k
  ctx->initialized = TRUE;
135
5.78k
  return Curl_vquic_tls_peer_init(origin, peer, sslc, &ctx->ssl_peer);
136
5.78k
}
137
138
void Curl_cf_ngtcp2_ctx_cleanup(struct cf_ngtcp2_ctx *ctx)
139
5.78k
{
140
5.78k
  if(ctx && ctx->initialized) {
141
5.78k
    if(ctx->qlogfd != -1) {
142
0
      curlx_close(ctx->qlogfd);
143
0
      ctx->qlogfd = -1;
144
0
    }
145
    /* Cleanup TLS instances first as ngtcp2 objects
146
     * might be registered there. */
147
5.78k
    Curl_vquic_tls_cleanup(&ctx->tls);
148
5.78k
    Curl_vquic_ctx_free(&ctx->q);
149
5.78k
    if(ctx->h3conn) {
150
4.37k
      nghttp3_conn_del(ctx->h3conn);
151
4.37k
      ctx->h3conn = NULL;
152
4.37k
    }
153
5.78k
    if(ctx->qconn) {
154
5.74k
      ngtcp2_conn_del(ctx->qconn);
155
5.74k
      ctx->qconn = NULL;
156
5.74k
    }
157
5.78k
#ifdef OPENSSL_QUIC_API2
158
5.78k
    if(ctx->ossl_ctx) {
159
5.74k
      ngtcp2_crypto_ossl_ctx_del(ctx->ossl_ctx);
160
5.74k
      ctx->ossl_ctx = NULL;
161
5.74k
    }
162
5.78k
#endif
163
5.78k
    Curl_bufcp_free(&ctx->stream_bufcp);
164
5.78k
    curlx_dyn_free(&ctx->scratch);
165
5.78k
    Curl_u32_ptrset_clear(&ctx->streams);
166
5.78k
    Curl_ssl_peer_cleanup(&ctx->ssl_peer);
167
5.78k
    curlx_safefree(ctx->tunnel_inbuf);
168
5.78k
    ctx->tunnel_inbuf_len = 0;
169
5.78k
  }
170
5.78k
}
171
172
struct Curl_easy *Curl_cf_ngtcp2_get_xfer(struct Curl_cfilter *cf,
173
                                          void *stream_user_data,
174
                                          struct h3_stream_ctx **pstream)
175
24.7k
{
176
24.7k
  struct h3_stream_ctx *stream = stream_user_data;
177
178
24.7k
  if(pstream)
179
22.5k
    *pstream = stream;
180
24.7k
  if(stream && (stream->mid != UINT32_MAX)) {
181
10.4k
    struct Curl_easy *data, *call_data = CF_DATA_CURRENT(cf);
182
10.4k
    if(!call_data || !call_data->multi) {
183
0
      DEBUGASSERT(0);
184
0
      return NULL;
185
0
    }
186
10.4k
    data = Curl_multi_get_easy(call_data->multi, stream->mid);
187
10.4k
    if(data && (data->id == stream->xfer_id))
188
10.4k
      return data;
189
0
    DEBUGASSERT(0);
190
0
  }
191
14.3k
  return NULL;
192
24.7k
}
193
194
static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
195
91.0k
{
196
91.0k
  struct Curl_cfilter *cf = conn_ref->user_data;
197
91.0k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
198
91.0k
  return ctx->qconn;
199
91.0k
}
200
201
#ifdef DEBUG_NGTCP2
202
static void quic_printf(void *user_data, const char *fmt, ...)
203
{
204
  va_list ap;
205
  (void)user_data;
206
  va_start(ap, fmt);
207
  curl_mvfprintf(stderr, fmt, ap);
208
  va_end(ap);
209
  curl_mfprintf(stderr, "\n");
210
}
211
#endif
212
213
static void qlog_callback(void *user_data, uint32_t flags,
214
                          const void *data, size_t datalen)
215
0
{
216
0
  struct Curl_cfilter *cf = user_data;
217
0
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
218
0
  (void)flags;
219
0
  if(ctx->qlogfd != -1) {
220
0
    ssize_t rc = write(ctx->qlogfd, data, datalen);
221
0
    if(rc == -1) {
222
      /* on write error, stop further write attempts */
223
0
      curlx_close(ctx->qlogfd);
224
0
      ctx->qlogfd = -1;
225
0
    }
226
0
  }
227
0
}
228
229
static void quic_settings(struct cf_ngtcp2_ctx *ctx,
230
                          struct Curl_easy *data,
231
                          struct cf_ngtcp2_io_ctx *pktx)
232
5.76k
{
233
5.76k
  ngtcp2_settings *s = &ctx->settings;
234
5.76k
  ngtcp2_transport_params *t = &ctx->transport_params;
235
236
5.76k
  ngtcp2_settings_default(s);
237
5.76k
  ngtcp2_transport_params_default(t);
238
#ifdef DEBUG_NGTCP2
239
  s->log_printf = quic_printf;
240
#else
241
5.76k
  s->log_printf = NULL;
242
5.76k
#endif
243
244
5.76k
  s->initial_ts = pktx->ts;
245
5.76k
  s->handshake_timeout = (data->set.connecttimeout > 0) ?
246
5.76k
    data->set.connecttimeout * NGTCP2_MILLISECONDS : QUIC_HANDSHAKE_TIMEOUT;
247
5.76k
  s->max_window = H3_CONN_WINDOW_SIZE_MAX;
248
5.76k
  s->max_stream_window = 0; /* disable ngtcp2 auto-tuning of window */
249
5.76k
  s->no_pmtud = FALSE;
250
5.76k
#ifdef NGTCP2_SETTINGS_V3
251
  /* try ten times the ngtcp2 defaults here for problems with Caddy */
252
5.76k
  s->glitch_ratelim_burst = 1000 * 10;
253
5.76k
  s->glitch_ratelim_rate = 33 * 10;
254
5.76k
#endif
255
5.76k
  t->initial_max_data = s->max_window;
256
5.76k
  t->initial_max_stream_data_bidi_local = H3_STREAM_WINDOW_SIZE_INITIAL;
257
5.76k
  t->initial_max_stream_data_bidi_remote = H3_STREAM_WINDOW_SIZE_INITIAL;
258
5.76k
  t->initial_max_stream_data_uni = t->initial_max_data;
259
5.76k
  t->initial_max_streams_bidi = QUIC_MAX_STREAMS;
260
5.76k
  t->initial_max_streams_uni = QUIC_MAX_STREAMS;
261
5.76k
  t->max_idle_timeout = 0; /* no idle timeout from our side */
262
5.76k
  if(ctx->qlogfd != -1) {
263
0
    s->qlog_write = qlog_callback;
264
0
  }
265
5.76k
}
266
267
#if defined(_MSC_VER) && defined(_DLL)
268
#pragma warning(push)
269
#pragma warning(disable:4232) /* MSVC extension, dllimport identity */
270
#endif
271
272
static int cb_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data)
273
4.37k
{
274
4.37k
  struct Curl_cfilter *cf = user_data;
275
4.37k
  struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL;
276
4.37k
  struct Curl_easy *data;
277
278
4.37k
  (void)tconn;
279
4.37k
  DEBUGASSERT(ctx);
280
4.37k
  data = CF_DATA_CURRENT(cf);
281
4.37k
  DEBUGASSERT(data);
282
4.37k
  if(!ctx || !data)
283
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
284
285
4.37k
  ctx->handshake_at = *Curl_pgrs_now(data);
286
4.37k
  ctx->tls_handshake_complete = TRUE;
287
4.37k
  Curl_vquic_report_handshake(&ctx->tls, cf, data);
288
289
4.37k
  ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf,
290
4.37k
                                                    data, &ctx->ssl_peer);
291
4.37k
  if(ctx->tls_vrfy_result)
292
2
    return NGTCP2_ERR_CALLBACK_FAILURE;
293
294
4.37k
#ifdef CURLVERBOSE
295
4.37k
  if(Curl_trc_is_verbose(data)) {
296
80
    const ngtcp2_transport_params *rp;
297
80
    rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
298
80
    CURL_TRC_CF(data, cf, "handshake complete after %" FMT_TIMEDIFF_T
299
80
                "ms, remote transport[max_udp_payload=%" PRIu64
300
80
                ", initial_max_data=%" PRIu64 "]",
301
80
                curlx_ptimediff_ms(&ctx->handshake_at, &ctx->started_at),
302
80
                rp->max_udp_payload_size, rp->initial_max_data);
303
80
  }
304
4.37k
#endif
305
306
  /* In case of earlydata, where we simulate being connected, update
307
   * the handshake time when we really did connect */
308
4.37k
  if(ctx->use_earlydata && !ctx->stats_reported &&
309
0
     !(cf->cft->flags & CF_TYPE_PROXY)) {
310
0
    Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
311
0
    ctx->stats_reported = TRUE;
312
0
  }
313
4.37k
  if(ctx->use_earlydata) {
314
0
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)
315
    /* Check for bug that OpenSSL did not even send the early data. */
316
0
    if(SSL_get_early_data_status(ctx->tls.ossl.ssl) == SSL_EARLY_DATA_NOT_SENT)
317
0
      CURL_TRC_CF(data, cf, "OpenSSL did not send early data");
318
0
#endif
319
320
0
#if NGTCP2_VERSION_NUM >= 0x011700
321
0
    ctx->earlydata_accepted =
322
0
      !ngtcp2_conn_get_tls_early_data_rejected2(ctx->qconn);
323
#else /* older NGTCP2 */
324
    {
325
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)
326
      int ossl_early_status = SSL_get_early_data_status(ctx->tls.ossl.ssl);
327
      if(ossl_early_status == SSL_EARLY_DATA_NOT_SENT)
328
        CURL_TRC_CF(data, cf, "OpenSSL did not send early data");
329
      ctx->earlydata_accepted = (ossl_early_status == SSL_EARLY_DATA_ACCEPTED);
330
#elif defined(USE_GNUTLS)
331
      int flags = gnutls_session_get_flags(ctx->tls.gtls.session);
332
      ctx->earlydata_accepted = !!(flags & GNUTLS_SFLAGS_EARLY_DATA);
333
#elif defined(USE_WOLFSSL)
334
#ifdef WOLFSSL_EARLY_DATA
335
      ctx->earlydata_accepted =
336
        (wolfSSL_get_early_data_status(ctx->tls.wssl.ssl) !=
337
         WOLFSSL_EARLY_DATA_REJECTED);
338
#else
339
      DEBUGASSERT(0); /* should not come here if ED is disabled. */
340
      ctx->earlydata_accepted = FALSE;
341
#endif /* WOLFSSL_EARLY_DATA */
342
#endif /* OPENSSL or GNUTLS or WOLFSSL */
343
    }
344
#endif /* older NGTCP2 */
345
0
    CURL_TRC_CF(data, cf, "server did%s accept %zu bytes of early data",
346
0
                ctx->earlydata_accepted ? "" : " not", ctx->earlydata_skip);
347
0
    Curl_pgrsEarlyData(data, ctx->earlydata_accepted ?
348
0
                              (curl_off_t)ctx->earlydata_skip :
349
0
                             -(curl_off_t)ctx->earlydata_skip);
350
0
  }
351
4.37k
  return 0;
352
4.37k
}
353
354
static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
355
                               int64_t stream_id, uint64_t offset,
356
                               const uint8_t *buf, size_t buflen,
357
                               void *user_data, void *stream_user_data)
358
15.7k
{
359
15.7k
  struct Curl_cfilter *cf = user_data;
360
15.7k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
361
15.7k
  nghttp3_ssize rc;
362
15.7k
  uint64_t nconsumed;
363
15.7k
  int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
364
15.7k
  struct h3_stream_ctx *stream;
365
15.7k
  struct Curl_easy *data =
366
15.7k
    Curl_cf_ngtcp2_get_xfer(cf, stream_user_data, &stream);
367
368
15.7k
  (void)offset;
369
15.7k
  rc = nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin);
370
15.7k
  if(rc < 0) {
371
52
    if(data && stream) {
372
43
      CURL_TRC_CF(data, cf, "[%" PRId64 "] error on known stream, "
373
43
                  "reset=%d, closed=%d",
374
43
                  stream_id, stream->reset, stream->closed);
375
43
    }
376
52
    return NGTCP2_ERR_CALLBACK_FAILURE;
377
52
  }
378
15.6k
  nconsumed = (uint64_t)rc;
379
15.6k
  if(nconsumed) {
380
    /* number of bytes inside buflen which consists of framing overhead
381
     * including QPACK HEADERS. In other words, it does not consume payload of
382
     * DATA frame. */
383
15.6k
    ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
384
15.6k
    ngtcp2_conn_extend_max_offset(tconn, nconsumed);
385
15.6k
    if(stream) {
386
1.73k
      stream->rx_offset += nconsumed;
387
1.73k
      stream->rx_offset_max += nconsumed;
388
1.73k
    }
389
15.6k
  }
390
15.6k
  return 0;
391
15.7k
}
392
393
static int cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
394
                                       uint64_t offset, uint64_t datalen,
395
                                       void *user_data, void *stream_user_data)
396
18.7k
{
397
18.7k
  struct Curl_cfilter *cf = user_data;
398
18.7k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
399
18.7k
  int rv;
400
18.7k
  (void)stream_id;
401
18.7k
  (void)tconn;
402
18.7k
  (void)offset;
403
18.7k
  (void)datalen;
404
18.7k
  (void)stream_user_data;
405
406
18.7k
  rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen);
407
18.7k
  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
408
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
409
0
  }
410
411
18.7k
  return 0;
412
18.7k
}
413
414
static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
415
                           int64_t stream_id, uint64_t app_error_code,
416
                           void *user_data, void *stream_user_data)
417
0
{
418
0
  struct Curl_cfilter *cf = user_data;
419
0
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
420
0
  struct Curl_easy *data = Curl_cf_ngtcp2_get_xfer(cf, stream_user_data, NULL);
421
0
  int rv;
422
423
0
  (void)tconn;
424
  /* stream is closed... */
425
0
  if(!data)
426
0
    data = CF_DATA_CURRENT(cf);
427
0
  if(!data)
428
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
429
430
0
  if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
431
0
    app_error_code = NGHTTP3_H3_NO_ERROR;
432
0
  }
433
434
0
  rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, app_error_code);
435
0
  CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(app_error=%"
436
0
              PRIu64 ") -> %d", stream_id, app_error_code, rv);
437
0
  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
438
0
    Curl_cf_ngtcp2_h3_err_set(cf, data, rv);
439
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
440
0
  }
441
442
0
  return 0;
443
0
}
444
445
#ifdef NGTCP2_CALLBACKS_V5  /* ngtcp2 v1.25.0+ */
446
static int cb_stream_close2(ngtcp2_conn *tconn, uint32_t flags,
447
                           int64_t stream_id,
448
                           uint64_t rx_app_error_code,
449
                           uint64_t tx_app_error_code,
450
                           void *user_data, void *stream_user_data)
451
1.62k
{
452
1.62k
  struct Curl_cfilter *cf = user_data;
453
1.62k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
454
1.62k
  struct Curl_easy *data = Curl_cf_ngtcp2_get_xfer(cf, stream_user_data, NULL);
455
1.62k
  uint64_t h3_app_error_code = NGHTTP3_H3_NO_ERROR;
456
1.62k
  int rv;
457
458
1.62k
  (void)tconn;
459
1.62k
  (void)tx_app_error_code;
460
  /* stream is closed... */
461
1.62k
  if(!data)
462
149
    data = CF_DATA_CURRENT(cf);
463
1.62k
  if(!data)
464
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
465
466
1.62k
  if(flags & NGTCP2_STREAM_CLOSE2_FLAG_RX_APP_ERROR_CODE_SET)
467
584
    h3_app_error_code = rx_app_error_code;
468
469
1.62k
  rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, h3_app_error_code);
470
1.62k
  CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(app_error=%"
471
1.62k
              PRIu64 ") -> %d", stream_id, h3_app_error_code, rv);
472
1.62k
  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
473
5
    Curl_cf_ngtcp2_h3_err_set(cf, data, rv);
474
5
    return NGTCP2_ERR_CALLBACK_FAILURE;
475
5
  }
476
477
1.62k
  return 0;
478
1.62k
}
479
#endif
480
481
static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
482
                           uint64_t final_size, uint64_t app_error_code,
483
                           void *user_data, void *stream_user_data)
484
591
{
485
591
  struct Curl_cfilter *cf = user_data;
486
591
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
487
591
  struct Curl_easy *data = Curl_cf_ngtcp2_get_xfer(cf, stream_user_data, NULL);
488
591
  int rv;
489
591
  (void)tconn;
490
591
  (void)final_size;
491
591
  (void)app_error_code;
492
493
591
  rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
494
591
  if(data)
495
477
    CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
496
591
  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
497
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
498
0
  }
499
500
591
  return 0;
501
591
}
502
503
static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
504
                                  uint64_t app_error_code, void *user_data,
505
                                  void *stream_user_data)
506
1.68k
{
507
1.68k
  struct Curl_cfilter *cf = user_data;
508
1.68k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
509
1.68k
  int rv;
510
1.68k
  (void)tconn;
511
1.68k
  (void)app_error_code;
512
1.68k
  (void)stream_user_data;
513
514
1.68k
  rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
515
1.68k
  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
516
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
517
0
  }
518
519
1.68k
  return 0;
520
1.68k
}
521
522
static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
523
                                            uint64_t max_streams,
524
                                            void *user_data)
525
4.37k
{
526
4.37k
  struct Curl_cfilter *cf = user_data;
527
4.37k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
528
4.37k
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
529
530
4.37k
  (void)tconn;
531
4.37k
  ctx->max_bidi_streams = max_streams;
532
4.37k
  if(data)
533
4.37k
    CURL_TRC_CF(data, cf, "max bidi streams now %" PRIu64 ", used %" PRIu64,
534
4.37k
                ctx->max_bidi_streams, ctx->used_bidi_streams);
535
4.37k
  return 0;
536
4.37k
}
537
538
static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
539
                                     uint64_t max_data, void *user_data,
540
                                     void *stream_user_data)
541
10
{
542
10
  struct Curl_cfilter *cf = user_data;
543
10
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
544
10
  struct h3_stream_ctx *stream;
545
10
  struct Curl_easy *data =
546
10
    Curl_cf_ngtcp2_get_xfer(cf, stream_user_data, &stream);
547
10
  int rv;
548
10
  (void)tconn;
549
10
  (void)max_data;
550
551
10
  rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id);
552
10
  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
553
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
554
0
  }
555
10
  if(stream && stream->quic_flow_blocked) {
556
1
    CURL_TRC_CF(data, cf, "[%" PRId64 "] unblock quic flow", stream_id);
557
1
    stream->quic_flow_blocked = FALSE;
558
1
    if(data)
559
1
      Curl_multi_mark_dirty(data);
560
1
  }
561
10
  return 0;
562
10
}
563
564
static void cb_rand(uint8_t *dest, size_t destlen,
565
                    const ngtcp2_rand_ctx *rand_ctx)
566
23.1k
{
567
23.1k
  CURLcode result;
568
23.1k
  (void)rand_ctx;
569
570
23.1k
  result = Curl_rand(NULL, dest, destlen);
571
23.1k
  if(result) {
572
    /* cb_rand is only used for non-cryptographic context. If Curl_rand
573
       failed, fill 0 and call it *random*. */
574
0
    memset(dest, 0, destlen);
575
0
  }
576
23.1k
}
577
578
/* for ngtcp2 <v1.22.0 */
579
static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
580
                                    uint8_t *token, size_t cidlen,
581
                                    void *user_data)
582
0
{
583
0
  CURLcode result;
584
0
  (void)tconn;
585
0
  (void)user_data;
586
587
0
  result = Curl_rand(NULL, cid->data, cidlen);
588
0
  if(result)
589
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
590
0
  cid->datalen = cidlen;
591
592
0
  result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
593
0
  if(result)
594
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
595
596
0
  return 0;
597
0
}
598
599
#ifdef NGTCP2_CALLBACKS_V3  /* ngtcp2 v1.22.0+ */
600
static int cb_get_new_connection_id2(
601
  ngtcp2_conn *tconn, ngtcp2_cid *cid,
602
  struct ngtcp2_stateless_reset_token *token, size_t cidlen, void *user_data)
603
4.37k
{
604
4.37k
  CURLcode result;
605
4.37k
  (void)tconn;
606
4.37k
  (void)user_data;
607
608
4.37k
  result = Curl_rand(NULL, cid->data, cidlen);
609
4.37k
  if(result)
610
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
611
4.37k
  cid->datalen = cidlen;
612
613
4.37k
  result = Curl_rand(NULL, token->data, sizeof(token->data));
614
4.37k
  if(result)
615
0
    return NGTCP2_ERR_CALLBACK_FAILURE;
616
617
4.37k
  return 0;
618
4.37k
}
619
#endif
620
621
static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level,
622
                          void *user_data)
623
8.75k
{
624
8.75k
  struct Curl_cfilter *cf = user_data;
625
8.75k
  struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL;
626
8.75k
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
627
8.75k
  (void)tconn;
628
629
8.75k
  if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT)
630
4.37k
    return 0;
631
632
4.37k
  DEBUGASSERT(ctx);
633
4.37k
  DEBUGASSERT(data);
634
4.37k
  if(ctx && data && !ctx->h3conn && ctx->init_h3_conn_cb) {
635
4.37k
    if(ctx->init_h3_conn_cb(cf, data, ctx))
636
2
      return NGTCP2_ERR_CALLBACK_FAILURE;
637
4.37k
  }
638
4.37k
  return 0;
639
4.37k
}
640
641
#ifdef CURL_HAVE_DIAG
642
#pragma GCC diagnostic push
643
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
644
#endif
645
static ngtcp2_callbacks ng_callbacks = {
646
  ngtcp2_crypto_client_initial_cb,
647
  NULL, /* recv_client_initial */
648
  ngtcp2_crypto_recv_crypto_data_cb,
649
  cb_ngtcp2_handshake_completed,
650
  NULL, /* recv_version_negotiation */
651
  ngtcp2_crypto_encrypt_cb,
652
  ngtcp2_crypto_decrypt_cb,
653
  ngtcp2_crypto_hp_mask_cb,
654
  cb_recv_stream_data,
655
  cb_acked_stream_data_offset,
656
  NULL, /* stream_open */
657
  cb_stream_close,
658
  NULL, /* recv_stateless_reset */
659
  ngtcp2_crypto_recv_retry_cb,
660
  cb_extend_max_local_streams_bidi,
661
  NULL, /* extend_max_local_streams_uni */
662
  cb_rand,
663
  cb_get_new_connection_id, /* for ngtcp2 <v1.22.0 */
664
  NULL, /* remove_connection_id */
665
  ngtcp2_crypto_update_key_cb, /* update_key */
666
  NULL, /* path_validation */
667
  NULL, /* select_preferred_addr */
668
  cb_stream_reset,
669
  NULL, /* extend_max_remote_streams_bidi */
670
  NULL, /* extend_max_remote_streams_uni */
671
  cb_extend_max_stream_data,
672
  NULL, /* dcid_status */
673
  NULL, /* handshake_confirmed */
674
  NULL, /* recv_new_token */
675
  ngtcp2_crypto_delete_crypto_aead_ctx_cb,
676
  ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
677
  NULL, /* recv_datagram */
678
  NULL, /* ack_datagram */
679
  NULL, /* lost_datagram */
680
  ngtcp2_crypto_get_path_challenge_data_cb,
681
  cb_stream_stop_sending,
682
  NULL, /* version_negotiation */
683
  cb_recv_rx_key,
684
  NULL, /* recv_tx_key */
685
  NULL, /* early_data_rejected */
686
#ifdef NGTCP2_CALLBACKS_V2  /* ngtcp2 v1.14.0+ */
687
  NULL, /* begin_path_validation */
688
#endif
689
#ifdef NGTCP2_CALLBACKS_V3  /* ngtcp2 v1.22.0+ */
690
  NULL, /* recv_stateless_reset2 */
691
  cb_get_new_connection_id2, /* get_new_connection_id2 */
692
  NULL, /* dcid_status2 */
693
  ngtcp2_crypto_get_path_challenge_data2_cb, /* get_path_challenge_data2 */
694
#endif
695
#ifdef NGTCP2_CALLBACKS_V4  /* ngtcp2 v1.24.0+ */
696
  NULL, /* recv_stop_sending */
697
#endif
698
#ifdef NGTCP2_CALLBACKS_V5  /* ngtcp2 v1.25.0+ */
699
  cb_stream_close2, /* is called instead of cb_stream_close when set */
700
#endif
701
};
702
#ifdef CURL_HAVE_DIAG
703
#pragma GCC diagnostic pop
704
#endif
705
706
#if defined(_MSC_VER) && defined(_DLL)
707
#pragma warning(pop)
708
#endif
709
710
#ifdef USE_OPENSSL
711
/* The "new session" callback must return zero if the session can be removed
712
 * or non-zero if the session has been put into the session cache.
713
 */
714
static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
715
8.64k
{
716
8.64k
  struct Curl_cfilter *cf;
717
8.64k
  struct cf_ngtcp2_ctx *ctx;
718
8.64k
  struct Curl_easy *data;
719
8.64k
  ngtcp2_crypto_conn_ref *cref;
720
721
8.64k
  cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl);
722
8.64k
  cf = cref ? cref->user_data : NULL;
723
8.64k
  ctx = cf ? cf->ctx : NULL;
724
8.64k
  data = cf ? CF_DATA_CURRENT(cf) : NULL;
725
8.64k
  if(cf && data && ctx) {
726
8.64k
    unsigned char *quic_tp = NULL;
727
8.64k
    size_t quic_tp_len = 0;
728
8.64k
#ifdef HAVE_OPENSSL_EARLYDATA
729
8.64k
    ngtcp2_ssize tplen;
730
8.64k
    uint8_t tpbuf[256];
731
732
8.64k
    tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf,
733
8.64k
                                                     sizeof(tpbuf));
734
8.64k
    if(tplen < 0)
735
0
      CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s",
736
8.64k
                  ngtcp2_strerror((int)tplen));
737
8.64k
    else {
738
8.64k
      quic_tp = (unsigned char *)tpbuf;
739
8.64k
      quic_tp_len = (size_t)tplen;
740
8.64k
    }
741
8.64k
#endif
742
8.64k
    Curl_ossl_add_session(cf, data, &ctx->tls.ossl, ctx->ssl_peer.scache_key,
743
8.64k
                          ssl_sessionid, "h3", quic_tp, quic_tp_len, NULL);
744
8.64k
  }
745
8.64k
  return 0;
746
8.64k
}
747
#endif /* USE_OPENSSL */
748
749
#ifdef USE_GNUTLS
750
751
#ifdef CURLVERBOSE
752
static const char *gtls_hs_msg_name(int mtype)
753
{
754
  switch(mtype) {
755
  case 1:
756
    return "ClientHello";
757
  case 2:
758
    return "ServerHello";
759
  case 4:
760
    return "SessionTicket";
761
  case 8:
762
    return "EncryptedExtensions";
763
  case 11:
764
    return "Certificate";
765
  case 13:
766
    return "CertificateRequest";
767
  case 15:
768
    return "CertificateVerify";
769
  case 20:
770
    return "Finished";
771
  case 24:
772
    return "KeyUpdate";
773
  case 254:
774
    return "MessageHash";
775
  }
776
  return "Unknown";
777
}
778
#endif
779
780
static int quic_gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
781
                                  unsigned when, unsigned int incoming,
782
                                  const gnutls_datum_t *msg)
783
{
784
  ngtcp2_crypto_conn_ref *conn_ref = gnutls_session_get_ptr(session);
785
  struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
786
  struct cf_ngtcp2_ctx *ctx = cf ? cf->ctx : NULL;
787
788
  (void)msg;
789
  (void)incoming;
790
  if(when && cf && ctx) { /* after message has been processed */
791
    struct Curl_easy *data = CF_DATA_CURRENT(cf);
792
    DEBUGASSERT(data);
793
    if(!data)
794
      return 0;
795
    CURL_TRC_CF(data, cf, "SSL message: %s %s [%u]",
796
                incoming ? "<-" : "->", gtls_hs_msg_name(htype), htype);
797
    switch(htype) {
798
    case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
799
      ngtcp2_ssize tplen;
800
      uint8_t tpbuf[256];
801
      unsigned char *quic_tp = NULL;
802
      size_t quic_tp_len = 0;
803
804
      tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf,
805
                                                       sizeof(tpbuf));
806
      if(tplen < 0)
807
        CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s",
808
                    ngtcp2_strerror((int)tplen));
809
      else {
810
        quic_tp = (unsigned char *)tpbuf;
811
        quic_tp_len = (size_t)tplen;
812
      }
813
      (void)Curl_gtls_cache_session(cf, data, ctx->ssl_peer.scache_key,
814
                                    session, 0, "h3", quic_tp, quic_tp_len,
815
                                    NULL);
816
      break;
817
    }
818
    default:
819
      break;
820
    }
821
  }
822
  return 0;
823
}
824
#endif /* USE_GNUTLS */
825
826
#ifdef USE_WOLFSSL
827
static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
828
{
829
  ngtcp2_crypto_conn_ref *conn_ref = wolfSSL_get_app_data(ssl);
830
  struct Curl_cfilter *cf = conn_ref ? conn_ref->user_data : NULL;
831
832
  DEBUGASSERT(cf);
833
  if(cf && session) {
834
    struct cf_ngtcp2_ctx *ctx = cf->ctx;
835
    struct Curl_easy *data = CF_DATA_CURRENT(cf);
836
    DEBUGASSERT(data);
837
    if(data && ctx) {
838
      ngtcp2_ssize tplen;
839
      uint8_t tpbuf[256];
840
      unsigned char *quic_tp = NULL;
841
      size_t quic_tp_len = 0;
842
843
      tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf,
844
                                                       sizeof(tpbuf));
845
      if(tplen < 0)
846
        CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s",
847
                    ngtcp2_strerror((int)tplen));
848
      else {
849
        quic_tp = (unsigned char *)tpbuf;
850
        quic_tp_len = (size_t)tplen;
851
      }
852
      (void)Curl_wssl_cache_session(cf, data, ctx->ssl_peer.scache_key,
853
                                    session, wolfSSL_version(ssl),
854
                                    "h3", quic_tp, quic_tp_len, NULL);
855
    }
856
  }
857
  return 0;
858
}
859
#endif /* USE_WOLFSSL */
860
861
static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
862
                                        struct Curl_easy *data,
863
                                        void *user_data)
864
5.74k
{
865
5.74k
  struct curl_tls_ctx *ctx = user_data;
866
867
5.74k
#ifdef USE_OPENSSL
868
#if defined(OPENSSL_IS_AWSLC) || defined(OPENSSL_IS_BORINGSSL)
869
  if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
870
     != 0) {
871
    failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
872
    return CURLE_FAILED_INIT;
873
  }
874
#elif defined(OPENSSL_QUIC_API2)
875
  /* nothing to do */
876
#else
877
  if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
878
    failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
879
    return CURLE_FAILED_INIT;
880
  }
881
#endif /* !OPENSSL_IS_AWSLC && !OPENSSL_IS_BORINGSSL */
882
5.74k
  if(Curl_ssl_scache_use(cf, data)) {
883
    /* Enable the session cache because it is a prerequisite for the
884
     * "new session" callback. Use the "external storage" mode to prevent
885
     * OpenSSL from creating an internal session cache.
886
     */
887
5.74k
    SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
888
5.74k
                                   SSL_SESS_CACHE_CLIENT |
889
5.74k
                                   SSL_SESS_CACHE_NO_INTERNAL);
890
5.74k
    SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
891
5.74k
  }
892
893
#elif defined(USE_GNUTLS)
894
  if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
895
    failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
896
    return CURLE_FAILED_INIT;
897
  }
898
  if(Curl_ssl_scache_use(cf, data)) {
899
    gnutls_handshake_set_hook_function(ctx->gtls.session,
900
                                       GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
901
                                       quic_gtls_handshake_cb);
902
  }
903
904
#elif defined(USE_WOLFSSL)
905
  if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ssl_ctx) != 0) {
906
    failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
907
    return CURLE_FAILED_INIT;
908
  }
909
  if(Curl_ssl_scache_use(cf, data)) {
910
    /* Register to get notified when a new session is received */
911
    wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ssl_ctx, wssl_quic_new_session_cb);
912
  }
913
#endif
914
5.74k
  return CURLE_OK;
915
5.74k
}
916
917
static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
918
                                           struct Curl_easy *data,
919
                                           struct alpn_spec *alpns,
920
                                           struct Curl_ssl_session *scs,
921
                                           bool *do_early_data)
922
0
{
923
0
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
924
0
  CURLcode result = CURLE_OK;
925
926
0
  *do_early_data = FALSE;
927
0
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)
928
0
  ctx->earlydata_max = scs->earlydata_max;
929
0
#endif
930
#ifdef USE_GNUTLS
931
  ctx->earlydata_max =
932
    gnutls_record_get_max_early_data_size(ctx->tls.gtls.session);
933
#endif
934
#ifdef USE_WOLFSSL
935
#ifdef WOLFSSL_EARLY_DATA
936
  ctx->earlydata_max = scs->earlydata_max;
937
#else
938
  ctx->earlydata_max = 0;
939
#endif /* WOLFSSL_EARLY_DATA */
940
#endif
941
0
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
942
0
  (defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA))
943
0
  if(!ctx->earlydata_max) {
944
0
    CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
945
0
  }
946
0
  else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
947
0
    CURL_TRC_CF(data, cf, "SSL session from different ALPN, no early data");
948
0
  }
949
0
  else if(!scs->quic_tp || !scs->quic_tp_len) {
950
0
    CURL_TRC_CF(data, cf, "no 0RTT transport parameters, no early data");
951
0
  }
952
0
  else {
953
0
    int rv;
954
0
    rv = ngtcp2_conn_decode_and_set_0rtt_transport_params(
955
0
      ctx->qconn, (const uint8_t *)scs->quic_tp, scs->quic_tp_len);
956
0
    if(rv)
957
0
      CURL_TRC_CF(data, cf, "no early data, failed to set 0RTT transport "
958
0
                  "parameters: %s", ngtcp2_strerror(rv));
959
0
    else if(ctx->init_h3_conn_cb) {
960
0
      infof(data, "SSL session allows %zu bytes of early data, "
961
0
            "reusing ALPN '%s'", ctx->earlydata_max, scs->alpn);
962
0
      result = ctx->init_h3_conn_cb(cf, data, ctx);
963
0
      if(!result) {
964
0
        ctx->use_earlydata = TRUE;
965
0
        cf->connected = TRUE;
966
0
        *do_early_data = TRUE;
967
0
      }
968
0
    }
969
0
    else { /* init_h3_conn_cb not set, assume done */
970
0
      ctx->use_earlydata = TRUE;
971
0
      cf->connected = TRUE;
972
0
      *do_early_data = TRUE;
973
0
    }
974
0
  }
975
#else /* not supported in the TLS backend */
976
  (void)data;
977
  (void)ctx;
978
  (void)scs;
979
  (void)alpns;
980
#endif
981
0
  return result;
982
0
}
983
984
/*
985
 * Might be called twice for happy eyeballs.
986
 */
987
static CURLcode cf_connect_start(struct Curl_cfilter *cf,
988
                                 struct Curl_easy *data,
989
                                 struct cf_ngtcp2_io_ctx *pktx)
990
5.76k
{
991
5.76k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
992
5.76k
  int rc;
993
5.76k
  int rv;
994
5.76k
  CURLcode result;
995
5.76k
  const struct Curl_sockaddr_ex *sockaddr = NULL;
996
5.76k
  int qfd;
997
5.76k
  static const struct alpn_spec ALPN_SPEC_H3 = { { "h3", "h3-29" }, 2 };
998
999
5.76k
  DEBUGASSERT(ctx->initialized);
1000
5.76k
  ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
1001
5.76k
  result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN);
1002
5.76k
  if(result)
1003
0
    return result;
1004
1005
5.76k
  ctx->scid.datalen = NGTCP2_MAX_CIDLEN;
1006
5.76k
  result = Curl_rand(data, ctx->scid.data, NGTCP2_MAX_CIDLEN);
1007
5.76k
  if(result)
1008
0
    return result;
1009
1010
5.76k
  (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
1011
5.76k
  ctx->qlogfd = qfd; /* -1 if failure above */
1012
5.76k
  quic_settings(ctx, data, pktx);
1013
1014
5.76k
  result = Curl_vquic_ctx_init(data, &ctx->q);
1015
5.76k
  if(result)
1016
0
    return result;
1017
1018
  /* Query socket and remote address from sub-chain */
1019
5.76k
  if(Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL)) {
1020
    /* No direct socket - must be tunneled QUIC (CONNECT-UDP through proxy) */
1021
1.38k
    ctx->q.sockfd = CURL_SOCKET_BAD;
1022
1.38k
  }
1023
1024
5.76k
  if(ctx->q.sockfd != CURL_SOCKET_BAD) {
1025
    /* Direct UDP socket - get local address for ngtcp2 */
1026
4.38k
    ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
1027
4.38k
    rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
1028
4.38k
                     &ctx->q.local_addrlen);
1029
4.38k
    if(rv == -1)
1030
0
      return CURLE_QUIC_CONNECT_ERROR;
1031
1032
4.38k
    ngtcp2_addr_init(&ctx->connected_path.local,
1033
4.38k
                     (struct sockaddr *)&ctx->q.local_addr,
1034
4.38k
                     ctx->q.local_addrlen);
1035
4.38k
    ngtcp2_addr_init(&ctx->connected_path.remote,
1036
4.38k
                     &sockaddr->curl_sa_addr, (socklen_t)sockaddr->addrlen);
1037
4.38k
  }
1038
1.38k
  else {
1039
    /* Tunneled QUIC (e.g. CONNECT-UDP): get remote address
1040
       from the connected filter below */
1041
1.38k
    const struct Curl_sockaddr_ex *remote = NULL;
1042
1.38k
    if(cf->next->cft->query(cf->next, data, CF_QUERY_REMOTE_ADDR, NULL,
1043
1.38k
                            CURL_UNCONST(&remote)))
1044
0
      return CURLE_QUIC_CONNECT_ERROR;
1045
1.38k
    if(!remote)
1046
0
      return CURLE_QUIC_CONNECT_ERROR;
1047
1048
1.38k
    memset(&ctx->q.local_addr, 0, sizeof(ctx->q.local_addr));
1049
1.38k
    switch(remote->family) {
1050
1.38k
    case AF_INET:
1051
1.38k
      ((struct sockaddr_in *)&ctx->q.local_addr)->sin_family = AF_INET;
1052
1.38k
      ctx->q.local_addrlen = sizeof(struct sockaddr_in);
1053
1.38k
      break;
1054
0
#ifdef USE_IPV6
1055
0
    case AF_INET6:
1056
0
      ((struct sockaddr_in6 *)&ctx->q.local_addr)->sin6_family = AF_INET6;
1057
0
      ctx->q.local_addrlen = sizeof(struct sockaddr_in6);
1058
0
      break;
1059
0
#endif
1060
0
    default:
1061
0
      return CURLE_QUIC_CONNECT_ERROR;
1062
1.38k
    }
1063
1064
1.38k
    ngtcp2_addr_init(&ctx->connected_path.local,
1065
1.38k
                     (struct sockaddr *)&ctx->q.local_addr,
1066
1.38k
                     ctx->q.local_addrlen);
1067
1.38k
    ngtcp2_addr_init(&ctx->connected_path.remote,
1068
1.38k
                     &remote->curl_sa_addr,
1069
1.38k
                     (socklen_t)remote->addrlen);
1070
1.38k
  }
1071
1072
5.76k
  rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
1073
5.76k
                              &ctx->connected_path,
1074
5.76k
                              NGTCP2_PROTO_VER_V1, &ng_callbacks,
1075
5.76k
                              &ctx->settings, &ctx->transport_params,
1076
5.76k
                              Curl_ngtcp2_mem(), cf);
1077
5.76k
  if(rc)
1078
18
    return CURLE_QUIC_CONNECT_ERROR;
1079
1080
5.74k
  ctx->conn_ref.get_conn = get_conn;
1081
5.74k
  ctx->conn_ref.user_data = cf;
1082
1083
5.74k
  result = Curl_vquic_tls_init(&ctx->tls, cf, data,
1084
5.74k
                               &ctx->ssl_peer, &ALPN_SPEC_H3,
1085
5.74k
                               cf_ngtcp2_tls_ctx_setup, &ctx->tls,
1086
5.74k
                               &ctx->conn_ref,
1087
5.74k
                               cf_ngtcp2_on_session_reuse);
1088
5.74k
  if(result)
1089
0
    return result;
1090
1091
5.74k
#if defined(USE_OPENSSL) && defined(OPENSSL_QUIC_API2)
1092
5.74k
  if(ngtcp2_crypto_ossl_ctx_new(&ctx->ossl_ctx, ctx->tls.ossl.ssl) != 0) {
1093
0
    failf(data, "ngtcp2_crypto_ossl_ctx_new failed");
1094
0
    return CURLE_FAILED_INIT;
1095
0
  }
1096
5.74k
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->ossl_ctx);
1097
5.74k
  if(ngtcp2_crypto_ossl_configure_client_session(ctx->tls.ossl.ssl) != 0) {
1098
0
    failf(data, "ngtcp2_crypto_ossl_configure_client_session failed");
1099
0
    return CURLE_FAILED_INIT;
1100
0
  }
1101
#elif defined(USE_OPENSSL)
1102
  SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0);
1103
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
1104
#elif defined(USE_GNUTLS)
1105
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
1106
#elif defined(USE_WOLFSSL)
1107
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.ssl);
1108
#else
1109
#error "ngtcp2 TLS backend not defined"
1110
#endif
1111
1112
5.74k
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA) && \
1113
5.74k
    defined(OPENSSL_QUIC_API2)
1114
  /* We need to tell OpenSSL to *really* use Early Data for QUIC and
1115
   * this only works *after* ngtcp2 has tweaked all SSL parameters,
1116
   * otherwise OpenSSL does not accept it. */
1117
5.74k
  if(ctx->use_earlydata &&
1118
0
     !SSL_set_quic_tls_early_data_enabled(ctx->tls.ossl.ssl, 1)) {
1119
0
    CURL_TRC_CF(data, cf, "OpenSSL refused to use early data");
1120
0
    ctx->use_earlydata = FALSE;
1121
0
    cf->connected = FALSE;
1122
0
  }
1123
5.74k
#endif
1124
5.74k
  ngtcp2_ccerr_default(&ctx->last_error);
1125
1126
5.74k
  return CURLE_OK;
1127
5.74k
}
1128
1129
CURLcode Curl_cf_ngtcp2_cmn_connect(struct Curl_cfilter *cf,
1130
                                    struct Curl_easy *data,
1131
                                    bool *done)
1132
111k
{
1133
111k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1134
111k
  CURLcode result = CURLE_OK;
1135
111k
  struct cf_call_data save;
1136
111k
  struct cf_ngtcp2_io_ctx pktx;
1137
1138
111k
  if(cf->connected) {
1139
0
    *done = TRUE;
1140
0
    return CURLE_OK;
1141
0
  }
1142
1143
  /* Connect the sub-chain */
1144
111k
  if(cf->next && !cf->next->connected) {
1145
5.76k
    result = Curl_conn_cf_connect(cf->next, data, done);
1146
5.76k
    if(result || !*done)
1147
0
      return result;
1148
5.76k
  }
1149
1150
111k
  *done = FALSE;
1151
1152
111k
  if(Curl_ssl_need_httpsrr(cf) &&
1153
0
     !Curl_conn_dns_resolved_https(data, cf->sockindex, ctx->ssl_peer.peer)) {
1154
0
    CURL_TRC_CF(data, cf, "need HTTPS-RR, delaying connect");
1155
0
    return CURLE_OK;
1156
0
  }
1157
1158
111k
  Curl_cf_ngtcp2_io_ctx_init(&pktx, cf, data);
1159
111k
  CF_DATA_SAVE(save, cf, data);
1160
1161
111k
  if(!ctx->qconn) {
1162
5.76k
    ctx->started_at = *Curl_pgrs_now(data);
1163
5.76k
    result = cf_connect_start(cf, data, &pktx);
1164
5.76k
    if(result)
1165
18
      goto out;
1166
5.74k
    if(cf->connected) {
1167
0
      *done = TRUE;
1168
0
      goto out;
1169
0
    }
1170
5.74k
    result = Curl_cf_ngtcp2_progress_egress(cf, data, &pktx);
1171
    /* we do not expect to be able to recv anything yet */
1172
5.74k
    goto out;
1173
5.74k
  }
1174
1175
105k
  result = Curl_cf_ngtcp2_progress_ingress(cf, data, &pktx);
1176
105k
  if(result)
1177
569
    goto out;
1178
1179
105k
  result = Curl_cf_ngtcp2_progress_egress(cf, data, &pktx);
1180
105k
  if(result)
1181
0
    goto out;
1182
1183
105k
  if(ngtcp2_conn_get_handshake_completed(ctx->qconn)) {
1184
4.37k
    result = ctx->tls_vrfy_result;
1185
4.37k
    if(!result) {
1186
4.37k
      CURL_TRC_CF(data, cf, "peer verified");
1187
4.37k
      cf->connected = TRUE;
1188
4.37k
      *done = TRUE;
1189
4.37k
    }
1190
4.37k
  }
1191
1192
111k
out:
1193
111k
  if(ctx->tls_vrfy_result)
1194
2
    result = ctx->tls_vrfy_result;
1195
111k
  if(ctx->qconn &&
1196
111k
     ((result == CURLE_RECV_ERROR) || (result == CURLE_SEND_ERROR)) &&
1197
575
     ngtcp2_conn_in_draining_period(ctx->qconn)) {
1198
0
    const ngtcp2_ccerr *cerr = ngtcp2_conn_get_ccerr(ctx->qconn);
1199
1200
0
    result = CURLE_COULDNT_CONNECT;
1201
0
    if(cerr) {
1202
0
      CURL_TRC_CF(data, cf, "connect error, type=%d, code=%" PRIu64,
1203
0
                  (int)cerr->type, cerr->error_code);
1204
0
      switch(cerr->type) {
1205
0
      case NGTCP2_CCERR_TYPE_VERSION_NEGOTIATION:
1206
0
        CURL_TRC_CF(data, cf, "error in version negotiation");
1207
0
        break;
1208
0
      default:
1209
0
        if(cerr->error_code >= NGTCP2_CRYPTO_ERROR) {
1210
0
          CURL_TRC_CF(data, cf, "crypto error, tls alert=%u",
1211
0
                      (unsigned int)(cerr->error_code & 0xffU));
1212
0
        }
1213
0
        else if(cerr->error_code == NGTCP2_CONNECTION_REFUSED) {
1214
0
          CURL_TRC_CF(data, cf, "connection refused by server");
1215
          /* When a QUIC server instance is shutting down, it may send us a
1216
           * CONNECTION_CLOSE with this code right away. We want
1217
           * to keep on trying in this case. */
1218
0
          result = CURLE_WEIRD_SERVER_REPLY;
1219
0
        }
1220
0
      }
1221
0
    }
1222
0
  }
1223
1224
111k
#ifdef CURLVERBOSE
1225
111k
  if(result) {
1226
609
    if(ctx->q.sockfd != CURL_SOCKET_BAD) {
1227
      /* Direct UDP socket - get IP info for error reporting */
1228
13
      struct ip_quadruple ip;
1229
1230
13
      if(!Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip))
1231
13
        infof(data, "QUIC connect to %s port %u failed: %s",
1232
13
              ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
1233
13
    }
1234
609
  }
1235
111k
#endif
1236
111k
  if(!result && ctx->qconn) {
1237
111k
    result = Curl_cf_ngtcp2_cmn_set_expiry(cf, data, &pktx);
1238
111k
  }
1239
111k
  if(result || *done)
1240
4.98k
    CURL_TRC_CF(data, cf, "connect -> %d, done=%d", (int)result, *done);
1241
111k
  CF_DATA_RESTORE(cf, save);
1242
111k
  return result;
1243
111k
}
1244
1245
CURLcode Curl_cf_ngtcp2_cmn_shutdown(struct Curl_cfilter *cf,
1246
                                     struct Curl_easy *data, bool *done)
1247
10.1k
{
1248
10.1k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1249
10.1k
  struct cf_call_data save;
1250
10.1k
  struct cf_ngtcp2_io_ctx pktx;
1251
10.1k
  CURLcode result = CURLE_OK;
1252
1253
10.1k
  if(cf->shutdown || !ctx->qconn) {
1254
4.31k
    *done = TRUE;
1255
4.31k
    return CURLE_OK;
1256
4.31k
  }
1257
1258
5.83k
  if(!cf->next) {
1259
1.43k
    Curl_bufq_reset(&ctx->q.sendbuf);
1260
1.43k
    *done = TRUE;
1261
1.43k
    return CURLE_OK;
1262
1.43k
  }
1263
1264
4.40k
  CF_DATA_SAVE(save, cf, data);
1265
4.40k
  *done = FALSE;
1266
4.40k
  Curl_cf_ngtcp2_io_ctx_init(&pktx, cf, data);
1267
1268
4.40k
  if(!ctx->shutdown_started) {
1269
4.39k
    char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
1270
4.39k
    ngtcp2_ssize nwritten;
1271
1272
4.39k
    if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
1273
0
      CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf");
1274
0
      result = Curl_cf_ngtcp2_progress_egress(cf, data, &pktx);
1275
0
      if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
1276
0
        CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
1277
0
        result = CURLE_OK;
1278
0
        goto out;
1279
0
      }
1280
0
      else if(result) {
1281
0
        CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf",
1282
0
                    (int)result);
1283
0
        *done = TRUE;
1284
0
        goto out;
1285
0
      }
1286
0
    }
1287
1288
4.39k
    DEBUGASSERT(Curl_bufq_is_empty(&ctx->q.sendbuf));
1289
4.39k
    ctx->shutdown_started = TRUE;
1290
4.39k
    nwritten = ngtcp2_conn_write_connection_close(
1291
4.39k
      ctx->qconn, NULL, /* path */
1292
4.39k
      NULL, /* pkt_info */
1293
4.39k
      (uint8_t *)buffer, sizeof(buffer),
1294
4.39k
      &ctx->last_error, pktx.ts);
1295
4.39k
    CURL_TRC_CF(data, cf, "start shutdown(err_type=%d, err_code=%"
1296
4.39k
                PRIu64 ") -> %zd", (int)ctx->last_error.type,
1297
4.39k
                ctx->last_error.error_code, (ssize_t)nwritten);
1298
    /* there are cases listed in ngtcp2 documentation where this call
1299
     * may fail. Since we are doing a connection shutdown as graceful
1300
     * as we can, such an error is ignored here. */
1301
4.39k
    if(nwritten > 0) {
1302
      /* Ignore amount written. sendbuf was empty and has always room for
1303
       * NGTCP2_MAX_UDP_PAYLOAD_SIZE. It can only completely fail, in which
1304
       * case `result` is set non zero. */
1305
3.21k
      size_t n;
1306
3.21k
      result = Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
1307
3.21k
                               (size_t)nwritten, &n);
1308
3.21k
      if(result) {
1309
0
        CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, "
1310
0
                    "aborting shutdown", (int)result);
1311
0
        goto out;
1312
0
      }
1313
1314
3.21k
      ctx->q.no_gso = TRUE;
1315
3.21k
      ctx->q.gsolen = (size_t)nwritten;
1316
3.21k
      ctx->q.split_len = 0;
1317
3.21k
    }
1318
4.39k
  }
1319
1320
4.40k
  if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
1321
3.21k
    CURL_TRC_CF(data, cf, "shutdown, flushing egress");
1322
3.21k
    result = Curl_vquic_flush(cf, data, &ctx->q);
1323
3.21k
    if(result == CURLE_AGAIN) {
1324
0
      CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
1325
0
      result = CURLE_OK;
1326
0
      goto out;
1327
0
    }
1328
3.21k
    else if(result) {
1329
0
      CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf",
1330
0
                  (int)result);
1331
0
      *done = TRUE;
1332
0
      goto out;
1333
0
    }
1334
3.21k
  }
1335
1336
4.40k
  if(Curl_bufq_is_empty(&ctx->q.sendbuf)) {
1337
    /* Sent everything off. ngtcp2 seems to have no support for graceful
1338
     * shutdowns. We are done. */
1339
4.40k
    CURL_TRC_CF(data, cf, "shutdown completely sent off, done");
1340
4.40k
    *done = TRUE;
1341
4.40k
    result = CURLE_OK;
1342
4.40k
  }
1343
4.40k
out:
1344
4.40k
  CF_DATA_RESTORE(cf, save);
1345
4.40k
  return result;
1346
4.40k
}
1347
1348
void Curl_cf_ngtcp2_cmn_conn_close(struct Curl_cfilter *cf,
1349
                                   struct Curl_easy *data)
1350
5.83k
{
1351
5.83k
  bool done;
1352
5.83k
  Curl_cf_ngtcp2_cmn_shutdown(cf, data, &done);
1353
5.83k
}
1354
1355
static bool cf_ngtcp2_err_is_fatal(int code)
1356
3.70k
{
1357
3.70k
  return (NGTCP2_ERR_FATAL >= code) ||
1358
3.62k
         (NGTCP2_ERR_DROP_CONN == code) ||
1359
3.62k
         (NGTCP2_ERR_IDLE_CLOSE == code);
1360
3.70k
}
1361
1362
void Curl_cf_ngtcp2_cmn_err_set(struct Curl_cfilter *cf,
1363
                                struct Curl_easy *data, int code)
1364
3.70k
{
1365
3.70k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1366
3.70k
  if(!ctx->last_error.error_code) {
1367
1.24k
    if(NGTCP2_ERR_CRYPTO == code) {
1368
3
      ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
1369
3
                                 ngtcp2_conn_get_tls_alert(ctx->qconn),
1370
3
                                 NULL, 0);
1371
3
    }
1372
1.24k
    else {
1373
1.24k
      ngtcp2_ccerr_set_liberr(&ctx->last_error, code, NULL, 0);
1374
1.24k
    }
1375
1.24k
  }
1376
3.70k
  if(cf_ngtcp2_err_is_fatal(code))
1377
82
    Curl_cf_ngtcp2_cmn_conn_close(cf, data);
1378
3.70k
}
1379
1380
void Curl_cf_ngtcp2_io_ctx_init(struct cf_ngtcp2_io_ctx *io_ctx,
1381
                                struct Curl_cfilter *cf,
1382
                                struct Curl_easy *data)
1383
139k
{
1384
139k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1385
1386
139k
  io_ctx->cf = cf;
1387
139k
  io_ctx->data = data;
1388
139k
  io_ctx->now = *Curl_pgrs_now(data);
1389
139k
  ngtcp2_path_storage_zero(&io_ctx->ps);
1390
139k
  Curl_vquic_ctx_set_time(&ctx->q, &io_ctx->now);
1391
139k
  io_ctx->ts = ((ngtcp2_tstamp)io_ctx->now.tv_sec * NGTCP2_SECONDS) +
1392
139k
               ((ngtcp2_tstamp)io_ctx->now.tv_usec * NGTCP2_MICROSECONDS);
1393
139k
}
1394
1395
void Curl_cf_ngtcp2_io_ctx_update_time(struct Curl_easy *data,
1396
                                       struct cf_ngtcp2_io_ctx *io_ctx,
1397
                                       struct Curl_cfilter *cf)
1398
301k
{
1399
301k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1400
1401
301k
  io_ctx->now = *Curl_pgrs_now(data);
1402
301k
  Curl_vquic_ctx_update_time(&ctx->q, &io_ctx->now);
1403
301k
  io_ctx->ts = ((ngtcp2_tstamp)io_ctx->now.tv_sec * NGTCP2_SECONDS) +
1404
301k
               ((ngtcp2_tstamp)io_ctx->now.tv_usec * NGTCP2_MICROSECONDS);
1405
301k
}
1406
1407
#if NGTCP2_VERSION_NUM < 0x011100
1408
struct cf_ngtcp2_sfind_ctx {
1409
  int64_t stream_id;
1410
  struct h3_stream_ctx *stream;
1411
  uint32_t mid;
1412
};
1413
1414
static bool cf_ngtcp2_sfind(uint32_t mid, void *value, void *user_data)
1415
{
1416
  struct cf_ngtcp2_sfind_ctx *fctx = user_data;
1417
  struct h3_stream_ctx *stream = value;
1418
1419
  if(fctx->stream_id == stream->id) {
1420
    fctx->mid = mid;
1421
    fctx->stream = stream;
1422
    return FALSE;
1423
  }
1424
  return TRUE; /* continue */
1425
}
1426
1427
static struct h3_stream_ctx *cf_ngtcp2_get_stream(struct cf_ngtcp2_ctx *ctx,
1428
                                                  int64_t stream_id)
1429
{
1430
  struct cf_ngtcp2_sfind_ctx fctx;
1431
  fctx.stream_id = stream_id;
1432
  fctx.stream = NULL;
1433
  Curl_u32_ptrset_visit(&ctx->streams, cf_ngtcp2_sfind, &fctx);
1434
  return fctx.stream;
1435
}
1436
#else
1437
static struct h3_stream_ctx *cf_ngtcp2_get_stream(struct cf_ngtcp2_ctx *ctx,
1438
                                                  int64_t stream_id)
1439
1
{
1440
1
  return ngtcp2_conn_get_stream_user_data(ctx->qconn, stream_id);
1441
1
}
1442
#endif
1443
1444
/**
1445
 * Read a network packet to send from ngtcp2 into `buf`.
1446
 * Return number of bytes written or -1 with *err set.
1447
 */
1448
static CURLcode read_pkt_to_send(void *userp,
1449
                                 unsigned char *buf, size_t buflen,
1450
                                 size_t *pnread)
1451
177k
{
1452
177k
  struct cf_ngtcp2_io_ctx *x = userp;
1453
177k
  struct cf_ngtcp2_ctx *ctx = x->cf->ctx;
1454
177k
  nghttp3_vec vec[16];
1455
177k
  nghttp3_ssize veccnt;
1456
177k
  ngtcp2_ssize ndatalen;
1457
177k
  uint32_t flags;
1458
177k
  int64_t stream_id;
1459
177k
  int fin;
1460
177k
  ssize_t n;
1461
1462
177k
  *pnread = 0;
1463
177k
  veccnt = 0;
1464
177k
  stream_id = -1;
1465
177k
  fin = 0;
1466
1467
  /* ngtcp2 may want to put several frames from different streams into
1468
   * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so.
1469
   * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make
1470
   * another iteration.
1471
   * When ngtcp2 is happy (because it has no other frame that would fit
1472
   * or it has nothing more to send), it returns the total length
1473
   * of the assembled packet. This may be 0 if there was nothing to send. */
1474
197k
  for(;;) {
1475
1476
197k
    if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) {
1477
74.5k
      veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec,
1478
74.5k
                                          CURL_ARRAYSIZE(vec));
1479
74.5k
      if(veccnt < 0) {
1480
0
        failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
1481
0
              nghttp3_strerror((int)veccnt));
1482
0
        Curl_cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt);
1483
0
        return CURLE_SEND_ERROR;
1484
0
      }
1485
74.5k
    }
1486
1487
197k
    flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
1488
197k
            (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
1489
197k
    n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path,
1490
197k
                                  NULL, buf, buflen,
1491
197k
                                  &ndatalen, flags, stream_id,
1492
197k
                                  (const ngtcp2_vec *)vec, veccnt, x->ts);
1493
197k
    if(n == 0) {
1494
      /* nothing to send */
1495
131k
      return CURLE_AGAIN;
1496
131k
    }
1497
65.6k
    else if(n < 0) {
1498
22.5k
      switch(n) {
1499
1
      case NGTCP2_ERR_STREAM_DATA_BLOCKED: {
1500
1
        struct h3_stream_ctx *stream;
1501
1
        DEBUGASSERT(ndatalen == -1);
1502
1
        nghttp3_conn_block_stream(ctx->h3conn, stream_id);
1503
1
        CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] block quic flow",
1504
1
                    stream_id);
1505
1
        stream = cf_ngtcp2_get_stream(ctx, stream_id);
1506
1
        if(stream) /* it might be not one of our h3 streams? */
1507
1
          stream->quic_flow_blocked = TRUE;
1508
1
        n = 0;
1509
1
        break;
1510
1
      }
1511
58
      case NGTCP2_ERR_STREAM_SHUT_WR:
1512
58
        DEBUGASSERT(ndatalen == -1);
1513
58
        nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id);
1514
58
        n = 0;
1515
58
        break;
1516
19.9k
      case NGTCP2_ERR_WRITE_MORE:
1517
        /* ngtcp2 wants to send more. update the flow of the stream whose data
1518
         * is in the buffer and continue */
1519
19.9k
        DEBUGASSERT(ndatalen >= 0);
1520
19.9k
        n = 0;
1521
19.9k
        break;
1522
2.47k
      default:
1523
2.47k
        DEBUGASSERT(ndatalen == -1);
1524
2.47k
        failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
1525
2.47k
              ngtcp2_strerror((int)n));
1526
2.47k
        Curl_cf_ngtcp2_cmn_err_set(x->cf, x->data, (int)n);
1527
2.47k
        return CURLE_SEND_ERROR;
1528
22.5k
      }
1529
22.5k
    }
1530
1531
63.1k
    if(ndatalen >= 0) {
1532
      /* we add the amount of data bytes to the flow windows */
1533
21.4k
      int rv = nghttp3_conn_add_write_offset(ctx->h3conn, stream_id, ndatalen);
1534
21.4k
      if(rv) {
1535
0
        failf(x->data, "nghttp3_conn_add_write_offset returned error: %s",
1536
0
              nghttp3_strerror(rv));
1537
0
        return CURLE_SEND_ERROR;
1538
0
      }
1539
21.4k
    }
1540
1541
63.1k
    if(n > 0) {
1542
      /* packet assembled, leave */
1543
43.0k
      *pnread = (size_t)n;
1544
43.0k
      return CURLE_OK;
1545
43.0k
    }
1546
63.1k
  }
1547
177k
}
1548
1549
CURLcode Curl_cf_ngtcp2_progress_egress(struct Curl_cfilter *cf,
1550
                                        struct Curl_easy *data,
1551
                                        struct cf_ngtcp2_io_ctx *pktx)
1552
134k
{
1553
134k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1554
134k
  size_t nread;
1555
134k
  size_t max_payload_size, path_max_payload_size;
1556
134k
  size_t pktcnt = 0;
1557
134k
  size_t gsolen = 0;  /* this disables gso until we have a clue */
1558
134k
  size_t send_quantum;
1559
134k
  CURLcode result;
1560
134k
  struct cf_ngtcp2_io_ctx local_pktx;
1561
1562
134k
  if(!pktx) {
1563
2.88k
    Curl_cf_ngtcp2_io_ctx_init(&local_pktx, cf, data);
1564
2.88k
    pktx = &local_pktx;
1565
2.88k
  }
1566
131k
  else {
1567
131k
    Curl_cf_ngtcp2_io_ctx_update_time(data, pktx, cf);
1568
131k
    ngtcp2_path_storage_zero(&pktx->ps);
1569
131k
  }
1570
1571
134k
  result = Curl_vquic_flush(cf, data, &ctx->q);
1572
134k
  if(result) {
1573
0
    if(result == CURLE_AGAIN) {
1574
0
      Curl_expire_set(data, EXPIRE_QUIC, 1, &pktx->now);
1575
0
      return CURLE_OK;
1576
0
    }
1577
0
    return result;
1578
0
  }
1579
1580
  /* In UDP, there is a maximum theoretical packet payload length and
1581
   * a minimum payload length that is "guaranteed" to work.
1582
   * To detect if this minimum payload can be increased, ngtcp2 sends
1583
   * now and then a packet payload larger than the minimum. It that
1584
   * is ACKed by the peer, both parties know that it works and
1585
   * the subsequent packets can use a larger one.
1586
   * This is called PMTUD (Path Maximum Transmission Unit Discovery).
1587
   * Since a PMTUD might be rejected right on send, we do not want it
1588
   * be followed by other packets of lesser size. Because those would
1589
   * also fail then. If we detect a PMTUD while buffering, we flush.
1590
   */
1591
134k
  max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn);
1592
134k
  path_max_payload_size =
1593
134k
    ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn);
1594
134k
  send_quantum = ngtcp2_conn_get_send_quantum(ctx->qconn);
1595
134k
  CURL_TRC_CF(data, cf, "egress, collect and send packets, quantum=%zu",
1596
134k
              send_quantum);
1597
177k
  for(;;) {
1598
    /* add the next packet to send, if any, to our buffer */
1599
177k
    result = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
1600
177k
                            read_pkt_to_send, pktx, &nread);
1601
177k
    if(result == CURLE_AGAIN)
1602
131k
      break;
1603
45.5k
    else if(result)
1604
2.47k
      return result;
1605
43.0k
    else {
1606
43.0k
      size_t buflen = Curl_bufq_len(&ctx->q.sendbuf);
1607
43.0k
      if((buflen >= send_quantum) ||
1608
43.0k
         ((buflen + gsolen) >= ctx->q.sendbuf.chunk_size))
1609
4
        break;
1610
43.0k
      DEBUGASSERT(nread > 0);
1611
43.0k
      ++pktcnt;
1612
43.0k
      if(pktcnt == 1) {
1613
        /* first packet in buffer. This is either of a known, "good"
1614
         * payload size or it is a PMTUD. We shall see. */
1615
25.9k
        gsolen = nread;
1616
25.9k
      }
1617
17.1k
      else if(nread > gsolen ||
1618
12.7k
              (gsolen > path_max_payload_size && nread != gsolen)) {
1619
        /* The added packet is a PMTUD *or* the one(s) before the added were
1620
         * PMTUD and the last one is smaller. Flush the buffer before the last
1621
         * add. */
1622
8.69k
        result = Curl_vquic_send_tail_split(cf, data, &ctx->q,
1623
8.69k
                                            gsolen, nread, nread);
1624
8.69k
        if(result) {
1625
0
          if(result == CURLE_AGAIN) {
1626
0
            Curl_expire_set(data, EXPIRE_QUIC, 1, &pktx->now);
1627
0
            return CURLE_OK;
1628
0
          }
1629
0
          return result;
1630
0
        }
1631
8.69k
        pktcnt = 0;
1632
8.69k
      }
1633
8.43k
      else if(nread < gsolen) {
1634
        /* Reached capacity of our buffer *or*
1635
         * last add was shorter than the previous ones, flush */
1636
171
        break;
1637
171
      }
1638
43.0k
    }
1639
177k
  }
1640
1641
131k
  if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
1642
    /* time to send */
1643
17.2k
    CURL_TRC_CF(data, cf, "egress, send collected %zu packets in %zu bytes",
1644
17.2k
                pktcnt, Curl_bufq_len(&ctx->q.sendbuf));
1645
17.2k
    result = Curl_vquic_send(cf, data, &ctx->q, gsolen);
1646
17.2k
    if(result) {
1647
2
      if(result == CURLE_AGAIN) {
1648
0
        Curl_expire_set(data, EXPIRE_QUIC, 1, &pktx->now);
1649
0
        return CURLE_OK;
1650
0
      }
1651
2
      return result;
1652
2
    }
1653
17.2k
    Curl_cf_ngtcp2_io_ctx_update_time(data, pktx, cf);
1654
17.2k
    ngtcp2_conn_update_pkt_tx_time(ctx->qconn, pktx->ts);
1655
17.2k
  }
1656
131k
  return CURLE_OK;
1657
131k
}
1658
1659
struct cf_ngtcp2_recv_ctx {
1660
  struct cf_ngtcp2_io_ctx *pktx;
1661
  size_t pkt_count;
1662
};
1663
1664
static CURLcode cf_ngtcp2_recv_pkts(const unsigned char *buf, size_t buflen,
1665
                                    size_t gso_size,
1666
                                    struct sockaddr_storage *remote_addr,
1667
                                    socklen_t remote_addrlen, uint8_t ecn,
1668
                                    void *userp)
1669
47.5k
{
1670
47.5k
  struct cf_ngtcp2_recv_ctx *rctx = userp;
1671
47.5k
  struct cf_ngtcp2_io_ctx *pktx = rctx->pktx;
1672
47.5k
  struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
1673
47.5k
  ngtcp2_pkt_info pi;
1674
47.5k
  ngtcp2_path path;
1675
47.5k
  size_t offset, pktlen;
1676
47.5k
  int rv;
1677
1678
47.5k
  if(!rctx->pkt_count) {
1679
21.3k
    Curl_cf_ngtcp2_io_ctx_update_time(pktx->data, pktx, pktx->cf);
1680
21.3k
    ngtcp2_path_storage_zero(&pktx->ps);
1681
21.3k
  }
1682
1683
47.5k
  if(ecn)
1684
0
    CURL_TRC_CF(pktx->data, pktx->cf, "vquic_recv(len=%zu, gso=%zu, ecn=%x)",
1685
47.5k
                buflen, gso_size, (unsigned)ecn);
1686
47.5k
  ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
1687
47.5k
                   ctx->q.local_addrlen);
1688
47.5k
  ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
1689
47.5k
                   remote_addrlen);
1690
47.5k
  pi.ecn = (uint8_t)ecn;
1691
1692
93.7k
  for(offset = 0; offset < buflen; offset += gso_size) {
1693
47.5k
    rctx->pkt_count++;
1694
47.5k
    pktlen = ((offset + gso_size) <= buflen) ? gso_size : (buflen - offset);
1695
47.5k
    rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi,
1696
47.5k
                              buf + offset, pktlen, pktx->ts);
1697
47.5k
    if(rv) {
1698
1.23k
      CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
1699
1.23k
                  ngtcp2_strerror(rv), rv);
1700
1.23k
      Curl_cf_ngtcp2_cmn_err_set(pktx->cf, pktx->data, rv);
1701
1702
1.23k
      if(rv == NGTCP2_ERR_CRYPTO)
1703
        /* this is a "TLS problem", but a failed certificate verification
1704
           is a common reason for this */
1705
3
        return CURLE_PEER_FAILED_VERIFICATION;
1706
1.23k
      return CURLE_RECV_ERROR;
1707
1.23k
    }
1708
47.5k
  }
1709
46.2k
  return CURLE_OK;
1710
47.5k
}
1711
1712
CURLcode Curl_cf_ngtcp2_progress_ingress(struct Curl_cfilter *cf,
1713
                                         struct Curl_easy *data,
1714
                                         struct cf_ngtcp2_io_ctx *pktx)
1715
126k
{
1716
126k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1717
126k
  struct cf_ngtcp2_io_ctx local_pktx;
1718
126k
  struct cf_ngtcp2_recv_ctx rctx;
1719
126k
  CURLcode result = CURLE_OK;
1720
1721
126k
  if(!pktx) {
1722
0
    Curl_cf_ngtcp2_io_ctx_init(&local_pktx, cf, data);
1723
0
    pktx = &local_pktx;
1724
0
  }
1725
1726
126k
  result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
1727
126k
  if(result)
1728
0
    return result;
1729
1730
126k
  rctx.pktx = pktx;
1731
126k
  rctx.pkt_count = 0;
1732
1733
126k
  if(ctx->q.sockfd != CURL_SOCKET_BAD) {
1734
    /* Direct UDP socket (via happy eyeballs) */
1735
29.0k
    CURL_TRC_CF(data, cf, "progress_ingress(socket)");
1736
29.0k
    return Curl_vquic_recv_packets(cf, data, &ctx->q, 1000,
1737
29.0k
                                   cf_ngtcp2_recv_pkts, &rctx);
1738
29.0k
  }
1739
97.1k
  else {
1740
    /* Tunneled QUIC (CONNECT-UDP through proxy) */
1741
97.1k
    unsigned char *buf;
1742
97.1k
    size_t max_udp_payload = QUIC_TUNNEL_INBUF_SIZE;
1743
97.1k
    size_t pkt_limit = QUIC_TUNNEL_INGRESS_PKT_LIMIT;
1744
97.1k
    size_t nread;
1745
97.1k
    struct sockaddr_storage remote_addr;
1746
97.1k
    socklen_t remote_addrlen;
1747
1748
97.1k
    CURL_TRC_CF(data, cf, "progress_ingress(sub-filters)");
1749
97.1k
    if(ctx->qconn) {
1750
97.1k
      size_t max_path_payload;
1751
97.1k
      max_path_payload =
1752
97.1k
        ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn);
1753
97.1k
      if(max_path_payload > max_udp_payload)
1754
0
        max_udp_payload = max_path_payload;
1755
97.1k
    }
1756
1757
97.1k
    if(ctx->tunnel_inbuf_len < max_udp_payload) {
1758
1.34k
      unsigned char *newbuf = curlx_realloc(ctx->tunnel_inbuf,
1759
1.34k
                                            max_udp_payload);
1760
1.34k
      if(!newbuf)
1761
1
        return CURLE_OUT_OF_MEMORY;
1762
1.34k
      ctx->tunnel_inbuf = newbuf;
1763
1.34k
      ctx->tunnel_inbuf_len = max_udp_payload;
1764
1.34k
    }
1765
97.1k
    buf = ctx->tunnel_inbuf;
1766
1767
116k
    while(pkt_limit--) {
1768
116k
      result = Curl_conn_cf_recv(cf->next, data, (char *)buf,
1769
116k
                                 ctx->tunnel_inbuf_len, &nread);
1770
116k
      if(result == CURLE_AGAIN) {
1771
        /* no more data available at the moment */
1772
95.1k
        return CURLE_OK;
1773
95.1k
      }
1774
21.1k
      if(result) {
1775
558
        CURL_TRC_CF(data, cf, "ingress, recv from tunnel failed: %d",
1776
558
                    (int)result);
1777
558
        return result;
1778
558
      }
1779
20.5k
      if(nread == 0) {
1780
        /* tunnel closed */
1781
1.41k
        return CURLE_OK;
1782
1.41k
      }
1783
1784
19.1k
      memcpy(&remote_addr, ctx->connected_path.remote.addr,
1785
19.1k
             ctx->connected_path.remote.addrlen);
1786
19.1k
      remote_addrlen = (socklen_t)ctx->connected_path.remote.addrlen;
1787
19.1k
      result = cf_ngtcp2_recv_pkts(buf, nread, nread, &remote_addr,
1788
19.1k
                                   remote_addrlen, 0, &rctx);
1789
19.1k
      if(result)
1790
3
        return result;
1791
1792
19.1k
      if(!ctx->q.got_first_byte) {
1793
790
        ctx->q.got_first_byte = TRUE;
1794
790
        ctx->q.first_byte_at = ctx->q.last_op;
1795
790
      }
1796
19.1k
      ctx->q.last_io = ctx->q.last_op;
1797
19.1k
    }
1798
13
    return CURLE_OK;
1799
97.1k
  }
1800
126k
}
1801
1802
/**
1803
 * Connection maintenance like timeouts on packet ACKs etc. are done by us, not
1804
 * the OS like for TCP. POLL events on the socket therefore are not
1805
 * sufficient.
1806
 * ngtcp2 tells us when it wants to be invoked again. We handle that via
1807
 * the `Curl_expire()` mechanisms.
1808
 */
1809
CURLcode Curl_cf_ngtcp2_cmn_set_expiry(struct Curl_cfilter *cf,
1810
                                       struct Curl_easy *data,
1811
                                       struct cf_ngtcp2_io_ctx *pktx)
1812
131k
{
1813
131k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1814
131k
  struct cf_ngtcp2_io_ctx local_pktx;
1815
131k
  ngtcp2_tstamp expiry;
1816
1817
131k
  if(!pktx) {
1818
0
    Curl_cf_ngtcp2_io_ctx_init(&local_pktx, cf, data);
1819
0
    pktx = &local_pktx;
1820
0
  }
1821
131k
  else {
1822
131k
    Curl_cf_ngtcp2_io_ctx_update_time(data, pktx, cf);
1823
131k
  }
1824
1825
131k
  expiry = ngtcp2_conn_get_expiry(ctx->qconn);
1826
131k
  if(expiry != UINT64_MAX) {
1827
131k
    if(expiry <= pktx->ts) {
1828
40
      CURLcode result;
1829
40
      int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts);
1830
40
      if(rv) {
1831
0
        failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
1832
0
              ngtcp2_strerror(rv));
1833
0
        Curl_cf_ngtcp2_cmn_err_set(cf, data, rv);
1834
0
        return CURLE_SEND_ERROR;
1835
0
      }
1836
40
      result = Curl_cf_ngtcp2_progress_ingress(cf, data, pktx);
1837
40
      if(!result)
1838
40
        result = Curl_cf_ngtcp2_progress_egress(cf, data, pktx);
1839
40
      if(result) {
1840
        /* a verify failure during ingress must win over generic errors */
1841
10
        if(ctx->tls_vrfy_result)
1842
0
          result = ctx->tls_vrfy_result;
1843
10
        return result;
1844
10
      }
1845
      /* ask again, things might have changed */
1846
30
      expiry = ngtcp2_conn_get_expiry(ctx->qconn);
1847
30
    }
1848
1849
131k
    if(expiry > pktx->ts) {
1850
131k
      ngtcp2_duration timeout = expiry - pktx->ts;
1851
131k
      if(timeout % NGTCP2_MILLISECONDS) {
1852
131k
        timeout += NGTCP2_MILLISECONDS;
1853
131k
      }
1854
131k
      Curl_expire_set(data, EXPIRE_QUIC,
1855
131k
                      (timediff_t)(timeout / NGTCP2_MILLISECONDS),
1856
131k
                      &pktx->now);
1857
131k
    }
1858
131k
  }
1859
131k
  return CURLE_OK;
1860
131k
}
1861
1862
static void cf_ngtcp2_setup_keep_alive(struct Curl_cfilter *cf,
1863
                                       struct Curl_easy *data)
1864
8.72k
{
1865
8.72k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1866
8.72k
  const ngtcp2_transport_params *rp;
1867
  /* Peer should have sent us its transport parameters. If it
1868
   * announces a positive `max_idle_timeout` it closes the
1869
   * connection when it does not hear from us for that time.
1870
   *
1871
   * Some servers use this as a keep-alive timer at a rather low
1872
   * value. We are doing HTTP/3 here and waiting for the response
1873
   * to a request may take a considerable amount of time. We need
1874
   * to prevent the peer's QUIC stack from closing in this case.
1875
   */
1876
8.72k
  if(!ctx->qconn)
1877
0
    return;
1878
1879
8.72k
  rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
1880
8.72k
  if(!rp || !rp->max_idle_timeout) {
1881
0
    ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX);
1882
0
    CURL_TRC_CF(data, cf, "no peer idle timeout, unset keep-alive");
1883
0
  }
1884
8.72k
  else if(!Curl_u32_ptrset_count(&ctx->streams)) {
1885
4.36k
    ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX);
1886
4.36k
    CURL_TRC_CF(data, cf, "no active streams, unset keep-alive");
1887
4.36k
  }
1888
4.36k
  else {
1889
4.36k
    ngtcp2_duration keep_ns;
1890
4.36k
    keep_ns = (rp->max_idle_timeout > 1) ? (rp->max_idle_timeout / 2) : 1;
1891
4.36k
    ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, keep_ns);
1892
4.36k
    CURL_TRC_CF(data, cf, "peer idle timeout is %" PRIu64 "ms, "
1893
4.36k
                "set keep-alive to %" PRIu64 " ms.",
1894
4.36k
                (rp->max_idle_timeout / NGTCP2_MILLISECONDS),
1895
4.36k
                (keep_ns / NGTCP2_MILLISECONDS));
1896
4.36k
  }
1897
8.72k
}
1898
1899
CURLcode Curl_cf_ngtcp2_h3_stream_setup(struct Curl_cfilter *cf,
1900
                                        struct Curl_easy *data,
1901
                                        struct h3_stream_ctx **pstream)
1902
4.36k
{
1903
4.36k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1904
4.36k
  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1905
1906
4.36k
  *pstream = NULL;
1907
4.36k
  if(!data)
1908
0
    return CURLE_FAILED_INIT;
1909
1910
4.36k
  if(stream) {
1911
0
    *pstream = stream;
1912
0
    return CURLE_OK;
1913
0
  }
1914
1915
4.36k
  stream = curlx_calloc(1, sizeof(*stream));
1916
4.36k
  if(!stream)
1917
0
    return CURLE_OUT_OF_MEMORY;
1918
1919
4.36k
  stream->id = -1;
1920
4.36k
  stream->xfer_id = data->id;
1921
4.36k
  stream->mid = data->mid;
1922
4.36k
  stream->rx_offset = 0;
1923
4.36k
  stream->rx_offset_max = H3_STREAM_WINDOW_SIZE_INITIAL;
1924
4.36k
  stream->tx_in_flight_ideal = H3_STREAM_SEND_BUF_INITIAL;
1925
1926
  /* on send, we control how much we put into the buffer */
1927
4.36k
  Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
1928
4.36k
                  H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
1929
4.36k
  stream->tx_in_flight_size = 0;
1930
4.36k
  Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
1931
1932
4.36k
  if(Curl_u32_ptrset_set(&ctx->streams, data->mid, stream)) {
1933
0
    Curl_cf_ngtcp2_h3_stream_ctx_free(stream);
1934
0
    return CURLE_OUT_OF_MEMORY;
1935
0
  }
1936
1937
4.36k
  if(Curl_u32_ptrset_count(&ctx->streams) == 1)
1938
4.36k
    cf_ngtcp2_setup_keep_alive(cf, data);
1939
1940
4.36k
  *pstream = stream;
1941
4.36k
  return CURLE_OK;
1942
4.36k
}
1943
1944
void Curl_cf_ngtcp2_h3_stream_close(struct Curl_cfilter *cf,
1945
                                    struct Curl_easy *data,
1946
                                    struct h3_stream_ctx *stream)
1947
4.36k
{
1948
4.36k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1949
4.36k
  DEBUGASSERT(data);
1950
4.36k
  DEBUGASSERT(stream);
1951
4.36k
  if(!stream->closed && ctx->qconn && ctx->h3conn) {
1952
2.88k
    CURLcode result;
1953
1954
2.88k
    nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
1955
2.88k
    ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
1956
2.88k
    stream->closed = TRUE;
1957
2.88k
    (void)ngtcp2_conn_shutdown_stream(ctx->qconn, 0, stream->id,
1958
2.88k
                                      NGHTTP3_H3_REQUEST_CANCELLED);
1959
2.88k
    result = Curl_cf_ngtcp2_progress_egress(cf, data, NULL);
1960
2.88k
    if(result)
1961
1.22k
      CURL_TRC_CF(data, cf, "[%" PRId64 "] cancel stream -> %d",
1962
2.88k
                  stream->id, (int)result);
1963
2.88k
  }
1964
4.36k
}
1965
1966
void Curl_cf_ngtcp2_h3_stream_done(struct Curl_cfilter *cf,
1967
                                   struct Curl_easy *data)
1968
5.15k
{
1969
5.15k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1970
5.15k
  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
1971
5.15k
  (void)cf;
1972
5.15k
  if(stream) {
1973
4.36k
    CURL_TRC_CF(data, cf, "[%" PRId64 "] easy handle is done", stream->id);
1974
4.36k
    Curl_cf_ngtcp2_h3_stream_close(cf, data, stream);
1975
4.36k
    Curl_u32_ptrset_unset(&ctx->streams, data->mid);
1976
4.36k
    if(!Curl_u32_ptrset_count(&ctx->streams))
1977
4.36k
      cf_ngtcp2_setup_keep_alive(cf, data);
1978
4.36k
  }
1979
5.15k
}
1980
1981
bool Curl_cf_ngtcp2_cmn_conn_is_alive(struct Curl_cfilter *cf,
1982
                                      struct Curl_easy *data,
1983
                                      bool *input_pending)
1984
0
{
1985
0
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
1986
0
  bool alive = FALSE;
1987
0
  const ngtcp2_transport_params *rp;
1988
0
  struct cf_call_data save;
1989
1990
0
  CF_DATA_SAVE(save, cf, data);
1991
0
  *input_pending = FALSE;
1992
0
  if(!ctx->qconn || ctx->shutdown_started)
1993
0
    goto out;
1994
1995
  /* We do not announce a max idle timeout, but when the peer does
1996
   * it closes the connection when it expires. */
1997
0
  rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
1998
0
  if(rp && rp->max_idle_timeout) {
1999
0
    timediff_t idletime_ms =
2000
0
      curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->q.last_io);
2001
0
    if(idletime_ms > 0) {
2002
0
      uint64_t max_idle_ms =
2003
0
        (uint64_t)(rp->max_idle_timeout / NGTCP2_MILLISECONDS);
2004
0
      if((uint64_t)idletime_ms > max_idle_ms)
2005
0
        goto out;
2006
0
    }
2007
0
  }
2008
2009
0
  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
2010
0
    goto out;
2011
2012
0
  alive = TRUE;
2013
0
  if(*input_pending) {
2014
0
    CURLcode result;
2015
    /* This happens before we have sent off a request and the connection is
2016
       not in use by any other transfer, there should not be any data here,
2017
       only "protocol frames" */
2018
0
    *input_pending = FALSE;
2019
0
    result = Curl_cf_ngtcp2_progress_ingress(cf, data, NULL);
2020
0
    CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", (int)result);
2021
0
    alive = result ? FALSE : TRUE;
2022
0
  }
2023
2024
0
out:
2025
0
  CF_DATA_RESTORE(cf, save);
2026
0
  return alive;
2027
0
}
2028
2029
CURLcode Curl_cf_ngtcp2_h3_init_ctrls(struct cf_ngtcp2_ctx *ctx,
2030
                                      struct Curl_easy *data)
2031
4.37k
{
2032
4.37k
  int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
2033
4.37k
  int rc;
2034
2035
4.37k
  rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &ctrl_stream_id, NULL);
2036
4.37k
  if(rc) {
2037
0
    failf(data, "error creating HTTP/3 control stream: %s",
2038
0
          ngtcp2_strerror(rc));
2039
0
    return CURLE_QUIC_CONNECT_ERROR;
2040
0
  }
2041
4.37k
  rc = nghttp3_conn_bind_control_stream(ctx->h3conn, ctrl_stream_id);
2042
4.37k
  if(rc) {
2043
1
    failf(data, "error binding HTTP/3 control stream: %s",
2044
1
          ngtcp2_strerror(rc));
2045
1
    return CURLE_QUIC_CONNECT_ERROR;
2046
1
  }
2047
4.37k
  rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_enc_stream_id, NULL);
2048
4.37k
  if(rc) {
2049
0
    failf(data, "error creating HTTP/3 qpack encoding stream: %s",
2050
0
          ngtcp2_strerror(rc));
2051
0
    return CURLE_QUIC_CONNECT_ERROR;
2052
0
  }
2053
4.37k
  rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_dec_stream_id, NULL);
2054
4.37k
  if(rc) {
2055
0
    failf(data, "error creating HTTP/3 qpack decoding stream: %s",
2056
0
          ngtcp2_strerror(rc));
2057
0
    return CURLE_QUIC_CONNECT_ERROR;
2058
0
  }
2059
4.37k
  rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id,
2060
4.37k
                                       qpack_dec_stream_id);
2061
4.37k
  if(rc) {
2062
1
    failf(data, "error binding HTTP/3 qpack streams: %s", ngtcp2_strerror(rc));
2063
1
    return CURLE_QUIC_CONNECT_ERROR;
2064
1
  }
2065
4.37k
  return CURLE_OK;
2066
4.37k
}
2067
2068
CURLcode Curl_cf_ngtcp2_cmn_query(struct Curl_cfilter *cf,
2069
                                  struct Curl_easy *data,
2070
                                  int query, int *pres1, void *pres2)
2071
170k
{
2072
170k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
2073
2074
170k
  switch(query) {
2075
0
  case CF_QUERY_CONNECT_REPLY_MS:
2076
0
    if((ctx->q.sockfd != CURL_SOCKET_BAD) && ctx->q.got_first_byte) {
2077
0
      timediff_t ms = curlx_ptimediff_ms(&ctx->q.first_byte_at,
2078
0
                                         &ctx->started_at);
2079
0
      *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
2080
0
      return CURLE_OK;
2081
0
    }
2082
0
    break;
2083
1.19k
  case CF_QUERY_REALLY_CONNECTED:
2084
1.19k
    if(ctx->q.sockfd != CURL_SOCKET_BAD) {
2085
0
      *pres1 = ctx->q.got_first_byte;
2086
0
      return CURLE_OK;
2087
0
    }
2088
1.19k
    break;
2089
168k
  default:
2090
168k
    break;
2091
170k
  }
2092
170k
  return cf->next ?
2093
170k
    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
2094
170k
    CURLE_UNKNOWN_OPTION;
2095
170k
}
2096
2097
CURLcode Curl_cf_ngtcp2_cmn_cntrl(struct Curl_cfilter *cf,
2098
                                  struct Curl_easy *data,
2099
                                  int event, int arg1, void *arg2)
2100
9.51k
{
2101
9.51k
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
2102
9.51k
  CURLcode result = CURLE_OK;
2103
2104
9.51k
  (void)arg1;
2105
9.51k
  (void)arg2;
2106
9.51k
  switch(event) {
2107
4.96k
  case CF_CTRL_REPORT_STATS:
2108
4.96k
    if(cf->connected && !ctx->stats_reported) {
2109
4.37k
      if((cf->cft->flags & CF_TYPE_PROXY) &&
2110
0
         (ctx->q.sockfd != CURL_SOCKET_BAD) && ctx->q.got_first_byte) {
2111
0
        Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->q.first_byte_at);
2112
0
        ctx->stats_reported = TRUE;
2113
0
      }
2114
4.37k
      else if(ctx->handshake_at.tv_sec || ctx->handshake_at.tv_usec) {
2115
4.37k
        if(ctx->q.sockfd != CURL_SOCKET_BAD)
2116
4.37k
          Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->q.first_byte_at);
2117
4.37k
        Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
2118
4.37k
        ctx->stats_reported = TRUE;
2119
4.37k
      }
2120
4.37k
    }
2121
4.96k
    break;
2122
4.55k
  default:
2123
4.55k
    break;
2124
9.51k
  }
2125
9.51k
  return result;
2126
9.51k
}
2127
2128
#endif /* !CURL_DISABLE_HTTP && USE_NGTCP2 && USE_NGHTTP3 */