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