about summary refs log tree commit diff
path: root/tls_bio_cb.c
diff options
context:
space:
mode:
Diffstat (limited to 'tls_bio_cb.c')
-rw-r--r--tls_bio_cb.c44
1 files changed, 31 insertions, 13 deletions
diff --git a/tls_bio_cb.c b/tls_bio_cb.c
index 8adbf55..9dd435a 100644
--- a/tls_bio_cb.c
+++ b/tls_bio_cb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_bio_cb.c,v 1.19 2017/01/12 16:18:39 jsing Exp $ */
+/* $OpenBSD: tls_bio_cb.c,v 1.20 2022/01/10 23:39:48 tb Exp $ */
 /*
  * Copyright (c) 2016 Tobias Pape <tobias@netshed.de>
  *
@@ -32,26 +32,39 @@ static long bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr);
 
 static BIO_METHOD *bio_cb_method;
 
-static pthread_once_t bio_cb_init_once = PTHREAD_ONCE_INIT;
+static pthread_mutex_t bio_cb_method_lock = PTHREAD_MUTEX_INITIALIZER;
 
 static void
-bio_s_cb_init(void)
+bio_cb_method_init(void)
 {
-	bio_cb_method = BIO_meth_new(BIO_TYPE_MEM, "libtls_callbacks");
-	if (bio_cb_method == NULL)
+	BIO_METHOD *bio_method;
+
+	if (bio_cb_method != NULL)
+		return;
+
+	bio_method = BIO_meth_new(BIO_TYPE_MEM, "libtls_callbacks");
+	if (bio_method == NULL)
 		return;
 
-	BIO_meth_set_write(bio_cb_method, bio_cb_write);
-	BIO_meth_set_read(bio_cb_method, bio_cb_read);
-	BIO_meth_set_puts(bio_cb_method, bio_cb_puts);
-	BIO_meth_set_ctrl(bio_cb_method, bio_cb_ctrl);
+	BIO_meth_set_write(bio_method, bio_cb_write);
+	BIO_meth_set_read(bio_method, bio_cb_read);
+	BIO_meth_set_puts(bio_method, bio_cb_puts);
+	BIO_meth_set_ctrl(bio_method, bio_cb_ctrl);
+
+	bio_cb_method = bio_method;
 }
 
 static BIO_METHOD *
 bio_s_cb(void)
 {
-	pthread_once(&bio_cb_init_once, bio_s_cb_init);
-	return bio_cb_method;
+	if (bio_cb_method != NULL)
+		return (bio_cb_method);
+
+	pthread_mutex_lock(&bio_cb_method_lock);
+	bio_cb_method_init();
+	pthread_mutex_unlock(&bio_cb_method_lock);
+
+	return (bio_cb_method);
 }
 
 static int
@@ -125,8 +138,9 @@ int
 tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
     void *cb_arg)
 {
-	int rv = -1;
+	const BIO_METHOD *bio_cb;
 	BIO *bio;
+	int rv = -1;
 
 	if (read_cb == NULL || write_cb == NULL) {
 		tls_set_errorx(ctx, "no callbacks provided");
@@ -137,7 +151,11 @@ tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
 	ctx->write_cb = write_cb;
 	ctx->cb_arg = cb_arg;
 
-	if ((bio = BIO_new(bio_s_cb())) == NULL) {
+	if ((bio_cb = bio_s_cb()) == NULL) {
+		tls_set_errorx(ctx, "failed to create callback method");
+		goto err;
+	}
+	if ((bio = BIO_new(bio_cb)) == NULL) {
 		tls_set_errorx(ctx, "failed to create callback i/o");
 		goto err;
 	}