diff options
Diffstat (limited to 'librabbitmq/amqp-openssl.c')
-rw-r--r-- | librabbitmq/amqp-openssl.c | 102 |
1 files changed, 97 insertions, 5 deletions
diff --git a/librabbitmq/amqp-openssl.c b/librabbitmq/amqp-openssl.c index d136b70..965f6e1 100644 --- a/librabbitmq/amqp-openssl.c +++ b/librabbitmq/amqp-openssl.c @@ -26,8 +26,10 @@ #include "amqp-ssl.h" #include "amqp_private.h" +#include "threads.h" #include <ctype.h> #include <openssl/bio.h> +#include <openssl/conf.h> #include <openssl/err.h> #include <openssl/ssl.h> #include <stdlib.h> @@ -35,9 +37,17 @@ static int initialize_openssl(); static int destroy_openssl(); -int open_connections = 0; -amqp_boolean_t do_initialize_openssl = 1; -amqp_boolean_t openssl_initialized = 0; +static int open_ssl_connections = 0; +static amqp_boolean_t do_initialize_openssl = 1; +static amqp_boolean_t openssl_initialized = 0; + +#ifdef ENABLE_THREAD_SAFETY +static unsigned long amqp_ssl_threadid_callback(void); +static void amqp_ssl_locking_callback(int mode, int n, const char *file, int line); + +static pthread_mutex_t openssl_init_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t *amqp_openssl_lockarray = NULL; +#endif /* ENABLE_THREAD_SAFETY */ struct amqp_ssl_socket_context { BIO *bio; @@ -286,11 +296,68 @@ amqp_set_initialize_ssl_library(amqp_boolean_t do_initialize) } } + +#ifdef ENABLE_THREAD_SAFETY +unsigned long +amqp_ssl_threadid_callback(void) +{ + return (unsigned long)pthread_self(); +} + +void +amqp_ssl_locking_callback(int mode, int n, const char *file, int line) +{ + if (mode & CRYPTO_LOCK) + { + if (pthread_mutex_lock(&amqp_openssl_lockarray[n])) + amqp_abort("Runtime error: Failure in trying to lock OpenSSL mutex"); + } + else + { + if (pthread_mutex_unlock(&amqp_openssl_lockarray[n])) + amqp_abort("Runtime error: Failure in trying to unlock OpenSSL mutex"); + } +} +#endif /* ENABLE_THREAD_SAFETY */ + static int initialize_openssl() { +#ifdef ENABLE_THREAD_SAFETY + if (pthread_mutex_lock(&openssl_init_mutex)) + return -1; +#endif /* ENABLE_THREAD_SAFETY */ if (do_initialize_openssl) { +#ifdef ENABLE_THREAD_SAFETY + if (NULL == amqp_openssl_lockarray) + { + int i = 0; + amqp_openssl_lockarray = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t)); + if (!amqp_openssl_lockarray) + { + pthread_mutex_unlock(&openssl_init_mutex); + return -1; + } + for (int i = 0; i < CRYPTO_num_locks(); ++i) + { + if (pthread_mutex_init(&amqp_openssl_lockarray[i], NULL)) + { + free(amqp_openssl_lockarray); + amqp_openssl_lockarray = NULL; + pthread_mutex_unlock(&openssl_init_mutex); + return -1; + } + } + } + + if (0 == open_ssl_connections) + { + CRYPTO_set_id_callback(amqp_ssl_threadid_callback); + CRYPTO_set_locking_callback(amqp_ssl_locking_callback); + } +#endif /* ENABLE_THREAD_SAFETY */ + if (!openssl_initialized) { OPENSSL_config(NULL); @@ -302,12 +369,37 @@ initialize_openssl() } } - ++open_connections; + ++open_ssl_connections; + +#ifdef ENABLE_THREAD_SAFETY + pthread_mutex_unlock(&openssl_init_mutex); +#endif /* ENABLE_THREAD_SAFETY */ return 0; } static int destroy_openssl() { - --open_connections; +#ifdef ENABLE_THREAD_SAFETY + if (pthread_mutex_lock(&openssl_init_mutex)) + return -1; +#endif /* ENABLE_THREAD_SAFETY */ + + if (open_ssl_connections > 0) + --open_ssl_connections; + +#ifdef ENABLE_THREAD_SAFETY + if (0 == open_ssl_connections && do_initialize_openssl) + { + /* Unsetting these allows the rabbitmq-c library to be unloaded + * safely. We do leak the amqp_openssl_lockarray. Which is only + * an issue if you repeatedly unload and load the library + */ + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_id_callback(NULL); + } + + pthread_mutex_unlock(&openssl_init_mutex); +#endif /* ENABLE_THREAD_SAFETY */ + return 0; } |