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