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