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