[patch] Threading support in ssh-agent

Alexander V Alekseev alex at alemate.ru
Mon Mar 12 05:57:03 EST 2012


 		Hi all!

 	I do not know openssh patch policy so I am just sending
the patch to the mailing list. Sorry for inconvenience.
 	Ssh-agent seems to be too slow if you need to access thousands of
servers. This is a simple patch to enable threading in ssh2 authentication.
Patch adds "-p numthreads" option and defaults to the number of processors.

 	I've tested it as I could, but unfortunately I could check it
only in Linux environment. Though it shouldn't break anything.

 		Bye. Alex.
-------------- next part --------------
Index: Makefile.in
===================================================================
RCS file: /cvs/openssh/Makefile.in,v
retrieving revision 1.325
diff -u -r1.325 Makefile.in
--- Makefile.in	5 Aug 2011 20:15:18 -0000	1.325
+++ Makefile.in	11 Mar 2012 18:27:13 -0000
@@ -149,8 +149,8 @@
 ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
 	$(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
 
-ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
-	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o ssh-openssl-thread-locking.o
+	$(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o ssh-openssl-thread-locking.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
 
 ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
 	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
Index: configure.ac
===================================================================
RCS file: /cvs/openssh/configure.ac,v
retrieving revision 1.487
diff -u -r1.487 configure.ac
--- configure.ac	23 Feb 2012 23:40:43 -0000	1.487
+++ configure.ac	11 Mar 2012 18:27:16 -0000
@@ -2440,6 +2440,83 @@
 	AC_MSG_ERROR([OpenSSH has no source of random numbers. Please configure OpenSSL with an entropy source or re-run configure using one of the --with-prngd-port or --with-prngd-socket options])
 fi
 
+AC_MSG_CHECKING([whether openssh has thread support compiled-in])
+AC_COMPILE_IFELSE([
+	AC_LANG_PROGRAM(
+		[[
+			#define OPENSSL_THREAD_DEFINES
+			#include <openssl/opensslconf.h>
+		]] , [[
+			#if defined(OPENSSL_THREADS)
+			return 1;
+			#else
+			Must_not_compile 1 2 3;
+			#endif
+			]]
+		)
+		] , [
+		AC_MSG_RESULT([yes])
+		have_openssl_threads=yes;
+	] , [
+		AC_MSG_RESULT([no - threading could not be used])
+	]
+)
+
+AC_ARG_WITH([pthread],
+	[  --with-pthread          Use pthread],
+	[
+		if test "x$withval" = "xno" ; then
+			AC_MSG_CHECKING([whether pthread support enabled])
+			AC_MSG_RESULT([no])
+			ssh_agent_options="threading:no"
+		elif test "x$withval" = "xyes"; then
+			AC_CHECK_LIB(pthread, pthread_create,,
+				[
+					AC_MSG_ERROR([pthread library not found])
+				]
+			)
+			if test "$have_openssl_threads" ; then
+				true;
+			else
+				AC_MSG_ERROR([Openssl doesn't have thread support. Threading could not be used.])
+			fi
+
+			ssh_agent_options="threading:yes"
+		else
+			AC_MSG_ERROR([--with-pthread value must be 'yes' or 'no', but not '$withval'])
+		fi
+	],
+	[
+		AC_CHECK_LIB(pthread, pthread_create)
+
+		if test "$ac_cv_lib_pthread_pthread_create" -a "$have_openssl_threads" ; then
+			ssh_agent_options="threading:yes"
+		fi
+	]
+)
+
+if test "x$ssh_agent_options" = "xthreading:yes" ; then
+	AC_MSG_CHECKING([sysconf(_SC_NPROCESSORS_CONF)])
+	AC_COMPILE_IFELSE([
+		AC_LANG_PROGRAM(
+				[[
+					#include <unistd.h>
+				]] , [[
+					sysconf(_SC_NPROCESSORS_CONF);
+				]]
+			)
+		] , [
+		AC_DEFINE([HAVE___SC_NPROCESSORS_CONF],[],[Whether sysconf(_SC_NPROCESSORS_CONF) is supported.])
+		AC_MSG_RESULT([yes])
+		ssh_agent_options="$ssh_agent_options nthreads:auto"
+		] , [
+			AC_MSG_RESULT([no])
+			AC_MSG_WARN([ssh-agent: do not use threading by default])
+			ssh_agent_options="$ssh_agent_options nthreads:manual,default=0"
+		]
+	)
+fi
+
 # Check for PAM libs
 PAM_MSG="no"
 AC_ARG_WITH([pam],
@@ -4285,6 +4362,7 @@
 echo "                  BSD Auth support: $BSD_AUTH_MSG"
 echo "              Random number source: $RAND_MSG"
 echo "             Privsep sandbox style: $SANDBOX_STYLE"
+echo "                         ssh-agent: $ssh_agent_options"
 
 echo ""
 
Index: ssh-agent.1
===================================================================
RCS file: /cvs/openssh/ssh-agent.1,v
retrieving revision 1.53
diff -u -r1.53 ssh-agent.1
--- ssh-agent.1	1 Dec 2010 00:50:35 -0000	1.53
+++ ssh-agent.1	11 Mar 2012 18:27:16 -0000
@@ -102,6 +102,12 @@
 .Xr ssh-add 1
 overrides this value.
 Without this option the default maximum lifetime is forever.
+.It Fl p Ar numthreads
+Start given number of ssh2 auth threads. Defaults to number of processors if 
+.Pa sysconf(_SC_NPROCESSORS_CONF)
+is supported by the environment or to 0. 0 means "single-threaded mode".
+
+This option is unavailable if threading is not compiled in.
 .El
 .Pp
 If a commandline is given, this is executed as a subprocess of the agent.
Index: ssh-agent.c
===================================================================
RCS file: /cvs/openssh/ssh-agent.c,v
retrieving revision 1.194
diff -u -r1.194 ssh-agent.c
--- ssh-agent.c	3 Jun 2011 04:14:16 -0000	1.194
+++ ssh-agent.c	11 Mar 2012 18:27:17 -0000
@@ -13,6 +13,8 @@
  *
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  *
+ * Threading support by Alexander Alekseev <alex at alemate.ru>
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -58,6 +60,9 @@
 #ifdef HAVE_PATHS_H
 # include <paths.h>
 #endif
+#ifdef HAVE_LIBPTHREAD
+#include "ssh-openssl-thread-locking.h"
+#endif
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -88,6 +93,9 @@
 	AUTH_UNUSED,
 	AUTH_SOCKET,
 	AUTH_CONNECTION
+#ifdef HAVE_LIBPTHREAD
+    , AUTH_INUSE
+#endif
 } sock_type;
 
 typedef struct {
@@ -137,6 +145,50 @@
 /* Default lifetime (0 == forever) */
 static int lifetime = 0;
 
+#ifdef HAVE_LIBPTHREAD
+
+#define MAX_THREADS 20
+
+#define REQ_QUEUE_LEN (MAX_THREADS * 2)
+
+typedef void (*AuthWorker)(SocketEntry*);
+
+struct AuthRequestQueueEntry {
+	AuthWorker worker;
+	SocketEntry *e;
+};
+
+struct AuthRequestQueue {
+	struct AuthRequestQueueEntry queue[REQ_QUEUE_LEN];
+	int first;
+	int used;
+	int inprogress; /* operated by get() */
+	pthread_mutex_t lock;
+	pthread_cond_t cond;
+};
+
+struct Thread {
+	pthread_t tid;
+	pthread_mutex_t lock; /* is locked while thread is serving request. Used as barrier. */
+	struct AuthRequestQueue* queue;
+};
+
+struct TPool {
+	struct Thread threads[MAX_THREADS];
+	size_t num_threads;
+	struct AuthRequestQueue queue;
+};
+
+struct TPool tpool;
+
+void tpool_barrier(struct TPool*);
+
+#else
+
+#define tpool_barrier(a) do {} while(0)
+
+#endif
+
 static void
 close_socket(SocketEntry *e)
 {
@@ -154,7 +206,7 @@
 	int i;
 
 	for (i = 0; i <=2; i++) {
-		TAILQ_INIT(&idtable[i].idlist);
+		TAILQ_INIT(&(idtable[i].idlist));
 		idtable[i].nentries = 0;
 	}
 }
@@ -355,6 +407,224 @@
 	datafellows = odatafellows;
 }
 
+#ifdef HAVE_LIBPTHREAD
+
+int
+req_queue_init(struct AuthRequestQueue* q, int inprogress_initial)
+{
+	memset(q, 0, sizeof(struct AuthRequestQueue));
+
+	if (pthread_mutex_init(&(q->lock), 0)) {
+		error("pthread_mutex_init(queue): %s", strerror(errno));
+		return -1;
+	}
+	if (pthread_cond_init(&(q->cond), 0)) {
+		error("pthread_cond_init(queue): %s", strerror(errno));
+		return -1;
+	}
+	q->inprogress = inprogress_initial;
+	return 0;
+}
+
+int
+req_queue_enqueue(struct AuthRequestQueue* q, AuthWorker worker, SocketEntry *e)
+{
+	int off;
+
+	pthread_mutex_lock(&(q->lock));
+
+	while (q->used >= REQ_QUEUE_LEN) {
+		if (pthread_cond_wait(&(q->cond), &(q->lock))) {
+			error("pthread_cond_wait(enqueue): %s", strerror(errno));
+			pthread_mutex_unlock(&(q->lock));
+			return -1;
+		}
+	}
+	off = q->first + q->used;
+	if (off >= REQ_QUEUE_LEN) {
+		off -= REQ_QUEUE_LEN;
+	}
+	q->queue[off].worker = worker;
+	q->queue[off].e = e;
+
+	if (q->used == 0) {
+		if (pthread_cond_signal(&(q->cond))) {
+			error("pthread_cond_signal(enqueue): %s", strerror(errno));
+		}
+	}
+	q->used++;
+	pthread_mutex_unlock(&(q->lock));
+	return 0;
+}
+
+void thread_lock(struct Thread* t);
+void thread_unlock(struct Thread* t);
+
+int
+req_queue_unlock_thread_get_and_lock_thread(struct Thread* t, AuthWorker* out_worker, SocketEntry** out_e)
+{
+
+	struct AuthRequestQueue* q = t->queue;
+
+	pthread_mutex_lock(&(q->lock));
+	thread_unlock(t);
+
+	if (q->inprogress > 0) {
+		q->inprogress--;
+	}
+
+	while (q->used <= 0) {
+		if (pthread_cond_wait(&(q->cond), &(q->lock))) {
+			error("pthread_cond_wait(get): %s", strerror(errno));
+			thread_lock(t);
+			pthread_mutex_unlock(&(q->lock));
+			return -1;
+		}
+	}
+	*out_worker = q->queue[q->first].worker;
+	*out_e = q->queue[q->first].e;
+
+	q->first++;
+
+	if (q->first >= REQ_QUEUE_LEN) {
+		q->first = 0;
+	}
+
+	if (q->used >= REQ_QUEUE_LEN) {
+		if (pthread_cond_signal(&(q->cond))) {
+			error("pthread_cond_signal(get): %s", strerror(errno));
+		}
+	}
+	q->used--;
+	q->inprogress++;
+
+	thread_lock(t);
+	pthread_mutex_unlock(&(q->lock));
+	return 0;
+}
+
+/* Returns number of threads currently working plus number of requests in queue
+ * Returns -1 on error. */
+int
+req_queue_still_unserved(struct AuthRequestQueue* q)
+{
+	int retval;
+	if (pthread_mutex_lock(&(q->lock))) {
+		error("pthread_mutex_lock(queue): %s", strerror(errno));
+		return -1;
+	}
+	retval = q->inprogress + q->used;
+	pthread_mutex_unlock(&(q->lock));
+	return retval;
+}
+
+void*
+auth_thread_run(struct Thread* t)
+{
+	SocketEntry* e;
+	AuthWorker worker;
+
+	thread_lock(t);
+	while(1) {
+		if (req_queue_unlock_thread_get_and_lock_thread(t, &worker, &e)) {
+			sleep(1);
+		} else {
+			worker(e);
+			if (e->type == AUTH_INUSE) {
+				e->type = AUTH_CONNECTION;
+			}
+		}
+	}
+	return NULL;
+}
+
+int
+thread_init(struct Thread* t)
+{
+	if (pthread_mutex_init(&(t->lock), 0)) {
+		error("pthread_mutex_init(thread): %s", strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+void
+thread_lock(struct Thread* t)
+{
+	while (pthread_mutex_lock(&(t->lock))) {
+		if (errno != EINTR) {
+			error("pthread_mutex_lock(thread): %s", strerror(errno));
+			sleep(1);
+		}
+	}
+}
+
+void
+thread_unlock(struct Thread* t)
+{
+	pthread_mutex_unlock(&(t->lock));
+}
+
+void tpool_barrier(struct TPool* p)
+{
+	size_t i;
+
+	debug("tpool_barrier called");
+	for(i = 0; i < p->num_threads; ++i) {
+		thread_lock(&(p->threads[i]));
+		thread_unlock(&(p->threads[i]));
+	}
+}
+
+typedef void* (*PThreadThreadFunction)(void*);
+int
+tpool_init(struct TPool* p, int numthreads)
+{
+	int i;
+
+	memset(p, 0, sizeof(struct TPool));
+
+	if (req_queue_init(&(p->queue), numthreads)) {
+		return -1;
+	}
+
+	if (numthreads > MAX_THREADS) {
+		numthreads = MAX_THREADS;
+	}
+	for(i = 0; i < numthreads; i++) {
+		struct Thread* thr = &(p->threads[i]);
+		if (thread_init(thr)) {
+			return -1;
+		}
+		thr->queue = &(p->queue);
+		if (pthread_create(&(thr->tid), 0, (PThreadThreadFunction)auth_thread_run, thr)) {
+			error("pthread_create: %s", strerror(errno));
+			return -1;
+		}
+	}
+	p->num_threads = numthreads;
+
+	openssl_thread_locks_setup();
+	return 0;
+}
+
+#endif
+
+static void
+schedule_sign_request2(SocketEntry *e)
+{
+#ifndef HAVE_LIBPTHREAD
+	process_sign_request2(e);
+#else
+	if (tpool.num_threads) {
+		e->type = AUTH_INUSE;
+		req_queue_enqueue(&(tpool.queue), process_sign_request2, e);
+	} else {
+		process_sign_request2(e);
+	}
+#endif
+}
+
 /* shared */
 static void
 process_remove_identity(SocketEntry *e, int version)
@@ -397,8 +667,11 @@
 				    "internal error: tab->nentries %d",
 				    tab->nentries);
 			TAILQ_REMOVE(&tab->idlist, id, next);
-			free_identity(id);
 			tab->nentries--;
+
+			tpool_barrier(&tpool);
+
+			free_identity(id);
 			success = 1;
 		}
 		key_free(key);
@@ -418,6 +691,10 @@
 	for (id = TAILQ_FIRST(&tab->idlist); id;
 	    id = TAILQ_FIRST(&tab->idlist)) {
 		TAILQ_REMOVE(&tab->idlist, id, next);
+		tab->nentries--;
+
+		tpool_barrier(&tpool);
+
 		free_identity(id);
 	}
 
@@ -447,8 +724,11 @@
 			if (now >= id->death) {
 				debug("expiring key '%s'", id->comment);
 				TAILQ_REMOVE(&tab->idlist, id, next);
-				free_identity(id);
 				tab->nentries--;
+
+				tpool_barrier(&tpool);
+
+				free_identity(id);
 			} else
 				deadline = (deadline == 0) ? id->death :
 				    MIN(deadline, id->death);
@@ -776,8 +1056,11 @@
 			nxt = TAILQ_NEXT(id, next);
 			if (!strcmp(provider, id->provider)) {
 				TAILQ_REMOVE(&tab->idlist, id, next);
-				free_identity(id);
 				tab->nentries--;
+
+				tpool_barrier(&tpool);
+
+				free_identity(id);
 			}
 		}
 	}
@@ -861,7 +1144,7 @@
 		break;
 	/* ssh2 */
 	case SSH2_AGENTC_SIGN_REQUEST:
-		process_sign_request2(e);
+		schedule_sign_request2(e);
 		break;
 	case SSH2_AGENTC_REQUEST_IDENTITIES:
 		process_request_identities(e, 2);
@@ -943,6 +1226,10 @@
 			break;
 		case AUTH_UNUSED:
 			break;
+#ifdef HAVE_LIBPTHREAD
+		case AUTH_INUSE:
+			break;
+#endif
 		default:
 			fatal("Unknown socket type %d", sockets[i].type);
 			break;
@@ -981,6 +1268,13 @@
 	if (parent_alive_interval != 0)
 		deadline = (deadline == 0) ? parent_alive_interval :
 		    MIN(deadline, parent_alive_interval);
+#ifdef HAVE_LIBPTHREAD
+	if (req_queue_still_unserved(&(tpool.queue))) {
+		tv.tv_sec = 0;
+		tv.tv_usec = 10000; /* 1/100 of a second */
+		*tvpp = &tv;
+	} else
+#endif
 	if (deadline == 0) {
 		*tvpp = NULL;
 	} else {
@@ -1062,6 +1356,10 @@
 				process_message(&sockets[i]);
 			}
 			break;
+#ifdef HAVE_LIBPTHREAD
+		case AUTH_INUSE:
+			break;
+#endif
 		default:
 			fatal("Unknown type %d", sockets[i].type);
 		}
@@ -1120,6 +1418,9 @@
 	fprintf(stderr, "  -d          Debug mode.\n");
 	fprintf(stderr, "  -a socket   Bind agent socket to given name.\n");
 	fprintf(stderr, "  -t life     Default identity lifetime (seconds).\n");
+#ifdef HAVE_LIBPTHREAD
+	fprintf(stderr, "  -p numthr   Number of authenticate threads. 0 - do not use separate threads.\n");
+#endif
 	exit(1);
 }
 
@@ -1142,6 +1443,9 @@
 	char pidstrbuf[1 + 3 * sizeof pid];
 	struct timeval *tvp = NULL;
 	size_t len;
+#ifdef HAVE_LIBPTHREAD
+	int numthreads = -1;
+#endif
 
 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
 	sanitise_stdfd();
@@ -1160,7 +1464,7 @@
 	__progname = ssh_get_progname(av[0]);
 	seed_rng();
 
-	while ((ch = getopt(ac, av, "cdksa:t:")) != -1) {
+	while ((ch = getopt(ac, av, "cdksa:t:p:")) != -1) {
 		switch (ch) {
 		case 'c':
 			if (s_flag)
@@ -1189,6 +1493,22 @@
 				usage();
 			}
 			break;
+		case 'p':
+#ifdef HAVE_LIBPTHREAD
+			numthreads = atoi(optarg);
+			if ((numthreads <= 0) && strcmp(optarg, "0")) {
+				fprintf(stderr, "Invalid numthreads\n");
+				usage();
+			}
+			if (numthreads > MAX_THREADS) {
+				fprintf(stderr, "Number of threads is limited to %u. Recompile to increase.\n", MAX_THREADS);
+				usage();
+			}
+#else
+			fprintf(stderr, "Threading support not compiled in. \"-p numthreads\" not supported.\n");
+			usage();
+#endif
+			break;
 		default:
 			usage();
 		}
@@ -1355,6 +1675,27 @@
 	signal(SIGTERM, cleanup_handler);
 	nalloc = 0;
 
+#ifdef HAVE_LIBPTHREAD
+	if (numthreads == -1) {
+#ifdef HAVE___SC_NPROCESSORS_CONF
+		numthreads = sysconf(_SC_NPROCESSORS_CONF);
+		if (numthreads == -1) {
+			error("sysconf(_SC_NPROCESSORS_CONF): %s", strerror(errno));
+			error("Defaults to single-thread mode.");
+			numthreads = 0;
+		} else if (numthreads == 1) {
+			numthreads = 0;
+		}
+#else
+		numthreads = 0; /* Single thread. */
+#endif /* HAVE___SC_NPROCESSORS_CONF */
+	}
+
+	if (tpool_init(&tpool, numthreads)) {
+		error("Failed to init threads pool.");
+		cleanup_exit(1);
+	}
+#endif
 	while (1) {
 		prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
 		result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
--- ssh-openssl-thread-locking.c	2012-03-11 00:00:00.000000000 +0000
+++ ssh-openssl-thread-locking.c	2012-03-11 21:37:10.000000000 +0400
@@ -0,0 +1,132 @@
+/* This code is taken from openssl distribution crypto/threads/mttest.c */
+/* Non-pthreads code is removed. */
+/* */
+/* */
+/* */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include "includes.h"
+
+#include "ssh-openssl-thread-locking.h"
+
+#include <openssl/crypto.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_LIBPTHREAD
+
+static pthread_mutex_t *lock_cs;
+static long *lock_count;
+
+void pthreads_locking_callback(int mode, int type, char *file, int line);
+unsigned long pthreads_thread_id(void);
+
+void openssl_thread_locks_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 openssl_thread_locks_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);
+
+	}
+
+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);
+	}
+
+#endif
--- ssh-openssl-thread-locking.h	2012-03-11 00:00:00.000000000 +0000
+++ ssh-openssl-thread-locking.h	2012-03-11 21:23:23.000000000 +0400
@@ -0,0 +1,75 @@
+/* This code is taken from openssl distribution crypto/threads/mttest.c */
+/* Non-pthreads code is removed. */
+/* */
+/* */
+/* */
+/* Copyright (C) 1995-1998 Eric Young (eay at cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay at cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh at cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay at cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh at cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef SSH_OPENSSL_THREAD_LOCKING_INCLUDED
+#define SSH_OPENSSL_THREAD_LOCKING_INCLUDED
+
+#include <pthread.h>
+
+#ifdef HAVE_LIBPTHREAD
+
+void openssl_thread_locks_setup(void);
+void openssl_thread_locks_cleanup(void);
+
+#endif
+
+#endif


More information about the openssh-unix-dev mailing list