1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * SPDX-License-Identifier: curl
23 ***************************************************************************/
25 #include "curl_setup.h"
28 #include <ngtcp2/ngtcp2.h>
29 #include <nghttp3/nghttp3.h>
31 #include <openssl/err.h>
32 #ifdef OPENSSL_IS_BORINGSSL
33 #include <ngtcp2/ngtcp2_crypto_boringssl.h>
35 #include <ngtcp2/ngtcp2_crypto_openssl.h>
37 #include "vtls/openssl.h"
38 #elif defined(USE_GNUTLS)
39 #include <ngtcp2/ngtcp2_crypto_gnutls.h>
40 #include "vtls/gtls.h"
41 #elif defined(USE_WOLFSSL)
42 #include <ngtcp2/ngtcp2_crypto_wolfssl.h>
43 #include "vtls/wolfssl.h"
57 #include "vtls/keylog.h"
58 #include "vtls/vtls.h"
60 /* The last 3 #include files should be in this order */
61 #include "curl_printf.h"
62 #include "curl_memory.h"
65 /* #define DEBUG_NGTCP2 */
72 #define H3BUGF(x) do { } while(0)
75 #define H3_ALPN_H3_29 "\x5h3-29"
76 #define H3_ALPN_H3 "\x2h3"
79 * This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked.
80 * It is used as a circular buffer. Add new bytes at the end until it reaches
81 * the far end, then start over at index 0 again.
84 #define H3_SEND_SIZE (256*1024)
86 uint8_t buf[H3_SEND_SIZE];
87 size_t used; /* number of bytes used in the buffer */
88 size_t windex; /* index in the buffer where to start writing the next
92 #define QUIC_MAX_STREAMS (256*1024)
93 #define QUIC_MAX_DATA (1*1024*1024)
94 #define QUIC_IDLE_TIMEOUT (60*NGTCP2_SECONDS)
97 #define QUIC_CIPHERS \
98 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
99 "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
100 #define QUIC_GROUPS "P-256:X25519:P-384:P-521"
101 #elif defined(USE_GNUTLS)
102 #define QUIC_PRIORITY \
103 "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
104 "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
105 "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
106 "%DISABLE_TLS13_COMPAT_MODE"
107 #elif defined(USE_WOLFSSL)
108 #define QUIC_CIPHERS \
109 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
110 "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
111 #define QUIC_GROUPS "P-256:P-384:P-521"
114 /* ngtcp2 default congestion controller does not perform pacing. Limit
115 the maximum packet burst to MAX_PKT_BURST packets. */
116 #define MAX_PKT_BURST 10
118 static CURLcode ng_process_ingress(struct Curl_easy *data,
119 curl_socket_t sockfd,
120 struct quicsocket *qs);
121 static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd,
122 struct quicsocket *qs);
123 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
124 uint64_t datalen, void *user_data,
125 void *stream_user_data);
127 static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
129 struct quicsocket *qs = conn_ref->user_data;
133 static ngtcp2_tstamp timestamp(void)
135 struct curltime ct = Curl_now();
136 return ct.tv_sec * NGTCP2_SECONDS + ct.tv_usec * NGTCP2_MICROSECONDS;
140 static void quic_printf(void *user_data, const char *fmt, ...)
143 (void)user_data; /* TODO, use this to do infof() instead long-term */
145 vfprintf(stderr, fmt, ap);
147 fprintf(stderr, "\n");
151 static void qlog_callback(void *user_data, uint32_t flags,
152 const void *data, size_t datalen)
154 struct quicsocket *qs = (struct quicsocket *)user_data;
156 if(qs->qlogfd != -1) {
157 ssize_t rc = write(qs->qlogfd, data, datalen);
159 /* on write error, stop further write attempts */
167 static void quic_settings(struct quicsocket *qs,
168 uint64_t stream_buffer_size)
170 ngtcp2_settings *s = &qs->settings;
171 ngtcp2_transport_params *t = &qs->transport_params;
172 ngtcp2_settings_default(s);
173 ngtcp2_transport_params_default(t);
175 s->log_printf = quic_printf;
177 s->log_printf = NULL;
179 s->initial_ts = timestamp();
180 t->initial_max_stream_data_bidi_local = stream_buffer_size;
181 t->initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS;
182 t->initial_max_stream_data_uni = QUIC_MAX_STREAMS;
183 t->initial_max_data = QUIC_MAX_DATA;
184 t->initial_max_streams_bidi = 1;
185 t->initial_max_streams_uni = 3;
186 t->max_idle_timeout = QUIC_IDLE_TIMEOUT;
187 if(qs->qlogfd != -1) {
188 s->qlog.write = qlog_callback;
193 static void keylog_callback(const SSL *ssl, const char *line)
196 Curl_tls_keylog_write_line(line);
198 #elif defined(USE_GNUTLS)
199 static int keylog_callback(gnutls_session_t session, const char *label,
200 const gnutls_datum_t *secret)
202 gnutls_datum_t crandom;
203 gnutls_datum_t srandom;
205 gnutls_session_get_random(session, &crandom, &srandom);
206 if(crandom.size != 32) {
210 Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
213 #elif defined(USE_WOLFSSL)
214 #if defined(HAVE_SECRET_CALLBACK)
215 static void keylog_callback(const WOLFSSL *ssl, const char *line)
218 Curl_tls_keylog_write_line(line);
223 static int init_ngh3_conn(struct quicsocket *qs);
226 static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
228 struct connectdata *conn = data->conn;
229 SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
231 #ifdef OPENSSL_IS_BORINGSSL
232 if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) {
233 failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
237 if(ngtcp2_crypto_openssl_configure_client_context(ssl_ctx) != 0) {
238 failf(data, "ngtcp2_crypto_openssl_configure_client_context failed");
243 SSL_CTX_set_default_verify_paths(ssl_ctx);
245 #ifdef OPENSSL_IS_BORINGSSL
246 if(SSL_CTX_set1_curves_list(ssl_ctx, QUIC_GROUPS) != 1) {
247 failf(data, "SSL_CTX_set1_curves_list failed");
251 if(SSL_CTX_set_ciphersuites(ssl_ctx, QUIC_CIPHERS) != 1) {
252 char error_buffer[256];
253 ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
254 failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer);
258 if(SSL_CTX_set1_groups_list(ssl_ctx, QUIC_GROUPS) != 1) {
259 failf(data, "SSL_CTX_set1_groups_list failed");
264 /* Open the file if a TLS or QUIC backend has not done this before. */
265 Curl_tls_keylog_open();
266 if(Curl_tls_keylog_enabled()) {
267 SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
270 if(conn->ssl_config.verifypeer) {
271 const char * const ssl_cafile = conn->ssl_config.CAfile;
272 const char * const ssl_capath = conn->ssl_config.CApath;
274 if(ssl_cafile || ssl_capath) {
275 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
276 /* tell OpenSSL where to find CA certificates that are used to verify
277 the server's certificate. */
278 if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) {
279 /* Fail if we insist on successfully verifying the server. */
280 failf(data, "error setting certificate verify locations:"
281 " CAfile: %s CApath: %s",
282 ssl_cafile ? ssl_cafile : "none",
283 ssl_capath ? ssl_capath : "none");
286 infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
287 infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
289 #ifdef CURL_CA_FALLBACK
291 /* verifying the peer without any CA certificates won't work so
292 use openssl's built-in default as fallback */
293 SSL_CTX_set_default_verify_paths(ssl_ctx);
300 static CURLcode quic_set_client_cert(struct Curl_easy *data,
301 struct quicsocket *qs)
303 struct connectdata *conn = data->conn;
304 SSL_CTX *ssl_ctx = qs->sslctx;
305 char *const ssl_cert = SSL_SET_OPTION(primary.clientcert);
306 const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
307 const char *const ssl_cert_type = SSL_SET_OPTION(cert_type);
309 if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
310 return Curl_ossl_set_client_cert(
311 data, ssl_ctx, ssl_cert, ssl_cert_blob, ssl_cert_type,
312 SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob),
313 SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd));
319 /** SSL callbacks ***/
321 static int quic_init_ssl(struct quicsocket *qs)
323 const uint8_t *alpn = NULL;
325 /* this will need some attention when HTTPS proxy over QUIC get fixed */
326 const char * const hostname = qs->conn->host.name;
328 DEBUGASSERT(!qs->ssl);
329 qs->ssl = SSL_new(qs->sslctx);
331 SSL_set_app_data(qs->ssl, &qs->conn_ref);
332 SSL_set_connect_state(qs->ssl);
333 SSL_set_quic_use_legacy_codepoint(qs->ssl, 0);
335 alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
336 alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
338 SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
341 SSL_set_tlsext_host_name(qs->ssl, hostname);
344 #elif defined(USE_GNUTLS)
345 static int quic_init_ssl(struct quicsocket *qs)
347 gnutls_datum_t alpn[2];
348 /* this will need some attention when HTTPS proxy over QUIC get fixed */
349 const char * const hostname = qs->conn->host.name;
352 DEBUGASSERT(!qs->ssl);
354 gnutls_init(&qs->ssl, GNUTLS_CLIENT);
355 gnutls_session_set_ptr(qs->ssl, &qs->conn_ref);
357 if(ngtcp2_crypto_gnutls_configure_client_session(qs->ssl) != 0) {
358 H3BUGF(fprintf(stderr,
359 "ngtcp2_crypto_gnutls_configure_client_session failed\n"));
363 rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
365 H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
366 gnutls_strerror(rc)));
370 /* Open the file if a TLS or QUIC backend has not done this before. */
371 Curl_tls_keylog_open();
372 if(Curl_tls_keylog_enabled()) {
373 gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
377 gnutls_certificate_free_credentials(qs->cred);
379 rc = gnutls_certificate_allocate_credentials(&qs->cred);
381 H3BUGF(fprintf(stderr,
382 "gnutls_certificate_allocate_credentials failed: %s\n",
383 gnutls_strerror(rc)));
387 rc = gnutls_certificate_set_x509_system_trust(qs->cred);
389 H3BUGF(fprintf(stderr,
390 "gnutls_certificate_set_x509_system_trust failed: %s\n",
391 gnutls_strerror(rc)));
395 rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
397 H3BUGF(fprintf(stderr, "gnutls_credentials_set failed: %s\n",
398 gnutls_strerror(rc)));
402 /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
403 alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1;
404 alpn[0].size = sizeof(H3_ALPN_H3_29) - 2;
405 alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1;
406 alpn[1].size = sizeof(H3_ALPN_H3) - 2;
408 gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY);
411 gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
414 #elif defined(USE_WOLFSSL)
416 static WOLFSSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
418 struct connectdata *conn = data->conn;
419 WOLFSSL_CTX *ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
421 if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) {
422 failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
426 wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
428 if(wolfSSL_CTX_set_cipher_list(ssl_ctx, QUIC_CIPHERS) != 1) {
429 char error_buffer[256];
430 ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
431 failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer);
435 if(wolfSSL_CTX_set1_groups_list(ssl_ctx, (char *)QUIC_GROUPS) != 1) {
436 failf(data, "SSL_CTX_set1_groups_list failed");
440 /* Open the file if a TLS or QUIC backend has not done this before. */
441 Curl_tls_keylog_open();
442 if(Curl_tls_keylog_enabled()) {
443 #if defined(HAVE_SECRET_CALLBACK)
444 wolfSSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
446 failf(data, "wolfSSL was built without keylog callback");
451 if(conn->ssl_config.verifypeer) {
452 const char * const ssl_cafile = conn->ssl_config.CAfile;
453 const char * const ssl_capath = conn->ssl_config.CApath;
455 if(ssl_cafile || ssl_capath) {
456 wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
457 /* tell wolfSSL where to find CA certificates that are used to verify
458 the server's certificate. */
459 if(!wolfSSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) {
460 /* Fail if we insist on successfully verifying the server. */
461 failf(data, "error setting certificate verify locations:"
462 " CAfile: %s CApath: %s",
463 ssl_cafile ? ssl_cafile : "none",
464 ssl_capath ? ssl_capath : "none");
467 infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
468 infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
470 #ifdef CURL_CA_FALLBACK
472 /* verifying the peer without any CA certificates won't work so
473 use wolfssl's built-in default as fallback */
474 wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
479 wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
485 /** SSL callbacks ***/
487 static int quic_init_ssl(struct quicsocket *qs)
489 const uint8_t *alpn = NULL;
491 /* this will need some attention when HTTPS proxy over QUIC get fixed */
492 const char * const hostname = qs->conn->host.name;
494 DEBUGASSERT(!qs->ssl);
495 qs->ssl = SSL_new(qs->sslctx);
497 wolfSSL_set_app_data(qs->ssl, &qs->conn_ref);
498 wolfSSL_set_connect_state(qs->ssl);
499 wolfSSL_set_quic_use_legacy_codepoint(qs->ssl, 0);
501 alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
502 alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
504 wolfSSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
507 wolfSSL_UseSNI(qs->ssl, WOLFSSL_SNI_HOST_NAME,
508 hostname, (unsigned short)strlen(hostname));
512 #endif /* defined(USE_WOLFSSL) */
514 static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
521 static void extend_stream_window(ngtcp2_conn *tconn,
524 size_t thismuch = stream->unacked_window;
525 ngtcp2_conn_extend_max_stream_offset(tconn, stream->stream3_id, thismuch);
526 ngtcp2_conn_extend_max_offset(tconn, thismuch);
527 stream->unacked_window = 0;
531 static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
532 int64_t stream_id, uint64_t offset,
533 const uint8_t *buf, size_t buflen,
534 void *user_data, void *stream_user_data)
536 struct quicsocket *qs = (struct quicsocket *)user_data;
537 nghttp3_ssize nconsumed;
538 int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
540 (void)stream_user_data;
543 nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin);
545 ngtcp2_connection_close_error_set_application_error(
546 &qs->last_error, nghttp3_err_infer_quic_app_error_code((int)nconsumed),
548 return NGTCP2_ERR_CALLBACK_FAILURE;
551 /* number of bytes inside buflen which consists of framing overhead
552 * including QPACK HEADERS. In other words, it does not consume payload of
554 ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
555 ngtcp2_conn_extend_max_offset(tconn, nconsumed);
561 cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
562 uint64_t offset, uint64_t datalen, void *user_data,
563 void *stream_user_data)
565 struct quicsocket *qs = (struct quicsocket *)user_data;
571 (void)stream_user_data;
573 rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
575 return NGTCP2_ERR_CALLBACK_FAILURE;
581 static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
582 int64_t stream_id, uint64_t app_error_code,
583 void *user_data, void *stream_user_data)
585 struct quicsocket *qs = (struct quicsocket *)user_data;
588 (void)stream_user_data;
589 /* stream is closed... */
591 if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
592 app_error_code = NGHTTP3_H3_NO_ERROR;
595 rv = nghttp3_conn_close_stream(qs->h3conn, stream_id,
598 ngtcp2_connection_close_error_set_application_error(
599 &qs->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0);
600 return NGTCP2_ERR_CALLBACK_FAILURE;
606 static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
607 uint64_t final_size, uint64_t app_error_code,
608 void *user_data, void *stream_user_data)
610 struct quicsocket *qs = (struct quicsocket *)user_data;
614 (void)app_error_code;
615 (void)stream_user_data;
617 rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id);
619 return NGTCP2_ERR_CALLBACK_FAILURE;
625 static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id,
626 uint64_t app_error_code, void *user_data,
627 void *stream_user_data)
629 struct quicsocket *qs = (struct quicsocket *)user_data;
632 (void)app_error_code;
633 (void)stream_user_data;
635 rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id);
637 return NGTCP2_ERR_CALLBACK_FAILURE;
643 static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
644 uint64_t max_streams,
654 static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
655 uint64_t max_data, void *user_data,
656 void *stream_user_data)
658 struct quicsocket *qs = (struct quicsocket *)user_data;
662 (void)stream_user_data;
664 rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
666 return NGTCP2_ERR_CALLBACK_FAILURE;
672 static void cb_rand(uint8_t *dest, size_t destlen,
673 const ngtcp2_rand_ctx *rand_ctx)
678 result = Curl_rand(NULL, dest, destlen);
680 /* cb_rand is only used for non-cryptographic context. If Curl_rand
681 failed, just fill 0 and call it *random*. */
682 memset(dest, 0, destlen);
686 static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
687 uint8_t *token, size_t cidlen,
694 result = Curl_rand(NULL, cid->data, cidlen);
696 return NGTCP2_ERR_CALLBACK_FAILURE;
697 cid->datalen = cidlen;
699 result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN);
701 return NGTCP2_ERR_CALLBACK_FAILURE;
706 static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_crypto_level level,
709 struct quicsocket *qs = (struct quicsocket *)user_data;
712 if(level != NGTCP2_CRYPTO_LEVEL_APPLICATION) {
716 if(init_ngh3_conn(qs) != CURLE_OK) {
717 return NGTCP2_ERR_CALLBACK_FAILURE;
723 static ngtcp2_callbacks ng_callbacks = {
724 ngtcp2_crypto_client_initial_cb,
725 NULL, /* recv_client_initial */
726 ngtcp2_crypto_recv_crypto_data_cb,
727 cb_handshake_completed,
728 NULL, /* recv_version_negotiation */
729 ngtcp2_crypto_encrypt_cb,
730 ngtcp2_crypto_decrypt_cb,
731 ngtcp2_crypto_hp_mask_cb,
733 cb_acked_stream_data_offset,
734 NULL, /* stream_open */
736 NULL, /* recv_stateless_reset */
737 ngtcp2_crypto_recv_retry_cb,
738 cb_extend_max_local_streams_bidi,
739 NULL, /* extend_max_local_streams_uni */
741 cb_get_new_connection_id,
742 NULL, /* remove_connection_id */
743 ngtcp2_crypto_update_key_cb, /* update_key */
744 NULL, /* path_validation */
745 NULL, /* select_preferred_addr */
747 NULL, /* extend_max_remote_streams_bidi */
748 NULL, /* extend_max_remote_streams_uni */
749 cb_extend_max_stream_data,
750 NULL, /* dcid_status */
751 NULL, /* handshake_confirmed */
752 NULL, /* recv_new_token */
753 ngtcp2_crypto_delete_crypto_aead_ctx_cb,
754 ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
755 NULL, /* recv_datagram */
756 NULL, /* ack_datagram */
757 NULL, /* lost_datagram */
758 ngtcp2_crypto_get_path_challenge_data_cb,
759 cb_stream_stop_sending,
760 NULL, /* version_negotiation */
762 NULL, /* recv_tx_key */
763 NULL, /* early_data_rejected */
767 * Might be called twice for happy eyeballs.
769 CURLcode Curl_quic_connect(struct Curl_easy *data,
770 struct connectdata *conn,
771 curl_socket_t sockfd,
773 const struct sockaddr *addr,
779 ngtcp2_path path; /* TODO: this must be initialized properly */
780 struct quicsocket *qs = &conn->hequic[sockindex];
786 Curl_quic_disconnect(data, conn, sockindex);
789 /* extract the used address as a string */
790 if(!Curl_addr2string((struct sockaddr*)addr, addrlen, ipbuf, &port)) {
791 char buffer[STRERROR_LEN];
792 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
793 SOCKERRNO, Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
794 return CURLE_BAD_FUNCTION_ARGUMENT;
797 infof(data, "Connect socket %d over QUIC to %s:%d",
798 sockfd, ipbuf, port);
800 qs->version = NGTCP2_PROTO_VER_MAX;
802 qs->sslctx = quic_ssl_ctx(data);
804 return CURLE_QUIC_CONNECT_ERROR;
806 result = quic_set_client_cert(data, qs);
809 #elif defined(USE_WOLFSSL)
810 qs->sslctx = quic_ssl_ctx(data);
812 return CURLE_QUIC_CONNECT_ERROR;
815 if(quic_init_ssl(qs))
816 return CURLE_QUIC_CONNECT_ERROR;
818 qs->dcid.datalen = NGTCP2_MAX_CIDLEN;
819 result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN);
823 qs->scid.datalen = NGTCP2_MAX_CIDLEN;
824 result = Curl_rand(data, qs->scid.data, NGTCP2_MAX_CIDLEN);
828 (void)Curl_qlogdir(data, qs->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
829 qs->qlogfd = qfd; /* -1 if failure above */
830 quic_settings(qs, data->set.buffer_size);
832 qs->local_addrlen = sizeof(qs->local_addr);
833 rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr,
836 return CURLE_QUIC_CONNECT_ERROR;
838 ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
840 ngtcp2_addr_init(&path.remote, addr, addrlen);
842 rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path,
843 NGTCP2_PROTO_VER_V1, &ng_callbacks,
844 &qs->settings, &qs->transport_params, NULL, qs);
846 return CURLE_QUIC_CONNECT_ERROR;
848 ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl);
850 ngtcp2_connection_close_error_default(&qs->last_error);
852 #if defined(__linux__) && defined(UDP_SEGMENT) && defined(HAVE_SENDMSG)
858 qs->num_blocked_pkt = 0;
859 qs->num_blocked_pkt_sent = 0;
860 memset(&qs->blocked_pkt, 0, sizeof(qs->blocked_pkt));
862 qs->pktbuflen = NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE * MAX_PKT_BURST;
863 qs->pktbuf = malloc(qs->pktbuflen);
865 ngtcp2_conn_del(qs->qconn);
867 return CURLE_OUT_OF_MEMORY;
870 qs->conn_ref.get_conn = get_conn;
871 qs->conn_ref.user_data = qs;
877 * Store ngtcp2 version info in this buffer.
879 void Curl_quic_ver(char *p, size_t len)
881 const ngtcp2_info *ng2 = ngtcp2_version(0);
882 const nghttp3_info *ht3 = nghttp3_version(0);
883 (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
884 ng2->version_str, ht3->version_str);
887 static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
888 curl_socket_t *socks)
890 struct SingleRequest *k = &data->req;
891 int bitmap = GETSOCK_BLANK;
892 struct HTTP *stream = data->req.p.http;
893 struct quicsocket *qs = conn->quic;
895 socks[0] = conn->sock[FIRSTSOCKET];
897 /* in a HTTP/2 connection we can basically always get a frame so we should
898 always be ready for one */
899 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
901 /* we're still uploading or the HTTP/2 layer wants to send data */
902 if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND &&
903 (!stream->h3out || stream->h3out->used < H3_SEND_SIZE) &&
904 ngtcp2_conn_get_cwnd_left(qs->qconn) &&
905 ngtcp2_conn_get_max_data_left(qs->qconn) &&
906 nghttp3_conn_is_stream_writable(qs->h3conn, stream->stream3_id))
907 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
912 static void qs_disconnect(struct quicsocket *qs)
914 char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
918 if(!qs->conn) /* already closed */
921 rc = ngtcp2_conn_write_connection_close(qs->qconn, NULL, /* path */
923 (uint8_t *)buffer, sizeof(buffer),
924 &qs->last_error, ts);
926 while((send(qs->conn->sock[FIRSTSOCKET], buffer, rc, 0) == -1) &&
931 if(qs->qlogfd != -1) {
938 #elif defined(USE_GNUTLS)
939 gnutls_deinit(qs->ssl);
940 #elif defined(USE_WOLFSSL)
941 wolfSSL_free(qs->ssl);
946 gnutls_certificate_free_credentials(qs->cred);
951 nghttp3_conn_del(qs->h3conn);
952 ngtcp2_conn_del(qs->qconn);
954 SSL_CTX_free(qs->sslctx);
955 #elif defined(USE_WOLFSSL)
956 wolfSSL_CTX_free(qs->sslctx);
960 void Curl_quic_disconnect(struct Curl_easy *data,
961 struct connectdata *conn,
965 if(conn->transport == TRNSPRT_QUIC)
966 qs_disconnect(&conn->hequic[tempindex]);
969 static CURLcode ng_disconnect(struct Curl_easy *data,
970 struct connectdata *conn,
971 bool dead_connection)
973 (void)dead_connection;
974 Curl_quic_disconnect(data, conn, 0);
975 Curl_quic_disconnect(data, conn, 1);
979 static unsigned int ng_conncheck(struct Curl_easy *data,
980 struct connectdata *conn,
981 unsigned int checks_to_perform)
985 (void)checks_to_perform;
986 return CONNRESULT_NONE;
989 static const struct Curl_handler Curl_handler_http3 = {
990 "HTTPS", /* scheme */
991 ZERO_NULL, /* setup_connection */
992 Curl_http, /* do_it */
993 Curl_http_done, /* done */
994 ZERO_NULL, /* do_more */
995 ZERO_NULL, /* connect_it */
996 ZERO_NULL, /* connecting */
997 ZERO_NULL, /* doing */
998 ng_getsock, /* proto_getsock */
999 ng_getsock, /* doing_getsock */
1000 ZERO_NULL, /* domore_getsock */
1001 ng_getsock, /* perform_getsock */
1002 ng_disconnect, /* disconnect */
1003 ZERO_NULL, /* readwrite */
1004 ng_conncheck, /* connection_check */
1005 ZERO_NULL, /* attach connection */
1006 PORT_HTTP, /* defport */
1007 CURLPROTO_HTTPS, /* protocol */
1008 CURLPROTO_HTTP, /* family */
1009 PROTOPT_SSL | PROTOPT_STREAM /* flags */
1012 static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
1013 uint64_t app_error_code, void *user_data,
1014 void *stream_user_data)
1016 struct Curl_easy *data = stream_user_data;
1017 struct HTTP *stream = data->req.p.http;
1020 (void)app_error_code;
1022 H3BUGF(infof(data, "cb_h3_stream_close CALLED"));
1024 stream->closed = TRUE;
1025 stream->error3 = app_error_code;
1026 Curl_expire(data, 0, EXPIRE_QUIC);
1027 /* make sure that ngh3_stream_recv is called again to complete the transfer
1028 even if there are no more packets to be received from the server. */
1029 data->state.drain = 1;
1034 * write_data() copies data to the stream's receive buffer. If not enough
1035 * space is available in the receive buffer, it copies the rest to the
1036 * stream's overflow buffer.
1038 static CURLcode write_data(struct HTTP *stream, const void *mem, size_t memlen)
1040 CURLcode result = CURLE_OK;
1041 const char *buf = mem;
1042 size_t ncopy = memlen;
1043 /* copy as much as possible to the receive buffer */
1045 size_t len = CURLMIN(ncopy, stream->len);
1046 memcpy(stream->mem, buf, len);
1048 stream->memlen += len;
1053 /* copy the rest to the overflow buffer */
1055 result = Curl_dyn_addn(&stream->overflow, buf, ncopy);
1059 static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
1060 const uint8_t *buf, size_t buflen,
1061 void *user_data, void *stream_user_data)
1063 struct Curl_easy *data = stream_user_data;
1064 struct HTTP *stream = data->req.p.http;
1065 CURLcode result = CURLE_OK;
1068 result = write_data(stream, buf, buflen);
1072 stream->unacked_window += buflen;
1078 static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
1079 size_t consumed, void *user_data,
1080 void *stream_user_data)
1082 struct quicsocket *qs = user_data;
1084 (void)stream_user_data;
1087 ngtcp2_conn_extend_max_stream_offset(qs->qconn, stream_id, consumed);
1088 ngtcp2_conn_extend_max_offset(qs->qconn, consumed);
1092 /* Decode HTTP status code. Returns -1 if no valid status code was
1093 decoded. (duplicate from http2.c) */
1094 static int decode_status_code(const uint8_t *value, size_t len)
1105 for(i = 0; i < 3; ++i) {
1108 if(c < '0' || c > '9') {
1119 static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
1120 int fin, void *user_data, void *stream_user_data)
1122 struct Curl_easy *data = stream_user_data;
1123 struct HTTP *stream = data->req.p.http;
1124 CURLcode result = CURLE_OK;
1130 /* add a CRLF only if we've received some headers */
1131 if(stream->firstheader) {
1132 result = write_data(stream, "\r\n", 2);
1138 if(stream->status_code / 100 != 1) {
1139 stream->bodystarted = TRUE;
1144 static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
1145 int32_t token, nghttp3_rcbuf *name,
1146 nghttp3_rcbuf *value, uint8_t flags,
1147 void *user_data, void *stream_user_data)
1149 nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
1150 nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
1151 struct Curl_easy *data = stream_user_data;
1152 struct HTTP *stream = data->req.p.http;
1153 CURLcode result = CURLE_OK;
1160 if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
1161 char line[14]; /* status line is always 13 characters long */
1163 stream->status_code = decode_status_code(h3val.base, h3val.len);
1164 DEBUGASSERT(stream->status_code != -1);
1165 ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
1166 stream->status_code);
1167 result = write_data(stream, line, ncopy);
1173 /* store as a HTTP1-style header */
1174 result = write_data(stream, h3name.base, h3name.len);
1178 result = write_data(stream, ": ", 2);
1182 result = write_data(stream, h3val.base, h3val.len);
1186 result = write_data(stream, "\r\n", 2);
1192 stream->firstheader = TRUE;
1196 static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
1197 uint64_t app_error_code, void *user_data,
1198 void *stream_user_data)
1200 struct quicsocket *qs = user_data;
1203 (void)stream_user_data;
1205 rv = ngtcp2_conn_shutdown_stream_read(qs->qconn, stream_id, app_error_code);
1206 if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
1207 return NGTCP2_ERR_CALLBACK_FAILURE;
1213 static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
1214 uint64_t app_error_code, void *user_data,
1215 void *stream_user_data) {
1216 struct quicsocket *qs = user_data;
1219 (void)stream_user_data;
1221 rv = ngtcp2_conn_shutdown_stream_write(qs->qconn, stream_id, app_error_code);
1222 if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
1223 return NGTCP2_ERR_CALLBACK_FAILURE;
1229 static nghttp3_callbacks ngh3_callbacks = {
1230 cb_h3_acked_stream_data, /* acked_stream_data */
1233 cb_h3_deferred_consume,
1234 NULL, /* begin_headers */
1237 NULL, /* begin_trailers */
1239 NULL, /* end_trailers */
1241 NULL, /* end_stream */
1246 static int init_ngh3_conn(struct quicsocket *qs)
1250 int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;
1252 if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) {
1253 return CURLE_QUIC_CONNECT_ERROR;
1256 nghttp3_settings_default(&qs->h3settings);
1258 rc = nghttp3_conn_client_new(&qs->h3conn,
1261 nghttp3_mem_default(),
1264 result = CURLE_OUT_OF_MEMORY;
1268 rc = ngtcp2_conn_open_uni_stream(qs->qconn, &ctrl_stream_id, NULL);
1270 result = CURLE_QUIC_CONNECT_ERROR;
1274 rc = nghttp3_conn_bind_control_stream(qs->h3conn, ctrl_stream_id);
1276 result = CURLE_QUIC_CONNECT_ERROR;
1280 rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_enc_stream_id, NULL);
1282 result = CURLE_QUIC_CONNECT_ERROR;
1286 rc = ngtcp2_conn_open_uni_stream(qs->qconn, &qpack_dec_stream_id, NULL);
1288 result = CURLE_QUIC_CONNECT_ERROR;
1292 rc = nghttp3_conn_bind_qpack_streams(qs->h3conn, qpack_enc_stream_id,
1293 qpack_dec_stream_id);
1295 result = CURLE_QUIC_CONNECT_ERROR;
1305 static Curl_recv ngh3_stream_recv;
1306 static Curl_send ngh3_stream_send;
1308 static size_t drain_overflow_buffer(struct HTTP *stream)
1310 size_t overlen = Curl_dyn_len(&stream->overflow);
1311 size_t ncopy = CURLMIN(overlen, stream->len);
1313 memcpy(stream->mem, Curl_dyn_ptr(&stream->overflow), ncopy);
1314 stream->len -= ncopy;
1315 stream->mem += ncopy;
1316 stream->memlen += ncopy;
1317 if(ncopy != overlen)
1318 /* make the buffer only keep the tail */
1319 (void)Curl_dyn_tail(&stream->overflow, overlen - ncopy);
1321 Curl_dyn_reset(&stream->overflow);
1326 /* incoming data frames on the h3 stream */
1327 static ssize_t ngh3_stream_recv(struct Curl_easy *data,
1333 struct connectdata *conn = data->conn;
1334 curl_socket_t sockfd = conn->sock[sockindex];
1335 struct HTTP *stream = data->req.p.http;
1336 struct quicsocket *qs = conn->quic;
1338 if(!stream->memlen) {
1339 /* remember where to store incoming data for this stream and how big the
1342 stream->len = buffersize;
1344 /* else, there's data in the buffer already */
1346 /* if there's data in the overflow buffer from a previous call, copy as much
1347 as possible to the receive buffer before receiving more */
1348 drain_overflow_buffer(stream);
1350 if(ng_process_ingress(data, sockfd, qs)) {
1351 *curlcode = CURLE_RECV_ERROR;
1354 if(ng_flush_egress(data, sockfd, qs)) {
1355 *curlcode = CURLE_SEND_ERROR;
1359 if(stream->memlen) {
1360 ssize_t memlen = stream->memlen;
1362 *curlcode = CURLE_OK;
1363 /* reset to allow more data to come */
1366 stream->len = buffersize;
1367 /* extend the stream window with the data we're consuming and send out
1368 any additional packets to tell the server that we can receive more */
1369 extend_stream_window(qs->qconn, stream);
1370 if(ng_flush_egress(data, sockfd, qs)) {
1371 *curlcode = CURLE_SEND_ERROR;
1377 if(stream->closed) {
1378 if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
1380 "HTTP/3 stream %" PRId64 " was not closed cleanly: (err %" PRIu64
1382 stream->stream3_id, stream->error3);
1383 *curlcode = CURLE_HTTP3;
1387 if(!stream->bodystarted) {
1389 "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
1390 " all response header fields, treated as error",
1391 stream->stream3_id);
1392 *curlcode = CURLE_HTTP3;
1396 *curlcode = CURLE_OK;
1400 infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN");
1401 *curlcode = CURLE_AGAIN;
1405 /* this amount of data has now been acked on this stream */
1406 static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
1407 uint64_t datalen, void *user_data,
1408 void *stream_user_data)
1410 struct Curl_easy *data = stream_user_data;
1411 struct HTTP *stream = data->req.p.http;
1414 if(!data->set.postfields) {
1415 stream->h3out->used -= datalen;
1417 "cb_h3_acked_stream_data, %zd bytes, %zd left unacked",
1418 datalen, stream->h3out->used));
1419 DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
1421 if(stream->h3out->used == 0) {
1422 int rv = nghttp3_conn_resume_stream(conn, stream_id);
1424 return NGTCP2_ERR_CALLBACK_FAILURE;
1431 static nghttp3_ssize cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
1432 nghttp3_vec *vec, size_t veccnt,
1433 uint32_t *pflags, void *user_data,
1434 void *stream_user_data)
1436 struct Curl_easy *data = stream_user_data;
1438 struct HTTP *stream = data->req.p.http;
1444 if(data->set.postfields) {
1445 vec[0].base = data->set.postfields;
1446 vec[0].len = data->state.infilesize;
1447 *pflags = NGHTTP3_DATA_FLAG_EOF;
1451 if(stream->upload_len && H3_SEND_SIZE <= stream->h3out->used) {
1452 return NGHTTP3_ERR_WOULDBLOCK;
1455 nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used);
1457 /* nghttp3 wants us to hold on to the data until it tells us it is okay to
1458 delete it. Append the data at the end of the h3out buffer. Since we can
1459 only return consecutive data, copy the amount that fits and the next
1460 part comes in next invoke. */
1461 struct h3out *out = stream->h3out;
1462 if(nread + out->windex > H3_SEND_SIZE)
1463 nread = H3_SEND_SIZE - out->windex;
1465 memcpy(&out->buf[out->windex], stream->upload_mem, nread);
1467 /* that's the chunk we return to nghttp3 */
1468 vec[0].base = &out->buf[out->windex];
1471 out->windex += nread;
1474 if(out->windex == H3_SEND_SIZE)
1475 out->windex = 0; /* wrap */
1476 stream->upload_mem += nread;
1477 stream->upload_len -= nread;
1478 if(data->state.infilesize != -1) {
1479 stream->upload_left -= nread;
1480 if(!stream->upload_left)
1481 *pflags = NGHTTP3_DATA_FLAG_EOF;
1483 H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)",
1484 nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
1487 if(stream->upload_done && !stream->upload_len &&
1488 (stream->upload_left <= 0)) {
1489 H3BUGF(infof(data, "cb_h3_readfunction sets EOF"));
1490 *pflags = NGHTTP3_DATA_FLAG_EOF;
1491 return nread ? 1 : 0;
1494 return NGHTTP3_ERR_WOULDBLOCK;
1499 /* Index where :authority header field will appear in request header
1501 #define AUTHORITY_DST_IDX 3
1503 static CURLcode http_request(struct Curl_easy *data, const void *mem,
1506 struct connectdata *conn = data->conn;
1507 struct HTTP *stream = data->req.p.http;
1509 struct quicsocket *qs = conn->quic;
1510 CURLcode result = CURLE_OK;
1511 nghttp3_nv *nva = NULL;
1514 struct h3out *h3out = NULL;
1515 struct h2h3req *hreq = NULL;
1517 rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL);
1519 failf(data, "can get bidi streams");
1520 result = CURLE_SEND_ERROR;
1524 stream->stream3_id = stream3_id;
1525 stream->h3req = TRUE; /* senf off! */
1526 Curl_dyn_init(&stream->overflow, CURL_MAX_READ_SIZE);
1528 result = Curl_pseudo_headers(data, mem, len, &hreq);
1531 nheader = hreq->entries;
1533 nva = malloc(sizeof(nghttp3_nv) * nheader);
1535 result = CURLE_OUT_OF_MEMORY;
1540 for(i = 0; i < nheader; i++) {
1541 nva[i].name = (unsigned char *)hreq->header[i].name;
1542 nva[i].namelen = hreq->header[i].namelen;
1543 nva[i].value = (unsigned char *)hreq->header[i].value;
1544 nva[i].valuelen = hreq->header[i].valuelen;
1545 nva[i].flags = NGHTTP3_NV_FLAG_NONE;
1549 switch(data->state.httpreq) {
1551 case HTTPREQ_POST_FORM:
1552 case HTTPREQ_POST_MIME:
1554 nghttp3_data_reader data_reader;
1555 if(data->state.infilesize != -1)
1556 stream->upload_left = data->state.infilesize;
1558 /* data sending without specifying the data amount up front */
1559 stream->upload_left = -1; /* unknown, but not zero */
1561 data_reader.read_data = cb_h3_readfunction;
1563 h3out = calloc(sizeof(struct h3out), 1);
1565 result = CURLE_OUT_OF_MEMORY;
1568 stream->h3out = h3out;
1570 rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1571 nva, nheader, &data_reader, data);
1573 result = CURLE_SEND_ERROR;
1579 stream->upload_left = 0; /* nothing left to send */
1580 rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id,
1581 nva, nheader, NULL, data);
1583 result = CURLE_SEND_ERROR;
1591 infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)",
1592 stream3_id, (void *)data);
1594 Curl_pseudo_free(hreq);
1599 Curl_pseudo_free(hreq);
1602 static ssize_t ngh3_stream_send(struct Curl_easy *data,
1609 struct connectdata *conn = data->conn;
1610 struct quicsocket *qs = conn->quic;
1611 curl_socket_t sockfd = conn->sock[sockindex];
1612 struct HTTP *stream = data->req.p.http;
1614 if(stream->closed) {
1615 *curlcode = CURLE_HTTP3;
1619 if(!stream->h3req) {
1620 CURLcode result = http_request(data, mem, len);
1622 *curlcode = CURLE_SEND_ERROR;
1625 /* Assume that mem of length len only includes HTTP/1.1 style
1626 header fields. In other words, it does not contain request
1631 H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes",
1633 if(!stream->upload_len) {
1634 stream->upload_mem = mem;
1635 stream->upload_len = len;
1636 (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
1639 *curlcode = CURLE_AGAIN;
1644 if(ng_flush_egress(data, sockfd, qs)) {
1645 *curlcode = CURLE_SEND_ERROR;
1649 /* Reset post upload buffer after resumed. */
1650 if(stream->upload_mem) {
1651 if(data->set.postfields) {
1655 sent = len - stream->upload_len;
1658 stream->upload_mem = NULL;
1659 stream->upload_len = 0;
1662 *curlcode = CURLE_AGAIN;
1667 *curlcode = CURLE_OK;
1671 static CURLcode ng_has_connected(struct Curl_easy *data,
1672 struct connectdata *conn, int tempindex)
1674 CURLcode result = CURLE_OK;
1675 conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
1676 conn->send[FIRSTSOCKET] = ngh3_stream_send;
1677 conn->handler = &Curl_handler_http3;
1678 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1679 conn->httpversion = 30;
1680 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
1681 conn->quic = &conn->hequic[tempindex];
1683 if(conn->ssl_config.verifyhost) {
1686 server_cert = SSL_get_peer_certificate(conn->quic->ssl);
1688 return CURLE_PEER_FAILED_VERIFICATION;
1690 result = Curl_ossl_verifyhost(data, conn, server_cert);
1691 X509_free(server_cert);
1694 infof(data, "Verified certificate just fine");
1695 #elif defined(USE_GNUTLS)
1696 result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET);
1697 #elif defined(USE_WOLFSSL)
1698 char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
1700 (wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE))
1701 return CURLE_PEER_FAILED_VERIFICATION;
1702 infof(data, "Verified certificate just fine");
1706 infof(data, "Skipped certificate verification");
1708 if(data->set.ssl.certinfo)
1709 /* asked to gather certificate info */
1710 (void)Curl_ossl_certchain(data, conn->quic->ssl);
1716 * There can be multiple connection attempts going on in parallel.
1718 CURLcode Curl_quic_is_connected(struct Curl_easy *data,
1719 struct connectdata *conn,
1724 struct quicsocket *qs = &conn->hequic[sockindex];
1725 curl_socket_t sockfd = conn->tempsock[sockindex];
1727 result = ng_process_ingress(data, sockfd, qs);
1731 result = ng_flush_egress(data, sockfd, qs);
1735 if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
1736 result = ng_has_connected(data, conn, sockindex);
1743 (void)qs_disconnect(qs);
1748 static CURLcode ng_process_ingress(struct Curl_easy *data,
1749 curl_socket_t sockfd,
1750 struct quicsocket *qs)
1755 size_t bufsize = sizeof(buf);
1756 struct sockaddr_storage remote_addr;
1757 socklen_t remote_addrlen;
1759 ngtcp2_tstamp ts = timestamp();
1760 ngtcp2_pkt_info pi = { 0 };
1763 remote_addrlen = sizeof(remote_addr);
1764 while((recvd = recvfrom(sockfd, (char *)buf, bufsize, 0,
1765 (struct sockaddr *)&remote_addr,
1766 &remote_addrlen)) == -1 &&
1770 if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK)
1773 failf(data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd);
1774 return CURLE_RECV_ERROR;
1777 ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
1779 ngtcp2_addr_init(&path.remote, (struct sockaddr *)&remote_addr,
1782 rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
1784 if(!qs->last_error.error_code) {
1785 if(rv == NGTCP2_ERR_CRYPTO) {
1786 ngtcp2_connection_close_error_set_transport_error_tls_alert(
1787 &qs->last_error, ngtcp2_conn_get_tls_alert(qs->qconn), NULL, 0);
1790 ngtcp2_connection_close_error_set_transport_error_liberr(
1791 &qs->last_error, rv, NULL, 0);
1795 if(rv == NGTCP2_ERR_CRYPTO)
1796 /* this is a "TLS problem", but a failed certificate verification
1797 is a common reason for this */
1798 return CURLE_PEER_FAILED_VERIFICATION;
1799 return CURLE_RECV_ERROR;
1806 static CURLcode do_sendmsg(size_t *sent, struct Curl_easy *data, int sockfd,
1807 struct quicsocket *qs, const uint8_t *pkt,
1808 size_t pktlen, size_t gsolen);
1810 static CURLcode send_packet_no_gso(size_t *psent, struct Curl_easy *data,
1811 int sockfd, struct quicsocket *qs,
1812 const uint8_t *pkt, size_t pktlen,
1815 const uint8_t *p, *end = pkt + pktlen;
1820 for(p = pkt; p < end; p += gsolen) {
1821 size_t len = CURLMIN(gsolen, (size_t)(end - p));
1822 CURLcode curlcode = do_sendmsg(&sent, data, sockfd, qs, p, len, len);
1823 if(curlcode != CURLE_OK) {
1832 static CURLcode do_sendmsg(size_t *psent, struct Curl_easy *data, int sockfd,
1833 struct quicsocket *qs, const uint8_t *pkt,
1834 size_t pktlen, size_t gsolen)
1837 struct iovec msg_iov;
1838 struct msghdr msg = {0};
1840 #if defined(__linux__) && defined(UDP_SEGMENT)
1841 uint8_t msg_ctrl[32];
1846 msg_iov.iov_base = (uint8_t *)pkt;
1847 msg_iov.iov_len = pktlen;
1848 msg.msg_iov = &msg_iov;
1851 #if defined(__linux__) && defined(UDP_SEGMENT)
1852 if(pktlen > gsolen) {
1853 /* Only set this, when we need it. macOS, for example,
1854 * does not seem to like a msg_control of length 0. */
1855 msg.msg_control = msg_ctrl;
1856 assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(uint16_t)));
1857 msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
1858 cm = CMSG_FIRSTHDR(&msg);
1859 cm->cmsg_level = SOL_UDP;
1860 cm->cmsg_type = UDP_SEGMENT;
1861 cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
1862 *(uint16_t *)(void *)CMSG_DATA(cm) = gsolen & 0xffff;
1867 while((sent = sendmsg(sockfd, &msg, 0)) == -1 && SOCKERRNO == EINTR)
1873 #if EAGAIN != EWOULDBLOCK
1878 /* UDP datagram is too large; caused by PMTUD. Just let it be lost. */
1881 if(pktlen > gsolen) {
1883 failf(data, "sendmsg() returned %zd (errno %d); disable GSO", sent,
1886 return send_packet_no_gso(psent, data, sockfd, qs, pkt, pktlen,
1891 failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO);
1892 return CURLE_SEND_ERROR;
1896 assert(pktlen == (size_t)sent);
1905 while((sent = send(sockfd, (const char *)pkt, pktlen, 0)) == -1 &&
1910 if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
1914 failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO);
1915 if(SOCKERRNO != EMSGSIZE) {
1916 return CURLE_SEND_ERROR;
1918 /* UDP datagram is too large; caused by PMTUD. Just let it be
1929 static CURLcode send_packet(size_t *psent, struct Curl_easy *data, int sockfd,
1930 struct quicsocket *qs, const uint8_t *pkt,
1931 size_t pktlen, size_t gsolen)
1933 if(qs->no_gso && pktlen > gsolen) {
1934 return send_packet_no_gso(psent, data, sockfd, qs, pkt, pktlen, gsolen);
1937 return do_sendmsg(psent, data, sockfd, qs, pkt, pktlen, gsolen);
1940 static void push_blocked_pkt(struct quicsocket *qs, const uint8_t *pkt,
1941 size_t pktlen, size_t gsolen)
1943 struct blocked_pkt *blkpkt;
1945 assert(qs->num_blocked_pkt <
1946 sizeof(qs->blocked_pkt) / sizeof(qs->blocked_pkt[0]));
1948 blkpkt = &qs->blocked_pkt[qs->num_blocked_pkt++];
1951 blkpkt->pktlen = pktlen;
1952 blkpkt->gsolen = gsolen;
1955 static CURLcode send_blocked_pkt(struct Curl_easy *data, int sockfd,
1956 struct quicsocket *qs)
1960 struct blocked_pkt *blkpkt;
1962 for(; qs->num_blocked_pkt_sent < qs->num_blocked_pkt;
1963 ++qs->num_blocked_pkt_sent) {
1964 blkpkt = &qs->blocked_pkt[qs->num_blocked_pkt_sent];
1965 curlcode = send_packet(&sent, data, sockfd, qs, blkpkt->pkt,
1966 blkpkt->pktlen, blkpkt->gsolen);
1969 if(curlcode == CURLE_AGAIN) {
1970 blkpkt->pkt += sent;
1971 blkpkt->pktlen -= sent;
1977 qs->num_blocked_pkt = 0;
1978 qs->num_blocked_pkt_sent = 0;
1983 static CURLcode ng_flush_egress(struct Curl_easy *data,
1985 struct quicsocket *qs)
1989 ngtcp2_ssize outlen;
1990 uint8_t *outpos = qs->pktbuf;
1991 size_t max_udp_payload_size =
1992 ngtcp2_conn_get_max_tx_udp_payload_size(qs->qconn);
1993 size_t path_max_udp_payload_size =
1994 ngtcp2_conn_get_path_max_tx_udp_payload_size(qs->qconn);
1996 CURLMIN(MAX_PKT_BURST, qs->pktbuflen / max_udp_payload_size);
1999 ngtcp2_path_storage ps;
2000 ngtcp2_tstamp ts = timestamp();
2001 ngtcp2_tstamp expiry;
2002 ngtcp2_duration timeout;
2004 nghttp3_ssize veccnt;
2006 nghttp3_vec vec[16];
2007 ngtcp2_ssize ndatalen;
2011 rv = ngtcp2_conn_handle_expiry(qs->qconn, ts);
2013 failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
2014 ngtcp2_strerror(rv));
2015 ngtcp2_connection_close_error_set_transport_error_liberr(&qs->last_error,
2017 return CURLE_SEND_ERROR;
2020 if(qs->num_blocked_pkt) {
2021 curlcode = send_blocked_pkt(data, sockfd, qs);
2023 if(curlcode == CURLE_AGAIN) {
2024 Curl_expire(data, 1, EXPIRE_QUIC);
2031 ngtcp2_path_storage_zero(&ps);
2038 if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) {
2039 veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec,
2040 sizeof(vec) / sizeof(vec[0]));
2042 failf(data, "nghttp3_conn_writev_stream returned error: %s",
2043 nghttp3_strerror((int)veccnt));
2044 ngtcp2_connection_close_error_set_application_error(
2046 nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0);
2047 return CURLE_SEND_ERROR;
2051 flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
2052 (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
2053 outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, outpos,
2054 max_udp_payload_size,
2055 &ndatalen, flags, stream_id,
2056 (const ngtcp2_vec *)vec, veccnt, ts);
2058 if(outpos != qs->pktbuf) {
2059 curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf,
2060 outpos - qs->pktbuf, gsolen);
2062 if(curlcode == CURLE_AGAIN) {
2063 push_blocked_pkt(qs, qs->pktbuf + sent, outpos - qs->pktbuf - sent,
2065 Curl_expire(data, 1, EXPIRE_QUIC);
2076 case NGTCP2_ERR_STREAM_DATA_BLOCKED:
2077 assert(ndatalen == -1);
2078 nghttp3_conn_block_stream(qs->h3conn, stream_id);
2080 case NGTCP2_ERR_STREAM_SHUT_WR:
2081 assert(ndatalen == -1);
2082 nghttp3_conn_shutdown_stream_write(qs->h3conn, stream_id);
2084 case NGTCP2_ERR_WRITE_MORE:
2085 assert(ndatalen >= 0);
2086 rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
2088 failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
2089 nghttp3_strerror(rv));
2090 return CURLE_SEND_ERROR;
2094 assert(ndatalen == -1);
2095 failf(data, "ngtcp2_conn_writev_stream returned error: %s",
2096 ngtcp2_strerror((int)outlen));
2097 ngtcp2_connection_close_error_set_transport_error_liberr(
2098 &qs->last_error, (int)outlen, NULL, 0);
2099 return CURLE_SEND_ERROR;
2102 else if(ndatalen >= 0) {
2103 rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
2105 failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
2106 nghttp3_strerror(rv));
2107 return CURLE_SEND_ERROR;
2116 else if((size_t)outlen > gsolen ||
2117 (gsolen > path_max_udp_payload_size &&
2118 (size_t)outlen != gsolen)) {
2119 /* Packet larger than path_max_udp_payload_size is PMTUD probe
2120 packet and it might not be sent because of EMSGSIZE. Send
2121 them separately to minimize the loss. */
2122 curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf,
2123 outpos - outlen - qs->pktbuf, gsolen);
2125 if(curlcode == CURLE_AGAIN) {
2126 push_blocked_pkt(qs, qs->pktbuf + sent,
2127 outpos - outlen - qs->pktbuf - sent, gsolen);
2128 push_blocked_pkt(qs, outpos - outlen, outlen, outlen);
2129 Curl_expire(data, 1, EXPIRE_QUIC);
2134 curlcode = send_packet(&sent, data, sockfd, qs, outpos - outlen, outlen,
2137 if(curlcode == CURLE_AGAIN) {
2139 push_blocked_pkt(qs, outpos - outlen, outlen, outlen);
2140 Curl_expire(data, 1, EXPIRE_QUIC);
2147 outpos = qs->pktbuf;
2151 if(++pktcnt >= max_pktcnt || (size_t)outlen < gsolen) {
2152 curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf,
2153 outpos - qs->pktbuf, gsolen);
2155 if(curlcode == CURLE_AGAIN) {
2156 push_blocked_pkt(qs, qs->pktbuf + sent, outpos - qs->pktbuf - sent,
2158 Curl_expire(data, 1, EXPIRE_QUIC);
2165 outpos = qs->pktbuf;
2169 expiry = ngtcp2_conn_get_expiry(qs->qconn);
2170 if(expiry != UINT64_MAX) {
2175 timeout = expiry - ts;
2176 if(timeout % NGTCP2_MILLISECONDS) {
2177 timeout += NGTCP2_MILLISECONDS;
2180 Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
2187 * Called from transfer.c:done_sending when we stop HTTP/3 uploading.
2189 CURLcode Curl_quic_done_sending(struct Curl_easy *data)
2191 struct connectdata *conn = data->conn;
2193 if(conn->handler == &Curl_handler_http3) {
2194 /* only for HTTP/3 transfers */
2195 struct HTTP *stream = data->req.p.http;
2196 struct quicsocket *qs = conn->quic;
2197 stream->upload_done = TRUE;
2198 (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
2205 * Called from http.c:Curl_http_done when a request completes.
2207 void Curl_quic_done(struct Curl_easy *data, bool premature)
2210 if(data->conn->handler == &Curl_handler_http3) {
2211 /* only for HTTP/3 transfers */
2212 struct HTTP *stream = data->req.p.http;
2213 Curl_dyn_free(&stream->overflow);
2214 free(stream->h3out);
2219 * Called from transfer.c:data_pending to know if we should keep looping
2220 * to receive more data from the connection.
2222 bool Curl_quic_data_pending(const struct Curl_easy *data)
2224 /* We may have received more data than we're able to hold in the receive
2225 buffer and allocated an overflow buffer. Since it's possible that
2226 there's no more data coming on the socket, we need to keep reading
2227 until the overflow buffer is empty. */
2228 const struct HTTP *stream = data->req.p.http;
2229 return Curl_dyn_len(&stream->overflow) > 0;
2233 * Called from transfer.c:Curl_readwrite when neither HTTP level read
2234 * nor write is performed. It is a good place to handle timer expiry
2235 * for QUIC transport.
2237 CURLcode Curl_quic_idle(struct Curl_easy *data)
2239 struct connectdata *conn = data->conn;
2240 curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
2241 struct quicsocket *qs = conn->quic;
2243 if(ngtcp2_conn_get_expiry(qs->qconn) > timestamp()) {
2247 if(ng_flush_egress(data, sockfd, qs)) {
2248 return CURLE_SEND_ERROR;