diff options
Diffstat (limited to 'ssl/quic/quic_impl.c')
-rw-r--r-- | ssl/quic/quic_impl.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index e3402e5c65..fbcc85e52a 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -2306,6 +2306,191 @@ size_t ossl_quic_get_accept_stream_queue_len(SSL *s) } /* + * SSL_stream_reset + * ---------------- + */ +int ossl_quic_stream_reset(SSL *ssl, + const SSL_STREAM_RESET_ARGS *args, + size_t args_len) +{ + QCTX ctx; + QUIC_STREAM_MAP *qsm; + QUIC_STREAM *qs; + uint64_t error_code; + + if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/0, &ctx)) + return 0; + + qsm = ossl_quic_channel_get_qsm(ctx.qc->ch); + qs = ctx.xso->stream; + error_code = (args != NULL ? args->quic_error_code : 0); + + ossl_quic_stream_map_reset_stream_send_part(qsm, qs, error_code); + + quic_unlock(ctx.qc); + return 1; +} + +/* + * SSL_get_stream_read_state + * ------------------------- + */ +static void quic_classify_stream(QUIC_CONNECTION *qc, + QUIC_STREAM *qs, + int is_write, + int *state, + uint64_t *app_error_code) +{ + int local_init; + uint64_t final_size; + + local_init = (ossl_quic_stream_is_server_init(qs) == qc->as_server); + + if (app_error_code != NULL) + *app_error_code = UINT64_MAX; + else + app_error_code = &final_size; /* throw away value */ + + if (!ossl_quic_stream_is_bidi(qs) && local_init != is_write) { + /* + * Unidirectional stream and this direction of transmission doesn't + * exist. + */ + *state = SSL_STREAM_STATE_WRONG_DIR; + } else if (ossl_quic_channel_is_term_any(qc->ch)) { + /* Connection already closed. */ + *state = SSL_STREAM_STATE_CONN_CLOSED; + } else if (!is_write && qs->recv_fin_retired) { + /* Application has read a FIN. */ + *state = SSL_STREAM_STATE_FINISHED; + } else if ((!is_write && qs->stop_sending) + || (is_write && qs->reset_stream)) { + /* + * Stream has been reset locally. FIN takes precedence over this for the + * read case as the application need not care if the stream is reset + * after a FIN has been successfully processed. + */ + *state = SSL_STREAM_STATE_RESET_LOCAL; + *app_error_code = !is_write + ? qs->stop_sending_aec + : qs->reset_stream_aec; + } else if ((!is_write && qs->peer_reset_stream) + || (is_write && qs->peer_stop_sending)) { + /* + * Stream has been reset remotely. */ + *state = SSL_STREAM_STATE_RESET_REMOTE; + *app_error_code = !is_write + ? qs->peer_reset_stream_aec + : qs->peer_stop_sending_aec; + } else if (is_write && ossl_quic_sstream_get_final_size(qs->sstream, + &final_size)) { + /* + * Stream has been finished. Stream reset takes precedence over this for + * the write case as peer may not have received all data. + */ + *state = SSL_STREAM_STATE_FINISHED; + } else { + /* Stream still healthy. */ + *state = SSL_STREAM_STATE_OK; + } +} + +static int quic_get_stream_state(SSL *ssl, int is_write) +{ + QCTX ctx; + int state; + + if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/-1, &ctx)) + return SSL_STREAM_STATE_NONE; + + quic_classify_stream(ctx.qc, ctx.xso->stream, is_write, &state, NULL); + quic_unlock(ctx.qc); + return state; +} + +int ossl_quic_get_stream_read_state(SSL *ssl) +{ + return quic_get_stream_state(ssl, /*is_write=*/0); +} + +/* + * SSL_get_stream_write_state + * -------------------------- + */ +int ossl_quic_get_stream_write_state(SSL *ssl) +{ + return quic_get_stream_state(ssl, /*is_write=*/1); +} + +/* + * SSL_get_stream_read_error_code + * ------------------------------ + */ +static int quic_get_stream_error_code(SSL *ssl, int is_write, + uint64_t *app_error_code) +{ + QCTX ctx; + int state; + + if (!expect_quic_with_stream_lock(ssl, /*remote_init=*/-1, &ctx)) + return -1; + + quic_classify_stream(ctx.qc, ctx.xso->stream, /*is_write=*/0, + &state, app_error_code); + + quic_unlock(ctx.qc); + switch (state) { + case SSL_STREAM_STATE_FINISHED: + return 0; + case SSL_STREAM_STATE_RESET_LOCAL: + case SSL_STREAM_STATE_RESET_REMOTE: + return 1; + default: + return -1; + } +} + +int ossl_quic_get_stream_read_error_code(SSL *ssl, uint64_t *app_error_code) +{ + return quic_get_stream_error_code(ssl, /*is_write=*/0, app_error_code); +} + +/* + * SSL_get_stream_write_error_code + * ------------------------------- + */ +int ossl_quic_get_stream_write_error_code(SSL *ssl, uint64_t *app_error_code) +{ + return quic_get_stream_error_code(ssl, /*is_write=*/1, app_error_code); +} + +/* + * SSL_get_conn_close_info + * ----------------------- + */ +int ossl_quic_get_conn_close_info(SSL *ssl, + SSL_CONN_CLOSE_INFO *info, + size_t info_len) +{ + QCTX ctx; + const QUIC_TERMINATE_CAUSE *tc; + + if (!expect_quic_conn_only(ssl, &ctx)) + return -1; + + tc = ossl_quic_channel_get_terminate_cause(ctx.qc->ch); + if (tc == NULL) + return 0; + + info->error_code = tc->error_code; + info->reason = NULL; /* TODO(QUIC): Wire reason */ + info->reason_len = 0; + info->is_local = !tc->remote; + info->is_transport = !tc->app; + return 1; +} + +/* * QUIC Front-End I/O API: SSL_CTX Management * ========================================== */ |