summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2024-03-28 09:00:13 +0000
committerTomas Mraz <tomas@openssl.org>2024-04-10 15:48:35 +0200
commitda01235692de643c990a34cae0f523a126be7573 (patch)
treecd9519bc8696342fb0d14086a101031aaae37622
parent26dd6ba070fdc2566c1a51d29e57e55c9ec7c78b (diff)
QUIC APL: Revise SSL_pending and SSL_has_pending handling for s_client compat
Reviewed-by: Neil Horman <nhorman@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/24040) (cherry picked from commit 7c33eb1e7fd3248ad29c172b5b4c0658a7be3adc)
-rw-r--r--ssl/quic/quic_impl.c53
1 files changed, 34 insertions, 19 deletions
diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c
index c4c332b203..62ebcd29aa 100644
--- a/ssl/quic/quic_impl.c
+++ b/ssl/quic/quic_impl.c
@@ -25,7 +25,7 @@ static void aon_write_finish(QUIC_XSO *xso);
static int create_channel(QUIC_CONNECTION *qc);
static QUIC_XSO *create_xso_from_stream(QUIC_CONNECTION *qc, QUIC_STREAM *qs);
static int qc_try_create_default_xso_for_write(QCTX *ctx);
-static int qc_wait_for_default_xso_for_read(QCTX *ctx);
+static int qc_wait_for_default_xso_for_read(QCTX *ctx, int peek);
static void quic_lock(QUIC_CONNECTION *qc);
static void quic_unlock(QUIC_CONNECTION *qc);
static void quic_lock_for_io(QCTX *ctx);
@@ -268,7 +268,7 @@ static int ossl_unused expect_quic_with_stream_lock(const SSL *s, int remote_ini
if (!qc_try_create_default_xso_for_write(ctx))
goto err;
} else {
- if (!qc_wait_for_default_xso_for_read(ctx))
+ if (!qc_wait_for_default_xso_for_read(ctx, /*peek=*/0))
goto err;
}
@@ -1851,7 +1851,7 @@ static int quic_wait_for_stream(void *arg)
}
QUIC_NEEDS_LOCK
-static int qc_wait_for_default_xso_for_read(QCTX *ctx)
+static int qc_wait_for_default_xso_for_read(QCTX *ctx, int peek)
{
/* Called on a QCSO and we don't currently have a default stream. */
uint64_t expect_id;
@@ -1893,6 +1893,9 @@ static int qc_wait_for_default_xso_for_read(QCTX *ctx)
}
if (qs == NULL) {
+ if (peek)
+ return 0;
+
if (!qc_blocking_mode(qc))
/* Non-blocking mode, so just bail immediately. */
return QUIC_RAISE_NORMAL_ERROR(ctx, SSL_ERROR_WANT_READ);
@@ -2524,10 +2527,19 @@ int ossl_quic_write_flags(SSL *s, const void *buf, size_t len,
*written = 0;
- if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, /*io=*/1, &ctx))
- return 0;
+ if (len == 0) {
+ /* Do not autocreate default XSO for zero-length writes. */
+ if (!expect_quic(s, &ctx))
+ return 0;
+
+ quic_lock_for_io(&ctx);
+ } else {
+ if (!expect_quic_with_stream_lock(s, /*remote_init=*/0, /*io=*/1, &ctx))
+ return 0;
+ }
- partial_write = ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0);
+ partial_write = ((ctx.xso != NULL)
+ ? ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0) : 0);
if ((flags & ~SSL_WRITE_FLAG_CONCLUDE) != 0) {
ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_UNSUPPORTED_WRITE_FLAG, NULL);
@@ -2549,7 +2561,7 @@ int ossl_quic_write_flags(SSL *s, const void *buf, size_t len,
}
/* Ensure correct stream state, stream send part not concluded, etc. */
- if (!quic_validate_for_write(ctx.xso, &err)) {
+ if (len > 0 && !quic_validate_for_write(ctx.xso, &err)) {
ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, err, NULL);
goto out;
}
@@ -2753,7 +2765,7 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek
* Wait until we get a stream initiated by the peer (blocking mode) or
* fail if we don't have one yet (non-blocking mode).
*/
- if (!qc_wait_for_default_xso_for_read(&ctx)) {
+ if (!qc_wait_for_default_xso_for_read(&ctx, /*peek=*/0)) {
ret = 0; /* error already raised here */
goto out;
}
@@ -2840,8 +2852,6 @@ static size_t ossl_quic_pending_int(const SSL *s, int check_channel)
{
QCTX ctx;
size_t avail = 0;
- int fin = 0;
-
if (!expect_quic(s, &ctx))
return 0;
@@ -2849,21 +2859,26 @@ static size_t ossl_quic_pending_int(const SSL *s, int check_channel)
quic_lock(ctx.qc);
if (ctx.xso == NULL) {
- QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_NO_STREAM, NULL);
- goto out;
+ /* No XSO yet, but there might be a default XSO eligible to be created. */
+ if (qc_wait_for_default_xso_for_read(&ctx, /*peek=*/1)) {
+ ctx.xso = ctx.qc->default_xso;
+ } else {
+ QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_NO_STREAM, NULL);
+ goto out;
+ }
}
- if (ctx.xso->stream == NULL
- || !ossl_quic_stream_has_recv_buffer(ctx.xso->stream)) {
+ if (ctx.xso->stream == NULL) {
QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_INTERNAL_ERROR, NULL);
goto out;
}
- if (!ossl_quic_rstream_available(ctx.xso->stream->rstream, &avail, &fin))
- avail = 0;
-
- if (avail == 0 && check_channel && ossl_quic_channel_has_pending(ctx.qc->ch))
- avail = 1;
+ if (check_channel)
+ avail = ossl_quic_stream_recv_pending(ctx.xso->stream)
+ || ossl_quic_channel_has_pending(ctx.qc->ch)
+ || ossl_quic_channel_is_term_any(ctx.qc->ch);
+ else
+ avail = ossl_quic_stream_recv_pending(ctx.xso->stream);
out:
quic_unlock(ctx.qc);