summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vquic
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2024-09-11 21:49:43 +0300
committerdartraiden <wowemuh@gmail.com>2024-09-11 21:52:35 +0300
commitc36db68a5f58ec6c9135eff778b6e77c30e58088 (patch)
tree22eea126db82c50388c9f94cd683d6ec6f04e6cb /libs/libcurl/src/vquic
parent02bb82c1c0a4031e7b2f5578370fa5acd620f8e1 (diff)
libcurl: update to 8.10.0
Diffstat (limited to 'libs/libcurl/src/vquic')
-rw-r--r--libs/libcurl/src/vquic/curl_msh3.c66
-rw-r--r--libs/libcurl/src/vquic/curl_ngtcp2.c191
-rw-r--r--libs/libcurl/src/vquic/curl_osslq.c163
-rw-r--r--libs/libcurl/src/vquic/curl_quiche.c331
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.c2
-rw-r--r--libs/libcurl/src/vquic/vquic.c4
6 files changed, 402 insertions, 355 deletions
diff --git a/libs/libcurl/src/vquic/curl_msh3.c b/libs/libcurl/src/vquic/curl_msh3.c
index a780acc31f..464f7c5af6 100644
--- a/libs/libcurl/src/vquic/curl_msh3.c
+++ b/libs/libcurl/src/vquic/curl_msh3.c
@@ -119,16 +119,38 @@ 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 streams; /* hash `data->id` to `stream_ctx` */
+ struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */
/* Flags written by msh3/msquic thread */
bool handshake_complete;
bool handshake_succeeded;
bool connected;
+ BIT(initialized);
/* Flags written by curl thread */
BIT(verbose);
BIT(active);
};
+static void h3_stream_hash_free(void *stream);
+
+static void cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
+ const struct Curl_addrinfo *ai)
+{
+ DEBUGASSERT(!ctx->initialized);
+ Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
+ Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
+ ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+ ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
+ ctx->initialized = TRUE;
+}
+
+static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx)
+{
+ if(ctx && ctx->initialized) {
+ Curl_hash_destroy(&ctx->streams);
+ }
+ free(ctx);
+}
+
static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data);
/* How to access `call_data` from a cf_msh3 filter */
@@ -158,7 +180,7 @@ struct stream_ctx {
};
#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)((data && ctx)? \
- Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+ Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
static void h3_stream_ctx_free(struct stream_ctx *stream)
{
@@ -191,7 +213,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->id, stream)) {
+ if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -207,7 +229,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)cf;
if(stream) {
CURL_TRC_CF(data, cf, "easy handle is done");
- Curl_hash_offt_remove(&ctx->streams, data->id);
+ Curl_hash_offt_remove(&ctx->streams, data->mid);
}
}
@@ -593,7 +615,8 @@ out:
}
static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, CURLcode *err)
+ const void *buf, size_t len, bool eos,
+ CURLcode *err)
{
struct cf_msh3_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -603,7 +626,6 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
size_t nheader, i;
ssize_t nwritten = -1;
struct cf_call_data save;
- bool eos;
CF_DATA_SAVE(save, cf, data);
@@ -646,21 +668,6 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
nva[i].ValueLength = e->valuelen;
}
- switch(data->state.httpreq) {
- case HTTPREQ_POST:
- case HTTPREQ_POST_FORM:
- case HTTPREQ_POST_MIME:
- case HTTPREQ_PUT:
- /* known request body size or -1 */
- eos = FALSE;
- break;
- default:
- /* there is not request body */
- eos = TRUE;
- stream->upload_done = TRUE;
- break;
- }
-
CURL_TRC_CF(data, cf, "req: send %zu headers", nheader);
stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data,
nva, nheader,
@@ -813,7 +820,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
CURLcode result;
bool verify;
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
+ DEBUGASSERT(ctx->initialized);
conn_config = Curl_ssl_cf_get_primary_config(cf);
if(!conn_config)
return CURLE_FAILED_INIT;
@@ -904,7 +911,6 @@ static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "handshake succeeded");
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
- cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
cf->connected = TRUE;
cf->conn->alpn = CURL_HTTP_VERSION_3;
*done = TRUE;
@@ -940,7 +946,6 @@ static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data)
MsH3ApiClose(ctx->api);
ctx->api = NULL;
}
- Curl_hash_destroy(&ctx->streams);
if(ctx->active) {
/* We share our socket at cf->conn->sock[cf->sockindex] when active.
@@ -979,10 +984,11 @@ static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
CF_DATA_SAVE(save, cf, data);
cf_msh3_close(cf, data);
- free(cf->ctx);
- cf->ctx = NULL;
+ if(cf->ctx) {
+ cf_msh3_ctx_free(cf->ctx);
+ cf->ctx = NULL;
+ }
/* no CF_DATA_RESTORE(cf, save); its gone */
-
}
static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
@@ -1081,9 +1087,7 @@ CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
- ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
- ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
+ cf_msh3_ctx_init(ctx, ai);
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
@@ -1091,7 +1095,7 @@ out:
*pcf = (!result)? cf : NULL;
if(result) {
Curl_safefree(cf);
- Curl_safefree(ctx);
+ cf_msh3_ctx_free(ctx);
}
return result;
diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.c b/libs/libcurl/src/vquic/curl_ngtcp2.c
index 790e3c6ff4..54f3ce6929 100644
--- a/libs/libcurl/src/vquic/curl_ngtcp2.c
+++ b/libs/libcurl/src/vquic/curl_ngtcp2.c
@@ -132,12 +132,13 @@ struct cf_ngtcp2_ctx {
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
struct dynbuf scratch; /* temp buffer for header construction */
- struct Curl_hash streams; /* hash `data->id` to `h3_stream_ctx` */
+ struct Curl_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 */
int qlogfd;
+ BIT(initialized);
BIT(shutdown_started); /* queued shutdown packets */
};
@@ -146,6 +147,34 @@ struct cf_ngtcp2_ctx {
#define CF_CTX_CALL_DATA(cf) \
((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
+static void h3_stream_hash_free(void *stream);
+
+static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx)
+{
+ DEBUGASSERT(!ctx->initialized);
+ 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);
+ ctx->initialized = TRUE;
+}
+
+static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx)
+{
+ if(ctx && ctx->initialized) {
+ Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_dyn_free(&ctx->scratch);
+ Curl_hash_clean(&ctx->streams);
+ Curl_hash_destroy(&ctx->streams);
+ Curl_ssl_peer_cleanup(&ctx->peer);
+ }
+ free(ctx);
+}
+
struct pkt_io_ctx;
static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -174,7 +203,7 @@ struct h3_stream_ctx {
};
#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+ 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))))
@@ -197,10 +226,8 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- if(!data) {
- failf(data, "initialization failure, transfer not http initialized");
+ if(!data)
return CURLE_FAILED_INIT;
- }
if(stream)
return CURLE_OK;
@@ -216,7 +243,7 @@ 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->id, stream)) {
+ if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -241,7 +268,7 @@ static void cf_ngtcp2_stream_close(struct Curl_cfilter *cf,
NGHTTP3_H3_REQUEST_CANCELLED);
result = cf_progress_egress(cf, data, NULL);
if(result)
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cancel stream -> %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cancel stream -> %d",
stream->id, result);
}
}
@@ -252,10 +279,10 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] easy handle is done",
+ 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->id);
+ Curl_hash_offt_remove(&ctx->streams, data->mid);
}
}
@@ -265,7 +292,6 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
struct h3_stream_ctx **pstream)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct Curl_easy *sdata;
struct h3_stream_ctx *stream;
(void)cf;
@@ -275,8 +301,10 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
return data;
}
else {
+ struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
- for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
+ struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn != data->conn)
continue;
stream = H3_STREAM_CTX(ctx, sdata);
@@ -490,12 +518,12 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
if(!data)
data = CF_DATA_CURRENT(cf);
if(data)
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read_stream(len=%zu) -> %zd",
+ 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);
if(data && stream) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] error on known stream, "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] error on known stream, "
"reset=%d, closed=%d",
stream_id, stream->reset, stream->closed);
}
@@ -555,8 +583,8 @@ static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
}
rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, app_error_code);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] quic close(app_error=%"
- CURL_PRIu64 ") -> %d", stream_id, (curl_uint64_t)app_error_code,
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] quic close(app_error=%"
+ FMT_PRIu64 ") -> %d", stream_id, (curl_uint64_t)app_error_code,
rv);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
cf_ngtcp2_h3_err_set(cf, data, rv);
@@ -581,7 +609,7 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t sid,
(void)data;
rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -619,8 +647,8 @@ static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
(void)tconn;
ctx->max_bidi_streams = max_streams;
if(data)
- CURL_TRC_CF(data, cf, "max bidi streams now %" CURL_PRIu64
- ", used %" CURL_PRIu64, (curl_uint64_t)ctx->max_bidi_streams,
+ CURL_TRC_CF(data, cf, "max bidi streams now %" FMT_PRIu64
+ ", used %" FMT_PRIu64, (curl_uint64_t)ctx->max_bidi_streams,
(curl_uint64_t)ctx->used_bidi_streams);
return 0;
}
@@ -646,8 +674,7 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t sid,
}
s_data = get_stream_easy(cf, data, stream_id, &stream);
if(s_data && stream && stream->quic_flow_blocked) {
- CURL_TRC_CF(s_data, cf, "[%" CURL_PRId64 "] unblock quic flow",
- stream_id);
+ CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow", stream_id);
stream->quic_flow_blocked = FALSE;
h3_drain_stream(cf, s_data);
}
@@ -705,6 +732,11 @@ static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level,
return 0;
}
+#if defined(_MSC_VER) && defined(_DLL)
+# pragma warning(push)
+# pragma warning(disable:4232) /* MSVC extension, dllimport identity */
+#endif
+
static ngtcp2_callbacks ng_callbacks = {
ngtcp2_crypto_client_initial_cb,
NULL, /* recv_client_initial */
@@ -748,6 +780,10 @@ static ngtcp2_callbacks ng_callbacks = {
NULL, /* early_data_rejected */
};
+#if defined(_MSC_VER) && defined(_DLL)
+# pragma warning(pop)
+#endif
+
/**
* Connection maintenance like timeouts on packet ACKs etc. are done by us, not
* the OS like for TCP. POLL events on the socket therefore are not
@@ -858,11 +894,11 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid,
if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
stream->reset = TRUE;
stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] RESET: error %" CURL_PRIu64,
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] RESET: error %" FMT_PRIu64,
stream->id, stream->error3);
}
else {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] CLOSED", stream->id);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->id);
}
h3_drain_stream(cf, data);
return 0;
@@ -878,7 +914,7 @@ static void h3_xfer_write_resp_hd(struct Curl_cfilter *cf,
if(!stream->xfer_result) {
stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
if(stream->xfer_result)
- CURL_TRC_CF(data, cf, "[%"CURL_PRId64"] error %d writing %zu "
+ CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu "
"bytes of headers", stream->id, stream->xfer_result, blen);
}
}
@@ -894,7 +930,7 @@ static void h3_xfer_write_resp(struct Curl_cfilter *cf,
stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
/* If the transfer write is errored, we do not want any more data */
if(stream->xfer_result) {
- CURL_TRC_CF(data, cf, "[%"CURL_PRId64"] error %d writing %zu bytes "
+ CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu bytes "
"of data", stream->id, stream->xfer_result, blen);
}
}
@@ -917,12 +953,12 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
h3_xfer_write_resp(cf, data, stream, (char *)buf, blen, FALSE);
if(blen) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] ACK %zu bytes of DATA",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] ACK %zu bytes of DATA",
stream->id, blen);
ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen);
ngtcp2_conn_extend_max_offset(ctx->qconn, blen);
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] DATA len=%zu", stream->id, blen);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu", stream->id, blen);
return 0;
}
@@ -960,7 +996,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
/* add a CRLF only if we have received some headers */
h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] end_headers, status=%d",
stream_id, stream->status_code);
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -1008,7 +1044,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
if(!result)
h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
Curl_dyn_len(&ctx->scratch), FALSE);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] status: %s",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s",
stream_id, Curl_dyn_ptr(&ctx->scratch));
if(result) {
return -1;
@@ -1016,7 +1052,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
}
else {
/* store as an HTTP1-style header */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] header: %.*s: %.*s",
+ 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);
@@ -1049,7 +1085,7 @@ static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id,
app_error_code);
if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
}
return 0;
@@ -1068,9 +1104,9 @@ static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id,
app_error_code);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
}
return 0;
@@ -1163,14 +1199,13 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
(void)cf;
if(stream->reset) {
- failf(data,
- "HTTP/3 stream %" CURL_PRId64 " reset by server", stream->id);
+ failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
*err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
failf(data,
- "HTTP/3 stream %" CURL_PRId64 " was closed cleanly, but before "
+ "HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before "
"getting all response header fields, treated as error",
stream->id);
*err = CURLE_HTTP3;
@@ -1217,7 +1252,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(stream->xfer_result) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
cf_ngtcp2_stream_close(cf, data, stream);
*err = stream->xfer_result;
nread = -1;
@@ -1242,7 +1277,7 @@ out:
nread = -1;
}
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
stream? stream->id : -1, blen, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
@@ -1275,7 +1310,7 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
int rv = nghttp3_conn_resume_stream(conn, stream_id);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- return NGTCP2_ERR_CALLBACK_FAILURE;
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
}
}
return 0;
@@ -1333,14 +1368,13 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
}
else if(!nwritten) {
/* Not EOF, and nothing to give, we signal WOULDBLOCK. */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> AGAIN",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN",
stream->id);
return NGHTTP3_ERR_WOULDBLOCK;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> "
- "%d vecs%s with %zu (buffered=%zu, left=%"
- CURL_FORMAT_CURL_OFF_T ")",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
+ "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
stream->id, (int)nvecs,
*pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
nwritten, Curl_bufq_len(&stream->sendbuf),
@@ -1454,12 +1488,12 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
if(rc) {
switch(rc) {
case NGHTTP3_ERR_CONN_CLOSING:
- CURL_TRC_CF(data, cf, "h3sid[%" CURL_PRId64 "] failed to send, "
+ CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send, "
"connection is closing", stream->id);
break;
default:
- CURL_TRC_CF(data, cf, "h3sid[%" CURL_PRId64 "] failed to send -> "
- "%d (%s)", stream->id, rc, ngtcp2_strerror(rc));
+ CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send -> "
+ "%d (%s)", stream->id, rc, nghttp3_strerror(rc));
break;
}
*err = CURLE_SEND_ERROR;
@@ -1468,10 +1502,10 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
}
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" CURL_PRId64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" FMT_PRId64 "] OPENED stream for %s",
stream->id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" CURL_PRId64 "] [%.*s: %.*s]", stream->id,
+ infof(data, "[HTTP/3] [%" FMT_PRId64 "] [%.*s: %.*s]", stream->id,
(int)nva[i].namelen, nva[i].name,
(int)nva[i].valuelen, nva[i].value);
}
@@ -1484,7 +1518,8 @@ out:
}
static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, CURLcode *err)
+ const void *buf, size_t len, bool eos,
+ CURLcode *err)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -1500,6 +1535,7 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
pktx_init(&pktx, cf, data);
*err = CURLE_OK;
+ (void)eos; /* TODO: use for stream EOF and block handling */
result = cf_progress_ingress(cf, data, &pktx);
if(result) {
*err = result;
@@ -1521,7 +1557,7 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
stream = H3_STREAM_CTX(ctx, data);
}
else if(stream->xfer_result) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
cf_ngtcp2_stream_close(cf, data, stream);
*err = stream->xfer_result;
sent = -1;
@@ -1534,13 +1570,13 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* body. This happens on 30x or 40x responses.
* We silently discard the data sent, since this is not a transport
* error situation. */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
sent = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
"-> stream closed", stream->id, len);
*err = CURLE_HTTP3;
sent = -1;
@@ -1554,7 +1590,7 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
else {
sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send, add to "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
"sendbuf(len=%zu) -> %zd, %d",
stream->id, len, sent, *err);
if(sent < 0) {
@@ -1576,7 +1612,7 @@ out:
*err = result;
sent = -1;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
stream? stream->id : -1, len, sent, *err);
CF_DATA_RESTORE(cf, save);
return sent;
@@ -1589,7 +1625,6 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
- cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
}
@@ -1723,7 +1758,7 @@ static ssize_t read_pkt_to_send(void *userp,
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
DEBUGASSERT(ndatalen == -1);
nghttp3_conn_block_stream(ctx->h3conn, stream_id);
- CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRId64 "] block quic flow",
+ CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] block quic flow",
(curl_int64_t)stream_id);
DEBUGASSERT(stream);
if(stream)
@@ -1960,27 +1995,22 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
return result;
}
-static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
+static void cf_ngtcp2_ctx_close(struct cf_ngtcp2_ctx *ctx)
{
struct cf_call_data save = ctx->call_data;
+ if(!ctx->initialized)
+ return;
if(ctx->qlogfd != -1) {
close(ctx->qlogfd);
}
+ ctx->qlogfd = -1;
Curl_vquic_tls_cleanup(&ctx->tls);
vquic_ctx_free(&ctx->q);
if(ctx->h3conn)
nghttp3_conn_del(ctx->h3conn);
if(ctx->qconn)
ngtcp2_conn_del(ctx->qconn);
- Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_dyn_free(&ctx->scratch);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
- Curl_ssl_peer_cleanup(&ctx->peer);
-
- memset(ctx, 0, sizeof(*ctx));
- ctx->qlogfd = -1;
ctx->call_data = save;
}
@@ -2027,7 +2057,7 @@ static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf,
(uint8_t *)buffer, sizeof(buffer),
&ctx->last_error, pktx.ts);
CURL_TRC_CF(data, cf, "start shutdown(err_type=%d, err_code=%"
- CURL_PRIu64 ") -> %d", ctx->last_error.type,
+ FMT_PRIu64 ") -> %d", ctx->last_error.type,
(curl_uint64_t)ctx->last_error.error_code, (int)nwritten);
if(nwritten > 0) {
Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
@@ -2085,7 +2115,7 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
CF_DATA_SAVE(save, cf, data);
if(ctx && ctx->qconn) {
cf_ngtcp2_conn_close(cf, data);
- cf_ngtcp2_ctx_clear(ctx);
+ cf_ngtcp2_ctx_close(ctx);
CURL_TRC_CF(data, cf, "close");
}
cf->connected = FALSE;
@@ -2094,18 +2124,11 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
CURL_TRC_CF(data, cf, "destroy");
- if(ctx) {
- cf_ngtcp2_ctx_clear(ctx);
- free(ctx);
+ if(cf->ctx) {
+ cf_ngtcp2_ctx_free(cf->ctx);
+ cf->ctx = NULL;
}
- cf->ctx = NULL;
- /* No CF_DATA_RESTORE(cf, save) possible */
- (void)save;
}
#ifdef USE_OPENSSL
@@ -2187,14 +2210,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
const struct Curl_sockaddr_ex *sockaddr = NULL;
int qfd;
- 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);
-
+ DEBUGASSERT(ctx->initialized);
result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
return result;
@@ -2389,7 +2405,7 @@ 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[%" CURL_FORMAT_CURL_OFF_T "]: "
+ 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));
CF_DATA_RESTORE(cf, save);
@@ -2509,8 +2525,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- ctx->qlogfd = -1;
- cf_ngtcp2_ctx_clear(ctx);
+ cf_ngtcp2_ctx_init(ctx);
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
if(result)
@@ -2531,7 +2546,7 @@ out:
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
Curl_safefree(cf);
- Curl_safefree(ctx);
+ cf_ngtcp2_ctx_free(ctx);
}
return result;
}
diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c
index 59c1f5053e..1f83726e93 100644
--- a/libs/libcurl/src/vquic/curl_osslq.c
+++ b/libs/libcurl/src/vquic/curl_osslq.c
@@ -290,9 +290,10 @@ struct cf_osslq_ctx {
struct curltime first_byte_at; /* when first byte was recvd */
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash streams; /* hash `data->id` to `h3_stream_ctx` */
+ struct Curl_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 */
+ BIT(initialized);
BIT(got_first_byte); /* if first byte was received */
BIT(x509_store_setup); /* if x509 store has been set up */
BIT(protocol_shutdown); /* QUIC connection is shut down */
@@ -300,19 +301,35 @@ struct cf_osslq_ctx {
BIT(need_send); /* QUIC connection needs to send */
};
-static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx)
+static void h3_stream_hash_free(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);
+ ctx->initialized = TRUE;
+}
+
+static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx)
+{
+ if(ctx && ctx->initialized) {
+ Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_hash_clean(&ctx->streams);
+ Curl_hash_destroy(&ctx->streams);
+ Curl_ssl_peer_cleanup(&ctx->peer);
+ }
+ free(ctx);
+}
+
+static void cf_osslq_ctx_close(struct cf_osslq_ctx *ctx)
{
struct cf_call_data save = ctx->call_data;
cf_osslq_h3conn_cleanup(&ctx->h3);
Curl_vquic_tls_cleanup(&ctx->tls);
vquic_ctx_free(&ctx->q);
- Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
- Curl_ssl_peer_cleanup(&ctx->peer);
-
- memset(ctx, 0, sizeof(*ctx));
ctx->call_data = save;
}
@@ -401,7 +418,7 @@ static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
(SSL_SHUTDOWN_FLAG_NO_BLOCK | SSL_SHUTDOWN_FLAG_RAPID),
NULL, 0);
}
- cf_osslq_ctx_clear(ctx);
+ cf_osslq_ctx_close(ctx);
}
cf->connected = FALSE;
@@ -417,8 +434,9 @@ static void cf_osslq_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
CURL_TRC_CF(data, cf, "destroy");
if(ctx) {
CURL_TRC_CF(data, cf, "cf_osslq_destroy()");
- cf_osslq_ctx_clear(ctx);
- free(ctx);
+ if(ctx->tls.ossl.ssl)
+ cf_osslq_ctx_close(ctx);
+ cf_osslq_ctx_free(ctx);
}
cf->ctx = NULL;
/* No CF_DATA_RESTORE(cf, save) possible */
@@ -435,7 +453,7 @@ static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
/* rejected, we are full */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] rejecting remote stream",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] rejecting remote stream",
stream_id);
SSL_free(stream_ssl);
return CURLE_FAILED_INIT;
@@ -446,12 +464,12 @@ static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
nstream->id = stream_id;
nstream->ssl = stream_ssl;
Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] accepted remote uni stream",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] accepted remote uni stream",
stream_id);
break;
}
default:
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reject remote non-uni-read"
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reject remote non-uni-read"
" stream", stream_id);
SSL_free(stream_ssl);
return CURLE_FAILED_INIT;
@@ -546,7 +564,6 @@ static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf,
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
- cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
}
@@ -573,7 +590,7 @@ struct h3_stream_ctx {
};
#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+ data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
{
@@ -596,10 +613,8 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- if(!data) {
- failf(data, "initialization failure, transfer not http initialized");
+ if(!data)
return CURLE_FAILED_INIT;
- }
if(stream)
return CURLE_OK;
@@ -620,7 +635,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->id, stream)) {
+ if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -635,7 +650,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%"CURL_PRId64"] easy handle is done",
+ CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] easy handle is done",
stream->s.id);
if(ctx->h3.conn && !stream->closed) {
nghttp3_conn_shutdown_stream_read(ctx->h3.conn, stream->s.id);
@@ -645,7 +660,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
stream->closed = TRUE;
}
- Curl_hash_offt_remove(&ctx->streams, data->id);
+ Curl_hash_offt_remove(&ctx->streams, data->mid);
}
}
@@ -655,7 +670,6 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
{
struct cf_osslq_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- struct Curl_easy *sdata;
if(stream && stream->s.id == stream_id) {
return &stream->s;
@@ -670,8 +684,10 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
return &ctx->h3.s_qpack_dec;
}
else {
+ struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
- for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
+ struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn != data->conn)
continue;
stream = H3_STREAM_CTX(ctx, sdata);
@@ -732,11 +748,11 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
stream->reset = TRUE;
stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] RESET: error %" CURL_PRIu64,
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] RESET: error %" FMT_PRIu64,
stream->s.id, stream->error3);
}
else {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] CLOSED", stream->s.id);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->s.id);
}
h3_drain_stream(cf, data);
return 0;
@@ -796,12 +812,12 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
result = write_resp_raw(cf, data, buf, buflen, TRUE);
if(result) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] DATA len=%zu, ERROR %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, ERROR %d",
stream->s.id, buflen, result);
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
stream->download_recvd += (curl_off_t)buflen;
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] DATA len=%zu, total=%zd",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, total=%zd",
stream->s.id, buflen, stream->download_recvd);
h3_drain_stream(cf, data);
return 0;
@@ -819,7 +835,7 @@ static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
(void)conn;
(void)stream_id;
if(stream)
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] deferred consume %zu bytes",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] deferred consume %zu bytes",
stream->s.id, consumed);
return 0;
}
@@ -857,7 +873,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
return -1;
ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
stream->status_code);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] status: %s", stream_id, line);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s", stream_id, line);
result = write_resp_raw(cf, data, line, ncopy, FALSE);
if(result) {
return -1;
@@ -865,7 +881,7 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
}
else {
/* store as an HTTP1-style header */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] header: %.*s: %.*s",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] header: %.*s: %.*s",
stream_id, (int)h3name.len, h3name.base,
(int)h3val.len, h3val.base);
result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE);
@@ -910,7 +926,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
return -1;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] end_headers, status=%d",
stream_id, stream->status_code);
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -934,7 +950,7 @@ static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t sid,
if(!stream || !stream->s.ssl)
return 0;
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] stop_sending", stream_id);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] stop_sending", stream_id);
cf_osslq_stream_close(&stream->s);
return 0;
}
@@ -954,7 +970,7 @@ static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
SSL_STREAM_RESET_ARGS args = {0};
args.quic_error_code = app_error_code;
rv = !SSL_stream_reset(stream->s.ssl, &args, sizeof(args));
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
if(!rv) {
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
@@ -1014,14 +1030,13 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
}
else if(!nwritten) {
/* Not EOF, and nothing to give, we signal WOULDBLOCK. */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> AGAIN",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN",
stream->s.id);
return NGHTTP3_ERR_WOULDBLOCK;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read req body -> "
- "%d vecs%s with %zu (buffered=%zu, left=%"
- CURL_FORMAT_CURL_OFF_T ")",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
+ "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
stream->s.id, (int)nvecs,
*pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
nwritten, Curl_bufq_len(&stream->sendbuf),
@@ -1147,9 +1162,7 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
BIO *bio = NULL;
BIO_ADDR *baddr = NULL;
- 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);
+ DEBUGASSERT(ctx->initialized);
result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
if(result)
goto out;
@@ -1263,7 +1276,7 @@ static ssize_t h3_quic_recv(void *reader_ctx,
return -1;
}
else if(detail == SSL_ERROR_ZERO_RETURN) {
- CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRId64 "] h3_quic_recv -> EOS",
+ CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> EOS",
x->s->id);
x->s->recvd_eos = TRUE;
return 0;
@@ -1272,8 +1285,8 @@ static ssize_t h3_quic_recv(void *reader_ctx,
SSL_STREAM_STATE_RESET_REMOTE) {
uint64_t app_error_code = NGHTTP3_H3_NO_ERROR;
SSL_get_stream_read_error_code(x->s->ssl, &app_error_code);
- CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRId64 "] h3_quic_recv -> RESET, "
- "rv=%d, app_err=%" CURL_PRIu64,
+ CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> RESET, "
+ "rv=%d, app_err=%" FMT_PRIu64,
x->s->id, rv, (curl_uint64_t)app_error_code);
if(app_error_code != NGHTTP3_H3_NO_ERROR) {
x->s->reset = TRUE;
@@ -1329,7 +1342,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
while(Curl_bufq_peek(&s->recvbuf, &buf, &blen)) {
nread = nghttp3_conn_read_stream(ctx->h3.conn, s->id,
buf, blen, 0);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] forward %zu bytes "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] forward %zu bytes "
"to nghttp3 -> %zd", s->id, blen, nread);
if(nread < 0) {
failf(data, "nghttp3_conn_read_stream(len=%zu) error: %s",
@@ -1368,7 +1381,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id,
NGHTTP3_H3_NO_ERROR);
s->closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] close nghttp3 stream -> %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] close nghttp3 stream -> %d",
s->id, rv);
if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
failf(data, "nghttp3_conn_close_stream returned error: %s",
@@ -1381,7 +1394,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
}
out:
if(result)
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_osslq_stream_recv -> %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_osslq_stream_recv -> %d",
s->id, result);
return result;
}
@@ -1422,11 +1435,12 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
}
if(ctx->h3.conn) {
- struct Curl_easy *sdata;
+ struct Curl_llist_node *e;
struct h3_stream_ctx *stream;
/* PULL all open streams */
DEBUGASSERT(data->multi);
- for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
+ struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) {
stream = H3_STREAM_CTX(ctx, sdata);
if(stream && !stream->closed &&
@@ -1449,11 +1463,12 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *sdata;
struct h3_stream_ctx *stream;
if(ctx->h3.conn) {
- for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ struct Curl_llist_node *e;
+ for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
+ struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn == data->conn) {
stream = H3_STREAM_CTX(ctx, sdata);
if(stream && stream->s.ssl && stream->s.send_blocked &&
@@ -1505,7 +1520,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
s = cf_osslq_get_qstream(cf, data, stream_id);
if(!s) {
failf(data, "nghttp3_conn_writev_stream gave unknown stream %"
- CURL_PRId64, (curl_int64_t)stream_id);
+ FMT_PRId64, (curl_int64_t)stream_id);
result = CURLE_SEND_ERROR;
goto out;
}
@@ -1526,7 +1541,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
if(ok) {
/* As OpenSSL buffers the data, we count this as acknowledged
* from nghttp3's point of view */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send %zu bytes to QUIC ok",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send %zu bytes to QUIC ok",
s->id, vec[i].len);
acked_len += vec[i].len;
}
@@ -1536,14 +1551,14 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
/* QUIC blocked us from writing more */
- CURL_TRC_CF(data, cf, "[%"CURL_PRId64 "] send %zu bytes to "
+ CURL_TRC_CF(data, cf, "[%"FMT_PRId64 "] send %zu bytes to "
"QUIC blocked", s->id, vec[i].len);
written = 0;
nghttp3_conn_block_stream(ctx->h3.conn, s->id);
s->send_blocked = blocked = TRUE;
break;
default:
- failf(data, "[%"CURL_PRId64 "] send %zu bytes to QUIC, SSL error %d",
+ failf(data, "[%"FMT_PRId64 "] send %zu bytes to QUIC, SSL error %d",
s->id, vec[i].len, detail);
result = cf_osslq_ssl_err(cf, data, detail, CURLE_HTTP3);
goto out;
@@ -1569,13 +1584,13 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
result = CURLE_SEND_ERROR;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] forwarded %zu/%zu h3 bytes "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] forwarded %zu/%zu h3 bytes "
"to QUIC, eos=%d", s->id, acked_len, total_len, eos);
}
if(eos && !s->send_blocked && !eos_written) {
/* wrote everything and H3 indicates end of stream */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] closing QUIC stream", s->id);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] closing QUIC stream", s->id);
SSL_stream_conclude(s->ssl, 0);
}
}
@@ -1868,11 +1883,11 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
if(rc) {
switch(rc) {
case NGHTTP3_ERR_CONN_CLOSING:
- CURL_TRC_CF(data, cf, "h3sid[%"CURL_PRId64"] failed to send, "
+ CURL_TRC_CF(data, cf, "h3sid[%"FMT_PRId64"] failed to send, "
"connection is closing", stream->s.id);
break;
default:
- CURL_TRC_CF(data, cf, "h3sid[%"CURL_PRId64 "] failed to send -> %d (%s)",
+ CURL_TRC_CF(data, cf, "h3sid[%"FMT_PRId64 "] failed to send -> %d (%s)",
stream->s.id, rc, nghttp3_strerror(rc));
break;
}
@@ -1882,10 +1897,10 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
}
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" CURL_PRId64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" FMT_PRId64 "] OPENED stream for %s",
stream->s.id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" CURL_PRId64 "] [%.*s: %.*s]",
+ infof(data, "[HTTP/3] [%" FMT_PRId64 "] [%.*s: %.*s]",
stream->s.id,
(int)nva[i].namelen, nva[i].name,
(int)nva[i].valuelen, nva[i].value);
@@ -1899,7 +1914,8 @@ out:
}
static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, CURLcode *err)
+ const void *buf, size_t len, bool eos,
+ CURLcode *err)
{
struct cf_osslq_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -1907,6 +1923,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
ssize_t nwritten;
CURLcode result;
+ (void)eos; /* TODO: use to end stream */
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
DEBUGASSERT(ctx->tls.ossl.ssl);
@@ -1942,13 +1959,13 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* body. This happens on 30x or 40x responses.
* We silently discard the data sent, since this is not a transport
* error situation. */
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
"on closed stream with response", stream->s.id);
*err = CURLE_OK;
nwritten = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
"-> stream closed", stream->s.id, len);
*err = CURLE_HTTP3;
nwritten = -1;
@@ -1956,7 +1973,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
else {
nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send, add to "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
"sendbuf(len=%zu) -> %zd, %d",
stream->s.id, len, nwritten, *err);
if(nwritten < 0) {
@@ -1974,7 +1991,7 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
out:
result = check_and_set_expiry(cf, data);
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
stream? stream->s.id : -1, len, nwritten, *err);
CF_DATA_RESTORE(cf, save);
return nwritten;
@@ -1990,14 +2007,14 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
(void)cf;
if(stream->reset) {
failf(data,
- "HTTP/3 stream %" CURL_PRId64 " reset by server",
+ "HTTP/3 stream %" FMT_PRId64 " reset by server",
stream->s.id);
*err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
failf(data,
- "HTTP/3 stream %" CURL_PRId64
+ "HTTP/3 stream %" FMT_PRId64
" was closed cleanly, but before getting"
" all response header fields, treated as error",
stream->s.id);
@@ -2037,7 +2054,7 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->s.id, len, nread, *err);
goto out;
}
@@ -2055,7 +2072,7 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->s.id, len, nread, *err);
goto out;
}
@@ -2085,7 +2102,7 @@ out:
nread = -1;
}
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
stream? stream->s.id : -1, len, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
@@ -2325,7 +2342,7 @@ CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- cf_osslq_ctx_clear(ctx);
+ cf_osslq_ctx_init(ctx);
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
if(result)
@@ -2346,7 +2363,7 @@ out:
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
Curl_safefree(cf);
- Curl_safefree(ctx);
+ cf_osslq_ctx_free(ctx);
}
return result;
}
diff --git a/libs/libcurl/src/vquic/curl_quiche.c b/libs/libcurl/src/vquic/curl_quiche.c
index 66e3592bb2..61b97e2119 100644
--- a/libs/libcurl/src/vquic/curl_quiche.c
+++ b/libs/libcurl/src/vquic/curl_quiche.c
@@ -98,14 +98,17 @@ struct cf_quiche_ctx {
struct curltime handshake_at; /* time connect handshake finished */
struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash streams; /* hash `data->id` to `stream_ctx` */
+ struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */
curl_off_t data_recvd;
+ BIT(initialized);
BIT(goaway); /* got GOAWAY from server */
BIT(x509_store_setup); /* if x509 store has been set up */
BIT(shutdown_started); /* queued shutdown packets */
};
#ifdef DEBUG_QUICHE
+/* initialize debug log callback only once */
+static int debug_log_init = 0;
static void quiche_debug_log(const char *line, void *argp)
{
(void)argp;
@@ -113,17 +116,27 @@ static void quiche_debug_log(const char *line, void *argp)
}
#endif
-static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
+static void h3_stream_hash_free(void *stream);
+
+static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
{
- if(ctx) {
- if(ctx->h3c)
- quiche_h3_conn_free(ctx->h3c);
- if(ctx->h3config)
- quiche_h3_config_free(ctx->h3config);
- if(ctx->qconn)
- quiche_conn_free(ctx->qconn);
- if(ctx->cfg)
- quiche_config_free(ctx->cfg);
+ DEBUGASSERT(!ctx->initialized);
+#ifdef DEBUG_QUICHE
+ if(!debug_log_init) {
+ quiche_enable_debug_logging(quiche_debug_log, NULL);
+ debug_log_init = 1;
+ }
+#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);
+ ctx->data_recvd = 0;
+ ctx->initialized = TRUE;
+}
+
+static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
+{
+ if(ctx && ctx->initialized) {
/* quiche just freed it */
ctx->tls.ossl.ssl = NULL;
Curl_vquic_tls_cleanup(&ctx->tls);
@@ -132,9 +145,20 @@ static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
Curl_bufcp_free(&ctx->stream_bufcp);
Curl_hash_clean(&ctx->streams);
Curl_hash_destroy(&ctx->streams);
-
- memset(ctx, 0, sizeof(*ctx));
}
+ free(ctx);
+}
+
+static void cf_quiche_ctx_close(struct cf_quiche_ctx *ctx)
+{
+ if(ctx->h3c)
+ quiche_h3_conn_free(ctx->h3c);
+ if(ctx->h3config)
+ quiche_h3_config_free(ctx->h3config);
+ if(ctx->qconn)
+ quiche_conn_free(ctx->qconn);
+ if(ctx->cfg)
+ quiche_config_free(ctx->cfg);
}
static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
@@ -148,7 +172,6 @@ struct stream_ctx {
struct bufq recvbuf; /* h3 response */
struct h1_req_parser h1; /* h1 request parsing */
curl_uint64_t error3; /* HTTP/3 stream error code */
- curl_off_t upload_left; /* number of request bytes left to upload */
BIT(opened); /* TRUE after stream has been opened */
BIT(closed); /* TRUE on stream close */
BIT(reset); /* TRUE on stream reset */
@@ -159,7 +182,7 @@ struct stream_ctx {
};
#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
+ data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
static void h3_stream_ctx_free(struct stream_ctx *stream)
{
@@ -178,17 +201,17 @@ static void check_resumes(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct Curl_easy *sdata;
- struct stream_ctx *stream;
+ struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
- for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
+ struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn == data->conn) {
- stream = H3_STREAM_CTX(ctx, sdata);
+ struct stream_ctx *stream = H3_STREAM_CTX(ctx, sdata);
if(stream && stream->quic_flow_blocked) {
stream->quic_flow_blocked = FALSE;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] unblock", stream->id);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] unblock", stream->id);
}
}
}
@@ -212,7 +235,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->id, stream)) {
+ if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
h3_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
@@ -228,7 +251,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] easy handle is done", stream->id);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] easy handle is done", stream->id);
if(ctx->qconn && !stream->closed) {
quiche_conn_stream_shutdown(ctx->qconn, stream->id,
QUICHE_SHUTDOWN_READ, CURL_H3_NO_ERROR);
@@ -242,7 +265,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->id);
+ Curl_hash_offt_remove(&ctx->streams, data->mid);
}
}
@@ -255,7 +278,7 @@ static void drain_stream(struct Curl_cfilter *cf,
(void)cf;
bits = CURL_CSELECT_IN;
- if(stream && !stream->send_closed && stream->upload_left)
+ if(stream && !stream->send_closed)
bits |= CURL_CSELECT_OUT;
if(data->state.select_bits != bits) {
data->state.select_bits = bits;
@@ -269,7 +292,6 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
struct stream_ctx **pstream)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct Curl_easy *sdata;
struct stream_ctx *stream;
(void)cf;
@@ -279,8 +301,10 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
return data;
}
else {
+ struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
- for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
+ struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata->conn != data->conn)
continue;
stream = H3_STREAM_CTX(ctx, sdata);
@@ -297,11 +321,12 @@ static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct Curl_easy *sdata;
+ struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
CURL_TRC_CF(data, cf, "conn closed, expire all transfers");
- for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
+ struct Curl_easy *sdata = Curl_node_elem(e);
if(sdata == data || sdata->conn != data->conn)
continue;
CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");
@@ -357,7 +382,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
return CURLE_OK;
if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7)) {
- CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRIu64 "] status: %.*s",
+ CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRIu64 "] status: %.*s",
stream->id, (int)value_len, value);
result = write_resp_raw(x->cf, x->data, "HTTP/3 ", sizeof("HTTP/3 ") - 1);
if(!result)
@@ -366,7 +391,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
result = write_resp_raw(x->cf, x->data, " \r\n", 3);
}
else {
- CURL_TRC_CF(x->data, x->cf, "[%" CURL_PRIu64 "] header: %.*s: %.*s",
+ CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRIu64 "] header: %.*s: %.*s",
stream->id, (int)name_len, name,
(int)value_len, value);
result = write_resp_raw(x->cf, x->data, name, name_len);
@@ -378,7 +403,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
result = write_resp_raw(x->cf, x->data, "\r\n", 2);
}
if(result) {
- CURL_TRC_CF(x->data, x->cf, "[%"CURL_PRIu64"] on header error %d",
+ CURL_TRC_CF(x->data, x->cf, "[%"FMT_PRIu64"] on header error %d",
stream->id, result);
}
return result;
@@ -435,9 +460,9 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
stream_resp_read, &cb_ctx, &result);
if(nwritten < 0 && result != CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] recv_body error %zd",
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zd",
stream->id, nwritten);
- failf(data, "Error %d in HTTP/3 response body for stream[%"CURL_PRIu64"]",
+ failf(data, "Error %d in HTTP/3 response body for stream[%"FMT_PRIu64"]",
result, stream->id);
stream->closed = TRUE;
stream->reset = TRUE;
@@ -489,10 +514,10 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
rc = quiche_h3_event_for_each_header(ev, cb_each_header, &cb_ctx);
if(rc) {
failf(data, "Error %d in HTTP/3 response header for stream[%"
- CURL_PRIu64"]", rc, stream->id);
+ FMT_PRIu64"]", rc, stream->id);
return CURLE_RECV_ERROR;
}
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] <- [HEADERS]", stream->id);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] <- [HEADERS]", stream->id);
break;
case QUICHE_H3_EVENT_DATA:
@@ -502,7 +527,7 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_RESET:
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] RESET", stream->id);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] RESET", stream->id);
stream->closed = TRUE;
stream->reset = TRUE;
stream->send_closed = TRUE;
@@ -510,7 +535,7 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_FINISHED:
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] CLOSED", stream->id);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] CLOSED", stream->id);
if(!stream->resp_hds_complete) {
result = write_resp_raw(cf, data, "\r\n", 2);
if(result)
@@ -522,11 +547,11 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_GOAWAY:
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] <- [GOAWAY]", stream->id);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] <- [GOAWAY]", stream->id);
break;
default:
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] recv, unhandled event %d",
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv, unhandled event %d",
stream->id, quiche_h3_event_type(ev));
break;
}
@@ -549,13 +574,13 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
break;
}
else if(stream3_id < 0) {
- CURL_TRC_CF(data, cf, "error poll: %"CURL_PRId64, stream3_id);
+ CURL_TRC_CF(data, cf, "error poll: %"FMT_PRId64, stream3_id);
return CURLE_HTTP3;
}
sdata = get_stream_easy(cf, data, stream3_id, &stream);
if(!sdata || !stream) {
- CURL_TRC_CF(data, cf, "discard event %s for unknown [%"CURL_PRId64"]",
+ CURL_TRC_CF(data, cf, "discard event %s for unknown [%"FMT_PRId64"]",
cf_ev_name(ev), stream3_id);
}
else {
@@ -563,7 +588,7 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
drain_stream(cf, sdata);
if(result) {
CURL_TRC_CF(data, cf, "error processing event %s "
- "for [%"CURL_PRIu64"] -> %d", cf_ev_name(ev),
+ "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
stream3_id, result);
if(data == sdata) {
/* Only report this error to the caller if it is about the
@@ -793,19 +818,19 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
DEBUGASSERT(stream);
if(stream->reset) {
failf(data,
- "HTTP/3 stream %" CURL_PRIu64 " reset by server", stream->id);
+ "HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id);
*err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_recv, was reset -> %d",
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d",
stream->id, *err);
}
else if(!stream->resp_got_header) {
failf(data,
- "HTTP/3 stream %" CURL_PRIu64 " was closed cleanly, but before "
+ "HTTP/3 stream %" FMT_PRIu64 " was closed cleanly, but before "
"getting all response header fields, treated as error",
stream->id);
/* *err = CURLE_PARTIAL_FILE; */
*err = CURLE_HTTP3;
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_recv, closed incomplete"
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, closed incomplete"
" -> %d", stream->id, *err);
}
else {
@@ -833,7 +858,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!Curl_bufq_is_empty(&stream->recvbuf)) {
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->id, len, nread, *err);
if(nread < 0)
goto out;
@@ -850,7 +875,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->id, len, nread, *err);
if(nread < 0)
goto out;
@@ -884,19 +909,70 @@ out:
}
if(nread > 0)
ctx->data_recvd += nread;
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] cf_recv(total=%"
- CURL_FORMAT_CURL_OFF_T ") -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] cf_recv(total=%"
+ FMT_OFF_T ") -> %zd, %d",
stream->id, ctx->data_recvd, nread, *err);
return nread;
}
+static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct stream_ctx *stream,
+ const void *buf, size_t len, bool eos,
+ CURLcode *err)
+{
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ ssize_t nwritten;
+
+ nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
+ (uint8_t *)buf, len, eos);
+ if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
+ /* TODO: we seem to be blocked on flow control and should HOLD
+ * sending. But when do we open again? */
+ if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
+ "-> window exhausted", stream->id, len);
+ stream->quic_flow_blocked = TRUE;
+ }
+ *err = CURLE_AGAIN;
+ return -1;
+ }
+ else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
+ "-> invalid stream state", stream->id, len);
+ *err = CURLE_HTTP3;
+ return -1;
+ }
+ else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
+ "-> exceeds size", stream->id, len);
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+ else if(nwritten < 0) {
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
+ "-> quiche err %zd", stream->id, len, nwritten);
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+ else {
+ if(eos && (len == (size_t)nwritten))
+ stream->send_closed = TRUE;
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send body(len=%zu, "
+ "eos=%d) -> %zd",
+ stream->id, len, stream->send_closed, nwritten);
+ *err = CURLE_OK;
+ return nwritten;
+ }
+}
+
/* Index where :authority header field will appear in request header
field list. */
#define AUTHORITY_DST_IDX 3
static ssize_t h3_open_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const void *buf, size_t len,
+ const char *buf, size_t len, bool eos,
CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
@@ -952,23 +1028,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
nva[i].value_len = e->valuelen;
}
- switch(data->state.httpreq) {
- case HTTPREQ_POST:
- case HTTPREQ_POST_FORM:
- case HTTPREQ_POST_MIME:
- case HTTPREQ_PUT:
- if(data->state.infilesize != -1)
- stream->upload_left = data->state.infilesize;
- else
- /* data sending without specifying the data amount up front */
- stream->upload_left = -1; /* unknown */
- break;
- default:
- stream->upload_left = 0; /* no request body */
- break;
- }
-
- if(stream->upload_left == 0)
+ if(eos && ((size_t)nwritten == len))
stream->send_closed = TRUE;
stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader,
@@ -977,14 +1037,14 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) {
/* quiche seems to report this error if the connection window is
* exhausted. Which happens frequently and intermittent. */
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] blocked", stream->id);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] blocked", stream->id);
stream->quic_flow_blocked = TRUE;
*err = CURLE_AGAIN;
nwritten = -1;
goto out;
}
else {
- CURL_TRC_CF(data, cf, "send_request(%s) -> %" CURL_PRIu64,
+ CURL_TRC_CF(data, cf, "send_request(%s) -> %" FMT_PRIu64,
data->state.url, stream3_id);
}
*err = CURLE_SEND_ERROR;
@@ -1000,15 +1060,31 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
stream->reset = FALSE;
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" CURL_PRIu64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" FMT_PRIu64 "] OPENED stream for %s",
stream->id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" CURL_PRIu64 "] [%.*s: %.*s]", stream->id,
+ infof(data, "[HTTP/3] [%" FMT_PRIu64 "] [%.*s: %.*s]", stream->id,
(int)nva[i].name_len, nva[i].name,
(int)nva[i].value_len, nva[i].value);
}
}
+ if(nwritten > 0 && ((size_t)nwritten < len)) {
+ /* after the headers, there was request BODY data */
+ size_t hds_len = (size_t)nwritten;
+ ssize_t bwritten;
+
+ bwritten = cf_quiche_send_body(cf, data, stream,
+ buf + hds_len, len - hds_len, eos, err);
+ if((bwritten < 0) && (CURLE_AGAIN != *err)) {
+ /* real error, fail */
+ nwritten = -1;
+ }
+ else if(bwritten > 0) {
+ nwritten += bwritten;
+ }
+ }
+
out:
free(nva);
Curl_dynhds_free(&h2_headers);
@@ -1016,7 +1092,8 @@ out:
}
static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, CURLcode *err)
+ const void *buf, size_t len, bool eos,
+ CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -1032,7 +1109,7 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(!stream || !stream->opened) {
- nwritten = h3_open_stream(cf, data, buf, len, err);
+ nwritten = h3_open_stream(cf, data, buf, len, eos, err);
if(nwritten < 0)
goto out;
stream = H3_STREAM_CTX(ctx, data);
@@ -1047,70 +1124,20 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* sending the 30x response.
* This is sort of a race: had the transfer loop called recv first,
* it would see the response and stop/discard sending on its own- */
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
nwritten = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
"-> stream closed", stream->id, len);
*err = CURLE_HTTP3;
nwritten = -1;
goto out;
}
else {
- bool eof = (stream->upload_left >= 0 &&
- (curl_off_t)len >= stream->upload_left);
- nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
- (uint8_t *)buf, len, eof);
- if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
- /* TODO: we seem to be blocked on flow control and should HOLD
- * sending. But when do we open again? */
- if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> window exhausted", stream->id, len);
- stream->quic_flow_blocked = TRUE;
- }
- *err = CURLE_AGAIN;
- nwritten = -1;
- goto out;
- }
- else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> invalid stream state", stream->id, len);
- *err = CURLE_HTTP3;
- nwritten = -1;
- goto out;
- }
- else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> exceeds size", stream->id, len);
- *err = CURLE_SEND_ERROR;
- nwritten = -1;
- goto out;
- }
- else if(nwritten < 0) {
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send_body(len=%zu) "
- "-> quiche err %zd", stream->id, len, nwritten);
- *err = CURLE_SEND_ERROR;
- nwritten = -1;
- goto out;
- }
- else {
- /* quiche accepted all or at least a part of the buf */
- if(stream->upload_left > 0) {
- stream->upload_left = (nwritten < stream->upload_left)?
- (stream->upload_left - nwritten) : 0;
- }
- if(stream->upload_left == 0)
- stream->send_closed = TRUE;
-
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] send body(len=%zu, "
- "left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd",
- stream->id, len, stream->upload_left, nwritten);
- *err = CURLE_OK;
- }
+ nwritten = cf_quiche_send_body(cf, data, stream, buf, len, eos, err);
}
out:
@@ -1119,8 +1146,8 @@ out:
*err = result;
nwritten = -1;
}
- CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
- stream? stream->id : (uint64_t)~0, len, nwritten, *err);
+ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
+ stream? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
return nwritten;
}
@@ -1215,10 +1242,9 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
ssize_t sent;
stream->send_closed = TRUE;
- stream->upload_left = 0;
body[0] = 'X';
- sent = cf_quiche_send(cf, data, body, 0, &result);
- CURL_TRC_CF(data, cf, "[%"CURL_PRIu64"] DONE_SEND -> %zd, %d",
+ sent = cf_quiche_send(cf, data, body, 0, TRUE, &result);
+ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] DONE_SEND -> %zd, %d",
stream->id, sent, result);
}
break;
@@ -1238,8 +1264,8 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
return result;
}
-static CURLcode cf_connect_start(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
int rv;
@@ -1247,19 +1273,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
const struct Curl_sockaddr_ex *sockaddr;
DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
-
-#ifdef DEBUG_QUICHE
- /* initialize debug log callback only once */
- static int debug_log_init = 0;
- if(!debug_log_init) {
- quiche_enable_debug_logging(quiche_debug_log, NULL);
- debug_log_init = 1;
- }
-#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);
- ctx->data_recvd = 0;
+ DEBUGASSERT(ctx->initialized);
result = vquic_ctx_init(&ctx->q);
if(result)
@@ -1366,7 +1380,6 @@ static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf,
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
- cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
}
@@ -1401,7 +1414,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
}
if(!ctx->qconn) {
- result = cf_connect_start(cf, data);
+ result = cf_quiche_ctx_open(cf, data);
if(result)
goto out;
ctx->started_at = ctx->q.last_op;
@@ -1513,23 +1526,20 @@ out:
static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
-
- if(ctx) {
+ if(cf->ctx) {
bool done;
(void)cf_quiche_shutdown(cf, data, &done);
- cf_quiche_ctx_clear(ctx);
+ cf_quiche_ctx_close(cf->ctx);
}
}
static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
-
(void)data;
- cf_quiche_ctx_clear(ctx);
- free(ctx);
- cf->ctx = NULL;
+ if(cf->ctx) {
+ cf_quiche_ctx_free(cf->ctx);
+ cf->ctx = NULL;
+ }
}
static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
@@ -1545,7 +1555,7 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
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[%" CURL_FORMAT_CURL_OFF_T "]: "
+ 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));
return CURLE_OK;
@@ -1650,6 +1660,7 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+ cf_quiche_ctx_init(ctx);
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
if(result)
@@ -1669,7 +1680,7 @@ out:
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
Curl_safefree(cf);
- Curl_safefree(ctx);
+ cf_quiche_ctx_free(ctx);
}
return result;
diff --git a/libs/libcurl/src/vquic/vquic-tls.c b/libs/libcurl/src/vquic/vquic-tls.c
index d3ddce2c53..f51ec0cc22 100644
--- a/libs/libcurl/src/vquic/vquic-tls.c
+++ b/libs/libcurl/src/vquic/vquic-tls.c
@@ -162,7 +162,7 @@ static CURLcode Curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
#ifdef CURL_CA_FALLBACK
else {
/* verifying the peer without any CA certificates will not work so
- use wolfssl's built-in default as fallback */
+ use wolfSSL's built-in default as fallback */
wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
}
#endif
diff --git a/libs/libcurl/src/vquic/vquic.c b/libs/libcurl/src/vquic/vquic.c
index 13d9929ee2..f68a8d2912 100644
--- a/libs/libcurl/src/vquic/vquic.c
+++ b/libs/libcurl/src/vquic/vquic.c
@@ -22,7 +22,7 @@
*
***************************************************************************/
-/* WIP, experimental: use recvmmsg() on linux
+/* WIP, experimental: use recvmmsg() on Linux
* we have no configure check, yet
* and also it is only available for _GNU_SOURCE, which
* we do not use otherwise.
@@ -720,7 +720,7 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
const struct connectdata *conn)
{
if(conn->transport == TRNSPRT_UNIX) {
- /* cannot do QUIC over a unix domain socket */
+ /* cannot do QUIC over a Unix domain socket */
return CURLE_QUIC_CONNECT_ERROR;
}
if(!(conn->handler->flags & PROTOPT_SSL)) {