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