From 6bc1de43adbec4263822282d198c9bce4d03cd4f Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Tue, 2 May 2006 18:08:55 +0000 Subject: [PATCH] fixes bug 76111 "Auto detect online/offline status (on win32)" patch by juan_lang@yahoo.com, r=darin --- allmakefiles.sh | 2 + netwerk/Makefile.in | 1 + netwerk/build/Makefile.in | 9 + netwerk/build/nsNetCID.h | 13 + netwerk/build/nsNetModule.cpp | 16 +- netwerk/system/Makefile.in | 51 ++ netwerk/system/win32/Makefile.in | 61 +++ netwerk/system/win32/nsNotifyAddrListener.cpp | 463 ++++++++++++++++++ netwerk/system/win32/nsNotifyAddrListener.h | 89 ++++ 9 files changed, 704 insertions(+), 1 deletion(-) create mode 100644 netwerk/system/Makefile.in create mode 100644 netwerk/system/win32/Makefile.in create mode 100644 netwerk/system/win32/nsNotifyAddrListener.cpp create mode 100644 netwerk/system/win32/nsNotifyAddrListener.h diff --git a/allmakefiles.sh b/allmakefiles.sh index de69976bc418..b9f692608d38 100755 --- a/allmakefiles.sh +++ b/allmakefiles.sh @@ -464,6 +464,8 @@ netwerk/test/Makefile netwerk/testserver/Makefile netwerk/resources/Makefile netwerk/locales/Makefile +netwerk/system/Makefile +netwerk/system/win32/Makefile uriloader/exthandler/Makefile intl/strres/public/Makefile intl/locale/idl/Makefile diff --git a/netwerk/Makefile.in b/netwerk/Makefile.in index 6170fec96c2f..14b6c9b3f086 100644 --- a/netwerk/Makefile.in +++ b/netwerk/Makefile.in @@ -53,6 +53,7 @@ DIRS = \ streamconv \ cache \ protocol \ + system \ build \ resources \ locales \ diff --git a/netwerk/build/Makefile.in b/netwerk/build/Makefile.in index 2675ac91030b..14176a7b5692 100644 --- a/netwerk/build/Makefile.in +++ b/netwerk/build/Makefile.in @@ -87,6 +87,11 @@ SHARED_LIBRARY_LIBS = \ ../protocol/$(d)/src/$(LIB_PREFIX)nk$(d)_s.$(LIB_SUFFIX)) \ $(NULL) +ifeq ($(OS_ARCH),WINNT) + SHARED_LIBRARY_LIBS += \ + ../system/win32/$(LIB_PREFIX)neckosystem_s.$(LIB_SUFFIX) +endif + LOCAL_INCLUDES = \ -I$(srcdir)/../base/src \ -I$(srcdir)/../dns/src \ @@ -100,6 +105,10 @@ LOCAL_INCLUDES = \ -I$(srcdir)/../protocol/$(d)/src) \ $(NULL) +ifeq ($(OS_ARCH),WINNT) + LOCAL_INCLUDES += -I$(srcdir)/../system/win32 +endif + ifdef NECKO_COOKIES SHARED_LIBRARY_LIBS += \ ../cookie/src/$(LIB_PREFIX)neckocookie_s.$(LIB_SUFFIX) \ diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index d7d733f63401..e6a0ff8475cf 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -756,6 +756,19 @@ #define NS_GENERIC_CONTENT_SNIFFER \ "@mozilla.org/network/content-sniffer;1" +/****************************************************************************** + * netwerk/system classes + */ + +// service implementing nsINetworkLinkService +#define NS_NETWORK_LINK_SERVICE_CLASSNAME "Network Link Status" +#define NS_NETWORK_LINK_SERVICE_CID \ + { 0x75a500a2, \ + 0x0030, \ + 0x40f7, \ + { 0x86, 0xf8, 0x63, 0xf2, 0x25, 0xb9, 0x40, 0xae } \ + } + /****************************************************************************** * Contracts that can be implemented by necko users. */ diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 7fa21d125d01..3eb5310ecb80 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -258,6 +258,12 @@ NS_GENERIC_AGGREGATED_CONSTRUCTOR(nsSimpleURI) #include "nsIDNService.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsIDNService, Init) +/////////////////////////////////////////////////////////////////////////////// +#ifdef XP_WIN +#include "nsNotifyAddrListener.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNotifyAddrListener, Init) +#endif + /////////////////////////////////////////////////////////////////////////////// #ifdef NECKO_PROTOCOL_ftp @@ -1126,7 +1132,15 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { NS_VIEWSOURCEHANDLER_CID, NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "view-source", nsViewSourceHandlerConstructor - } + }, +#endif + +#ifdef XP_WIN + { NS_NETWORK_LINK_SERVICE_CLASSNAME, + NS_NETWORK_LINK_SERVICE_CID, + NS_NETWORK_LINK_SERVICE_CONTRACTID, + nsNotifyAddrListenerConstructor + }, #endif }; diff --git a/netwerk/system/Makefile.in b/netwerk/system/Makefile.in new file mode 100644 index 000000000000..8164413a5eef --- /dev/null +++ b/netwerk/system/Makefile.in @@ -0,0 +1,51 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Juan Lang +# Portions created by the Initial Developer are Copyright (C) 2006 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = necko + +ifeq ($(OS_ARCH),WINNT) + DIRS += win32 +endif + +include $(topsrcdir)/config/rules.mk diff --git a/netwerk/system/win32/Makefile.in b/netwerk/system/win32/Makefile.in new file mode 100644 index 000000000000..e8bb13121b17 --- /dev/null +++ b/netwerk/system/win32/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Juan Lang +# Portions created by the Initial Developer are Copyright (C) 2006 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = necko +LIBRARY_NAME = neckosystem_s +LIBXUL_LIBRARY = 1 +REQUIRES = xpcom \ + string \ + pref \ + $(NULL) + +FORCE_STATIC_LIB = 1 + +ifeq ($(OS_ARCH),WINNT) + CPPSRCS += nsNotifyAddrListener.cpp +endif + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DIMPL_NS_NET diff --git a/netwerk/system/win32/nsNotifyAddrListener.cpp b/netwerk/system/win32/nsNotifyAddrListener.cpp new file mode 100644 index 000000000000..11277e1d07e1 --- /dev/null +++ b/netwerk/system/win32/nsNotifyAddrListener.cpp @@ -0,0 +1,463 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set et sw=4 ts=4: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is written by Juan Lang. + * + * The Initial Developer of the Original Code is + * Juan Lang. + * Portions created by the Initial Developer are Copyright (C) 2003,2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include +#include +#include +#include "prmem.h" +#include "prthread.h" +#include "plstr.h" +#include "nsEventQueueUtils.h" +#include "nsIObserverService.h" +#include "nsServiceManagerUtils.h" +#include "nsNotifyAddrListener.h" +#include "nsString.h" + +typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(ULONG, DWORD, PVOID, + PIP_ADAPTER_ADDRESSES, + PULONG); +typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO, PULONG); +typedef DWORD (WINAPI *GetIfEntryFunc)(PMIB_IFROW); +typedef DWORD (WINAPI *GetIpAddrTableFunc)(PMIB_IPADDRTABLE, PULONG, BOOL); +typedef DWORD (WINAPI *NotifyAddrChangeFunc)(PHANDLE, LPOVERLAPPED); + +static HMODULE sIPHelper; +static GetAdaptersAddressesFunc sGetAdaptersAddresses; +static GetAdaptersInfoFunc sGetAdaptersInfo; +static GetIfEntryFunc sGetIfEntry; +static GetIpAddrTableFunc sGetIpAddrTable; +static NotifyAddrChangeFunc sNotifyAddrChange; + +static void InitIPHelperLibrary(void) +{ + if (sIPHelper) + return; + + sIPHelper = LoadLibraryA("iphlpapi.dll"); + if (!sIPHelper) + return; + + sGetAdaptersAddresses = (GetAdaptersAddressesFunc) + GetProcAddress(sIPHelper, "GetAdaptersAddresses"); + sGetAdaptersInfo = (GetAdaptersInfoFunc) + GetProcAddress(sIPHelper, "GetAdaptersInfo"); + sGetIfEntry = (GetIfEntryFunc) + GetProcAddress(sIPHelper, "GetIfEntry"); + sGetIpAddrTable = (GetIpAddrTableFunc) + GetProcAddress(sIPHelper, "GetIpAddrTable"); + sNotifyAddrChange = (NotifyAddrChangeFunc) + GetProcAddress(sIPHelper, "NotifyAddrChange"); +} + +static void FreeIPHelperLibrary(void) +{ + if (!sIPHelper) + return; + + sGetAdaptersAddresses = nsnull; + sGetAdaptersInfo = nsnull; + sGetIfEntry = nsnull; + sGetIpAddrTable = nsnull; + sNotifyAddrChange = nsnull; + + FreeLibrary(sIPHelper); + sIPHelper = nsnull; +} + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsNotifyAddrListener, + nsINetworkLinkService, + nsIRunnable, + nsIObserver) + +nsNotifyAddrListener::nsNotifyAddrListener() + : mLinkUp(PR_FALSE) + , mStatusKnown(PR_FALSE) + , mThread(0) + , mShutdownEvent(nsnull) +{ + mOSVerInfo.dwOSVersionInfoSize = sizeof(mOSVerInfo); + GetVersionEx(&mOSVerInfo); + InitIPHelperLibrary(); +} + +nsNotifyAddrListener::~nsNotifyAddrListener() +{ + NS_ASSERTION(!mThread, "nsNotifyAddrListener thread shutdown failed"); + FreeIPHelperLibrary(); +} + +NS_IMETHODIMP +nsNotifyAddrListener::GetIsLinkUp(PRBool *aIsUp) +{ + *aIsUp = mLinkUp; + return NS_OK; +} + +NS_IMETHODIMP +nsNotifyAddrListener::GetLinkStatusKnown(PRBool *aIsUp) +{ + *aIsUp = mStatusKnown; + return NS_OK; +} + +NS_IMETHODIMP +nsNotifyAddrListener::Run() +{ + HANDLE ev = CreateEvent(nsnull, FALSE, FALSE, nsnull); + NS_ENSURE_TRUE(ev, NS_ERROR_OUT_OF_MEMORY); + + HANDLE handles[2] = { ev, mShutdownEvent }; + OVERLAPPED overlapped = { 0 }; + PRBool shuttingDown = PR_FALSE; + + overlapped.hEvent = ev; + while (!shuttingDown) { + HANDLE h; + DWORD ret = sNotifyAddrChange(&h, &overlapped); + + if (ret == ERROR_IO_PENDING) { + ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); + if (ret == WAIT_OBJECT_0) { + CheckLinkStatus(); + } else { + shuttingDown = PR_TRUE; + } + } else { + shuttingDown = PR_TRUE; + } + } + CloseHandle(ev); + + return NS_OK; +} + +NS_IMETHODIMP +nsNotifyAddrListener::Observe(nsISupports *subject, + const char *topic, + const PRUnichar *data) +{ + if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic)) + Shutdown(); + + return NS_OK; +} + +nsresult +nsNotifyAddrListener::Init(void) +{ + CheckLinkStatus(); + + // only start a thread on Windows 2000 or later + if (mOSVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT || + mOSVerInfo.dwMajorVersion < 5) + return NS_OK; + + nsresult rv; + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, + PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + mShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + NS_ENSURE_TRUE(mShutdownEvent, NS_ERROR_OUT_OF_MEMORY); + + rv = NS_NewThread(getter_AddRefs(mThread), this, 0, + PR_JOINABLE_THREAD); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult +nsNotifyAddrListener::Shutdown(void) +{ + // remove xpcom shutdown observer + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1"); + if (observerService) + observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + + if (!mShutdownEvent) + return NS_OK; + + SetEvent(mShutdownEvent); + + nsresult rv = mThread->Join(); + + // Have to break the cycle here, otherwise nsNotifyAddrListener holds + // onto the thread and the thread holds onto the nsNotifyAddrListener + // via its mRunnable + mThread = nsnull; + + CloseHandle(mShutdownEvent); + mShutdownEvent = NULL; + + return rv; +} + +/* Sends the given event to the UI thread. Assumes aEventID never goes out + * of scope (static strings are ideal). + */ +nsresult +nsNotifyAddrListener::SendEventToUI(const char *aEventID) +{ + nsresult rv; + + if (!aEventID) return NS_ERROR_NULL_POINTER; + + nsCOMPtr eq; + rv = NS_GetMainEventQ(getter_AddRefs(eq)); + if (NS_FAILED(rv)) + return rv; + + ChangeEvent *event = new ChangeEvent(aEventID); + if (!event) + return NS_ERROR_OUT_OF_MEMORY; + // AddRef this because it is being placed in the PLEvent; it'll be Released + // when DestroyInterfaceEvent is called + NS_ADDREF_THIS(); + PL_InitEvent(event, this, HandleInterfaceEvent, DestroyInterfaceEvent); + + if (NS_FAILED(rv = eq->PostEvent(event))) { + NS_ERROR("failed to post event to UI EventQueue"); + PL_DestroyEvent(event); + } + return rv; +} + +/*static*/ void *PR_CALLBACK +nsNotifyAddrListener::HandleInterfaceEvent(PLEvent *aEvent) +{ + ChangeEvent *event = NS_STATIC_CAST(ChangeEvent *, aEvent); + + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1"); + if (observerService) + observerService->NotifyObservers( + NS_STATIC_CAST(nsINetworkLinkService *, PL_GetEventOwner(aEvent)), + NS_NETWORK_LINK_TOPIC, + NS_ConvertASCIItoUTF16(event->mEventID).get()); + return nsnull; +} + +/*static*/ void PR_CALLBACK +nsNotifyAddrListener::DestroyInterfaceEvent(PLEvent *aEvent) +{ + nsNotifyAddrListener *self = + NS_STATIC_CAST(nsNotifyAddrListener *, PL_GetEventOwner(aEvent)); + NS_RELEASE(self); + delete aEvent; +} + +DWORD +nsNotifyAddrListener::GetOperationalStatus(DWORD aAdapterIndex) +{ + DWORD status = MIB_IF_OPER_STATUS_CONNECTED; + + // try to get operational status on WinNT--on Win98, it consistently gives + // me the wrong status, dagnabbit + if (mOSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + // If this fails, assume it's connected. Didn't find a KB, but it + // failed for me w/Win2K SP2, and succeeded for me w/Win2K SP3. + if (sGetIfEntry) { + MIB_IFROW ifRow; + + ifRow.dwIndex = aAdapterIndex; + if (sGetIfEntry(&ifRow) == ERROR_SUCCESS) + status = ifRow.dwOperStatus; + } + } + return status; +} + +/** + * Calls GetIpAddrTable to check whether a link is up. Assumes so if any + * adapter has a non-zero IP (v4) address. Sets mLinkUp if GetIpAddrTable + * succeeds, but doesn't set mStatusKnown. + * Returns ERROR_SUCCESS on success, and a Win32 error code otherwise. + */ +DWORD +nsNotifyAddrListener::CheckIPAddrTable(void) +{ + if (!sGetIpAddrTable) + return ERROR_CALL_NOT_IMPLEMENTED; + + ULONG size = 0; + DWORD ret = sGetIpAddrTable(nsnull, &size, FALSE); + if (ret == ERROR_INSUFFICIENT_BUFFER && size > 0) { + PMIB_IPADDRTABLE table = (PMIB_IPADDRTABLE) malloc(size); + if (!table) + return ERROR_OUTOFMEMORY; + + ret = sGetIpAddrTable(table, &size, FALSE); + if (ret == ERROR_SUCCESS) { + PRBool linkUp = PR_FALSE; + + for (DWORD i = 0; !linkUp && i < table->dwNumEntries; i++) { + if (GetOperationalStatus(table->table[i].dwIndex) >= + MIB_IF_OPER_STATUS_CONNECTED && + table->table[i].dwAddr != 0) + linkUp = PR_TRUE; + } + mLinkUp = linkUp; + } + free(table); + } + return ret; +} + +/** + * Checks whether a link is up by calling GetAdaptersInfo. If any adapter's + * operational status is at least MIB_IF_OPER_STATUS_CONNECTED, checks: + * 1. If it's configured for DHCP, the link is considered up if the DHCP + * server is initialized. + * 2. If it's not configured for DHCP, the link is considered up if it has a + * nonzero IP address. + * Sets mLinkUp and mStatusKnown if GetAdaptersInfo succeeds. + * Returns ERROR_SUCCESS on success, and a Win32 error code otherwise. If the + * call is not present on the current platform, returns ERROR_NOT_SUPPORTED. + */ +DWORD +nsNotifyAddrListener::CheckAdaptersInfo(void) +{ + if (!sGetAdaptersInfo) + return ERROR_NOT_SUPPORTED; + + ULONG adaptersLen = 0; + + DWORD ret = sGetAdaptersInfo(0, &adaptersLen); + if (ret == ERROR_BUFFER_OVERFLOW && adaptersLen > 0) { + PIP_ADAPTER_INFO adapters = (PIP_ADAPTER_INFO) malloc(adaptersLen); + if (sGetAdaptersInfo(adapters, &adaptersLen) == ERROR_SUCCESS) { + PRBool linkUp = PR_FALSE; + PIP_ADAPTER_INFO ptr; + + for (ptr = adapters; ptr && !linkUp; ptr = ptr->Next) { + if (GetOperationalStatus(ptr->Index) >= + MIB_IF_OPER_STATUS_CONNECTED) { + if (ptr->DhcpEnabled) { + if (PL_strcmp(ptr->DhcpServer.IpAddress.String, + "255.255.255.255")) { + // it has a DHCP server, therefore it must have + // a usable address + linkUp = PR_TRUE; + } + } + else { + PIP_ADDR_STRING ipAddr; + for (ipAddr = &ptr->IpAddressList; ipAddr && !linkUp; + ipAddr = ipAddr->Next) + if (PL_strcmp(ipAddr->IpAddress.String, "0.0.0.0")) + linkUp = PR_TRUE; + } + } + } + mLinkUp = linkUp; + mStatusKnown = PR_TRUE; + free(adapters); + } + } + return ret; +} + +DWORD +nsNotifyAddrListener::CheckAdaptersAddresses(void) +{ + static const DWORD flags = + GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; + + if (!sGetAdaptersAddresses) + return ERROR_NOT_SUPPORTED; + + ULONG len = 0; + + DWORD ret = sGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len); + if (ret == ERROR_BUFFER_OVERFLOW) { + PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES) malloc(len); + if (addresses) { + ret = sGetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &len); + if (ret == ERROR_SUCCESS) { + PIP_ADAPTER_ADDRESSES ptr; + BOOL linkUp = FALSE; + + for (ptr = addresses; !linkUp && ptr; ptr = ptr->Next) { + if (ptr->OperStatus == IfOperStatusUp && + ptr->IfType != IF_TYPE_SOFTWARE_LOOPBACK) + linkUp = TRUE; + } + mLinkUp = linkUp; + mStatusKnown = TRUE; + } + free(addresses); + } + } + return ret; +} + +/** + * Checks the status of all network adapters. If one is up and has a valid IP + * address, sets mLinkUp to true. Sets mStatusKnown to true if the link status + * is definitive. + */ +void +nsNotifyAddrListener::CheckLinkStatus(void) +{ + DWORD ret; + const char *event; + + ret = CheckAdaptersAddresses(); + if (ret == ERROR_NOT_SUPPORTED) + ret = CheckAdaptersInfo(); + if (ret == ERROR_NOT_SUPPORTED) + ret = CheckIPAddrTable(); + if (ret != ERROR_SUCCESS) + mLinkUp = PR_TRUE; // I can't tell, so assume there's a link + + if (mStatusKnown) + event = mLinkUp ? NS_NETWORK_LINK_DATA_UP : NS_NETWORK_LINK_DATA_DOWN; + else + event = NS_NETWORK_LINK_DATA_UNKNOWN; + SendEventToUI(event); +} diff --git a/netwerk/system/win32/nsNotifyAddrListener.h b/netwerk/system/win32/nsNotifyAddrListener.h new file mode 100644 index 000000000000..35dd3709163a --- /dev/null +++ b/netwerk/system/win32/nsNotifyAddrListener.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set et sw=4 ts=4: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is written by Juan Lang. + * + * The Initial Developer of the Original Code is + * Juan Lang. + * Portions created by the Initial Developer are Copyright (C) 2003,2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef NSNOTIFYADDRLISTENER_H_ +#define NSNOTIFYADDRLISTENER_H_ + +#include "nsINetworkLinkService.h" +#include "nsIRunnable.h" +#include "nsIObserver.h" +#include "nsIThread.h" +#include "nsCOMPtr.h" + +class nsNotifyAddrListener : public nsINetworkLinkService, + public nsIRunnable, + public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSINETWORKLINKSERVICE + NS_DECL_NSIRUNNABLE + NS_DECL_NSIOBSERVER + + nsNotifyAddrListener(); + virtual ~nsNotifyAddrListener(); + + nsresult Init(void); + +protected: + struct ChangeEvent : public PLEvent { + ChangeEvent(const char *aEventID) : mEventID(aEventID) { } + const char *mEventID; + }; + + PRPackedBool mLinkUp; + PRPackedBool mStatusKnown; + + nsresult Shutdown(void); + nsresult SendEventToUI(const char *aEventID); + + DWORD GetOperationalStatus(DWORD aAdapterIndex); + DWORD CheckIPAddrTable(void); + DWORD CheckAdaptersInfo(void); + DWORD CheckAdaptersAddresses(void); + void CheckLinkStatus(void); + + PR_STATIC_CALLBACK(void*) HandleInterfaceEvent(PLEvent *aEvent); + PR_STATIC_CALLBACK(void) DestroyInterfaceEvent(PLEvent *aEvent); + + nsCOMPtr mThread; + + OSVERSIONINFO mOSVerInfo; + HANDLE mShutdownEvent; +}; + +#endif /* NSNOTIFYADDRLISTENER_H_ */