Expose OpenSSL initialization functions

Otherwise, commit is a logical no-op; it keeps the same OpenSSL
initialization behavior as before.  Move the SSL initialization
functionality to one place to make it easier to track.

Signed-off-by: Alan Dunn <amdunn@gmail.com>
Signed-off-by: Roger Meier <roger@apache.org>
diff --git a/lib/cpp/src/thrift/transport/TSSLSocket.cpp b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
index 9a8c758..4b36f8c 100644
--- a/lib/cpp/src/thrift/transport/TSSLSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
@@ -49,6 +49,87 @@
 
 namespace apache { namespace thrift { namespace transport {
 
+// OpenSSL initialization/cleanup
+
+static bool openSSLInitialized = false;
+static boost::shared_array<Mutex> mutexes;
+
+static void callbackLocking(int mode, int n, const char*, int) {
+  if (mode & CRYPTO_LOCK) {
+    mutexes[n].lock();
+  } else {
+    mutexes[n].unlock();
+  }
+}
+
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
+static unsigned long callbackThreadID() {
+  return (unsigned long) pthread_self();
+}
+#endif
+
+static CRYPTO_dynlock_value* dyn_create(const char*, int) {
+  return new CRYPTO_dynlock_value;
+}
+
+static void dyn_lock(int mode,
+                     struct CRYPTO_dynlock_value* lock,
+                     const char*, int) {
+  if (lock != NULL) {
+    if (mode & CRYPTO_LOCK) {
+      lock->mutex.lock();
+    } else {
+      lock->mutex.unlock();
+    }
+  }
+}
+
+static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
+  delete lock;
+}
+
+void initializeOpenSSL() {
+  if (openSSLInitialized) {
+    return;
+  }
+  openSSLInitialized = true;
+  SSL_library_init();
+  SSL_load_error_strings();
+  // static locking
+  mutexes = boost::shared_array<Mutex>(new Mutex[::CRYPTO_num_locks()]);
+  if (mutexes == NULL) {
+    throw TTransportException(TTransportException::INTERNAL_ERROR,
+          "initializeOpenSSL() failed, "
+          "out of memory while creating mutex array");
+  }
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
+  CRYPTO_set_id_callback(callbackThreadID);
+#endif
+  CRYPTO_set_locking_callback(callbackLocking);
+  // dynamic locking
+  CRYPTO_set_dynlock_create_callback(dyn_create);
+  CRYPTO_set_dynlock_lock_callback(dyn_lock);
+  CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
+}
+
+void cleanupOpenSSL() {
+  if (!openSSLInitialized) {
+    return;
+  }
+  openSSLInitialized = false;
+#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
+  CRYPTO_set_id_callback(NULL);
+#endif
+  CRYPTO_set_locking_callback(NULL);
+  CRYPTO_set_dynlock_create_callback(NULL);
+  CRYPTO_set_dynlock_lock_callback(NULL);
+  CRYPTO_set_dynlock_destroy_callback(NULL);
+  CRYPTO_cleanup_all_ex_data();
+  ERR_free_strings();
+  EVP_cleanup();
+  ERR_remove_state(0);
+  mutexes.reset();
+}
 
 static void buildErrors(string& message, int error = 0);
 static bool matchName(const char* host, const char* pattern, int size);
@@ -377,7 +458,6 @@
 }
 
 // TSSLSocketFactory implementation
-bool     TSSLSocketFactory::initialized = false;
 uint64_t TSSLSocketFactory::count_ = 0;
 Mutex    TSSLSocketFactory::mutex_;
 
@@ -520,85 +600,6 @@
   return length;
 }
 
-static boost::shared_array<Mutex> mutexes;
-
-static void callbackLocking(int mode, int n, const char*, int) {
-  if (mode & CRYPTO_LOCK) {
-    mutexes[n].lock();
-  } else {
-    mutexes[n].unlock();
-  }
-}
-
-#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
-static unsigned long callbackThreadID() {
-  return (unsigned long) pthread_self();
-}
-#endif
-
-static CRYPTO_dynlock_value* dyn_create(const char*, int) {
-  return new CRYPTO_dynlock_value;
-}
-
-static void dyn_lock(int mode,
-                     struct CRYPTO_dynlock_value* lock,
-                     const char*, int) {
-  if (lock != NULL) {
-    if (mode & CRYPTO_LOCK) {
-      lock->mutex.lock();
-    } else {
-      lock->mutex.unlock();
-    }
-  }
-}
-
-static void dyn_destroy(struct CRYPTO_dynlock_value* lock, const char*, int) {
-  delete lock;
-}
-
-void TSSLSocketFactory::initializeOpenSSL() {
-  if (initialized) {
-    return;
-  }
-  initialized = true;
-  SSL_library_init();
-  SSL_load_error_strings();
-  // static locking
-  mutexes = boost::shared_array<Mutex>(new Mutex[::CRYPTO_num_locks()]);
-  if (mutexes == NULL) {
-    throw TTransportException(TTransportException::INTERNAL_ERROR,
-          "initializeOpenSSL() failed, "
-          "out of memory while creating mutex array");
-  }
-#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
-  CRYPTO_set_id_callback(callbackThreadID);
-#endif
-  CRYPTO_set_locking_callback(callbackLocking);
-  // dynamic locking
-  CRYPTO_set_dynlock_create_callback(dyn_create);
-  CRYPTO_set_dynlock_lock_callback(dyn_lock);
-  CRYPTO_set_dynlock_destroy_callback(dyn_destroy);
-}
-
-void TSSLSocketFactory::cleanupOpenSSL() {
-  if (!initialized) {
-    return;
-  }
-  initialized = false;
-#if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_NO_THREAD_ID)
-  CRYPTO_set_id_callback(NULL);
-#endif
-  CRYPTO_set_locking_callback(NULL);
-  CRYPTO_set_dynlock_create_callback(NULL);
-  CRYPTO_set_dynlock_lock_callback(NULL);
-  CRYPTO_set_dynlock_destroy_callback(NULL);
-  CRYPTO_cleanup_all_ex_data();
-  ERR_free_strings();
-  EVP_cleanup();
-  ERR_remove_state(0);
-  mutexes.reset();
-}
-
 // extract error messages from error queue
 void buildErrors(string& errors, int errno_copy) {
   unsigned long  errorCode;
diff --git a/lib/cpp/src/thrift/transport/TSSLSocket.h b/lib/cpp/src/thrift/transport/TSSLSocket.h
index 7c19206..eca9591 100644
--- a/lib/cpp/src/thrift/transport/TSSLSocket.h
+++ b/lib/cpp/src/thrift/transport/TSSLSocket.h
@@ -42,6 +42,21 @@
 
 
 /**
+ * Initialize OpenSSL library.  This function, or some other
+ * equivalent function to initialize OpenSSL, must be called before
+ * TSSLSocket is used.  Currently TSSLSocketFactory automatically
+ * calls this function, so you should not.
+ */
+void initializeOpenSSL();
+/**
+ * Cleanup OpenSSL library.  This function should be called to clean
+ * up OpenSSL after use of OpenSSL functionality is finished.
+ * Currently TSSLSocketFactory automatically calls this function, so
+ * you should not.
+ */
+void cleanupOpenSSL();
+
+/**
  * OpenSSL implementation for SSL socket interface.
  */
 class TSSLSocket: public TSocket {
@@ -204,8 +219,6 @@
  protected:
   boost::shared_ptr<SSLContext> ctx_;
 
-  static void initializeOpenSSL();
-  static void cleanupOpenSSL();
   /**
    * Override this method for custom password callback. It may be called
    * multiple times at any time during a session as necessary.
@@ -217,7 +230,6 @@
  private:
   bool server_;
   boost::shared_ptr<AccessManager> access_;
-  static bool initialized;
   static concurrency::Mutex mutex_;
   static uint64_t count_;
   void setup(boost::shared_ptr<TSSLSocket> ssl);