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:
Anderson Toshiyuki Sasaki
2018-07-02 13:03:12 +02:00
committed by Andreas Schneider
parent 6a077fe750
commit 83b43443e5
15 changed files with 678 additions and 446 deletions

View File

@@ -1,132 +0,0 @@
project(libssh-threads C)
set(LIBSSH_THREADS_PUBLIC_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}
CACHE INTERNAL "libssh public include directories"
)
set(LIBSSH_THREADS_PRIVATE_INCLUDE_DIRS
${CMAKE_BINARY_DIR}
)
set(LIBSSH_THREADS_SHARED_LIBRARY
ssh_threads_shared
CACHE INTERNAL "libssh threads shared library"
)
if (WITH_STATIC_LIB)
set(LIBSSH_THREADS_STATIC_LIBRARY
ssh_threads_static
CACHE INTERNAL "libssh threads static library"
)
endif (WITH_STATIC_LIB)
set(LIBSSH_THREADS_LINK_LIBRARIES
${LIBSSH_SHARED_LIBRARY}
)
message(STATUS "threads library: Threads_FOUND=${Threads_FOUND}")
set(libssh_threads_SRCS) # empty SRC
# build and link pthread
if (CMAKE_USE_PTHREADS_INIT)
set(libssh_threads_SRCS
${libssh_threads_SRCS}
pthread.c
)
set(LIBSSH_THREADS_LINK_LIBRARIES
${LIBSSH_THREADS_LINK_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
message(STATUS "libssh_threads_SRCS=${libssh_threads_SRCS}")
endif (CMAKE_USE_PTHREADS_INIT)
set(LIBSSH_THREADS_LINK_LIBRARIES
${LIBSSH_THREADS_LINK_LIBRARIES}
CACHE INTERNAL "libssh threads link libraries"
)
include_directories(
${LIBSSH_THREADS_PUBLIC_INCLUDE_DIRS}
${LIBSSH_THREADS_PRIVATE_INCLUDE_DIRS}
)
if (libssh_threads_SRCS)
set(LIBSSH_THREADS ON CACHE "libssh threads lib" INTERNAL)
add_library(${LIBSSH_THREADS_SHARED_LIBRARY} SHARED ${libssh_threads_SRCS})
target_link_libraries(${LIBSSH_THREADS_SHARED_LIBRARY} ${LIBSSH_THREADS_LINK_LIBRARIES})
set_target_properties(
${LIBSSH_THREADS_SHARED_LIBRARY}
PROPERTIES
VERSION
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh_threads
DEFINE_SYMBOL
LIBSSH_EXPORTS
)
if (WITH_VISIBILITY_HIDDEN)
set_target_properties(${LIBSSH_THREADS_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
endif (WITH_VISIBILITY_HIDDEN)
install(
TARGETS
${LIBSSH_THREADS_SHARED_LIBRARY}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
COMPONENT libraries
)
if (WITH_STATIC_LIB)
add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
VERSION
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh_threads
ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
)
if (WIN32)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
COMPILE_FLAGS
"-DLIBSSH_STATIC"
)
endif (WIN32)
install(
TARGETS
${LIBSSH_THREADS_STATIC_LIBRARY}
DESTINATION
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT
libraries
)
endif (WITH_STATIC_LIB)
endif (libssh_threads_SRCS)

125
src/threads/libcrypto.c Normal file
View File

@@ -0,0 +1,125 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2018 by Anderson Toshiyuki Sasaki
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/crypto.h"
#include "libssh/threads.h"
#include <libssh/callbacks.h>
#if (OPENSSL_VERSION_NUMBER >= 0x10100000)
int crypto_thread_init(struct ssh_threads_callbacks_struct *cb)
{
(void) cb;
return SSH_OK;
}
void crypto_thread_finalize(void)
{
return;
}
#else
static struct ssh_threads_callbacks_struct *user_callbacks = NULL;
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 */
int crypto_thread_init(struct ssh_threads_callbacks_struct *cb)
{
int n = CRYPTO_num_locks();
int cmp;
int i;
if (cb == NULL) {
return SSH_OK;
}
if (user_callbacks != NULL) {
crypto_thread_finalize();
}
user_callbacks = cb;
cmp = strcmp(user_callbacks->type, "threads_noop");
if (cmp == 0) {
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;
}
void crypto_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

74
src/threads/libgcrypt.c Normal file
View File

@@ -0,0 +1,74 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2018 by Anderson Toshiyuki Sasaki
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/crypto.h"
#include "libssh/threads.h"
#include <libssh/callbacks.h>
#if (GCRYPT_VERSION_NUMBER >= 0x010600)
/* libgcrypt >= 1.6 does not support custom callbacks */
GCRY_THREAD_OPTION_PTHREAD_IMPL;
int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks)
{
(void) user_callbacks;
return SSH_OK;
}
#else
/* Libgcrypt < 1.6 specific way of handling thread callbacks */
static struct gcry_thread_cbs gcrypt_threads_callbacks;
int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks)
{
int cmp;
if (user_callbacks == NULL) {
return SSH_OK;
}
cmp = strcmp(user_callbacks->type, "threads_noop");
if (cmp == 0) {
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 */
void crypto_thread_finalize(void)
{
return;
}

65
src/threads/mbedtls.c Normal file
View File

@@ -0,0 +1,65 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2018 by Anderson Toshiyuki Sasaki
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/crypto.h"
#include "libssh/threads.h"
#include <libssh/callbacks.h>
#include <mbedtls/threading.h>
int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks)
{
int cmp;
if (user_callbacks == NULL) {
return SSH_OK;
}
cmp = strcmp(user_callbacks->type, "threads_noop");
if (cmp == 0) {
return SSH_OK;
}
#ifdef MBEDTLS_THREADING_ALT
else {
if (user_callbacks != NULL) {
crypto_thread_finalize();
}
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
}
void crypto_thread_finalize(void)
{
#ifdef MBEDTLS_THREADING_ALT
mbedtls_threading_free_alt();
#endif
return;
}

74
src/threads/noop.c Normal file
View File

@@ -0,0 +1,74 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2018 by Anderson Toshiyuki Sasaki
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/threads.h"
#include <libssh/callbacks.h>
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 =
{
.type = "threads_noop",
.mutex_init = threads_noop,
.mutex_destroy = threads_noop,
.mutex_lock = threads_noop,
.mutex_unlock = threads_noop,
.thread_id = threads_id_noop
};
/* Threads interface implementation */
#if !(HAVE_PTHREAD)
void ssh_mutex_lock(SSH_MUTEX *mutex)
{
(void) mutex;
return;
}
void ssh_mutex_unlock(SSH_MUTEX *mutex)
{
(void) mutex;
return;
}
struct ssh_threads_callbacks_struct *ssh_threads_get_default(void)
{
return &ssh_threads_noop;
}
#endif
struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void)
{
return &ssh_threads_noop;
}

View File

@@ -20,61 +20,64 @@
*/
#include "config.h"
#include "libssh/threads.h"
#include <libssh/callbacks.h>
#ifdef HAVE_PTHREAD
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
/** @brief Defines the needed callbacks for pthread. Use this if your
* OS supports libpthread and want to use it for threading.
* @code
* #include <libssh/callbacks.h>
* #include <errno.h>
* #include <pthread.h>
* SSH_THREADS_PTHREAD(ssh_pthread_callbacks);
* int main(){
* ssh_init_set_threads_callbacks(&ssh_pthread_callbacks);
* ssh_init();
* ...
* }
* @endcode
* @param name name of the structure to be declared, containing the
* callbacks for threading
*
*/
static int ssh_pthread_mutex_init (void **mutex)
{
int rc = 0;
static int ssh_pthread_mutex_init (void **priv){
int err = 0;
*priv = malloc (sizeof (pthread_mutex_t));
if (*priv==NULL)
return ENOMEM;
err = pthread_mutex_init (*priv, NULL);
if (err != 0){
free (*priv);
*priv=NULL;
}
return err;
if (mutex == NULL) {
return EINVAL;
}
*mutex = malloc(sizeof(pthread_mutex_t));
if (*mutex == NULL) {
return ENOMEM;
}
rc = pthread_mutex_init ((pthread_mutex_t *)*mutex, NULL);
if (rc){
free (*mutex);
*mutex = NULL;
}
return rc;
}
static int ssh_pthread_mutex_destroy (void **lock) {
int err = pthread_mutex_destroy (*lock);
free (*lock);
*lock=NULL;
return err;
static int ssh_pthread_mutex_destroy (void **mutex)
{
int rc = 0;
if (mutex == NULL) {
return EINVAL;
}
rc = pthread_mutex_destroy ((pthread_mutex_t *)*mutex);
free (*mutex);
*mutex = NULL;
return rc;
}
static int ssh_pthread_mutex_lock (void **lock) {
return pthread_mutex_lock (*lock);
static int ssh_pthread_mutex_lock (void **mutex)
{
return pthread_mutex_lock((pthread_mutex_t *)*mutex);
}
static int ssh_pthread_mutex_unlock (void **lock){
return pthread_mutex_unlock (*lock);
static int ssh_pthread_mutex_unlock (void **mutex)
{
return pthread_mutex_unlock((pthread_mutex_t *)*mutex);
}
static unsigned long ssh_pthread_thread_id (void){
static unsigned long ssh_pthread_thread_id (void)
{
#if defined(_WIN32) && !defined(__WINPTHREADS_VERSION)
return (unsigned long) pthread_self().p;
#else
@@ -84,16 +87,54 @@ static unsigned long ssh_pthread_thread_id (void){
static struct ssh_threads_callbacks_struct ssh_threads_pthread =
{
.type="threads_pthread",
.mutex_init=ssh_pthread_mutex_init,
.mutex_destroy=ssh_pthread_mutex_destroy,
.mutex_lock=ssh_pthread_mutex_lock,
.mutex_unlock=ssh_pthread_mutex_unlock,
.thread_id=ssh_pthread_thread_id
.type = "threads_pthread",
.mutex_init = ssh_pthread_mutex_init,
.mutex_destroy = ssh_pthread_mutex_destroy,
.mutex_lock = ssh_pthread_mutex_lock,
.mutex_unlock = ssh_pthread_mutex_unlock,
.thread_id = ssh_pthread_thread_id
};
struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void) {
return &ssh_threads_pthread;
/* Threads interface implementation */
#if (HAVE_PTHREAD)
void ssh_mutex_lock(SSH_MUTEX *mutex)
{
int rc;
if (mutex == NULL) {
exit(EINVAL);
}
rc = pthread_mutex_lock(mutex);
if (rc) {
exit(rc);
}
}
#endif /* HAVE_PTHREAD */
void ssh_mutex_unlock(SSH_MUTEX *mutex)
{
int rc;
if (mutex == NULL) {
exit(EINVAL);
}
rc = pthread_mutex_unlock(mutex);
if (rc) {
exit(rc);
}
}
struct ssh_threads_callbacks_struct *ssh_threads_get_default(void)
{
return &ssh_threads_pthread;
}
#endif
struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void)
{
return &ssh_threads_pthread;
}