Permalink
Browse files

Add thread safety to OpenSSL gem

With OpenSSL, you need to register some methods to make sure OpenSSL is
thread safe to use. Since we don't want to lock around the whole
extension, we make sure to setup this stuff.
  • Loading branch information...
1 parent fa98fa8 commit 677aac929b7c97151534649c91a678df2869736b @dbussink dbussink committed May 8, 2013
Showing with 111 additions and 0 deletions.
  1. +37 −0 lib/18/openssl/ext/ossl.c
  2. +37 −0 lib/19/openssl/ext/ossl.c
  3. +37 −0 lib/20/openssl/ext/ossl.c
View
@@ -406,6 +406,37 @@ ossl_debug_set(VALUE self, VALUE val)
return val;
}
+/**
+ * Stores locks needed for OpenSSL thread safety
+ */
+static VALUE* ossl_locks;
+
+static void ossl_lock_callback(int mode, int type, char *file, int line)
+{
+ if (mode & CRYPTO_LOCK) {
+ rb_mutex_lock(ossl_locks[type]);
+ } else {
+ rb_mutex_unlock(ossl_locks[type]);
+ }
+}
+
+static unsigned long ossl_thread_id(void)
+{
+ return NUM2ULONG(rb_obj_id(rb_thread_current()));
+}
+
+static void Init_ossl_locks(void)
+{
+ ossl_locks = (VALUE*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(VALUE));
+ for (int i = 0; i < CRYPTO_num_locks(); i++) {
+ ossl_locks[i] = rb_mutex_new();
+ rb_global_variable(&(ossl_locks[i]));
+ }
+
+ CRYPTO_set_id_callback((unsigned long (*)())ossl_thread_id);
+ CRYPTO_set_locking_callback((void (*)())ossl_lock_callback);
+}
+
/*
* OSSL library init
*/
@@ -447,6 +478,7 @@ Init_openssl()
* Init main module
*/
mOSSL = rb_define_module("OpenSSL");
+ rb_global_variable(&mOSSL);
/*
* Constants
@@ -460,6 +492,7 @@ Init_openssl()
* common for all classes under OpenSSL module
*/
eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_global_variable(&eOSSLError);
/*
* Verify callback Proc index for ext-data
@@ -471,6 +504,8 @@ Init_openssl()
* Init debug core
*/
dOSSL = Qfalse;
+ rb_global_variable(&dOSSL);
+
rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0);
rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1);
rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0);
@@ -480,6 +515,8 @@ Init_openssl()
*/
ossl_s_to_der = rb_intern("to_der");
+ Init_ossl_locks();
+
/*
* Init components
*/
View
@@ -415,6 +415,37 @@ ossl_debug_set(VALUE self, VALUE val)
return val;
}
+/**
+ * Stores locks needed for OpenSSL thread safety
+ */
+static VALUE* ossl_locks;
+
+static void ossl_lock_callback(int mode, int type, char *file, int line)
+{
+ if (mode & CRYPTO_LOCK) {
+ rb_mutex_lock(ossl_locks[type]);
+ } else {
+ rb_mutex_unlock(ossl_locks[type]);
+ }
+}
+
+static unsigned long ossl_thread_id(void)
+{
+ return NUM2ULONG(rb_obj_id(rb_thread_current()));
+}
+
+static void Init_ossl_locks(void)
+{
+ ossl_locks = (VALUE*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(VALUE));
+ for (int i = 0; i < CRYPTO_num_locks(); i++) {
+ ossl_locks[i] = rb_mutex_new();
+ rb_global_variable(&(ossl_locks[i]));
+ }
+
+ CRYPTO_set_id_callback((unsigned long (*)())ossl_thread_id);
+ CRYPTO_set_locking_callback((void (*)())ossl_lock_callback);
+}
+
/*
* OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the
* OpenSSL[http://www.openssl.org/] library.
@@ -826,6 +857,7 @@ Init_openssl()
* Init main module
*/
mOSSL = rb_define_module("OpenSSL");
+ rb_global_variable(&mOSSL);
/*
* OpenSSL ruby extension version
@@ -847,6 +879,7 @@ Init_openssl()
* common for all classes under OpenSSL module
*/
eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_global_variable(&eOSSLError);
/*
* Verify callback Proc index for ext-data
@@ -858,6 +891,8 @@ Init_openssl()
* Init debug core
*/
dOSSL = Qfalse;
+ rb_global_variable(&dOSSL);
+
rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0);
rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1);
rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0);
@@ -867,6 +902,8 @@ Init_openssl()
*/
ossl_s_to_der = rb_intern("to_der");
+ Init_ossl_locks();
+
/*
* Init components
*/
View
@@ -415,6 +415,37 @@ ossl_debug_set(VALUE self, VALUE val)
return val;
}
+/**
+ * Stores locks needed for OpenSSL thread safety
+ */
+static VALUE* ossl_locks;
+
+static void ossl_lock_callback(int mode, int type, char *file, int line)
+{
+ if (mode & CRYPTO_LOCK) {
+ rb_mutex_lock(ossl_locks[type]);
+ } else {
+ rb_mutex_unlock(ossl_locks[type]);
+ }
+}
+
+static unsigned long ossl_thread_id(void)
+{
+ return NUM2ULONG(rb_obj_id(rb_thread_current()));
+}
+
+static void Init_ossl_locks(void)
+{
+ ossl_locks = (VALUE*) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(VALUE));
+ for (int i = 0; i < CRYPTO_num_locks(); i++) {
+ ossl_locks[i] = rb_mutex_new();
+ rb_global_variable(&(ossl_locks[i]));
+ }
+
+ CRYPTO_set_id_callback((unsigned long (*)())ossl_thread_id);
+ CRYPTO_set_locking_callback((void (*)())ossl_lock_callback);
+}
+
/*
* OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the
* OpenSSL[http://www.openssl.org/] library.
@@ -826,6 +857,7 @@ Init_openssl()
* Init main module
*/
mOSSL = rb_define_module("OpenSSL");
+ rb_global_variable(&mOSSL);
/*
* OpenSSL ruby extension version
@@ -847,6 +879,7 @@ Init_openssl()
* common for all classes under OpenSSL module
*/
eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_global_variable(&eOSSLError);
/*
* Verify callback Proc index for ext-data
@@ -858,6 +891,8 @@ Init_openssl()
* Init debug core
*/
dOSSL = Qfalse;
+ rb_global_variable(&dOSSL);
+
rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0);
rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1);
rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0);
@@ -867,6 +902,8 @@ Init_openssl()
*/
ossl_s_to_der = rb_intern("to_der");
+ Init_ossl_locks();
+
/*
* Init components
*/

0 comments on commit 677aac9

Please sign in to comment.