int touch, QUIC_XSO **old_xso);
static SSL *quic_conn_stream_new(QCTX *ctx, uint64_t flags, int need_lock);
static int quic_validate_for_write(QUIC_XSO *xso, int *err);
+static int quic_mutation_allowed(QUIC_CONNECTION *qc, int req_active);
/*
* QUIC Front-End I/O API: Common Utilities
quic_lock(ctx->qc);
if (ctx->xso == NULL && remote_init >= 0) {
- if (ossl_quic_channel_is_term_any(ctx->qc->ch)) {
+ if (!quic_mutation_allowed(ctx->qc, /*req_active=*/0)) {
QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
goto err;
}
#endif
}
+/*
+ * This predicate is the criterion which should determine API call rejection for
+ * *most* mutating API calls, particularly stream-related operations for send
+ * parts.
+ *
+ * A call is rejected (this function returns 0) if shutdown is in progress
+ * (stream flushing), or we are in a TERMINATING or TERMINATED state. If
+ * req_active=1, the connection must be active (i.e., the IDLE state is also
+ * rejected).
+ */
+static int quic_mutation_allowed(QUIC_CONNECTION *qc, int req_active)
+{
+ if (qc->shutting_down || ossl_quic_channel_is_term_any(qc->ch))
+ return 0;
+
+ if (req_active && !ossl_quic_channel_is_active(qc->ch))
+ return 0;
+
+ return 1;
+}
/*
* QUIC Front-End I/O API: Initialization
{
struct quic_handshake_wait_args *args = arg;
- if (!ossl_quic_channel_is_active(args->qc->ch))
+ if (!quic_mutation_allowed(args->qc, /*req_active=*/1))
return -1;
if (ossl_quic_channel_is_handshake_complete(args->qc->ch))
/* Handshake already completed. */
return 1;
- if (ossl_quic_channel_is_term_any(qc->ch))
+ if (!quic_mutation_allowed(qc, /*req_active=*/0))
return QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
if (BIO_ADDR_family(&qc->init_peer_addr) == AF_UNSPEC) {
args.qc = qc;
ret = block_until_pred(qc, quic_handshake_wait, &args, 0);
- if (!ossl_quic_channel_is_active(qc->ch)) {
+ if (!quic_mutation_allowed(qc, /*req_active=*/1)) {
QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
return 0; /* Shutdown before completion */
} else if (ret <= 0) {
{
struct quic_wait_for_stream_args *args = arg;
- if (!ossl_quic_channel_is_active(args->qc->ch)) {
+ if (!quic_mutation_allowed(args->qc, /*req_active=*/1)) {
/* If connection is torn down due to an error while blocking, stop. */
QUIC_RAISE_NON_NORMAL_ERROR(args->ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
return -1;
if (need_lock)
quic_lock(qc);
- if (ossl_quic_channel_is_term_any(qc->ch)) {
+ if (!quic_mutation_allowed(qc, /*req_active=*/0)) {
QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
goto err;
}
struct quic_write_again_args *args = arg;
size_t actual_written = 0;
- if (!ossl_quic_channel_is_active(args->xso->conn->ch))
+ if (!quic_mutation_allowed(args->xso->conn, /*req_active=*/1))
/* If connection is torn down due to an error while blocking, stop. */
return -2;
res = block_until_pred(xso->conn, quic_write_again, &args, 0);
if (res <= 0) {
- if (!ossl_quic_channel_is_active(xso->conn->ch))
+ if (!quic_mutation_allowed(xso->conn, /*req_active=*/1))
return QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
else
return QUIC_RAISE_NON_NORMAL_ERROR(ctx, args.err, NULL);
partial_write = ((ctx.xso->ssl_mode & SSL_MODE_ENABLE_PARTIAL_WRITE) != 0);
- if (ossl_quic_channel_is_term_any(ctx.qc->ch)) {
+ if (!quic_mutation_allowed(ctx.qc, /*req_active=*/0)) {
ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
goto out;
}
{
struct quic_read_again_args *args = arg;
- if (!ossl_quic_channel_is_active(args->ctx->qc->ch)) {
+ if (!quic_mutation_allowed(args->ctx->qc, /*req_active=*/1)) {
/* If connection is torn down due to an error while blocking, stop. */
QUIC_RAISE_NON_NORMAL_ERROR(args->ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
return -1;
quic_lock(ctx.qc);
- if (ossl_quic_channel_is_term_any(ctx.qc->ch)) {
+ if (!quic_mutation_allowed(ctx.qc, /*req_active=*/0)) {
ret = QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
goto out;
}
qs = ctx.xso->stream;
- if (!ossl_quic_channel_is_active(ctx.qc->ch)) {
+ if (!quic_mutation_allowed(ctx.qc, /*req_active=*/1)) {
quic_unlock(ctx.qc);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
}
QUIC_CONNECTION *qc = args->ctx->qc;
QUIC_STREAM_MAP *qsm = ossl_quic_channel_get_qsm(qc->ch);
- if (!ossl_quic_channel_is_active(qc->ch)) {
+ if (!quic_mutation_allowed(qc, /*req_active=*/1)) {
/* If connection is torn down due to an error while blocking, stop. */
QUIC_RAISE_NON_NORMAL_ERROR(args->ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
return -1;