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