Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / vquic / ngtcp2.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, 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 #ifdef USE_OPENSSL
31 #include <openssl/err.h>
32 #ifdef OPENSSL_IS_BORINGSSL
33 #include <ngtcp2/ngtcp2_crypto_boringssl.h>
34 #else
35 #include <ngtcp2/ngtcp2_crypto_openssl.h>
36 #endif
37 #include "vtls/openssl.h"
38 #elif defined(USE_GNUTLS)
39 #include <ngtcp2/ngtcp2_crypto_gnutls.h>
40 #include "vtls/gtls.h"
41 #elif defined(USE_WOLFSSL)
42 #include <ngtcp2/ngtcp2_crypto_wolfssl.h>
43 #include "vtls/wolfssl.h"
44 #endif
45 #include "urldata.h"
46 #include "sendf.h"
47 #include "strdup.h"
48 #include "rand.h"
49 #include "ngtcp2.h"
50 #include "multiif.h"
51 #include "strcase.h"
52 #include "connect.h"
53 #include "strerror.h"
54 #include "dynbuf.h"
55 #include "vquic.h"
56 #include "h2h3.h"
57 #include "vtls/keylog.h"
58 #include "vtls/vtls.h"
59
60 /* The last 3 #include files should be in this order */
61 #include "curl_printf.h"
62 #include "curl_memory.h"
63 #include "memdebug.h"
64
65 /* #define DEBUG_NGTCP2 */
66 #ifdef CURLDEBUG
67 #define DEBUG_HTTP3
68 #endif
69 #ifdef DEBUG_HTTP3
70 #define H3BUGF(x) x
71 #else
72 #define H3BUGF(x) do { } while(0)
73 #endif
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
96 #ifdef USE_OPENSSL
97 #define QUIC_CIPHERS                                                          \
98   "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_"               \
99   "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
100 #define QUIC_GROUPS "P-256:X25519:P-384:P-521"
101 #elif defined(USE_GNUTLS)
102 #define QUIC_PRIORITY \
103   "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
104   "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
105   "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
106   "%DISABLE_TLS13_COMPAT_MODE"
107 #elif defined(USE_WOLFSSL)
108 #define QUIC_CIPHERS                                                          \
109   "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_"               \
110   "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
111 #define QUIC_GROUPS "P-256:P-384:P-521"
112 #endif
113
114 /* ngtcp2 default congestion controller does not perform pacing. Limit
115    the maximum packet burst to MAX_PKT_BURST packets. */
116 #define MAX_PKT_BURST 10
117
118 static CURLcode ng_process_ingress(struct Curl_easy *data,
119                                    curl_socket_t sockfd,
120                                    struct quicsocket *qs);
121 static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd,
122                                 struct quicsocket *qs);
123 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
124                                    uint64_t datalen, void *user_data,
125                                    void *stream_user_data);
126
127 static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
128 {
129   struct quicsocket *qs = conn_ref->user_data;
130   return qs->qconn;
131 }
132
133 static ngtcp2_tstamp timestamp(void)
134 {
135   struct curltime ct = Curl_now();
136   return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
137 }
138
139 #ifdef DEBUG_NGTCP2
140 static void quic_printf(void *user_data, const char *fmt, ...)
141 {
142   va_list ap;
143   (void)user_data; /* TODO, use this to do infof() instead long-term */
144   va_start(ap, fmt);
145   vfprintf(stderr, fmt, ap);
146   va_end(ap);
147   fprintf(stderr, "\n");
148 }
149 #endif
150
151 static void qlog_callback(void *user_data, uint32_t flags,
152                           const void *data, size_t datalen)
153 {
154   struct quicsocket *qs = (struct quicsocket *)user_data;
155   (void)flags;
156   if(qs->qlogfd != -1) {
157     ssize_t rc = write(qs->qlogfd, data, datalen);
158     if(rc == -1) {
159       /* on write error, stop further write attempts */
160       close(qs->qlogfd);
161       qs->qlogfd = -1;
162     }
163   }
164
165 }
166
167 static void quic_settings(struct quicsocket *qs,
168                           uint64_t stream_buffer_size)
169 {
170   ngtcp2_settings *s = &qs->settings;
171   ngtcp2_transport_params *t = &qs->transport_params;
172   ngtcp2_settings_default(s);
173   ngtcp2_transport_params_default(t);
174 #ifdef DEBUG_NGTCP2
175   s->log_printf = quic_printf;
176 #else
177   s->log_printf = NULL;
178 #endif
179   s->initial_ts = timestamp();
180   t->initial_max_stream_data_bidi_local = stream_buffer_size;
181   t->initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS;
182   t->initial_max_stream_data_uni = QUIC_MAX_STREAMS;
183   t->initial_max_data = QUIC_MAX_DATA;
184   t->initial_max_streams_bidi = 1;
185   t->initial_max_streams_uni = 3;
186   t->max_idle_timeout = QUIC_IDLE_TIMEOUT;
187   if(qs->qlogfd != -1) {
188     s->qlog.write = qlog_callback;
189   }
190 }
191
192 #ifdef USE_OPENSSL
193 static void keylog_callback(const SSL *ssl, const char *line)
194 {
195   (void)ssl;
196   Curl_tls_keylog_write_line(line);
197 }
198 #elif defined(USE_GNUTLS)
199 static int keylog_callback(gnutls_session_t session, const char *label,
200                     const gnutls_datum_t *secret)
201 {
202   gnutls_datum_t crandom;
203   gnutls_datum_t srandom;
204
205   gnutls_session_get_random(session, &crandom, &srandom);
206   if(crandom.size != 32) {
207     return -1;
208   }
209
210   Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
211   return 0;
212 }
213 #elif defined(USE_WOLFSSL)
214 #if defined(HAVE_SECRET_CALLBACK)
215 static void keylog_callback(const WOLFSSL *ssl, const char *line)
216 {
217   (void)ssl;
218   Curl_tls_keylog_write_line(line);
219 }
220 #endif
221 #endif
222
223 static int init_ngh3_conn(struct quicsocket *qs);
224
225 #ifdef USE_OPENSSL
226 static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
227 {
228   struct connectdata *conn = data->conn;
229   SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
230
231 #ifdef OPENSSL_IS_BORINGSSL
232   if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) {
233     failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
234     return NULL;
235   }
236 #else
237   if(ngtcp2_crypto_openssl_configure_client_context(ssl_ctx) != 0) {
238     failf(data, "ngtcp2_crypto_openssl_configure_client_context failed");
239     return NULL;
240   }
241 #endif
242
243   SSL_CTX_set_default_verify_paths(ssl_ctx);
244
245 #ifdef OPENSSL_IS_BORINGSSL
246   if(SSL_CTX_set1_curves_list(ssl_ctx, QUIC_GROUPS) != 1) {
247     failf(data, "SSL_CTX_set1_curves_list failed");
248     return NULL;
249   }
250 #else
251   if(SSL_CTX_set_ciphersuites(ssl_ctx, QUIC_CIPHERS) != 1) {
252     char error_buffer[256];
253     ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
254     failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer);
255     return NULL;
256   }
257
258   if(SSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) {
259     failf(data, "SSL_CTX_set1_groups_list failed");
260     return NULL;
261   }
262 #endif
263
264   /* Open the file if a TLS or QUIC backend has not done this before. */
265   Curl_tls_keylog_open();
266   if(Curl_tls_keylog_enabled()) {
267     SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
268   }
269
270   if(conn->ssl_config.verifypeer) {
271     const char * const ssl_cafile = conn->ssl_config.CAfile;
272     const char * const ssl_capath = conn->ssl_config.CApath;
273
274     if(ssl_cafile || ssl_capath) {
275       SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
276       /* tell OpenSSL where to find CA certificates that are used to verify
277          the server's certificate. */
278       if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) {
279         /* Fail if we insist on successfully verifying the server. */
280         failf(data, "error setting certificate verify locations:"
281               "  CAfile: %s CApath: %s",
282               ssl_cafile ? ssl_cafile : "none",
283               ssl_capath ? ssl_capath : "none");
284         return NULL;
285       }
286       infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
287       infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
288     }
289 #ifdef CURL_CA_FALLBACK
290     else {
291       /* verifying the peer without any CA certificates won't work so
292          use openssl's built-in default as fallback */
293       SSL_CTX_set_default_verify_paths(ssl_ctx);
294     }
295 #endif
296   }
297   return ssl_ctx;
298 }
299
300 static CURLcode quic_set_client_cert(struct Curl_easy *data,
301                                      struct quicsocket *qs)
302 {
303   struct connectdata *conn = data->conn;
304   SSL_CTX *ssl_ctx = qs->sslctx;
305   char *const ssl_cert = SSL_SET_OPTION(primary.clientcert);
306   const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
307   const char *const ssl_cert_type = SSL_SET_OPTION(cert_type);
308
309   if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
310     return Curl_ossl_set_client_cert(
311         data, ssl_ctx, ssl_cert, ssl_cert_blob, ssl_cert_type,
312         SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob),
313         SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd));
314   }
315
316   return CURLE_OK;
317 }
318
319 /** SSL callbacks ***/
320
321 static int quic_init_ssl(struct quicsocket *qs)
322 {
323   const uint8_t *alpn = NULL;
324   size_t alpnlen = 0;
325   /* this will need some attention when HTTPS proxy over QUIC get fixed */
326   const char * const hostname = qs->conn->host.name;
327
328   DEBUGASSERT(!qs->ssl);
329   qs->ssl = SSL_new(qs->sslctx);
330
331   SSL_set_app_data(qs->ssl, &qs->conn_ref);
332   SSL_set_connect_state(qs->ssl);
333   SSL_set_quic_use_legacy_codepoint(qs->ssl, 0);
334
335   alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
336   alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
337   if(alpn)
338     SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
339
340   /* set SNI */
341   SSL_set_tlsext_host_name(qs->ssl, hostname);
342   return 0;
343 }
344 #elif defined(USE_GNUTLS)
345 static int quic_init_ssl(struct quicsocket *qs)
346 {
347   gnutls_datum_t alpn[2];
348   /* this will need some attention when HTTPS proxy over QUIC get fixed */
349   const char * const hostname = qs->conn->host.name;
350   int rc;
351
352   DEBUGASSERT(!qs->ssl);
353
354   gnutls_init(&qs->ssl, GNUTLS_CLIENT);
355   gnutls_session_set_ptr(qs->ssl, &qs->conn_ref);
356
357   if(ngtcp2_crypto_gnutls_configure_client_session(qs->ssl) != 0) {
358     H3BUGF(fprintf(stderr,
359                    "ngtcp2_crypto_gnutls_configure_client_session failed\n"));
360     return 1;
361   }
362
363   rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
364   if(rc < 0) {
365     H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
366                    gnutls_strerror(rc)));
367     return 1;
368   }
369
370   /* Open the file if a TLS or QUIC backend has not done this before. */
371   Curl_tls_keylog_open();
372   if(Curl_tls_keylog_enabled()) {
373     gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
374   }
375
376   if(qs->cred)
377     gnutls_certificate_free_credentials(qs->cred);
378
379   rc = gnutls_certificate_allocate_credentials(&qs->cred);
380   if(rc < 0) {
381     H3BUGF(fprintf(stderr,
382                    "gnutls_certificate_allocate_credentials failed: %s\n",
383                    gnutls_strerror(rc)));
384     return 1;
385   }
386
387   rc = gnutls_certificate_set_x509_system_trust(qs->cred);
388   if(rc < 0) {
389     H3BUGF(fprintf(stderr,
390                    "gnutls_certificate_set_x509_system_trust failed: %s\n",
391                    gnutls_strerror(rc)));
392     return 1;
393   }
394
395   rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
396   if(rc < 0) {
397     H3BUGF(fprintf(stderr, "gnutls_credentials_set failed: %s\n",
398                    gnutls_strerror(rc)));
399     return 1;
400   }
401
402   /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
403   alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1;
404   alpn[0].size = sizeof(H3_ALPN_H3_29) - 2;
405   alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1;
406   alpn[1].size = sizeof(H3_ALPN_H3) - 2;
407
408   gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY);
409
410   /* set SNI */
411   gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
412   return 0;
413 }
414 #elif defined(USE_WOLFSSL)
415
416 static WOLFSSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
417 {
418   struct connectdata *conn = data->conn;
419   WOLFSSL_CTX *ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
420
421   if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) {
422     failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
423     return NULL;
424   }
425
426   wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
427
428   if(wolfSSL_CTX_set_cipher_list(ssl_ctx, QUIC_CIPHERS) != 1) {
429     char error_buffer[256];
430     ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
431     failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer);
432     return NULL;
433   }
434
435   if(wolfSSL_CTX_set1_groups_list(ssl_ctx, (char *)QUIC_GROUPS) != 1) {
436     failf(data, "SSL_CTX_set1_groups_list failed");
437     return NULL;
438   }
439
440   /* Open the file if a TLS or QUIC backend has not done this before. */
441   Curl_tls_keylog_open();
442   if(Curl_tls_keylog_enabled()) {
443 #if defined(HAVE_SECRET_CALLBACK)
444     wolfSSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
445 #else
446     failf(data, "wolfSSL was built without keylog callback");
447     return NULL;
448 #endif
449   }
450
451   if(conn->ssl_config.verifypeer) {
452     const char * const ssl_cafile = conn->ssl_config.CAfile;
453     const char * const ssl_capath = conn->ssl_config.CApath;
454
455     if(ssl_cafile || ssl_capath) {
456       wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
457       /* tell wolfSSL where to find CA certificates that are used to verify
458          the server's certificate. */
459       if(!wolfSSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) {
460         /* Fail if we insist on successfully verifying the server. */
461         failf(data, "error setting certificate verify locations:"
462               "  CAfile: %s CApath: %s",
463               ssl_cafile ? ssl_cafile : "none",
464               ssl_capath ? ssl_capath : "none");
465         return NULL;
466       }
467       infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
468       infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
469     }
470 #ifdef CURL_CA_FALLBACK
471     else {
472       /* verifying the peer without any CA certificates won't work so
473          use wolfssl's built-in default as fallback */
474       wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
475     }
476 #endif
477   }
478   else {
479     wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
480   }
481
482   return ssl_ctx;
483 }
484
485 /** SSL callbacks ***/
486
487 static int quic_init_ssl(struct quicsocket *qs)
488 {
489   const uint8_t *alpn = NULL;
490   size_t alpnlen = 0;
491   /* this will need some attention when HTTPS proxy over QUIC get fixed */
492   const char * const hostname = qs->conn->host.name;
493
494   DEBUGASSERT(!qs->ssl);
495   qs->ssl = SSL_new(qs->sslctx);
496
497   wolfSSL_set_app_data(qs->ssl, &qs->conn_ref);
498   wolfSSL_set_connect_state(qs->ssl);
499   wolfSSL_set_quic_use_legacy_codepoint(qs->ssl, 0);
500
501   alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
502   alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
503   if(alpn)
504     wolfSSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
505
506   /* set SNI */
507   wolfSSL_UseSNI(qs->ssl, WOLFSSL_SNI_HOST_NAME,
508                  hostname, (unsigned short)strlen(hostname));
509
510   return 0;
511 }
512 #endif /* defined(USE_WOLFSSL) */
513
514 static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
515 {
516   (void)user_data;
517   (void)tconn;
518   return 0;
519 }
520
521 static void extend_stream_window(ngtcp2_conn *tconn,
522                                  struct HTTP *stream)
523 {
524   size_t thismuch = stream->unacked_window;
525   ngtcp2_conn_extend_max_stream_offset(tconn, stream->stream3_id, thismuch);
526   ngtcp2_conn_extend_max_offset(tconn, thismuch);
527   stream->unacked_window = 0;
528 }
529
530
531 static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
532                                int64_t stream_id, uint64_t offset,
533                                const uint8_t *buf, size_t buflen,
534                                void *user_data, void *stream_user_data)
535 {
536   struct quicsocket *qs = (struct quicsocket *)user_data;
537   nghttp3_ssize nconsumed;
538   int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
539   (void)offset;
540   (void)stream_user_data;
541
542   nconsumed =
543     nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin);
544   if(nconsumed < 0) {
545     ngtcp2_connection_close_error_set_application_error(
546         &qs->last_error, nghttp3_err_infer_quic_app_error_code((int)nconsumed),
547         NULL, 0);
548     return NGTCP2_ERR_CALLBACK_FAILURE;
549   }
550
551   /* number of bytes inside buflen which consists of framing overhead
552    * including QPACK HEADERS. In other words, it does not consume payload of
553    * DATA frame. */
554   ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
555   ngtcp2_conn_extend_max_offset(tconn, nconsumed);
556
557   return 0;
558 }
559
560 static int
561 cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
562                             uint64_t offset, uint64_t datalen, void *user_data,
563                             void *stream_user_data)
564 {
565   struct quicsocket *qs = (struct quicsocket *)user_data;
566   int rv;
567   (void)stream_id;
568   (void)tconn;
569   (void)offset;
570   (void)datalen;
571   (void)stream_user_data;
572
573   rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
574   if(rv) {
575     return NGTCP2_ERR_CALLBACK_FAILURE;
576   }
577
578   return 0;
579 }
580
581 static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
582                            int64_t stream_id, uint64_t app_error_code,
583                            void *user_data, void *stream_user_data)
584 {
585   struct quicsocket *qs = (struct quicsocket *)user_data;
586   int rv;
587   (void)tconn;
588   (void)stream_user_data;
589   /* stream is closed... */
590
591   if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
592     app_error_code = NGHTTP3_H3_NO_ERROR;
593   }
594
595   rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
596                                  app_error_code);
597   if(rv) {
598     ngtcp2_connection_close_error_set_application_error(
599         &qs->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0);
600     return NGTCP2_ERR_CALLBACK_FAILURE;
601   }
602
603   return 0;
604 }
605
606 static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
607                            uint64_t final_size, uint64_t app_error_code,
608                            void *user_data, void *stream_user_data)
609 {
610   struct quicsocket *qs = (struct quicsocket *)user_data;
611   int rv;
612   (void)tconn;
613   (void)final_size;
614   (void)app_error_code;
615   (void)stream_user_data;
616
617   rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id);
618   if(rv) {
619     return NGTCP2_ERR_CALLBACK_FAILURE;
620   }
621
622   return 0;
623 }
624
625 static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
626                                   uint64_t app_error_code, void *user_data,
627                                   void *stream_user_data)
628 {
629   struct quicsocket *qs = (struct quicsocket *)user_data;
630   int rv;
631   (void)tconn;
632   (void)app_error_code;
633   (void)stream_user_data;
634
635   rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id);
636   if(rv) {
637     return NGTCP2_ERR_CALLBACK_FAILURE;
638   }
639
640   return 0;
641 }
642
643 static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
644                                             uint64_t max_streams,
645                                             void *user_data)
646 {
647   (void)tconn;
648   (void)max_streams;
649   (void)user_data;
650
651   return 0;
652 }
653
654 static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
655                                      uint64_t max_data, void *user_data,
656                                      void *stream_user_data)
657 {
658   struct quicsocket *qs = (struct quicsocket *)user_data;
659   int rv;
660   (void)tconn;
661   (void)max_data;
662   (void)stream_user_data;
663
664   rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
665   if(rv) {
666     return NGTCP2_ERR_CALLBACK_FAILURE;
667   }
668
669   return 0;
670 }
671
672 static void cb_rand(uint8_t *dest, size_t destlen,
673                     const ngtcp2_rand_ctx *rand_ctx)
674 {
675   CURLcode result;
676   (void)rand_ctx;
677
678   result = Curl_rand(NULL, dest, destlen);
679   if(result) {
680     /* cb_rand is only used for non-cryptographic context.  If Curl_rand
681        failed, just fill 0 and call it *random*. */
682     memset(dest, 0, destlen);
683   }
684 }
685
686 static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
687                                     uint8_t *token, size_t cidlen,
688                                     void *user_data)
689 {
690   CURLcode result;
691   (void)tconn;
692   (void)user_data;
693
694   result = Curl_rand(NULL, cid->data, cidlen);
695   if(result)
696     return NGTCP2_ERR_CALLBACK_FAILURE;
697   cid->datalen = cidlen;
698
699   result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
700   if(result)
701     return NGTCP2_ERR_CALLBACK_FAILURE;
702
703   return 0;
704 }
705
706 static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_crypto_level level,
707                           void *user_data)
708 {
709   struct quicsocket *qs = (struct quicsocket *)user_data;
710   (void)tconn;
711
712   if(level != NGTCP2_CRYPTO_LEVEL_APPLICATION) {
713     return 0;
714   }
715
716   if(init_ngh3_conn(qs) != CURLE_OK) {
717     return NGTCP2_ERR_CALLBACK_FAILURE;
718   }
719
720   return 0;
721 }
722
723 static ngtcp2_callbacks ng_callbacks = {
724   ngtcp2_crypto_client_initial_cb,
725   NULL, /* recv_client_initial */
726   ngtcp2_crypto_recv_crypto_data_cb,
727   cb_handshake_completed,
728   NULL, /* recv_version_negotiation */
729   ngtcp2_crypto_encrypt_cb,
730   ngtcp2_crypto_decrypt_cb,
731   ngtcp2_crypto_hp_mask_cb,
732   cb_recv_stream_data,
733   cb_acked_stream_data_offset,
734   NULL, /* stream_open */
735   cb_stream_close,
736   NULL, /* recv_stateless_reset */
737   ngtcp2_crypto_recv_retry_cb,
738   cb_extend_max_local_streams_bidi,
739   NULL, /* extend_max_local_streams_uni */
740   cb_rand,
741   cb_get_new_connection_id,
742   NULL, /* remove_connection_id */
743   ngtcp2_crypto_update_key_cb, /* update_key */
744   NULL, /* path_validation */
745   NULL, /* select_preferred_addr */
746   cb_stream_reset,
747   NULL, /* extend_max_remote_streams_bidi */
748   NULL, /* extend_max_remote_streams_uni */
749   cb_extend_max_stream_data,
750   NULL, /* dcid_status */
751   NULL, /* handshake_confirmed */
752   NULL, /* recv_new_token */
753   ngtcp2_crypto_delete_crypto_aead_ctx_cb,
754   ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
755   NULL, /* recv_datagram */
756   NULL, /* ack_datagram */
757   NULL, /* lost_datagram */
758   ngtcp2_crypto_get_path_challenge_data_cb,
759   cb_stream_stop_sending,
760   NULL, /* version_negotiation */
761   cb_recv_rx_key,
762   NULL, /* recv_tx_key */
763   NULL, /* early_data_rejected */
764 };
765
766 /*
767  * Might be called twice for happy eyeballs.
768  */
769 CURLcode Curl_quic_connect(struct Curl_easy *data,
770                            struct connectdata *conn,
771                            curl_socket_t sockfd,
772                            int sockindex,
773                            const struct sockaddr *addr,
774                            socklen_t addrlen)
775 {
776   int rc;
777   int rv;
778   CURLcode result;
779   ngtcp2_path path; /* TODO: this must be initialized properly */
780   struct quicsocket *qs = &conn->hequic[sockindex];
781   char ipbuf[40];
782   int port;
783   int qfd;
784
785   if(qs->conn)
786     Curl_quic_disconnect(data, conn, sockindex);
787   qs->conn = conn;
788
789   /* extract the used address as a string */
790   if(!Curl_addr2string((struct sockaddr*)addr, addrlen, ipbuf, &port)) {
791     char buffer[STRERROR_LEN];
792     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
793           SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
794     return CURLE_BAD_FUNCTION_ARGUMENT;
795   }
796
797   infof(data, "Connect socket %d over QUIC to %s:%d",
798         sockfd, ipbuf, port);
799
800   qs->version = NGTCP2_PROTO_VER_MAX;
801 #ifdef USE_OPENSSL
802   qs->sslctx = quic_ssl_ctx(data);
803   if(!qs->sslctx)
804     return CURLE_QUIC_CONNECT_ERROR;
805
806   result = quic_set_client_cert(data, qs);
807   if(result)
808     return result;
809 #elif defined(USE_WOLFSSL)
810   qs->sslctx = quic_ssl_ctx(data);
811   if(!qs->sslctx)
812     return CURLE_QUIC_CONNECT_ERROR;
813 #endif
814
815   if(quic_init_ssl(qs))
816     return CURLE_QUIC_CONNECT_ERROR;
817
818   qs->dcid.datalen = NGTCP2_MAX_CIDLEN;
819   result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN);
820   if(result)
821     return result;
822
823   qs->scid.datalen = NGTCP2_MAX_CIDLEN;
824   result = Curl_rand(data, qs->scid.data, NGTCP2_MAX_CIDLEN);
825   if(result)
826     return result;
827
828   (void)Curl_qlogdir(data, qs->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
829   qs->qlogfd = qfd; /* -1 if failure above */
830   quic_settings(qs, data->set.buffer_size);
831
832   qs->local_addrlen = sizeof(qs->local_addr);
833   rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr,
834                    &qs->local_addrlen);
835   if(rv == -1)
836     return CURLE_QUIC_CONNECT_ERROR;
837
838   ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
839                    qs->local_addrlen);
840   ngtcp2_addr_init(&path.remote, addr, addrlen);
841
842   rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path,
843                               NGTCP2_PROTO_VER_V1, &ng_callbacks,
844                               &qs->settings, &qs->transport_params, NULL, qs);
845   if(rc)
846     return CURLE_QUIC_CONNECT_ERROR;
847
848   ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl);
849
850   ngtcp2_connection_close_error_default(&qs->last_error);
851
852 #if defined(__linux__) && defined(UDP_SEGMENT) && defined(HAVE_SENDMSG)
853   qs->no_gso = FALSE;
854 #else
855   qs->no_gso = TRUE;
856 #endif
857
858   qs->num_blocked_pkt = 0;
859   qs->num_blocked_pkt_sent = 0;
860   memset(&qs->blocked_pkt, 0, sizeof(qs->blocked_pkt));
861
862   qs->pktbuflen = NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE * MAX_PKT_BURST;
863   qs->pktbuf = malloc(qs->pktbuflen);
864   if(!qs->pktbuf) {
865     ngtcp2_conn_del(qs->qconn);
866     qs->qconn = NULL;
867     return CURLE_OUT_OF_MEMORY;
868   }
869
870   qs->conn_ref.get_conn = get_conn;
871   qs->conn_ref.user_data = qs;
872
873   return CURLE_OK;
874 }
875
876 /*
877  * Store ngtcp2 version info in this buffer.
878  */
879 void Curl_quic_ver(char *p, size_t len)
880 {
881   const ngtcp2_info *ng2 = ngtcp2_version(0);
882   const nghttp3_info *ht3 = nghttp3_version(0);
883   (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
884                   ng2->version_str, ht3->version_str);
885 }
886
887 static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
888                       curl_socket_t *socks)
889 {
890   struct SingleRequest *k = &data->req;
891   int bitmap = GETSOCK_BLANK;
892   struct HTTP *stream = data->req.p.http;
893   struct quicsocket *qs = conn->quic;
894
895   socks[0] = conn->sock[FIRSTSOCKET];
896
897   /* in a HTTP/2 connection we can basically always get a frame so we should
898      always be ready for one */
899   bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
900
901   /* we're still uploading or the HTTP/2 layer wants to send data */
902   if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND &&
903      (!stream->h3out || stream->h3out->used < H3_SEND_SIZE) &&
904      ngtcp2_conn_get_cwnd_left(qs->qconn) &&
905      ngtcp2_conn_get_max_data_left(qs->qconn) &&
906      nghttp3_conn_is_stream_writable(qs->h3conn, stream->stream3_id))
907     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
908
909   return bitmap;
910 }
911
912 static void qs_disconnect(struct quicsocket *qs)
913 {
914   char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
915   ngtcp2_tstamp ts;
916   ngtcp2_ssize rc;
917
918   if(!qs->conn) /* already closed */
919     return;
920   ts = timestamp();
921   rc = ngtcp2_conn_write_connection_close(qs->qconn, NULL, /* path */
922                                           NULL, /* pkt_info */
923                                           (uint8_t *)buffer, sizeof(buffer),
924                                           &qs->last_error, ts);
925   if(rc > 0) {
926     while((send(qs->conn->sock[FIRSTSOCKET], buffer, rc, 0) == -1) &&
927           SOCKERRNO == EINTR);
928   }
929
930   qs->conn = NULL;
931   if(qs->qlogfd != -1) {
932     close(qs->qlogfd);
933     qs->qlogfd = -1;
934   }
935   if(qs->ssl)
936 #ifdef USE_OPENSSL
937     SSL_free(qs->ssl);
938 #elif defined(USE_GNUTLS)
939     gnutls_deinit(qs->ssl);
940 #elif defined(USE_WOLFSSL)
941     wolfSSL_free(qs->ssl);
942 #endif
943   qs->ssl = NULL;
944 #ifdef USE_GNUTLS
945   if(qs->cred) {
946     gnutls_certificate_free_credentials(qs->cred);
947     qs->cred = NULL;
948   }
949 #endif
950   free(qs->pktbuf);
951   nghttp3_conn_del(qs->h3conn);
952   ngtcp2_conn_del(qs->qconn);
953 #ifdef USE_OPENSSL
954   SSL_CTX_free(qs->sslctx);
955 #elif defined(USE_WOLFSSL)
956   wolfSSL_CTX_free(qs->sslctx);
957 #endif
958 }
959
960 void Curl_quic_disconnect(struct Curl_easy *data,
961                           struct connectdata *conn,
962                           int tempindex)
963 {
964   (void)data;
965   if(conn->transport == TRNSPRT_QUIC)
966     qs_disconnect(&conn->hequic[tempindex]);
967 }
968
969 static CURLcode ng_disconnect(struct Curl_easy *data,
970                               struct connectdata *conn,
971                               bool dead_connection)
972 {
973   (void)dead_connection;
974   Curl_quic_disconnect(data, conn, 0);
975   Curl_quic_disconnect(data, conn, 1);
976   return CURLE_OK;
977 }
978
979 static unsigned int ng_conncheck(struct Curl_easy *data,
980                                  struct connectdata *conn,
981                                  unsigned int checks_to_perform)
982 {
983   (void)data;
984   (void)conn;
985   (void)checks_to_perform;
986   return CONNRESULT_NONE;
987 }
988
989 static const struct Curl_handler Curl_handler_http3 = {
990   "HTTPS",                              /* scheme */
991   ZERO_NULL,                            /* setup_connection */
992   Curl_http,                            /* do_it */
993   Curl_http_done,                       /* done */
994   ZERO_NULL,                            /* do_more */
995   ZERO_NULL,                            /* connect_it */
996   ZERO_NULL,                            /* connecting */
997   ZERO_NULL,                            /* doing */
998   ng_getsock,                           /* proto_getsock */
999   ng_getsock,                           /* doing_getsock */
1000   ZERO_NULL,                            /* domore_getsock */
1001   ng_getsock,                           /* perform_getsock */
1002   ng_disconnect,                        /* disconnect */
1003   ZERO_NULL,                            /* readwrite */
1004   ng_conncheck,                         /* connection_check */
1005   ZERO_NULL,                            /* attach connection */
1006   PORT_HTTP,                            /* defport */
1007   CURLPROTO_HTTPS,                      /* protocol */
1008   CURLPROTO_HTTP,                       /* family */
1009   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
1010 };
1011
1012 static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
1013                               uint64_t app_error_code, void *user_data,
1014                               void *stream_user_data)
1015 {
1016   struct Curl_easy *data = stream_user_data;
1017   struct HTTP *stream = data->req.p.http;
1018   (void)conn;
1019   (void)stream_id;
1020   (void)app_error_code;
1021   (void)user_data;
1022   H3BUGF(infof(data, "cb_h3_stream_close CALLED"));
1023
1024   stream->closed = TRUE;
1025   stream->error3 = app_error_code;
1026   Curl_expire(data, 0, EXPIRE_QUIC);
1027   /* make sure that ngh3_stream_recv is called again to complete the transfer
1028      even if there are no more packets to be received from the server. */
1029   data->state.drain = 1;
1030   return 0;
1031 }
1032
1033 /*
1034  * write_data() copies data to the stream's receive buffer. If not enough
1035  * space is available in the receive buffer, it copies the rest to the
1036  * stream's overflow buffer.
1037  */
1038 static CURLcode write_data(struct HTTP *stream, const void *mem, size_t memlen)
1039 {
1040   CURLcode result = CURLE_OK;
1041   const char *buf = mem;
1042   size_t ncopy = memlen;
1043   /* copy as much as possible to the receive buffer */
1044   if(stream->len) {
1045     size_t len = CURLMIN(ncopy, stream->len);
1046     memcpy(stream->mem, buf, len);
1047     stream->len -= len;
1048     stream->memlen += len;
1049     stream->mem += len;
1050     buf += len;
1051     ncopy -= len;
1052   }
1053   /* copy the rest to the overflow buffer */
1054   if(ncopy)
1055     result = Curl_dyn_addn(&stream->overflow, buf, ncopy);
1056   return result;
1057 }
1058
1059 static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
1060                            const uint8_t *buf, size_t buflen,
1061                            void *user_data, void *stream_user_data)
1062 {
1063   struct Curl_easy *data = stream_user_data;
1064   struct HTTP *stream = data->req.p.http;
1065   CURLcode result = CURLE_OK;
1066   (void)conn;
1067
1068   result = write_data(stream, buf, buflen);
1069   if(result) {
1070     return -1;
1071   }
1072   stream->unacked_window += buflen;
1073   (void)stream_id;
1074   (void)user_data;
1075   return 0;
1076 }
1077
1078 static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
1079                                   size_t consumed, void *user_data,
1080                                   void *stream_user_data)
1081 {
1082   struct quicsocket *qs = user_data;
1083   (void)conn;
1084   (void)stream_user_data;
1085   (void)stream_id;
1086
1087   ngtcp2_conn_extend_max_stream_offset(qs->qconn, stream_id, consumed);
1088   ngtcp2_conn_extend_max_offset(qs->qconn, consumed);
1089   return 0;
1090 }
1091
1092 /* Decode HTTP status code.  Returns -1 if no valid status code was
1093    decoded. (duplicate from http2.c) */
1094 static int decode_status_code(const uint8_t *value, size_t len)
1095 {
1096   int i;
1097   int res;
1098
1099   if(len != 3) {
1100     return -1;
1101   }
1102
1103   res = 0;
1104
1105   for(i = 0; i < 3; ++i) {
1106     char c = value[i];
1107
1108     if(c < '0' || c > '9') {
1109       return -1;
1110     }
1111
1112     res *= 10;
1113     res += c - '0';
1114   }
1115
1116   return res;
1117 }
1118
1119 static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
1120                              int fin, void *user_data, void *stream_user_data)
1121 {
1122   struct Curl_easy *data = stream_user_data;
1123   struct HTTP *stream = data->req.p.http;
1124   CURLcode result = CURLE_OK;
1125   (void)conn;
1126   (void)stream_id;
1127   (void)user_data;
1128   (void)fin;
1129
1130   /* add a CRLF only if we've received some headers */
1131   if(stream->firstheader) {
1132     result = write_data(stream, "\r\n", 2);
1133     if(result) {
1134       return -1;
1135     }
1136   }
1137
1138   if(stream->status_code / 100 != 1) {
1139     stream->bodystarted = TRUE;
1140   }
1141   return 0;
1142 }
1143
1144 static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
1145                              int32_t token, nghttp3_rcbuf *name,
1146                              nghttp3_rcbuf *value, uint8_t flags,
1147                              void *user_data, void *stream_user_data)
1148 {
1149   nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
1150   nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
1151   struct Curl_easy *data = stream_user_data;
1152   struct HTTP *stream = data->req.p.http;
1153   CURLcode result = CURLE_OK;
1154   (void)conn;
1155   (void)stream_id;
1156   (void)token;
1157   (void)flags;
1158   (void)user_data;
1159
1160   if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
1161     char line[14]; /* status line is always 13 characters long */
1162     size_t ncopy;
1163     stream->status_code = decode_status_code(h3val.base, h3val.len);
1164     DEBUGASSERT(stream->status_code != -1);
1165     ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
1166                       stream->status_code);
1167     result = write_data(stream, line, ncopy);
1168     if(result) {
1169       return -1;
1170     }
1171   }
1172   else {
1173     /* store as a HTTP1-style header */
1174     result = write_data(stream, h3name.base, h3name.len);
1175     if(result) {
1176       return -1;
1177     }
1178     result = write_data(stream, ": ", 2);
1179     if(result) {
1180       return -1;
1181     }
1182     result = write_data(stream, h3val.base, h3val.len);
1183     if(result) {
1184       return -1;
1185     }
1186     result = write_data(stream, "\r\n", 2);
1187     if(result) {
1188       return -1;
1189     }
1190   }
1191
1192   stream->firstheader = TRUE;
1193   return 0;
1194 }
1195
1196 static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
1197                               uint64_t app_error_code, void *user_data,
1198                               void *stream_user_data)
1199 {
1200   struct quicsocket *qs = user_data;
1201   int rv;
1202   (void)conn;
1203   (void)stream_user_data;
1204
1205   rv = ngtcp2_conn_shutdown_stream_read(qs->qconn, stream_id, app_error_code);
1206   if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
1207     return NGTCP2_ERR_CALLBACK_FAILURE;
1208   }
1209
1210   return 0;
1211 }
1212
1213 static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
1214                               uint64_t app_error_code, void *user_data,
1215                               void *stream_user_data) {
1216   struct quicsocket *qs = user_data;
1217   int rv;
1218   (void)conn;
1219   (void)stream_user_data;
1220
1221   rv = ngtcp2_conn_shutdown_stream_write(qs->qconn, stream_id, app_error_code);
1222   if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
1223     return NGTCP2_ERR_CALLBACK_FAILURE;
1224   }
1225
1226   return 0;
1227 }
1228
1229 static nghttp3_callbacks ngh3_callbacks = {
1230   cb_h3_acked_stream_data, /* acked_stream_data */
1231   cb_h3_stream_close,
1232   cb_h3_recv_data,
1233   cb_h3_deferred_consume,
1234   NULL, /* begin_headers */
1235   cb_h3_recv_header,
1236   cb_h3_end_headers,
1237   NULL, /* begin_trailers */
1238   cb_h3_recv_header,
1239   NULL, /* end_trailers */
1240   cb_h3_stop_sending,
1241   NULL, /* end_stream */
1242   cb_h3_reset_stream,
1243   NULL /* shutdown */
1244 };
1245
1246 static int init_ngh3_conn(struct quicsocket *qs)
1247 {
1248   CURLcode result;
1249   int rc;
1250   int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
1251
1252   if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) {
1253     return CURLE_QUIC_CONNECT_ERROR;
1254   }
1255
1256   nghttp3_settings_default(&qs->h3settings);
1257
1258   rc = nghttp3_conn_client_new(&qs->h3conn,
1259                                &ngh3_callbacks,
1260                                &qs->h3settings,
1261                                nghttp3_mem_default(),
1262                                qs);
1263   if(rc) {
1264     result = CURLE_OUT_OF_MEMORY;
1265     goto fail;
1266   }
1267
1268   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &ctrl_stream_id, NULL);
1269   if(rc) {
1270     result = CURLE_QUIC_CONNECT_ERROR;
1271     goto fail;
1272   }
1273
1274   rc = nghttp3_conn_bind_control_stream(qs->h3conn, ctrl_stream_id);
1275   if(rc) {
1276     result = CURLE_QUIC_CONNECT_ERROR;
1277     goto fail;
1278   }
1279
1280   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_enc_stream_id, NULL);
1281   if(rc) {
1282     result = CURLE_QUIC_CONNECT_ERROR;
1283     goto fail;
1284   }
1285
1286   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_dec_stream_id, NULL);
1287   if(rc) {
1288     result = CURLE_QUIC_CONNECT_ERROR;
1289     goto fail;
1290   }
1291
1292   rc = nghttp3_conn_bind_qpack_streams(qs->h3conn, qpack_enc_stream_id,
1293                                        qpack_dec_stream_id);
1294   if(rc) {
1295     result = CURLE_QUIC_CONNECT_ERROR;
1296     goto fail;
1297   }
1298
1299   return CURLE_OK;
1300   fail:
1301
1302   return result;
1303 }
1304
1305 static Curl_recv ngh3_stream_recv;
1306 static Curl_send ngh3_stream_send;
1307
1308 static size_t drain_overflow_buffer(struct HTTP *stream)
1309 {
1310   size_t overlen = Curl_dyn_len(&stream->overflow);
1311   size_t ncopy = CURLMIN(overlen, stream->len);
1312   if(ncopy > 0) {
1313     memcpy(stream->mem, Curl_dyn_ptr(&stream->overflow), ncopy);
1314     stream->len -= ncopy;
1315     stream->mem += ncopy;
1316     stream->memlen += ncopy;
1317     if(ncopy != overlen)
1318       /* make the buffer only keep the tail */
1319       (void)Curl_dyn_tail(&stream->overflow, overlen - ncopy);
1320     else
1321       Curl_dyn_reset(&stream->overflow);
1322   }
1323   return ncopy;
1324 }
1325
1326 /* incoming data frames on the h3 stream */
1327 static ssize_t ngh3_stream_recv(struct Curl_easy *data,
1328                                 int sockindex,
1329                                 char *buf,
1330                                 size_t buffersize,
1331                                 CURLcode *curlcode)
1332 {
1333   struct connectdata *conn = data->conn;
1334   curl_socket_t sockfd = conn->sock[sockindex];
1335   struct HTTP *stream = data->req.p.http;
1336   struct quicsocket *qs = conn->quic;
1337
1338   if(!stream->memlen) {
1339     /* remember where to store incoming data for this stream and how big the
1340        buffer is */
1341     stream->mem = buf;
1342     stream->len = buffersize;
1343   }
1344   /* else, there's data in the buffer already */
1345
1346   /* if there's data in the overflow buffer from a previous call, copy as much
1347      as possible to the receive buffer before receiving more */
1348   drain_overflow_buffer(stream);
1349
1350   if(ng_process_ingress(data, sockfd, qs)) {
1351     *curlcode = CURLE_RECV_ERROR;
1352     return -1;
1353   }
1354   if(ng_flush_egress(data, sockfd, qs)) {
1355     *curlcode = CURLE_SEND_ERROR;
1356     return -1;
1357   }
1358
1359   if(stream->memlen) {
1360     ssize_t memlen = stream->memlen;
1361     /* data arrived */
1362     *curlcode = CURLE_OK;
1363     /* reset to allow more data to come */
1364     stream->memlen = 0;
1365     stream->mem = buf;
1366     stream->len = buffersize;
1367     /* extend the stream window with the data we're consuming and send out
1368        any additional packets to tell the server that we can receive more */
1369     extend_stream_window(qs->qconn, stream);
1370     if(ng_flush_egress(data, sockfd, qs)) {
1371       *curlcode = CURLE_SEND_ERROR;
1372       return -1;
1373     }
1374     return memlen;
1375   }
1376
1377   if(stream->closed) {
1378     if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
1379       failf(data,
1380             "HTTP/3 stream %" PRId64 " was not closed cleanly: (err %" PRIu64
1381             ")",
1382             stream->stream3_id, stream->error3);
1383       *curlcode = CURLE_HTTP3;
1384       return -1;
1385     }
1386
1387     if(!stream->bodystarted) {
1388       failf(data,
1389             "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
1390             " all response header fields, treated as error",
1391             stream->stream3_id);
1392       *curlcode = CURLE_HTTP3;
1393       return -1;
1394     }
1395
1396     *curlcode = CURLE_OK;
1397     return 0;
1398   }
1399
1400   infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN");
1401   *curlcode = CURLE_AGAIN;
1402   return -1;
1403 }
1404
1405 /* this amount of data has now been acked on this stream */
1406 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
1407                                    uint64_t datalen, void *user_data,
1408                                    void *stream_user_data)
1409 {
1410   struct Curl_easy *data = stream_user_data;
1411   struct HTTP *stream = data->req.p.http;
1412   (void)user_data;
1413
1414   if(!data->set.postfields) {
1415     stream->h3out->used -= datalen;
1416     H3BUGF(infof(data,
1417                  "cb_h3_acked_stream_data, %zd bytes, %zd left unacked",
1418                  datalen, stream->h3out->used));
1419     DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
1420
1421     if(stream->h3out->used == 0) {
1422       int rv = nghttp3_conn_resume_stream(conn, stream_id);
1423       if(rv) {
1424         return NGTCP2_ERR_CALLBACK_FAILURE;
1425       }
1426     }
1427   }
1428   return 0;
1429 }
1430
1431 static nghttp3_ssize cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
1432                                         nghttp3_vec *vec, size_t veccnt,
1433                                         uint32_t *pflags, void *user_data,
1434                                         void *stream_user_data)
1435 {
1436   struct Curl_easy *data = stream_user_data;
1437   size_t nread;
1438   struct HTTP *stream = data->req.p.http;
1439   (void)conn;
1440   (void)stream_id;
1441   (void)user_data;
1442   (void)veccnt;
1443
1444   if(data->set.postfields) {
1445     vec[0].base = data->set.postfields;
1446     vec[0].len = data->state.infilesize;
1447     *pflags = NGHTTP3_DATA_FLAG_EOF;
1448     return 1;
1449   }
1450
1451   if(stream->upload_len && H3_SEND_SIZE <= stream->h3out->used) {
1452     return NGHTTP3_ERR_WOULDBLOCK;
1453   }
1454
1455   nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used);
1456   if(nread > 0) {
1457     /* nghttp3 wants us to hold on to the data until it tells us it is okay to
1458        delete it. Append the data at the end of the h3out buffer. Since we can
1459        only return consecutive data, copy the amount that fits and the next
1460        part comes in next invoke. */
1461     struct h3out *out = stream->h3out;
1462     if(nread + out->windex > H3_SEND_SIZE)
1463       nread = H3_SEND_SIZE - out->windex;
1464
1465     memcpy(&out->buf[out->windex], stream->upload_mem, nread);
1466
1467     /* that's the chunk we return to nghttp3 */
1468     vec[0].base = &out->buf[out->windex];
1469     vec[0].len = nread;
1470
1471     out->windex += nread;
1472     out->used += nread;
1473
1474     if(out->windex == H3_SEND_SIZE)
1475       out->windex = 0; /* wrap */
1476     stream->upload_mem += nread;
1477     stream->upload_len -= nread;
1478     if(data->state.infilesize != -1) {
1479       stream->upload_left -= nread;
1480       if(!stream->upload_left)
1481         *pflags = NGHTTP3_DATA_FLAG_EOF;
1482     }
1483     H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)",
1484                  nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
1485                  out->used));
1486   }
1487   if(stream->upload_done && !stream->upload_len &&
1488      (stream->upload_left <= 0)) {
1489     H3BUGF(infof(data, "cb_h3_readfunction sets EOF"));
1490     *pflags = NGHTTP3_DATA_FLAG_EOF;
1491     return nread ? 1 : 0;
1492   }
1493   else if(!nread) {
1494     return NGHTTP3_ERR_WOULDBLOCK;
1495   }
1496   return 1;
1497 }
1498
1499 /* Index where :authority header field will appear in request header
1500    field list. */
1501 #define AUTHORITY_DST_IDX 3
1502
1503 static CURLcode http_request(struct Curl_easy *data, const void *mem,
1504                              size_t len)
1505 {
1506   struct connectdata *conn = data->conn;
1507   struct HTTP *stream = data->req.p.http;
1508   size_t nheader;
1509   struct quicsocket *qs = conn->quic;
1510   CURLcode result = CURLE_OK;
1511   nghttp3_nv *nva = NULL;
1512   int64_t stream3_id;
1513   int rc;
1514   struct h3out *h3out = NULL;
1515   struct h2h3req *hreq = NULL;
1516
1517   rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL);
1518   if(rc) {
1519     failf(data, "can get bidi streams");
1520     result = CURLE_SEND_ERROR;
1521     goto fail;
1522   }
1523
1524   stream->stream3_id = stream3_id;
1525   stream->h3req = TRUE; /* senf off! */
1526   Curl_dyn_init(&stream->overflow, CURL_MAX_READ_SIZE);
1527
1528   result = Curl_pseudo_headers(data, mem, len, &hreq);
1529   if(result)
1530     goto fail;
1531   nheader = hreq->entries;
1532
1533   nva = malloc(sizeof(nghttp3_nv) * nheader);
1534   if(!nva) {
1535     result = CURLE_OUT_OF_MEMORY;
1536     goto fail;
1537   }
1538   else {
1539     unsigned int i;
1540     for(i = 0; i < nheader; i++) {
1541       nva[i].name = (unsigned char *)hreq->header[i].name;
1542       nva[i].namelen = hreq->header[i].namelen;
1543       nva[i].value = (unsigned char *)hreq->header[i].value;
1544       nva[i].valuelen = hreq->header[i].valuelen;
1545       nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1546     }
1547   }
1548
1549   switch(data->state.httpreq) {
1550   case HTTPREQ_POST:
1551   case HTTPREQ_POST_FORM:
1552   case HTTPREQ_POST_MIME:
1553   case HTTPREQ_PUT: {
1554     nghttp3_data_reader data_reader;
1555     if(data->state.infilesize != -1)
1556       stream->upload_left = data->state.infilesize;
1557     else
1558       /* data sending without specifying the data amount up front */
1559       stream->upload_left = -1; /* unknown, but not zero */
1560
1561     data_reader.read_data = cb_h3_readfunction;
1562
1563     h3out = calloc(sizeof(struct h3out), 1);
1564     if(!h3out) {
1565       result = CURLE_OUT_OF_MEMORY;
1566       goto fail;
1567     }
1568     stream->h3out = h3out;
1569
1570     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1571                                      nva, nheader, &data_reader, data);
1572     if(rc) {
1573       result = CURLE_SEND_ERROR;
1574       goto fail;
1575     }
1576     break;
1577   }
1578   default:
1579     stream->upload_left = 0; /* nothing left to send */
1580     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1581                                      nva, nheader, NULL, data);
1582     if(rc) {
1583       result = CURLE_SEND_ERROR;
1584       goto fail;
1585     }
1586     break;
1587   }
1588
1589   Curl_safefree(nva);
1590
1591   infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)",
1592         stream3_id, (void *)data);
1593
1594   Curl_pseudo_free(hreq);
1595   return CURLE_OK;
1596
1597 fail:
1598   free(nva);
1599   Curl_pseudo_free(hreq);
1600   return result;
1601 }
1602 static ssize_t ngh3_stream_send(struct Curl_easy *data,
1603                                 int sockindex,
1604                                 const void *mem,
1605                                 size_t len,
1606                                 CURLcode *curlcode)
1607 {
1608   ssize_t sent = 0;
1609   struct connectdata *conn = data->conn;
1610   struct quicsocket *qs = conn->quic;
1611   curl_socket_t sockfd = conn->sock[sockindex];
1612   struct HTTP *stream = data->req.p.http;
1613
1614   if(stream->closed) {
1615     *curlcode = CURLE_HTTP3;
1616     return -1;
1617   }
1618
1619   if(!stream->h3req) {
1620     CURLcode result = http_request(data, mem, len);
1621     if(result) {
1622       *curlcode = CURLE_SEND_ERROR;
1623       return -1;
1624     }
1625     /* Assume that mem of length len only includes HTTP/1.1 style
1626        header fields.  In other words, it does not contain request
1627        body. */
1628     sent = len;
1629   }
1630   else {
1631     H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes",
1632                  len));
1633     if(!stream->upload_len) {
1634       stream->upload_mem = mem;
1635       stream->upload_len = len;
1636       (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
1637     }
1638     else {
1639       *curlcode = CURLE_AGAIN;
1640       return -1;
1641     }
1642   }
1643
1644   if(ng_flush_egress(data, sockfd, qs)) {
1645     *curlcode = CURLE_SEND_ERROR;
1646     return -1;
1647   }
1648
1649   /* Reset post upload buffer after resumed. */
1650   if(stream->upload_mem) {
1651     if(data->set.postfields) {
1652       sent = len;
1653     }
1654     else {
1655       sent = len - stream->upload_len;
1656     }
1657
1658     stream->upload_mem = NULL;
1659     stream->upload_len = 0;
1660
1661     if(sent == 0) {
1662       *curlcode = CURLE_AGAIN;
1663       return -1;
1664     }
1665   }
1666
1667   *curlcode = CURLE_OK;
1668   return sent;
1669 }
1670
1671 static CURLcode ng_has_connected(struct Curl_easy *data,
1672                                  struct connectdata *conn, int tempindex)
1673 {
1674   CURLcode result = CURLE_OK;
1675   conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
1676   conn->send[FIRSTSOCKET] = ngh3_stream_send;
1677   conn->handler = &Curl_handler_http3;
1678   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1679   conn->httpversion = 30;
1680   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
1681   conn->quic = &conn->hequic[tempindex];
1682
1683   if(conn->ssl_config.verifyhost) {
1684 #ifdef USE_OPENSSL
1685     X509 *server_cert;
1686     server_cert = SSL_get_peer_certificate(conn->quic->ssl);
1687     if(!server_cert) {
1688       return CURLE_PEER_FAILED_VERIFICATION;
1689     }
1690     result = Curl_ossl_verifyhost(data, conn, server_cert);
1691     X509_free(server_cert);
1692     if(result)
1693       return result;
1694     infof(data, "Verified certificate just fine");
1695 #elif defined(USE_GNUTLS)
1696     result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET);
1697 #elif defined(USE_WOLFSSL)
1698     char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
1699     if(!snihost ||
1700        (wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE))
1701       return CURLE_PEER_FAILED_VERIFICATION;
1702     infof(data, "Verified certificate just fine");
1703 #endif
1704   }
1705   else
1706     infof(data, "Skipped certificate verification");
1707 #ifdef USE_OPENSSL
1708   if(data->set.ssl.certinfo)
1709     /* asked to gather certificate info */
1710     (void)Curl_ossl_certchain(data, conn->quic->ssl);
1711 #endif
1712   return result;
1713 }
1714
1715 /*
1716  * There can be multiple connection attempts going on in parallel.
1717  */
1718 CURLcode Curl_quic_is_connected(struct Curl_easy *data,
1719                                 struct connectdata *conn,
1720                                 int sockindex,
1721                                 bool *done)
1722 {
1723   CURLcode result;
1724   struct quicsocket *qs = &conn->hequic[sockindex];
1725   curl_socket_t sockfd = conn->tempsock[sockindex];
1726
1727   result = ng_process_ingress(data, sockfd, qs);
1728   if(result)
1729     goto error;
1730
1731   result = ng_flush_egress(data, sockfd, qs);
1732   if(result)
1733     goto error;
1734
1735   if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
1736     result = ng_has_connected(data, conn, sockindex);
1737     if(!result)
1738       *done = TRUE;
1739   }
1740
1741   return result;
1742   error:
1743   (void)qs_disconnect(qs);
1744   return result;
1745
1746 }
1747
1748 static CURLcode ng_process_ingress(struct Curl_easy *data,
1749                                    curl_socket_t sockfd,
1750                                    struct quicsocket *qs)
1751 {
1752   ssize_t recvd;
1753   int rv;
1754   uint8_t buf[65536];
1755   size_t bufsize = sizeof(buf);
1756   struct sockaddr_storage remote_addr;
1757   socklen_t remote_addrlen;
1758   ngtcp2_path path;
1759   ngtcp2_tstamp ts = timestamp();
1760   ngtcp2_pkt_info pi = { 0 };
1761
1762   for(;;) {
1763     remote_addrlen = sizeof(remote_addr);
1764     while((recvd = recvfrom(sockfd, (char *)buf, bufsize, 0,
1765                             (struct sockaddr *)&remote_addr,
1766                             &remote_addrlen)) == -1 &&
1767           SOCKERRNO == EINTR)
1768       ;
1769     if(recvd == -1) {
1770       if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)
1771         break;
1772
1773       failf(data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd);
1774       return CURLE_RECV_ERROR;
1775     }
1776
1777     ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
1778                      qs->local_addrlen);
1779     ngtcp2_addr_init(&path.remote, (struct sockaddr *)&remote_addr,
1780                      remote_addrlen);
1781
1782     rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
1783     if(rv) {
1784       if(!qs->last_error.error_code) {
1785         if(rv == NGTCP2_ERR_CRYPTO) {
1786           ngtcp2_connection_close_error_set_transport_error_tls_alert(
1787               &qs->last_error, ngtcp2_conn_get_tls_alert(qs->qconn), NULL, 0);
1788         }
1789         else {
1790           ngtcp2_connection_close_error_set_transport_error_liberr(
1791               &qs->last_error, rv, NULL, 0);
1792         }
1793       }
1794
1795       if(rv == NGTCP2_ERR_CRYPTO)
1796         /* this is a "TLS problem", but a failed certificate verification
1797            is a common reason for this */
1798         return CURLE_PEER_FAILED_VERIFICATION;
1799       return CURLE_RECV_ERROR;
1800     }
1801   }
1802
1803   return CURLE_OK;
1804 }
1805
1806 static CURLcode do_sendmsg(size_t *sent, struct Curl_easy *data, int sockfd,
1807                            struct quicsocket *qs, const uint8_t *pkt,
1808                            size_t pktlen, size_t gsolen);
1809
1810 static CURLcode send_packet_no_gso(size_t *psent, struct Curl_easy *data,
1811                                    int sockfd, struct quicsocket *qs,
1812                                    const uint8_t *pkt, size_t pktlen,
1813                                    size_t gsolen)
1814 {
1815   const uint8_t *p, *end = pkt + pktlen;
1816   size_t sent;
1817
1818   *psent = 0;
1819
1820   for(p = pkt; p < end; p += gsolen) {
1821     size_t len = CURLMIN(gsolen, (size_t)(end - p));
1822     CURLcode curlcode = do_sendmsg(&sent, data, sockfd, qs, p, len, len);
1823     if(curlcode != CURLE_OK) {
1824       return curlcode;
1825     }
1826     *psent += sent;
1827   }
1828
1829   return CURLE_OK;
1830 }
1831
1832 static CURLcode do_sendmsg(size_t *psent, struct Curl_easy *data, int sockfd,
1833                            struct quicsocket *qs, const uint8_t *pkt,
1834                            size_t pktlen, size_t gsolen)
1835 {
1836 #ifdef HAVE_SENDMSG
1837   struct iovec msg_iov;
1838   struct msghdr msg = {0};
1839   ssize_t sent;
1840 #if defined(__linux__) && defined(UDP_SEGMENT)
1841   uint8_t msg_ctrl[32];
1842   struct cmsghdr *cm;
1843 #endif
1844
1845   *psent = 0;
1846   msg_iov.iov_base = (uint8_t *)pkt;
1847   msg_iov.iov_len = pktlen;
1848   msg.msg_iov = &msg_iov;
1849   msg.msg_iovlen = 1;
1850
1851 #if defined(__linux__) && defined(UDP_SEGMENT)
1852   if(pktlen > gsolen) {
1853     /* Only set this, when we need it. macOS, for example,
1854      * does not seem to like a msg_control of length 0. */
1855     msg.msg_control = msg_ctrl;
1856     assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(uint16_t)));
1857     msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
1858     cm = CMSG_FIRSTHDR(&msg);
1859     cm->cmsg_level = SOL_UDP;
1860     cm->cmsg_type = UDP_SEGMENT;
1861     cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
1862     *(uint16_t *)(void *)CMSG_DATA(cm) = gsolen & 0xffff;
1863   }
1864 #endif
1865
1866
1867   while((sent = sendmsg(sockfd, &msg, 0)) == -1 && SOCKERRNO == EINTR)
1868     ;
1869
1870   if(sent == -1) {
1871     switch(SOCKERRNO) {
1872     case EAGAIN:
1873 #if EAGAIN != EWOULDBLOCK
1874     case EWOULDBLOCK:
1875 #endif
1876       return CURLE_AGAIN;
1877     case EMSGSIZE:
1878       /* UDP datagram is too large; caused by PMTUD. Just let it be lost. */
1879       break;
1880     case EIO:
1881       if(pktlen > gsolen) {
1882         /* GSO failure */
1883         failf(data, "sendmsg() returned %zd (errno %d); disable GSO", sent,
1884               SOCKERRNO);
1885         qs->no_gso = TRUE;
1886         return send_packet_no_gso(psent, data, sockfd, qs, pkt, pktlen,
1887                                   gsolen);
1888       }
1889       /* FALLTHROUGH */
1890     default:
1891       failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO);
1892       return CURLE_SEND_ERROR;
1893     }
1894   }
1895   else {
1896     assert(pktlen == (size_t)sent);
1897   }
1898 #else
1899   ssize_t sent;
1900   (void)qs;
1901   (void)gsolen;
1902
1903   *psent = 0;
1904
1905   while((sent = send(sockfd, (const char *)pkt, pktlen, 0)) == -1 &&
1906         SOCKERRNO == EINTR)
1907     ;
1908
1909   if(sent == -1) {
1910     if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
1911       return CURLE_AGAIN;
1912     }
1913     else {
1914       failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO);
1915       if(SOCKERRNO != EMSGSIZE) {
1916         return CURLE_SEND_ERROR;
1917       }
1918       /* UDP datagram is too large; caused by PMTUD. Just let it be
1919          lost. */
1920     }
1921   }
1922 #endif
1923
1924   *psent = pktlen;
1925
1926   return CURLE_OK;
1927 }
1928
1929 static CURLcode send_packet(size_t *psent, struct Curl_easy *data, int sockfd,
1930                             struct quicsocket *qs, const uint8_t *pkt,
1931                             size_t pktlen, size_t gsolen)
1932 {
1933   if(qs->no_gso && pktlen > gsolen) {
1934     return send_packet_no_gso(psent, data, sockfd, qs, pkt, pktlen, gsolen);
1935   }
1936
1937   return do_sendmsg(psent, data, sockfd, qs, pkt, pktlen, gsolen);
1938 }
1939
1940 static void push_blocked_pkt(struct quicsocket *qs, const uint8_t *pkt,
1941                              size_t pktlen, size_t gsolen)
1942 {
1943   struct blocked_pkt *blkpkt;
1944
1945   assert(qs->num_blocked_pkt <
1946          sizeof(qs->blocked_pkt) / sizeof(qs->blocked_pkt[0]));
1947
1948   blkpkt = &qs->blocked_pkt[qs->num_blocked_pkt++];
1949
1950   blkpkt->pkt = pkt;
1951   blkpkt->pktlen = pktlen;
1952   blkpkt->gsolen = gsolen;
1953 }
1954
1955 static CURLcode send_blocked_pkt(struct Curl_easy *data, int sockfd,
1956                                  struct quicsocket *qs)
1957 {
1958   size_t sent;
1959   CURLcode curlcode;
1960   struct blocked_pkt *blkpkt;
1961
1962   for(; qs->num_blocked_pkt_sent < qs->num_blocked_pkt;
1963       ++qs->num_blocked_pkt_sent) {
1964     blkpkt = &qs->blocked_pkt[qs->num_blocked_pkt_sent];
1965     curlcode = send_packet(&sent, data, sockfd, qs, blkpkt->pkt,
1966                            blkpkt->pktlen, blkpkt->gsolen);
1967
1968     if(curlcode) {
1969       if(curlcode == CURLE_AGAIN) {
1970         blkpkt->pkt += sent;
1971         blkpkt->pktlen -= sent;
1972       }
1973       return curlcode;
1974     }
1975   }
1976
1977   qs->num_blocked_pkt = 0;
1978   qs->num_blocked_pkt_sent = 0;
1979
1980   return CURLE_OK;
1981 }
1982
1983 static CURLcode ng_flush_egress(struct Curl_easy *data,
1984                                 int sockfd,
1985                                 struct quicsocket *qs)
1986 {
1987   int rv;
1988   size_t sent;
1989   ngtcp2_ssize outlen;
1990   uint8_t *outpos = qs->pktbuf;
1991   size_t max_udp_payload_size =
1992       ngtcp2_conn_get_max_tx_udp_payload_size(qs->qconn);
1993   size_t path_max_udp_payload_size =
1994       ngtcp2_conn_get_path_max_tx_udp_payload_size(qs->qconn);
1995   size_t max_pktcnt =
1996       CURLMIN(MAX_PKT_BURST, qs->pktbuflen / max_udp_payload_size);
1997   size_t pktcnt = 0;
1998   size_t gsolen;
1999   ngtcp2_path_storage ps;
2000   ngtcp2_tstamp ts = timestamp();
2001   ngtcp2_tstamp expiry;
2002   ngtcp2_duration timeout;
2003   int64_t stream_id;
2004   nghttp3_ssize veccnt;
2005   int fin;
2006   nghttp3_vec vec[16];
2007   ngtcp2_ssize ndatalen;
2008   uint32_t flags;
2009   CURLcode curlcode;
2010
2011   rv = ngtcp2_conn_handle_expiry(qs->qconn, ts);
2012   if(rv) {
2013     failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
2014           ngtcp2_strerror(rv));
2015     ngtcp2_connection_close_error_set_transport_error_liberr(&qs->last_error,
2016                                                              rv, NULL, 0);
2017     return CURLE_SEND_ERROR;
2018   }
2019
2020   if(qs->num_blocked_pkt) {
2021     curlcode = send_blocked_pkt(data, sockfd, qs);
2022     if(curlcode) {
2023       if(curlcode == CURLE_AGAIN) {
2024         Curl_expire(data, 1, EXPIRE_QUIC);
2025         return CURLE_OK;
2026       }
2027       return curlcode;
2028     }
2029   }
2030
2031   ngtcp2_path_storage_zero(&ps);
2032
2033   for(;;) {
2034     veccnt = 0;
2035     stream_id = -1;
2036     fin = 0;
2037
2038     if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) {
2039       veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec,
2040                                           sizeof(vec) / sizeof(vec[0]));
2041       if(veccnt < 0) {
2042         failf(data, "nghttp3_conn_writev_stream returned error: %s",
2043               nghttp3_strerror((int)veccnt));
2044         ngtcp2_connection_close_error_set_application_error(
2045             &qs->last_error,
2046             nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0);
2047         return CURLE_SEND_ERROR;
2048       }
2049     }
2050
2051     flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
2052             (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
2053     outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, outpos,
2054                                        max_udp_payload_size,
2055                                        &ndatalen, flags, stream_id,
2056                                        (const ngtcp2_vec *)vec, veccnt, ts);
2057     if(outlen == 0) {
2058       if(outpos != qs->pktbuf) {
2059         curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf,
2060                                outpos - qs->pktbuf, gsolen);
2061         if(curlcode) {
2062           if(curlcode == CURLE_AGAIN) {
2063             push_blocked_pkt(qs, qs->pktbuf + sent, outpos - qs->pktbuf - sent,
2064                              gsolen);
2065             Curl_expire(data, 1, EXPIRE_QUIC);
2066             return CURLE_OK;
2067           }
2068           return curlcode;
2069         }
2070       }
2071
2072       break;
2073     }
2074     if(outlen < 0) {
2075       switch(outlen) {
2076       case NGTCP2_ERR_STREAM_DATA_BLOCKED:
2077         assert(ndatalen == -1);
2078         nghttp3_conn_block_stream(qs->h3conn, stream_id);
2079         continue;
2080       case NGTCP2_ERR_STREAM_SHUT_WR:
2081         assert(ndatalen == -1);
2082         nghttp3_conn_shutdown_stream_write(qs->h3conn, stream_id);
2083         continue;
2084       case NGTCP2_ERR_WRITE_MORE:
2085         assert(ndatalen >= 0);
2086         rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
2087         if(rv) {
2088           failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
2089                 nghttp3_strerror(rv));
2090           return CURLE_SEND_ERROR;
2091         }
2092         continue;
2093       default:
2094         assert(ndatalen == -1);
2095         failf(data, "ngtcp2_conn_writev_stream returned error: %s",
2096               ngtcp2_strerror((int)outlen));
2097         ngtcp2_connection_close_error_set_transport_error_liberr(
2098             &qs->last_error, (int)outlen, NULL, 0);
2099         return CURLE_SEND_ERROR;
2100       }
2101     }
2102     else if(ndatalen >= 0) {
2103       rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
2104       if(rv) {
2105         failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
2106               nghttp3_strerror(rv));
2107         return CURLE_SEND_ERROR;
2108       }
2109     }
2110
2111     outpos += outlen;
2112
2113     if(pktcnt == 0) {
2114       gsolen = outlen;
2115     }
2116     else if((size_t)outlen > gsolen ||
2117             (gsolen > path_max_udp_payload_size &&
2118              (size_t)outlen != gsolen)) {
2119       /* Packet larger than path_max_udp_payload_size is PMTUD probe
2120          packet and it might not be sent because of EMSGSIZE. Send
2121          them separately to minimize the loss. */
2122       curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf,
2123                              outpos - outlen - qs->pktbuf, gsolen);
2124       if(curlcode) {
2125         if(curlcode == CURLE_AGAIN) {
2126           push_blocked_pkt(qs, qs->pktbuf + sent,
2127                            outpos - outlen - qs->pktbuf - sent, gsolen);
2128           push_blocked_pkt(qs, outpos - outlen, outlen, outlen);
2129           Curl_expire(data, 1, EXPIRE_QUIC);
2130           return CURLE_OK;
2131         }
2132         return curlcode;
2133       }
2134       curlcode = send_packet(&sent, data, sockfd, qs, outpos - outlen, outlen,
2135                              outlen);
2136       if(curlcode) {
2137         if(curlcode == CURLE_AGAIN) {
2138           assert(0 == sent);
2139           push_blocked_pkt(qs, outpos - outlen, outlen, outlen);
2140           Curl_expire(data, 1, EXPIRE_QUIC);
2141           return CURLE_OK;
2142         }
2143         return curlcode;
2144       }
2145
2146       pktcnt = 0;
2147       outpos = qs->pktbuf;
2148       continue;
2149     }
2150
2151     if(++pktcnt >= max_pktcnt || (size_t)outlen < gsolen) {
2152       curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf,
2153                              outpos - qs->pktbuf, gsolen);
2154       if(curlcode) {
2155         if(curlcode == CURLE_AGAIN) {
2156           push_blocked_pkt(qs, qs->pktbuf + sent, outpos - qs->pktbuf - sent,
2157                            gsolen);
2158           Curl_expire(data, 1, EXPIRE_QUIC);
2159           return CURLE_OK;
2160         }
2161         return curlcode;
2162       }
2163
2164       pktcnt = 0;
2165       outpos = qs->pktbuf;
2166     }
2167   }
2168
2169   expiry = ngtcp2_conn_get_expiry(qs->qconn);
2170   if(expiry != UINT64_MAX) {
2171     if(expiry <= ts) {
2172       timeout = 0;
2173     }
2174     else {
2175       timeout = expiry - ts;
2176       if(timeout % NGTCP2_MILLISECONDS) {
2177         timeout += NGTCP2_MILLISECONDS;
2178       }
2179     }
2180     Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
2181   }
2182
2183   return CURLE_OK;
2184 }
2185
2186 /*
2187  * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
2188  */
2189 CURLcode Curl_quic_done_sending(struct Curl_easy *data)
2190 {
2191   struct connectdata *conn = data->conn;
2192   DEBUGASSERT(conn);
2193   if(conn->handler == &Curl_handler_http3) {
2194     /* only for HTTP/3 transfers */
2195     struct HTTP *stream = data->req.p.http;
2196     struct quicsocket *qs = conn->quic;
2197     stream->upload_done = TRUE;
2198     (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
2199   }
2200
2201   return CURLE_OK;
2202 }
2203
2204 /*
2205  * Called from http.c:Curl_http_done when a request completes.
2206  */
2207 void Curl_quic_done(struct Curl_easy *data, bool premature)
2208 {
2209   (void)premature;
2210   if(data->conn->handler == &Curl_handler_http3) {
2211     /* only for HTTP/3 transfers */
2212     struct HTTP *stream = data->req.p.http;
2213     Curl_dyn_free(&stream->overflow);
2214     free(stream->h3out);
2215   }
2216 }
2217
2218 /*
2219  * Called from transfer.c:data_pending to know if we should keep looping
2220  * to receive more data from the connection.
2221  */
2222 bool Curl_quic_data_pending(const struct Curl_easy *data)
2223 {
2224   /* We may have received more data than we're able to hold in the receive
2225      buffer and allocated an overflow buffer. Since it's possible that
2226      there's no more data coming on the socket, we need to keep reading
2227      until the overflow buffer is empty. */
2228   const struct HTTP *stream = data->req.p.http;
2229   return Curl_dyn_len(&stream->overflow) > 0;
2230 }
2231
2232 /*
2233  * Called from transfer.c:Curl_readwrite when neither HTTP level read
2234  * nor write is performed. It is a good place to handle timer expiry
2235  * for QUIC transport.
2236  */
2237 CURLcode Curl_quic_idle(struct Curl_easy *data)
2238 {
2239   struct connectdata *conn = data->conn;
2240   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
2241   struct quicsocket *qs = conn->quic;
2242
2243   if(ngtcp2_conn_get_expiry(qs->qconn) > timestamp()) {
2244     return CURLE_OK;
2245   }
2246
2247   if(ng_flush_egress(data, sockfd, qs)) {
2248     return CURLE_SEND_ERROR;
2249   }
2250
2251   return CURLE_OK;
2252 }
2253
2254 #endif