Repository: qpid-proton Updated Branches: refs/heads/master 12ebe05a4 -> 1e9e243a3
PROTON-992: Make cyrus sasl initialisation/shutdown thread safe Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1e9e243a Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1e9e243a Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1e9e243a Branch: refs/heads/master Commit: 1e9e243a37acca22b5a77177cc1ab4d06ba4b2ec Parents: 12ebe05 Author: Andrew Stitcher <[email protected]> Authored: Tue May 3 16:40:21 2016 -0400 Committer: Andrew Stitcher <[email protected]> Committed: Wed May 11 13:51:31 2016 +0100 ---------------------------------------------------------------------- proton-c/CMakeLists.txt | 2 +- proton-c/src/sasl/cyrus_sasl.c | 77 +++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1e9e243a/proton-c/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt index 372e67c..8219256 100644 --- a/proton-c/CMakeLists.txt +++ b/proton-c/CMakeLists.txt @@ -105,7 +105,7 @@ endif(PN_WINAPI) if (SASL_IMPL STREQUAL cyrus) set(pn_sasl_impl src/sasl/sasl.c src/sasl/cyrus_sasl.c) include_directories (${CYRUS_SASL_INCLUDE_DIR}) - set(SASL_LIB ${CYRUS_SASL_LIBRARY}) + set(SASL_LIB ${CYRUS_SASL_LIBRARY} -lpthread) elseif (SASL_IMPL STREQUAL none) set(pn_sasl_impl src/sasl/sasl.c src/sasl/none_sasl.c) endif () http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1e9e243a/proton-c/src/sasl/cyrus_sasl.c ---------------------------------------------------------------------- diff --git a/proton-c/src/sasl/cyrus_sasl.c b/proton-c/src/sasl/cyrus_sasl.c index 4af1f52..b1e2e03 100644 --- a/proton-c/src/sasl/cyrus_sasl.c +++ b/proton-c/src/sasl/cyrus_sasl.c @@ -25,6 +25,7 @@ #include "engine/engine-internal.h" #include <sasl/sasl.h> +#include <pthread.h> // If the version of Cyrus SASL is too early for sasl_client_done()/sasl_server_done() // don't do any global clean up as it's not safe to use just sasl_done() for an @@ -102,17 +103,72 @@ static const sasl_callback_t pni_user_callbacks[] = { {SASL_CB_LIST_END, NULL, NULL}, }; +// Machinery to initialise the cyrus library only once even in a multithreaded environment +// Relies on pthreads. +static char *pni_cyrus_config_dir = NULL; +static const char *pni_cyrus_config_name = "proton-server"; +static pthread_mutex_t pni_cyrus_mutex = PTHREAD_MUTEX_INITIALIZER; +static bool pni_cyrus_client_started = false; +static bool pni_cyrus_server_started = false; + +__attribute__((destructor)) +static void pni_cyrus_finish(void) { + pthread_mutex_lock(&pni_cyrus_mutex); + if (pni_cyrus_client_started) sasl_client_done(); + if (pni_cyrus_server_started) sasl_server_done(); + pthread_mutex_unlock(&pni_cyrus_mutex); +} + +static int pni_cyrus_client_init_rc = SASL_OK; +static void pni_cyrus_client_once(void) { + pthread_mutex_lock(&pni_cyrus_mutex); + int result = SASL_OK; + if (pni_cyrus_config_dir) { + result = sasl_set_path(SASL_PATH_TYPE_CONFIG, pni_cyrus_config_dir); + } + if (result==SASL_OK) { + result = sasl_client_init(NULL); + } + pni_cyrus_client_started = true; + pni_cyrus_client_init_rc = result; + pthread_mutex_unlock(&pni_cyrus_mutex); +} + +static int pni_cyrus_server_init_rc = SASL_OK; +static void pni_cyrus_server_once(void) { + pthread_mutex_lock(&pni_cyrus_mutex); + int result = SASL_OK; + if (pni_cyrus_config_dir) { + result = sasl_set_path(SASL_PATH_TYPE_CONFIG, pni_cyrus_config_dir); + } + if (result==SASL_OK) { + result = sasl_server_init(NULL, pni_cyrus_config_name); + } + pni_cyrus_server_started = true; + pni_cyrus_server_init_rc = result; + pthread_mutex_unlock(&pni_cyrus_mutex); +} + +static pthread_once_t pni_cyrus_client_init = PTHREAD_ONCE_INIT; +static void pni_cyrus_client_start(void) { + pthread_once(&pni_cyrus_client_init, pni_cyrus_client_once); +} +static pthread_once_t pni_cyrus_server_init = PTHREAD_ONCE_INIT; +static void pni_cyrus_server_start(void) { + pthread_once(&pni_cyrus_server_init, pni_cyrus_server_once); +} + bool pni_init_client(pn_transport_t* transport) { pni_sasl_t *sasl = transport->sasl; int result; sasl_conn_t *cyrus_conn = NULL; do { if (sasl->config_dir) { - result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir); - if (result!=SASL_OK) break; + pni_cyrus_config_dir = sasl->config_dir; } - result = sasl_client_init(NULL); + pni_cyrus_client_start(); + result = pni_cyrus_client_init_rc; if (result!=SASL_OK) break; const sasl_callback_t *callbacks = sasl->username ? sasl->password ? pni_user_password_callbacks : pni_user_callbacks : NULL; @@ -246,11 +302,15 @@ bool pni_init_server(pn_transport_t* transport) sasl_conn_t *cyrus_conn = NULL; do { if (sasl->config_dir) { - result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir); - if (result!=SASL_OK) break; + pni_cyrus_config_dir = sasl->config_dir; + } + + if (sasl->config_name) { + pni_cyrus_config_name = sasl->config_name; } - result = sasl_server_init(NULL, sasl->config_name ? sasl->config_name : "proton-server"); + pni_cyrus_server_start(); + result = pni_cyrus_server_init_rc; if (result!=SASL_OK) break; result = sasl_server_new(amqp_service, NULL, NULL, NULL, NULL, NULL, 0, &cyrus_conn); @@ -456,11 +516,6 @@ void pni_sasl_impl_free(pn_transport_t *transport) sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; sasl_dispose(&cyrus_conn); transport->sasl->impl_context = cyrus_conn; - if (transport->sasl->client) { - sasl_client_done(); - } else { - sasl_server_done(); - } } bool pn_sasl_extended(void) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
