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