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 ¶ms, 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, ¶ms) != 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, ¶ms);
402 nwrite = ngtcp2_encode_transport_params(
403 paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
404 ¶ms);
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