Skip to content

Commit

Permalink
Bug 939318 - Detect network interface changes on windows properly. r=…
Browse files Browse the repository at this point in the history
…mcmanus

Now supports IPv6 as well if a new enough windows version is used.
Which notification function to use is detect at run-time.

Now sends CHANGED event if the online interface(s) are different in any
way since it was previously checked and considered UP. CHANGED is sent
before UP in case both are detected.

nIOService: split up the network event receiver function from the
network status init function and have the event receiver act on the
incoming event.

DNSservice: acts on network changes (flushes the host cache)

HttpHandler: acts on network changes
  • Loading branch information
bagder committed Aug 29, 2014
1 parent 8181432 commit aafcd6d
Show file tree
Hide file tree
Showing 9 changed files with 299 additions and 125 deletions.
7 changes: 6 additions & 1 deletion netwerk/base/public/nsINetworkLinkService.idl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* Network link status monitoring service.
*/
[scriptable, uuid(f7d3be87-7403-4a1e-b89f-2797776e9b08)]
[scriptable, uuid(2deead82-1d29-45f5-8c59-5dbee477cff8)]
interface nsINetworkLinkService : nsISupports
{
/* Link type constants */
Expand Down Expand Up @@ -64,6 +64,11 @@ interface nsINetworkLinkService : nsISupports
* isLinkUp is now false, linkStatusKnown is true.
*/
#define NS_NETWORK_LINK_DATA_DOWN "down"
/**
* isLinkUp is still true, but the network setup is modified.
* linkStatusKnown is true.
*/
#define NS_NETWORK_LINK_DATA_CHANGED "changed"
/**
* linkStatusKnown is now false.
*/
Expand Down
92 changes: 54 additions & 38 deletions netwerk/base/src/nsIOService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ using namespace mozilla;
nsIOService* gIOService = nullptr;
static bool gHasWarnedUploadChannel2;

// A general port blacklist. Connections to these ports will not be allowed unless
// the protocol overrides.
// A general port blacklist. Connections to these ports will not be allowed
// unless the protocol overrides.
//
// TODO: I am sure that there are more ports to be added.
// This cut is based on the classic mozilla codebase
Expand Down Expand Up @@ -265,10 +265,9 @@ nsIOService::InitializeNetworkLinkService()
// so let's cross our fingers!
mManageOfflineStatus = false;
}


if (mManageOfflineStatus)
TrackNetworkLinkStatusForOffline();
OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
else
SetOffline(false);

Expand Down Expand Up @@ -922,7 +921,7 @@ nsIOService::Observe(nsISupports *subject,
if (mOfflineForProfileChange) {
mOfflineForProfileChange = false;
if (!mManageOfflineStatus ||
NS_FAILED(TrackNetworkLinkStatusForOffline())) {
NS_FAILED(OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN))) {
SetOffline(false);
}
}
Expand Down Expand Up @@ -952,11 +951,11 @@ nsIOService::Observe(nsISupports *subject,
mProxyService = nullptr;
}
else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
if (!mOfflineForProfileChange && mManageOfflineStatus) {
TrackNetworkLinkStatusForOffline();
if (!mOfflineForProfileChange) {
OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
}
}

return NS_OK;
}

Expand Down Expand Up @@ -1054,24 +1053,25 @@ nsIOService::NewSimpleNestedURI(nsIURI* aURI, nsIURI** aResult)
}

NS_IMETHODIMP
nsIOService::SetManageOfflineStatus(bool aManage) {
nsIOService::SetManageOfflineStatus(bool aManage)
{
nsresult rv = NS_OK;

// SetManageOfflineStatus must throw when we fail to go from non-managed
// to managed. Usually because there is no link monitoring service
// available. Failure to do this switch is detected by a failure of
// TrackNetworkLinkStatusForOffline(). When there is no network link
// available during call to InitializeNetworkLinkService(), application is
// put to offline mode. And when we change mMangeOfflineStatus to false
// on the next line we get stuck on being offline even though the link
// becomes later available.
// to managed. Usually because there is no link monitoring service
// available. Failure to do this switch is detected by a failure of
// OnNetworkLinkEvent(). When there is no network link available during
// call to InitializeNetworkLinkService(), application is put to offline
// mode. And when we change mMangeOfflineStatus to false on the next line
// we get stuck on being offline even though the link becomes later
// available.
bool wasManaged = mManageOfflineStatus;
mManageOfflineStatus = aManage;

InitializeNetworkLinkService();

if (mManageOfflineStatus && !wasManaged) {
rv = TrackNetworkLinkStatusForOffline();
rv = OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
if (NS_FAILED(rv))
mManageOfflineStatus = false;
}
Expand All @@ -1084,41 +1084,57 @@ nsIOService::GetManageOfflineStatus(bool* aManage) {
return NS_OK;
}

// input argument 'data' is already UTF8'ed
nsresult
nsIOService::TrackNetworkLinkStatusForOffline()
nsIOService::OnNetworkLinkEvent(const char *data)
{
NS_ASSERTION(mManageOfflineStatus,
"Don't call this unless we're managing the offline status");
if (!mNetworkLinkService)
return NS_ERROR_FAILURE;

if (mShutdown)
return NS_ERROR_NOT_AVAILABLE;

// check to make sure this won't collide with Autodial
if (mSocketTransportService) {
bool autodialEnabled = false;
mSocketTransportService->GetAutodialEnabled(&autodialEnabled);
// If autodialing-on-link-down is enabled, check if the OS auto dial
// option is set to always autodial. If so, then we are
// always up for the purposes of offline management.
if (autodialEnabled) {

if (mManageOfflineStatus)
return NS_OK;

if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
// check to make sure this won't collide with Autodial
if (mSocketTransportService) {
bool autodialEnabled = false;
mSocketTransportService->GetAutodialEnabled(&autodialEnabled);
// If autodialing-on-link-down is enabled, check if the OS auto
// dial option is set to always autodial. If so, then we are
// always up for the purposes of offline management.
if (autodialEnabled) {
#if defined(XP_WIN)
// On Windows, we should first check with the OS
// to see if autodial is enabled. If it is
// enabled then we are allowed to manage the
// offline state.
if(nsNativeConnectionHelper::IsAutodialEnabled())
return SetOffline(false);
// On Windows, we should first check with the OS to see if
// autodial is enabled. If it is enabled then we are allowed
// to manage the offline state.
if (nsNativeConnectionHelper::IsAutodialEnabled()) {
return SetOffline(false);
}
#else
return SetOffline(false);
return SetOffline(false);
#endif
}
}
}

bool isUp;
nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp);
NS_ENSURE_SUCCESS(rv, rv);
if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
isUp = false;
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) {
isUp = true;
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_CHANGED)) {
// CHANGED events are handled by others
return NS_OK;
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_UNKNOWN)) {
nsresult rv = mNetworkLinkService->GetIsLinkUp(&isUp);
NS_ENSURE_SUCCESS(rv, rv);
} else {
NS_WARNING("Unhandled network event!");
return NS_OK;
}
return SetOffline(!isUp);
}

Expand Down
2 changes: 1 addition & 1 deletion netwerk/base/src/nsIOService.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class nsIOService MOZ_FINAL : public nsIIOService2
nsIOService();
~nsIOService();

nsresult TrackNetworkLinkStatusForOffline();
nsresult OnNetworkLinkEvent(const char *data);

nsresult GetCachedProtocolHandler(const char *scheme,
nsIProtocolHandler* *hdlrResult,
Expand Down
27 changes: 21 additions & 6 deletions netwerk/dns/nsDNSService2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@
#include "nsCharSeparatedTokenizer.h"
#include "nsNetAddr.h"
#include "nsProxyRelease.h"
#include "nsIObserverService.h"
#include "nsINetworkLinkService.h"

#include "mozilla/Attributes.h"
#include "mozilla/VisualEventTracer.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/ChildDNSService.h"
#include "mozilla/net/DNSListenerProxy.h"
#include "mozilla/Services.h"

using namespace mozilla;
using namespace mozilla::net;
Expand Down Expand Up @@ -540,12 +543,13 @@ nsDNSService::Init()
prefs->AddObserver("network.proxy.type", this, false);
}

nsresult rv;
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, "last-pb-context-exited", false);
observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
}

}

nsDNSPrefetch::Initialize(this);
Expand Down Expand Up @@ -870,10 +874,21 @@ nsDNSService::GetMyHostName(nsACString &result)
NS_IMETHODIMP
nsDNSService::Observe(nsISupports *subject, const char *topic, const char16_t *data)
{
// we are only getting called if a preference has changed.
// We are only getting called if a preference has changed or there's a
// network link event.
NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0 ||
strcmp(topic, "last-pb-context-exited") == 0,
"unexpected observe call");
strcmp(topic, "last-pb-context-exited") == 0 ||
strcmp(topic, NS_NETWORK_LINK_TOPIC) == 0,
"unexpected observe call");

if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
nsCString converted = NS_ConvertUTF16toUTF8(data);
const char *state = converted.get();
if (!strcmp(state, NS_NETWORK_LINK_DATA_CHANGED)) {
mResolver->FlushCache();
}
return NS_OK;
}

//
// Shutdown and this function are both only called on the UI thread, so we don't
Expand Down
25 changes: 16 additions & 9 deletions netwerk/dns/nsHostResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,10 +478,8 @@ nsHostResolver::ClearPendingQueue(PRCList *aPendingQ)
}

void
nsHostResolver::Shutdown()
nsHostResolver::FlushCache()
{
LOG(("Shutting down host resolver.\n"));

PRCList pendingQHigh, pendingQMed, pendingQLow, evictionQ;
PR_INIT_CLIST(&pendingQHigh);
PR_INIT_CLIST(&pendingQMed);
Expand All @@ -490,23 +488,20 @@ nsHostResolver::Shutdown()

{
MutexAutoLock lock(mLock);

mShutdown = true;

MoveCList(mHighQ, pendingQHigh);
MoveCList(mMediumQ, pendingQMed);
MoveCList(mLowQ, pendingQLow);
MoveCList(mEvictionQ, evictionQ);
mEvictionQSize = 0;
mPendingCount = 0;

if (mNumIdleThreads)
mIdleThreadCV.NotifyAll();

// empty host database
PL_DHashTableEnumerate(&mDB, HostDB_RemoveEntry, nullptr);
}

ClearPendingQueue(&pendingQHigh);
ClearPendingQueue(&pendingQMed);
ClearPendingQueue(&pendingQLow);
Expand All @@ -519,6 +514,18 @@ nsHostResolver::Shutdown()
NS_RELEASE(rec);
}
}
}

void
nsHostResolver::Shutdown()
{
LOG(("Shutting down host resolver.\n"));

{
MutexAutoLock lock(mLock);
mShutdown = true;
}
FlushCache();

#ifdef NS_BUILD_REFCNT_LOGGING

Expand Down
5 changes: 5 additions & 0 deletions netwerk/dns/nsHostResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ class nsHostResolver

size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

/**
* Flush the DNS cache.
*/
void FlushCache();

private:
explicit nsHostResolver(uint32_t maxCacheEntries = 50, uint32_t maxCacheLifetime = 60,
uint32_t lifetimeGracePeriod = 0);
Expand Down
Loading

0 comments on commit aafcd6d

Please sign in to comment.