security/manager/ssl/src/nsNSSShutDown.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "nsNSSShutDown.h"
     6 #include "nsCOMPtr.h"
     8 using namespace mozilla;
    10 #ifdef PR_LOGGING
    11 extern PRLogModuleInfo* gPIPNSSLog;
    12 #endif
    14 struct ObjectHashEntry : PLDHashEntryHdr {
    15   nsNSSShutDownObject *obj;
    16 };
    18 static bool
    19 ObjectSetMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
    20                          const void *key)
    21 {
    22   const ObjectHashEntry *entry = static_cast<const ObjectHashEntry*>(hdr);
    23   return entry->obj == static_cast<const nsNSSShutDownObject*>(key);
    24 }
    26 static bool
    27 ObjectSetInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
    28                      const void *key)
    29 {
    30   ObjectHashEntry *entry = static_cast<ObjectHashEntry*>(hdr);
    31   entry->obj = const_cast<nsNSSShutDownObject*>(static_cast<const nsNSSShutDownObject*>(key));
    32   return true;
    33 }
    35 static const PLDHashTableOps gSetOps = {
    36   PL_DHashAllocTable,
    37   PL_DHashFreeTable,
    38   PL_DHashVoidPtrKeyStub,
    39   ObjectSetMatchEntry,
    40   PL_DHashMoveEntryStub,
    41   PL_DHashClearEntryStub,
    42   PL_DHashFinalizeStub,
    43   ObjectSetInitEntry
    44 };
    46 nsNSSShutDownList *nsNSSShutDownList::singleton = nullptr;
    48 nsNSSShutDownList::nsNSSShutDownList()
    49 :mListLock("nsNSSShutDownList.mListLock")
    50 {
    51   mActiveSSLSockets = 0;
    52   mPK11LogoutCancelObjects.ops = nullptr;
    53   mObjects.ops = nullptr;
    54   PL_DHashTableInit(&mObjects, &gSetOps, nullptr,
    55                     sizeof(ObjectHashEntry), 16);
    56   PL_DHashTableInit(&mPK11LogoutCancelObjects, &gSetOps, nullptr,
    57                     sizeof(ObjectHashEntry), 16);
    58 }
    60 nsNSSShutDownList::~nsNSSShutDownList()
    61 {
    62   if (mObjects.ops) {
    63     PL_DHashTableFinish(&mObjects);
    64     mObjects.ops = nullptr;
    65   }
    66   if (mPK11LogoutCancelObjects.ops) {
    67     PL_DHashTableFinish(&mPK11LogoutCancelObjects);
    68     mPK11LogoutCancelObjects.ops = nullptr;
    69   }
    70   PR_ASSERT(this == singleton);
    71   singleton = nullptr;
    72 }
    74 void nsNSSShutDownList::remember(nsNSSShutDownObject *o)
    75 {
    76   if (!singleton)
    77     return;
    79   PR_ASSERT(o);
    80   MutexAutoLock lock(singleton->mListLock);
    81     PL_DHashTableOperate(&singleton->mObjects, o, PL_DHASH_ADD);
    82 }
    84 void nsNSSShutDownList::forget(nsNSSShutDownObject *o)
    85 {
    86   if (!singleton)
    87     return;
    89   PR_ASSERT(o);
    90   MutexAutoLock lock(singleton->mListLock);
    91   PL_DHashTableOperate(&singleton->mObjects, o, PL_DHASH_REMOVE);
    92 }
    94 void nsNSSShutDownList::remember(nsOnPK11LogoutCancelObject *o)
    95 {
    96   if (!singleton)
    97     return;
    99   PR_ASSERT(o);
   100   MutexAutoLock lock(singleton->mListLock);
   101   PL_DHashTableOperate(&singleton->mPK11LogoutCancelObjects, o, PL_DHASH_ADD);
   102 }
   104 void nsNSSShutDownList::forget(nsOnPK11LogoutCancelObject *o)
   105 {
   106   if (!singleton)
   107     return;
   109   PR_ASSERT(o);
   110   MutexAutoLock lock(singleton->mListLock);
   111   PL_DHashTableOperate(&singleton->mPK11LogoutCancelObjects, o, PL_DHASH_REMOVE);
   112 }
   114 void nsNSSShutDownList::trackSSLSocketCreate()
   115 {
   116   if (!singleton)
   117     return;
   119   MutexAutoLock lock(singleton->mListLock);
   120   ++singleton->mActiveSSLSockets;
   121 }
   123 void nsNSSShutDownList::trackSSLSocketClose()
   124 {
   125   if (!singleton)
   126     return;
   128   MutexAutoLock lock(singleton->mListLock);
   129   --singleton->mActiveSSLSockets;
   130 }
   132 bool nsNSSShutDownList::areSSLSocketsActive()
   133 {
   134   if (!singleton) {
   135     // I'd rather prefer to be pessimistic and return true.
   136     // However, maybe we will get called at a time when the singleton
   137     // has already been freed, and returning true would bring up an 
   138     // unnecessary warning.
   139     return false;
   140   }
   142   MutexAutoLock lock(singleton->mListLock);
   143   return (singleton->mActiveSSLSockets > 0);
   144 }
   146 nsresult nsNSSShutDownList::doPK11Logout()
   147 {
   148     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("canceling all open SSL sockets to disallow future IO\n"));
   149   // During our iteration we will set a bunch of PRBools to true.
   150   // Nobody else ever modifies that bool, only we do.
   151   // We only must ensure that our objects do not go away.
   152   // This is guaranteed by holding the list lock.
   154   MutexAutoLock lock(singleton->mListLock);
   155   PL_DHashTableEnumerate(&mPK11LogoutCancelObjects, doPK11LogoutHelper, 0);
   157   return NS_OK;
   158 }
   160 PLDHashOperator
   161 nsNSSShutDownList::doPK11LogoutHelper(PLDHashTable *table, 
   162   PLDHashEntryHdr *hdr, uint32_t number, void *arg)
   163 {
   164   ObjectHashEntry *entry = static_cast<ObjectHashEntry*>(hdr);
   166   nsOnPK11LogoutCancelObject *pklco = 
   167     reinterpret_cast<nsOnPK11LogoutCancelObject*>(entry->obj);
   169   if (pklco) {
   170     pklco->logout();
   171   }
   173   return PL_DHASH_NEXT;
   174 }
   176 bool nsNSSShutDownList::isUIActive()
   177 {
   178   bool canDisallow = mActivityState.ifPossibleDisallowUI(nsNSSActivityState::test_only);
   179   bool bIsUIActive = !canDisallow;
   180   return bIsUIActive;
   181 }
   183 bool nsNSSShutDownList::ifPossibleDisallowUI()
   184 {
   185   bool isNowDisallowed = mActivityState.ifPossibleDisallowUI(nsNSSActivityState::do_it_for_real);
   186   return isNowDisallowed;
   187 }
   189 void nsNSSShutDownList::allowUI()
   190 {
   191   mActivityState.allowUI();
   192 }
   194 nsresult nsNSSShutDownList::evaporateAllNSSResources()
   195 {
   196   if (PR_SUCCESS != mActivityState.restrictActivityToCurrentThread()) {
   197     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("failed to restrict activity to current thread\n"));
   198     return NS_ERROR_FAILURE;
   199   }
   201   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("now evaporating NSS resources\n"));
   202   int removedCount;
   203   do {
   204     MutexAutoLock lock(mListLock);
   205     removedCount = PL_DHashTableEnumerate(&mObjects, evaporateAllNSSResourcesHelper, 0);
   206   } while (removedCount > 0);
   208   mActivityState.releaseCurrentThreadActivityRestriction();
   209   return NS_OK;
   210 }
   212 PLDHashOperator
   213 nsNSSShutDownList::evaporateAllNSSResourcesHelper(PLDHashTable *table, 
   214   PLDHashEntryHdr *hdr, uint32_t number, void *arg)
   215 {
   216   ObjectHashEntry *entry = static_cast<ObjectHashEntry*>(hdr);
   217   {
   218     MutexAutoUnlock unlock(singleton->mListLock);
   219     entry->obj->shutdown(nsNSSShutDownObject::calledFromList);
   220   }
   221   // Never free more than one entry, because other threads might be calling
   222   // us and remove themselves while we are iterating over the list,
   223   // and the behaviour of changing the list while iterating is undefined.
   224   return (PLDHashOperator)(PL_DHASH_STOP | PL_DHASH_REMOVE);
   225 }
   227 nsNSSShutDownList *nsNSSShutDownList::construct()
   228 {
   229   if (singleton) {
   230     // we should never ever be called twice
   231     return nullptr;
   232   }
   234   singleton = new nsNSSShutDownList();
   235   return singleton;
   236 }
   238 nsNSSActivityState::nsNSSActivityState()
   239 :mNSSActivityStateLock("nsNSSActivityState.mNSSActivityStateLock"), 
   240  mNSSActivityChanged(mNSSActivityStateLock,
   241                      "nsNSSActivityState.mNSSActivityStateLock"),
   242  mNSSActivityCounter(0),
   243  mBlockingUICounter(0),
   244  mIsUIForbidden(false),
   245  mNSSRestrictedThread(nullptr)
   246 {
   247 }
   249 nsNSSActivityState::~nsNSSActivityState()
   250 {
   251 }
   253 void nsNSSActivityState::enter()
   254 {
   255   MutexAutoLock lock(mNSSActivityStateLock);
   257   while (mNSSRestrictedThread && mNSSRestrictedThread != PR_GetCurrentThread()) {
   258     mNSSActivityChanged.Wait();
   259   }
   261   ++mNSSActivityCounter;
   262 }
   264 void nsNSSActivityState::leave()
   265 {
   266   MutexAutoLock lock(mNSSActivityStateLock);
   268   --mNSSActivityCounter;
   270   mNSSActivityChanged.NotifyAll();
   271 }
   273 void nsNSSActivityState::enterBlockingUIState()
   274 {
   275   MutexAutoLock lock(mNSSActivityStateLock);
   277   ++mBlockingUICounter;
   278 }
   280 void nsNSSActivityState::leaveBlockingUIState()
   281 {
   282   MutexAutoLock lock(mNSSActivityStateLock);
   284   --mBlockingUICounter;
   285 }
   287 bool nsNSSActivityState::isBlockingUIActive()
   288 {
   289   MutexAutoLock lock(mNSSActivityStateLock);
   290   return (mBlockingUICounter > 0);
   291 }
   293 bool nsNSSActivityState::isUIForbidden()
   294 {
   295   MutexAutoLock lock(mNSSActivityStateLock);
   296   return mIsUIForbidden;
   297 }
   299 bool nsNSSActivityState::ifPossibleDisallowUI(RealOrTesting rot)
   300 {
   301   bool retval = false;
   302   MutexAutoLock lock(mNSSActivityStateLock);
   304   // Checking and disallowing the UI must be done atomically.
   306   if (!mBlockingUICounter) {
   307     // No UI is currently shown, we are able to evaporate.
   308     retval = true;
   309     if (rot == do_it_for_real) {
   310       // Remember to disallow UI.
   311       mIsUIForbidden = true;
   313       // to clear the "forbidden" state,
   314       // one must either call 
   315       // restrictActivityToCurrentThread() + releaseCurrentThreadActivityRestriction()
   316       // or cancel the operation by calling
   317       // unprepareCurrentThreadRestriction()
   318     }
   319   }
   320   return retval;
   321 }
   323 void nsNSSActivityState::allowUI()
   324 {
   325   MutexAutoLock lock(mNSSActivityStateLock);
   327   mIsUIForbidden = false;
   328 }
   330 PRStatus nsNSSActivityState::restrictActivityToCurrentThread()
   331 {
   332   PRStatus retval = PR_FAILURE;
   333   MutexAutoLock lock(mNSSActivityStateLock);
   335   if (!mBlockingUICounter) {
   336     while (0 < mNSSActivityCounter && !mBlockingUICounter) {
   337       mNSSActivityChanged.Wait(PR_TicksPerSecond());
   338     }
   340     if (mBlockingUICounter) {
   341       // This should never happen.
   342       // If we arrive here, our logic is broken.
   343       PR_ASSERT(0);
   344     }
   345     else {
   346       mNSSRestrictedThread = PR_GetCurrentThread();
   347       retval = PR_SUCCESS;
   348     }
   349   }
   351   return retval;
   352 }
   354 void nsNSSActivityState::releaseCurrentThreadActivityRestriction()
   355 {
   356   MutexAutoLock lock(mNSSActivityStateLock);
   358   mNSSRestrictedThread = nullptr;
   359   mIsUIForbidden = false;
   361   mNSSActivityChanged.NotifyAll();
   362 }
   364 nsNSSShutDownPreventionLock::nsNSSShutDownPreventionLock()
   365 {
   366   nsNSSActivityState *state = nsNSSShutDownList::getActivityState();
   367   if (!state)
   368     return;
   370   state->enter();
   371 }
   373 nsNSSShutDownPreventionLock::~nsNSSShutDownPreventionLock()
   374 {
   375   nsNSSActivityState *state = nsNSSShutDownList::getActivityState();
   376   if (!state)
   377     return;
   379   state->leave();
   380 }
   382 nsPSMUITracker::nsPSMUITracker()
   383 {
   384   nsNSSActivityState *state = nsNSSShutDownList::getActivityState();
   385   if (!state)
   386     return;
   388   state->enterBlockingUIState();
   389 }
   391 nsPSMUITracker::~nsPSMUITracker()
   392 {
   393   nsNSSActivityState *state = nsNSSShutDownList::getActivityState();
   394   if (!state)
   395     return;
   397   state->leaveBlockingUIState();
   398 }
   400 bool nsPSMUITracker::isUIForbidden()
   401 {
   402   nsNSSActivityState *state = nsNSSShutDownList::getActivityState();
   403   if (!state)
   404     return false;
   406   return state->isUIForbidden();
   407 }

mercurial