summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vquic
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2025-06-04 09:49:23 +0300
committerdartraiden <wowemuh@gmail.com>2025-06-04 10:27:11 +0300
commit86d1a677fd310d7d90d6f7545c02a4bd68e1d955 (patch)
tree7fd5f46ef18038d10dcdf9fa19ffee547d51d6ad /libs/libcurl/src/vquic
parente8e2a816fbbcec0d6a64496928fecff19c281d82 (diff)
libcurl: update to 8.14.0
Diffstat (limited to 'libs/libcurl/src/vquic')
-rw-r--r--libs/libcurl/src/vquic/curl_msh3.c116
-rw-r--r--libs/libcurl/src/vquic/curl_msh3.h2
-rw-r--r--libs/libcurl/src/vquic/curl_ngtcp2.c259
-rw-r--r--libs/libcurl/src/vquic/curl_ngtcp2.h7
-rw-r--r--libs/libcurl/src/vquic/curl_osslq.c137
-rw-r--r--libs/libcurl/src/vquic/curl_osslq.h4
-rw-r--r--libs/libcurl/src/vquic/curl_quiche.c142
-rw-r--r--libs/libcurl/src/vquic/curl_quiche.h2
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.c44
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.h12
-rw-r--r--libs/libcurl/src/vquic/vquic.c71
-rw-r--r--libs/libcurl/src/vquic/vquic.h5
-rw-r--r--libs/libcurl/src/vquic/vquic_int.h9
13 files changed, 438 insertions, 372 deletions
diff --git a/libs/libcurl/src/vquic/curl_msh3.c b/libs/libcurl/src/vquic/curl_msh3.c
index c3f1375016..8f9590391f 100644
--- a/libs/libcurl/src/vquic/curl_msh3.c
+++ b/libs/libcurl/src/vquic/curl_msh3.c
@@ -22,31 +22,32 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_MSH3
-#include "urldata.h"
-#include "hash.h"
-#include "hash_offt.h"
-#include "timeval.h"
-#include "multiif.h"
-#include "sendf.h"
-#include "curl_trc.h"
-#include "cfilters.h"
-#include "cf-socket.h"
-#include "connect.h"
-#include "progress.h"
-#include "http1.h"
+#include "../urldata.h"
+#include "../hash.h"
+#include "../uint-hash.h"
+#include "../curlx/timeval.h"
+#include "../multiif.h"
+#include "../sendf.h"
+#include "../curl_trc.h"
+#include "../cfilters.h"
+#include "../cf-socket.h"
+#include "../connect.h"
+#include "../progress.h"
+#include "../http1.h"
#include "curl_msh3.h"
-#include "socketpair.h"
-#include "vtls/vtls.h"
-#include "vquic/vquic.h"
+#include "../socketpair.h"
+#include "../vtls/vtls.h"
+#include "vquic.h"
+#include "vquic_int.h"
/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_printf.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
#ifdef CURL_DISABLE_SOCKETPAIR
#error "MSH3 cannot be build with CURL_DISABLE_SOCKETPAIR set"
@@ -120,18 +121,18 @@ struct cf_msh3_ctx {
struct cf_call_data call_data;
struct curltime connect_started; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
- struct Curl_hash_offt streams; /* hash `data->mid` to `stream_ctx` */
+ struct uint_hash streams; /* hash `data->mid` to `stream_ctx` */
/* Flags written by msh3/msquic thread */
- bool handshake_complete;
- bool handshake_succeeded;
- bool connected;
+ BIT(handshake_complete);
+ BIT(handshake_succeeded);
+ BIT(connected);
BIT(initialized);
/* Flags written by curl thread */
BIT(verbose);
BIT(active);
};
-static void h3_stream_hash_free(curl_off_t id, void *stream);
+static void h3_stream_hash_free(unsigned int id, void *stream);
static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
const struct Curl_addrinfo *ai)
@@ -139,7 +140,7 @@ static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
CURLcode result;
DEBUGASSERT(!ctx->initialized);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
+ Curl_uint_hash_init(&ctx->streams, 63, h3_stream_hash_free);
result = Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
if(result)
@@ -155,7 +156,7 @@ static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx)
{
if(ctx && ctx->initialized) {
- Curl_hash_offt_destroy(&ctx->streams);
+ Curl_uint_hash_destroy(&ctx->streams);
}
free(ctx);
}
@@ -170,7 +171,7 @@ static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data);
/**
* All about the H3 internals of a stream
*/
-struct stream_ctx {
+struct h3_stream_ctx {
struct MSH3_REQUEST *req;
struct bufq recvbuf; /* h3 response */
#ifdef _WIN32
@@ -181,34 +182,31 @@ struct stream_ctx {
uint64_t error3; /* HTTP/3 stream error code */
int status_code; /* HTTP status code */
CURLcode recv_error;
- bool closed;
- bool reset;
- bool upload_done;
- bool firstheader; /* FALSE until headers arrive */
- bool recv_header_complete;
+ BIT(closed);
+ BIT(reset);
+ BIT(upload_done);
+ BIT(firstheader); /* FALSE until headers arrive */
+ BIT(recv_header_complete);
};
-#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)((data && ctx)? \
- Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-
-static void h3_stream_ctx_free(struct stream_ctx *stream)
+static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
{
Curl_bufq_free(&stream->recvbuf);
free(stream);
}
-static void h3_stream_hash_free(curl_off_t id, void *stream)
+static void h3_stream_hash_free(unsigned int id, void *stream)
{
(void)id;
DEBUGASSERT(stream);
- h3_stream_ctx_free((struct stream_ctx *)stream);
+ h3_stream_ctx_free((struct h3_stream_ctx *)stream);
}
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream)
return CURLE_OK;
@@ -223,7 +221,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
CURL_TRC_CF(data, cf, "data setup");
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
+ if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -234,17 +232,17 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
if(stream) {
CURL_TRC_CF(data, cf, "easy handle is done");
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_uint_hash_remove(&ctx->streams, data->mid);
}
}
static void drain_stream_from_other_thread(struct Curl_easy *data,
- struct stream_ctx *stream)
+ struct h3_stream_ctx *stream)
{
unsigned char bits;
@@ -262,7 +260,7 @@ static void h3_drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
unsigned char bits;
(void)cf;
@@ -361,7 +359,7 @@ static CURLcode write_resp_raw(struct Curl_easy *data,
const void *mem, size_t memlen)
{
struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
ssize_t nwritten;
@@ -388,7 +386,7 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
{
struct Curl_easy *data = userp;
struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
(void)Request;
@@ -439,7 +437,7 @@ static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
{
struct Curl_easy *data = IfContext;
struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
bool rv = FALSE;
@@ -479,7 +477,7 @@ static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
{
struct Curl_easy *data = IfContext;
struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)Request;
if(!stream)
@@ -499,7 +497,7 @@ static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
{
struct Curl_easy *data = IfContext;
struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(!stream)
return;
@@ -512,7 +510,7 @@ static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request,
{
struct Curl_easy *data = IfContext;
struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(!stream)
return;
(void)Request;
@@ -525,7 +523,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
CURLcode *err)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
if(!stream) {
@@ -559,7 +557,7 @@ out:
static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
/* we have no indication from msh3 when it would be a good time
* to juggle the connection again. So, we compromise by calling
@@ -577,7 +575,7 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
struct cf_call_data save;
@@ -629,7 +627,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURLcode *err)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct h1_req_parser h1;
struct dynhds h2_headers;
MSH3_HEADER *nva = NULL;
@@ -725,7 +723,7 @@ static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
@@ -745,7 +743,7 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
bool pending = FALSE;
@@ -783,7 +781,7 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
int event, int arg1, void *arg2)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
struct cf_call_data save;
CURLcode result = CURLE_OK;
@@ -903,14 +901,14 @@ static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
*done = FALSE;
if(!ctx->qconn) {
- ctx->connect_started = Curl_now();
+ ctx->connect_started = curlx_now();
result = cf_connect_start(cf, data);
if(result)
goto out;
}
if(ctx->handshake_complete) {
- ctx->handshake_at = Curl_now();
+ ctx->handshake_at = curlx_now();
if(ctx->handshake_succeeded) {
CURL_TRC_CF(data, cf, "handshake succeeded");
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
diff --git a/libs/libcurl/src/vquic/curl_msh3.h b/libs/libcurl/src/vquic/curl_msh3.h
index e3f40c2ab9..259011499b 100644
--- a/libs/libcurl/src/vquic/curl_msh3.h
+++ b/libs/libcurl/src/vquic/curl_msh3.h
@@ -24,7 +24,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_MSH3
diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.c b/libs/libcurl/src/vquic/curl_ngtcp2.c
index 7b3f0f9b7e..d5a9553677 100644
--- a/libs/libcurl/src/vquic/curl_ngtcp2.c
+++ b/libs/libcurl/src/vquic/curl_ngtcp2.c
@@ -22,7 +22,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
#include <ngtcp2/ngtcp2.h>
@@ -32,49 +32,51 @@
#include <openssl/err.h>
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
#include <ngtcp2/ngtcp2_crypto_boringssl.h>
+#elif defined(OPENSSL_QUIC_API2)
+#include <ngtcp2/ngtcp2_crypto_ossl.h>
#else
#include <ngtcp2/ngtcp2_crypto_quictls.h>
#endif
-#include "vtls/openssl.h"
+#include "../vtls/openssl.h"
#elif defined(USE_GNUTLS)
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
-#include "vtls/gtls.h"
+#include "../vtls/gtls.h"
#elif defined(USE_WOLFSSL)
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
-#include "vtls/wolfssl.h"
+#include "../vtls/wolfssl.h"
#endif
-#include "urldata.h"
-#include "hash_offt.h"
-#include "sendf.h"
-#include "strdup.h"
-#include "rand.h"
-#include "multiif.h"
-#include "strcase.h"
-#include "cfilters.h"
-#include "cf-socket.h"
-#include "connect.h"
-#include "progress.h"
-#include "strerror.h"
-#include "dynbuf.h"
-#include "http1.h"
-#include "select.h"
-#include "inet_pton.h"
-#include "transfer.h"
+#include "../urldata.h"
+#include "../uint-hash.h"
+#include "../sendf.h"
+#include "../strdup.h"
+#include "../rand.h"
+#include "../multiif.h"
+#include "../strcase.h"
+#include "../cfilters.h"
+#include "../cf-socket.h"
+#include "../connect.h"
+#include "../progress.h"
+#include "../strerror.h"
+#include "../curlx/dynbuf.h"
+#include "../http1.h"
+#include "../select.h"
+#include "../curlx/inet_pton.h"
+#include "../transfer.h"
#include "vquic.h"
#include "vquic_int.h"
#include "vquic-tls.h"
-#include "vtls/keylog.h"
-#include "vtls/vtls.h"
-#include "vtls/vtls_scache.h"
+#include "../vtls/keylog.h"
+#include "../vtls/vtls.h"
+#include "../vtls/vtls_scache.h"
#include "curl_ngtcp2.h"
-#include "warnless.h"
+#include "../curlx/warnless.h"
/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_printf.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
#define QUIC_MAX_STREAMS (256*1024)
@@ -87,6 +89,10 @@
* Chunk size is large enough to take a full DATA frame */
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE (16 * 1024)
+#if H3_STREAM_CHUNK_SIZE < NGTCP2_MAX_UDP_PAYLOAD_SIZE
+#error H3_STREAM_CHUNK_SIZE smaller than NGTCP2_MAX_UDP_PAYLOAD_SIZE
+#endif
+
/* The pool keeps spares around and half of a full stream windows
* seems good. More does not seem to improve performance.
* The benefit of the pool is that stream buffer to not keep
@@ -117,6 +123,9 @@ struct cf_ngtcp2_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
struct curl_tls_ctx tls;
+#ifdef OPENSSL_QUIC_API2
+ ngtcp2_crypto_ossl_ctx *ossl_ctx;
+#endif
ngtcp2_path connected_path;
ngtcp2_conn *qconn;
ngtcp2_cid dcid;
@@ -133,9 +142,8 @@ struct cf_ngtcp2_ctx {
struct curltime handshake_at; /* time connect handshake finished */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
struct dynbuf scratch; /* temp buffer for header construction */
- struct Curl_hash_offt streams; /* hash `data->mid` to `h3_stream_ctx` */
+ struct uint_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
size_t max_stream_window; /* max flow window for one stream */
- uint64_t max_idle_ms; /* max idle time for QUIC connection */
uint64_t used_bidi_streams; /* bidi streams we have opened */
uint64_t max_bidi_streams; /* max bidi streams we can open */
size_t earlydata_max; /* max amount of early data supported by
@@ -156,7 +164,7 @@ struct cf_ngtcp2_ctx {
#define CF_CTX_CALL_DATA(cf) \
((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
-static void h3_stream_hash_free(curl_off_t id, void *stream);
+static void h3_stream_hash_free(unsigned int id, void *stream);
static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx)
{
@@ -164,11 +172,10 @@ static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx)
ctx->qlogfd = -1;
ctx->version = NGTCP2_PROTO_VER_MAX;
ctx->max_stream_window = H3_STREAM_WINDOW_SIZE;
- ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
- Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
+ curlx_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
+ Curl_uint_hash_init(&ctx->streams, 63, h3_stream_hash_free);
ctx->initialized = TRUE;
}
@@ -178,13 +185,51 @@ static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx)
Curl_vquic_tls_cleanup(&ctx->tls);
vquic_ctx_free(&ctx->q);
Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_dyn_free(&ctx->scratch);
- Curl_hash_offt_destroy(&ctx->streams);
+ curlx_dyn_free(&ctx->scratch);
+ Curl_uint_hash_destroy(&ctx->streams);
Curl_ssl_peer_cleanup(&ctx->peer);
}
free(ctx);
}
+static void cf_ngtcp2_setup_keep_alive(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ const ngtcp2_transport_params *rp;
+ /* Peer should have sent us its transport parameters. If it
+ * announces a positive `max_idle_timeout` it will close the
+ * connection when it does not hear from us for that time.
+ *
+ * Some servers use this as a keep-alive timer at a rather low
+ * value. We are doing HTTP/3 here and waiting for the response
+ * to a request may take a considerable amount of time. We need
+ * to prevent the peer's QUIC stack from closing in this case.
+ */
+ if(!ctx->qconn)
+ return;
+
+ rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
+ if(!rp || !rp->max_idle_timeout) {
+ ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX);
+ CURL_TRC_CF(data, cf, "no peer idle timeout, unset keep-alive");
+ }
+ else if(!Curl_uint_hash_count(&ctx->streams)) {
+ ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, UINT64_MAX);
+ CURL_TRC_CF(data, cf, "no active streams, unset keep-alive");
+ }
+ else {
+ ngtcp2_duration keep_ns;
+ keep_ns = (rp->max_idle_timeout > 1) ? (rp->max_idle_timeout / 2) : 1;
+ ngtcp2_conn_set_keep_alive_timeout(ctx->qconn, keep_ns);
+ CURL_TRC_CF(data, cf, "peer idle timeout is %" FMT_PRIu64 "ms, "
+ "set keep-alive to %" FMT_PRIu64 " ms.",
+ (curl_uint64_t)(rp->max_idle_timeout / NGTCP2_MILLISECONDS),
+ (curl_uint64_t)(keep_ns / NGTCP2_MILLISECONDS));
+ }
+}
+
+
struct pkt_io_ctx;
static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -205,18 +250,13 @@ struct h3_stream_ctx {
curl_off_t upload_left; /* number of request bytes left to upload */
int status_code; /* HTTP status code */
CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
- bool resp_hds_complete; /* we have a complete, final response */
- bool closed; /* TRUE on stream close */
- bool reset; /* TRUE on stream reset */
- bool send_closed; /* stream is local closed */
+ BIT(resp_hds_complete); /* we have a complete, final response */
+ BIT(closed); /* TRUE on stream close */
+ BIT(reset); /* TRUE on stream reset */
+ BIT(send_closed); /* stream is local closed */
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-#define H3_STREAM_CTX_ID(ctx,id) ((struct h3_stream_ctx *)(\
- Curl_hash_offt_get(&(ctx)->streams, (id))))
-
static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
{
Curl_bufq_free(&stream->sendbuf);
@@ -224,7 +264,7 @@ static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
free(stream);
}
-static void h3_stream_hash_free(curl_off_t id, void *stream)
+static void h3_stream_hash_free(unsigned int id, void *stream)
{
(void)id;
DEBUGASSERT(stream);
@@ -254,11 +294,14 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
stream->sendbuf_len_in_flight = 0;
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
+ if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
+ if(Curl_uint_hash_count(&ctx->streams) == 1)
+ cf_ngtcp2_setup_keep_alive(cf, data);
+
return CURLE_OK;
}
@@ -293,7 +336,9 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] easy handle is done",
stream->id);
cf_ngtcp2_stream_close(cf, data, stream);
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_uint_hash_remove(&ctx->streams, data->mid);
+ if(!Curl_uint_hash_count(&ctx->streams))
+ cf_ngtcp2_setup_keep_alive(cf, data);
}
}
@@ -415,7 +460,7 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx,
t->initial_max_stream_data_uni = ctx->max_stream_window;
t->initial_max_streams_bidi = QUIC_MAX_STREAMS;
t->initial_max_streams_uni = QUIC_MAX_STREAMS;
- t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS);
+ t->max_idle_timeout = 0; /* no idle timeout from our side */
if(ctx->qlogfd != -1) {
s->qlog_write = qlog_callback;
}
@@ -437,14 +482,14 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data)
if(!ctx || !data)
return NGHTTP3_ERR_CALLBACK_FAILURE;
- ctx->handshake_at = Curl_now();
+ ctx->handshake_at = curlx_now();
ctx->tls_handshake_complete = TRUE;
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf,
data, &ctx->peer);
CURL_TRC_CF(data, cf, "handshake complete after %dms",
- (int)Curl_timediff(ctx->handshake_at, ctx->started_at));
+ (int)curlx_timediff(ctx->handshake_at, ctx->started_at));
/* In case of earlydata, where we simulate being connected, update
* the handshake time when we really did connect */
if(ctx->use_earlydata)
@@ -546,7 +591,7 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read_stream(len=%zu) -> %zd",
stream_id, buflen, nconsumed);
if(nconsumed < 0) {
- struct h3_stream_ctx *stream = H3_STREAM_CTX_ID(ctx, stream_id);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(data && stream) {
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] error on known stream, "
"reset=%d, closed=%d",
@@ -1060,18 +1105,18 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
(const char *)h3val.base, h3val.len);
if(result)
return -1;
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 "));
+ curlx_dyn_reset(&ctx->scratch);
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 "));
if(!result)
- result = Curl_dyn_addn(&ctx->scratch,
- (const char *)h3val.base, h3val.len);
+ result = curlx_dyn_addn(&ctx->scratch,
+ (const char *)h3val.base, h3val.len);
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
if(!result)
- h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
+ h3_xfer_write_resp_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch),
+ curlx_dyn_len(&ctx->scratch), FALSE);
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s",
- stream_id, Curl_dyn_ptr(&ctx->scratch));
+ stream_id, curlx_dyn_ptr(&ctx->scratch));
if(result) {
return -1;
}
@@ -1081,19 +1126,19 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] header: %.*s: %.*s",
stream_id, (int)h3name.len, h3name.base,
(int)h3val.len, h3val.base);
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch,
- (const char *)h3name.base, h3name.len);
+ curlx_dyn_reset(&ctx->scratch);
+ result = curlx_dyn_addn(&ctx->scratch,
+ (const char *)h3name.base, h3name.len);
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST(": "));
if(!result)
- result = Curl_dyn_addn(&ctx->scratch,
- (const char *)h3val.base, h3val.len);
+ result = curlx_dyn_addn(&ctx->scratch,
+ (const char *)h3val.base, h3val.len);
if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
+ result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
if(!result)
- h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
+ h3_xfer_write_resp_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch),
+ curlx_dyn_len(&ctx->scratch), FALSE);
}
return 0;
}
@@ -2014,10 +2059,20 @@ static void cf_ngtcp2_ctx_close(struct cf_ngtcp2_ctx *ctx)
ctx->qlogfd = -1;
Curl_vquic_tls_cleanup(&ctx->tls);
vquic_ctx_free(&ctx->q);
- if(ctx->h3conn)
+ if(ctx->h3conn) {
nghttp3_conn_del(ctx->h3conn);
- if(ctx->qconn)
+ ctx->h3conn = NULL;
+ }
+ if(ctx->qconn) {
ngtcp2_conn_del(ctx->qconn);
+ ctx->qconn = NULL;
+ }
+#ifdef OPENSSL_QUIC_API2
+ if(ctx->ossl_ctx) {
+ ngtcp2_crypto_ossl_ctx_del(ctx->ossl_ctx);
+ ctx->ossl_ctx = NULL;
+ }
+#endif
ctx->call_data = save;
}
@@ -2057,6 +2112,7 @@ static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf,
}
}
+ DEBUGASSERT(Curl_bufq_is_empty(&ctx->q.sendbuf));
ctx->shutdown_started = TRUE;
nwritten = ngtcp2_conn_write_connection_close(
ctx->qconn, NULL, /* path */
@@ -2066,14 +2122,21 @@ static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "start shutdown(err_type=%d, err_code=%"
FMT_PRIu64 ") -> %d", ctx->last_error.type,
(curl_uint64_t)ctx->last_error.error_code, (int)nwritten);
+ /* there are cases listed in ngtcp2 documentation where this call
+ * may fail. Since we are doing a connection shutdown as graceful
+ * as we can, such an error is ignored here. */
if(nwritten > 0) {
- Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
- (size_t)nwritten, &result);
+ /* Ignore amount written. sendbuf was empty and has always room for
+ * NGTCP2_MAX_UDP_PAYLOAD_SIZE. It can only completely fail, in which
+ * case `result` is set non zero. */
+ (void)Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
+ (size_t)nwritten, &result);
if(result) {
CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, "
"aborting shutdown", result);
goto out;
}
+
ctx->q.no_gso = TRUE;
ctx->q.gsolen = (size_t)nwritten;
ctx->q.split_len = 0;
@@ -2133,6 +2196,7 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "destroy");
if(cf->ctx) {
+ cf_ngtcp2_close(cf, data);
cf_ngtcp2_ctx_free(cf->ctx);
cf->ctx = NULL;
}
@@ -2291,6 +2355,8 @@ static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
return CURLE_FAILED_INIT;
}
+#elif defined(OPENSSL_QUIC_API2)
+ /* nothing to do */
#else
if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
@@ -2453,6 +2519,9 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
+ ctx->conn_ref.get_conn = get_conn;
+ ctx->conn_ref.user_data = cf;
+
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, &ALPN_SPEC_H3,
cf_ngtcp2_tls_ctx_setup, &ctx->tls,
&ctx->conn_ref,
@@ -2460,7 +2529,17 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
if(result)
return result;
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL) && defined(OPENSSL_QUIC_API2)
+ if(ngtcp2_crypto_ossl_ctx_new(&ctx->ossl_ctx, ctx->tls.ossl.ssl) != 0) {
+ failf(data, "ngtcp2_crypto_ossl_ctx_new failed");
+ return CURLE_FAILED_INIT;
+ }
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->ossl_ctx);
+ if(ngtcp2_crypto_ossl_configure_client_session(ctx->tls.ossl.ssl) != 0) {
+ failf(data, "ngtcp2_crypto_ossl_configure_client_session failed");
+ return CURLE_FAILED_INIT;
+ }
+#elif defined(USE_OPENSSL)
SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0);
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
#elif defined(USE_GNUTLS)
@@ -2473,9 +2552,6 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
ngtcp2_ccerr_default(&ctx->last_error);
- ctx->conn_ref.get_conn = get_conn;
- ctx->conn_ref.user_data = cf;
-
return CURLE_OK;
}
@@ -2502,7 +2578,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
- now = Curl_now();
+ now = curlx_now();
pktx_init(&pktx, cf, data);
CF_DATA_SAVE(save, cf, data);
@@ -2589,7 +2665,7 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
}
else if(ctx->max_bidi_streams) {
uint64_t avail_bidi_streams = 0;
- uint64_t max_streams = CONN_INUSE(cf->conn);
+ uint64_t max_streams = CONN_ATTACHED(cf->conn);
if(ctx->max_bidi_streams > ctx->used_bidi_streams)
avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
max_streams += avail_bidi_streams;
@@ -2598,14 +2674,14 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
else /* transport params not arrived yet? take our default. */
*pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
- "MAX_CONCURRENT -> %d (%zu in use)",
- cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
+ "MAX_CONCURRENT -> %d (%u in use)",
+ cf->conn->connection_id, *pres1, CONN_ATTACHED(cf->conn));
CF_DATA_RESTORE(cf, save);
return CURLE_OK;
}
case CF_QUERY_CONNECT_REPLY_MS:
if(ctx->q.got_first_byte) {
- timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
+ timediff_t ms = curlx_timediff(ctx->q.first_byte_at, ctx->started_at);
*pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
}
else
@@ -2648,21 +2724,12 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
if(!ctx->qconn || ctx->shutdown_started)
goto out;
- /* Both sides of the QUIC connection announce they max idle times in
- * the transport parameters. Look at the minimum of both and if
- * we exceed this, regard the connection as dead. The other side
- * may have completely purged it and will no longer respond
- * to any packets from us. */
+ /* We do not announce a max idle timeout, but when the peer does
+ * it will close the connection when it expires. */
rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
- if(rp) {
- timediff_t idletime;
- uint64_t idle_ms = ctx->max_idle_ms;
-
- if(rp->max_idle_timeout &&
- (rp->max_idle_timeout / NGTCP2_MILLISECONDS) < idle_ms)
- idle_ms = (rp->max_idle_timeout / NGTCP2_MILLISECONDS);
- idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
- if(idletime > 0 && (uint64_t)idletime > idle_ms)
+ if(rp && rp->max_idle_timeout) {
+ timediff_t idletime = curlx_timediff(curlx_now(), ctx->q.last_io);
+ if(idletime > 0 && (uint64_t)idletime > rp->max_idle_timeout)
goto out;
}
diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.h b/libs/libcurl/src/vquic/curl_ngtcp2.h
index 7b8a158b76..313d853644 100644
--- a/libs/libcurl/src/vquic/curl_ngtcp2.h
+++ b/libs/libcurl/src/vquic/curl_ngtcp2.h
@@ -24,7 +24,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
@@ -33,6 +33,9 @@
#endif
#include <ngtcp2/ngtcp2_crypto.h>
+#ifdef OPENSSL_QUIC_API2
+#include <ngtcp2/ngtcp2_crypto_ossl.h>
+#endif
#include <nghttp3/nghttp3.h>
#ifdef USE_OPENSSL
#include <openssl/ssl.h>
@@ -44,7 +47,7 @@
struct Curl_cfilter;
-#include "urldata.h"
+#include "../urldata.h"
void Curl_ngtcp2_ver(char *p, size_t len);
diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c
index 7dbd0f13f3..3067ccfbda 100644
--- a/libs/libcurl/src/vquic/curl_osslq.c
+++ b/libs/libcurl/src/vquic/curl_osslq.c
@@ -22,7 +22,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
@@ -31,36 +31,36 @@
#include <openssl/err.h>
#include <nghttp3/nghttp3.h>
-#include "urldata.h"
-#include "hash.h"
-#include "sendf.h"
-#include "strdup.h"
-#include "rand.h"
-#include "multiif.h"
-#include "strcase.h"
-#include "cfilters.h"
-#include "cf-socket.h"
-#include "connect.h"
-#include "progress.h"
-#include "strerror.h"
-#include "dynbuf.h"
-#include "http1.h"
-#include "select.h"
-#include "inet_pton.h"
+#include "../urldata.h"
+#include "../hash.h"
+#include "../sendf.h"
+#include "../strdup.h"
+#include "../rand.h"
+#include "../multiif.h"
+#include "../strcase.h"
+#include "../cfilters.h"
+#include "../cf-socket.h"
+#include "../connect.h"
+#include "../progress.h"
+#include "../strerror.h"
+#include "../curlx/dynbuf.h"
+#include "../http1.h"
+#include "../select.h"
+#include "../curlx/inet_pton.h"
+#include "../uint-hash.h"
#include "vquic.h"
#include "vquic_int.h"
#include "vquic-tls.h"
-#include "vtls/keylog.h"
-#include "vtls/vtls.h"
-#include "vtls/openssl.h"
+#include "../vtls/keylog.h"
+#include "../vtls/vtls.h"
+#include "../vtls/openssl.h"
#include "curl_osslq.h"
-
-#include "warnless.h"
+#include "../curlx/warnless.h"
/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_printf.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
/* A stream window is the maximum amount we need to buffer for
* each active transfer. We use HTTP/3 flow control and only ACK
@@ -285,7 +285,7 @@ struct cf_osslq_ctx {
struct curltime handshake_at; /* time connect handshake finished */
struct curltime first_byte_at; /* when first byte was recvd */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash_offt streams; /* hash `data->mid` to `h3_stream_ctx` */
+ struct uint_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
size_t max_stream_window; /* max flow window for one stream */
uint64_t max_idle_ms; /* max idle time for QUIC connection */
SSL_POLL_ITEM *poll_items; /* Array for polling on writable state */
@@ -299,14 +299,14 @@ struct cf_osslq_ctx {
BIT(need_send); /* QUIC connection needs to send */
};
-static void h3_stream_hash_free(curl_off_t id, void *stream);
+static void h3_stream_hash_free(unsigned int id, void *stream);
static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx)
{
DEBUGASSERT(!ctx->initialized);
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
+ Curl_uint_hash_init(&ctx->streams, 63, h3_stream_hash_free);
ctx->poll_items = NULL;
ctx->curl_items = NULL;
ctx->items_max = 0;
@@ -317,7 +317,7 @@ static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx)
{
if(ctx && ctx->initialized) {
Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_hash_offt_destroy(&ctx->streams);
+ Curl_uint_hash_destroy(&ctx->streams);
Curl_ssl_peer_cleanup(&ctx->peer);
free(ctx->poll_items);
free(ctx->curl_items);
@@ -583,16 +583,13 @@ struct h3_stream_ctx {
curl_off_t upload_left; /* number of request bytes left to upload */
curl_off_t download_recvd; /* number of response DATA bytes received */
int status_code; /* HTTP status code */
- bool resp_hds_complete; /* we have a complete, final response */
- bool closed; /* TRUE on stream close */
- bool reset; /* TRUE on stream reset */
- bool send_closed; /* stream is local closed */
+ BIT(resp_hds_complete); /* we have a complete, final response */
+ BIT(closed); /* TRUE on stream close */
+ BIT(reset); /* TRUE on stream reset */
+ BIT(send_closed); /* stream is local closed */
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-
static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
{
cf_osslq_stream_cleanup(&stream->s);
@@ -602,7 +599,7 @@ static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
free(stream);
}
-static void h3_stream_hash_free(curl_off_t id, void *stream)
+static void h3_stream_hash_free(unsigned int id, void *stream)
{
(void)id;
DEBUGASSERT(stream);
@@ -637,7 +634,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
stream->recv_buf_nonflow = 0;
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
+ if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -654,7 +651,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
if(stream) {
CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] easy handle is done",
stream->s.id);
- if(ctx->h3.conn && !stream->closed) {
+ if(ctx->h3.conn && (stream->s.id >= 0) && !stream->closed) {
nghttp3_conn_shutdown_stream_read(ctx->h3.conn, stream->s.id);
nghttp3_conn_close_stream(ctx->h3.conn, stream->s.id,
NGHTTP3_H3_REQUEST_CANCELLED);
@@ -662,7 +659,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
stream->closed = TRUE;
}
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_uint_hash_remove(&ctx->streams, data->mid);
}
}
@@ -671,7 +668,7 @@ struct cf_ossq_find_ctx {
struct h3_stream_ctx *stream;
};
-static bool cf_osslq_find_stream(curl_off_t mid, void *val, void *user_data)
+static bool cf_osslq_find_stream(unsigned int mid, void *val, void *user_data)
{
struct h3_stream_ctx *stream = val;
struct cf_ossq_find_ctx *fctx = user_data;
@@ -707,7 +704,7 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
struct cf_ossq_find_ctx fctx;
fctx.stream_id = stream_id;
fctx.stream = NULL;
- Curl_hash_offt_visit(&ctx->streams, cf_osslq_find_stream, &fctx);
+ Curl_uint_hash_visit(&ctx->streams, cf_osslq_find_stream, &fctx);
if(fctx.stream)
return &fctx.stream->s;
}
@@ -832,7 +829,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
stream->download_recvd += (curl_off_t)buflen;
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, total=%zd",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, total=%" FMT_OFF_T,
stream->s.id, buflen, stream->download_recvd);
h3_drain_stream(cf, data);
return 0;
@@ -1239,17 +1236,6 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
goto out;
}
-#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
- /* Added in OpenSSL v3.3.x */
- if(!SSL_set_feature_request_uint(ctx->tls.ossl.ssl,
- SSL_VALUE_QUIC_IDLE_TIMEOUT,
- CURL_QUIC_MAX_IDLE_MS)) {
- CURL_TRC_CF(data, cf, "error setting idle timeout, ");
- result = CURLE_FAILED_INIT;
- goto out;
- }
-#endif
-
SSL_set_bio(ctx->tls.ossl.ssl, bio, bio);
bio = NULL;
SSL_set_connect_state(ctx->tls.ossl.ssl);
@@ -1420,14 +1406,14 @@ struct cf_ossq_recv_ctx {
CURLcode result;
};
-static bool cf_osslq_iter_recv(curl_off_t mid, void *val, void *user_data)
+static bool cf_osslq_iter_recv(unsigned int mid, void *val, void *user_data)
{
struct h3_stream_ctx *stream = val;
struct cf_ossq_recv_ctx *rctx = user_data;
(void)mid;
if(stream && !stream->closed && !Curl_bufq_is_full(&stream->recvbuf)) {
- struct Curl_easy *sdata = Curl_multi_get_handle(rctx->multi, mid);
+ struct Curl_easy *sdata = Curl_multi_get_easy(rctx->multi, mid);
if(sdata) {
rctx->result = cf_osslq_stream_recv(&stream->s, rctx->cf, sdata);
if(rctx->result)
@@ -1479,7 +1465,7 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
rctx.cf = cf;
rctx.multi = data->multi;
rctx.result = CURLE_OK;
- Curl_hash_offt_visit(&ctx->streams, cf_osslq_iter_recv, &rctx);
+ Curl_uint_hash_visit(&ctx->streams, cf_osslq_iter_recv, &rctx);
result = rctx.result;
}
@@ -1494,7 +1480,7 @@ struct cf_ossq_fill_ctx {
size_t n;
};
-static bool cf_osslq_collect_block_send(curl_off_t mid, void *val,
+static bool cf_osslq_collect_block_send(unsigned int mid, void *val,
void *user_data)
{
struct h3_stream_ctx *stream = val;
@@ -1505,9 +1491,7 @@ static bool cf_osslq_collect_block_send(curl_off_t mid, void *val,
return FALSE;
if(stream && stream->s.ssl && stream->s.send_blocked) {
- struct Curl_easy *sdata = Curl_multi_get_handle(fctx->multi, mid);
- fprintf(stderr, "[OSSLQ] stream %" FMT_PRId64 " sdata=%p\n",
- stream->s.id, (void *)sdata);
+ struct Curl_easy *sdata = Curl_multi_get_easy(fctx->multi, mid);
if(sdata) {
ctx->poll_items[fctx->n].desc = SSL_as_poll_descriptor(stream->s.ssl);
ctx->poll_items[fctx->n].events = SSL_POLL_EVENT_W;
@@ -1534,8 +1518,8 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
if(ctx->h3.conn) {
struct cf_ossq_fill_ctx fill_ctx;
- if(ctx->items_max < Curl_hash_offt_count(&ctx->streams)) {
- size_t nmax = Curl_hash_offt_count(&ctx->streams);
+ if(ctx->items_max < Curl_uint_hash_count(&ctx->streams)) {
+ size_t nmax = Curl_uint_hash_count(&ctx->streams);
ctx->items_max = 0;
tmpptr = realloc(ctx->poll_items, nmax * sizeof(SSL_POLL_ITEM));
if(!tmpptr) {
@@ -1560,7 +1544,7 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
fill_ctx.ctx = ctx;
fill_ctx.multi = data->multi;
fill_ctx.n = 0;
- Curl_hash_offt_visit(&ctx->streams, cf_osslq_collect_block_send,
+ Curl_uint_hash_visit(&ctx->streams, cf_osslq_collect_block_send,
&fill_ctx);
poll_count = fill_ctx.n;
if(poll_count) {
@@ -1578,10 +1562,13 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
idx_count++) {
if(ctx->poll_items[idx_count].revents & SSL_POLL_EVENT_W) {
stream = H3_STREAM_CTX(ctx, ctx->curl_items[idx_count]);
- nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
- stream->s.send_blocked = FALSE;
- h3_drain_stream(cf, ctx->curl_items[idx_count]);
- CURL_TRC_CF(ctx->curl_items[idx_count], cf, "unblocked");
+ DEBUGASSERT(stream); /* should still exist */
+ if(stream) {
+ nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
+ stream->s.send_blocked = FALSE;
+ h3_drain_stream(cf, ctx->curl_items[idx_count]);
+ CURL_TRC_CF(ctx->curl_items[idx_count], cf, "unblocked");
+ }
result_count--;
}
}
@@ -1677,7 +1664,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
if(acked_len > 0 || (eos && !s->send_blocked)) {
/* Since QUIC buffers the data written internally, we can tell
* nghttp3 that it can move forward on it */
- ctx->q.last_io = Curl_now();
+ ctx->q.last_io = curlx_now();
rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
@@ -1791,7 +1778,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
}
*done = FALSE;
- now = Curl_now();
+ now = curlx_now();
CF_DATA_SAVE(save, cf, data);
if(!ctx->tls.ossl.ssl) {
@@ -1805,7 +1792,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
int readable = SOCKET_READABLE(ctx->q.sockfd, 0);
if(readable > 0 && (readable & CURL_CSELECT_IN)) {
ctx->got_first_byte = TRUE;
- ctx->first_byte_at = Curl_now();
+ ctx->first_byte_at = curlx_now();
}
}
@@ -1825,7 +1812,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
ctx->handshake_at = now;
ctx->q.last_io = now;
CURL_TRC_CF(data, cf, "handshake complete after %dms",
- (int)Curl_timediff(now, ctx->started_at));
+ (int)curlx_timediff(now, ctx->started_at));
result = cf_osslq_verify_peer(cf, data);
if(!result) {
CURL_TRC_CF(data, cf, "peer verified");
@@ -2301,7 +2288,7 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
goto out;
}
CURL_TRC_CF(data, cf, "negotiated idle timeout: %zums", (size_t)idle_ms);
- idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
+ idletime = curlx_timediff(curlx_now(), ctx->q.last_io);
if(idletime > 0 && (uint64_t)idletime > idle_ms)
goto out;
}
@@ -2378,7 +2365,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
return CURLE_HTTP3;
}
/* we report avail + in_use */
- v += CONN_INUSE(cf->conn);
+ v += CONN_ATTACHED(cf->conn);
*pres1 = (v > INT_MAX) ? INT_MAX : (int)v;
#else
*pres1 = 100;
@@ -2388,7 +2375,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
}
case CF_QUERY_CONNECT_REPLY_MS:
if(ctx->got_first_byte) {
- timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
+ timediff_t ms = curlx_timediff(ctx->first_byte_at, ctx->started_at);
*pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
}
else
diff --git a/libs/libcurl/src/vquic/curl_osslq.h b/libs/libcurl/src/vquic/curl_osslq.h
index f34d84baf8..f0e670c106 100644
--- a/libs/libcurl/src/vquic/curl_osslq.h
+++ b/libs/libcurl/src/vquic/curl_osslq.h
@@ -24,7 +24,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
@@ -34,7 +34,7 @@
struct Curl_cfilter;
-#include "urldata.h"
+#include "../urldata.h"
void Curl_osslq_ver(char *p, size_t len);
diff --git a/libs/libcurl/src/vquic/curl_quiche.c b/libs/libcurl/src/vquic/curl_quiche.c
index 5d565e31c1..d8bbbd72f6 100644
--- a/libs/libcurl/src/vquic/curl_quiche.c
+++ b/libs/libcurl/src/vquic/curl_quiche.c
@@ -22,40 +22,40 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_QUICHE
#include <quiche.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
-#include "bufq.h"
-#include "hash_offt.h"
-#include "urldata.h"
-#include "cfilters.h"
-#include "cf-socket.h"
-#include "sendf.h"
-#include "strdup.h"
-#include "rand.h"
-#include "strcase.h"
-#include "multiif.h"
-#include "connect.h"
-#include "progress.h"
-#include "strerror.h"
-#include "http1.h"
+#include "../bufq.h"
+#include "../uint-hash.h"
+#include "../urldata.h"
+#include "../cfilters.h"
+#include "../cf-socket.h"
+#include "../sendf.h"
+#include "../strdup.h"
+#include "../rand.h"
+#include "../strcase.h"
+#include "../multiif.h"
+#include "../connect.h"
+#include "../progress.h"
+#include "../strerror.h"
+#include "../http1.h"
#include "vquic.h"
#include "vquic_int.h"
#include "vquic-tls.h"
#include "curl_quiche.h"
-#include "transfer.h"
-#include "inet_pton.h"
-#include "vtls/openssl.h"
-#include "vtls/keylog.h"
-#include "vtls/vtls.h"
+#include "../transfer.h"
+#include "../curlx/inet_pton.h"
+#include "../vtls/openssl.h"
+#include "../vtls/keylog.h"
+#include "../vtls/vtls.h"
/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_printf.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
/* HTTP/3 error values defined in RFC 9114, ch. 8.1 */
#define CURL_H3_NO_ERROR (0x0100)
@@ -97,7 +97,7 @@ struct cf_quiche_ctx {
struct curltime started_at; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash_offt streams; /* hash `data->mid` to `stream_ctx` */
+ struct uint_hash streams; /* hash `data->mid` to `stream_ctx` */
curl_off_t data_recvd;
BIT(initialized);
BIT(goaway); /* got GOAWAY from server */
@@ -115,7 +115,7 @@ static void quiche_debug_log(const char *line, void *argp)
}
#endif
-static void h3_stream_hash_free(curl_off_t id, void *stream);
+static void h3_stream_hash_free(unsigned int id, void *stream);
static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
{
@@ -128,7 +128,7 @@ static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
#endif
Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
H3_STREAM_POOL_SPARES);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
+ Curl_uint_hash_init(&ctx->streams, 63, h3_stream_hash_free);
ctx->data_recvd = 0;
ctx->initialized = TRUE;
}
@@ -142,7 +142,7 @@ static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
Curl_ssl_peer_cleanup(&ctx->peer);
vquic_ctx_free(&ctx->q);
Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_hash_offt_destroy(&ctx->streams);
+ Curl_uint_hash_destroy(&ctx->streams);
}
free(ctx);
}
@@ -165,7 +165,7 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
/**
* All about the H3 internals of a stream
*/
-struct stream_ctx {
+struct h3_stream_ctx {
curl_uint64_t id; /* HTTP/3 protocol stream identifier */
struct bufq recvbuf; /* h3 response */
struct h1_req_parser h1; /* h1 request parsing */
@@ -179,26 +179,23 @@ struct stream_ctx {
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-
-static void h3_stream_ctx_free(struct stream_ctx *stream)
+static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
{
Curl_bufq_free(&stream->recvbuf);
Curl_h1_req_parse_free(&stream->h1);
free(stream);
}
-static void h3_stream_hash_free(curl_off_t id, void *stream)
+static void h3_stream_hash_free(unsigned int id, void *stream)
{
(void)id;
DEBUGASSERT(stream);
- h3_stream_ctx_free((struct stream_ctx *)stream);
+ h3_stream_ctx_free((struct h3_stream_ctx *)stream);
}
typedef bool cf_quiche_svisit(struct Curl_cfilter *cf,
struct Curl_easy *sdata,
- struct stream_ctx *stream,
+ struct h3_stream_ctx *stream,
void *user_data);
struct cf_quiche_visit_ctx {
@@ -208,11 +205,11 @@ struct cf_quiche_visit_ctx {
void *user_data;
};
-static bool cf_quiche_stream_do(curl_off_t mid, void *val, void *user_data)
+static bool cf_quiche_stream_do(unsigned int mid, void *val, void *user_data)
{
struct cf_quiche_visit_ctx *vctx = user_data;
- struct stream_ctx *stream = val;
- struct Curl_easy *sdata = Curl_multi_get_handle(vctx->multi, mid);
+ struct h3_stream_ctx *stream = val;
+ struct Curl_easy *sdata = Curl_multi_get_easy(vctx->multi, mid);
if(sdata)
return vctx->cb(vctx->cf, sdata, stream, vctx->user_data);
return TRUE;
@@ -229,12 +226,12 @@ static void cf_quiche_for_all_streams(struct Curl_cfilter *cf,
vctx.multi = multi;
vctx.cb = do_cb;
vctx.user_data = user_data;
- Curl_hash_offt_visit(&ctx->streams, cf_quiche_stream_do, &vctx);
+ Curl_uint_hash_visit(&ctx->streams, cf_quiche_stream_do, &vctx);
}
static bool cf_quiche_do_resume(struct Curl_cfilter *cf,
struct Curl_easy *sdata,
- struct stream_ctx *stream,
+ struct h3_stream_ctx *stream,
void *user_data)
{
(void)user_data;
@@ -248,7 +245,7 @@ static bool cf_quiche_do_resume(struct Curl_cfilter *cf,
static bool cf_quiche_do_expire(struct Curl_cfilter *cf,
struct Curl_easy *sdata,
- struct stream_ctx *stream,
+ struct h3_stream_ctx *stream,
void *user_data)
{
(void)stream;
@@ -262,7 +259,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream)
return CURLE_OK;
@@ -276,7 +273,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
+ if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -287,7 +284,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
(void)cf;
@@ -306,7 +303,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
if(result)
CURL_TRC_CF(data, cf, "data_done, flush egress -> %d", result);
}
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_uint_hash_remove(&ctx->streams, data->mid);
}
}
@@ -314,7 +311,7 @@ static void h3_drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
unsigned char bits;
(void)cf;
@@ -345,7 +342,7 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
const void *mem, size_t memlen)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result = CURLE_OK;
ssize_t nwritten;
@@ -376,7 +373,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
{
struct cb_ctx *x = argp;
struct cf_quiche_ctx *ctx = x->cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
CURLcode result;
if(!stream)
@@ -416,7 +413,7 @@ static ssize_t stream_resp_read(void *reader_ctx,
{
struct cb_ctx *x = reader_ctx;
struct cf_quiche_ctx *ctx = x->cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
ssize_t nread;
if(!stream) {
@@ -440,7 +437,7 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nwritten;
struct cb_ctx cb_ctx;
CURLcode result = CURLE_OK;
@@ -498,7 +495,7 @@ static const char *cf_ev_name(quiche_h3_event *ev)
static CURLcode h3_process_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct stream_ctx *stream,
+ struct h3_stream_ctx *stream,
quiche_h3_event *ev)
{
struct cb_ctx cb_ctx;
@@ -561,7 +558,7 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
static CURLcode cf_quiche_ev_process(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct stream_ctx *stream,
+ struct h3_stream_ctx *stream,
quiche_h3_event *ev)
{
CURLcode result = h3_process_event(cf, data, stream, ev);
@@ -581,13 +578,13 @@ struct cf_quich_disp_ctx {
CURLcode result;
};
-static bool cf_quiche_disp_event(curl_off_t mid, void *val, void *user_data)
+static bool cf_quiche_disp_event(unsigned int mid, void *val, void *user_data)
{
struct cf_quich_disp_ctx *dctx = user_data;
- struct stream_ctx *stream = val;
+ struct h3_stream_ctx *stream = val;
if(stream->id == dctx->stream_id) {
- struct Curl_easy *sdata = Curl_multi_get_handle(dctx->multi, mid);
+ struct Curl_easy *sdata = Curl_multi_get_easy(dctx->multi, mid);
if(sdata)
dctx->result = cf_quiche_ev_process(dctx->cf, sdata, stream, dctx->ev);
return FALSE; /* stop iterating */
@@ -599,7 +596,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = NULL;
+ struct h3_stream_ctx *stream = NULL;
quiche_h3_event *ev;
/* Take in the events and distribute them to the transfers. */
@@ -630,7 +627,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
else {
/* another transfer, do not return errors, as they are not for
* the calling transfer */
- Curl_hash_offt_visit(&ctx->streams, cf_quiche_disp_event, &dctx);
+ Curl_uint_hash_visit(&ctx->streams, cf_quiche_disp_event, &dctx);
quiche_h3_event_free(ev);
}
}
@@ -848,7 +845,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
DEBUGASSERT(stream);
@@ -880,7 +877,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
ssize_t nread = -1;
CURLcode result;
@@ -953,7 +950,7 @@ out:
static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct stream_ctx *stream,
+ struct h3_stream_ctx *stream,
const void *buf, size_t len, bool eos,
CURLcode *err)
{
@@ -1012,7 +1009,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
size_t nheader, i;
curl_int64_t stream3_id;
struct dynhds h2_headers;
@@ -1132,7 +1129,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
CURLcode result;
ssize_t nwritten;
@@ -1191,7 +1188,7 @@ static bool stream_is_writeable(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
return stream && (quiche_conn_stream_writable(
ctx->qconn, (curl_uint64_t)stream->id, 1) > 0);
@@ -1209,7 +1206,7 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(want_recv || want_send) {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
bool c_exhaust, s_exhaust;
c_exhaust = FALSE; /* Have not found any call in quiche that tells
@@ -1232,7 +1229,7 @@ static bool cf_quiche_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- const struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ const struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
return stream && !Curl_bufq_is_empty(&stream->recvbuf);
}
@@ -1269,7 +1266,7 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
h3_data_done(cf, data);
break;
case CF_CTRL_DATA_DONE_SEND: {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream && !stream->send_closed) {
unsigned char body[1];
ssize_t sent;
@@ -1283,7 +1280,7 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
break;
}
case CF_CTRL_DATA_IDLE: {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
if(stream && !stream->closed) {
result = cf_flush_egress(cf, data);
if(result)
@@ -1321,7 +1318,6 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
return CURLE_FAILED_INIT;
}
quiche_config_enable_pacing(ctx->cfg, FALSE);
- quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
/* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);
@@ -1456,7 +1452,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
if(quiche_conn_is_established(ctx->qconn)) {
ctx->handshake_at = ctx->q.last_op;
CURL_TRC_CF(data, cf, "handshake complete after %dms",
- (int)Curl_timediff(ctx->handshake_at, ctx->started_at));
+ (int)curlx_timediff(ctx->handshake_at, ctx->started_at));
result = cf_quiche_verify_peer(cf, data);
if(!result) {
CURL_TRC_CF(data, cf, "peer verified");
@@ -1572,19 +1568,19 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
switch(query) {
case CF_QUERY_MAX_CONCURRENT: {
- curl_uint64_t max_streams = CONN_INUSE(cf->conn);
+ curl_uint64_t max_streams = CONN_ATTACHED(cf->conn);
if(!ctx->goaway) {
max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
}
*pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
- "MAX_CONCURRENT -> %d (%zu in use)",
- cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
+ "MAX_CONCURRENT -> %d (%u in use)",
+ cf->conn->connection_id, *pres1, CONN_ATTACHED(cf->conn));
return CURLE_OK;
}
case CF_QUERY_CONNECT_REPLY_MS:
if(ctx->q.got_first_byte) {
- timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
+ timediff_t ms = curlx_timediff(ctx->q.first_byte_at, ctx->started_at);
*pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
}
else
diff --git a/libs/libcurl/src/vquic/curl_quiche.h b/libs/libcurl/src/vquic/curl_quiche.h
index 6af88dd479..caf21e0137 100644
--- a/libs/libcurl/src/vquic/curl_quiche.h
+++ b/libs/libcurl/src/vquic/curl_quiche.h
@@ -24,7 +24,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_QUICHE
diff --git a/libs/libcurl/src/vquic/vquic-tls.c b/libs/libcurl/src/vquic/vquic-tls.c
index feae0f594a..7eb343538e 100644
--- a/libs/libcurl/src/vquic/vquic-tls.c
+++ b/libs/libcurl/src/vquic/vquic-tls.c
@@ -22,41 +22,41 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#if defined(USE_HTTP3) && \
(defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
#ifdef USE_OPENSSL
#include <openssl/err.h>
-#include "vtls/openssl.h"
+#include "../vtls/openssl.h"
#elif defined(USE_GNUTLS)
#include <gnutls/abstract.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/crypto.h>
#include <nettle/sha2.h>
-#include "vtls/gtls.h"
+#include "../vtls/gtls.h"
#elif defined(USE_WOLFSSL)
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/quic.h>
-#include "vtls/wolfssl.h"
+#include "../vtls/wolfssl.h"
#endif
-#include "urldata.h"
-#include "curl_trc.h"
-#include "cfilters.h"
-#include "multiif.h"
-#include "vtls/keylog.h"
-#include "vtls/vtls.h"
-#include "vtls/vtls_scache.h"
+#include "../urldata.h"
+#include "../curl_trc.h"
+#include "../cfilters.h"
+#include "../multiif.h"
+#include "../vtls/keylog.h"
+#include "../vtls/vtls.h"
+#include "../vtls/vtls_scache.h"
#include "vquic-tls.h"
/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_printf.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
@@ -179,16 +179,16 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
#elif defined(USE_WOLFSSL)
(void)data;
if(conn_config->verifyhost) {
- if(peer->sni) {
- WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.ssl);
- if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
- == WOLFSSL_FAILURE) {
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- wolfSSL_X509_free(cert);
+ char *snihost = peer->sni ? peer->sni : peer->hostname;
+ WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.ssl);
+ if(wolfSSL_X509_check_host(cert, snihost, strlen(snihost), 0, NULL)
+ == WOLFSSL_FAILURE) {
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
-
+ wolfSSL_X509_free(cert);
}
+ if(!result)
+ result = Curl_wssl_verify_pinned(cf, data, &ctx->wssl);
#endif
/* on error, remove any session we might have in the pool */
if(result)
diff --git a/libs/libcurl/src/vquic/vquic-tls.h b/libs/libcurl/src/vquic/vquic-tls.h
index 7bc24819d8..0b9a1ec4f7 100644
--- a/libs/libcurl/src/vquic/vquic-tls.h
+++ b/libs/libcurl/src/vquic/vquic-tls.h
@@ -24,16 +24,16 @@
*
***************************************************************************/
-#include "curl_setup.h"
-#include "bufq.h"
-#include "vtls/vtls.h"
-#include "vtls/vtls_int.h"
-#include "vtls/openssl.h"
+#include "../curl_setup.h"
+#include "../bufq.h"
+#include "../vtls/vtls.h"
+#include "../vtls/vtls_int.h"
+#include "../vtls/openssl.h"
#if defined(USE_HTTP3) && \
(defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
-#include "vtls/wolfssl.h"
+#include "../vtls/wolfssl.h"
struct ssl_peer;
struct Curl_ssl_session;
diff --git a/libs/libcurl/src/vquic/vquic.c b/libs/libcurl/src/vquic/vquic.c
index f24c9dc799..4b7ab97c5b 100644
--- a/libs/libcurl/src/vquic/vquic.c
+++ b/libs/libcurl/src/vquic/vquic.c
@@ -22,7 +22,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
@@ -30,26 +30,26 @@
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
-#include "urldata.h"
-#include "bufq.h"
-#include "dynbuf.h"
-#include "cfilters.h"
-#include "curl_trc.h"
+#include "../urldata.h"
+#include "../bufq.h"
+#include "../curlx/dynbuf.h"
+#include "../cfilters.h"
+#include "../curl_trc.h"
#include "curl_msh3.h"
#include "curl_ngtcp2.h"
#include "curl_osslq.h"
#include "curl_quiche.h"
-#include "multiif.h"
-#include "rand.h"
+#include "../multiif.h"
+#include "../rand.h"
#include "vquic.h"
#include "vquic_int.h"
-#include "strerror.h"
-#include "strparse.h"
+#include "../strerror.h"
+#include "../curlx/strparse.h"
/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_printf.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
#ifdef USE_HTTP3
@@ -58,6 +58,16 @@
#define NW_SEND_CHUNKS 2
+int Curl_vquic_init(void)
+{
+#if defined(USE_NGTCP2) && defined(OPENSSL_QUIC_API2)
+ if(ngtcp2_crypto_ossl_init())
+ return 0;
+#endif
+
+ return 1;
+}
+
void Curl_quic_ver(char *p, size_t len)
{
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
@@ -85,7 +95,7 @@ CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx)
const char *p = getenv("CURL_DBG_QUIC_WBLOCK");
if(p) {
curl_off_t l;
- if(!Curl_str_number(&p, &l, 100))
+ if(!curlx_str_number(&p, &l, 100))
qctx->wblock_percent = (int)l;
}
}
@@ -102,7 +112,7 @@ void vquic_ctx_free(struct cf_quic_ctx *qctx)
void vquic_ctx_update_time(struct cf_quic_ctx *qctx)
{
- qctx->last_op = Curl_now();
+ qctx->last_op = curlx_now();
}
static CURLcode send_packet_no_gso(struct Curl_cfilter *cf,
@@ -471,19 +481,20 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
size_t pktlen;
size_t offset, to;
- msg_iov.iov_base = buf;
- msg_iov.iov_len = (int)sizeof(buf);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &msg_iov;
- msg.msg_iovlen = 1;
- msg.msg_control = msg_ctrl;
-
DEBUGASSERT(max_pkts > 0);
for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
+ /* fully initialise this on each call to `recvmsg()`. There seem to
+ * operating systems out there that mess with `msg_iov.iov_len`. */
+ memset(&msg, 0, sizeof(msg));
+ msg_iov.iov_base = buf;
+ msg_iov.iov_len = (int)sizeof(buf);
+ msg.msg_iov = &msg_iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = msg_ctrl;
msg.msg_name = &remote_addr;
msg.msg_namelen = sizeof(remote_addr);
msg.msg_controllen = sizeof(msg_ctrl);
+
while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
SOCKERRNO == SOCKEINTR)
;
@@ -640,25 +651,25 @@ CURLcode Curl_qlogdir(struct Curl_easy *data,
struct dynbuf fname;
CURLcode result;
unsigned int i;
- Curl_dyn_init(&fname, DYN_QLOG_NAME);
- result = Curl_dyn_add(&fname, qlog_dir);
+ curlx_dyn_init(&fname, DYN_QLOG_NAME);
+ result = curlx_dyn_add(&fname, qlog_dir);
if(!result)
- result = Curl_dyn_add(&fname, "/");
+ result = curlx_dyn_add(&fname, "/");
for(i = 0; (i < scidlen) && !result; i++) {
char hex[3];
msnprintf(hex, 3, "%02x", scid[i]);
- result = Curl_dyn_add(&fname, hex);
+ result = curlx_dyn_add(&fname, hex);
}
if(!result)
- result = Curl_dyn_add(&fname, ".sqlog");
+ result = curlx_dyn_add(&fname, ".sqlog");
if(!result) {
- int qlogfd = open(Curl_dyn_ptr(&fname), O_WRONLY|O_CREAT|CURL_O_BINARY,
+ int qlogfd = open(curlx_dyn_ptr(&fname), O_WRONLY|O_CREAT|CURL_O_BINARY,
data->set.new_file_perms);
if(qlogfd != -1)
*qlogfdp = qlogfd;
}
- Curl_dyn_free(&fname);
+ curlx_dyn_free(&fname);
if(result)
return result;
}
diff --git a/libs/libcurl/src/vquic/vquic.h b/libs/libcurl/src/vquic/vquic.h
index 8d7474fbdc..0534d49286 100644
--- a/libs/libcurl/src/vquic/vquic.h
+++ b/libs/libcurl/src/vquic/vquic.h
@@ -24,7 +24,7 @@
*
***************************************************************************/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_HTTP3
struct Curl_cfilter;
@@ -33,6 +33,7 @@ struct connectdata;
struct Curl_addrinfo;
void Curl_quic_ver(char *p, size_t len);
+int Curl_vquic_init(void);
CURLcode Curl_qlogdir(struct Curl_easy *data,
unsigned char *scid,
@@ -48,6 +49,8 @@ CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
extern struct Curl_cftype Curl_cft_http3;
+#else
+#define Curl_vquic_init() 1
#endif /* !USE_HTTP3 */
CURLcode Curl_conn_may_http3(struct Curl_easy *data,
diff --git a/libs/libcurl/src/vquic/vquic_int.h b/libs/libcurl/src/vquic/vquic_int.h
index 52203735bf..75dfd33d26 100644
--- a/libs/libcurl/src/vquic/vquic_int.h
+++ b/libs/libcurl/src/vquic/vquic_int.h
@@ -24,15 +24,13 @@
*
***************************************************************************/
-#include "curl_setup.h"
-#include "bufq.h"
+#include "../curl_setup.h"
+#include "../bufq.h"
#ifdef USE_HTTP3
#define MAX_PKT_BURST 10
#define MAX_UDP_PAYLOAD_SIZE 1452
-/* Default QUIC connection timeout we announce from our side */
-#define CURL_QUIC_MAX_IDLE_MS (120 * 1000)
struct cf_quic_ctx {
curl_socket_t sockfd; /* connected UDP socket */
@@ -53,6 +51,9 @@ struct cf_quic_ctx {
BIT(no_gso); /* do not use gso on sending */
};
+#define H3_STREAM_CTX(ctx,data) \
+ (data ? Curl_uint_hash_get(&(ctx)->streams, (data)->mid) : NULL)
+
CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx);
void vquic_ctx_free(struct cf_quic_ctx *qctx);