Bug 470274 - Firefox cannot visit any websites when waking from sleep. r+sr=bz
authorDave Camp <dcamp@mozilla.com>
Sun, 22 Feb 2009 11:09:09 -0800
changeset 25375 cd7eadaaccc2ba8d14b41e94ca721e1c0d7e6d8f
parent 25374 9f3f8b980b7a2db22664f63866434ff8abc2027a
child 25376 ad173cf77112b6294dda1acb63e817f798eab5e0
push idunknown
push userunknown
push dateunknown
bugs470274
milestone1.9.2a1pre
Bug 470274 - Firefox cannot visit any websites when waking from sleep. r+sr=bz
netwerk/base/src/nsIOService.cpp
netwerk/base/src/nsIOService.h
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -160,16 +160,18 @@ static const char kProfileChangeNetResto
 // Necko buffer cache
 nsIMemory* nsIOService::gBufferCache = nsnull;
 
 ////////////////////////////////////////////////////////////////////////////////
 
 nsIOService::nsIOService()
     : mOffline(PR_FALSE)
     , mOfflineForProfileChange(PR_FALSE)
+    , mSettingOffline(PR_FALSE)
+    , mSetOfflineValue(PR_FALSE)
     , mManageOfflineStatus(PR_TRUE)
     , mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY)
     , mContentSniffers(NS_CONTENT_SNIFFER_CATEGORY)
 {
     // Get the allocator ready
     if (!gBufferCache)
     {
         nsresult rv = NS_OK;
@@ -610,71 +612,88 @@ nsIOService::GetOffline(PRBool *offline)
 {
     *offline = mOffline;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsIOService::SetOffline(PRBool offline)
 {
+    // SetOffline() may re-enter while it's shutting down services.
+    // If that happens, save the most recent value and it will be
+    // processed when the first SetOffline() call is done bringing
+    // down the service.
+    mSetOfflineValue = offline;
+    if (mSettingOffline) {
+        return NS_OK;
+    }
+    mSettingOffline = PR_TRUE;
+
     nsCOMPtr<nsIObserverService> observerService =
         do_GetService("@mozilla.org/observer-service;1");
-    
-    nsresult rv;
-    if (offline && !mOffline) {
-        NS_NAMED_LITERAL_STRING(offlineString, NS_IOSERVICE_OFFLINE);
-        mOffline = PR_TRUE; // indicate we're trying to shutdown
+
+    while (mSetOfflineValue != mOffline) {
+        offline = mSetOfflineValue;
+
+        nsresult rv;
+        if (offline && !mOffline) {
+            NS_NAMED_LITERAL_STRING(offlineString, NS_IOSERVICE_OFFLINE);
+            mOffline = PR_TRUE; // indicate we're trying to shutdown
 
-        // don't care if notification fails
-        // this allows users to attempt a little cleanup before dns and socket transport are shut down.
-        if (observerService)
-            observerService->NotifyObservers(static_cast<nsIIOService *>(this),
-                                             NS_IOSERVICE_GOING_OFFLINE_TOPIC,
-                                             offlineString.get());
+            // don't care if notification fails
+            // this allows users to attempt a little cleanup before dns and socket transport are shut down.
+            if (observerService)
+                observerService->NotifyObservers(static_cast<nsIIOService *>(this),
+                                                 NS_IOSERVICE_GOING_OFFLINE_TOPIC,
+                                                 offlineString.get());
 
-        // be sure to try and shutdown both (even if the first fails)...
-        // shutdown dns service first, because it has callbacks for socket transport
-        if (mDNSService) {
-            rv = mDNSService->Shutdown();
-            NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service shutdown failed");
-        }
-        if (mSocketTransportService) {
-            rv = mSocketTransportService->Shutdown();
-            NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed");
-        }
+            // be sure to try and shutdown both (even if the first fails)...
+            // shutdown dns service first, because it has callbacks for socket transport
+            if (mDNSService) {
+                rv = mDNSService->Shutdown();
+                NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service shutdown failed");
+            }
+            if (mSocketTransportService) {
+                rv = mSocketTransportService->Shutdown();
+                NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed");
+            }
 
-        // don't care if notification fails
-        if (observerService)
-            observerService->NotifyObservers(static_cast<nsIIOService *>(this),
-                                             NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
-                                             offlineString.get());
-    }
-    else if (!offline && mOffline) {
-        // go online
-        if (mDNSService) {
-            rv = mDNSService->Init();
-            NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed");
+            // don't care if notification fails
+            if (observerService)
+                observerService->NotifyObservers(static_cast<nsIIOService *>(this),
+                                                 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
+                                                 offlineString.get());
         }
-        if (mSocketTransportService) {
-            rv = mSocketTransportService->Init();
-            NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed");
+        else if (!offline && mOffline) {
+            // go online
+            if (mDNSService) {
+                rv = mDNSService->Init();
+                NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed");
+            }
+            if (mSocketTransportService) {
+                rv = mSocketTransportService->Init();
+                NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service init failed");
+            }
+            mOffline = PR_FALSE;    // indicate success only AFTER we've
+                                    // brought up the services
+
+            // trigger a PAC reload when we come back online
+            if (mProxyService)
+                mProxyService->ReloadPAC();
+
+            // don't care if notification fails
+            if (observerService)
+                observerService->NotifyObservers(static_cast<nsIIOService *>(this),
+                                                 NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
+                                                 NS_LITERAL_STRING(NS_IOSERVICE_ONLINE).get());
         }
-        mOffline = PR_FALSE;    // indicate success only AFTER we've
-                                // brought up the services
-         
-        // trigger a PAC reload when we come back online
-        if (mProxyService)
-            mProxyService->ReloadPAC();
- 
-        // don't care if notification fails
-        if (observerService)
-            observerService->NotifyObservers(static_cast<nsIIOService *>(this),
-                                             NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
-                                             NS_LITERAL_STRING(NS_IOSERVICE_ONLINE).get());
     }
+
+    mSettingOffline = PR_FALSE;
+
     return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsIOService::AllowPort(PRInt32 inPort, const char *scheme, PRBool *_retval)
 {
     PRInt16 port = inPort;
--- a/netwerk/base/src/nsIOService.h
+++ b/netwerk/base/src/nsIOService.h
@@ -129,16 +129,22 @@ private:
     NS_HIDDEN_(void) PrefsChanged(nsIPrefBranch *prefs, const char *pref = nsnull);
     NS_HIDDEN_(void) GetPrefBranch(nsIPrefBranch2 **);
     NS_HIDDEN_(void) ParsePortList(nsIPrefBranch *prefBranch, const char *pref, PRBool remove);
 
 private:
     PRPackedBool                         mOffline;
     PRPackedBool                         mOfflineForProfileChange;
     PRPackedBool                         mManageOfflineStatus;
+
+    // Used to handle SetOffline() reentrancy.  See the comment in
+    // SetOffline() for more details.
+    PRPackedBool                         mSettingOffline;
+    PRPackedBool                         mSetOfflineValue;
+
     nsCOMPtr<nsPISocketTransportService> mSocketTransportService;
     nsCOMPtr<nsPIDNSService>             mDNSService;
     nsCOMPtr<nsIProtocolProxyService2>   mProxyService;
     nsCOMPtr<nsINetworkLinkService>      mNetworkLinkService;
     
     // Cached protocol handlers
     nsWeakPtr                            mWeakHandler[NS_N(gScheme)];