aboutsummaryrefslogtreecommitdiff
path: root/src/threads
diff options
context:
space:
mode:
authorAnderson Toshiyuki Sasaki <ansasaki@redhat.com>2018-07-02 13:03:12 +0200
committerAndreas Schneider <asn@cryptomilk.org>2018-08-03 16:43:03 +0200
commit83b43443e51b5db06184750fb874e1e8d7ece95a (patch)
tree9c81acc146ee9d0d129ab953a38e2363574fa888 /src/threads
parent6a077fe7509fb3141c0c63365a32208e42aa90f1 (diff)
downloadlibssh-83b43443e51b5db06184750fb874e1e8d7ece95a.tar.gz
libssh-83b43443e51b5db06184750fb874e1e8d7ece95a.tar.xz
libssh-83b43443e51b5db06184750fb874e1e8d7ece95a.zip
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>
Diffstat (limited to 'src/threads')
-rw-r--r--src/threads/CMakeLists.txt132
-rw-r--r--src/threads/libcrypto.c125
-rw-r--r--src/threads/libgcrypt.c74
-rw-r--r--src/threads/mbedtls.c65
-rw-r--r--src/threads/noop.c74
-rw-r--r--src/threads/pthread.c139
6 files changed, 428 insertions, 181 deletions
diff --git a/src/threads/CMakeLists.txt b/src/threads/CMakeLists.txt
deleted file mode 100644
index 2ab4e1ba..00000000
--- a/src/threads/CMakeLists.txt
+++ /dev/null
@@ -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)
diff --git a/src/threads/libcrypto.c b/src/threads/libcrypto.c
new file mode 100644
index 00000000..156e5041
--- /dev/null
+++ b/src/threads/libcrypto.c
@@ -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
diff --git a/src/threads/libgcrypt.c b/src/threads/libgcrypt.c
new file mode 100644
index 00000000..3560dc55
--- /dev/null
+++ b/src/threads/libgcrypt.c
@@ -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;
+}
diff --git a/src/threads/mbedtls.c b/src/threads/mbedtls.c
new file mode 100644
index 00000000..6cc3fa53
--- /dev/null
+++ b/src/threads/mbedtls.c
@@ -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;
+}
diff --git a/src/threads/noop.c b/src/threads/noop.c
new file mode 100644
index 00000000..aad4934e
--- /dev/null
+++ b/src/threads/noop.c
@@ -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;
+}
diff --git a/src/threads/pthread.c b/src/threads/pthread.c
index a0a266d7..422dd854 100644
--- a/src/threads/pthread.c
+++ b/src/threads/pthread.c
@@ -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;
+
+ if (mutex == NULL) {
+ return EINVAL;
+ }
-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;
+ *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);
+ }
+}
+
+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
-#endif /* HAVE_PTHREAD */
+struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void)
+{
+ return &ssh_threads_pthread;
+}