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