Merge pull request #86 from vcrhonek/ssl-thread-safe

Fix SSL library usage is not thread safe
diff --git a/src/server/wsmand-listener.c b/src/server/wsmand-listener.c
index a1cfe1f..3bbf4a6 100644
--- a/src/server/wsmand-listener.c
+++ b/src/server/wsmand-listener.c
@@ -83,6 +83,10 @@
 #endif
 #include <sys/socket.h>
 
+/* SSL thread safe */
+#include <openssl/crypto.h>
+static pthread_mutex_t *lock_cs;
+static long *lock_count;
 
 static pthread_mutex_t shttpd_mutex;
 static pthread_cond_t shttpd_cond;
@@ -107,6 +111,50 @@
 int gss_encrypt(struct shttpd_arg *arg, char *input, int inlen, char **output, int *outlen);
 #endif
 
+/* SSL thread safe */
+void pthreads_locking_callback(int mode, int type, char *file, int line) {
+	if (mode & CRYPTO_LOCK) {
+		pthread_mutex_lock(&(lock_cs[type]));
+		lock_count[type]++;
+	}
+	else {
+		pthread_mutex_unlock(&(lock_cs[type]));
+	}
+}
+
+unsigned long pthreads_thread_id(void) {
+	unsigned long ret;
+
+	ret = (unsigned long)pthread_self();
+	return(ret);
+}
+
+void thread_setup(void) {
+	int i;
+
+	lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+	lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
+	for (i = 0; i < CRYPTO_num_locks(); i++) {
+		lock_count[i] = 0;
+		pthread_mutex_init(&(lock_cs[i]), NULL);
+	}
+
+	CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
+	CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
+}
+
+void thread_cleanup(void) {
+	int i;
+
+	CRYPTO_set_locking_callback(NULL);
+	for (i = 0; i < CRYPTO_num_locks(); i++) {
+		pthread_mutex_destroy(&(lock_cs[i]));
+	}
+
+	OPENSSL_free(lock_cs);
+	OPENSSL_free(lock_count);
+}
+
 /* Check HTTP headers */
 static
 int check_request_content_type(struct shttpd_arg *arg) {
@@ -723,6 +771,10 @@
 
 	if (wsman_setup_thread(&pattrs) == 0 )
 		return listener;
+
+	/* SSL thread safe */
+	thread_setup();
+
 	pthread_create(&tid, &pattrs, wsman_server_auxiliary_loop_thread, cntx);
 
 #ifdef ENABLE_EVENTING_SUPPORT
@@ -749,5 +801,9 @@
 		}
                 shttpd_add_socket(thread->ctx, sock, use_ssl);
         }
+
+	/* SSL thread safe */
+	thread_cleanup();
+
         return listener;
 }