From: Matt Caswell Date: Thu, 1 Dec 2022 16:37:47 +0000 (+0000) Subject: Enable QUIC test server to find out the termination reason X-Git-Tag: openssl-3.2.0-alpha1~1260 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=149a8e6c0a279b0dbbced72ffa6c5ed870a1bbc0;p=thirdparty%2Fopenssl.git Enable QUIC test server to find out the termination reason We enable querying of the termination reason which is useful for tests. Reviewed-by: Hugo Landau Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/20030) --- diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index a4039d8c022..4048bcd9c9f 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -64,6 +64,34 @@ typedef struct quic_channel_args_st { typedef struct quic_channel_st QUIC_CHANNEL; +/* Represents the cause for a connection's termination. */ +typedef struct quic_terminate_cause_st { + /* + * If we are in a TERMINATING or TERMINATED state, this is the error code + * associated with the error. This field is valid iff we are in the + * TERMINATING or TERMINATED states. + */ + uint64_t error_code; + + /* + * If terminate_app is set and this is nonzero, this is the frame type which + * caused the connection to be terminated. + */ + uint64_t frame_type; + + /* Is this error code in the transport (0) or application (1) space? */ + unsigned int app : 1; + + /* + * If set, the cause of the termination is a received CONNECTION_CLOSE + * frame. Otherwise, we decided to terminate ourselves and sent a + * CONNECTION_CLOSE frame (regardless of whether the peer later also sends + * one). + */ + unsigned int remote : 1; +} QUIC_TERMINATE_CAUSE; + + /* * Create a new QUIC channel using the given arguments. The argument structure * does not need to remain allocated. Returns NULL on failure. @@ -158,9 +186,12 @@ QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch, uint64_t stream_id); /* Returns 1 if channel is terminating or terminated. */ -int ossl_quic_channel_is_term_any(const QUIC_CHANNEL *ch); -int ossl_quic_channel_is_terminating(const QUIC_CHANNEL *ch); -int ossl_quic_channel_is_terminated(const QUIC_CHANNEL *ch); +int ossl_quic_channel_is_term_any(const QUIC_CHANNEL *ch, + QUIC_TERMINATE_CAUSE *cause); +int ossl_quic_channel_is_terminating(const QUIC_CHANNEL *ch, + QUIC_TERMINATE_CAUSE *cause); +int ossl_quic_channel_is_terminated(const QUIC_CHANNEL *ch, + QUIC_TERMINATE_CAUSE *cause); int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch); diff --git a/include/internal/quic_tserver.h b/include/internal/quic_tserver.h index 0d564d8c21b..cd26c81042b 100644 --- a/include/internal/quic_tserver.h +++ b/include/internal/quic_tserver.h @@ -12,6 +12,7 @@ # include # include "internal/quic_stream.h" +# include "internal/quic_channel.h" # ifndef OPENSSL_NO_QUIC @@ -54,8 +55,12 @@ int ossl_quic_tserver_tick(QUIC_TSERVER *srv); int ossl_quic_tserver_is_connected(QUIC_TSERVER *srv); /* Returns 1 if the server is in any terminating or terminated state */ -int ossl_quic_tserver_is_term_any(QUIC_TSERVER *srv); +int ossl_quic_tserver_is_term_any(QUIC_TSERVER *srv, + QUIC_TERMINATE_CAUSE *cause); +/* Returns 1 if the server is in a terminated state */ +int ossl_quic_tserver_is_terminated(QUIC_TSERVER *srv, + QUIC_TERMINATE_CAUSE *cause); /* * Attempts to read from stream 0. Writes the number of bytes read to * *bytes_read and returns 1 on success. If no bytes are available, 0 is written diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 6a0cc6d0049..293dddd2986 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -398,21 +398,34 @@ int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch) return ch != NULL && ch->state == QUIC_CHANNEL_STATE_ACTIVE; } -int ossl_quic_channel_is_terminating(const QUIC_CHANNEL *ch) +int ossl_quic_channel_is_terminating(const QUIC_CHANNEL *ch, + QUIC_TERMINATE_CAUSE *cause) { - return ch->state == QUIC_CHANNEL_STATE_TERMINATING_CLOSING - || ch->state == QUIC_CHANNEL_STATE_TERMINATING_DRAINING; + if (ch->state == QUIC_CHANNEL_STATE_TERMINATING_CLOSING + || ch->state == QUIC_CHANNEL_STATE_TERMINATING_DRAINING) { + if (cause != NULL) + *cause = ch->terminate_cause; + return 1; + } + return 0; } -int ossl_quic_channel_is_terminated(const QUIC_CHANNEL *ch) +int ossl_quic_channel_is_terminated(const QUIC_CHANNEL *ch, + QUIC_TERMINATE_CAUSE *cause) { - return ch->state == QUIC_CHANNEL_STATE_TERMINATED; + if (ch->state == QUIC_CHANNEL_STATE_TERMINATED) { + if (cause != NULL) + *cause = ch->terminate_cause; + return 1; + } + return 0; } -int ossl_quic_channel_is_term_any(const QUIC_CHANNEL *ch) +int ossl_quic_channel_is_term_any(const QUIC_CHANNEL *ch, + QUIC_TERMINATE_CAUSE *cause) { - return ossl_quic_channel_is_terminating(ch) - || ossl_quic_channel_is_terminated(ch); + return ossl_quic_channel_is_terminating(ch, cause) + || ossl_quic_channel_is_terminated(ch, cause); } int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch) @@ -1191,7 +1204,7 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg) */ /* If we are in the TERMINATED state, there is nothing to do. */ - if (ossl_quic_channel_is_terminated(ch)) { + if (ossl_quic_channel_is_terminated(ch, NULL)) { res->net_read_desired = 0; res->net_write_desired = 0; res->tick_deadline = ossl_time_infinite(); @@ -1202,7 +1215,7 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg) * If we are in the TERMINATING state, check if the terminating timer has * expired. */ - if (ossl_quic_channel_is_terminating(ch)) { + if (ossl_quic_channel_is_terminating(ch, NULL)) { now = ossl_time_now(); if (ossl_time_compare(now, ch->terminate_deadline) >= 0) { @@ -1273,11 +1286,11 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg) * errors in ch_rx_pre() or ch_tx() may have caused us to transition to the * Terminated state. */ - res->net_read_desired = !ossl_quic_channel_is_terminated(ch); + res->net_read_desired = !ossl_quic_channel_is_terminated(ch, NULL); /* We want to write to the network if we have any in our queue. */ res->net_write_desired - = (!ossl_quic_channel_is_terminated(ch) + = (!ossl_quic_channel_is_terminated(ch, NULL) && ossl_qtx_get_queue_len_datagrams(ch->qtx) > 0); } @@ -1581,7 +1594,7 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) OSSL_TIME deadline; uint32_t pn_space; - if (ossl_quic_channel_is_terminated(ch)) + if (ossl_quic_channel_is_terminated(ch, NULL)) return ossl_time_infinite(); deadline = ossl_ackm_get_loss_detection_deadline(ch->ackm); @@ -1599,7 +1612,7 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) ch->cc_method->get_next_credit_time(ch->cc_data)); /* Is the terminating timer armed? */ - if (ossl_quic_channel_is_terminating(ch)) + if (ossl_quic_channel_is_terminating(ch, NULL)) deadline = ossl_time_min(deadline, ch->terminate_deadline); else if (!ossl_time_is_infinite(ch->idle_deadline)) @@ -1729,7 +1742,7 @@ void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code) { QUIC_TERMINATE_CAUSE tcause = {0}; - if (ossl_quic_channel_is_term_any(ch)) + if (ossl_quic_channel_is_term_any(ch, NULL)) return; tcause.app = 1; diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h index 2240ad6e203..fa2618bce54 100644 --- a/ssl/quic/quic_channel_local.h +++ b/ssl/quic/quic_channel_local.h @@ -5,33 +5,6 @@ # ifndef OPENSSL_NO_QUIC -/* Represents the cause for a connection's termination. */ -typedef struct quic_terminate_cause_st { - /* - * If we are in a TERMINATING or TERMINATED state, this is the error code - * associated with the error. This field is valid iff we are in the - * TERMINATING or TERMINATED states. - */ - uint64_t error_code; - - /* - * If terminate_app is set and this is nonzero, this is the frame type which - * caused the connection to be terminated. - */ - uint64_t frame_type; - - /* Is this error code in the transport (0) or application (1) space? */ - unsigned int app : 1; - - /* - * If set, the cause of the termination is a received CONNECTION_CLOSE - * frame. Otherwise, we decided to terminate ourselves and sent a - * CONNECTION_CLOSE frame (regardless of whether the peer later also sends - * one). - */ - unsigned int remote : 1; -} QUIC_TERMINATE_CAUSE; - /* * QUIC Channel Structure * ====================== diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 5448e32e73f..bb9132eb759 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -646,7 +646,7 @@ int ossl_quic_do_handshake(QUIC_CONNECTION *qc) /* Handshake already completed. */ return 1; - if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch)) + if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch, NULL)) return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL); if (BIO_ADDR_family(&qc->init_peer_addr) == AF_UNSPEC) { @@ -1012,7 +1012,7 @@ int ossl_quic_write(SSL *s, const void *buf, size_t len, size_t *written) if (!expect_quic_conn(qc)) return 0; - if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch)) + if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch, NULL)) return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL); /* @@ -1133,7 +1133,7 @@ static int quic_read(SSL *s, void *buf, size_t len, size_t *bytes_read, int peek if (!expect_quic_conn(qc)) return 0; - if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch)) + if (qc->ch != NULL && ossl_quic_channel_is_term_any(qc->ch, NULL)) return QUIC_RAISE_NON_NORMAL_ERROR(qc, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL); /* If we haven't finished the handshake, try to advance it. */ diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index ea131ca9c15..1bb17e8e53e 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -148,9 +148,17 @@ int ossl_quic_tserver_is_connected(QUIC_TSERVER *srv) } /* Returns 1 if the server is in any terminating or terminated state */ -int ossl_quic_tserver_is_term_any(QUIC_TSERVER *srv) +int ossl_quic_tserver_is_term_any(QUIC_TSERVER *srv, + QUIC_TERMINATE_CAUSE *cause) { - return ossl_quic_channel_is_term_any(srv->ch); + return ossl_quic_channel_is_term_any(srv->ch, cause); +} + +/* Returns 1 if the server is in a terminated state */ +int ossl_quic_tserver_is_terminated(QUIC_TSERVER *srv, + QUIC_TERMINATE_CAUSE *cause) +{ + return ossl_quic_channel_is_terminated(srv->ch, cause); } int ossl_quic_tserver_read(QUIC_TSERVER *srv, diff --git a/test/helpers/quictestlib.c b/test/helpers/quictestlib.c index 3886014c3c5..34672a5913b 100644 --- a/test/helpers/quictestlib.c +++ b/test/helpers/quictestlib.c @@ -144,7 +144,7 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl) SSL_tick(clientssl); if (!servererr) { ossl_quic_tserver_tick(qtserv); - servererr = ossl_quic_tserver_is_term_any(qtserv); + servererr = ossl_quic_tserver_is_term_any(qtserv, NULL); if (!servererr && !rets) rets = ossl_quic_tserver_is_connected(qtserv); }