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