diff options
author | Hugo Landau <hlandau@openssl.org> | 2024-02-02 12:21:28 +0000 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2024-02-10 11:37:14 +0000 |
commit | 6ba77d674335c92c29dcabab2682d2ecdd1ceb5a (patch) | |
tree | 5207e62f2bc89463d03b9de5167d1a2068993061 | |
parent | a5d16ac371245bd87e9ec264763a16db7015d59b (diff) |
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)
-rw-r--r-- | include/internal/quic_ssl.h | 3 | ||||
-rw-r--r-- | ssl/quic/quic_impl.c | 154 | ||||
-rw-r--r-- | ssl/quic/quic_local.h | 9 |
3 files changed, 162 insertions, 4 deletions
diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h index 38963d6bdc..b8922363bd 100644 --- a/include/internal/quic_ssl.h +++ b/include/internal/quic_ssl.h @@ -142,6 +142,9 @@ int ossl_quic_get_shutdown(const SSL *s); */ 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 diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index af505d1203..42e7b085e7 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -2639,10 +2639,12 @@ static int quic_read_actual(QCTX *ctx, QUIC_CONNECTION *qc = ctx->qc; 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); - else + } else { return QUIC_RAISE_NON_NORMAL_ERROR(ctx, err, NULL); + } } if (peek) { @@ -2684,8 +2686,10 @@ static int quic_read_actual(QCTX *ctx, 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 1; } @@ -3454,7 +3458,7 @@ size_t ossl_quic_get_accept_stream_queue_len(SSL *s) 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); 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); + if (ok) + ctx.xso->requested_reset = 1; err: quic_unlock(ctx.qc); @@ -3837,6 +3843,146 @@ int ossl_quic_get_shutdown(const SSL *s) } /* + * 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 * ===================== */ diff --git a/ssl/quic/quic_local.h b/ssl/quic/quic_local.h index ca95f46f52..cd65610cd8 100644 --- a/ssl/quic/quic_local.h +++ b/ssl/quic/quic_local.h @@ -54,6 +54,15 @@ struct quic_xso_st { */ 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 * emulation. |