1 /**
2  * @file openssl.c  OpenSSL initialisation and multi-threading routines
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #ifdef HAVE_SIGNAL
7 #include <signal.h>
8 #endif
9 #ifdef HAVE_PTHREAD
10 #include <pthread.h>
11 #endif
12 #include <openssl/crypto.h>
13 #include <openssl/ssl.h>
14 #include <openssl/err.h>
15 #include <re_types.h>
16 #include <re_lock.h>
17 #include <re_mem.h>
18 #include "main.h"
19 
20 
21 #if defined (HAVE_PTHREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
22 
23 
24 static pthread_mutex_t *lockv;
25 
26 
threadid(void)27 static inline unsigned long threadid(void)
28 {
29 #if defined (DARWIN) || defined (FREEBSD) || defined (OPENBSD) || \
30 	defined (NETBSD) || defined (DRAGONFLY)
31 	return (unsigned long)(void *)pthread_self();
32 #else
33 	return (unsigned long)pthread_self();
34 #endif
35 }
36 
37 
38 #if OPENSSL_VERSION_NUMBER >= 0x10000000
threadid_handler(CRYPTO_THREADID * id)39 static void threadid_handler(CRYPTO_THREADID *id)
40 {
41 	CRYPTO_THREADID_set_numeric(id, threadid());
42 }
43 #else
threadid_handler(void)44 static unsigned long threadid_handler(void)
45 {
46 	return threadid();
47 }
48 #endif
49 
50 
locking_handler(int mode,int type,const char * file,int line)51 static void locking_handler(int mode, int type, const char *file, int line)
52 {
53 	(void)file;
54 	(void)line;
55 
56 	if (mode & CRYPTO_LOCK)
57 		(void)pthread_mutex_lock(&lockv[type]);
58 	else
59 		(void)pthread_mutex_unlock(&lockv[type]);
60 }
61 
62 
63 #endif
64 
65 
66 #if OPENSSL_VERSION_NUMBER < 0x10100000L
dynlock_create_handler(const char * file,int line)67 static struct CRYPTO_dynlock_value *dynlock_create_handler(const char *file,
68 							   int line)
69 {
70 	struct lock *lock;
71 	(void)file;
72 	(void)line;
73 
74 	if (lock_alloc(&lock))
75 		return NULL;
76 
77 	return (struct CRYPTO_dynlock_value *)lock;
78 }
79 
80 
dynlock_lock_handler(int mode,struct CRYPTO_dynlock_value * l,const char * file,int line)81 static void dynlock_lock_handler(int mode, struct CRYPTO_dynlock_value *l,
82 				 const char *file, int line)
83 {
84 	struct lock *lock = (struct lock *)l;
85 	(void)file;
86 	(void)line;
87 
88 	if (mode & CRYPTO_LOCK)
89 		lock_write_get(lock);
90 	else
91 		lock_rel(lock);
92 }
93 
94 
dynlock_destroy_handler(struct CRYPTO_dynlock_value * l,const char * file,int line)95 static void dynlock_destroy_handler(struct CRYPTO_dynlock_value *l,
96 				    const char *file, int line)
97 {
98 	(void)file;
99 	(void)line;
100 
101 	mem_deref(l);
102 }
103 #endif
104 
105 
106 #ifdef SIGPIPE
sigpipe_handler(int x)107 static void sigpipe_handler(int x)
108 {
109 	(void)x;
110 	(void)signal(SIGPIPE, sigpipe_handler);
111 }
112 #endif
113 
114 
openssl_init(void)115 int openssl_init(void)
116 {
117 #if defined (HAVE_PTHREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
118 	int err, i;
119 
120 	lockv = mem_zalloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks(), NULL);
121 	if (!lockv)
122 		return ENOMEM;
123 
124 	for (i=0; i<CRYPTO_num_locks(); i++) {
125 
126 		err = pthread_mutex_init(&lockv[i], NULL);
127 		if (err) {
128 			lockv = mem_deref(lockv);
129 			return err;
130 		}
131 	}
132 
133 #if OPENSSL_VERSION_NUMBER >= 0x10000000
134 	CRYPTO_THREADID_set_callback(threadid_handler);
135 #else
136 	CRYPTO_set_id_callback(threadid_handler);
137 #endif
138 
139 	CRYPTO_set_locking_callback(locking_handler);
140 #endif
141 
142 #if OPENSSL_VERSION_NUMBER < 0x10100000L
143 	CRYPTO_set_dynlock_create_callback(dynlock_create_handler);
144 	CRYPTO_set_dynlock_lock_callback(dynlock_lock_handler);
145 	CRYPTO_set_dynlock_destroy_callback(dynlock_destroy_handler);
146 #endif
147 
148 #ifdef SIGPIPE
149 	(void)signal(SIGPIPE, sigpipe_handler);
150 #endif
151 
152 	SSL_library_init();
153 	SSL_load_error_strings();
154 
155 	return 0;
156 }
157 
158 
openssl_close(void)159 void openssl_close(void)
160 {
161 	ERR_free_strings();
162 #if defined (HAVE_PTHREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
163 	lockv = mem_deref(lockv);
164 #endif
165 }
166