diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | ConfigureChecks.cmake | 10 | ||||
-rw-r--r-- | config.h.cmake | 8 | ||||
-rw-r--r-- | include/libssh/callbacks.h | 15 | ||||
-rw-r--r-- | include/libssh/threads.h | 13 | ||||
-rw-r--r-- | libssh/dh.c | 2 | ||||
-rw-r--r-- | libssh/threads.c | 121 | ||||
-rw-r--r-- | tests/unittests/torture_rand.c | 5 |
8 files changed, 135 insertions, 41 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1276d149..e7c5b6ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,8 @@ else (WITH_GCRYPT) endif (NOT OPENSSL_FOUND) endif(WITH_GCRYPT) +#find out if we have threading available +include(FindThreads) # config.h checks include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index e8f01a90..4a1738be 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -58,6 +58,12 @@ check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H) set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS}) check_include_file(openssl/des.h HAVE_OPENSSL_DES_H) +include(FindThreads) + +if(CMAKE_HAVE_PTHREAD_H) + set(HAVE_PTHREAD_H) +endif(CMAKE_HAVE_PTHREAD_H) + # FUNCTIONS if (UNIX) @@ -114,6 +120,10 @@ if (WITH_DEBUG_CALLTRACE) set(DEBUG_CALLTRACE 1) endif (WITH_DEBUG_CALLTRACE) +if (CMAKE_HAVE_PTHREAD_CREATE) + set(HAVE_PTHREAD) +endif (CMAKE_HAVE_PTHREAD_CREATE) + # ENDIAN if (NOT WIN32) test_big_endian(WORDS_BIGENDIAN) diff --git a/config.h.cmake b/config.h.cmake index 257c7bc3..44f0e459 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -35,6 +35,10 @@ /* Define to 1 if you have the <openssl/des.h> header file. */ #cmakedefine HAVE_OPENSSL_DES_H 1 +/* Define to 1 if you have the <pthread.h> header file. */ +#cmakedefine HAVE_PTHREAD_H 1 + + /*************************** FUNCTIONS ***************************/ /* Define to 1 if you have the `vsnprintf' function. */ @@ -78,6 +82,10 @@ /* Define to 1 if you have the `z' library (-lz). */ #cmakedefine HAVE_LIBZ 1 +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#cmakedefine HAVE_PTHREAD 1 + + /**************************** OPTIONS ****************************/ /* Define to 1 if you want to enable ZLIB */ diff --git a/include/libssh/callbacks.h b/include/libssh/callbacks.h index 589c0aea..e66fb64e 100644 --- a/include/libssh/callbacks.h +++ b/include/libssh/callbacks.h @@ -248,6 +248,21 @@ typedef struct ssh_packet_callbacks_struct *ssh_packet_callbacks; */ LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb); +/** @} */ + +typedef int (*ssh_thread_callback) (void **lock); +typedef unsigned long (*ssh_thread_id_callback) (void); +struct ssh_threads_callbacks_struct { + ssh_thread_callback mutex_init; + ssh_thread_callback mutex_destroy; + ssh_thread_callback mutex_lock; + ssh_thread_callback mutex_unlock; + ssh_thread_id_callback thread_id; +}; + +LIBSSH_API int ssh_init_set_threads_callbacks(struct ssh_threads_callbacks_struct + *cb); + #ifdef __cplusplus } #endif diff --git a/include/libssh/threads.h b/include/libssh/threads.h index 6f82ee33..d83e4219 100644 --- a/include/libssh/threads.h +++ b/include/libssh/threads.h @@ -22,17 +22,10 @@ #ifndef THREADS_H_ #define THREADS_H_ -typedef int (*ssh_thread_callback) (void **lock); -struct ssh_threads_callbacks_struct { - ssh_thread_callback mutex_init; - ssh_thread_callback mutex_destroy; - ssh_thread_callback mutex_lock; - ssh_thread_callback mutex_unlock; -}; +#include <libssh/callbacks.h> int ssh_threads_init(void); -int ssh_init_set_threads_callbacks(struct ssh_threads_callbacks_struct - *cb); -int ssh_init_set_threads_pthreads(void); +void ssh_threads_finalize(void); + #endif /* THREADS_H_ */ diff --git a/libssh/dh.c b/libssh/dh.c index c81ed8fc..eff74bf9 100644 --- a/libssh/dh.c +++ b/libssh/dh.c @@ -55,6 +55,7 @@ #include "libssh/session.h" #include "libssh/keys.h" #include "libssh/dh.h" +#include "libssh/threads.h" /* todo: remove it */ #include "libssh/string.h" @@ -155,6 +156,7 @@ void ssh_crypto_finalize(void) { bignum_free(p); p = NULL; ssh_crypto_initialized=0; + ssh_threads_finalize(); } } diff --git a/libssh/threads.c b/libssh/threads.c index c7fc37bf..63e9d83f 100644 --- a/libssh/threads.c +++ b/libssh/threads.c @@ -30,10 +30,13 @@ #include "libssh/priv.h" #include "libssh/threads.h" +#ifndef HAVE_PTHREAD +#warning "You do not have any threading library installed. If the linked" +#warning "application doesn't provide the threading callbacks, you're screwed" +#endif -#ifdef HAVE_LIBGCRYPT -#define HAVE_PTHREADS -#ifdef HAVE_PTHREADS +//#define HAVE_PTHREAD +#ifdef HAVE_PTHREAD #include <errno.h> #include <pthread.h> @@ -66,31 +69,83 @@ static int ssh_pthread_mutex_unlock (void **lock){ return pthread_mutex_unlock (*lock); } +static unsigned long ssh_pthread_thread_id (void){ + return (unsigned long) pthread_self(); +} -static struct ssh_threads_callbacks_struct ssh_gcrypt_user_callbacks= +static struct ssh_threads_callbacks_struct ssh_pthread_user_callbacks= { .mutex_init=ssh_pthread_mutex_init, .mutex_destroy=ssh_pthread_mutex_destroy, .mutex_lock=ssh_pthread_mutex_lock, - .mutex_unlock=ssh_pthread_mutex_unlock + .mutex_unlock=ssh_pthread_mutex_unlock, + .thread_id=ssh_pthread_thread_id }; #endif -static struct gcry_thread_cbs gcrypt_threads_callbacks; - -#endif - static struct ssh_threads_callbacks_struct *user_callbacks; #ifdef HAVE_LIBGCRYPT -static void copy_callback(struct ssh_threads_callbacks_struct *cb){ + +/* Libgcrypt 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; gcrypt_threads_callbacks.option= GCRY_THREAD_OPTION_VERSION << 8 || GCRY_THREAD_OPTION_USER; - gcrypt_threads_callbacks.mutex_init=cb->mutex_init; - gcrypt_threads_callbacks.mutex_destroy=cb->mutex_destroy; - gcrypt_threads_callbacks.mutex_lock=cb->mutex_lock; - gcrypt_threads_callbacks.mutex_unlock=cb->mutex_unlock; + 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; +} +#else + +/* Libcrypto specific stuff */ + +void **libcrypto_mutexes; + +static 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]); + } +} + +static int libcrypto_thread_init(){ + int n=CRYPTO_num_locks(); + int i; + libcrypto_mutexes=malloc(sizeof(void *) * n); + if (libcrypto_mutexes == NULL) + return SSH_ERROR; + for (i=0;i<n;++i){ + user_callbacks->mutex_init(&libcrypto_mutexes[i]); + } + CRYPTO_set_id_callback(user_callbacks->thread_id); + CRYPTO_set_locking_callback(libcrypto_lock_callback); + + return SSH_OK; +} + +static void libcrypto_thread_finalize(){ + 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 /** @internal @@ -98,34 +153,38 @@ static void copy_callback(struct ssh_threads_callbacks_struct *cb){ */ int ssh_threads_init(void){ -#ifdef HAVE_LIBGCRYPT - if(user_callbacks != NULL){ - copy_callback(user_callbacks); - gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks); - return SSH_OK; - } -#ifdef HAVE_PTHREADS - else { - copy_callback(&ssh_gcrypt_user_callbacks); - gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks); - return SSH_OK; - } + /* first initialize the user_callbacks with our default handlers if not + * already the case + */ + if(user_callbacks == NULL){ +#ifdef HAVE_PTHREAD + user_callbacks=&ssh_pthread_user_callbacks; + } else { #endif -#else - + return SSH_ERROR; // Can't do anything to initialize threading + } + /* Then initialize the crypto libraries threading callbacks */ +#ifdef HAVE_LIBGCRYPT + return libgcrypt_thread_init(); +#else /* Libcrypto */ + return libcrypto_thread_init(); #endif return SSH_ERROR; } +void ssh_threads_finalize(void){ +#ifdef HAVE_LIBGCRYPT +#else + libcrypto_thread_finalize(); +#endif +} + int ssh_init_set_threads_callbacks(struct ssh_threads_callbacks_struct *cb){ user_callbacks=cb; return SSH_OK; } -int ssh_init_set_threads_pthreads(void){ - return SSH_OK; -} /** * @} */ diff --git a/tests/unittests/torture_rand.c b/tests/unittests/torture_rand.c index 087389c7..d5a1b5c5 100644 --- a/tests/unittests/torture_rand.c +++ b/tests/unittests/torture_rand.c @@ -3,7 +3,12 @@ #include <pthread.h> #include "torture.h" +#ifdef HAVE_LIBGCRYPT #define NUM_LOOPS 1000 +#else +/* openssl is much faster */ +#define NUM_LOOPS 20000 +#endif #define NUM_THREADS 100 static void setup(){ |