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