summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vquic/curl_osslq.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vquic/curl_osslq.c')
-rw-r--r--libs/libcurl/src/vquic/curl_osslq.c102
1 files changed, 79 insertions, 23 deletions
diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c
index c3d695d415..47dbd9afa2 100644
--- a/libs/libcurl/src/vquic/curl_osslq.c
+++ b/libs/libcurl/src/vquic/curl_osslq.c
@@ -82,10 +82,6 @@
#define H3_STREAM_SEND_CHUNKS \
(H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
typedef uint32_t sslerr_t;
#else
@@ -292,6 +288,9 @@ struct cf_osslq_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 */
+ SSL_POLL_ITEM *poll_items; /* Array for polling on writable state */
+ struct Curl_easy **curl_items; /* Array of easy objs */
+ size_t item_count; /* count of elements in poll/curl_items */
BIT(initialized);
BIT(got_first_byte); /* if first byte was received */
BIT(x509_store_setup); /* if x509 store has been set up */
@@ -308,6 +307,9 @@ static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx)
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->poll_items = NULL;
+ ctx->curl_items = NULL;
+ ctx->item_count = 0;
ctx->initialized = TRUE;
}
@@ -318,6 +320,8 @@ static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx)
Curl_hash_clean(&ctx->streams);
Curl_hash_destroy(&ctx->streams);
Curl_ssl_peer_cleanup(&ctx->peer);
+ free(ctx->poll_items);
+ free(ctx->curl_items);
}
free(ctx);
}
@@ -450,7 +454,7 @@ static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
struct cf_osslq_ctx *ctx = cf->ctx;
curl_int64_t stream_id = (curl_int64_t)SSL_get_stream_id(stream_ssl);
- if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
+ if(h3->remote_ctrl_n >= CURL_ARRAYSIZE(h3->remote_ctrl)) {
/* rejected, we are full */
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] rejecting remote stream",
stream_id);
@@ -562,7 +566,6 @@ static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf,
struct cf_osslq_ctx *ctx = cf->ctx;
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
- cf->conn->httpversion = 30;
return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
}
@@ -1162,14 +1165,11 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
BIO_ADDR *baddr = NULL;
DEBUGASSERT(ctx->initialized);
- result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
- if(result)
- goto out;
#define H3_ALPN "\x2h3"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
H3_ALPN, sizeof(H3_ALPN) - 1,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
if(result)
goto out;
@@ -1464,24 +1464,80 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
{
struct cf_osslq_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream;
+ size_t poll_count = 0;
+ size_t result_count = 0;
+ size_t idx_count = 0;
+ CURLcode res = CURLE_OK;
+ struct timeval timeout;
+ void *tmpptr;
if(ctx->h3.conn) {
struct Curl_llist_node *e;
+
+ res = CURLE_OUT_OF_MEMORY;
+
+ if(ctx->item_count < Curl_llist_count(&data->multi->process)) {
+ ctx->item_count = 0;
+ tmpptr = realloc(ctx->poll_items,
+ Curl_llist_count(&data->multi->process) *
+ sizeof(SSL_POLL_ITEM));
+ if(!tmpptr) {
+ free(ctx->poll_items);
+ ctx->poll_items = NULL;
+ goto out;
+ }
+ ctx->poll_items = tmpptr;
+
+ tmpptr = realloc(ctx->curl_items,
+ Curl_llist_count(&data->multi->process) *
+ sizeof(struct Curl_easy *));
+ if(!tmpptr) {
+ free(ctx->curl_items);
+ ctx->curl_items = NULL;
+ goto out;
+ }
+ ctx->curl_items = tmpptr;
+
+ ctx->item_count = Curl_llist_count(&data->multi->process);
+ }
+
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 &&
- !SSL_want_write(stream->s.ssl)) {
- nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
- stream->s.send_blocked = FALSE;
- h3_drain_stream(cf, sdata);
- CURL_TRC_CF(sdata, cf, "unblocked");
+ if(stream && stream->s.ssl && stream->s.send_blocked) {
+ ctx->poll_items[poll_count].desc =
+ SSL_as_poll_descriptor(stream->s.ssl);
+ ctx->poll_items[poll_count].events = SSL_POLL_EVENT_W;
+ ctx->curl_items[poll_count] = sdata;
+ poll_count++;
}
}
}
+
+ memset(&timeout, 0, sizeof(struct timeval));
+ res = CURLE_UNRECOVERABLE_POLL;
+ if(!SSL_poll(ctx->poll_items, poll_count, sizeof(SSL_POLL_ITEM), &timeout,
+ 0, &result_count))
+ goto out;
+
+ res = CURLE_OK;
+
+ for(idx_count = 0; idx_count < poll_count && result_count > 0;
+ 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");
+ result_count--;
+ }
+ }
}
- return CURLE_OK;
+
+out:
+ return res;
}
static CURLcode h3_send_streams(struct Curl_cfilter *cf,
@@ -1504,7 +1560,7 @@ static CURLcode h3_send_streams(struct Curl_cfilter *cf,
bool blocked = FALSE, eos_written = FALSE;
n = nghttp3_conn_writev_stream(ctx->h3.conn, &stream_id, &eos,
- vec, ARRAYSIZE(vec));
+ vec, CURL_ARRAYSIZE(vec));
if(n < 0) {
failf(data, "nghttp3_conn_writev_stream returned error: %s",
nghttp3_strerror((int)n));
@@ -1924,7 +1980,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 */
+ (void)eos; /* use to end stream */
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
DEBUGASSERT(ctx->tls.ossl.ssl);
@@ -2139,9 +2195,6 @@ static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
case CF_CTRL_DATA_PAUSE:
result = h3_data_pause(cf, data, (arg1 != 0));
break;
- case CF_CTRL_DATA_DETACH:
- h3_data_done(cf, data);
- break;
case CF_CTRL_DATA_DONE:
h3_data_done(cf, data);
break;
@@ -2301,6 +2354,9 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
*when = ctx->handshake_at;
return CURLE_OK;
}
+ case CF_QUERY_HTTP_VERSION:
+ *pres1 = 30;
+ return CURLE_OK;
default:
break;
}
@@ -2311,7 +2367,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_http3 = {
"HTTP/3",
- CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
+ CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX | CF_TYPE_HTTP,
0,
cf_osslq_destroy,
cf_osslq_connect,