static QUIC_XSO *create_xso_from_stream(QUIC_CONNECTION *qc, QUIC_STREAM *qs);
static int qc_try_create_default_xso_for_write(QCTX *ctx);
static int qc_wait_for_default_xso_for_read(QCTX *ctx, int peek);
-static void quic_lock(QUIC_CONNECTION *qc);
-static void quic_unlock(QUIC_CONNECTION *qc);
+static void qctx_lock(QCTX *qctx);
+static void qctx_unlock(QCTX *qctx);
static void quic_lock_for_io(QCTX *ctx);
static int quic_do_handshake(QCTX *ctx);
static void qc_update_reject_policy(QUIC_CONNECTION *qc);
* - whether a QSSO was passed (xso == NULL must not be used to determine this
* because it may be non-NULL when a QCSO is passed if that QCSO has a
* default stream);
+ * - a pointer to a QUIC_LISTENER object, if one is relevant;
* - whether we are in "I/O context", meaning that non-normal errors can
* be reported via SSL_get_error() as well as via ERR. Functions such as
* SSL_read(), SSL_write() and SSL_do_handshake() are "I/O context"
* of SSL_get_error.
*/
struct qctx_st {
+ QUIC_OBJ *obj;
+ QUIC_LISTENER *ql;
QUIC_CONNECTION *qc;
QUIC_XSO *xso;
- int is_stream, in_io;
+ int is_stream, is_listener, in_io;
};
QUIC_NEEDS_LOCK
(msg))
/*
- * Given a QCSO or QSSO, initialises a QCTX, determining the contextually
- * applicable QUIC_CONNECTION pointer and, if applicable, QUIC_XSO pointer.
+ * Given a QCSO, QSSO or QLSO, initialises a QCTX, determining the contextually
+ * applicable QUIC_LISTENER, QUIC_CONNECTION, QUIC_XSO and QUIC_CONNECTION
+ * pointers.
*
* After this returns 1, all fields of the passed QCTX are initialised.
* Returns 0 on failure. This function is intended to be used to provide API
* semantics and as such, it invokes QUIC_RAISE_NON_NORMAL_ERROR() on failure.
*/
-static int expect_quic(const SSL *s, QCTX *ctx)
+static int expect_quic_any(const SSL *s, QCTX *ctx)
{
+ QUIC_LISTENER *ql;
QUIC_CONNECTION *qc;
QUIC_XSO *xso;
- ctx->qc = NULL;
- ctx->xso = NULL;
- ctx->is_stream = 0;
+ ctx->obj = NULL;
+ ctx->ql = NULL;
+ ctx->qc = NULL;
+ ctx->xso = NULL;
+ ctx->is_stream = 0;
+ ctx->is_listener = 0;
if (s == NULL)
return QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_PASSED_NULL_PARAMETER, NULL);
switch (s->type) {
case SSL_TYPE_QUIC_CONNECTION:
qc = (QUIC_CONNECTION *)s;
+ ctx->obj = &qc->obj;
+ ctx->ql = qc->listener;
ctx->qc = qc;
ctx->xso = qc->default_xso;
ctx->is_stream = 0;
case SSL_TYPE_QUIC_XSO:
xso = (QUIC_XSO *)s;
+ ctx->obj = &xso->obj;
+ ctx->ql = xso->conn->listener;
ctx->qc = xso->conn;
ctx->xso = xso;
ctx->is_stream = 1;
ctx->in_io = 0;
return 1;
+ case SSL_TYPE_QUIC_LISTENER:
+ ql = (QUIC_LISTENER *)s;
+ ctx->obj = &ql->obj;
+ ctx->ql = ql;
+ ctx->is_listener = 1;
+ ctx->in_io = 0;
+ return 1;
+
default:
return QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL);
}
}
+/*
+ * Given a QCSO or QSSO, initialises a QCTX, determining the contextually
+ * applicable QUIC_CONNECTION pointer and, if applicable, QUIC_XSO pointer.
+ *
+ * After this returns 1, all fields of the passed QCTX are initialised.
+ * Returns 0 on failure. This function is intended to be used to provide API
+ * semantics and as such, it invokes QUIC_RAISE_NON_NORMAL_ERROR() on failure.
+ */
+static int expect_quic(const SSL *s, QCTX *ctx)
+{
+ if (!expect_quic_any(s, ctx))
+ return 0;
+
+ if (ctx->obj->ssl.type == SSL_TYPE_QUIC_LISTENER)
+ return QUIC_RAISE_NON_NORMAL_ERROR(NULL, SSL_R_CONN_USE_ONLY, NULL);
+
+ return 1;
+}
+
+static int expect_quic_listener(const SSL *s, QCTX *ctx)
+{
+ if (!expect_quic_any(s, ctx))
+ return 0;
+
+ if (ctx->obj->ssl.type != SSL_TYPE_QUIC_LISTENER)
+ return QUIC_RAISE_NON_NORMAL_ERROR(NULL, SSL_R_LISTENER_USE_ONLY, NULL);
+
+ return 1;
+}
+
/*
* Like expect_quic(), but requires a QUIC_XSO be contextually available. In
* other words, requires that the passed QSO be a QSSO or a QCSO with a default
if (in_io)
quic_lock_for_io(ctx);
else
- quic_lock(ctx->qc);
+ qctx_lock(ctx);
if (ctx->xso == NULL && remote_init >= 0) {
if (!quic_mutation_allowed(ctx->qc, /*req_active=*/0)) {
return 1; /* coverity[missing_unlock]: lock held */
err:
- quic_unlock(ctx->qc);
+ qctx_unlock(ctx);
return 0;
}
}
/*
- * Ensures that the channel mutex is held for a method which touches channel
+ * Ensures that the domain mutex is held for a method which touches channel
* state.
*
- * Precondition: Channel mutex is not held (unchecked)
+ * Precondition: Domain mutex is not held (unchecked)
*/
-static void quic_lock(QUIC_CONNECTION *qc)
+static void qctx_lock(QCTX *ctx)
+{
+#if defined(OPENSSL_THREADS)
+ assert(ctx->obj != NULL);
+ ossl_crypto_mutex_lock(ossl_quic_obj_get0_mutex(ctx->obj));
+#endif
+}
+
+/* Precondition: Channel mutex is held (unchecked) */
+QUIC_NEEDS_LOCK
+static void qctx_unlock(QCTX *ctx)
{
#if defined(OPENSSL_THREADS)
- ossl_crypto_mutex_lock(qc->mutex);
+ assert(ctx->obj != NULL);
+ ossl_crypto_mutex_unlock(ossl_quic_obj_get0_mutex(ctx->obj));
#endif
}
static void quic_lock_for_io(QCTX *ctx)
{
- quic_lock(ctx->qc);
+ qctx_lock(ctx);
ctx->in_io = 1;
/*
quic_set_last_error(ctx, SSL_ERROR_NONE);
}
-/* Precondition: Channel mutex is held (unchecked) */
-QUIC_NEEDS_LOCK
-static void quic_unlock(QUIC_CONNECTION *qc)
-{
-#if defined(OPENSSL_THREADS)
- ossl_crypto_mutex_unlock(qc->mutex);
-#endif
-}
-
/*
* This predicate is the criterion which should determine API call rejection for
* *most* mutating API calls, particularly stream-related operations for send
qc->tls = NULL;
if (have_lock)
- quic_unlock(qc); /* tsan doesn't like freeing locked mutexes */
+ /* tsan doesn't like freeing locked mutexes */
+ ossl_crypto_mutex_unlock(qc->mutex);
#if defined(OPENSSL_THREADS)
ossl_crypto_mutex_free(&qc->mutex);
if (!expect_quic(s, &ctx))
return;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (ctx.is_stream) {
/*
ctx.xso->stream);
is_default = (ctx.xso == ctx.qc->default_xso);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
/*
* Unref the connection in most cases; the XSO has a ref to the QC and
if (ctx.qc->default_xso != NULL) {
QUIC_XSO *xso = ctx.qc->default_xso;
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
SSL_free(&xso->obj.ssl);
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
ctx.qc->default_xso = NULL;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
ctx.qc->override_now_cb = now_cb;
ctx.qc->override_now_cb_arg = now_cb_arg;
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
if (!expect_quic(ssl, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (!ctx.is_stream) {
/*
ret = ctx.is_stream ? ctx.xso->ssl_options : ctx.qc->default_ssl_options;
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
/* Sanity check - can we support the request given the current network BIO? */
if (blocking) {
ret = 1;
out:
qc_update_blocking_mode(ctx.qc);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (ctx.qc->started)
ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(ctx.qc->ch), 0);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (ctx.qc->started)
deadline
tv->tv_sec = 1000000;
tv->tv_usec = 0;
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
*tv = ossl_time_to_timeval(ossl_time_subtract(deadline, get_time(ctx.qc)));
*is_infinite = 0;
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
ret = ossl_quic_reactor_net_read_desired(ossl_quic_channel_get_reactor(ctx.qc->ch));
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
ret = ossl_quic_reactor_net_write_desired(ossl_quic_channel_get_reactor(ctx.qc->ch));
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
return -1;
}
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (ossl_quic_channel_is_terminated(ctx.qc->ch)) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
}
if (!qc_shutdown_flush_finished(ctx.qc)) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 0; /* ongoing */
}
}
SSL_set_shutdown(ctx.qc->tls, SSL_SENT_SHUTDOWN);
if (ossl_quic_channel_is_terminated(ctx.qc->ch)) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
ret = ossl_quic_channel_is_terminated(ctx.qc->ch);
err:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
quic_lock_for_io(&ctx);
ret = quic_do_handshake(&ctx);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
int advance = ((flags & SSL_STREAM_FLAG_ADVANCE) != 0);
if (need_lock)
- quic_lock(qc);
+ qctx_lock(ctx);
if (!quic_mutation_allowed(qc, /*req_active=*/0)) {
QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
qc_touch_default_xso(qc); /* inhibits default XSO */
if (need_lock)
- quic_unlock(qc);
+ qctx_unlock(ctx);
return &xso->obj.ssl;
OPENSSL_free(xso);
ossl_quic_stream_map_release(ossl_quic_channel_get_qsm(qc->ch), qs);
if (need_lock)
- quic_unlock(qc);
+ qctx_unlock(ctx);
return NULL;
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
net_error = ossl_quic_channel_net_error(ctx.qc->ch);
last_error = ctx.is_stream ? ctx.xso->last_error : ctx.qc->last_error;
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
if (net_error)
return SSL_ERROR_SYSCALL;
if (!expect_quic(s, &ctx))
return SSL_NOTHING;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
w = error_to_want(ctx.is_stream ? ctx.xso->last_error : ctx.qc->last_error);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return w;
}
ret = quic_write_nonblocking_aon(&ctx, buf, len, flags, written);
out:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
}
out:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (!ctx.qc->started)
goto out;
/*include_fin=*/0);
out:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return avail;
}
qs = ctx.xso->stream;
if (!quic_mutation_allowed(ctx.qc, /*req_active=*/1)) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_PROTOCOL_IS_SHUTDOWN, NULL);
}
if (!quic_validate_for_write(ctx.xso, &err)) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, err, NULL);
}
if (ossl_quic_sstream_get_final_size(qs->sstream, NULL)) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
ossl_quic_sstream_fin(qs->sstream);
quic_post_write(ctx.xso, 1, 0, 0, qctx_should_autotick(&ctx));
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
if (!expect_quic(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
demux = ossl_quic_channel_get0_demux(ctx.qc->ch);
ret = ossl_quic_demux_inject(demux, buf, buf_len, peer, local);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
return UINT64_MAX;
id = ctx.xso->stream->id;
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return id;
}
return -1;
is_local = ossl_quic_stream_is_local_init(ctx.xso->stream);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return is_local;
}
if (!expect_quic_conn_only(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (ctx.qc->default_xso_created) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED,
"too late to change default stream mode");
}
ctx.qc->default_stream_mode = mode;
break;
default:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_PASSED_INVALID_ARGUMENT,
"bad default stream type");
}
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
if (!expect_quic_conn_only(s, &ctx))
return NULL;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
/* Calling this function inhibits default XSO autocreation. */
/* QC ref to any default XSO is transferred to us and to caller. */
qc_set_default_xso_keep_ref(ctx.qc, NULL, /*touch=*/1, &xso);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return xso != NULL ? &xso->obj.ssl : NULL;
}
xso = (QUIC_XSO *)stream;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (ctx.qc->default_xso != NULL) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED,
"connection already has a default stream");
}
* more than one ref.
*/
if (!CRYPTO_GET_REF(&xso->obj.ssl.references, &nref)) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_INTERNAL_ERROR,
"ref");
}
if (nref != 1) {
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return QUIC_RAISE_NON_NORMAL_ERROR(&ctx, ERR_R_PASSED_INVALID_ARGUMENT,
"stream being attached must have "
"only 1 reference");
/* Calling this function inhibits default XSO autocreation. */
qc_set_default_xso(ctx.qc, xso, /*touch=*/1);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}
if (!expect_quic_conn_only(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
switch (policy) {
case SSL_INCOMING_STREAM_POLICY_AUTO:
}
qc_update_reject_policy(ctx.qc);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
if (!expect_quic_conn_only(s, &ctx))
return NULL;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
if (qc_get_effective_incoming_stream_policy(ctx.qc)
== SSL_INCOMING_STREAM_POLICY_REJECT) {
qc_touch_default_xso(ctx.qc); /* inhibits default XSO */
out:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return new_s;
}
if (!expect_quic_conn_only(s, &ctx))
return 0;
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
v = ossl_quic_stream_map_get_total_accept_queue_len(ossl_quic_channel_get_qsm(ctx.qc->ch));
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return v;
}
ctx.xso->requested_reset = 1;
err:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ok;
}
return SSL_STREAM_STATE_NONE;
quic_classify_stream(ctx.qc, ctx.xso->stream, is_write, &state, NULL);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return state;
}
quic_classify_stream(ctx.qc, ctx.xso->stream, /*is_write=*/0,
&state, app_error_code);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
switch (state) {
case SSL_STREAM_STATE_FINISHED:
return 0;
ret = 1;
out:
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return ret;
}
return 0;
}
- quic_lock(ctx.qc);
+ qctx_lock(&ctx);
/* Attempt to perform a TXKU. */
if (!ossl_quic_channel_trigger_txku(ctx.qc->ch)) {
QUIC_RAISE_NON_NORMAL_ERROR(&ctx, SSL_R_TOO_MANY_KEY_UPDATES, NULL);
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 0;
}
- quic_unlock(ctx.qc);
+ qctx_unlock(&ctx);
return 1;
}