mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-12-02 01:17:52 +03:00
threads: Automatically call ssh_init on load
This makes unnecessary to call ssh_init() when the library is dynamically loaded. Also removes the threads shared library. The used threads implementation is chosen in configuration time, changing the ssh_threads_get_default() depending on the available threads library. Internally, it is expected a threads implementation providing: - void ssh_mutex_lock(void **mutex); - void ssh_mutex_unlock(void **mutex); - struct ssh_threads_callbacks_struct *ssh_threads_get_default(void); and a crypto implementation providing: - int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks); - void crypto_thread_finalize(void); This adds internal threads implementation for pthreads and noop. Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
committed by
Andreas Schneider
parent
6a077fe750
commit
83b43443e5
240
src/threads.c
240
src/threads.c
@@ -33,213 +33,63 @@
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/threads.h"
|
||||
|
||||
#ifdef HAVE_LIBMBEDCRYPTO
|
||||
#include <mbedtls/threading.h>
|
||||
#endif
|
||||
|
||||
static int threads_noop (void **lock){
|
||||
(void)lock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long threads_id_noop (void){
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct ssh_threads_callbacks_struct ssh_threads_noop =
|
||||
{
|
||||
"threads_noop",
|
||||
threads_noop,
|
||||
threads_noop,
|
||||
threads_noop,
|
||||
threads_noop,
|
||||
threads_id_noop
|
||||
};
|
||||
|
||||
struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void) {
|
||||
return &ssh_threads_noop;
|
||||
}
|
||||
|
||||
static struct ssh_threads_callbacks_struct *user_callbacks =&ssh_threads_noop;
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#if (GCRYPT_VERSION_NUMBER >= 0x010600)
|
||||
/* libgcrypt >= 1.6 does not support custom callbacks */
|
||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||
|
||||
static int libgcrypt_thread_init(void){
|
||||
if(user_callbacks == NULL)
|
||||
return SSH_ERROR;
|
||||
if(user_callbacks == &ssh_threads_noop)
|
||||
return SSH_OK;
|
||||
if (strcmp(user_callbacks->type, "threads_pthread") == 0){
|
||||
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||
return SSH_OK;
|
||||
} else {
|
||||
/* not supported */
|
||||
SSH_LOG(SSH_LOG_WARN, "Custom thread handlers not supported with libgcrypt >=1.6, using pthreads");
|
||||
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/* Libgcrypt < 1.6 specific way of handling thread callbacks */
|
||||
|
||||
static struct gcry_thread_cbs gcrypt_threads_callbacks;
|
||||
|
||||
static int libgcrypt_thread_init(void){
|
||||
if(user_callbacks == NULL)
|
||||
return SSH_ERROR;
|
||||
if(user_callbacks == &ssh_threads_noop){
|
||||
gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 || GCRY_THREAD_OPTION_DEFAULT;
|
||||
} else {
|
||||
gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 || GCRY_THREAD_OPTION_USER;
|
||||
}
|
||||
gcrypt_threads_callbacks.mutex_init=user_callbacks->mutex_init;
|
||||
gcrypt_threads_callbacks.mutex_destroy=user_callbacks->mutex_destroy;
|
||||
gcrypt_threads_callbacks.mutex_lock=user_callbacks->mutex_lock;
|
||||
gcrypt_threads_callbacks.mutex_unlock=user_callbacks->mutex_unlock;
|
||||
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks);
|
||||
return SSH_OK;
|
||||
}
|
||||
#endif /* GCRYPT_VERSION_NUMBER */
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
static int libmbedcrypto_thread_init(void)
|
||||
{
|
||||
if (user_callbacks == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (user_callbacks == &ssh_threads_noop) {
|
||||
return SSH_OK;
|
||||
}
|
||||
#ifdef MBEDTLS_THREADING_ALT
|
||||
else {
|
||||
mbedtls_threading_set_alt(user_callbacks->mutex_init,
|
||||
user_callbacks->mutex_destroy, user_callbacks->mutex_lock,
|
||||
user_callbacks->mutex_unlock);
|
||||
}
|
||||
#elif defined MBEDTLS_THREADING_PTHREAD
|
||||
return SSH_OK;
|
||||
#else
|
||||
return SSH_ERROR;
|
||||
#endif
|
||||
}
|
||||
#else /* HAVE_LIBGCRYPT */
|
||||
|
||||
/* Libcrypto specific stuff */
|
||||
|
||||
static void **libcrypto_mutexes;
|
||||
|
||||
void libcrypto_lock_callback(int mode, int i, const char *file, int line);
|
||||
|
||||
void libcrypto_lock_callback(int mode, int i, const char *file, int line)
|
||||
{
|
||||
(void)file;
|
||||
(void)line;
|
||||
if(mode & CRYPTO_LOCK){
|
||||
user_callbacks->mutex_lock(&libcrypto_mutexes[i]);
|
||||
} else {
|
||||
user_callbacks->mutex_unlock(&libcrypto_mutexes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
|
||||
static void libcrypto_THREADID_callback(CRYPTO_THREADID *id)
|
||||
{
|
||||
unsigned long thread_id = (*user_callbacks->thread_id)();
|
||||
|
||||
CRYPTO_THREADID_set_numeric(id, thread_id);
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK */
|
||||
|
||||
static int libcrypto_thread_init(void){
|
||||
int n=CRYPTO_num_locks();
|
||||
int i;
|
||||
if(user_callbacks == &ssh_threads_noop)
|
||||
return SSH_OK;
|
||||
libcrypto_mutexes = calloc(n, sizeof(void *));
|
||||
if (libcrypto_mutexes == NULL)
|
||||
return SSH_ERROR;
|
||||
for (i=0;i<n;++i){
|
||||
user_callbacks->mutex_init(&libcrypto_mutexes[i]);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK
|
||||
CRYPTO_THREADID_set_callback(libcrypto_THREADID_callback);
|
||||
#else
|
||||
CRYPTO_set_id_callback(user_callbacks->thread_id);
|
||||
#endif
|
||||
|
||||
CRYPTO_set_locking_callback(libcrypto_lock_callback);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void libcrypto_thread_finalize(void){
|
||||
int n=CRYPTO_num_locks();
|
||||
int i;
|
||||
if (libcrypto_mutexes==NULL)
|
||||
return;
|
||||
for (i=0;i<n;++i){
|
||||
user_callbacks->mutex_destroy(&libcrypto_mutexes[i]);
|
||||
}
|
||||
SAFE_FREE(libcrypto_mutexes);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
static struct ssh_threads_callbacks_struct *user_callbacks = NULL;
|
||||
|
||||
/** @internal
|
||||
* @brief inits the threading with the backend cryptographic libraries
|
||||
*/
|
||||
|
||||
int ssh_threads_init(void){
|
||||
static int threads_initialized=0;
|
||||
int ret;
|
||||
if(threads_initialized)
|
||||
return SSH_OK;
|
||||
/* first initialize the user_callbacks with our default handlers if not
|
||||
* already the case
|
||||
*/
|
||||
if(user_callbacks == NULL){
|
||||
user_callbacks=&ssh_threads_noop;
|
||||
}
|
||||
int ssh_threads_init(void)
|
||||
{
|
||||
static int threads_initialized = 0;
|
||||
int rc;
|
||||
|
||||
/* Then initialize the crypto libraries threading callbacks */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
ret = libgcrypt_thread_init();
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
ret = libmbedcrypto_thread_init();
|
||||
#else /* Libcrypto */
|
||||
ret = libcrypto_thread_init();
|
||||
#endif
|
||||
if(ret == SSH_OK)
|
||||
threads_initialized=1;
|
||||
return ret;
|
||||
if (threads_initialized) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/* first initialize the user_callbacks with our default handlers if not
|
||||
* already the case
|
||||
*/
|
||||
if (user_callbacks == NULL){
|
||||
user_callbacks = ssh_threads_get_default();
|
||||
}
|
||||
|
||||
/* Then initialize the crypto libraries threading callbacks */
|
||||
rc = crypto_thread_init(user_callbacks);
|
||||
if (rc == SSH_OK) {
|
||||
threads_initialized = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ssh_threads_finalize(void){
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
#ifdef MBEDTLS_THREADING_ALT
|
||||
mbedtls_threading_free_alt();
|
||||
#endif
|
||||
#else
|
||||
libcrypto_thread_finalize();
|
||||
#endif
|
||||
void ssh_threads_finalize(void)
|
||||
{
|
||||
crypto_thread_finalize();
|
||||
}
|
||||
|
||||
int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct *cb){
|
||||
user_callbacks=cb;
|
||||
return SSH_OK;
|
||||
int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct *cb)
|
||||
{
|
||||
|
||||
int rc;
|
||||
|
||||
if (user_callbacks != NULL) {
|
||||
crypto_thread_finalize();
|
||||
}
|
||||
|
||||
user_callbacks = cb;
|
||||
|
||||
rc = crypto_thread_init(user_callbacks);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
const char *ssh_threads_get_type(void) {
|
||||
if(user_callbacks != NULL)
|
||||
return user_callbacks->type;
|
||||
return NULL;
|
||||
const char *ssh_threads_get_type(void)
|
||||
{
|
||||
if (user_callbacks != NULL) {
|
||||
return user_callbacks->type;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user