• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2021, 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  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #ifdef USE_NGTCP2
26 #include <ngtcp2/ngtcp2.h>
27 #include <ngtcp2/ngtcp2_crypto.h>
28 #include <nghttp3/nghttp3.h>
29 #ifdef USE_OPENSSL
30 #include <openssl/err.h>
31 #endif
32 #include "urldata.h"
33 #include "sendf.h"
34 #include "strdup.h"
35 #include "rand.h"
36 #include "ngtcp2.h"
37 #include "multiif.h"
38 #include "strcase.h"
39 #include "connect.h"
40 #include "strerror.h"
41 #include "dynbuf.h"
42 #include "vquic.h"
43 #include "vtls/keylog.h"
44 
45 /* The last 3 #include files should be in this order */
46 #include "curl_printf.h"
47 #include "curl_memory.h"
48 #include "memdebug.h"
49 
50 /* #define DEBUG_NGTCP2 */
51 #ifdef CURLDEBUG
52 #define DEBUG_HTTP3
53 #endif
54 #ifdef DEBUG_HTTP3
55 #define H3BUGF(x) x
56 #else
57 #define H3BUGF(x) do { } while(0)
58 #endif
59 
60 #define H3_ALPN_H3_29 "\x5h3-29"
61 
62 /*
63  * This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked.
64  * It is used as a circular buffer. Add new bytes at the end until it reaches
65  * the far end, then start over at index 0 again.
66  */
67 
68 #define H3_SEND_SIZE (20*1024)
69 struct h3out {
70   uint8_t buf[H3_SEND_SIZE];
71   size_t used;   /* number of bytes used in the buffer */
72   size_t windex; /* index in the buffer where to start writing the next
73                     data block */
74 };
75 
76 #define QUIC_MAX_STREAMS (256*1024)
77 #define QUIC_MAX_DATA (1*1024*1024)
78 #define QUIC_IDLE_TIMEOUT 60000 /* milliseconds */
79 
80 #ifdef USE_OPENSSL
81 #define QUIC_CIPHERS                                                          \
82   "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_"               \
83   "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
84 #define QUIC_GROUPS "P-256:X25519:P-384:P-521"
85 #elif defined(USE_GNUTLS)
86 #define QUIC_PRIORITY \
87   "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
88   "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
89   "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
90   "%DISABLE_TLS13_COMPAT_MODE"
91 #endif
92 
93 static CURLcode ng_process_ingress(struct Curl_easy *data,
94                                    curl_socket_t sockfd,
95                                    struct quicsocket *qs);
96 static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd,
97                                 struct quicsocket *qs);
98 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
99                                    size_t datalen, void *user_data,
100                                    void *stream_user_data);
101 
timestamp(void)102 static ngtcp2_tstamp timestamp(void)
103 {
104   struct curltime ct = Curl_now();
105   return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
106 }
107 
108 #ifdef DEBUG_NGTCP2
quic_printf(void * user_data,const char * fmt,...)109 static void quic_printf(void *user_data, const char *fmt, ...)
110 {
111   va_list ap;
112   (void)user_data; /* TODO, use this to do infof() instead long-term */
113   va_start(ap, fmt);
114   vfprintf(stderr, fmt, ap);
115   va_end(ap);
116   fprintf(stderr, "\n");
117 }
118 #endif
119 
120 #ifdef USE_OPENSSL
121 static ngtcp2_crypto_level
quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)122 quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level)
123 {
124   switch(ossl_level) {
125   case ssl_encryption_initial:
126     return NGTCP2_CRYPTO_LEVEL_INITIAL;
127   case ssl_encryption_early_data:
128     return NGTCP2_CRYPTO_LEVEL_EARLY;
129   case ssl_encryption_handshake:
130     return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
131   case ssl_encryption_application:
132     return NGTCP2_CRYPTO_LEVEL_APPLICATION;
133   default:
134     assert(0);
135   }
136 }
137 #elif defined(USE_GNUTLS)
138 static ngtcp2_crypto_level
quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)139 quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)
140 {
141   switch(gtls_level) {
142   case GNUTLS_ENCRYPTION_LEVEL_INITIAL:
143     return NGTCP2_CRYPTO_LEVEL_INITIAL;
144   case GNUTLS_ENCRYPTION_LEVEL_EARLY:
145     return NGTCP2_CRYPTO_LEVEL_EARLY;
146   case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE:
147     return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
148   case GNUTLS_ENCRYPTION_LEVEL_APPLICATION:
149     return NGTCP2_CRYPTO_LEVEL_APPLICATION;
150   default:
151     assert(0);
152   }
153 }
154 #endif
155 
qlog_callback(void * user_data,uint32_t flags,const void * data,size_t datalen)156 static void qlog_callback(void *user_data, uint32_t flags,
157                           const void *data, size_t datalen)
158 {
159   struct quicsocket *qs = (struct quicsocket *)user_data;
160   (void)flags;
161   if(qs->qlogfd != -1) {
162     ssize_t rc = write(qs->qlogfd, data, datalen);
163     if(rc == -1) {
164       /* on write error, stop further write attempts */
165       close(qs->qlogfd);
166       qs->qlogfd = -1;
167     }
168   }
169 
170 }
171 
quic_settings(struct quicsocket * qs,uint64_t stream_buffer_size)172 static void quic_settings(struct quicsocket *qs,
173                           uint64_t stream_buffer_size)
174 {
175   ngtcp2_settings *s = &qs->settings;
176   ngtcp2_transport_params *t = &qs->transport_params;
177   ngtcp2_settings_default(s);
178   ngtcp2_transport_params_default(t);
179 #ifdef DEBUG_NGTCP2
180   s->log_printf = quic_printf;
181 #else
182   s->log_printf = NULL;
183 #endif
184   s->initial_ts = timestamp();
185   t->initial_max_stream_data_bidi_local = stream_buffer_size;
186   t->initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS;
187   t->initial_max_stream_data_uni = QUIC_MAX_STREAMS;
188   t->initial_max_data = QUIC_MAX_DATA;
189   t->initial_max_streams_bidi = 1;
190   t->initial_max_streams_uni = 3;
191   t->max_idle_timeout = QUIC_IDLE_TIMEOUT;
192   if(qs->qlogfd != -1) {
193     s->qlog.write = qlog_callback;
194   }
195 }
196 
197 #ifdef USE_OPENSSL
keylog_callback(const SSL * ssl,const char * line)198 static void keylog_callback(const SSL *ssl, const char *line)
199 {
200   (void)ssl;
201   Curl_tls_keylog_write_line(line);
202 }
203 #elif defined(USE_GNUTLS)
keylog_callback(gnutls_session_t session,const char * label,const gnutls_datum_t * secret)204 static int keylog_callback(gnutls_session_t session, const char *label,
205                     const gnutls_datum_t *secret)
206 {
207   gnutls_datum_t crandom;
208   gnutls_datum_t srandom;
209 
210   gnutls_session_get_random(session, &crandom, &srandom);
211   if(crandom.size != 32) {
212     return -1;
213   }
214 
215   Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
216   return 0;
217 }
218 #endif
219 
220 static int init_ngh3_conn(struct quicsocket *qs);
221 
write_client_handshake(struct quicsocket * qs,ngtcp2_crypto_level level,const uint8_t * data,size_t len)222 static int write_client_handshake(struct quicsocket *qs,
223                                   ngtcp2_crypto_level level,
224                                   const uint8_t *data, size_t len)
225 {
226   struct quic_handshake *crypto_data;
227   int rv;
228 
229   crypto_data = &qs->crypto_data[level];
230   if(!crypto_data->buf) {
231     crypto_data->buf = malloc(4096);
232     if(!crypto_data->buf)
233       return 0;
234     crypto_data->alloclen = 4096;
235   }
236 
237   /* TODO Just pretend that handshake does not grow more than 4KiB for
238      now */
239   assert(crypto_data->len + len <= crypto_data->alloclen);
240 
241   memcpy(&crypto_data->buf[crypto_data->len], data, len);
242   crypto_data->len += len;
243 
244   rv = ngtcp2_conn_submit_crypto_data(
245     qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len),
246     len);
247   if(rv) {
248     H3BUGF(fprintf(stderr, "write_client_handshake failed\n"));
249   }
250   assert(0 == rv);
251 
252   return 1;
253 }
254 
255 #ifdef USE_OPENSSL
quic_set_encryption_secrets(SSL * ssl,OSSL_ENCRYPTION_LEVEL ossl_level,const uint8_t * rx_secret,const uint8_t * tx_secret,size_t secretlen)256 static int quic_set_encryption_secrets(SSL *ssl,
257                                        OSSL_ENCRYPTION_LEVEL ossl_level,
258                                        const uint8_t *rx_secret,
259                                        const uint8_t *tx_secret,
260                                        size_t secretlen)
261 {
262   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
263   int level = quic_from_ossl_level(ossl_level);
264 
265   if(ngtcp2_crypto_derive_and_install_rx_key(
266        qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
267     return 0;
268 
269   if(ngtcp2_crypto_derive_and_install_tx_key(
270        qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
271     return 0;
272 
273   if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
274     if(init_ngh3_conn(qs) != CURLE_OK)
275       return 0;
276   }
277 
278   return 1;
279 }
280 
quic_add_handshake_data(SSL * ssl,OSSL_ENCRYPTION_LEVEL ossl_level,const uint8_t * data,size_t len)281 static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
282                                    const uint8_t *data, size_t len)
283 {
284   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
285   ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level);
286 
287   return write_client_handshake(qs, level, data, len);
288 }
289 
quic_flush_flight(SSL * ssl)290 static int quic_flush_flight(SSL *ssl)
291 {
292   (void)ssl;
293   return 1;
294 }
295 
quic_send_alert(SSL * ssl,enum ssl_encryption_level_t level,uint8_t alert)296 static int quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level,
297                            uint8_t alert)
298 {
299   struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
300   (void)level;
301 
302   qs->tls_alert = alert;
303   return 1;
304 }
305 
306 static SSL_QUIC_METHOD quic_method = {quic_set_encryption_secrets,
307                                       quic_add_handshake_data,
308                                       quic_flush_flight, quic_send_alert};
309 
quic_ssl_ctx(struct Curl_easy * data)310 static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
311 {
312   SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
313 
314   SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
315   SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
316 
317   SSL_CTX_set_default_verify_paths(ssl_ctx);
318 
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     return NULL;
324   }
325 
326   if(SSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) {
327     failf(data, "SSL_CTX_set1_groups_list failed");
328     return NULL;
329   }
330 
331   SSL_CTX_set_quic_method(ssl_ctx, &quic_method);
332 
333   /* Open the file if a TLS or QUIC backend has not done this before. */
334   Curl_tls_keylog_open();
335   if(Curl_tls_keylog_enabled()) {
336     SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
337   }
338 
339   return ssl_ctx;
340 }
341 
342 /** SSL callbacks ***/
343 
quic_init_ssl(struct quicsocket * qs)344 static int quic_init_ssl(struct quicsocket *qs)
345 {
346   const uint8_t *alpn = NULL;
347   size_t alpnlen = 0;
348   /* this will need some attention when HTTPS proxy over QUIC get fixed */
349   const char * const hostname = qs->conn->host.name;
350 
351   DEBUGASSERT(!qs->ssl);
352   qs->ssl = SSL_new(qs->sslctx);
353 
354   SSL_set_app_data(qs->ssl, qs);
355   SSL_set_connect_state(qs->ssl);
356 
357   alpn = (const uint8_t *)H3_ALPN_H3_29;
358   alpnlen = sizeof(H3_ALPN_H3_29) - 1;
359   if(alpn)
360     SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
361 
362   /* set SNI */
363   SSL_set_tlsext_host_name(qs->ssl, hostname);
364   return 0;
365 }
366 #elif defined(USE_GNUTLS)
secret_func(gnutls_session_t ssl,gnutls_record_encryption_level_t gtls_level,const void * rx_secret,const void * tx_secret,size_t secretlen)367 static int secret_func(gnutls_session_t ssl,
368                        gnutls_record_encryption_level_t gtls_level,
369                        const void *rx_secret,
370                        const void *tx_secret, size_t secretlen)
371 {
372   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
373   int level = quic_from_gtls_level(gtls_level);
374 
375   if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
376      ngtcp2_crypto_derive_and_install_rx_key(
377        qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
378     return 0;
379 
380   if(ngtcp2_crypto_derive_and_install_tx_key(
381        qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
382     return 0;
383 
384   if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
385     if(init_ngh3_conn(qs) != CURLE_OK)
386       return -1;
387   }
388 
389   return 0;
390 }
391 
read_func(gnutls_session_t ssl,gnutls_record_encryption_level_t gtls_level,gnutls_handshake_description_t htype,const void * data,size_t len)392 static int read_func(gnutls_session_t ssl,
393                      gnutls_record_encryption_level_t gtls_level,
394                      gnutls_handshake_description_t htype, const void *data,
395                      size_t len)
396 {
397   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
398   ngtcp2_crypto_level level = quic_from_gtls_level(gtls_level);
399   int rv;
400 
401   if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
402     return 0;
403 
404   rv = write_client_handshake(qs, level, data, len);
405   if(rv == 0)
406     return -1;
407 
408   return 0;
409 }
410 
alert_read_func(gnutls_session_t ssl,gnutls_record_encryption_level_t gtls_level,gnutls_alert_level_t alert_level,gnutls_alert_description_t alert_desc)411 static int alert_read_func(gnutls_session_t ssl,
412                            gnutls_record_encryption_level_t gtls_level,
413                            gnutls_alert_level_t alert_level,
414                            gnutls_alert_description_t alert_desc)
415 {
416   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
417   (void)gtls_level;
418   (void)alert_level;
419 
420   qs->tls_alert = alert_desc;
421   return 1;
422 }
423 
tp_recv_func(gnutls_session_t ssl,const uint8_t * data,size_t data_size)424 static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data,
425                         size_t data_size)
426 {
427   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
428   ngtcp2_transport_params params;
429 
430   if(ngtcp2_decode_transport_params(
431        &params, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS,
432        data, data_size) != 0)
433     return -1;
434 
435   if(ngtcp2_conn_set_remote_transport_params(qs->qconn, &params) != 0)
436     return -1;
437 
438   return 0;
439 }
440 
tp_send_func(gnutls_session_t ssl,gnutls_buffer_t extdata)441 static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata)
442 {
443   struct quicsocket *qs = gnutls_session_get_ptr(ssl);
444   uint8_t paramsbuf[64];
445   ngtcp2_transport_params params;
446   ssize_t nwrite;
447   int rc;
448 
449   ngtcp2_conn_get_local_transport_params(qs->qconn, &params);
450   nwrite = ngtcp2_encode_transport_params(
451     paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
452     &params);
453   if(nwrite < 0) {
454     H3BUGF(fprintf(stderr, "ngtcp2_encode_transport_params: %s\n",
455                    ngtcp2_strerror((int)nwrite)));
456     return -1;
457   }
458 
459   rc = gnutls_buffer_append_data(extdata, paramsbuf, nwrite);
460   if(rc < 0)
461     return rc;
462 
463   return (int)nwrite;
464 }
465 
quic_init_ssl(struct quicsocket * qs)466 static int quic_init_ssl(struct quicsocket *qs)
467 {
468   gnutls_datum_t alpn = {NULL, 0};
469   /* this will need some attention when HTTPS proxy over QUIC get fixed */
470   const char * const hostname = qs->conn->host.name;
471   int rc;
472 
473   DEBUGASSERT(!qs->ssl);
474 
475   gnutls_init(&qs->ssl, GNUTLS_CLIENT);
476   gnutls_session_set_ptr(qs->ssl, qs);
477 
478   rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
479   if(rc < 0) {
480     H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
481                    gnutls_strerror(rc)));
482     return 1;
483   }
484 
485   gnutls_handshake_set_secret_function(qs->ssl, secret_func);
486   gnutls_handshake_set_read_function(qs->ssl, read_func);
487   gnutls_alert_set_read_function(qs->ssl, alert_read_func);
488 
489   rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters",
490                                    0xffa5, GNUTLS_EXT_TLS,
491                                    tp_recv_func, tp_send_func,
492                                    NULL, NULL, NULL,
493                                    GNUTLS_EXT_FLAG_TLS |
494                                    GNUTLS_EXT_FLAG_CLIENT_HELLO |
495                                    GNUTLS_EXT_FLAG_EE);
496   if(rc < 0) {
497     H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
498                    gnutls_strerror(rc)));
499     return 1;
500   }
501 
502   /* Open the file if a TLS or QUIC backend has not done this before. */
503   Curl_tls_keylog_open();
504   if(Curl_tls_keylog_enabled()) {
505     gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
506   }
507 
508   if(qs->cred)
509     gnutls_certificate_free_credentials(qs->cred);
510 
511   rc = gnutls_certificate_allocate_credentials(&qs->cred);
512   if(rc < 0) {
513     H3BUGF(fprintf(stderr,
514                    "gnutls_certificate_allocate_credentials failed: %s\n",
515                    gnutls_strerror(rc)));
516     return 1;
517   }
518 
519   rc = gnutls_certificate_set_x509_system_trust(qs->cred);
520   if(rc < 0) {
521     H3BUGF(fprintf(stderr,
522                    "gnutls_certificate_set_x509_system_trust failed: %s\n",
523                    gnutls_strerror(rc)));
524     return 1;
525   }
526 
527   rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
528   if(rc < 0) {
529     H3BUGF(fprintf(stderr, "gnutls_credentials_set failed: %s\n",
530                    gnutls_strerror(rc)));
531     return 1;
532   }
533 
534   /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
535   alpn.data = (unsigned char *)H3_ALPN_H3_29 + 1;
536   alpn.size = sizeof(H3_ALPN_H3_29) - 2;
537   if(alpn.data)
538     gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0);
539 
540   /* set SNI */
541   gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
542   return 0;
543 }
544 #endif
545 
546 static int
cb_recv_crypto_data(ngtcp2_conn * tconn,ngtcp2_crypto_level crypto_level,uint64_t offset,const uint8_t * data,size_t datalen,void * user_data)547 cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level,
548                     uint64_t offset,
549                     const uint8_t *data, size_t datalen,
550                     void *user_data)
551 {
552   (void)offset;
553   (void)user_data;
554 
555   if(ngtcp2_crypto_read_write_crypto_data(tconn, crypto_level, data,
556                                           datalen) != 0)
557     return NGTCP2_ERR_CRYPTO;
558 
559   return 0;
560 }
561 
cb_handshake_completed(ngtcp2_conn * tconn,void * user_data)562 static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
563 {
564   (void)user_data;
565   (void)tconn;
566   return 0;
567 }
568 
extend_stream_window(ngtcp2_conn * tconn,struct HTTP * stream)569 static void extend_stream_window(ngtcp2_conn *tconn,
570                                  struct HTTP *stream)
571 {
572   size_t thismuch = stream->unacked_window;
573   ngtcp2_conn_extend_max_stream_offset(tconn, stream->stream3_id, thismuch);
574   ngtcp2_conn_extend_max_offset(tconn, thismuch);
575   stream->unacked_window = 0;
576 }
577 
578 
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)579 static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
580                                int64_t stream_id, uint64_t offset,
581                                const uint8_t *buf, size_t buflen,
582                                void *user_data, void *stream_user_data)
583 {
584   struct quicsocket *qs = (struct quicsocket *)user_data;
585   ssize_t nconsumed;
586   int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
587   (void)offset;
588   (void)stream_user_data;
589 
590   nconsumed =
591     nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin);
592   if(nconsumed < 0) {
593     return NGTCP2_ERR_CALLBACK_FAILURE;
594   }
595 
596   /* number of bytes inside buflen which consists of framing overhead
597    * including QPACK HEADERS. In other words, it does not consume payload of
598    * DATA frame. */
599   ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
600   ngtcp2_conn_extend_max_offset(tconn, nconsumed);
601 
602   return 0;
603 }
604 
605 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)606 cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
607                             uint64_t offset, uint64_t datalen, void *user_data,
608                             void *stream_user_data)
609 {
610   struct quicsocket *qs = (struct quicsocket *)user_data;
611   int rv;
612   (void)stream_id;
613   (void)tconn;
614   (void)offset;
615   (void)datalen;
616   (void)stream_user_data;
617 
618   rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
619   if(rv) {
620     return NGTCP2_ERR_CALLBACK_FAILURE;
621   }
622 
623   return 0;
624 }
625 
cb_stream_close(ngtcp2_conn * tconn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)626 static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id,
627                            uint64_t app_error_code,
628                            void *user_data, void *stream_user_data)
629 {
630   struct quicsocket *qs = (struct quicsocket *)user_data;
631   int rv;
632   (void)tconn;
633   (void)stream_user_data;
634   /* stream is closed... */
635 
636   rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
637                                  app_error_code);
638   if(rv) {
639     return NGTCP2_ERR_CALLBACK_FAILURE;
640   }
641 
642   return 0;
643 }
644 
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)645 static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
646                            uint64_t final_size, uint64_t app_error_code,
647                            void *user_data, void *stream_user_data)
648 {
649   struct quicsocket *qs = (struct quicsocket *)user_data;
650   int rv;
651   (void)tconn;
652   (void)final_size;
653   (void)app_error_code;
654   (void)stream_user_data;
655 
656   rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id);
657   if(rv) {
658     return NGTCP2_ERR_CALLBACK_FAILURE;
659   }
660 
661   return 0;
662 }
663 
cb_extend_max_local_streams_bidi(ngtcp2_conn * tconn,uint64_t max_streams,void * user_data)664 static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
665                                             uint64_t max_streams,
666                                             void *user_data)
667 {
668   (void)tconn;
669   (void)max_streams;
670   (void)user_data;
671 
672   return 0;
673 }
674 
cb_extend_max_stream_data(ngtcp2_conn * tconn,int64_t stream_id,uint64_t max_data,void * user_data,void * stream_user_data)675 static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
676                                      uint64_t max_data, void *user_data,
677                                      void *stream_user_data)
678 {
679   struct quicsocket *qs = (struct quicsocket *)user_data;
680   int rv;
681   (void)tconn;
682   (void)max_data;
683   (void)stream_user_data;
684 
685   rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
686   if(rv) {
687     return NGTCP2_ERR_CALLBACK_FAILURE;
688   }
689 
690   return 0;
691 }
692 
cb_get_new_connection_id(ngtcp2_conn * tconn,ngtcp2_cid * cid,uint8_t * token,size_t cidlen,void * user_data)693 static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
694                                     uint8_t *token, size_t cidlen,
695                                     void *user_data)
696 {
697   CURLcode result;
698   (void)tconn;
699   (void)user_data;
700 
701   result = Curl_rand(NULL, cid->data, cidlen);
702   if(result)
703     return NGTCP2_ERR_CALLBACK_FAILURE;
704   cid->datalen = cidlen;
705 
706   result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
707   if(result)
708     return NGTCP2_ERR_CALLBACK_FAILURE;
709 
710   return 0;
711 }
712 
713 static ngtcp2_callbacks ng_callbacks = {
714   ngtcp2_crypto_client_initial_cb,
715   NULL, /* recv_client_initial */
716   cb_recv_crypto_data,
717   cb_handshake_completed,
718   NULL, /* recv_version_negotiation */
719   ngtcp2_crypto_encrypt_cb,
720   ngtcp2_crypto_decrypt_cb,
721   ngtcp2_crypto_hp_mask_cb,
722   cb_recv_stream_data,
723   NULL, /* acked_crypto_offset */
724   cb_acked_stream_data_offset,
725   NULL, /* stream_open */
726   cb_stream_close,
727   NULL, /* recv_stateless_reset */
728   ngtcp2_crypto_recv_retry_cb,
729   cb_extend_max_local_streams_bidi,
730   NULL, /* extend_max_local_streams_uni */
731   NULL, /* rand  */
732   cb_get_new_connection_id,
733   NULL, /* remove_connection_id */
734   ngtcp2_crypto_update_key_cb, /* update_key */
735   NULL, /* path_validation */
736   NULL, /* select_preferred_addr */
737   cb_stream_reset,
738   NULL, /* extend_max_remote_streams_bidi */
739   NULL, /* extend_max_remote_streams_uni */
740   cb_extend_max_stream_data,
741   NULL, /* dcid_status */
742   NULL, /* handshake_confirmed */
743   NULL, /* recv_new_token */
744   ngtcp2_crypto_delete_crypto_aead_ctx_cb,
745   ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
746   NULL, /* recv_datagram */
747   NULL, /* ack_datagram */
748   NULL  /* lost_datagram */
749 };
750 
751 /*
752  * Might be called twice for happy eyeballs.
753  */
Curl_quic_connect(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sockfd,int sockindex,const struct sockaddr * addr,socklen_t addrlen)754 CURLcode Curl_quic_connect(struct Curl_easy *data,
755                            struct connectdata *conn,
756                            curl_socket_t sockfd,
757                            int sockindex,
758                            const struct sockaddr *addr,
759                            socklen_t addrlen)
760 {
761   int rc;
762   int rv;
763   CURLcode result;
764   ngtcp2_path path; /* TODO: this must be initialized properly */
765   struct quicsocket *qs = &conn->hequic[sockindex];
766   char ipbuf[40];
767   int port;
768   int qfd;
769 
770   if(qs->conn)
771     Curl_quic_disconnect(data, conn, sockindex);
772   qs->conn = conn;
773 
774   /* extract the used address as a string */
775   if(!Curl_addr2string((struct sockaddr*)addr, addrlen, ipbuf, &port)) {
776     char buffer[STRERROR_LEN];
777     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
778           SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
779     return CURLE_BAD_FUNCTION_ARGUMENT;
780   }
781 
782   infof(data, "Connect socket %d over QUIC to %s:%d",
783         sockfd, ipbuf, port);
784 
785   qs->version = NGTCP2_PROTO_VER_MAX;
786 #ifdef USE_OPENSSL
787   qs->sslctx = quic_ssl_ctx(data);
788   if(!qs->sslctx)
789     return CURLE_QUIC_CONNECT_ERROR;
790 #endif
791 
792   if(quic_init_ssl(qs))
793     return CURLE_QUIC_CONNECT_ERROR;
794 
795   qs->dcid.datalen = NGTCP2_MAX_CIDLEN;
796   result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN);
797   if(result)
798     return result;
799 
800   qs->scid.datalen = NGTCP2_MAX_CIDLEN;
801   result = Curl_rand(data, qs->scid.data, NGTCP2_MAX_CIDLEN);
802   if(result)
803     return result;
804 
805   (void)Curl_qlogdir(data, qs->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
806   qs->qlogfd = qfd; /* -1 if failure above */
807   quic_settings(qs, data->set.buffer_size);
808 
809   qs->local_addrlen = sizeof(qs->local_addr);
810   rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr,
811                    &qs->local_addrlen);
812   if(rv == -1)
813     return CURLE_QUIC_CONNECT_ERROR;
814 
815   ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
816                    qs->local_addrlen);
817   ngtcp2_addr_init(&path.remote, addr, addrlen);
818 
819   rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path,
820                               NGTCP2_PROTO_VER_MIN, &ng_callbacks,
821                               &qs->settings, &qs->transport_params, NULL, qs);
822   if(rc)
823     return CURLE_QUIC_CONNECT_ERROR;
824 
825   ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl);
826 
827   return CURLE_OK;
828 }
829 
830 /*
831  * Store ngtcp2 version info in this buffer.
832  */
Curl_quic_ver(char * p,size_t len)833 void Curl_quic_ver(char *p, size_t len)
834 {
835   const ngtcp2_info *ng2 = ngtcp2_version(0);
836   nghttp3_info *ht3 = nghttp3_version(0);
837   (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
838                   ng2->version_str, ht3->version_str);
839 }
840 
ng_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * socks)841 static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
842                       curl_socket_t *socks)
843 {
844   struct SingleRequest *k = &data->req;
845   int bitmap = GETSOCK_BLANK;
846 
847   socks[0] = conn->sock[FIRSTSOCKET];
848 
849   /* in a HTTP/2 connection we can basically always get a frame so we should
850      always be ready for one */
851   bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
852 
853   /* we're still uploading or the HTTP/2 layer wants to send data */
854   if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND)
855     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
856 
857   return bitmap;
858 }
859 
qs_disconnect(struct quicsocket * qs)860 static void qs_disconnect(struct quicsocket *qs)
861 {
862   int i;
863   if(!qs->conn) /* already closed */
864     return;
865   qs->conn = NULL;
866   if(qs->qlogfd != -1) {
867     close(qs->qlogfd);
868     qs->qlogfd = -1;
869   }
870   if(qs->ssl)
871 #ifdef USE_OPENSSL
872     SSL_free(qs->ssl);
873 #elif defined(USE_GNUTLS)
874     gnutls_deinit(qs->ssl);
875 #endif
876   qs->ssl = NULL;
877 #ifdef USE_GNUTLS
878   if(qs->cred) {
879     gnutls_certificate_free_credentials(qs->cred);
880     qs->cred = NULL;
881   }
882 #endif
883   for(i = 0; i < 3; i++)
884     Curl_safefree(qs->crypto_data[i].buf);
885   nghttp3_conn_del(qs->h3conn);
886   ngtcp2_conn_del(qs->qconn);
887 #ifdef USE_OPENSSL
888   SSL_CTX_free(qs->sslctx);
889 #endif
890 }
891 
Curl_quic_disconnect(struct Curl_easy * data,struct connectdata * conn,int tempindex)892 void Curl_quic_disconnect(struct Curl_easy *data,
893                           struct connectdata *conn,
894                           int tempindex)
895 {
896   (void)data;
897   if(conn->transport == TRNSPRT_QUIC)
898     qs_disconnect(&conn->hequic[tempindex]);
899 }
900 
ng_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)901 static CURLcode ng_disconnect(struct Curl_easy *data,
902                               struct connectdata *conn,
903                               bool dead_connection)
904 {
905   (void)dead_connection;
906   Curl_quic_disconnect(data, conn, 0);
907   Curl_quic_disconnect(data, conn, 1);
908   return CURLE_OK;
909 }
910 
ng_conncheck(struct Curl_easy * data,struct connectdata * conn,unsigned int checks_to_perform)911 static unsigned int ng_conncheck(struct Curl_easy *data,
912                                  struct connectdata *conn,
913                                  unsigned int checks_to_perform)
914 {
915   (void)data;
916   (void)conn;
917   (void)checks_to_perform;
918   return CONNRESULT_NONE;
919 }
920 
921 static const struct Curl_handler Curl_handler_http3 = {
922   "HTTPS",                              /* scheme */
923   ZERO_NULL,                            /* setup_connection */
924   Curl_http,                            /* do_it */
925   Curl_http_done,                       /* done */
926   ZERO_NULL,                            /* do_more */
927   ZERO_NULL,                            /* connect_it */
928   ZERO_NULL,                            /* connecting */
929   ZERO_NULL,                            /* doing */
930   ng_getsock,                           /* proto_getsock */
931   ng_getsock,                           /* doing_getsock */
932   ZERO_NULL,                            /* domore_getsock */
933   ng_getsock,                           /* perform_getsock */
934   ng_disconnect,                        /* disconnect */
935   ZERO_NULL,                            /* readwrite */
936   ng_conncheck,                         /* connection_check */
937   ZERO_NULL,                            /* attach connection */
938   PORT_HTTP,                            /* defport */
939   CURLPROTO_HTTPS,                      /* protocol */
940   CURLPROTO_HTTP,                       /* family */
941   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
942 };
943 
cb_h3_stream_close(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)944 static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
945                               uint64_t app_error_code, void *user_data,
946                               void *stream_user_data)
947 {
948   struct Curl_easy *data = stream_user_data;
949   struct HTTP *stream = data->req.p.http;
950   (void)conn;
951   (void)stream_id;
952   (void)app_error_code;
953   (void)user_data;
954   H3BUGF(infof(data, "cb_h3_stream_close CALLED"));
955 
956   stream->closed = TRUE;
957   Curl_expire(data, 0, EXPIRE_QUIC);
958   /* make sure that ngh3_stream_recv is called again to complete the transfer
959      even if there are no more packets to be received from the server. */
960   data->state.drain = 1;
961   return 0;
962 }
963 
964 /*
965  * write_data() copies data to the stream's receive buffer. If not enough
966  * space is available in the receive buffer, it copies the rest to the
967  * stream's overflow buffer.
968  */
write_data(struct HTTP * stream,const void * mem,size_t memlen)969 static CURLcode write_data(struct HTTP *stream, const void *mem, size_t memlen)
970 {
971   CURLcode result = CURLE_OK;
972   const char *buf = mem;
973   size_t ncopy = memlen;
974   /* copy as much as possible to the receive buffer */
975   if(stream->len) {
976     size_t len = CURLMIN(ncopy, stream->len);
977     memcpy(stream->mem, buf, len);
978     stream->len -= len;
979     stream->memlen += len;
980     stream->mem += len;
981     buf += len;
982     ncopy -= len;
983   }
984   /* copy the rest to the overflow buffer */
985   if(ncopy)
986     result = Curl_dyn_addn(&stream->overflow, buf, ncopy);
987   return result;
988 }
989 
cb_h3_recv_data(nghttp3_conn * conn,int64_t stream_id,const uint8_t * buf,size_t buflen,void * user_data,void * stream_user_data)990 static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
991                            const uint8_t *buf, size_t buflen,
992                            void *user_data, void *stream_user_data)
993 {
994   struct Curl_easy *data = stream_user_data;
995   struct HTTP *stream = data->req.p.http;
996   CURLcode result = CURLE_OK;
997   (void)conn;
998 
999   result = write_data(stream, buf, buflen);
1000   if(result) {
1001     return -1;
1002   }
1003   stream->unacked_window += buflen;
1004   (void)stream_id;
1005   (void)user_data;
1006   return 0;
1007 }
1008 
cb_h3_deferred_consume(nghttp3_conn * conn,int64_t stream_id,size_t consumed,void * user_data,void * stream_user_data)1009 static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
1010                                   size_t consumed, void *user_data,
1011                                   void *stream_user_data)
1012 {
1013   struct quicsocket *qs = user_data;
1014   (void)conn;
1015   (void)stream_user_data;
1016   (void)stream_id;
1017 
1018   ngtcp2_conn_extend_max_stream_offset(qs->qconn, stream_id, consumed);
1019   ngtcp2_conn_extend_max_offset(qs->qconn, consumed);
1020   return 0;
1021 }
1022 
1023 /* Decode HTTP status code.  Returns -1 if no valid status code was
1024    decoded. (duplicate from http2.c) */
decode_status_code(const uint8_t * value,size_t len)1025 static int decode_status_code(const uint8_t *value, size_t len)
1026 {
1027   int i;
1028   int res;
1029 
1030   if(len != 3) {
1031     return -1;
1032   }
1033 
1034   res = 0;
1035 
1036   for(i = 0; i < 3; ++i) {
1037     char c = value[i];
1038 
1039     if(c < '0' || c > '9') {
1040       return -1;
1041     }
1042 
1043     res *= 10;
1044     res += c - '0';
1045   }
1046 
1047   return res;
1048 }
1049 
cb_h3_end_headers(nghttp3_conn * conn,int64_t stream_id,void * user_data,void * stream_user_data)1050 static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
1051                              void *user_data, void *stream_user_data)
1052 {
1053   struct Curl_easy *data = stream_user_data;
1054   struct HTTP *stream = data->req.p.http;
1055   CURLcode result = CURLE_OK;
1056   (void)conn;
1057   (void)stream_id;
1058   (void)user_data;
1059 
1060   /* add a CRLF only if we've received some headers */
1061   if(stream->firstheader) {
1062     result = write_data(stream, "\r\n", 2);
1063     if(result) {
1064       return -1;
1065     }
1066   }
1067   return 0;
1068 }
1069 
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)1070 static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
1071                              int32_t token, nghttp3_rcbuf *name,
1072                              nghttp3_rcbuf *value, uint8_t flags,
1073                              void *user_data, void *stream_user_data)
1074 {
1075   nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
1076   nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
1077   struct Curl_easy *data = stream_user_data;
1078   struct HTTP *stream = data->req.p.http;
1079   CURLcode result = CURLE_OK;
1080   (void)conn;
1081   (void)stream_id;
1082   (void)token;
1083   (void)flags;
1084   (void)user_data;
1085 
1086   if(h3name.len == sizeof(":status") - 1 &&
1087      !memcmp(":status", h3name.base, h3name.len)) {
1088     char line[14]; /* status line is always 13 characters long */
1089     size_t ncopy;
1090     int status = decode_status_code(h3val.base, h3val.len);
1091     DEBUGASSERT(status != -1);
1092     ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status);
1093     result = write_data(stream, line, ncopy);
1094     if(result) {
1095       return -1;
1096     }
1097   }
1098   else {
1099     /* store as a HTTP1-style header */
1100     result = write_data(stream, h3name.base, h3name.len);
1101     if(result) {
1102       return -1;
1103     }
1104     result = write_data(stream, ": ", 2);
1105     if(result) {
1106       return -1;
1107     }
1108     result = write_data(stream, h3val.base, h3val.len);
1109     if(result) {
1110       return -1;
1111     }
1112     result = write_data(stream, "\r\n", 2);
1113     if(result) {
1114       return -1;
1115     }
1116   }
1117 
1118   stream->firstheader = TRUE;
1119   return 0;
1120 }
1121 
cb_h3_send_stop_sending(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code,void * user_data,void * stream_user_data)1122 static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id,
1123                                    uint64_t app_error_code,
1124                                    void *user_data,
1125                                    void *stream_user_data)
1126 {
1127   (void)conn;
1128   (void)stream_id;
1129   (void)app_error_code;
1130   (void)user_data;
1131   (void)stream_user_data;
1132   return 0;
1133 }
1134 
1135 static nghttp3_callbacks ngh3_callbacks = {
1136   cb_h3_acked_stream_data, /* acked_stream_data */
1137   cb_h3_stream_close,
1138   cb_h3_recv_data,
1139   cb_h3_deferred_consume,
1140   NULL, /* begin_headers */
1141   cb_h3_recv_header,
1142   cb_h3_end_headers,
1143   NULL, /* begin_trailers */
1144   cb_h3_recv_header,
1145   NULL, /* end_trailers */
1146   NULL, /* http_begin_push_promise */
1147   NULL, /* http_recv_push_promise */
1148   NULL, /* http_end_push_promise */
1149   NULL, /* http_cancel_push */
1150   cb_h3_send_stop_sending,
1151   NULL, /* push_stream */
1152   NULL, /* end_stream */
1153   NULL, /* reset_stream */
1154 };
1155 
init_ngh3_conn(struct quicsocket * qs)1156 static int init_ngh3_conn(struct quicsocket *qs)
1157 {
1158   CURLcode result;
1159   int rc;
1160   int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
1161 
1162   if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) {
1163     return CURLE_QUIC_CONNECT_ERROR;
1164   }
1165 
1166   nghttp3_settings_default(&qs->h3settings);
1167 
1168   rc = nghttp3_conn_client_new(&qs->h3conn,
1169                                &ngh3_callbacks,
1170                                &qs->h3settings,
1171                                nghttp3_mem_default(),
1172                                qs);
1173   if(rc) {
1174     result = CURLE_OUT_OF_MEMORY;
1175     goto fail;
1176   }
1177 
1178   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &ctrl_stream_id, NULL);
1179   if(rc) {
1180     result = CURLE_QUIC_CONNECT_ERROR;
1181     goto fail;
1182   }
1183 
1184   rc = nghttp3_conn_bind_control_stream(qs->h3conn, ctrl_stream_id);
1185   if(rc) {
1186     result = CURLE_QUIC_CONNECT_ERROR;
1187     goto fail;
1188   }
1189 
1190   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_enc_stream_id, NULL);
1191   if(rc) {
1192     result = CURLE_QUIC_CONNECT_ERROR;
1193     goto fail;
1194   }
1195 
1196   rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_dec_stream_id, NULL);
1197   if(rc) {
1198     result = CURLE_QUIC_CONNECT_ERROR;
1199     goto fail;
1200   }
1201 
1202   rc = nghttp3_conn_bind_qpack_streams(qs->h3conn, qpack_enc_stream_id,
1203                                        qpack_dec_stream_id);
1204   if(rc) {
1205     result = CURLE_QUIC_CONNECT_ERROR;
1206     goto fail;
1207   }
1208 
1209   return CURLE_OK;
1210   fail:
1211 
1212   return result;
1213 }
1214 
1215 static Curl_recv ngh3_stream_recv;
1216 static Curl_send ngh3_stream_send;
1217 
drain_overflow_buffer(struct HTTP * stream)1218 static size_t drain_overflow_buffer(struct HTTP *stream)
1219 {
1220   size_t overlen = Curl_dyn_len(&stream->overflow);
1221   size_t ncopy = CURLMIN(overlen, stream->len);
1222   if(ncopy > 0) {
1223     memcpy(stream->mem, Curl_dyn_ptr(&stream->overflow), ncopy);
1224     stream->len -= ncopy;
1225     stream->mem += ncopy;
1226     stream->memlen += ncopy;
1227     if(ncopy != overlen)
1228       /* make the buffer only keep the tail */
1229       (void)Curl_dyn_tail(&stream->overflow, overlen - ncopy);
1230   }
1231   return ncopy;
1232 }
1233 
1234 /* incoming data frames on the h3 stream */
ngh3_stream_recv(struct Curl_easy * data,int sockindex,char * buf,size_t buffersize,CURLcode * curlcode)1235 static ssize_t ngh3_stream_recv(struct Curl_easy *data,
1236                                 int sockindex,
1237                                 char *buf,
1238                                 size_t buffersize,
1239                                 CURLcode *curlcode)
1240 {
1241   struct connectdata *conn = data->conn;
1242   curl_socket_t sockfd = conn->sock[sockindex];
1243   struct HTTP *stream = data->req.p.http;
1244   struct quicsocket *qs = conn->quic;
1245 
1246   if(!stream->memlen) {
1247     /* remember where to store incoming data for this stream and how big the
1248        buffer is */
1249     stream->mem = buf;
1250     stream->len = buffersize;
1251   }
1252   /* else, there's data in the buffer already */
1253 
1254   /* if there's data in the overflow buffer from a previous call, copy as much
1255      as possible to the receive buffer before receiving more */
1256   drain_overflow_buffer(stream);
1257 
1258   if(ng_process_ingress(data, sockfd, qs)) {
1259     *curlcode = CURLE_RECV_ERROR;
1260     return -1;
1261   }
1262   if(ng_flush_egress(data, sockfd, qs)) {
1263     *curlcode = CURLE_SEND_ERROR;
1264     return -1;
1265   }
1266 
1267   if(stream->memlen) {
1268     ssize_t memlen = stream->memlen;
1269     /* data arrived */
1270     *curlcode = CURLE_OK;
1271     /* reset to allow more data to come */
1272     stream->memlen = 0;
1273     stream->mem = buf;
1274     stream->len = buffersize;
1275     /* extend the stream window with the data we're consuming and send out
1276        any additional packets to tell the server that we can receive more */
1277     extend_stream_window(qs->qconn, stream);
1278     if(ng_flush_egress(data, sockfd, qs)) {
1279       *curlcode = CURLE_SEND_ERROR;
1280       return -1;
1281     }
1282     return memlen;
1283   }
1284 
1285   if(stream->closed) {
1286     *curlcode = CURLE_OK;
1287     return 0;
1288   }
1289 
1290   infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN");
1291   *curlcode = CURLE_AGAIN;
1292   return -1;
1293 }
1294 
1295 /* this amount of data has now been acked on this stream */
cb_h3_acked_stream_data(nghttp3_conn * conn,int64_t stream_id,size_t datalen,void * user_data,void * stream_user_data)1296 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
1297                                    size_t datalen, void *user_data,
1298                                    void *stream_user_data)
1299 {
1300   struct Curl_easy *data = stream_user_data;
1301   struct HTTP *stream = data->req.p.http;
1302   (void)user_data;
1303 
1304   if(!data->set.postfields) {
1305     stream->h3out->used -= datalen;
1306     H3BUGF(infof(data,
1307                  "cb_h3_acked_stream_data, %zd bytes, %zd left unacked",
1308                  datalen, stream->h3out->used));
1309     DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
1310 
1311     if(stream->h3out->used == 0) {
1312       int rv = nghttp3_conn_resume_stream(conn, stream_id);
1313       if(rv) {
1314         return NGTCP2_ERR_CALLBACK_FAILURE;
1315       }
1316     }
1317   }
1318   return 0;
1319 }
1320 
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)1321 static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
1322                                   nghttp3_vec *vec, size_t veccnt,
1323                                   uint32_t *pflags, void *user_data,
1324                                   void *stream_user_data)
1325 {
1326   struct Curl_easy *data = stream_user_data;
1327   size_t nread;
1328   struct HTTP *stream = data->req.p.http;
1329   (void)conn;
1330   (void)stream_id;
1331   (void)user_data;
1332   (void)veccnt;
1333 
1334   if(data->set.postfields) {
1335     vec[0].base = data->set.postfields;
1336     vec[0].len = data->state.infilesize;
1337     *pflags = NGHTTP3_DATA_FLAG_EOF;
1338     return 1;
1339   }
1340 
1341   nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used);
1342   if(nread > 0) {
1343     /* nghttp3 wants us to hold on to the data until it tells us it is okay to
1344        delete it. Append the data at the end of the h3out buffer. Since we can
1345        only return consecutive data, copy the amount that fits and the next
1346        part comes in next invoke. */
1347     struct h3out *out = stream->h3out;
1348     if(nread + out->windex > H3_SEND_SIZE)
1349       nread = H3_SEND_SIZE - out->windex;
1350 
1351     memcpy(&out->buf[out->windex], stream->upload_mem, nread);
1352 
1353     /* that's the chunk we return to nghttp3 */
1354     vec[0].base = &out->buf[out->windex];
1355     vec[0].len = nread;
1356 
1357     out->windex += nread;
1358     out->used += nread;
1359 
1360     if(out->windex == H3_SEND_SIZE)
1361       out->windex = 0; /* wrap */
1362     stream->upload_mem += nread;
1363     stream->upload_len -= nread;
1364     if(data->state.infilesize != -1) {
1365       stream->upload_left -= nread;
1366       if(!stream->upload_left)
1367         *pflags = NGHTTP3_DATA_FLAG_EOF;
1368     }
1369     H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)",
1370                  nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
1371                  out->used));
1372   }
1373   if(stream->upload_done && !stream->upload_len &&
1374      (stream->upload_left <= 0)) {
1375     H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF"));
1376     *pflags = NGHTTP3_DATA_FLAG_EOF;
1377     return nread ? 1 : 0;
1378   }
1379   else if(!nread) {
1380     return NGHTTP3_ERR_WOULDBLOCK;
1381   }
1382   return 1;
1383 }
1384 
1385 /* Index where :authority header field will appear in request header
1386    field list. */
1387 #define AUTHORITY_DST_IDX 3
1388 
http_request(struct Curl_easy * data,const void * mem,size_t len)1389 static CURLcode http_request(struct Curl_easy *data, const void *mem,
1390                              size_t len)
1391 {
1392   struct connectdata *conn = data->conn;
1393   struct HTTP *stream = data->req.p.http;
1394   size_t nheader;
1395   size_t i;
1396   size_t authority_idx;
1397   char *hdbuf = (char *)mem;
1398   char *end, *line_end;
1399   struct quicsocket *qs = conn->quic;
1400   CURLcode result = CURLE_OK;
1401   nghttp3_nv *nva = NULL;
1402   int64_t stream3_id;
1403   int rc;
1404   struct h3out *h3out = NULL;
1405 
1406   rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL);
1407   if(rc) {
1408     failf(data, "can get bidi streams");
1409     result = CURLE_SEND_ERROR;
1410     goto fail;
1411   }
1412 
1413   stream->stream3_id = stream3_id;
1414   stream->h3req = TRUE; /* senf off! */
1415   Curl_dyn_init(&stream->overflow, CURL_MAX_READ_SIZE);
1416 
1417   /* Calculate number of headers contained in [mem, mem + len). Assumes a
1418      correctly generated HTTP header field block. */
1419   nheader = 0;
1420   for(i = 1; i < len; ++i) {
1421     if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
1422       ++nheader;
1423       ++i;
1424     }
1425   }
1426   if(nheader < 2)
1427     goto fail;
1428 
1429   /* We counted additional 2 \r\n in the first and last line. We need 3
1430      new headers: :method, :path and :scheme. Therefore we need one
1431      more space. */
1432   nheader += 1;
1433   nva = malloc(sizeof(nghttp3_nv) * nheader);
1434   if(!nva) {
1435     result = CURLE_OUT_OF_MEMORY;
1436     goto fail;
1437   }
1438 
1439   /* Extract :method, :path from request line
1440      We do line endings with CRLF so checking for CR is enough */
1441   line_end = memchr(hdbuf, '\r', len);
1442   if(!line_end) {
1443     result = CURLE_BAD_FUNCTION_ARGUMENT; /* internal error */
1444     goto fail;
1445   }
1446 
1447   /* Method does not contain spaces */
1448   end = memchr(hdbuf, ' ', line_end - hdbuf);
1449   if(!end || end == hdbuf)
1450     goto fail;
1451   nva[0].name = (unsigned char *)":method";
1452   nva[0].namelen = strlen((char *)nva[0].name);
1453   nva[0].value = (unsigned char *)hdbuf;
1454   nva[0].valuelen = (size_t)(end - hdbuf);
1455   nva[0].flags = NGHTTP3_NV_FLAG_NONE;
1456 
1457   hdbuf = end + 1;
1458 
1459   /* Path may contain spaces so scan backwards */
1460   end = NULL;
1461   for(i = (size_t)(line_end - hdbuf); i; --i) {
1462     if(hdbuf[i - 1] == ' ') {
1463       end = &hdbuf[i - 1];
1464       break;
1465     }
1466   }
1467   if(!end || end == hdbuf)
1468     goto fail;
1469   nva[1].name = (unsigned char *)":path";
1470   nva[1].namelen = strlen((char *)nva[1].name);
1471   nva[1].value = (unsigned char *)hdbuf;
1472   nva[1].valuelen = (size_t)(end - hdbuf);
1473   nva[1].flags = NGHTTP3_NV_FLAG_NONE;
1474 
1475   nva[2].name = (unsigned char *)":scheme";
1476   nva[2].namelen = strlen((char *)nva[2].name);
1477   if(conn->handler->flags & PROTOPT_SSL)
1478     nva[2].value = (unsigned char *)"https";
1479   else
1480     nva[2].value = (unsigned char *)"http";
1481   nva[2].valuelen = strlen((char *)nva[2].value);
1482   nva[2].flags = NGHTTP3_NV_FLAG_NONE;
1483 
1484 
1485   authority_idx = 0;
1486   i = 3;
1487   while(i < nheader) {
1488     size_t hlen;
1489 
1490     hdbuf = line_end + 2;
1491 
1492     /* check for next CR, but only within the piece of data left in the given
1493        buffer */
1494     line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
1495     if(!line_end || (line_end == hdbuf))
1496       goto fail;
1497 
1498     /* header continuation lines are not supported */
1499     if(*hdbuf == ' ' || *hdbuf == '\t')
1500       goto fail;
1501 
1502     for(end = hdbuf; end < line_end && *end != ':'; ++end)
1503       ;
1504     if(end == hdbuf || end == line_end)
1505       goto fail;
1506     hlen = end - hdbuf;
1507 
1508     if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
1509       authority_idx = i;
1510       nva[i].name = (unsigned char *)":authority";
1511       nva[i].namelen = strlen((char *)nva[i].name);
1512     }
1513     else {
1514       nva[i].namelen = (size_t)(end - hdbuf);
1515       /* Lower case the header name for HTTP/3 */
1516       Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
1517       nva[i].name = (unsigned char *)hdbuf;
1518     }
1519     nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1520     hdbuf = end + 1;
1521     while(*hdbuf == ' ' || *hdbuf == '\t')
1522       ++hdbuf;
1523     end = line_end;
1524 
1525 #if 0 /* This should probably go in more or less like this */
1526     switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
1527                           end - hdbuf)) {
1528     case HEADERINST_IGNORE:
1529       /* skip header fields prohibited by HTTP/2 specification. */
1530       --nheader;
1531       continue;
1532     case HEADERINST_TE_TRAILERS:
1533       nva[i].value = (uint8_t*)"trailers";
1534       nva[i].value_len = sizeof("trailers") - 1;
1535       break;
1536     default:
1537       nva[i].value = (unsigned char *)hdbuf;
1538       nva[i].value_len = (size_t)(end - hdbuf);
1539     }
1540 #endif
1541     nva[i].value = (unsigned char *)hdbuf;
1542     nva[i].valuelen = (size_t)(end - hdbuf);
1543     nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1544 
1545     ++i;
1546   }
1547 
1548   /* :authority must come before non-pseudo header fields */
1549   if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
1550     nghttp3_nv authority = nva[authority_idx];
1551     for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
1552       nva[i] = nva[i - 1];
1553     }
1554     nva[i] = authority;
1555   }
1556 
1557   /* Warn stream may be rejected if cumulative length of headers is too
1558      large. */
1559 #define MAX_ACC 60000  /* <64KB to account for some overhead */
1560   {
1561     size_t acc = 0;
1562     for(i = 0; i < nheader; ++i)
1563       acc += nva[i].namelen + nva[i].valuelen;
1564 
1565     if(acc > MAX_ACC) {
1566       infof(data, "http_request: Warning: The cumulative length of all "
1567             "headers exceeds %d bytes and that could cause the "
1568             "stream to be rejected.", MAX_ACC);
1569     }
1570   }
1571 
1572   switch(data->state.httpreq) {
1573   case HTTPREQ_POST:
1574   case HTTPREQ_POST_FORM:
1575   case HTTPREQ_POST_MIME:
1576   case HTTPREQ_PUT: {
1577     nghttp3_data_reader data_reader;
1578     if(data->state.infilesize != -1)
1579       stream->upload_left = data->state.infilesize;
1580     else
1581       /* data sending without specifying the data amount up front */
1582       stream->upload_left = -1; /* unknown, but not zero */
1583 
1584     data_reader.read_data = cb_h3_readfunction;
1585 
1586     h3out = calloc(sizeof(struct h3out), 1);
1587     if(!h3out) {
1588       result = CURLE_OUT_OF_MEMORY;
1589       goto fail;
1590     }
1591     stream->h3out = h3out;
1592 
1593     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1594                                      nva, nheader, &data_reader, data);
1595     if(rc) {
1596       result = CURLE_SEND_ERROR;
1597       goto fail;
1598     }
1599     break;
1600   }
1601   default:
1602     stream->upload_left = 0; /* nothing left to send */
1603     rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1604                                      nva, nheader, NULL, data);
1605     if(rc) {
1606       result = CURLE_SEND_ERROR;
1607       goto fail;
1608     }
1609     break;
1610   }
1611 
1612   Curl_safefree(nva);
1613 
1614   infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)",
1615         stream3_id, (void *)data);
1616 
1617   return CURLE_OK;
1618 
1619 fail:
1620   free(nva);
1621   return result;
1622 }
ngh3_stream_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,CURLcode * curlcode)1623 static ssize_t ngh3_stream_send(struct Curl_easy *data,
1624                                 int sockindex,
1625                                 const void *mem,
1626                                 size_t len,
1627                                 CURLcode *curlcode)
1628 {
1629   ssize_t sent;
1630   struct connectdata *conn = data->conn;
1631   struct quicsocket *qs = conn->quic;
1632   curl_socket_t sockfd = conn->sock[sockindex];
1633   struct HTTP *stream = data->req.p.http;
1634 
1635   if(!stream->h3req) {
1636     CURLcode result = http_request(data, mem, len);
1637     if(result) {
1638       *curlcode = CURLE_SEND_ERROR;
1639       return -1;
1640     }
1641     sent = len;
1642   }
1643   else {
1644     H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes",
1645                  len));
1646     if(!stream->upload_len) {
1647       stream->upload_mem = mem;
1648       stream->upload_len = len;
1649       (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
1650       sent = len;
1651     }
1652     else {
1653       *curlcode = CURLE_AGAIN;
1654       return -1;
1655     }
1656   }
1657 
1658   if(ng_flush_egress(data, sockfd, qs)) {
1659     *curlcode = CURLE_SEND_ERROR;
1660     return -1;
1661   }
1662 
1663   *curlcode = CURLE_OK;
1664   return sent;
1665 }
1666 
ng_has_connected(struct connectdata * conn,int tempindex)1667 static void ng_has_connected(struct connectdata *conn, int tempindex)
1668 {
1669   conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
1670   conn->send[FIRSTSOCKET] = ngh3_stream_send;
1671   conn->handler = &Curl_handler_http3;
1672   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1673   conn->httpversion = 30;
1674   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
1675   conn->quic = &conn->hequic[tempindex];
1676 }
1677 
1678 /*
1679  * There can be multiple connection attempts going on in parallel.
1680  */
Curl_quic_is_connected(struct Curl_easy * data,struct connectdata * conn,int sockindex,bool * done)1681 CURLcode Curl_quic_is_connected(struct Curl_easy *data,
1682                                 struct connectdata *conn,
1683                                 int sockindex,
1684                                 bool *done)
1685 {
1686   CURLcode result;
1687   struct quicsocket *qs = &conn->hequic[sockindex];
1688   curl_socket_t sockfd = conn->tempsock[sockindex];
1689 
1690   result = ng_process_ingress(data, sockfd, qs);
1691   if(result)
1692     goto error;
1693 
1694   result = ng_flush_egress(data, sockfd, qs);
1695   if(result)
1696     goto error;
1697 
1698   if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
1699     *done = TRUE;
1700     ng_has_connected(conn, sockindex);
1701   }
1702 
1703   return result;
1704   error:
1705   (void)qs_disconnect(qs);
1706   return result;
1707 
1708 }
1709 
ng_process_ingress(struct Curl_easy * data,curl_socket_t sockfd,struct quicsocket * qs)1710 static CURLcode ng_process_ingress(struct Curl_easy *data,
1711                                    curl_socket_t sockfd,
1712                                    struct quicsocket *qs)
1713 {
1714   ssize_t recvd;
1715   int rv;
1716   uint8_t buf[65536];
1717   size_t bufsize = sizeof(buf);
1718   struct sockaddr_storage remote_addr;
1719   socklen_t remote_addrlen;
1720   ngtcp2_path path;
1721   ngtcp2_tstamp ts = timestamp();
1722   ngtcp2_pkt_info pi = { 0 };
1723 
1724   for(;;) {
1725     remote_addrlen = sizeof(remote_addr);
1726     while((recvd = recvfrom(sockfd, (char *)buf, bufsize, 0,
1727                             (struct sockaddr *)&remote_addr,
1728                             &remote_addrlen)) == -1 &&
1729           SOCKERRNO == EINTR)
1730       ;
1731     if(recvd == -1) {
1732       if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)
1733         break;
1734 
1735       failf(data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd);
1736       return CURLE_RECV_ERROR;
1737     }
1738 
1739     ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
1740                      qs->local_addrlen);
1741     ngtcp2_addr_init(&path.remote, (struct sockaddr *)&remote_addr,
1742                      remote_addrlen);
1743 
1744     rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
1745     if(rv) {
1746       /* TODO Send CONNECTION_CLOSE if possible */
1747       return CURLE_RECV_ERROR;
1748     }
1749   }
1750 
1751   return CURLE_OK;
1752 }
1753 
ng_flush_egress(struct Curl_easy * data,int sockfd,struct quicsocket * qs)1754 static CURLcode ng_flush_egress(struct Curl_easy *data,
1755                                 int sockfd,
1756                                 struct quicsocket *qs)
1757 {
1758   int rv;
1759   ssize_t sent;
1760   ssize_t outlen;
1761   uint8_t out[NGTCP2_MAX_PKTLEN_IPV4];
1762   size_t pktlen;
1763   ngtcp2_path_storage ps;
1764   ngtcp2_tstamp ts = timestamp();
1765   struct sockaddr_storage remote_addr;
1766   ngtcp2_tstamp expiry;
1767   ngtcp2_duration timeout;
1768   int64_t stream_id;
1769   ssize_t veccnt;
1770   int fin;
1771   nghttp3_vec vec[16];
1772   ssize_t ndatalen;
1773   uint32_t flags;
1774 
1775   switch(qs->local_addr.ss_family) {
1776   case AF_INET:
1777     pktlen = NGTCP2_MAX_PKTLEN_IPV4;
1778     break;
1779 #ifdef ENABLE_IPV6
1780   case AF_INET6:
1781     pktlen = NGTCP2_MAX_PKTLEN_IPV6;
1782     break;
1783 #endif
1784   default:
1785     assert(0);
1786   }
1787 
1788   rv = ngtcp2_conn_handle_expiry(qs->qconn, ts);
1789   if(rv) {
1790     failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
1791           ngtcp2_strerror(rv));
1792     return CURLE_SEND_ERROR;
1793   }
1794 
1795   ngtcp2_path_storage_zero(&ps);
1796 
1797   for(;;) {
1798     veccnt = 0;
1799     stream_id = -1;
1800     fin = 0;
1801 
1802     if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) {
1803       veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec,
1804                                           sizeof(vec) / sizeof(vec[0]));
1805       if(veccnt < 0) {
1806         failf(data, "nghttp3_conn_writev_stream returned error: %s",
1807               nghttp3_strerror((int)veccnt));
1808         return CURLE_SEND_ERROR;
1809       }
1810     }
1811 
1812     flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
1813             (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
1814     outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out, pktlen,
1815                                        &ndatalen, flags, stream_id,
1816                                        (const ngtcp2_vec *)vec, veccnt, ts);
1817     if(outlen == 0) {
1818       break;
1819     }
1820     if(outlen < 0) {
1821       if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED ||
1822          outlen == NGTCP2_ERR_STREAM_SHUT_WR) {
1823         assert(ndatalen == -1);
1824         rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
1825         if(rv) {
1826           failf(data, "nghttp3_conn_block_stream returned error: %s\n",
1827                 nghttp3_strerror(rv));
1828           return CURLE_SEND_ERROR;
1829         }
1830         continue;
1831       }
1832       else if(outlen == NGTCP2_ERR_WRITE_MORE) {
1833         assert(ndatalen >= 0);
1834         rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
1835         if(rv) {
1836           failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
1837                 nghttp3_strerror(rv));
1838           return CURLE_SEND_ERROR;
1839         }
1840         continue;
1841       }
1842       else {
1843         assert(ndatalen == -1);
1844         failf(data, "ngtcp2_conn_writev_stream returned error: %s",
1845               ngtcp2_strerror((int)outlen));
1846         return CURLE_SEND_ERROR;
1847       }
1848     }
1849     else if(ndatalen >= 0) {
1850       rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
1851       if(rv) {
1852         failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
1853               nghttp3_strerror(rv));
1854         return CURLE_SEND_ERROR;
1855       }
1856     }
1857 
1858     memcpy(&remote_addr, ps.path.remote.addr, ps.path.remote.addrlen);
1859     while((sent = send(sockfd, (const char *)out, outlen, 0)) == -1 &&
1860           SOCKERRNO == EINTR)
1861       ;
1862 
1863     if(sent == -1) {
1864       if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
1865         /* TODO Cache packet */
1866         break;
1867       }
1868       else {
1869         failf(data, "send() returned %zd (errno %d)", sent,
1870               SOCKERRNO);
1871         return CURLE_SEND_ERROR;
1872       }
1873     }
1874   }
1875 
1876   expiry = ngtcp2_conn_get_expiry(qs->qconn);
1877   if(expiry != UINT64_MAX) {
1878     if(expiry <= ts) {
1879       timeout = NGTCP2_MILLISECONDS;
1880     }
1881     else {
1882       timeout = expiry - ts;
1883     }
1884     Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
1885   }
1886 
1887   return CURLE_OK;
1888 }
1889 
1890 /*
1891  * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
1892  */
Curl_quic_done_sending(struct Curl_easy * data)1893 CURLcode Curl_quic_done_sending(struct Curl_easy *data)
1894 {
1895   struct connectdata *conn = data->conn;
1896   DEBUGASSERT(conn);
1897   if(conn->handler == &Curl_handler_http3) {
1898     /* only for HTTP/3 transfers */
1899     struct HTTP *stream = data->req.p.http;
1900     struct quicsocket *qs = conn->quic;
1901     stream->upload_done = TRUE;
1902     (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
1903   }
1904 
1905   return CURLE_OK;
1906 }
1907 
1908 /*
1909  * Called from http.c:Curl_http_done when a request completes.
1910  */
Curl_quic_done(struct Curl_easy * data,bool premature)1911 void Curl_quic_done(struct Curl_easy *data, bool premature)
1912 {
1913   (void)premature;
1914   if(data->conn->handler == &Curl_handler_http3) {
1915     /* only for HTTP/3 transfers */
1916     struct HTTP *stream = data->req.p.http;
1917     Curl_dyn_free(&stream->overflow);
1918   }
1919 }
1920 
1921 /*
1922  * Called from transfer.c:data_pending to know if we should keep looping
1923  * to receive more data from the connection.
1924  */
Curl_quic_data_pending(const struct Curl_easy * data)1925 bool Curl_quic_data_pending(const struct Curl_easy *data)
1926 {
1927   /* We may have received more data than we're able to hold in the receive
1928      buffer and allocated an overflow buffer. Since it's possible that
1929      there's no more data coming on the socket, we need to keep reading
1930      until the overflow buffer is empty. */
1931   const struct HTTP *stream = data->req.p.http;
1932   return Curl_dyn_len(&stream->overflow) > 0;
1933 }
1934 
1935 #endif
1936