VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/vquic/curl_ngtcp2.c@ 106165

最後變更 在這個檔案從106165是 104083,由 vboxsync 提交於 8 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

檔案大小: 67.2 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, 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#endif
45
46#include "urldata.h"
47#include "sendf.h"
48#include "strdup.h"
49#include "rand.h"
50#include "multiif.h"
51#include "strcase.h"
52#include "cfilters.h"
53#include "cf-socket.h"
54#include "connect.h"
55#include "progress.h"
56#include "strerror.h"
57#include "dynbuf.h"
58#include "http1.h"
59#include "select.h"
60#include "inet_pton.h"
61#include "transfer.h"
62#include "vquic.h"
63#include "vquic_int.h"
64#include "vquic-tls.h"
65#include "vtls/keylog.h"
66#include "vtls/vtls.h"
67#include "curl_ngtcp2.h"
68
69#include "warnless.h"
70
71/* The last 3 #include files should be in this order */
72#include "curl_printf.h"
73#include "curl_memory.h"
74#include "memdebug.h"
75
76
77#define QUIC_MAX_STREAMS (256*1024)
78#define QUIC_MAX_DATA (1*1024*1024)
79#define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS)
80
81/* A stream window is the maximum amount we need to buffer for
82 * each active transfer. We use HTTP/3 flow control and only ACK
83 * when we take things out of the buffer.
84 * Chunk size is large enough to take a full DATA frame */
85#define H3_STREAM_WINDOW_SIZE (128 * 1024)
86#define H3_STREAM_CHUNK_SIZE (16 * 1024)
87/* The pool keeps spares around and half of a full stream windows
88 * seems good. More does not seem to improve performance.
89 * The benefit of the pool is that stream buffer to not keep
90 * spares. So memory consumption goes down when streams run empty,
91 * have a large upload done, etc. */
92#define H3_STREAM_POOL_SPARES \
93 (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
94/* Receive and Send max number of chunks just follows from the
95 * chunk size and window size */
96#define H3_STREAM_RECV_CHUNKS \
97 (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
98#define H3_STREAM_SEND_CHUNKS \
99 (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
100
101
102/*
103 * Store ngtcp2 version info in this buffer.
104 */
105void Curl_ngtcp2_ver(char *p, size_t len)
106{
107 const ngtcp2_info *ng2 = ngtcp2_version(0);
108 const nghttp3_info *ht3 = nghttp3_version(0);
109 (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
110 ng2->version_str, ht3->version_str);
111}
112
113struct cf_ngtcp2_ctx {
114 struct cf_quic_ctx q;
115 struct ssl_peer peer;
116 struct quic_tls_ctx tls;
117 ngtcp2_path connected_path;
118 ngtcp2_conn *qconn;
119 ngtcp2_cid dcid;
120 ngtcp2_cid scid;
121 uint32_t version;
122 ngtcp2_settings settings;
123 ngtcp2_transport_params transport_params;
124 ngtcp2_ccerr last_error;
125 ngtcp2_crypto_conn_ref conn_ref;
126 struct cf_call_data call_data;
127 nghttp3_conn *h3conn;
128 nghttp3_settings h3settings;
129 struct curltime started_at; /* time the current attempt started */
130 struct curltime handshake_at; /* time connect handshake finished */
131 struct curltime reconnect_at; /* time the next attempt should start */
132 struct bufc_pool stream_bufcp; /* chunk pool for streams */
133 size_t max_stream_window; /* max flow window for one stream */
134 uint64_t max_idle_ms; /* max idle time for QUIC connection */
135 int qlogfd;
136};
137
138/* How to access `call_data` from a cf_ngtcp2 filter */
139#undef CF_CTX_CALL_DATA
140#define CF_CTX_CALL_DATA(cf) \
141 ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
142
143/**
144 * All about the H3 internals of a stream
145 */
146struct h3_stream_ctx {
147 int64_t id; /* HTTP/3 protocol identifier */
148 struct bufq sendbuf; /* h3 request body */
149 struct h1_req_parser h1; /* h1 request parsing */
150 size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
151 size_t upload_blocked_len; /* the amount written last and EGAINed */
152 uint64_t error3; /* HTTP/3 stream error code */
153 curl_off_t upload_left; /* number of request bytes left to upload */
154 int status_code; /* HTTP status code */
155 bool resp_hds_complete; /* we have a complete, final response */
156 bool closed; /* TRUE on stream close */
157 bool reset; /* TRUE on stream reset */
158 bool send_closed; /* stream is local closed */
159 BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
160};
161
162#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
163 ((struct HTTP *)(d)->req.p.http)->h3_ctx \
164 : NULL))
165#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
166#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
167 H3_STREAM_CTX(d)->id : -2)
168
169static CURLcode h3_data_setup(struct Curl_cfilter *cf,
170 struct Curl_easy *data)
171{
172 struct cf_ngtcp2_ctx *ctx = cf->ctx;
173 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
174
175 if(!data || !data->req.p.http) {
176 failf(data, "initialization failure, transfer not http initialized");
177 return CURLE_FAILED_INIT;
178 }
179
180 if(stream)
181 return CURLE_OK;
182
183 stream = calloc(1, sizeof(*stream));
184 if(!stream)
185 return CURLE_OUT_OF_MEMORY;
186
187 stream->id = -1;
188 /* on send, we control how much we put into the buffer */
189 Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
190 H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
191 stream->sendbuf_len_in_flight = 0;
192 Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
193
194 H3_STREAM_LCTX(data) = stream;
195 return CURLE_OK;
196}
197
198static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
199{
200 struct cf_ngtcp2_ctx *ctx = cf->ctx;
201 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
202
203 (void)cf;
204 if(stream) {
205 CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
206 if(ctx->h3conn && !stream->closed) {
207 nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream->id);
208 nghttp3_conn_close_stream(ctx->h3conn, stream->id,
209 NGHTTP3_H3_REQUEST_CANCELLED);
210 nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
211 ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
212 stream->closed = TRUE;
213 }
214
215 Curl_bufq_free(&stream->sendbuf);
216 Curl_h1_req_parse_free(&stream->h1);
217 free(stream);
218 H3_STREAM_LCTX(data) = NULL;
219 }
220}
221
222static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
223 struct Curl_easy *data,
224 int64_t stream_id)
225{
226 struct Curl_easy *sdata;
227
228 (void)cf;
229 if(H3_STREAM_ID(data) == stream_id) {
230 return data;
231 }
232 else {
233 DEBUGASSERT(data->multi);
234 for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
235 if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) {
236 return sdata;
237 }
238 }
239 }
240 return NULL;
241}
242
243static void h3_drain_stream(struct Curl_cfilter *cf,
244 struct Curl_easy *data)
245{
246 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
247 unsigned char bits;
248
249 (void)cf;
250 bits = CURL_CSELECT_IN;
251 if(stream && stream->upload_left && !stream->send_closed)
252 bits |= CURL_CSELECT_OUT;
253 if(data->state.select_bits != bits) {
254 data->state.select_bits = bits;
255 Curl_expire(data, 0, EXPIRE_RUN_NOW);
256 }
257}
258
259/* ngtcp2 default congestion controller does not perform pacing. Limit
260 the maximum packet burst to MAX_PKT_BURST packets. */
261#define MAX_PKT_BURST 10
262
263struct pkt_io_ctx {
264 struct Curl_cfilter *cf;
265 struct Curl_easy *data;
266 ngtcp2_tstamp ts;
267 size_t pkt_count;
268 ngtcp2_path_storage ps;
269};
270
271static void pktx_update_time(struct pkt_io_ctx *pktx,
272 struct Curl_cfilter *cf)
273{
274 struct cf_ngtcp2_ctx *ctx = cf->ctx;
275
276 vquic_ctx_update_time(&ctx->q);
277 pktx->ts = ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
278 ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
279}
280
281static void pktx_init(struct pkt_io_ctx *pktx,
282 struct Curl_cfilter *cf,
283 struct Curl_easy *data)
284{
285 pktx->cf = cf;
286 pktx->data = data;
287 pktx->pkt_count = 0;
288 ngtcp2_path_storage_zero(&pktx->ps);
289 pktx_update_time(pktx, cf);
290}
291
292static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
293 struct Curl_easy *data,
294 struct pkt_io_ctx *pktx);
295static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
296 struct Curl_easy *data,
297 struct pkt_io_ctx *pktx);
298static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
299 uint64_t datalen, void *user_data,
300 void *stream_user_data);
301
302static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
303{
304 struct Curl_cfilter *cf = conn_ref->user_data;
305 struct cf_ngtcp2_ctx *ctx = cf->ctx;
306 return ctx->qconn;
307}
308
309#ifdef DEBUG_NGTCP2
310static void quic_printf(void *user_data, const char *fmt, ...)
311{
312 struct Curl_cfilter *cf = user_data;
313 struct cf_ngtcp2_ctx *ctx = cf->ctx;
314
315 (void)ctx; /* TODO: need an easy handle to infof() message */
316 va_list ap;
317 va_start(ap, fmt);
318 vfprintf(stderr, fmt, ap);
319 va_end(ap);
320 fprintf(stderr, "\n");
321}
322#endif
323
324static void qlog_callback(void *user_data, uint32_t flags,
325 const void *data, size_t datalen)
326{
327 struct Curl_cfilter *cf = user_data;
328 struct cf_ngtcp2_ctx *ctx = cf->ctx;
329 (void)flags;
330 if(ctx->qlogfd != -1) {
331 ssize_t rc = write(ctx->qlogfd, data, datalen);
332 if(rc == -1) {
333 /* on write error, stop further write attempts */
334 close(ctx->qlogfd);
335 ctx->qlogfd = -1;
336 }
337 }
338
339}
340
341static void quic_settings(struct cf_ngtcp2_ctx *ctx,
342 struct Curl_easy *data,
343 struct pkt_io_ctx *pktx)
344{
345 ngtcp2_settings *s = &ctx->settings;
346 ngtcp2_transport_params *t = &ctx->transport_params;
347
348 ngtcp2_settings_default(s);
349 ngtcp2_transport_params_default(t);
350#ifdef DEBUG_NGTCP2
351 s->log_printf = quic_printf;
352#else
353 s->log_printf = NULL;
354#endif
355
356 (void)data;
357 s->initial_ts = pktx->ts;
358 s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT;
359 s->max_window = 100 * ctx->max_stream_window;
360 s->max_stream_window = ctx->max_stream_window;
361
362 t->initial_max_data = 10 * ctx->max_stream_window;
363 t->initial_max_stream_data_bidi_local = ctx->max_stream_window;
364 t->initial_max_stream_data_bidi_remote = ctx->max_stream_window;
365 t->initial_max_stream_data_uni = ctx->max_stream_window;
366 t->initial_max_streams_bidi = QUIC_MAX_STREAMS;
367 t->initial_max_streams_uni = QUIC_MAX_STREAMS;
368 t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS);
369 if(ctx->qlogfd != -1) {
370 s->qlog_write = qlog_callback;
371 }
372}
373
374static int init_ngh3_conn(struct Curl_cfilter *cf);
375
376static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
377{
378 (void)user_data;
379 (void)tconn;
380 return 0;
381}
382
383static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
384 int64_t stream_id, uint64_t offset,
385 const uint8_t *buf, size_t buflen,
386 void *user_data, void *stream_user_data)
387{
388 struct Curl_cfilter *cf = user_data;
389 struct cf_ngtcp2_ctx *ctx = cf->ctx;
390 nghttp3_ssize nconsumed;
391 int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
392 struct Curl_easy *data = stream_user_data;
393 (void)offset;
394 (void)data;
395
396 nconsumed =
397 nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin);
398 CURL_TRC_CF(data, cf, "[%" PRId64 "] read_stream(len=%zu) -> %zd",
399 stream_id, buflen, nconsumed);
400 if(nconsumed < 0) {
401 if(!data) {
402 struct Curl_easy *cdata = CF_DATA_CURRENT(cf);
403 CURL_TRC_CF(cdata, cf, "[%" PRId64 "] nghttp3 error on stream not "
404 "used by us, ignored", stream_id);
405 return 0;
406 }
407 ngtcp2_ccerr_set_application_error(
408 &ctx->last_error,
409 nghttp3_err_infer_quic_app_error_code((int)nconsumed), NULL, 0);
410 return NGTCP2_ERR_CALLBACK_FAILURE;
411 }
412
413 /* number of bytes inside buflen which consists of framing overhead
414 * including QPACK HEADERS. In other words, it does not consume payload of
415 * DATA frame. */
416 ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
417 ngtcp2_conn_extend_max_offset(tconn, nconsumed);
418
419 return 0;
420}
421
422static int
423cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
424 uint64_t offset, uint64_t datalen, void *user_data,
425 void *stream_user_data)
426{
427 struct Curl_cfilter *cf = user_data;
428 struct cf_ngtcp2_ctx *ctx = cf->ctx;
429 int rv;
430 (void)stream_id;
431 (void)tconn;
432 (void)offset;
433 (void)datalen;
434 (void)stream_user_data;
435
436 rv = nghttp3_conn_add_ack_offset(ctx->h3conn, stream_id, datalen);
437 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
438 return NGTCP2_ERR_CALLBACK_FAILURE;
439 }
440
441 return 0;
442}
443
444static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
445 int64_t stream3_id, uint64_t app_error_code,
446 void *user_data, void *stream_user_data)
447{
448 struct Curl_cfilter *cf = user_data;
449 struct Curl_easy *data = stream_user_data;
450 struct cf_ngtcp2_ctx *ctx = cf->ctx;
451 int rv;
452
453 (void)tconn;
454 (void)data;
455 /* stream is closed... */
456
457 if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
458 app_error_code = NGHTTP3_H3_NO_ERROR;
459 }
460
461 rv = nghttp3_conn_close_stream(ctx->h3conn, stream3_id,
462 app_error_code);
463 CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(err=%"
464 PRIu64 ") -> %d", stream3_id, app_error_code, rv);
465 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
466 ngtcp2_ccerr_set_application_error(
467 &ctx->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0);
468 return NGTCP2_ERR_CALLBACK_FAILURE;
469 }
470
471 return 0;
472}
473
474static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
475 uint64_t final_size, uint64_t app_error_code,
476 void *user_data, void *stream_user_data)
477{
478 struct Curl_cfilter *cf = user_data;
479 struct cf_ngtcp2_ctx *ctx = cf->ctx;
480 struct Curl_easy *data = stream_user_data;
481 int rv;
482 (void)tconn;
483 (void)final_size;
484 (void)app_error_code;
485 (void)data;
486
487 rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
488 CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
489 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
490 return NGTCP2_ERR_CALLBACK_FAILURE;
491 }
492
493 return 0;
494}
495
496static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
497 uint64_t app_error_code, void *user_data,
498 void *stream_user_data)
499{
500 struct Curl_cfilter *cf = user_data;
501 struct cf_ngtcp2_ctx *ctx = cf->ctx;
502 int rv;
503 (void)tconn;
504 (void)app_error_code;
505 (void)stream_user_data;
506
507 rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
508 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
509 return NGTCP2_ERR_CALLBACK_FAILURE;
510 }
511
512 return 0;
513}
514
515static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
516 uint64_t max_streams,
517 void *user_data)
518{
519 (void)tconn;
520 (void)max_streams;
521 (void)user_data;
522
523 return 0;
524}
525
526static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
527 uint64_t max_data, void *user_data,
528 void *stream_user_data)
529{
530 struct Curl_cfilter *cf = user_data;
531 struct cf_ngtcp2_ctx *ctx = cf->ctx;
532 struct Curl_easy *data = CF_DATA_CURRENT(cf);
533 struct Curl_easy *s_data;
534 struct h3_stream_ctx *stream;
535 int rv;
536 (void)tconn;
537 (void)max_data;
538 (void)stream_user_data;
539
540 rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id);
541 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
542 return NGTCP2_ERR_CALLBACK_FAILURE;
543 }
544 s_data = get_stream_easy(cf, data, stream_id);
545 stream = H3_STREAM_CTX(s_data);
546 if(stream && stream->quic_flow_blocked) {
547 CURL_TRC_CF(data, cf, "[%" PRId64 "] unblock quic flow", stream_id);
548 stream->quic_flow_blocked = FALSE;
549 h3_drain_stream(cf, data);
550 }
551 return 0;
552}
553
554static void cb_rand(uint8_t *dest, size_t destlen,
555 const ngtcp2_rand_ctx *rand_ctx)
556{
557 CURLcode result;
558 (void)rand_ctx;
559
560 result = Curl_rand(NULL, dest, destlen);
561 if(result) {
562 /* cb_rand is only used for non-cryptographic context. If Curl_rand
563 failed, just fill 0 and call it *random*. */
564 memset(dest, 0, destlen);
565 }
566}
567
568static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
569 uint8_t *token, size_t cidlen,
570 void *user_data)
571{
572 CURLcode result;
573 (void)tconn;
574 (void)user_data;
575
576 result = Curl_rand(NULL, cid->data, cidlen);
577 if(result)
578 return NGTCP2_ERR_CALLBACK_FAILURE;
579 cid->datalen = cidlen;
580
581 result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
582 if(result)
583 return NGTCP2_ERR_CALLBACK_FAILURE;
584
585 return 0;
586}
587
588static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level,
589 void *user_data)
590{
591 struct Curl_cfilter *cf = user_data;
592 (void)tconn;
593
594 if(level != NGTCP2_ENCRYPTION_LEVEL_1RTT) {
595 return 0;
596 }
597
598 if(init_ngh3_conn(cf) != CURLE_OK) {
599 return NGTCP2_ERR_CALLBACK_FAILURE;
600 }
601
602 return 0;
603}
604
605static ngtcp2_callbacks ng_callbacks = {
606 ngtcp2_crypto_client_initial_cb,
607 NULL, /* recv_client_initial */
608 ngtcp2_crypto_recv_crypto_data_cb,
609 cb_handshake_completed,
610 NULL, /* recv_version_negotiation */
611 ngtcp2_crypto_encrypt_cb,
612 ngtcp2_crypto_decrypt_cb,
613 ngtcp2_crypto_hp_mask_cb,
614 cb_recv_stream_data,
615 cb_acked_stream_data_offset,
616 NULL, /* stream_open */
617 cb_stream_close,
618 NULL, /* recv_stateless_reset */
619 ngtcp2_crypto_recv_retry_cb,
620 cb_extend_max_local_streams_bidi,
621 NULL, /* extend_max_local_streams_uni */
622 cb_rand,
623 cb_get_new_connection_id,
624 NULL, /* remove_connection_id */
625 ngtcp2_crypto_update_key_cb, /* update_key */
626 NULL, /* path_validation */
627 NULL, /* select_preferred_addr */
628 cb_stream_reset,
629 NULL, /* extend_max_remote_streams_bidi */
630 NULL, /* extend_max_remote_streams_uni */
631 cb_extend_max_stream_data,
632 NULL, /* dcid_status */
633 NULL, /* handshake_confirmed */
634 NULL, /* recv_new_token */
635 ngtcp2_crypto_delete_crypto_aead_ctx_cb,
636 ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
637 NULL, /* recv_datagram */
638 NULL, /* ack_datagram */
639 NULL, /* lost_datagram */
640 ngtcp2_crypto_get_path_challenge_data_cb,
641 cb_stream_stop_sending,
642 NULL, /* version_negotiation */
643 cb_recv_rx_key,
644 NULL, /* recv_tx_key */
645 NULL, /* early_data_rejected */
646};
647
648/**
649 * Connection maintenance like timeouts on packet ACKs etc. are done by us, not
650 * the OS like for TCP. POLL events on the socket therefore are not
651 * sufficient.
652 * ngtcp2 tells us when it wants to be invoked again. We handle that via
653 * the `Curl_expire()` mechanisms.
654 */
655static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
656 struct Curl_easy *data,
657 struct pkt_io_ctx *pktx)
658{
659 struct cf_ngtcp2_ctx *ctx = cf->ctx;
660 struct pkt_io_ctx local_pktx;
661 ngtcp2_tstamp expiry;
662
663 if(!pktx) {
664 pktx_init(&local_pktx, cf, data);
665 pktx = &local_pktx;
666 }
667 else {
668 pktx_update_time(pktx, cf);
669 }
670
671 expiry = ngtcp2_conn_get_expiry(ctx->qconn);
672 if(expiry != UINT64_MAX) {
673 if(expiry <= pktx->ts) {
674 CURLcode result;
675 int rv = ngtcp2_conn_handle_expiry(ctx->qconn, pktx->ts);
676 if(rv) {
677 failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
678 ngtcp2_strerror(rv));
679 ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
680 return CURLE_SEND_ERROR;
681 }
682 result = cf_progress_ingress(cf, data, pktx);
683 if(result)
684 return result;
685 result = cf_progress_egress(cf, data, pktx);
686 if(result)
687 return result;
688 /* ask again, things might have changed */
689 expiry = ngtcp2_conn_get_expiry(ctx->qconn);
690 }
691
692 if(expiry > pktx->ts) {
693 ngtcp2_duration timeout = expiry - pktx->ts;
694 if(timeout % NGTCP2_MILLISECONDS) {
695 timeout += NGTCP2_MILLISECONDS;
696 }
697 Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
698 }
699 }
700 return CURLE_OK;
701}
702
703static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
704 struct Curl_easy *data,
705 struct easy_pollset *ps)
706{
707 struct cf_ngtcp2_ctx *ctx = cf->ctx;
708 bool want_recv, want_send;
709
710 if(!ctx->qconn)
711 return;
712
713 Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
714 if(want_recv || want_send) {
715 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
716 struct cf_call_data save;
717 bool c_exhaust, s_exhaust;
718
719 CF_DATA_SAVE(save, cf, data);
720 c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
721 !ngtcp2_conn_get_max_data_left(ctx->qconn));
722 s_exhaust = want_send && stream && stream->id >= 0 &&
723 stream->quic_flow_blocked;
724 want_recv = (want_recv || c_exhaust || s_exhaust);
725 want_send = (!s_exhaust && want_send) ||
726 !Curl_bufq_is_empty(&ctx->q.sendbuf);
727
728 Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
729 CF_DATA_RESTORE(cf, save);
730 }
731}
732
733static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
734 uint64_t app_error_code, void *user_data,
735 void *stream_user_data)
736{
737 struct Curl_cfilter *cf = user_data;
738 struct Curl_easy *data = stream_user_data;
739 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
740 (void)conn;
741 (void)stream_id;
742
743 /* we might be called by nghttp3 after we already cleaned up */
744 if(!stream)
745 return 0;
746
747 stream->closed = TRUE;
748 stream->error3 = app_error_code;
749 if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
750 stream->reset = TRUE;
751 stream->send_closed = TRUE;
752 CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64,
753 stream->id, stream->error3);
754 }
755 else {
756 CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->id);
757 }
758 h3_drain_stream(cf, data);
759 return 0;
760}
761
762static CURLcode write_resp_hds(struct Curl_easy *data,
763 const char *buf, size_t blen)
764{
765 return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
766}
767
768static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
769 const uint8_t *buf, size_t blen,
770 void *user_data, void *stream_user_data)
771{
772 struct Curl_cfilter *cf = user_data;
773 struct cf_ngtcp2_ctx *ctx = cf->ctx;
774 struct Curl_easy *data = stream_user_data;
775 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
776 CURLcode result;
777
778 (void)conn;
779 (void)stream3_id;
780
781 if(!stream)
782 return NGHTTP3_ERR_CALLBACK_FAILURE;
783
784 result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
785 if(result) {
786 CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
787 stream->id, blen, result);
788 return NGHTTP3_ERR_CALLBACK_FAILURE;
789 }
790 if(blen) {
791 CURL_TRC_CF(data, cf, "[%" PRId64 "] ACK %zu bytes of DATA",
792 stream->id, blen);
793 ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen);
794 ngtcp2_conn_extend_max_offset(ctx->qconn, blen);
795 }
796 CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, blen);
797 return 0;
798}
799
800static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream3_id,
801 size_t consumed, void *user_data,
802 void *stream_user_data)
803{
804 struct Curl_cfilter *cf = user_data;
805 struct cf_ngtcp2_ctx *ctx = cf->ctx;
806 (void)conn;
807 (void)stream_user_data;
808
809 /* nghttp3 has consumed bytes on the QUIC stream and we need to
810 * tell the QUIC connection to increase its flow control */
811 ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream3_id, consumed);
812 ngtcp2_conn_extend_max_offset(ctx->qconn, consumed);
813 return 0;
814}
815
816static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
817 int fin, void *user_data, void *stream_user_data)
818{
819 struct Curl_cfilter *cf = user_data;
820 struct Curl_easy *data = stream_user_data;
821 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
822 CURLcode result = CURLE_OK;
823 (void)conn;
824 (void)stream_id;
825 (void)fin;
826 (void)cf;
827
828 if(!stream)
829 return 0;
830 /* add a CRLF only if we've received some headers */
831 result = write_resp_hds(data, "\r\n", 2);
832 if(result) {
833 return -1;
834 }
835
836 CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d",
837 stream_id, stream->status_code);
838 if(stream->status_code / 100 != 1) {
839 stream->resp_hds_complete = TRUE;
840 }
841 h3_drain_stream(cf, data);
842 return 0;
843}
844
845static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
846 int32_t token, nghttp3_rcbuf *name,
847 nghttp3_rcbuf *value, uint8_t flags,
848 void *user_data, void *stream_user_data)
849{
850 struct Curl_cfilter *cf = user_data;
851 nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
852 nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
853 struct Curl_easy *data = stream_user_data;
854 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
855 CURLcode result = CURLE_OK;
856 (void)conn;
857 (void)stream_id;
858 (void)token;
859 (void)flags;
860 (void)cf;
861
862 /* we might have cleaned up this transfer already */
863 if(!stream)
864 return 0;
865
866 if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
867 char line[14]; /* status line is always 13 characters long */
868 size_t ncopy;
869
870 result = Curl_http_decode_status(&stream->status_code,
871 (const char *)h3val.base, h3val.len);
872 if(result)
873 return -1;
874 ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
875 stream->status_code);
876 CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line);
877 result = write_resp_hds(data, line, ncopy);
878 if(result) {
879 return -1;
880 }
881 }
882 else {
883 /* store as an HTTP1-style header */
884 CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
885 stream_id, (int)h3name.len, h3name.base,
886 (int)h3val.len, h3val.base);
887 result = write_resp_hds(data, (const char *)h3name.base, h3name.len);
888 if(result) {
889 return -1;
890 }
891 result = write_resp_hds(data, ": ", 2);
892 if(result) {
893 return -1;
894 }
895 result = write_resp_hds(data, (const char *)h3val.base, h3val.len);
896 if(result) {
897 return -1;
898 }
899 result = write_resp_hds(data, "\r\n", 2);
900 if(result) {
901 return -1;
902 }
903 }
904 return 0;
905}
906
907static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
908 uint64_t app_error_code, void *user_data,
909 void *stream_user_data)
910{
911 struct Curl_cfilter *cf = user_data;
912 struct cf_ngtcp2_ctx *ctx = cf->ctx;
913 int rv;
914 (void)conn;
915 (void)stream_user_data;
916
917 rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id,
918 app_error_code);
919 if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
920 return NGTCP2_ERR_CALLBACK_FAILURE;
921 }
922
923 return 0;
924}
925
926static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
927 uint64_t app_error_code, void *user_data,
928 void *stream_user_data) {
929 struct Curl_cfilter *cf = user_data;
930 struct cf_ngtcp2_ctx *ctx = cf->ctx;
931 struct Curl_easy *data = stream_user_data;
932 int rv;
933 (void)conn;
934 (void)data;
935
936 rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id,
937 app_error_code);
938 CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
939 if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
940 return NGTCP2_ERR_CALLBACK_FAILURE;
941 }
942
943 return 0;
944}
945
946static nghttp3_callbacks ngh3_callbacks = {
947 cb_h3_acked_req_body, /* acked_stream_data */
948 cb_h3_stream_close,
949 cb_h3_recv_data,
950 cb_h3_deferred_consume,
951 NULL, /* begin_headers */
952 cb_h3_recv_header,
953 cb_h3_end_headers,
954 NULL, /* begin_trailers */
955 cb_h3_recv_header,
956 NULL, /* end_trailers */
957 cb_h3_stop_sending,
958 NULL, /* end_stream */
959 cb_h3_reset_stream,
960 NULL, /* shutdown */
961 NULL /* recv_settings */
962};
963
964static int init_ngh3_conn(struct Curl_cfilter *cf)
965{
966 struct cf_ngtcp2_ctx *ctx = cf->ctx;
967 CURLcode result;
968 int rc;
969 int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
970
971 if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) {
972 return CURLE_QUIC_CONNECT_ERROR;
973 }
974
975 nghttp3_settings_default(&ctx->h3settings);
976
977 rc = nghttp3_conn_client_new(&ctx->h3conn,
978 &ngh3_callbacks,
979 &ctx->h3settings,
980 nghttp3_mem_default(),
981 cf);
982 if(rc) {
983 result = CURLE_OUT_OF_MEMORY;
984 goto fail;
985 }
986
987 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &ctrl_stream_id, NULL);
988 if(rc) {
989 result = CURLE_QUIC_CONNECT_ERROR;
990 goto fail;
991 }
992
993 rc = nghttp3_conn_bind_control_stream(ctx->h3conn, ctrl_stream_id);
994 if(rc) {
995 result = CURLE_QUIC_CONNECT_ERROR;
996 goto fail;
997 }
998
999 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_enc_stream_id, NULL);
1000 if(rc) {
1001 result = CURLE_QUIC_CONNECT_ERROR;
1002 goto fail;
1003 }
1004
1005 rc = ngtcp2_conn_open_uni_stream(ctx->qconn, &qpack_dec_stream_id, NULL);
1006 if(rc) {
1007 result = CURLE_QUIC_CONNECT_ERROR;
1008 goto fail;
1009 }
1010
1011 rc = nghttp3_conn_bind_qpack_streams(ctx->h3conn, qpack_enc_stream_id,
1012 qpack_dec_stream_id);
1013 if(rc) {
1014 result = CURLE_QUIC_CONNECT_ERROR;
1015 goto fail;
1016 }
1017
1018 return CURLE_OK;
1019fail:
1020
1021 return result;
1022}
1023
1024static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
1025 struct Curl_easy *data,
1026 struct h3_stream_ctx *stream,
1027 CURLcode *err)
1028{
1029 ssize_t nread = -1;
1030
1031 (void)cf;
1032 if(stream->reset) {
1033 failf(data,
1034 "HTTP/3 stream %" PRId64 " reset by server", stream->id);
1035 *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
1036 goto out;
1037 }
1038 else if(!stream->resp_hds_complete) {
1039 failf(data,
1040 "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
1041 " all response header fields, treated as error",
1042 stream->id);
1043 *err = CURLE_HTTP3;
1044 goto out;
1045 }
1046 *err = CURLE_OK;
1047 nread = 0;
1048
1049out:
1050 return nread;
1051}
1052
1053/* incoming data frames on the h3 stream */
1054static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1055 char *buf, size_t blen, CURLcode *err)
1056{
1057 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1058 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1059 ssize_t nread = -1;
1060 struct cf_call_data save;
1061 struct pkt_io_ctx pktx;
1062
1063 (void)ctx;
1064 (void)buf;
1065
1066 CF_DATA_SAVE(save, cf, data);
1067 DEBUGASSERT(cf->connected);
1068 DEBUGASSERT(ctx);
1069 DEBUGASSERT(ctx->qconn);
1070 DEBUGASSERT(ctx->h3conn);
1071 *err = CURLE_OK;
1072
1073 pktx_init(&pktx, cf, data);
1074
1075 if(!stream) {
1076 *err = CURLE_RECV_ERROR;
1077 goto out;
1078 }
1079
1080 if(cf_progress_ingress(cf, data, &pktx)) {
1081 *err = CURLE_RECV_ERROR;
1082 nread = -1;
1083 goto out;
1084 }
1085
1086 if(stream->closed) {
1087 nread = recv_closed_stream(cf, data, stream, err);
1088 goto out;
1089 }
1090 *err = CURLE_AGAIN;
1091 nread = -1;
1092
1093out:
1094 if(cf_progress_egress(cf, data, &pktx)) {
1095 *err = CURLE_SEND_ERROR;
1096 nread = -1;
1097 }
1098 else {
1099 CURLcode result2 = check_and_set_expiry(cf, data, &pktx);
1100 if(result2) {
1101 *err = result2;
1102 nread = -1;
1103 }
1104 }
1105 CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
1106 stream? stream->id : -1, blen, nread, *err);
1107 CF_DATA_RESTORE(cf, save);
1108 return nread;
1109}
1110
1111static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
1112 uint64_t datalen, void *user_data,
1113 void *stream_user_data)
1114{
1115 struct Curl_cfilter *cf = user_data;
1116 struct Curl_easy *data = stream_user_data;
1117 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1118 size_t skiplen;
1119
1120 (void)cf;
1121 if(!stream)
1122 return 0;
1123 /* The server acknowledged `datalen` of bytes from our request body.
1124 * This is a delta. We have kept this data in `sendbuf` for
1125 * re-transmissions and can free it now. */
1126 if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
1127 skiplen = stream->sendbuf_len_in_flight;
1128 else
1129 skiplen = (size_t)datalen;
1130 Curl_bufq_skip(&stream->sendbuf, skiplen);
1131 stream->sendbuf_len_in_flight -= skiplen;
1132
1133 /* Everything ACKed, we resume upload processing */
1134 if(!stream->sendbuf_len_in_flight) {
1135 int rv = nghttp3_conn_resume_stream(conn, stream_id);
1136 if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
1137 return NGTCP2_ERR_CALLBACK_FAILURE;
1138 }
1139 }
1140 return 0;
1141}
1142
1143static nghttp3_ssize
1144cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
1145 nghttp3_vec *vec, size_t veccnt,
1146 uint32_t *pflags, void *user_data,
1147 void *stream_user_data)
1148{
1149 struct Curl_cfilter *cf = user_data;
1150 struct Curl_easy *data = stream_user_data;
1151 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1152 ssize_t nwritten = 0;
1153 size_t nvecs = 0;
1154 (void)cf;
1155 (void)conn;
1156 (void)stream_id;
1157 (void)user_data;
1158 (void)veccnt;
1159
1160 if(!stream)
1161 return NGHTTP3_ERR_CALLBACK_FAILURE;
1162 /* nghttp3 keeps references to the sendbuf data until it is ACKed
1163 * by the server (see `cb_h3_acked_req_body()` for updates).
1164 * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
1165 * that we have already passed to nghttp3, but which have not been
1166 * ACKed yet.
1167 * Any amount beyond `sendbuf_len_in_flight` we need still to pass
1168 * to nghttp3. Do that now, if we can. */
1169 if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
1170 nvecs = 0;
1171 while(nvecs < veccnt &&
1172 Curl_bufq_peek_at(&stream->sendbuf,
1173 stream->sendbuf_len_in_flight,
1174 (const unsigned char **)&vec[nvecs].base,
1175 &vec[nvecs].len)) {
1176 stream->sendbuf_len_in_flight += vec[nvecs].len;
1177 nwritten += vec[nvecs].len;
1178 ++nvecs;
1179 }
1180 DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */
1181 }
1182
1183 if(nwritten > 0 && stream->upload_left != -1)
1184 stream->upload_left -= nwritten;
1185
1186 /* When we stopped sending and everything in `sendbuf` is "in flight",
1187 * we are at the end of the request body. */
1188 if(stream->upload_left == 0) {
1189 *pflags = NGHTTP3_DATA_FLAG_EOF;
1190 stream->send_closed = TRUE;
1191 }
1192 else if(!nwritten) {
1193 /* Not EOF, and nothing to give, we signal WOULDBLOCK. */
1194 CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN",
1195 stream->id);
1196 return NGHTTP3_ERR_WOULDBLOCK;
1197 }
1198
1199 CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> "
1200 "%d vecs%s with %zu (buffered=%zu, left=%"
1201 CURL_FORMAT_CURL_OFF_T ")",
1202 stream->id, (int)nvecs,
1203 *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
1204 nwritten, Curl_bufq_len(&stream->sendbuf),
1205 stream->upload_left);
1206 return (nghttp3_ssize)nvecs;
1207}
1208
1209/* Index where :authority header field will appear in request header
1210 field list. */
1211#define AUTHORITY_DST_IDX 3
1212
1213static ssize_t h3_stream_open(struct Curl_cfilter *cf,
1214 struct Curl_easy *data,
1215 const void *buf, size_t len,
1216 CURLcode *err)
1217{
1218 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1219 struct h3_stream_ctx *stream = NULL;
1220 struct dynhds h2_headers;
1221 size_t nheader;
1222 nghttp3_nv *nva = NULL;
1223 int rc = 0;
1224 unsigned int i;
1225 ssize_t nwritten = -1;
1226 nghttp3_data_reader reader;
1227 nghttp3_data_reader *preader = NULL;
1228
1229 Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
1230
1231 *err = h3_data_setup(cf, data);
1232 if(*err)
1233 goto out;
1234 stream = H3_STREAM_CTX(data);
1235 DEBUGASSERT(stream);
1236 if(!stream) {
1237 *err = CURLE_FAILED_INIT;
1238 goto out;
1239 }
1240
1241 nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
1242 if(nwritten < 0)
1243 goto out;
1244 if(!stream->h1.done) {
1245 /* need more data */
1246 goto out;
1247 }
1248 DEBUGASSERT(stream->h1.req);
1249
1250 *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
1251 if(*err) {
1252 nwritten = -1;
1253 goto out;
1254 }
1255 /* no longer needed */
1256 Curl_h1_req_parse_free(&stream->h1);
1257
1258 nheader = Curl_dynhds_count(&h2_headers);
1259 nva = malloc(sizeof(nghttp3_nv) * nheader);
1260 if(!nva) {
1261 *err = CURLE_OUT_OF_MEMORY;
1262 nwritten = -1;
1263 goto out;
1264 }
1265
1266 for(i = 0; i < nheader; ++i) {
1267 struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
1268 nva[i].name = (unsigned char *)e->name;
1269 nva[i].namelen = e->namelen;
1270 nva[i].value = (unsigned char *)e->value;
1271 nva[i].valuelen = e->valuelen;
1272 nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1273 }
1274
1275 rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &stream->id, data);
1276 if(rc) {
1277 failf(data, "can get bidi streams");
1278 *err = CURLE_SEND_ERROR;
1279 goto out;
1280 }
1281
1282 switch(data->state.httpreq) {
1283 case HTTPREQ_POST:
1284 case HTTPREQ_POST_FORM:
1285 case HTTPREQ_POST_MIME:
1286 case HTTPREQ_PUT:
1287 /* known request body size or -1 */
1288 if(data->state.infilesize != -1)
1289 stream->upload_left = data->state.infilesize;
1290 else
1291 /* data sending without specifying the data amount up front */
1292 stream->upload_left = -1; /* unknown */
1293 break;
1294 default:
1295 /* there is not request body */
1296 stream->upload_left = 0; /* no request body */
1297 break;
1298 }
1299
1300 stream->send_closed = (stream->upload_left == 0);
1301 if(!stream->send_closed) {
1302 reader.read_data = cb_h3_read_req_body;
1303 preader = &reader;
1304 }
1305
1306 rc = nghttp3_conn_submit_request(ctx->h3conn, stream->id,
1307 nva, nheader, preader, data);
1308 if(rc) {
1309 switch(rc) {
1310 case NGHTTP3_ERR_CONN_CLOSING:
1311 CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, "
1312 "connection is closing", stream->id);
1313 break;
1314 default:
1315 CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)",
1316 stream->id, rc, ngtcp2_strerror(rc));
1317 break;
1318 }
1319 *err = CURLE_SEND_ERROR;
1320 nwritten = -1;
1321 goto out;
1322 }
1323
1324 if(Curl_trc_is_verbose(data)) {
1325 infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
1326 stream->id, data->state.url);
1327 for(i = 0; i < nheader; ++i) {
1328 infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id,
1329 (int)nva[i].namelen, nva[i].name,
1330 (int)nva[i].valuelen, nva[i].value);
1331 }
1332 }
1333
1334out:
1335 free(nva);
1336 Curl_dynhds_free(&h2_headers);
1337 return nwritten;
1338}
1339
1340static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1341 const void *buf, size_t len, CURLcode *err)
1342{
1343 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1344 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1345 ssize_t sent = 0;
1346 struct cf_call_data save;
1347 struct pkt_io_ctx pktx;
1348 CURLcode result;
1349
1350 CF_DATA_SAVE(save, cf, data);
1351 DEBUGASSERT(cf->connected);
1352 DEBUGASSERT(ctx->qconn);
1353 DEBUGASSERT(ctx->h3conn);
1354 pktx_init(&pktx, cf, data);
1355 *err = CURLE_OK;
1356
1357 result = cf_progress_ingress(cf, data, &pktx);
1358 if(result) {
1359 *err = result;
1360 sent = -1;
1361 }
1362
1363 if(!stream || stream->id < 0) {
1364 sent = h3_stream_open(cf, data, buf, len, err);
1365 if(sent < 0) {
1366 CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
1367 goto out;
1368 }
1369 stream = H3_STREAM_CTX(data);
1370 }
1371 else if(stream->upload_blocked_len) {
1372 /* the data in `buf` has already been submitted or added to the
1373 * buffers, but have been EAGAINed on the last invocation. */
1374 DEBUGASSERT(len >= stream->upload_blocked_len);
1375 if(len < stream->upload_blocked_len) {
1376 /* Did we get called again with a smaller `len`? This should not
1377 * happen. We are not prepared to handle that. */
1378 failf(data, "HTTP/3 send again with decreased length");
1379 *err = CURLE_HTTP3;
1380 sent = -1;
1381 goto out;
1382 }
1383 sent = (ssize_t)stream->upload_blocked_len;
1384 stream->upload_blocked_len = 0;
1385 }
1386 else if(stream->closed) {
1387 if(stream->resp_hds_complete) {
1388 /* Server decided to close the stream after having sent us a final
1389 * response. This is valid if it is not interested in the request
1390 * body. This happens on 30x or 40x responses.
1391 * We silently discard the data sent, since this is not a transport
1392 * error situation. */
1393 CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
1394 "on closed stream with response", stream->id);
1395 *err = CURLE_OK;
1396 sent = (ssize_t)len;
1397 goto out;
1398 }
1399 CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
1400 "-> stream closed", stream->id, len);
1401 *err = CURLE_HTTP3;
1402 sent = -1;
1403 goto out;
1404 }
1405 else {
1406 sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
1407 CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to "
1408 "sendbuf(len=%zu) -> %zd, %d",
1409 stream->id, len, sent, *err);
1410 if(sent < 0) {
1411 goto out;
1412 }
1413
1414 (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
1415 }
1416
1417 result = cf_progress_egress(cf, data, &pktx);
1418 if(result) {
1419 *err = result;
1420 sent = -1;
1421 }
1422
1423 if(stream && sent > 0 && stream->sendbuf_len_in_flight) {
1424 /* We have unacknowledged DATA and cannot report success to our
1425 * caller. Instead we EAGAIN and remember how much we have already
1426 * "written" into our various internal connection buffers. */
1427 stream->upload_blocked_len = sent;
1428 CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), "
1429 "%zu bytes in flight -> EGAIN", stream->id, len,
1430 stream->sendbuf_len_in_flight);
1431 *err = CURLE_AGAIN;
1432 sent = -1;
1433 }
1434
1435out:
1436 result = check_and_set_expiry(cf, data, &pktx);
1437 if(result) {
1438 *err = result;
1439 sent = -1;
1440 }
1441 CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
1442 stream? stream->id : -1, len, sent, *err);
1443 CF_DATA_RESTORE(cf, save);
1444 return sent;
1445}
1446
1447static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
1448 struct Curl_easy *data)
1449{
1450 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1451
1452 cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1453 cf->conn->httpversion = 30;
1454 cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
1455
1456 return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
1457}
1458
1459static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
1460 struct sockaddr_storage *remote_addr,
1461 socklen_t remote_addrlen, int ecn,
1462 void *userp)
1463{
1464 struct pkt_io_ctx *pktx = userp;
1465 struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
1466 ngtcp2_pkt_info pi;
1467 ngtcp2_path path;
1468 int rv;
1469
1470 ++pktx->pkt_count;
1471 ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
1472 ctx->q.local_addrlen);
1473 ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
1474 remote_addrlen);
1475 pi.ecn = (uint8_t)ecn;
1476
1477 rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts);
1478 if(rv) {
1479 CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
1480 ngtcp2_strerror(rv), rv);
1481 if(!ctx->last_error.error_code) {
1482 if(rv == NGTCP2_ERR_CRYPTO) {
1483 ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
1484 ngtcp2_conn_get_tls_alert(ctx->qconn),
1485 NULL, 0);
1486 }
1487 else {
1488 ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
1489 }
1490 }
1491
1492 if(rv == NGTCP2_ERR_CRYPTO)
1493 /* this is a "TLS problem", but a failed certificate verification
1494 is a common reason for this */
1495 return CURLE_PEER_FAILED_VERIFICATION;
1496 return CURLE_RECV_ERROR;
1497 }
1498
1499 return CURLE_OK;
1500}
1501
1502static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
1503 struct Curl_easy *data,
1504 struct pkt_io_ctx *pktx)
1505{
1506 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1507 struct pkt_io_ctx local_pktx;
1508 size_t pkts_chunk = 128, i;
1509 CURLcode result = CURLE_OK;
1510
1511 if(!pktx) {
1512 pktx_init(&local_pktx, cf, data);
1513 pktx = &local_pktx;
1514 }
1515 else {
1516 pktx_update_time(pktx, cf);
1517 }
1518
1519 result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
1520 if(result)
1521 return result;
1522
1523 for(i = 0; i < 4; ++i) {
1524 if(i)
1525 pktx_update_time(pktx, cf);
1526 pktx->pkt_count = 0;
1527 result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk,
1528 recv_pkt, pktx);
1529 if(result || !pktx->pkt_count) /* error or got nothing */
1530 break;
1531 }
1532 return result;
1533}
1534
1535/**
1536 * Read a network packet to send from ngtcp2 into `buf`.
1537 * Return number of bytes written or -1 with *err set.
1538 */
1539static ssize_t read_pkt_to_send(void *userp,
1540 unsigned char *buf, size_t buflen,
1541 CURLcode *err)
1542{
1543 struct pkt_io_ctx *x = userp;
1544 struct cf_ngtcp2_ctx *ctx = x->cf->ctx;
1545 nghttp3_vec vec[16];
1546 nghttp3_ssize veccnt;
1547 ngtcp2_ssize ndatalen;
1548 uint32_t flags;
1549 int64_t stream_id;
1550 int fin;
1551 ssize_t nwritten, n;
1552 veccnt = 0;
1553 stream_id = -1;
1554 fin = 0;
1555
1556 /* ngtcp2 may want to put several frames from different streams into
1557 * this packet. `NGTCP2_WRITE_STREAM_FLAG_MORE` tells it to do so.
1558 * When `NGTCP2_ERR_WRITE_MORE` is returned, we *need* to make
1559 * another iteration.
1560 * When ngtcp2 is happy (because it has no other frame that would fit
1561 * or it has nothing more to send), it returns the total length
1562 * of the assembled packet. This may be 0 if there was nothing to send. */
1563 nwritten = 0;
1564 *err = CURLE_OK;
1565 for(;;) {
1566
1567 if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) {
1568 veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec,
1569 sizeof(vec) / sizeof(vec[0]));
1570 if(veccnt < 0) {
1571 failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
1572 nghttp3_strerror((int)veccnt));
1573 ngtcp2_ccerr_set_application_error(
1574 &ctx->last_error,
1575 nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0);
1576 *err = CURLE_SEND_ERROR;
1577 return -1;
1578 }
1579 }
1580
1581 flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
1582 (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
1583 n = ngtcp2_conn_writev_stream(ctx->qconn, &x->ps.path,
1584 NULL, buf, buflen,
1585 &ndatalen, flags, stream_id,
1586 (const ngtcp2_vec *)vec, veccnt, x->ts);
1587 if(n == 0) {
1588 /* nothing to send */
1589 *err = CURLE_AGAIN;
1590 nwritten = -1;
1591 goto out;
1592 }
1593 else if(n < 0) {
1594 switch(n) {
1595 case NGTCP2_ERR_STREAM_DATA_BLOCKED: {
1596 struct h3_stream_ctx *stream = H3_STREAM_CTX(x->data);
1597 DEBUGASSERT(ndatalen == -1);
1598 nghttp3_conn_block_stream(ctx->h3conn, stream_id);
1599 CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] block quic flow",
1600 stream_id);
1601 DEBUGASSERT(stream);
1602 if(stream)
1603 stream->quic_flow_blocked = TRUE;
1604 n = 0;
1605 break;
1606 }
1607 case NGTCP2_ERR_STREAM_SHUT_WR:
1608 DEBUGASSERT(ndatalen == -1);
1609 nghttp3_conn_shutdown_stream_write(ctx->h3conn, stream_id);
1610 n = 0;
1611 break;
1612 case NGTCP2_ERR_WRITE_MORE:
1613 /* ngtcp2 wants to send more. update the flow of the stream whose data
1614 * is in the buffer and continue */
1615 DEBUGASSERT(ndatalen >= 0);
1616 n = 0;
1617 break;
1618 default:
1619 DEBUGASSERT(ndatalen == -1);
1620 failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
1621 ngtcp2_strerror((int)n));
1622 ngtcp2_ccerr_set_liberr(&ctx->last_error, (int)n, NULL, 0);
1623 *err = CURLE_SEND_ERROR;
1624 nwritten = -1;
1625 goto out;
1626 }
1627 }
1628
1629 if(ndatalen >= 0) {
1630 /* we add the amount of data bytes to the flow windows */
1631 int rv = nghttp3_conn_add_write_offset(ctx->h3conn, stream_id, ndatalen);
1632 if(rv) {
1633 failf(x->data, "nghttp3_conn_add_write_offset returned error: %s\n",
1634 nghttp3_strerror(rv));
1635 return CURLE_SEND_ERROR;
1636 }
1637 }
1638
1639 if(n > 0) {
1640 /* packet assembled, leave */
1641 nwritten = n;
1642 goto out;
1643 }
1644 }
1645out:
1646 return nwritten;
1647}
1648
1649static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
1650 struct Curl_easy *data,
1651 struct pkt_io_ctx *pktx)
1652{
1653 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1654 ssize_t nread;
1655 size_t max_payload_size, path_max_payload_size, max_pktcnt;
1656 size_t pktcnt = 0;
1657 size_t gsolen = 0; /* this disables gso until we have a clue */
1658 CURLcode curlcode;
1659 struct pkt_io_ctx local_pktx;
1660
1661 if(!pktx) {
1662 pktx_init(&local_pktx, cf, data);
1663 pktx = &local_pktx;
1664 }
1665 else {
1666 pktx_update_time(pktx, cf);
1667 ngtcp2_path_storage_zero(&pktx->ps);
1668 }
1669
1670 curlcode = vquic_flush(cf, data, &ctx->q);
1671 if(curlcode) {
1672 if(curlcode == CURLE_AGAIN) {
1673 Curl_expire(data, 1, EXPIRE_QUIC);
1674 return CURLE_OK;
1675 }
1676 return curlcode;
1677 }
1678
1679 /* In UDP, there is a maximum theoretical packet paload length and
1680 * a minimum payload length that is "guaranteed" to work.
1681 * To detect if this minimum payload can be increased, ngtcp2 sends
1682 * now and then a packet payload larger than the minimum. It that
1683 * is ACKed by the peer, both parties know that it works and
1684 * the subsequent packets can use a larger one.
1685 * This is called PMTUD (Path Maximum Transmission Unit Discovery).
1686 * Since a PMTUD might be rejected right on send, we do not want it
1687 * be followed by other packets of lesser size. Because those would
1688 * also fail then. So, if we detect a PMTUD while buffering, we flush.
1689 */
1690 max_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(ctx->qconn);
1691 path_max_payload_size =
1692 ngtcp2_conn_get_path_max_tx_udp_payload_size(ctx->qconn);
1693 /* maximum number of packets buffered before we flush to the socket */
1694 max_pktcnt = CURLMIN(MAX_PKT_BURST,
1695 ctx->q.sendbuf.chunk_size / max_payload_size);
1696
1697 for(;;) {
1698 /* add the next packet to send, if any, to our buffer */
1699 nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
1700 read_pkt_to_send, pktx, &curlcode);
1701 if(nread < 0) {
1702 if(curlcode != CURLE_AGAIN)
1703 return curlcode;
1704 /* Nothing more to add, flush and leave */
1705 curlcode = vquic_send(cf, data, &ctx->q, gsolen);
1706 if(curlcode) {
1707 if(curlcode == CURLE_AGAIN) {
1708 Curl_expire(data, 1, EXPIRE_QUIC);
1709 return CURLE_OK;
1710 }
1711 return curlcode;
1712 }
1713 goto out;
1714 }
1715
1716 DEBUGASSERT(nread > 0);
1717 if(pktcnt == 0) {
1718 /* first packet in buffer. This is either of a known, "good"
1719 * payload size or it is a PMTUD. We'll see. */
1720 gsolen = (size_t)nread;
1721 }
1722 else if((size_t)nread > gsolen ||
1723 (gsolen > path_max_payload_size && (size_t)nread != gsolen)) {
1724 /* The just added packet is a PMTUD *or* the one(s) before the
1725 * just added were PMTUD and the last one is smaller.
1726 * Flush the buffer before the last add. */
1727 curlcode = vquic_send_tail_split(cf, data, &ctx->q,
1728 gsolen, nread, nread);
1729 if(curlcode) {
1730 if(curlcode == CURLE_AGAIN) {
1731 Curl_expire(data, 1, EXPIRE_QUIC);
1732 return CURLE_OK;
1733 }
1734 return curlcode;
1735 }
1736 pktcnt = 0;
1737 continue;
1738 }
1739
1740 if(++pktcnt >= max_pktcnt || (size_t)nread < gsolen) {
1741 /* Reached MAX_PKT_BURST *or*
1742 * the capacity of our buffer *or*
1743 * last add was shorter than the previous ones, flush */
1744 curlcode = vquic_send(cf, data, &ctx->q, gsolen);
1745 if(curlcode) {
1746 if(curlcode == CURLE_AGAIN) {
1747 Curl_expire(data, 1, EXPIRE_QUIC);
1748 return CURLE_OK;
1749 }
1750 return curlcode;
1751 }
1752 /* pktbuf has been completely sent */
1753 pktcnt = 0;
1754 }
1755 }
1756
1757out:
1758 return CURLE_OK;
1759}
1760
1761/*
1762 * Called from transfer.c:data_pending to know if we should keep looping
1763 * to receive more data from the connection.
1764 */
1765static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf,
1766 const struct Curl_easy *data)
1767{
1768 (void)cf;
1769 (void)data;
1770 return FALSE;
1771}
1772
1773static CURLcode h3_data_pause(struct Curl_cfilter *cf,
1774 struct Curl_easy *data,
1775 bool pause)
1776{
1777 /* TODO: there seems right now no API in ngtcp2 to shrink/enlarge
1778 * the streams windows. As we do in HTTP/2. */
1779 if(!pause) {
1780 h3_drain_stream(cf, data);
1781 Curl_expire(data, 0, EXPIRE_RUN_NOW);
1782 }
1783 return CURLE_OK;
1784}
1785
1786static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
1787 struct Curl_easy *data,
1788 int event, int arg1, void *arg2)
1789{
1790 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1791 CURLcode result = CURLE_OK;
1792 struct cf_call_data save;
1793
1794 CF_DATA_SAVE(save, cf, data);
1795 (void)arg1;
1796 (void)arg2;
1797 switch(event) {
1798 case CF_CTRL_DATA_SETUP:
1799 break;
1800 case CF_CTRL_DATA_PAUSE:
1801 result = h3_data_pause(cf, data, (arg1 != 0));
1802 break;
1803 case CF_CTRL_DATA_DETACH:
1804 h3_data_done(cf, data);
1805 break;
1806 case CF_CTRL_DATA_DONE:
1807 h3_data_done(cf, data);
1808 break;
1809 case CF_CTRL_DATA_DONE_SEND: {
1810 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1811 if(stream && !stream->send_closed) {
1812 stream->send_closed = TRUE;
1813 stream->upload_left = Curl_bufq_len(&stream->sendbuf);
1814 (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
1815 }
1816 break;
1817 }
1818 case CF_CTRL_DATA_IDLE: {
1819 struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
1820 CURL_TRC_CF(data, cf, "data idle");
1821 if(stream && !stream->closed) {
1822 result = check_and_set_expiry(cf, data, NULL);
1823 if(result)
1824 CURL_TRC_CF(data, cf, "data idle, check_and_set_expiry -> %d", result);
1825 }
1826 break;
1827 }
1828 default:
1829 break;
1830 }
1831 CF_DATA_RESTORE(cf, save);
1832 return result;
1833}
1834
1835static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
1836{
1837 struct cf_call_data save = ctx->call_data;
1838
1839 if(ctx->qlogfd != -1) {
1840 close(ctx->qlogfd);
1841 }
1842 Curl_vquic_tls_cleanup(&ctx->tls);
1843 vquic_ctx_free(&ctx->q);
1844 if(ctx->h3conn)
1845 nghttp3_conn_del(ctx->h3conn);
1846 if(ctx->qconn)
1847 ngtcp2_conn_del(ctx->qconn);
1848 Curl_bufcp_free(&ctx->stream_bufcp);
1849 Curl_ssl_peer_cleanup(&ctx->peer);
1850
1851 memset(ctx, 0, sizeof(*ctx));
1852 ctx->qlogfd = -1;
1853 ctx->call_data = save;
1854}
1855
1856static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1857{
1858 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1859 struct cf_call_data save;
1860
1861 CF_DATA_SAVE(save, cf, data);
1862 if(ctx && ctx->qconn) {
1863 char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
1864 struct pkt_io_ctx pktx;
1865 ngtcp2_ssize rc;
1866
1867 CURL_TRC_CF(data, cf, "close");
1868 pktx_init(&pktx, cf, data);
1869 rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */
1870 NULL, /* pkt_info */
1871 (uint8_t *)buffer, sizeof(buffer),
1872 &ctx->last_error, pktx.ts);
1873 if(rc > 0) {
1874 while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
1875 SOCKERRNO == EINTR);
1876 }
1877
1878 cf_ngtcp2_ctx_clear(ctx);
1879 }
1880
1881 cf->connected = FALSE;
1882 CF_DATA_RESTORE(cf, save);
1883}
1884
1885static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1886{
1887 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1888 struct cf_call_data save;
1889
1890 CF_DATA_SAVE(save, cf, data);
1891 CURL_TRC_CF(data, cf, "destroy");
1892 if(ctx) {
1893 cf_ngtcp2_ctx_clear(ctx);
1894 free(ctx);
1895 }
1896 cf->ctx = NULL;
1897 /* No CF_DATA_RESTORE(cf, save) possible */
1898 (void)save;
1899}
1900
1901static CURLcode tls_ctx_setup(struct quic_tls_ctx *ctx,
1902 struct Curl_cfilter *cf,
1903 struct Curl_easy *data)
1904{
1905 (void)cf;
1906#ifdef USE_OPENSSL
1907#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
1908 if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ssl_ctx) != 0) {
1909 failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
1910 return CURLE_FAILED_INIT;
1911 }
1912#else
1913 if(ngtcp2_crypto_quictls_configure_client_context(ctx->ssl_ctx) != 0) {
1914 failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
1915 return CURLE_FAILED_INIT;
1916 }
1917#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
1918#elif defined(USE_GNUTLS)
1919 if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) {
1920 failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
1921 return CURLE_FAILED_INIT;
1922 }
1923#elif defined(USE_WOLFSSL)
1924 if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) {
1925 failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
1926 return CURLE_FAILED_INIT;
1927 }
1928#endif
1929 return CURLE_OK;
1930}
1931
1932/*
1933 * Might be called twice for happy eyeballs.
1934 */
1935static CURLcode cf_connect_start(struct Curl_cfilter *cf,
1936 struct Curl_easy *data,
1937 struct pkt_io_ctx *pktx)
1938{
1939 struct cf_ngtcp2_ctx *ctx = cf->ctx;
1940 int rc;
1941 int rv;
1942 CURLcode result;
1943 const struct Curl_sockaddr_ex *sockaddr = NULL;
1944 int qfd;
1945
1946 ctx->version = NGTCP2_PROTO_VER_MAX;
1947 ctx->max_stream_window = H3_STREAM_WINDOW_SIZE;
1948 ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
1949 Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
1950 H3_STREAM_POOL_SPARES);
1951
1952 result = Curl_ssl_peer_init(&ctx->peer, cf);
1953 if(result)
1954 return result;
1955
1956#define H3_ALPN "\x2h3\x5h3-29"
1957 result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
1958 H3_ALPN, sizeof(H3_ALPN) - 1,
1959 tls_ctx_setup, &ctx->conn_ref);
1960 if(result)
1961 return result;
1962
1963 ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
1964 result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN);
1965 if(result)
1966 return result;
1967
1968 ctx->scid.datalen = NGTCP2_MAX_CIDLEN;
1969 result = Curl_rand(data, ctx->scid.data, NGTCP2_MAX_CIDLEN);
1970 if(result)
1971 return result;
1972
1973 (void)Curl_qlogdir(data, ctx->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
1974 ctx->qlogfd = qfd; /* -1 if failure above */
1975 quic_settings(ctx, data, pktx);
1976
1977 result = vquic_ctx_init(&ctx->q);
1978 if(result)
1979 return result;
1980
1981 Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
1982 if(!sockaddr)
1983 return CURLE_QUIC_CONNECT_ERROR;
1984 ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
1985 rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
1986 &ctx->q.local_addrlen);
1987 if(rv == -1)
1988 return CURLE_QUIC_CONNECT_ERROR;
1989
1990 ngtcp2_addr_init(&ctx->connected_path.local,
1991 (struct sockaddr *)&ctx->q.local_addr,
1992 ctx->q.local_addrlen);
1993 ngtcp2_addr_init(&ctx->connected_path.remote,
1994 &sockaddr->sa_addr, sockaddr->addrlen);
1995
1996 rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
1997 &ctx->connected_path,
1998 NGTCP2_PROTO_VER_V1, &ng_callbacks,
1999 &ctx->settings, &ctx->transport_params,
2000 NULL, cf);
2001 if(rc)
2002 return CURLE_QUIC_CONNECT_ERROR;
2003
2004#ifdef USE_GNUTLS
2005 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls->session);
2006#else
2007 ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl);
2008#endif
2009
2010 ngtcp2_ccerr_default(&ctx->last_error);
2011
2012 ctx->conn_ref.get_conn = get_conn;
2013 ctx->conn_ref.user_data = cf;
2014
2015 return CURLE_OK;
2016}
2017
2018static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
2019 struct Curl_easy *data,
2020 bool blocking, bool *done)
2021{
2022 struct cf_ngtcp2_ctx *ctx = cf->ctx;
2023 CURLcode result = CURLE_OK;
2024 struct cf_call_data save;
2025 struct curltime now;
2026 struct pkt_io_ctx pktx;
2027
2028 if(cf->connected) {
2029 *done = TRUE;
2030 return CURLE_OK;
2031 }
2032
2033 /* Connect the UDP filter first */
2034 if(!cf->next->connected) {
2035 result = Curl_conn_cf_connect(cf->next, data, blocking, done);
2036 if(result || !*done)
2037 return result;
2038 }
2039
2040 *done = FALSE;
2041 now = Curl_now();
2042 pktx_init(&pktx, cf, data);
2043
2044 CF_DATA_SAVE(save, cf, data);
2045
2046 if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) {
2047 /* Not time yet to attempt the next connect */
2048 CURL_TRC_CF(data, cf, "waiting for reconnect time");
2049 goto out;
2050 }
2051
2052 if(!ctx->qconn) {
2053 ctx->started_at = now;
2054 result = cf_connect_start(cf, data, &pktx);
2055 if(result)
2056 goto out;
2057 result = cf_progress_egress(cf, data, &pktx);
2058 /* we do not expect to be able to recv anything yet */
2059 goto out;
2060 }
2061
2062 result = cf_progress_ingress(cf, data, &pktx);
2063 if(result)
2064 goto out;
2065
2066 result = cf_progress_egress(cf, data, &pktx);
2067 if(result)
2068 goto out;
2069
2070 if(ngtcp2_conn_get_handshake_completed(ctx->qconn)) {
2071 ctx->handshake_at = now;
2072 CURL_TRC_CF(data, cf, "handshake complete after %dms",
2073 (int)Curl_timediff(now, ctx->started_at));
2074 result = qng_verify_peer(cf, data);
2075 if(!result) {
2076 CURL_TRC_CF(data, cf, "peer verified");
2077 cf->connected = TRUE;
2078 cf->conn->alpn = CURL_HTTP_VERSION_3;
2079 *done = TRUE;
2080 connkeep(cf->conn, "HTTP/3 default");
2081 }
2082 }
2083
2084out:
2085 if(result == CURLE_RECV_ERROR && ctx->qconn &&
2086 ngtcp2_conn_in_draining_period(ctx->qconn)) {
2087 /* When a QUIC server instance is shutting down, it may send us a
2088 * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
2089 * state. The CONNECT may work in the near future again. Indicate
2090 * that as a "weird" reply. */
2091 result = CURLE_WEIRD_SERVER_REPLY;
2092 }
2093
2094#ifndef CURL_DISABLE_VERBOSE_STRINGS
2095 if(result) {
2096 struct ip_quadruple ip;
2097
2098 Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
2099 infof(data, "QUIC connect to %s port %u failed: %s",
2100 ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
2101 }
2102#endif
2103 if(!result && ctx->qconn) {
2104 result = check_and_set_expiry(cf, data, &pktx);
2105 }
2106 if(result || *done)
2107 CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
2108 CF_DATA_RESTORE(cf, save);
2109 return result;
2110}
2111
2112static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
2113 struct Curl_easy *data,
2114 int query, int *pres1, void *pres2)
2115{
2116 struct cf_ngtcp2_ctx *ctx = cf->ctx;
2117 struct cf_call_data save;
2118
2119 switch(query) {
2120 case CF_QUERY_MAX_CONCURRENT: {
2121 const ngtcp2_transport_params *rp;
2122 DEBUGASSERT(pres1);
2123
2124 CF_DATA_SAVE(save, cf, data);
2125 rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
2126 if(rp)
2127 *pres1 = (rp->initial_max_streams_bidi > INT_MAX)?
2128 INT_MAX : (int)rp->initial_max_streams_bidi;
2129 else /* not arrived yet? */
2130 *pres1 = Curl_multi_max_concurrent_streams(data->multi);
2131 CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
2132 CF_DATA_RESTORE(cf, save);
2133 return CURLE_OK;
2134 }
2135 case CF_QUERY_CONNECT_REPLY_MS:
2136 if(ctx->q.got_first_byte) {
2137 timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
2138 *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
2139 }
2140 else
2141 *pres1 = -1;
2142 return CURLE_OK;
2143 case CF_QUERY_TIMER_CONNECT: {
2144 struct curltime *when = pres2;
2145 if(ctx->q.got_first_byte)
2146 *when = ctx->q.first_byte_at;
2147 return CURLE_OK;
2148 }
2149 case CF_QUERY_TIMER_APPCONNECT: {
2150 struct curltime *when = pres2;
2151 if(cf->connected)
2152 *when = ctx->handshake_at;
2153 return CURLE_OK;
2154 }
2155 default:
2156 break;
2157 }
2158 return cf->next?
2159 cf->next->cft->query(cf->next, data, query, pres1, pres2) :
2160 CURLE_UNKNOWN_OPTION;
2161}
2162
2163static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
2164 struct Curl_easy *data,
2165 bool *input_pending)
2166{
2167 struct cf_ngtcp2_ctx *ctx = cf->ctx;
2168 bool alive = FALSE;
2169 const ngtcp2_transport_params *rp;
2170 struct cf_call_data save;
2171
2172 CF_DATA_SAVE(save, cf, data);
2173 *input_pending = FALSE;
2174 if(!ctx->qconn)
2175 goto out;
2176
2177 /* Both sides of the QUIC connection announce they max idle times in
2178 * the transport parameters. Look at the minimum of both and if
2179 * we exceed this, regard the connection as dead. The other side
2180 * may have completely purged it and will no longer respond
2181 * to any packets from us. */
2182 rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
2183 if(rp) {
2184 timediff_t idletime;
2185 uint64_t idle_ms = ctx->max_idle_ms;
2186
2187 if(rp->max_idle_timeout &&
2188 (rp->max_idle_timeout / NGTCP2_MILLISECONDS) < idle_ms)
2189 idle_ms = (rp->max_idle_timeout / NGTCP2_MILLISECONDS);
2190 idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
2191 if(idletime > 0 && (uint64_t)idletime > idle_ms)
2192 goto out;
2193 }
2194
2195 if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
2196 goto out;
2197
2198 alive = TRUE;
2199 if(*input_pending) {
2200 CURLcode result;
2201 /* This happens before we've sent off a request and the connection is
2202 not in use by any other transfer, there shouldn't be any data here,
2203 only "protocol frames" */
2204 *input_pending = FALSE;
2205 result = cf_progress_ingress(cf, data, NULL);
2206 CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
2207 alive = result? FALSE : TRUE;
2208 }
2209
2210out:
2211 CF_DATA_RESTORE(cf, save);
2212 return alive;
2213}
2214
2215struct Curl_cftype Curl_cft_http3 = {
2216 "HTTP/3",
2217 CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
2218 0,
2219 cf_ngtcp2_destroy,
2220 cf_ngtcp2_connect,
2221 cf_ngtcp2_close,
2222 Curl_cf_def_get_host,
2223 cf_ngtcp2_adjust_pollset,
2224 cf_ngtcp2_data_pending,
2225 cf_ngtcp2_send,
2226 cf_ngtcp2_recv,
2227 cf_ngtcp2_data_event,
2228 cf_ngtcp2_conn_is_alive,
2229 Curl_cf_def_conn_keep_alive,
2230 cf_ngtcp2_query,
2231};
2232
2233CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
2234 struct Curl_easy *data,
2235 struct connectdata *conn,
2236 const struct Curl_addrinfo *ai)
2237{
2238 struct cf_ngtcp2_ctx *ctx = NULL;
2239 struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
2240 CURLcode result;
2241
2242 (void)data;
2243 ctx = calloc(1, sizeof(*ctx));
2244 if(!ctx) {
2245 result = CURLE_OUT_OF_MEMORY;
2246 goto out;
2247 }
2248 ctx->qlogfd = -1;
2249 cf_ngtcp2_ctx_clear(ctx);
2250
2251 result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
2252 if(result)
2253 goto out;
2254
2255 result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
2256 if(result)
2257 goto out;
2258
2259 cf->conn = conn;
2260 udp_cf->conn = cf->conn;
2261 udp_cf->sockindex = cf->sockindex;
2262 cf->next = udp_cf;
2263
2264out:
2265 *pcf = (!result)? cf : NULL;
2266 if(result) {
2267 if(udp_cf)
2268 Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
2269 Curl_safefree(cf);
2270 Curl_safefree(ctx);
2271 }
2272 return result;
2273}
2274
2275bool Curl_conn_is_ngtcp2(const struct Curl_easy *data,
2276 const struct connectdata *conn,
2277 int sockindex)
2278{
2279 struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
2280
2281 (void)data;
2282 for(; cf; cf = cf->next) {
2283 if(cf->cft == &Curl_cft_http3)
2284 return TRUE;
2285 if(cf->cft->flags & CF_TYPE_IP_CONNECT)
2286 return FALSE;
2287 }
2288 return FALSE;
2289}
2290
2291#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette