QUIC APL: Implement SSL_poll backend

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23495)
This commit is contained in:
Hugo Landau 2024-02-02 12:21:28 +00:00
parent a5d16ac371
commit 6ba77d6743
3 changed files with 162 additions and 4 deletions

View File

@ -142,6 +142,9 @@ int ossl_quic_get_shutdown(const SSL *s);
*/ */
int ossl_quic_set_diag_title(SSL_CTX *ctx, const char *title); int ossl_quic_set_diag_title(SSL_CTX *ctx, const char *title);
/* APIs used by the polling infrastructure */
int ossl_quic_conn_poll_events(SSL *ssl, uint64_t events, uint64_t *revents);
# endif # endif
#endif #endif

View File

@ -2639,10 +2639,12 @@ static int quic_read_actual(QCTX *ctx,
QUIC_CONNECTION *qc = ctx->qc; QUIC_CONNECTION *qc = ctx->qc;
if (!quic_validate_for_read(ctx->xso, &err, &eos)) { if (!quic_validate_for_read(ctx->xso, &err, &eos)) {
if (eos) if (eos) {
ctx->xso->retired_fin = 1;
return QUIC_RAISE_NORMAL_ERROR(ctx, SSL_ERROR_ZERO_RETURN); return QUIC_RAISE_NORMAL_ERROR(ctx, SSL_ERROR_ZERO_RETURN);
else } else {
return QUIC_RAISE_NON_NORMAL_ERROR(ctx, err, NULL); return QUIC_RAISE_NON_NORMAL_ERROR(ctx, err, NULL);
}
} }
if (peek) { if (peek) {
@ -2684,8 +2686,10 @@ static int quic_read_actual(QCTX *ctx,
stream); stream);
} }
if (*bytes_read == 0 && is_fin) if (*bytes_read == 0 && is_fin) {
ctx->xso->retired_fin = 1;
return QUIC_RAISE_NORMAL_ERROR(ctx, SSL_ERROR_ZERO_RETURN); return QUIC_RAISE_NORMAL_ERROR(ctx, SSL_ERROR_ZERO_RETURN);
}
return 1; return 1;
} }
@ -3454,7 +3458,7 @@ size_t ossl_quic_get_accept_stream_queue_len(SSL *s)
quic_lock(ctx.qc); quic_lock(ctx.qc);
v = ossl_quic_stream_map_get_accept_queue_len(ossl_quic_channel_get_qsm(ctx.qc->ch)); v = ossl_quic_stream_map_get_total_accept_queue_len(ossl_quic_channel_get_qsm(ctx.qc->ch));
quic_unlock(ctx.qc); quic_unlock(ctx.qc);
return v; return v;
@ -3487,6 +3491,8 @@ int ossl_quic_stream_reset(SSL *ssl,
} }
ok = ossl_quic_stream_map_reset_stream_send_part(qsm, qs, error_code); ok = ossl_quic_stream_map_reset_stream_send_part(qsm, qs, error_code);
if (ok)
ctx.xso->requested_reset = 1;
err: err:
quic_unlock(ctx.qc); quic_unlock(ctx.qc);
@ -3836,6 +3842,146 @@ int ossl_quic_get_shutdown(const SSL *s)
return shut; return shut;
} }
/*
* QUIC Polling Support APIs
* =========================
*/
/* Do we have the R (read) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_r(QUIC_XSO *xso)
{
int fin = 0;
size_t avail = 0;
return ossl_quic_stream_has_recv_buffer(xso->stream)
&& ossl_quic_rstream_available(xso->stream->rstream, &avail, &fin)
&& (avail > 0 || (fin && !xso->retired_fin));
}
/* Do we have the ER (exception: read) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_er(QUIC_XSO *xso)
{
return ossl_quic_stream_has_recv(xso->stream)
&& ossl_quic_stream_recv_is_reset(xso->stream)
&& !xso->retired_fin;
}
/* Do we have the W (write) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_w(QUIC_XSO *xso)
{
return !xso->conn->shutting_down
&& ossl_quic_stream_has_send_buffer(xso->stream)
&& ossl_quic_sstream_get_buffer_avail(xso->stream->sstream)
&& !ossl_quic_sstream_get_final_size(xso->stream->sstream, NULL)
&& quic_mutation_allowed(xso->conn, /*req_active=*/1);
}
/* Do we have the EW (exception: write) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_ew(QUIC_XSO *xso)
{
return ossl_quic_stream_has_send(xso->stream)
&& xso->stream->peer_stop_sending
&& !xso->requested_reset
&& !xso->conn->shutting_down;
}
/* Do we have the EC (exception: connection) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_ec(QUIC_CONNECTION *qc)
{
return ossl_quic_channel_is_term_any(qc->ch);
}
/* Do we have the ECD (exception: connection drained) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_ecd(QUIC_CONNECTION *qc)
{
return ossl_quic_channel_is_terminated(qc->ch);
}
/* Do we have the IS (incoming: stream) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_is(QUIC_CONNECTION *qc, int is_uni)
{
return ossl_quic_stream_map_get_accept_queue_len(ossl_quic_channel_get_qsm(qc->ch),
is_uni);
}
/* Do we have the OS (outgoing: stream) condition? */
QUIC_NEEDS_LOCK
static int test_poll_event_os(QUIC_CONNECTION *qc, int is_uni)
{
/* Is it currently possible for us to make an outgoing stream? */
return quic_mutation_allowed(qc, /*req_active=*/1)
&& ossl_quic_channel_get_local_stream_count_avail(qc->ch, is_uni) > 0;
}
QUIC_TAKES_LOCK
int ossl_quic_conn_poll_events(SSL *ssl, uint64_t events, uint64_t *p_revents)
{
QCTX ctx;
uint64_t revents = 0;
if (!expect_quic(ssl, &ctx))
return 0;
quic_lock(ctx.qc);
if (ctx.xso != NULL) {
/* SSL object has a stream component. */
if ((events & SSL_POLL_EVENT_R) != 0
&& test_poll_event_r(ctx.xso))
revents |= SSL_POLL_EVENT_R;
if ((events & SSL_POLL_EVENT_ER) != 0
&& test_poll_event_er(ctx.xso))
revents |= SSL_POLL_EVENT_ER;
if ((events & SSL_POLL_EVENT_W) != 0
&& test_poll_event_w(ctx.xso))
revents |= SSL_POLL_EVENT_W;
if ((events & SSL_POLL_EVENT_EW) != 0
&& test_poll_event_ew(ctx.xso))
revents |= SSL_POLL_EVENT_EW;
}
if (!ctx.is_stream) {
if ((events & SSL_POLL_EVENT_EC) != 0
&& test_poll_event_ec(ctx.qc))
revents |= SSL_POLL_EVENT_EC;
if ((events & SSL_POLL_EVENT_ECD) != 0
&& test_poll_event_ecd(ctx.qc))
revents |= SSL_POLL_EVENT_ECD;
if ((events & SSL_POLL_EVENT_ISB) != 0
&& test_poll_event_is(ctx.qc, /*uni=*/0))
revents |= SSL_POLL_EVENT_ISB;
if ((events & SSL_POLL_EVENT_ISU) != 0
&& test_poll_event_is(ctx.qc, /*uni=*/1))
revents |= SSL_POLL_EVENT_ISU;
if ((events & SSL_POLL_EVENT_OSB) != 0
&& test_poll_event_os(ctx.qc, /*uni=*/0))
revents |= SSL_POLL_EVENT_OSB;
if ((events & SSL_POLL_EVENT_OSU) != 0
&& test_poll_event_os(ctx.qc, /*uni=*/1))
revents |= SSL_POLL_EVENT_OSU;
}
quic_unlock(ctx.qc);
*p_revents = revents;
return 1;
}
/* /*
* Internal Testing APIs * Internal Testing APIs
* ===================== * =====================

View File

@ -54,6 +54,15 @@ struct quic_xso_st {
*/ */
unsigned int desires_blocking_set : 1; unsigned int desires_blocking_set : 1;
/* The application has retired a FIN (i.e. SSL_ERROR_ZERO_RETURN). */
unsigned int retired_fin : 1;
/*
* The application has requested a reset. Not set for reflexive
* STREAM_RESETs caused by peer STOP_SENDING.
*/
unsigned int requested_reset : 1;
/* /*
* This state tracks SSL_write all-or-nothing (AON) write semantics * This state tracks SSL_write all-or-nothing (AON) write semantics
* emulation. * emulation.