We enable querying of the termination reason which is useful for tests.
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20030)
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.
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);
# include <openssl/ssl.h>
# include "internal/quic_stream.h"
+# include "internal/quic_channel.h"
# ifndef OPENSSL_NO_QUIC
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
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)
*/
/* 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();
* 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) {
* 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);
}
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);
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))
{
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;
# 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
* ======================
/* 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) {
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 (!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. */
}
/* 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,
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);
}