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 7c33eb1e7f)
This commit is contained in:
Hugo Landau 2024-03-28 09:00:13 +00:00 committed by Tomas Mraz
parent 26dd6ba070
commit da01235692

View File

@ -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;
partial_write = ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 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 != 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);