Commit c7922304 authored by Richard Levitte's avatar Richard Levitte
Browse files

Add support for dynamically created and destroyed mutexes. This will

be needed in some ENGINE code, and might serve elsewhere as well.
Note that it's implemented in such a way that the locking itself is
done through the same CRYPTO_lock function as the static locks.

WARNING: This is currently experimental and untested code (it will get
tested soon, though :-)).
parent a8b07aa4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
static ERR_STRING_DATA CRYPTO_str_functs[]=
	{
{ERR_PACK(0,CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX,0),	"CRYPTO_get_ex_new_index"},
{ERR_PACK(0,CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,0),	"CRYPTO_get_new_dynlockid"},
{ERR_PACK(0,CRYPTO_F_CRYPTO_GET_NEW_LOCKID,0),	"CRYPTO_get_new_lockid"},
{ERR_PACK(0,CRYPTO_F_CRYPTO_SET_EX_DATA,0),	"CRYPTO_set_ex_data"},
{0,NULL}
@@ -74,6 +75,7 @@ static ERR_STRING_DATA CRYPTO_str_functs[]=

static ERR_STRING_DATA CRYPTO_str_reasons[]=
	{
{CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK     ,"no dynlock create callback"},
{0,NULL}
	};

+134 −5
Original line number Diff line number Diff line
@@ -60,11 +60,15 @@
#include <string.h>
#include "cryptlib.h"
#include <openssl/crypto.h>
#include <openssl/safestack.h>

#if defined(WIN32) || defined(WIN16)
static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */
#endif

DECLARE_STACK_OF(CRYPTO_dynlock);
IMPLEMENT_STACK_OF(CRYPTO_dynlock);

/* real #defines in crypto.h, keep these upto date */
static const char* lock_names[CRYPTO_NUM_LOCKS] =
	{
@@ -100,13 +104,30 @@ static const char* lock_names[CRYPTO_NUM_LOCKS] =
#endif
	};

/* This is for applications to allocate new type names in the non-dynamic
   array of lock names.  These are numbered with positive numbers.  */
static STACK *app_locks=NULL;

/* For applications that want a more dynamic way of handling threads, the
   following stack is used.  These are externally numbered with negative
   numbers.  */
static STACK_OF(CRYPTO_dynlock) *dyn_locks=NULL;


static void (MS_FAR *locking_callback)(int mode,int type,
	const char *file,int line)=NULL;
static int (MS_FAR *add_lock_callback)(int *pointer,int amount,
	int type,const char *file,int line)=NULL;
static unsigned long (MS_FAR *id_callback)(void)=NULL;
static CRYPTO_dynlock *(MS_FAR *dynlock_create_callback)(const char *file,
	int line)=NULL;
static void (MS_FAR *dynlock_locking_callback)(int mode, CRYPTO_dynlock *l,
	const char *file,int line)=NULL;
static void (MS_FAR *dynlock_destroy_callback)(CRYPTO_dynlock *l,
	const char *file,int line)=NULL;
static int (MS_FAR *add_dynlock_callback)(int *pointer,int amount,
	CRYPTO_dynlock *l,const char *file,int line)=NULL;

int CRYPTO_get_new_lockid(char *name)
	{
	char *str;
@@ -126,7 +147,10 @@ int CRYPTO_get_new_lockid(char *name)
		return(0);
		}
	if ((str=BUF_strdup(name)) == NULL)
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_LOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}
	i=sk_push(app_locks,str);
	if (!i)
		OPENSSL_free(str);
@@ -140,30 +164,112 @@ int CRYPTO_num_locks(void)
	return CRYPTO_NUM_LOCKS;
	}

int CRYPTO_get_new_dynlockid(void)
	{
	int i = 0;
	CRYPTO_dynlock *pointer = NULL;

	if (dynlock_create_callback == NULL)
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK);
		return(0);
		}
	if ((dyn_locks == NULL)
		&& ((dyn_locks=sk_new_null()) == NULL))
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}

	pointer = dynlock_create_callback(__FILE__,__LINE__);
	if (pointer == NULL)
		{
		CRYPTOerr(CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID,ERR_R_MALLOC_FAILURE);
		return(0);
		}
	i=sk_CRYPTO_dynlock_push(dyn_locks,pointer);
	if (!i)
		dynlock_destroy_callback(pointer,__FILE__,__LINE__);
	else
		i += 1; /* to avoid 0 */
	return -i;
	}

void CRYPTO_destroy_dynlockid(int i)
	{
	if (i)
		i = -i-1;
	if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks))
		return;
	if (dynlock_destroy_callback == NULL)
		return;
	dynlock_destroy_callback(sk_CRYPTO_dynlock_value(dyn_locks, i),
		__FILE__,__LINE__);
	sk_CRYPTO_dynlock_set(dyn_locks, i, NULL);
	}

CRYPTO_dynlock *CRYPTO_get_dynlock_value(int i)
	{
	if (i)
		i = -i-1;
	if (dyn_locks == NULL || i >= sk_CRYPTO_dynlock_num(dyn_locks))
		return NULL;
	return sk_CRYPTO_dynlock_value(dyn_locks, i);
	}

void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file,
		int line)
	{
	return(locking_callback);
	}

void (*CRYPTO_get_dynlock_lock_callback(void))(int mode,CRYPTO_dynlock *l,
					       const char *file,int line)
	{
	return(dynlock_locking_callback);
	}

int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
					  const char *file,int line)
	{
	return(add_lock_callback);
	}

int (*CRYPTO_get_add_dynlock_callback(void))(int *num,int mount,
					     CRYPTO_dynlock *l,
					     const char *file,int line)
	{
	return(add_dynlock_callback);
	}

void CRYPTO_set_locking_callback(void (*func)(int mode,int type,
					      const char *file,int line))
	{
	locking_callback=func;
	}

void CRYPTO_set_dynlock_locking_callback(void (*func)(int mode,
						      CRYPTO_dynlock *l,
						      const char *file,
						      int line))
	{
	dynlock_locking_callback=func;
	}

void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
					      const char *file,int line))
	{
	add_lock_callback=func;
	}

void CRYPTO_set_add_dynlock_lock_callback(int (*func)(int *num,int mount,
						      CRYPTO_dynlock *l,
						      const char *file,
						      int line))
	{
	add_dynlock_callback=func;
	}

unsigned long (*CRYPTO_get_id_callback(void))(void)
	{
	return(id_callback);
@@ -220,6 +326,15 @@ void CRYPTO_lock(int mode, int type, const char *file, int line)
			CRYPTO_get_lock_name(type), file, line);
		}
#endif
	if (type < 0)
		{
		int i = -type-1;
		if (i < sk_CRYPTO_dynlock_num(dyn_locks))
			dynlock_locking_callback(mode,
				sk_CRYPTO_dynlock_value(dyn_locks,i),
				file,line);
		}
	else
		if (locking_callback != NULL)
			locking_callback(mode,type,file,line);
	}
@@ -227,7 +342,7 @@ void CRYPTO_lock(int mode, int type, const char *file, int line)
int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
	     int line)
	{
	int ret;
	int ret = 0;

	if (add_lock_callback != NULL)
		{
@@ -235,6 +350,20 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
		int before= *pointer;
#endif

		if (type < 0)
			{
			int i = -type-1;
			if (i >= sk_CRYPTO_dynlock_num(dyn_locks))
				/* FIXME: This is superbly dangerous if there
				   are threads competing on this value, but
				   hey, if the user used an invalid lock... */
				ret=(*pointer + amount);
			else
				ret=add_dynlock_callback(pointer,amount,
					sk_CRYPTO_dynlock_value(dyn_locks,i),
					file,line);
			}
		else
			ret=add_lock_callback(pointer,amount,type,file,line);
#ifdef LOCK_DEBUG
		fprintf(stderr,"ladd:%08lx:%2d+%2d->%2d %-18s %s:%d\n",
@@ -266,7 +395,7 @@ int CRYPTO_add_lock(int *pointer, int amount, int type, const char *file,
const char *CRYPTO_get_lock_name(int type)
	{
	if (type < 0)
		return("ERROR");
		return("dynamic");
	else if (type < CRYPTO_NUM_LOCKS)
		return(lock_names[type]);
	else if (type-CRYPTO_NUM_LOCKS >= sk_num(app_locks))
+19 −0
Original line number Diff line number Diff line
@@ -150,6 +150,12 @@ extern "C" {
#define CRYPTO_add(a,b,c)	((*(a))+=(b))
#endif

/* Some applications as well as some parts of OpenSSL need to allocate
   and deallocate locks in a dynamic fashion.  The following typedef
   makes this possible in a type-safe manner.  */
typedef struct CRYPTO_dynlock_value CRYPTO_dynlock;


/* The following can be used to detect memory leaks in the SSLeay library.
 * It used, it turns on malloc checking */

@@ -299,6 +305,16 @@ unsigned long CRYPTO_thread_id(void);
const char *CRYPTO_get_lock_name(int type);
int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file,
		    int line);
void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock *(*dyn_create_function)
	(char *file, int line));
void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)
	(int mode, CRYPTO_dynlock *l, const char *file, int line));
void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)
	(CRYPTO_dynlock *l, const char *file, int line));
void CRYPTO_set_dynlock_size(int dynlock_size);
int CRYPTO_get_new_dynlockid(void);
void CRYPTO_destroy_dynlockid(int i);
CRYPTO_dynlock *CRYPTO_get_dynlock_value(int i);

/* CRYPTO_set_mem_functions includes CRYPTO_set_locked_mem_functions --
 * call the latter last if you need different functions */
@@ -371,12 +387,15 @@ void ERR_load_CRYPTO_strings(void);

/* Function codes. */
#define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX		 100
#define CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID		 103
#define CRYPTO_F_CRYPTO_GET_NEW_LOCKID			 101
#define CRYPTO_F_CRYPTO_SET_EX_DATA			 102

/* Reason codes. */
#define CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK		 100

#ifdef  __cplusplus
}
#endif
#endif
+20 −0
Original line number Diff line number Diff line
@@ -164,6 +164,26 @@ STACK_OF(type) \
#endif

/* This block of defines is updated by util/mkstack.pl, please do not touch! */
#define sk_CRYPTO_dynlock_new(st) SKM_sk_new(CRYPTO_dynlock, (st))
#define sk_CRYPTO_dynlock_new_null() SKM_sk_new_null(CRYPTO_dynlock)
#define sk_CRYPTO_dynlock_free(st) SKM_sk_free(CRYPTO_dynlock, (st))
#define sk_CRYPTO_dynlock_num(st) SKM_sk_num(CRYPTO_dynlock, (st))
#define sk_CRYPTO_dynlock_value(st, i) SKM_sk_value(CRYPTO_dynlock, (st), (i))
#define sk_CRYPTO_dynlock_set(st, i, val) SKM_sk_set(CRYPTO_dynlock, (st), (i), (val))
#define sk_CRYPTO_dynlock_zero(st) SKM_sk_zero(CRYPTO_dynlock, (st))
#define sk_CRYPTO_dynlock_push(st, val) SKM_sk_push(CRYPTO_dynlock, (st), (val))
#define sk_CRYPTO_dynlock_unshift(st, val) SKM_sk_unshift(CRYPTO_dynlock, (st), (val))
#define sk_CRYPTO_dynlock_find(st, val) SKM_sk_find(CRYPTO_dynlock, (st), (val))
#define sk_CRYPTO_dynlock_delete(st, i) SKM_sk_delete(CRYPTO_dynlock, (st), (i))
#define sk_CRYPTO_dynlock_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_dynlock, (st), (ptr))
#define sk_CRYPTO_dynlock_insert(st, val, i) SKM_sk_insert(CRYPTO_dynlock, (st), (val), (i))
#define sk_CRYPTO_dynlock_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_dynlock, (st), (cmp))
#define sk_CRYPTO_dynlock_dup(st) SKM_sk_dup(CRYPTO_dynlock, st)
#define sk_CRYPTO_dynlock_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_dynlock, (st), (free_func))
#define sk_CRYPTO_dynlock_shift(st) SKM_sk_shift(CRYPTO_dynlock, (st))
#define sk_CRYPTO_dynlock_pop(st) SKM_sk_pop(CRYPTO_dynlock, (st))
#define sk_CRYPTO_dynlock_sort(st) SKM_sk_sort(CRYPTO_dynlock, (st))

#define sk_CRYPTO_EX_DATA_FUNCS_new(st) SKM_sk_new(CRYPTO_EX_DATA_FUNCS, (st))
#define sk_CRYPTO_EX_DATA_FUNCS_new_null() SKM_sk_new_null(CRYPTO_EX_DATA_FUNCS)
#define sk_CRYPTO_EX_DATA_FUNCS_free(st) SKM_sk_free(CRYPTO_EX_DATA_FUNCS, (st))
+65 −1
Original line number Diff line number Diff line
@@ -15,10 +15,27 @@ CRYPTO_set_locking_callback, CRYPTO_set_id_callback - OpenSSL thread support

 int CRYPTO_num_locks(void);


 /* struct CRYPTO_dynlock_value needs to be defined by the user */
 typedef struct CRYPTO_dynlock_value CRYPTO_dynlock;

 void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock *(*dyn_create_function)
	(char *file, int line));
 void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)
	(int mode, CRYPTO_dynlock *l, const char *file, int line));
 void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)
	(CRYPTO_dynlock *l, const char *file, int line));

 int CRYPTO_get_new_dynlockid(void);

 void CRYPTO_destroy_dynlockid(int i);

 void CRYPTO_lock(int mode, int n, const char *file, int line);

=head1 DESCRIPTION

OpenSSL can safely be used in multi-threaded applications provided
that two callback functions are set.
that at least two callback functions are set.

locking_function(int mode, int n, const char *file, int line) is
needed to perform locking on shared data stuctures. Multi-threaded
@@ -35,9 +52,55 @@ id_function(void) is a function that returns a thread ID. It is not
needed on Windows nor on platforms where getpid() returns a different
ID for each thread (most notably Linux).

Additionally, OpenSSL supports dynamic locks, and sometimes, some parts
of OpenSSL need it for better performance.  To enable this, the following
is required:

=item *
Three additional callback function, dyn_create_function, dyn_lock_function
and dyn_destroy_function.

=item *
A structure defined with the data that each lock needs to handle.

struct CRYPTO_dynlock_value has to be defined to contain whatever structure
is needed to handle locks.

dyn_create_function(const char *file, int line) is needed to create a
lock.  Multi-threaded applications might crash at random if it is not set.

dyn_lock_function(int mode, CRYPTO_dynlock *l, const char *file, int line)
is needed to perform locking off dynamic lock nunmbered n. Multi-threaded
applications might crash at random if it is not set.

dyn_destroy_function(CRYPTO_dynlock *l, const char *file, int line) is
needed to destroy the lock l. Multi-threaded applications might crash at
random if it is not set.

CRYPTO_get_new_dynlockid() is used to create locks.  It will call
dyn_create_function for the actual creation.

CRYPTO_destroy_dynlockid() is used to destroy locks.  It will call
dyn_destroy_function for the actual destruction.

CRYPTO_lock() is used to lock and unlock the locks.  mode is a bitfield
describing what should be done with the lock.  n is the number of the
lock as returned from CRYPTO_get_new_dynlockid().  mode can be combined
from the following values.  These values are pairwise exclusive, with
undefined behavior if misused (for example, CRYPTO_READ and CRYPTO_WRITE
should not be used together):

	CRYPTO_LOCK	0x01
	CRYPTO_UNLOCK	0x02
	CRYPTO_READ	0x04
	CRYPTO_WRITE	0x08

=head1 RETURN VALUES

CRYPTO_num_locks() returns the required number of locks.

CRYPTO_get_new_dynlockid() returns the index to the newly created lock.

The other functions return no values.

=head1 NOTE
@@ -62,6 +125,7 @@ Solaris, Irix and Win32.
CRYPTO_set_locking_callback() and CRYPTO_set_id_callback() are
available in all versions of SSLeay and OpenSSL.
CRYPTO_num_locks() was added in OpenSSL 0.9.4.
All functions dealing with dynamic locks were added in OpenSSL 0.9.5b-dev.

=head1 SEE ALSO

Loading