summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/Instance.cpp
diff options
context:
space:
mode:
authorBernard Normier <bernard@zeroc.com>2008-05-09 10:40:09 -0400
committerBernard Normier <bernard@zeroc.com>2008-05-09 10:40:09 -0400
commit240f2fc68b04cd5637e16811bb350267410b30fb (patch)
treee5472cb7cf3808d14c33e22487cad02009fe1cba /cpp/src/IceSSL/Instance.cpp
parentAdded missing service_running.png (diff)
parentBug 3119 - no local copy of dll for projects (diff)
downloadice-240f2fc68b04cd5637e16811bb350267410b30fb.tar.bz2
ice-240f2fc68b04cd5637e16811bb350267410b30fb.tar.xz
ice-240f2fc68b04cd5637e16811bb350267410b30fb.zip
Merge branch 'master' of cvs:/home/git/ice
Diffstat (limited to 'cpp/src/IceSSL/Instance.cpp')
-rw-r--r--cpp/src/IceSSL/Instance.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/cpp/src/IceSSL/Instance.cpp b/cpp/src/IceSSL/Instance.cpp
index b5234010cec..a40dc5275cd 100644
--- a/cpp/src/IceSSL/Instance.cpp
+++ b/cpp/src/IceSSL/Instance.cpp
@@ -19,8 +19,10 @@
#include <Ice/Properties.h>
#include <Ice/ProtocolPluginFacade.h>
+#include <IceUtil/StaticMutex.h>
#include <IceUtil/StringUtil.h>
+#include <openssl/rand.h>
#include <openssl/err.h>
#include <IceUtil/DisableWarnings.h>
@@ -31,9 +33,52 @@ using namespace IceSSL;
IceUtil::Shared* IceInternal::upCast(IceSSL::Instance* p) { return p; }
+static IceUtil::StaticMutex staticMutex = ICE_STATIC_MUTEX_INITIALIZER;
+static int instanceCount = 0;
+static IceUtil::Mutex* locks = 0;
+
extern "C"
{
+//
+// OpenSSL mutex callback.
+//
+void
+IceSSL_opensslLockCallback(int mode, int n, const char* file, int line)
+{
+ if(mode & CRYPTO_LOCK)
+ {
+ locks[n].lock();
+ }
+ else
+ {
+ locks[n].unlock();
+ }
+}
+
+//
+// OpenSSL thread id callback.
+//
+unsigned long
+IceSSL_opensslThreadIdCallback()
+{
+#if defined(_WIN32)
+ return static_cast<unsigned long>(GetCurrentThreadId());
+#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__osf1__)
+ //
+ // On some platforms, pthread_t is a pointer to a per-thread structure.
+ //
+ return reinterpret_cast<unsigned long>(pthread_self());
+#elif (defined(__linux) || defined(__sun) || defined(__hpux)) || defined(_AIX)
+ //
+ // On Linux, Solaris, HP-UX and AIX, pthread_t is an integer.
+ //
+ return static_cast<unsigned long>(pthread_self());
+#else
+# error "Unknown platform"
+#endif
+}
+
int
IceSSL_opensslPasswordCallback(char* buf, int size, int flag, void* userData)
{
@@ -87,6 +132,99 @@ IceSSL::Instance::Instance(const CommunicatorPtr& communicator) :
{
__setNoDelete(true);
+ //
+ // Initialize OpenSSL if necessary.
+ //
+ IceUtil::StaticMutex::Lock sync(staticMutex);
+ instanceCount++;
+
+ if(instanceCount == 1)
+ {
+ PropertiesPtr properties = communicator->getProperties();
+
+ //
+ // Create the mutexes and set the callbacks.
+ //
+ locks = new IceUtil::Mutex[CRYPTO_num_locks()];
+ CRYPTO_set_locking_callback(IceSSL_opensslLockCallback);
+ CRYPTO_set_id_callback(IceSSL_opensslThreadIdCallback);
+
+ //
+ // Load human-readable error messages.
+ //
+ SSL_load_error_strings();
+
+ //
+ // Initialize the SSL library.
+ //
+ SSL_library_init();
+
+ //
+ // Initialize the PRNG.
+ //
+#ifdef WINDOWS
+ RAND_screen(); // Uses data from the screen if possible.
+#endif
+ char randFile[1024];
+ if(RAND_file_name(randFile, sizeof(randFile))) // Gets the name of a default seed file.
+ {
+ RAND_load_file(randFile, 1024);
+ }
+ string randFiles = properties->getProperty("IceSSL.Random");
+ if(!randFiles.empty())
+ {
+ vector<string> files;
+#ifdef _WIN32
+ const string sep = ";";
+#else
+ const string sep = ":";
+#endif
+ string defaultDir = properties->getProperty("IceSSL.DefaultDir");
+ if(!IceUtilInternal::splitString(randFiles, sep, files))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: invalid value for IceSSL.Random:\n" + randFiles;
+ throw ex;
+ }
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ {
+ string file = *p;
+ if(!checkPath(file, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: entropy data file not found:\n" + file;
+ throw ex;
+ }
+ if(!RAND_load_file(file.c_str(), 1024))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unable to load entropy data from " + file;
+ throw ex;
+ }
+ }
+ }
+#ifndef _WIN32
+ //
+ // The Entropy Gathering Daemon (EGD) is not available on Windows.
+ // The file should be a Unix domain socket for the daemon.
+ //
+ string entropyDaemon = properties->getProperty("IceSSL.EntropyDaemon");
+ if(!entropyDaemon.empty())
+ {
+ if(RAND_egd(entropyDaemon.c_str()) <= 0)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: EGD failure using file " + entropyDaemon;
+ throw ex;
+ }
+ }
+#endif
+ if(!RAND_status())
+ {
+ communicator->getLogger()->warning("IceSSL: insufficient data to initialize PRNG");
+ }
+ }
+
_facade = IceInternal::getProtocolPluginFacade(communicator);
_securityTraceLevel = communicator->getProperties()->getPropertyAsInt("IceSSL.Trace.Security");
_securityTraceCategory = "Security";
@@ -102,6 +240,27 @@ IceSSL::Instance::Instance(const CommunicatorPtr& communicator) :
__setNoDelete(false);
}
+IceSSL::Instance::~Instance()
+{
+ //
+ // Clean up OpenSSL resources.
+ //
+ IceUtil::StaticMutex::Lock sync(staticMutex);
+
+ if(--instanceCount == 0)
+ {
+ CRYPTO_set_locking_callback(0);
+ CRYPTO_set_id_callback(0);
+ delete[] locks;
+ locks = 0;
+
+ CRYPTO_cleanup_all_ex_data();
+ RAND_cleanup();
+ ERR_free_strings();
+ EVP_cleanup();
+ }
+}
+
void
IceSSL::Instance::initialize()
{