Commit 081e76bac26e1ed6adafb402d15b30c622866d61

Carlos Martín Nieto 2014-06-12T16:20:52

ssl: init everything all the time Bring together all of the OpenSSL initialization to git_threads_init() so it's together and doesn't need locks. Moving it here also gives us libssh2 thread safety (when built against openssl).

diff --git a/src/global.c b/src/global.c
index 41428ec..b144b05 100644
--- a/src/global.c
+++ b/src/global.c
@@ -19,11 +19,9 @@ git_mutex git__mwindow_mutex;
 #ifdef GIT_SSL
 # include <openssl/ssl.h>
 SSL_CTX *git__ssl_ctx;
+static git_mutex *openssl_locks;
 #endif
 
-git_mutex git__ssl_mutex;
-git_atomic git__ssl_init;
-
 static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
 static git_atomic git__n_shutdown_callbacks;
 static git_atomic git__n_inits;
@@ -47,12 +45,59 @@ static void git__shutdown(void)
 
 }
 
+#if defined(GIT_THREADS) && defined(GIT_SSL)
+void openssl_locking_function(int mode, int n, const char *file, int line)
+{
+	int lock;
+
+	GIT_UNUSED(file);
+	GIT_UNUSED(line);
+
+	lock = mode & CRYPTO_LOCK;
+
+	if (lock) {
+		git_mutex_lock(&openssl_locks[n]);
+	} else {
+		git_mutex_unlock(&openssl_locks[n]);
+	}
+}
+#endif
+
+
 static void init_ssl(void)
 {
 #ifdef GIT_SSL
 	SSL_load_error_strings();
 	OpenSSL_add_ssl_algorithms();
 	git__ssl_ctx = SSL_CTX_new(SSLv23_method());
+	SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY);
+	SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL);
+	if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) {
+		SSL_CTX_free(git__ssl_ctx);
+		git__ssl_ctx = NULL;
+	}
+
+# ifdef GIT_THREADS
+	{
+		int num_locks, i;
+
+		num_locks = CRYPTO_num_locks();
+		openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
+		if (openssl_locks == NULL) {
+			SSL_CTX_free(git__ssl_ctx);
+			git__ssl_ctx = NULL;
+		}
+
+		for (i = 0; i < num_locks; i++) {
+			if (git_mutex_init(&openssl_locks[i]) != 0) {
+				SSL_CTX_free(git__ssl_ctx);
+				git__ssl_ctx = NULL;
+			}
+		}
+
+		CRYPTO_set_locking_callback(openssl_locking_function);
+	}
+# endif
 #endif
 }
 
@@ -183,8 +228,6 @@ static void init_once(void)
 {
 	if ((init_error = git_mutex_init(&git__mwindow_mutex)) != 0)
 		return;
-	if ((init_error = git_mutex_init(&git__ssl_mutex)) != 0)
-		return;
 	pthread_key_create(&_tls_key, &cb__free_status);
 
 
diff --git a/src/global.h b/src/global.h
index 8904e2d..745df3e 100644
--- a/src/global.h
+++ b/src/global.h
@@ -23,8 +23,6 @@ extern SSL_CTX *git__ssl_ctx;
 git_global_st *git__global_state(void);
 
 extern git_mutex git__mwindow_mutex;
-extern git_mutex git__ssl_mutex;
-extern git_atomic git__ssl_init;
 
 #define GIT_GLOBAL (git__global_state())
 
diff --git a/src/netops.c b/src/netops.c
index 54804d4..965e477 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -35,11 +35,6 @@
 #include "http_parser.h"
 #include "global.h"
 
-#if defined(GIT_SSL) && defined(GIT_THREADS)
-/* OpenSSL wants us to keep an array of locks */
-static git_mutex *openssl_locks;
-#endif
-
 #ifdef GIT_WIN32
 static void net_set_error(const char *str)
 {
@@ -391,86 +386,14 @@ cert_fail_name:
 	return -1;
 }
 
-#ifdef GIT_THREADS
-void openssl_locking_function(int mode, int n, const char *file, int line)
-{
-	int lock;
-
-	GIT_UNUSED(file);
-	GIT_UNUSED(line);
-
-	lock = mode & CRYPTO_LOCK;
-
-	if (lock) {
-		git_mutex_lock(&openssl_locks[n]);
-	} else {
-		git_mutex_unlock(&openssl_locks[n]);
-	}
-}
-#endif
-
-/**
- * The OpenSSL init functions are not reentrant so we need to init
- * them under lock.
- */
-static int init_ssl(void)
-{
-	if (git__ssl_init.val)
-		return 0;
-
-	if (git_mutex_lock(&git__ssl_mutex) < 0) {
-		giterr_set(GITERR_OS, "failed to acquire ssl init lock");
-		return -1;
-	}
-
-	/* if we had to wait for the lock, someone else did it, we can return */
-	if (git__ssl_init.val)
-		return 0;
-
-	SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY);
-	SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL);
-	if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx)) {
-		unsigned long err = ERR_get_error();
-		giterr_set(GITERR_SSL, "failed to set verify paths: %s\n", ERR_error_string(err, NULL));
-		return -1;
-	}
-
-#ifdef GIT_THREADS
-	{
-		int num_locks, i;
-
-		num_locks = CRYPTO_num_locks();
-		openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
-		if (openssl_locks == NULL) {
-			git_mutex_unlock(&git__ssl_mutex);
-			return -1;
-		}
-		GITERR_CHECK_ALLOC(openssl_locks);
-
-		for (i = 0; i < num_locks; i++) {
-			if (git_mutex_init(&openssl_locks[i]) != 0) {
-				git_mutex_unlock(&git__ssl_mutex);
-				giterr_set(GITERR_SSL, "failed to init lock %d", i);
-				return -1;
-			}
-		}
-	}
-
-	CRYPTO_set_locking_callback(openssl_locking_function);
-#endif
-
-	git_atomic_inc(&git__ssl_init);
-	git_mutex_unlock(&git__ssl_mutex);
-
-	return 0;
-}
-
 static int ssl_setup(gitno_socket *socket, const char *host, int flags)
 {
 	int ret;
 
-	if (init_ssl() < 0)
+	if (git__ssl_ctx == NULL) {
+		giterr_set(GITERR_NET, "OpenSSL initialization failed");
 		return -1;
+	}
 
 	socket->ssl.ssl = SSL_new(git__ssl_ctx);
 	if (socket->ssl.ssl == NULL)