* To support thread assisted mode, QUIC_CHANNEL can be used by multiple
* threads. **It is the caller's responsibility to ensure that the QUIC_CHANNEL
* is only accessed (whether via its methods or via direct access to its state)
- * while the QUIC_CHANNEL mutex is held**, except for methods explicitly marked
- * as not requiring prior locking. See ossl_quic_channel_get_mutex() for more
- * information. This is an unchecked precondition.
+ * while the channel mutex is held**, except for methods explicitly marked as
+ * not requiring prior locking. This is an unchecked precondition.
+ *
+ * The instantiator of the channel is responsible for providing a suitable
+ * mutex which then serves as the channel mutex; see QUIC_CHANNEL_ARGS.
*/
# define QUIC_NEEDS_LOCK
# define QUIC_CHANNEL_STATE_TERMINATED 4
typedef struct quic_channel_args_st {
- OSSL_LIB_CTX *libctx;
- const char *propq;
- int is_server;
- SSL *tls;
+ OSSL_LIB_CTX *libctx;
+ const char *propq;
+ int is_server;
+ SSL *tls;
+
+ /*
+ * This must be a mutex the lifetime of which will exceed that of the
+ * channel. The instantiator of the channel is responsible for providing a
+ * mutex as this makes it easier to handle instantiation and teardown of
+ * channels in situations potentially requiring locking.
+ */
+ CRYPTO_RWLOCK *mutex;
} QUIC_CHANNEL_ARGS;
typedef struct quic_channel_st QUIC_CHANNEL;
SSL *ossl_quic_channel_get0_ssl(QUIC_CHANNEL *ch);
/*
- * Retreves the channel mutex, which can be used to synchronise access to
- * channel functions and internal data. In order to allow locks to be acquired
- * and released with the correct granularity, it is the caller's responsibility
- * to ensure this lock is held for write while calling any QUIC_CHANNEL method.
+ * Retrieves a pointer to the channel mutex which was provided at the time the
+ * channel was instantiated. In order to allow locks to be acquired and released
+ * with the correct granularity, it is the caller's responsibility to ensure
+ * this lock is held for write while calling any QUIC_CHANNEL method, except for
+ * methods explicitly designed otherwise.
*
* This method is thread safe and does not require prior locking. It can also be
- * called while the lock is already held.
+ * called while the lock is already held. Note that this is simply a convenience
+ * function to access the mutex which was passed to the channel at instantiation
+ * time; it does not belong to the channel but rather is presumed to belong to
+ * the owner of the channel.
*/
CRYPTO_RWLOCK *ossl_quic_channel_get_mutex(QUIC_CHANNEL *ch);
-/*
- * Locks the channel mutex. It is roughly analagous to locking the mutex
- * returned by ossl_quic_channel_get_mutex() but might be able to avoid locking
- * where thread assisted mode is not being used, thus it is recommended that
- * these methods are used uniformly rather than locking the channel mutex
- * directly.
- *
- * This method is (obviously) thread safe and does not require prior locking. It
- * must not be called while the lock is already held.
- */
-int ossl_quic_channel_lock(QUIC_CHANNEL *ch);
-
-/* Unlocks the channel mutex. */
-void ossl_quic_channel_unlock(QUIC_CHANNEL *ch);
-
# endif
#endif
qtx_args.mdpl = QUIC_MIN_INITIAL_DGRAM_LEN;
ch->rx_max_udp_payload_size = qtx_args.mdpl;
- ch->mutex = CRYPTO_THREAD_lock_new();
- if (ch->mutex == NULL)
- goto err;
-
ch->qtx = ossl_qtx_new(&qtx_args);
if (ch->qtx == NULL)
goto err;
ossl_qrx_free(ch->qrx);
ossl_quic_demux_free(ch->demux);
OPENSSL_free(ch->local_transport_params);
- CRYPTO_THREAD_lock_free(ch->mutex);
}
QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args)
ch->propq = args->propq;
ch->is_server = args->is_server;
ch->tls = args->tls;
+ ch->mutex = args->mutex;
if (!ch_init(ch)) {
OPENSSL_free(ch);
return ch->mutex;
}
-int ossl_quic_channel_lock(QUIC_CHANNEL *ch)
-{
- return ossl_crypto_mutex_lock(ch->mutex);
-}
-
-void ossl_quic_channel_unlock(QUIC_CHANNEL *ch)
-{
- ossl_crypto_mutex_unlock(ch->mutex);
-}
-
/*
* QUIC Channel: Callbacks from Miscellaneous Subsidiary Components
* ================================================================
/*
* Master synchronisation mutex used for thread assisted mode
- * synchronisation.
+ * synchronisation. We don't own this; the instantiator of the channel
+ * passes it to us and is responsible for freeing it after channel
+ * destruction.
*/
CRYPTO_RWLOCK *mutex;
rtor = ossl_quic_channel_get_reactor(qc->ch);
return ossl_quic_reactor_block_until_pred(rtor, pred, pred_arg, flags,
- ossl_quic_channel_get_mutex(qc->ch));
+ qc->mutex);
}
/*
}
+/*
+ * Ensures that the channel mutex is held for a method which touches channel
+ * state.
+ *
+ * Precondition: Channel mutex is not held (unchecked)
+ */
+static int quic_lock(QUIC_CONNECTION *qc)
+{
+ return CRYPTO_THREAD_write_lock(qc->mutex);
+}
+
+/* Precondition: Channel mutex is held (unchecked) */
+QUIC_NEEDS_LOCK
+static void quic_unlock(QUIC_CONNECTION *qc)
+{
+ CRYPTO_THREAD_unlock(qc->mutex);
+}
+
+
/*
* QUIC Front-End I/O API: Initialization
* ======================================
if (qc->tls == NULL || (sc = SSL_CONNECTION_FROM_SSL(qc->tls)) == NULL)
goto err;
+ if ((qc->mutex = CRYPTO_THREAD_lock_new()) == NULL)
+ goto err;
+
/* Channel is not created yet. */
qc->ssl_mode = qc->ssl.ctx->mode;
qc->last_error = SSL_ERROR_NONE;
return ssl_base;
err:
+ SSL_free(qc->tls);
OPENSSL_free(qc);
return NULL;
}
/* Note: SSL_free calls OPENSSL_free(qc) for us */
SSL_free(qc->tls);
+ CRYPTO_THREAD_lock_free(qc->mutex);
}
/* SSL method init */
return 1;
}
-QUIC_TODO_LOCK
+QUIC_NEEDS_LOCK
static int ensure_channel(QUIC_CONNECTION *qc)
{
QUIC_CHANNEL_ARGS args = {0};
* via calls made to us from the application prior to starting a handshake
* attempt.
*/
-QUIC_TODO_LOCK
+QUIC_NEEDS_LOCK
static int ensure_channel_and_start(QUIC_CONNECTION *qc)
{
if (!ensure_channel(qc))
* - SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER.
*
*/
+QUIC_NEEDS_LOCK
static void quic_post_write(QUIC_CONNECTION *qc, int did_append, int do_tick)
{
/*
size_t total_written;
};
+QUIC_NEEDS_LOCK
static int quic_write_again(void *arg)
{
struct quic_write_again_args *args = arg;
return 0;
}
+QUIC_NEEDS_LOCK
static int quic_write_blocking(QUIC_CONNECTION *qc, const void *buf, size_t len,
size_t *written)
{
qc->aon_buf_len = 0;
}
+QUIC_NEEDS_LOCK
static int quic_write_nonblocking_aon(QUIC_CONNECTION *qc, const void *buf,
size_t len, size_t *written)
{
return QUIC_RAISE_NORMAL_ERROR(qc, SSL_ERROR_WANT_WRITE);
}
+QUIC_NEEDS_LOCK
static int quic_write_nonblocking_epw(QUIC_CONNECTION *qc, const void *buf, size_t len,
size_t *written)
{
int peek;
};
+QUIC_NEEDS_LOCK
static int quic_read_actual(QUIC_CONNECTION *qc,
QUIC_STREAM *stream,
void *buf, size_t buf_len,
return 1;
}
+QUIC_NEEDS_LOCK
static int quic_read_again(void *arg)
{
struct quic_read_again_args *args = arg;
*/
QUIC_CHANNEL *ch;
+ /*
+ * The mutex used to synchronise access to the QUIC_CHANNEL. We own this but
+ * provide it to the channel.
+ */
+ CRYPTO_RWLOCK *mutex;
+
/* Our single bidirectional application data stream. */
QUIC_STREAM *stream0;