summaryrefslogtreecommitdiff
path: root/src/netops.c
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-06-11 20:52:15 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-06-11 20:54:42 +0200
commit1d3364ac9d2bcd2d194f0afa0d301456d0d4e276 (patch)
tree74981c82bc5350a2303f6a68a9d162d6001dfec8 /src/netops.c
parent716e20b47eb82ebd94588fe6c950e661b6fe4f15 (diff)
downloadlibgit2-1d3364ac9d2bcd2d194f0afa0d301456d0d4e276.tar.gz
netops: init OpenSSL once under lock
The OpenSSL init functions are not reentrant, which means that running multiple fetches in parallel can cause us to crash. Use a mutex to init OpenSSL, and since we're adding this extra checks, init it only once.
Diffstat (limited to 'src/netops.c')
-rw-r--r--src/netops.c34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/netops.c b/src/netops.c
index a0193a022..7bce159ad 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -33,6 +33,7 @@
#include "posix.h"
#include "buffer.h"
#include "http_parser.h"
+#include "global.h"
#ifdef GIT_WIN32
static void net_set_error(const char *str)
@@ -386,12 +387,41 @@ cert_fail_name:
return -1;
}
-static int ssl_setup(gitno_socket *socket, const char *host, int flags)
+/**
+ * The OpenSSL init functions are not reentrant so we need to init
+ * them under lock.
+ */
+static int init_ssl(void)
{
- int ret;
+ 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_library_init();
SSL_load_error_strings();
+
+ git_atomic_set(&git__ssl_init, 1);
+ 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)
+ return -1;
+
socket->ssl.ctx = SSL_CTX_new(SSLv23_method());
if (socket->ssl.ctx == NULL)
return ssl_set_error(&socket->ssl, 0);