Backout 5dde4d86be49
authorHonza Bambas <honzab.moz@firemni.cz>
Fri, 27 Feb 2009 16:20:31 +0100
changeset 25599 95f3ee836b916322d515705907ec7f17dc0ca5f5
parent 25597 5dde4d86be49af09865236161c33cd064a046bb0
child 25600 b87f492915a8f8b462f158aacdbacc28b9a34a6e
push id5638
push userhonzab.moz@firemni.cz
push dateFri, 27 Feb 2009 15:23:28 +0000
treeherdermozilla-central@b87f492915a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.2a1pre
backs out5dde4d86be49af09865236161c33cd064a046bb0
Backout 5dde4d86be49
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSComponent.h
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsNSSIOLayer.h
security/manager/ssl/src/nsNSSModule.cpp
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -270,80 +270,18 @@ nsTokenEventRunnable::Run()
   nsresult rv;
   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
   if (NS_FAILED(rv))
     return rv;
 
   return nssComponent->DispatchEvent(mType, mTokenName);
 }
 
-// We must ensure that the nsNSSComponent has been loaded before
-// creating any other components.
-PRBool EnsureNSSInitialized(EnsureNSSOperator op)
-{
-  static PRBool loading = PR_FALSE;
-  static PRBool haveLoaded = PR_FALSE;
-
-  switch (op)
-  {
-    // In following 4 cases we are protected by monitor of XPCOM component
-    // manager - we are inside of do_GetService call for nss component, so it is
-    // safe to move with the flags here.
-  case nssLoading:
-    if (loading)
-      return PR_FALSE; // We are reentered during nss component creation
-    loading = PR_TRUE;
-    return PR_TRUE;
-
-  case nssInitSucceeded:
-    NS_ASSERTION(loading, "Bad call to EnsureNSSInitialized(nssInitSucceeded)");
-    loading = PR_FALSE;
-    haveLoaded = PR_TRUE;
-    return PR_TRUE;
-
-  case nssInitFailed:
-    NS_ASSERTION(loading, "Bad call to EnsureNSSInitialized(nssInitFailed)");
-    loading = PR_FALSE;
-    // no break
-
-  case nssShutdown:
-    haveLoaded = PR_FALSE;
-    return PR_FALSE;
-
-    // In this case we are called from a component to ensure nss initilization.
-    // If the component has not yet been loaded and is not currently loading
-    // call do_GetService for nss component to ensure it.
-  case nssEnsure:
-    if (haveLoaded)
-      return PR_TRUE; // OK, nss component is already up
-    
-    if (loading)
-      return PR_FALSE; // We are reentered during nss component creation
-
-    {
-    nsCOMPtr<nsISupports> nssComponent 
-      = do_GetService(PSM_COMPONENT_CONTRACTID);
-
-    // Nss component failed to initialize, inform the caller of that fact.
-    // Flags are appropriately set by component constructor itself.
-    if (!nssComponent)
-      return PR_FALSE;
-
-    return PR_TRUE;
-    }
-
-  default:
-    NS_ASSERTION(PR_FALSE, "Bad operator to EnsureNSSInitialized");
-    return PR_FALSE;
-  }
-}
-
 nsNSSComponent::nsNSSComponent()
-  :mNSSInitialized(PR_FALSE), mThreadList(nsnull),
-   mSSLThread(NULL), mCertVerificationThread(NULL)
+  :mNSSInitialized(PR_FALSE), mThreadList(nsnull)
 {
   mutex = PR_NewLock();
   
 #ifdef PR_LOGGING
   if (!gPIPNSSLog)
     gPIPNSSLog = PR_NewLogModule("pipnss");
 #endif
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::ctor\n"));
@@ -353,21 +291,29 @@ nsNSSComponent::nsNSSComponent()
   mTimer = nsnull;
   mCrlTimerLock = nsnull;
   mObserversRegistered = PR_FALSE;
 
   // In order to keep startup time lower, we delay loading and 
   // registering all identity data until first needed.
   memset(&mIdentityInfoCallOnce, 0, sizeof(PRCallOnceType));
 
+  nsSSLIOLayerHelpers::Init();
+  
   NS_ASSERTION( (0 == mInstanceCount), "nsNSSComponent is a singleton, but instantiated multiple times!");
   ++mInstanceCount;
   hashTableCerts = nsnull;
   mShutdownObjectList = nsNSSShutDownList::construct();
   mIsNetworkDown = PR_FALSE;
+  mSSLThread = new nsSSLThread();
+  if (mSSLThread)
+    mSSLThread->startThread();
+  mCertVerificationThread = new nsCertVerificationThread();
+  if (mCertVerificationThread)
+    mCertVerificationThread->startThread();
 }
 
 nsNSSComponent::~nsNSSComponent()
 {
   if (mSSLThread)
   {
     mSSLThread->requestExit();
     delete mSSLThread;
@@ -406,20 +352,16 @@ nsNSSComponent::~nsNSSComponent()
   --mInstanceCount;
   delete mShutdownObjectList;
 
   if (mutex) {
     PR_DestroyLock(mutex);
     mutex = nsnull;
   }
 
-  // We are being freed, drop the haveLoaded flag to re-enable
-  // potential nss initialization later.
-  EnsureNSSInitialized(nssShutdown);
-
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor finished\n"));
 }
 
 NS_IMETHODIMP
 nsNSSComponent::PostEvent(const nsAString &eventType, 
                                                   const nsAString &tokenName)
 {
   nsCOMPtr<nsIRunnable> runnable = 
@@ -1523,16 +1465,19 @@ nsNSSComponent::InitializeNSS(PRBool sho
 
     if (mNSSInitialized) {
       PR_ASSERT(!"Trying to initialize NSS twice"); // We should never try to 
                                                     // initialize NSS more than
                                                     // once in a process.
       return NS_ERROR_FAILURE;
     }
     
+    hashTableCerts = PL_NewHashTable( 0, certHashtable_keyHash, certHashtable_keyCompare, 
+      certHashtable_valueCompare, 0, 0 );
+
     nsresult rv;
     nsCAutoString profileStr;
     nsCOMPtr<nsIFile> profilePath;
 
     rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
                                 getter_AddRefs(profilePath));
     if (NS_FAILED(rv)) {
       PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to get profile directory\n"));
@@ -1571,19 +1516,16 @@ nsNSSComponent::InitializeNSS(PRBool sho
     if (NS_FAILED(rv))
       return rv;
   #endif
 
     rv = profilePath->GetNativePath(profileStr);
     if (NS_FAILED(rv)) 
       return rv;
 
-    hashTableCerts = PL_NewHashTable( 0, certHashtable_keyHash, certHashtable_keyCompare, 
-      certHashtable_valueCompare, 0, 0 );
-
   #if defined(XP_MACOSX)
     // function may modify the parameters
     // ignore return code from conversion, we continue anyway
     TryCFM2MachOMigration(cfmSecurityPath, profilePath);
   #endif
 
     PRBool supress_warning_preference = PR_FALSE;
     rv = mPrefBranch->GetBoolPref("security.suppress_nss_rw_impossible_warning", &supress_warning_preference);
@@ -1763,17 +1705,18 @@ nsNSSComponent::Init()
 {
   // No mutex protection.
   // Assume Init happens before any concurrency on "this" can start.
 
   nsresult rv = NS_OK;
 
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Beginning NSS initialization\n"));
 
-  if (!mutex || !mShutdownObjectList)
+  if (!mutex || !mShutdownObjectList || 
+      !mSSLThread || !mCertVerificationThread)
   {
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS init, out of memory in constructor\n"));
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   rv = InitializePIPNSSBundle();
   if (NS_FAILED(rv)) {
     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to create pipnss bundle.\n"));
@@ -1799,40 +1742,19 @@ nsNSSComponent::Init()
   }
 
   // Do that before NSS init, to make sure we won't get unloaded.
   RegisterObservers();
 
   rv = InitializeNSS(PR_TRUE); // ok to show a warning box on failure
   if (NS_FAILED(rv)) {
     PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("Unable to Initialize NSS.\n"));
-
-    DeregisterObservers();
-    mPIPNSSBundle = nsnull;
     return rv;
   }
 
-  nsSSLIOLayerHelpers::Init();
-  
-  mSSLThread = new nsSSLThread();
-  if (mSSLThread)
-    mSSLThread->startThread();
-  mCertVerificationThread = new nsCertVerificationThread();
-  if (mCertVerificationThread)
-    mCertVerificationThread->startThread();
-
-  if (!mSSLThread || !mCertVerificationThread)
-  {
-    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS init, could not create threads\n"));
-
-    DeregisterObservers();
-    mPIPNSSBundle = nsnull;
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
   InitializeCRLUpdateTimer();
   RegisterPSMContentListener();
 
   nsCOMPtr<nsIEntropyCollector> ec
       = do_GetService(NS_ENTROPYCOLLECTOR_CONTRACTID);
 
   nsCOMPtr<nsIBufEntropyCollector> bec;
 
@@ -2259,41 +2181,16 @@ nsNSSComponent::RegisterObservers()
     observerService->AddObserver(this, PROFILE_BEFORE_CHANGE_TOPIC, PR_FALSE);
     observerService->AddObserver(this, PROFILE_AFTER_CHANGE_TOPIC, PR_FALSE);
     observerService->AddObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC, PR_FALSE);
     observerService->AddObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC, PR_FALSE);
   }
   return NS_OK;
 }
 
-nsresult
-nsNSSComponent::DeregisterObservers()
-{
-  if (!mObserversRegistered)
-    return NS_OK;
-
-  nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));
-  NS_ASSERTION(observerService, "could not get observer service");
-  if (observerService) {
-    mObserversRegistered = PR_FALSE;
-    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent: removing observers\n"));
-
-    observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
-
-    observerService->RemoveObserver(this, PROFILE_APPROVE_CHANGE_TOPIC);
-    observerService->RemoveObserver(this, PROFILE_CHANGE_TEARDOWN_TOPIC);
-    observerService->RemoveObserver(this, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC);
-    observerService->RemoveObserver(this, PROFILE_BEFORE_CHANGE_TOPIC);
-    observerService->RemoveObserver(this, PROFILE_AFTER_CHANGE_TOPIC);
-    observerService->RemoveObserver(this, PROFILE_CHANGE_NET_TEARDOWN_TOPIC);
-    observerService->RemoveObserver(this, PROFILE_CHANGE_NET_RESTORE_TOPIC);
-  }
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 nsNSSComponent::RememberCert(CERTCertificate *cert)
 {
   nsNSSShutDownPreventionLock locker;
 
   // Must not interfere with init / shutdown / profile switch.
 
   nsAutoLock lock(mutex);
--- a/security/manager/ssl/src/nsNSSComponent.h
+++ b/security/manager/ssl/src/nsNSSComponent.h
@@ -88,27 +88,16 @@
 #define NS_PSMCONTENTLISTEN_CONTRACTID "@mozilla.org/security/psmdownload;1"
 
 #define NS_CRYPTO_HASH_CLASSNAME "Mozilla Crypto Hash Function Component"
 #define NS_CRYPTO_HASH_CID {0x36a1d3b3, 0xd886, 0x4317, {0x96, 0xff, 0x87, 0xb0, 0x00, 0x5c, 0xfe, 0xf7}}
 
 #define NS_CRYPTO_HMAC_CLASSNAME "Mozilla Crypto HMAC Function Component"
 #define NS_CRYPTO_HMAC_CID {0xa496d0a2, 0xdff7, 0x4e23, {0xbd, 0x65, 0x1c, 0xa7, 0x42, 0xfa, 0x17, 0x8a}}
 
-enum EnsureNSSOperator
-{
-  nssLoading = 0,
-  nssInitSucceeded = 1,
-  nssInitFailed = 2,
-  nssShutdown = 3,
-  nssEnsure = 4
-};
-
-extern PRBool EnsureNSSInitialized(EnsureNSSOperator op);
-
 //--------------------------------------------
 // Now we need a content listener to register 
 //--------------------------------------------
 class PSMContentDownloader : public nsIStreamListener
 {
 public:
   PSMContentDownloader() {NS_ASSERTION(PR_FALSE, "don't use this constructor."); }
   PSMContentDownloader(PRUint32 type);
@@ -293,17 +282,16 @@ private:
   void UnloadLoadableRoots();
   void LaunchSmartCardThreads();
   void ShutdownSmartCardThreads();
   void CleanupIdentityInfo();
   nsresult InitializePIPNSSBundle();
   nsresult ConfigureInternalPKCS11Token();
   nsresult RegisterPSMContentListener();
   nsresult RegisterObservers();
-  nsresult DeregisterObservers();
   nsresult DownloadCrlSilently();
   nsresult PostCRLImportEvent(const nsCSubstring &urlString, nsIStreamListener *psmDownloader);
   nsresult getParamsForNextCrlToDownload(nsAutoString *url, PRTime *time, nsAutoString *key);
   nsresult DispatchEventToWindow(nsIDOMWindow *domWin, const nsAString &eventType, const nsAString &token);
 
   // Methods that we use to handle the profile change notifications (and to
   // synthesize a full profile change when we're just doing a profile startup):
   void DoProfileApproveChange(nsISupports* aSubject);
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -772,20 +772,18 @@ void nsSSLIOLayerHelpers::Cleanup()
   if (mTLSIntolerantSites) {
     delete mTLSIntolerantSites;
     mTLSIntolerantSites = nsnull;
   }
 
   if (mSharedPollableEvent)
     PR_DestroyPollableEvent(mSharedPollableEvent);
 
-  if (mutex) {
+  if (mutex)
     PR_DestroyLock(mutex);
-    mutex = nsnull;
-  }
 }
 
 static nsresult
 getErrorMessage(PRInt32 err, 
                 const nsString &host,
                 PRInt32 port,
                 PRBool externalErrorReporting,
                 nsINSSComponent *component,
@@ -1768,17 +1766,16 @@ nsSSLIOLayerPoll(PRFileDesc *fd, PRInt16
   }
 
   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
 
   return nsSSLThread::requestPoll(socketInfo, in_flags, out_flags);
 }
 
-PRBool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = PR_FALSE;
 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
 PRLock *nsSSLIOLayerHelpers::mutex = nsnull;
 nsCStringHashSet *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
 PRFileDesc *nsSSLIOLayerHelpers::mSharedPollableEvent = nsnull;
 nsNSSSocketInfo *nsSSLIOLayerHelpers::mSocketOwningPollableEvent = nsnull;
 PRBool nsSSLIOLayerHelpers::mPollableEventCurrentlySet = PR_FALSE;
 
@@ -1930,53 +1927,50 @@ static PRStatus PR_CALLBACK PSMConnectco
   nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
   NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
 
   return nsSSLThread::requestConnectcontinue(socketInfo, out_flags);
 }
 
 nsresult nsSSLIOLayerHelpers::Init()
 {
-  if (!nsSSLIOLayerInitialized) {
-    nsSSLIOLayerInitialized = PR_TRUE;
-    nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
-    nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
-
-    nsSSLIOLayerMethods.available = (PRAvailableFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.available64 = (PRAvailable64FN)_PSM_InvalidInt64;
-    nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
-    nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
-    nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
-    nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
-    nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
-    nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
-    nsSSLIOLayerMethods.listen = (PRListenFN)_PSM_InvalidStatus;
-    nsSSLIOLayerMethods.shutdown = (PRShutdownFN)_PSM_InvalidStatus;
-    nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.sendto = (PRSendtoFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN)_PSM_InvalidInt;
-    nsSSLIOLayerMethods.sendfile = (PRSendfileFN)_PSM_InvalidInt;
-
-    nsSSLIOLayerMethods.getsockname = PSMGetsockname;
-    nsSSLIOLayerMethods.getpeername = PSMGetpeername;
-    nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
-    nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
-    nsSSLIOLayerMethods.recv = PSMRecv;
-    nsSSLIOLayerMethods.send = PSMSend;
-    nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
-
-    nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
-    nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
-    nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
-    nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
-    nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
-  }
+  nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
+  nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
+
+  nsSSLIOLayerMethods.available = (PRAvailableFN)_PSM_InvalidInt;
+  nsSSLIOLayerMethods.available64 = (PRAvailable64FN)_PSM_InvalidInt64;
+  nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
+  nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
+  nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
+  nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
+  nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
+  nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
+  nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
+  nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
+  nsSSLIOLayerMethods.listen = (PRListenFN)_PSM_InvalidStatus;
+  nsSSLIOLayerMethods.shutdown = (PRShutdownFN)_PSM_InvalidStatus;
+  nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN)_PSM_InvalidInt;
+  nsSSLIOLayerMethods.sendto = (PRSendtoFN)_PSM_InvalidInt;
+  nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN)_PSM_InvalidInt;
+  nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN)_PSM_InvalidInt;
+  nsSSLIOLayerMethods.sendfile = (PRSendfileFN)_PSM_InvalidInt;
+
+  nsSSLIOLayerMethods.getsockname = PSMGetsockname;
+  nsSSLIOLayerMethods.getpeername = PSMGetpeername;
+  nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
+  nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
+  nsSSLIOLayerMethods.recv = PSMRecv;
+  nsSSLIOLayerMethods.send = PSMSend;
+  nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
+
+  nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
+  nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
+  nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
+  nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
+  nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
 
   mutex = PR_NewLock();
   if (!mutex)
     return NS_ERROR_OUT_OF_MEMORY;
 
   mSharedPollableEvent = PR_NewPollableEvent();
 
   // if we can not get a pollable event, we'll have to do busy waiting
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -243,17 +243,16 @@ friend class nsSSLThread;
 class nsCStringHashSet;
 
 class nsSSLIOLayerHelpers
 {
 public:
   static nsresult Init();
   static void Cleanup();
 
-  static PRBool nsSSLIOLayerInitialized;
   static PRDescIdentity nsSSLIOLayerIdentity;
   static PRIOMethods nsSSLIOLayerMethods;
 
   static PRLock *mutex;
   static nsCStringHashSet *mTLSIntolerantSites;
   
   static PRBool rememberPossibleTLSProblemSite(PRFileDesc* fd, nsNSSSocketInfo *socketInfo);
 
--- a/security/manager/ssl/src/nsNSSModule.cpp
+++ b/security/manager/ssl/src/nsNSSModule.cpp
@@ -74,115 +74,97 @@
 #include "nsKeyModule.h"
 #include "nsDataSignatureVerifier.h"
 #include "nsCertOverrideService.h"
 #include "nsRandomGenerator.h"
 #include "nsRecentBadCerts.h"
 #include "nsSSLStatus.h"
 #include "nsNSSIOLayer.h"
 
+// We must ensure that the nsNSSComponent has been loaded before
+// creating any other components.
+static void EnsureNSSInitialized(PRBool triggeredByNSSComponent)
+{
+  static PRBool haveLoaded = PR_FALSE;
+  if (haveLoaded)
+    return;
+
+  haveLoaded = PR_TRUE;
+  
+  if (triggeredByNSSComponent) {
+    // We must prevent a recursion, as nsNSSComponent creates
+    // additional instances
+    return;
+  }
+  
+  nsCOMPtr<nsISupports> nssComponent 
+    = do_GetService(PSM_COMPONENT_CONTRACTID);
+}
+
 // These two macros are ripped off from nsIGenericFactory.h and slightly
 // modified.
 #define NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(triggeredByNSSComponent,           \
                                                       _InstanceClass)         \
 static NS_IMETHODIMP                                                          \
 _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID,               \
                             void **aResult)                                   \
 {                                                                             \
     nsresult rv;                                                              \
     _InstanceClass * inst;                                                    \
                                                                               \
+    EnsureNSSInitialized(triggeredByNSSComponent);                            \
+                                                                              \
     *aResult = NULL;                                                          \
     if (NULL != aOuter) {                                                     \
         rv = NS_ERROR_NO_AGGREGATION;                                         \
         return rv;                                                            \
     }                                                                         \
                                                                               \
-    if (triggeredByNSSComponent)                                              \
-    {                                                                         \
-        if (!EnsureNSSInitialized(nssLoading))                                \
-            return NS_ERROR_FAILURE;                                          \
-    }                                                                         \
-    else                                                                      \
-    {                                                                         \
-        if (!EnsureNSSInitialized(nssEnsure))                                 \
-            return NS_ERROR_FAILURE;                                          \
-    }                                                                         \
-                                                                              \
     NS_NEWXPCOM(inst, _InstanceClass);                                        \
     if (NULL == inst) {                                                       \
-        if (triggeredByNSSComponent)                                          \
-            EnsureNSSInitialized(nssInitFailed);                              \
         rv = NS_ERROR_OUT_OF_MEMORY;                                          \
         return rv;                                                            \
     }                                                                         \
     NS_ADDREF(inst);                                                          \
     rv = inst->QueryInterface(aIID, aResult);                                 \
     NS_RELEASE(inst);                                                         \
                                                                               \
-    if (triggeredByNSSComponent)                                              \
-    {                                                                         \
-        if (NS_SUCCEEDED(rv))                                                 \
-            EnsureNSSInitialized(nssInitSucceeded);                           \
-        else                                                                  \
-            EnsureNSSInitialized(nssInitFailed);                              \
-    }                                                                         \
-                                                                              \
     return rv;                                                                \
 }                                                                             \
 
  
 #define NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(triggeredByNSSComponent,      \
                                                 _InstanceClass, _InitMethod)  \
 static NS_IMETHODIMP                                                          \
 _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID,               \
                             void **aResult)                                   \
 {                                                                             \
     nsresult rv;                                                              \
     _InstanceClass * inst;                                                    \
                                                                               \
+    EnsureNSSInitialized(triggeredByNSSComponent);                            \
+                                                                              \
     *aResult = NULL;                                                          \
     if (NULL != aOuter) {                                                     \
         rv = NS_ERROR_NO_AGGREGATION;                                         \
         return rv;                                                            \
     }                                                                         \
                                                                               \
-    if (triggeredByNSSComponent)                                              \
-    {                                                                         \
-        if (!EnsureNSSInitialized(nssLoading))                                \
-            return NS_ERROR_FAILURE;                                          \
-    }                                                                         \
-    else                                                                      \
-    {                                                                         \
-        if (!EnsureNSSInitialized(nssEnsure))                                 \
-            return NS_ERROR_FAILURE;                                          \
-    }                                                                         \
-                                                                              \
     NS_NEWXPCOM(inst, _InstanceClass);                                        \
     if (NULL == inst) {                                                       \
-        if (triggeredByNSSComponent)                                          \
-            EnsureNSSInitialized(nssInitFailed);                              \
         rv = NS_ERROR_OUT_OF_MEMORY;                                          \
         return rv;                                                            \
     }                                                                         \
     NS_ADDREF(inst);                                                          \
     rv = inst->_InitMethod();                                                 \
     if(NS_SUCCEEDED(rv)) {                                                    \
         rv = inst->QueryInterface(aIID, aResult);                             \
     }                                                                         \
     NS_RELEASE(inst);                                                         \
                                                                               \
-    if (triggeredByNSSComponent)                                              \
-    {                                                                         \
-        if (NS_SUCCEEDED(rv))                                                 \
-            EnsureNSSInitialized(nssInitSucceeded);                           \
-        else                                                                  \
-            EnsureNSSInitialized(nssInitFailed);                              \
-    }                                                                         \
-                                                                              \
     return rv;                                                                \
 }                                                                             \
 
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(PR_TRUE, nsNSSComponent, Init)
 
 // Use the special factory constructor for everything this module implements,
 // because all code could potentially require the NSS library.
 // Our factory constructor takes an additional boolean parameter.