Back to index

lightning-sunbird  0.9+nobinonly
nsNotifyAddrListener.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:set et sw=4 ts=4: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License
00007  * Version 1.1 (the "License"); you may not use this file except in
00008  * compliance with the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is written by Juan Lang.
00017  *
00018  * The Initial Developer of the Original Code is 
00019  * Juan Lang.
00020  * Portions created by the Initial Developer are Copyright (C) 2003,2006
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or 
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <stdarg.h>
00040 #include <windef.h>
00041 #include <winbase.h>
00042 #include <wingdi.h>
00043 #include <winuser.h>
00044 #include <winsock2.h>
00045 #include <iprtrmib.h>
00046 #include <time.h>
00047 #include "prmem.h"
00048 #include "prthread.h"
00049 #include "plstr.h"
00050 #include "nsEventQueueUtils.h"
00051 #include "nsIObserverService.h"
00052 #include "nsServiceManagerUtils.h"
00053 #include "nsNotifyAddrListener.h"
00054 #include "nsString.h"
00055 
00056 // Unfortunately, this header file is not available in older SDKs.
00057 // #include <IPTypes.h>
00058 
00059 #define MAX_ADAPTER_DESCRIPTION_LENGTH  128 // arb.
00060 #define MAX_ADAPTER_NAME_LENGTH         256 // arb.
00061 #define MAX_ADAPTER_ADDRESS_LENGTH      8   // arb.
00062 
00063 #define GAA_FLAG_SKIP_ANYCAST       0x0002
00064 #define GAA_FLAG_SKIP_MULTICAST     0x0004
00065 #define GAA_FLAG_SKIP_DNS_SERVER    0x0008
00066 #define GAA_FLAG_SKIP_FRIENDLY_NAME 0x0020
00067 
00068 #define IF_TYPE_SOFTWARE_LOOPBACK       24
00069 
00070 typedef enum {
00071     IpPrefixOriginOther = 0,
00072     IpPrefixOriginManual,
00073     IpPrefixOriginWellKnown,
00074     IpPrefixOriginDhcp,
00075     IpPrefixOriginRouterAdvertisement
00076 } IP_PREFIX_ORIGIN;
00077 
00078 typedef enum {
00079     IpSuffixOriginOther = 0,
00080     IpSuffixOriginManual,
00081     IpSuffixOriginWellKnown,
00082     IpSuffixOriginDhcp,
00083     IpSuffixOriginLinkLayerAddress,
00084     IpSuffixOriginRandom
00085 } IP_SUFFIX_ORIGIN;
00086 
00087 typedef enum {
00088     IpDadStateInvalid    = 0,
00089     IpDadStateTentative,
00090     IpDadStateDuplicate,
00091     IpDadStateDeprecated,
00092     IpDadStatePreferred
00093 } IP_DAD_STATE;
00094 
00095 typedef struct _IP_ADAPTER_UNICAST_ADDRESS {
00096     union {
00097         ULONGLONG Alignment;
00098         struct {
00099             ULONG Length;
00100             DWORD Flags;
00101         } s;
00102     } u;
00103     struct _IP_ADAPTER_UNICAST_ADDRESS *Next;
00104     SOCKET_ADDRESS Address;
00105 
00106     IP_PREFIX_ORIGIN PrefixOrigin;
00107     IP_SUFFIX_ORIGIN SuffixOrigin;
00108     IP_DAD_STATE DadState;
00109 
00110     ULONG ValidLifetime;
00111     ULONG PreferredLifetime;
00112     ULONG LeaseLifetime;
00113 } IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS;
00114 
00115 typedef struct _IP_ADAPTER_ANYCAST_ADDRESS {
00116     union {
00117         ULONGLONG Alignment;
00118         struct {
00119             ULONG Length;
00120             DWORD Flags;
00121         } s;
00122     } u;
00123     struct _IP_ADAPTER_ANYCAST_ADDRESS *Next;
00124     SOCKET_ADDRESS Address;
00125 } IP_ADAPTER_ANYCAST_ADDRESS, *PIP_ADAPTER_ANYCAST_ADDRESS;
00126 
00127 typedef struct _IP_ADAPTER_MULTICAST_ADDRESS {
00128     union {
00129         ULONGLONG Alignment;
00130         struct {
00131             ULONG Length;
00132             DWORD Flags;
00133         } s;
00134     } u;
00135     struct _IP_ADAPTER_MULTICAST_ADDRESS *Next;
00136     SOCKET_ADDRESS Address;
00137 } IP_ADAPTER_MULTICAST_ADDRESS, *PIP_ADAPTER_MULTICAST_ADDRESS;
00138 
00139 typedef struct _IP_ADAPTER_DNS_SERVER_ADDRESS {
00140     union {
00141         ULONGLONG Alignment;
00142         struct {
00143             ULONG Length;
00144             DWORD Reserved;
00145         } s;
00146     } u;
00147     struct _IP_ADAPTER_DNS_SERVER_ADDRESS *Next;
00148     SOCKET_ADDRESS Address;
00149 } IP_ADAPTER_DNS_SERVER_ADDRESS, *PIP_ADAPTER_DNS_SERVER_ADDRESS;
00150 
00151 typedef enum {
00152     IfOperStatusUp = 1,
00153     IfOperStatusDown,
00154     IfOperStatusTesting,
00155     IfOperStatusUnknown,
00156     IfOperStatusDormant,
00157     IfOperStatusNotPresent,
00158     IfOperStatusLowerLayerDown
00159 } IF_OPER_STATUS;
00160 
00161 typedef struct _IP_ADAPTER_ADDRESSES {
00162     union {
00163         ULONGLONG Alignment;
00164         struct {
00165             ULONG Length;
00166             DWORD IfIndex;
00167         } s;
00168     } u;
00169     struct _IP_ADAPTER_ADDRESSES *Next;
00170     PCHAR AdapterName;
00171     PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress;
00172     PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress;
00173     PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress;
00174     PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress;
00175     PWCHAR DnsSuffix;
00176     PWCHAR Description;
00177     PWCHAR FriendlyName;
00178     BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
00179     DWORD PhysicalAddressLength;
00180     DWORD Flags;
00181     DWORD Mtu;
00182     DWORD IfType;
00183     IF_OPER_STATUS OperStatus;
00184 } IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES;
00185 
00186 typedef struct {
00187     char String[4 * 4];
00188 } IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
00189 
00190 typedef struct _IP_ADDR_STRING {
00191     struct _IP_ADDR_STRING* Next;
00192     IP_ADDRESS_STRING IpAddress;
00193     IP_MASK_STRING IpMask;
00194     DWORD Context;
00195 } IP_ADDR_STRING, *PIP_ADDR_STRING;
00196 
00197 typedef struct _IP_ADAPTER_INFO {
00198     struct _IP_ADAPTER_INFO* Next;
00199     DWORD ComboIndex;
00200     char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
00201     char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
00202     UINT AddressLength;
00203     BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
00204     DWORD Index;
00205     UINT Type;
00206     UINT DhcpEnabled;
00207     PIP_ADDR_STRING CurrentIpAddress;
00208     IP_ADDR_STRING IpAddressList;
00209     IP_ADDR_STRING GatewayList;
00210     IP_ADDR_STRING DhcpServer;
00211     BOOL HaveWins;
00212     IP_ADDR_STRING PrimaryWinsServer;
00213     IP_ADDR_STRING SecondaryWinsServer;
00214     time_t LeaseObtained;
00215     time_t LeaseExpires;
00216 } IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
00217 
00218 typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(ULONG, DWORD, PVOID,
00219                                                  PIP_ADAPTER_ADDRESSES,
00220                                                  PULONG);
00221 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO, PULONG);
00222 typedef DWORD (WINAPI *GetIfEntryFunc)(PMIB_IFROW);
00223 typedef DWORD (WINAPI *GetIpAddrTableFunc)(PMIB_IPADDRTABLE, PULONG, BOOL);
00224 typedef DWORD (WINAPI *NotifyAddrChangeFunc)(PHANDLE, LPOVERLAPPED);
00225 
00226 static HMODULE sIPHelper;
00227 static GetAdaptersAddressesFunc sGetAdaptersAddresses;
00228 static GetAdaptersInfoFunc sGetAdaptersInfo;
00229 static GetIfEntryFunc sGetIfEntry;
00230 static GetIpAddrTableFunc sGetIpAddrTable;
00231 static NotifyAddrChangeFunc sNotifyAddrChange;
00232 
00233 static void InitIPHelperLibrary(void)
00234 {
00235     if (sIPHelper)
00236         return;
00237 
00238     sIPHelper = LoadLibraryA("iphlpapi.dll");
00239     if (!sIPHelper)
00240         return;
00241 
00242     sGetAdaptersAddresses = (GetAdaptersAddressesFunc)
00243         GetProcAddress(sIPHelper, "GetAdaptersAddresses");
00244     sGetAdaptersInfo = (GetAdaptersInfoFunc)
00245         GetProcAddress(sIPHelper, "GetAdaptersInfo");
00246     sGetIfEntry = (GetIfEntryFunc)
00247         GetProcAddress(sIPHelper, "GetIfEntry");
00248     sGetIpAddrTable = (GetIpAddrTableFunc)
00249         GetProcAddress(sIPHelper, "GetIpAddrTable");
00250     sNotifyAddrChange = (NotifyAddrChangeFunc)
00251         GetProcAddress(sIPHelper, "NotifyAddrChange");
00252 }
00253 
00254 static void FreeIPHelperLibrary(void)
00255 {
00256     if (!sIPHelper)
00257         return;
00258 
00259     sGetAdaptersAddresses = nsnull;
00260     sGetAdaptersInfo = nsnull;
00261     sGetIfEntry = nsnull;
00262     sGetIpAddrTable = nsnull;
00263     sNotifyAddrChange = nsnull;
00264 
00265     FreeLibrary(sIPHelper);
00266     sIPHelper = nsnull;
00267 }
00268 
00269 NS_IMPL_THREADSAFE_ISUPPORTS3(nsNotifyAddrListener,
00270                               nsINetworkLinkService,
00271                               nsIRunnable,
00272                               nsIObserver)
00273 
00274 nsNotifyAddrListener::nsNotifyAddrListener()
00275     : mLinkUp(PR_TRUE)  // assume true by default
00276     , mStatusKnown(PR_FALSE)
00277     , mThread(0)
00278     , mShutdownEvent(nsnull)
00279 {
00280     mOSVerInfo.dwOSVersionInfoSize = sizeof(mOSVerInfo);
00281     GetVersionEx(&mOSVerInfo);
00282     InitIPHelperLibrary();
00283 }
00284 
00285 nsNotifyAddrListener::~nsNotifyAddrListener()
00286 {
00287     NS_ASSERTION(!mThread, "nsNotifyAddrListener thread shutdown failed");
00288     FreeIPHelperLibrary();
00289 }
00290 
00291 NS_IMETHODIMP
00292 nsNotifyAddrListener::GetIsLinkUp(PRBool *aIsUp)
00293 {
00294     *aIsUp = mLinkUp;
00295     return NS_OK;
00296 }
00297 
00298 NS_IMETHODIMP
00299 nsNotifyAddrListener::GetLinkStatusKnown(PRBool *aIsUp)
00300 {
00301     *aIsUp = mStatusKnown;
00302     return NS_OK;
00303 }
00304 
00305 NS_IMETHODIMP
00306 nsNotifyAddrListener::Run()
00307 {
00308     HANDLE ev = CreateEvent(nsnull, FALSE, FALSE, nsnull);
00309     NS_ENSURE_TRUE(ev, NS_ERROR_OUT_OF_MEMORY);
00310 
00311     HANDLE handles[2] = { ev, mShutdownEvent };
00312     OVERLAPPED overlapped = { 0 };
00313     PRBool shuttingDown = PR_FALSE;
00314 
00315     overlapped.hEvent = ev;
00316     while (!shuttingDown) {
00317         HANDLE h;
00318         DWORD ret = sNotifyAddrChange(&h, &overlapped);
00319 
00320         if (ret == ERROR_IO_PENDING) {
00321             ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
00322             if (ret == WAIT_OBJECT_0) {
00323                 CheckLinkStatus();
00324             } else {
00325                 shuttingDown = PR_TRUE;
00326             }
00327         } else {
00328             shuttingDown = PR_TRUE;
00329         }
00330     }
00331     CloseHandle(ev);
00332 
00333     return NS_OK;
00334 }
00335 
00336 NS_IMETHODIMP
00337 nsNotifyAddrListener::Observe(nsISupports *subject,
00338                               const char *topic,
00339                               const PRUnichar *data)
00340 {
00341     if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic))
00342         Shutdown();
00343 
00344     return NS_OK;
00345 }
00346 
00347 nsresult
00348 nsNotifyAddrListener::Init(void)
00349 {
00350     // XXX this call is very expensive (~650 milliseconds), so we
00351     //     don't want to call it synchronously.  Instead, we just
00352     //     start up assuming we have a network link, but we'll
00353     //     report that the status isn't known.
00354     //
00355     // CheckLinkStatus();
00356 
00357     // only start a thread on Windows 2000 or later
00358     if (mOSVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT ||
00359         mOSVerInfo.dwMajorVersion < 5)
00360         return NS_OK;
00361 
00362     nsresult rv;
00363     nsCOMPtr<nsIObserverService> observerService =
00364         do_GetService("@mozilla.org/observer-service;1", &rv);
00365     NS_ENSURE_SUCCESS(rv, rv);
00366 
00367     rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
00368                                       PR_FALSE);
00369     NS_ENSURE_SUCCESS(rv, rv);
00370 
00371     mShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
00372     NS_ENSURE_TRUE(mShutdownEvent, NS_ERROR_OUT_OF_MEMORY);
00373 
00374     rv = NS_NewThread(getter_AddRefs(mThread), this, 0,
00375                       PR_JOINABLE_THREAD);
00376     NS_ENSURE_SUCCESS(rv, rv);
00377 
00378     return NS_OK;
00379 }
00380 
00381 nsresult
00382 nsNotifyAddrListener::Shutdown(void)
00383 {
00384     // remove xpcom shutdown observer
00385     nsCOMPtr<nsIObserverService> observerService =
00386         do_GetService("@mozilla.org/observer-service;1");
00387     if (observerService)
00388         observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
00389 
00390     if (!mShutdownEvent)
00391         return NS_OK;
00392 
00393     SetEvent(mShutdownEvent);
00394 
00395     nsresult rv = mThread->Join();
00396 
00397     // Have to break the cycle here, otherwise nsNotifyAddrListener holds
00398     // onto the thread and the thread holds onto the nsNotifyAddrListener
00399     // via its mRunnable
00400     mThread = nsnull;
00401 
00402     CloseHandle(mShutdownEvent);
00403     mShutdownEvent = NULL;
00404 
00405     return rv;
00406 }
00407 
00408 /* Sends the given event to the UI thread.  Assumes aEventID never goes out
00409  * of scope (static strings are ideal).
00410  */
00411 nsresult
00412 nsNotifyAddrListener::SendEventToUI(const char *aEventID)
00413 {
00414     nsresult rv;
00415 
00416     if (!aEventID) return NS_ERROR_NULL_POINTER;
00417 
00418     nsCOMPtr<nsIEventQueue> eq;
00419     rv = NS_GetMainEventQ(getter_AddRefs(eq));
00420     if (NS_FAILED(rv))
00421         return rv;
00422 
00423     ChangeEvent *event = new ChangeEvent(aEventID);
00424     if (!event)
00425         return NS_ERROR_OUT_OF_MEMORY;
00426     // AddRef this because it is being placed in the PLEvent; it'll be Released
00427     // when DestroyInterfaceEvent is called
00428     NS_ADDREF_THIS();
00429     PL_InitEvent(event, this, HandleInterfaceEvent, DestroyInterfaceEvent);
00430 
00431     if (NS_FAILED(rv = eq->PostEvent(event))) {
00432         NS_ERROR("failed to post event to UI EventQueue");
00433         PL_DestroyEvent(event);
00434     }
00435     return rv;
00436 }
00437 
00438 /*static*/ void *PR_CALLBACK
00439 nsNotifyAddrListener::HandleInterfaceEvent(PLEvent *aEvent)
00440 {
00441     ChangeEvent *event = NS_STATIC_CAST(ChangeEvent *, aEvent);
00442 
00443     nsCOMPtr<nsIObserverService> observerService =
00444         do_GetService("@mozilla.org/observer-service;1");
00445     if (observerService)
00446         observerService->NotifyObservers(
00447             NS_STATIC_CAST(nsINetworkLinkService *, PL_GetEventOwner(aEvent)),
00448             NS_NETWORK_LINK_TOPIC,
00449             NS_ConvertASCIItoUTF16(event->mEventID).get());
00450     return nsnull;
00451 }
00452 
00453 /*static*/ void PR_CALLBACK
00454 nsNotifyAddrListener::DestroyInterfaceEvent(PLEvent *aEvent)
00455 {
00456     nsNotifyAddrListener *self =
00457         NS_STATIC_CAST(nsNotifyAddrListener *, PL_GetEventOwner(aEvent));
00458     NS_RELEASE(self);
00459     delete aEvent;
00460 }
00461 
00462 DWORD
00463 nsNotifyAddrListener::GetOperationalStatus(DWORD aAdapterIndex)
00464 {
00465     DWORD status = MIB_IF_OPER_STATUS_CONNECTED;
00466 
00467     // try to get operational status on WinNT--on Win98, it consistently gives
00468     // me the wrong status, dagnabbit
00469     if (mOSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
00470         // If this fails, assume it's connected.  Didn't find a KB, but it
00471         // failed for me w/Win2K SP2, and succeeded for me w/Win2K SP3.
00472         if (sGetIfEntry) {
00473             MIB_IFROW ifRow;
00474 
00475             ifRow.dwIndex = aAdapterIndex;
00476             if (sGetIfEntry(&ifRow) == ERROR_SUCCESS)
00477                 status = ifRow.dwOperStatus;
00478         }
00479     }
00480     return status;
00481 }
00482 
00489 DWORD
00490 nsNotifyAddrListener::CheckIPAddrTable(void)
00491 {
00492     if (!sGetIpAddrTable)
00493         return ERROR_CALL_NOT_IMPLEMENTED;
00494 
00495     ULONG size = 0;
00496     DWORD ret = sGetIpAddrTable(nsnull, &size, FALSE);
00497     if (ret == ERROR_INSUFFICIENT_BUFFER && size > 0) {
00498         PMIB_IPADDRTABLE table = (PMIB_IPADDRTABLE) malloc(size);
00499         if (!table)
00500             return ERROR_OUTOFMEMORY;
00501 
00502         ret = sGetIpAddrTable(table, &size, FALSE);
00503         if (ret == ERROR_SUCCESS) {
00504             PRBool linkUp = PR_FALSE;
00505 
00506             for (DWORD i = 0; !linkUp && i < table->dwNumEntries; i++) {
00507                 if (GetOperationalStatus(table->table[i].dwIndex) >=
00508                         MIB_IF_OPER_STATUS_CONNECTED &&
00509                         table->table[i].dwAddr != 0)
00510                     linkUp = PR_TRUE;
00511             }
00512             mLinkUp = linkUp;
00513         }
00514         free(table);
00515     }
00516     return ret;
00517 }
00518 
00530 DWORD
00531 nsNotifyAddrListener::CheckAdaptersInfo(void)
00532 {
00533     if (!sGetAdaptersInfo)
00534         return ERROR_NOT_SUPPORTED;
00535 
00536     ULONG adaptersLen = 0;
00537 
00538     DWORD ret = sGetAdaptersInfo(0, &adaptersLen);
00539     if (ret == ERROR_BUFFER_OVERFLOW && adaptersLen > 0) {
00540         PIP_ADAPTER_INFO adapters = (PIP_ADAPTER_INFO) malloc(adaptersLen);
00541         if (sGetAdaptersInfo(adapters, &adaptersLen) == ERROR_SUCCESS) {
00542             PRBool linkUp = PR_FALSE;
00543             PIP_ADAPTER_INFO ptr;
00544 
00545             for (ptr = adapters; ptr && !linkUp; ptr = ptr->Next) {
00546                 if (GetOperationalStatus(ptr->Index) >=
00547                         MIB_IF_OPER_STATUS_CONNECTED) {
00548                     if (ptr->DhcpEnabled) {
00549                         if (PL_strcmp(ptr->DhcpServer.IpAddress.String,
00550                                       "255.255.255.255")) {
00551                             // it has a DHCP server, therefore it must have
00552                             // a usable address
00553                             linkUp = PR_TRUE;
00554                         }
00555                     }
00556                     else {
00557                         PIP_ADDR_STRING ipAddr;
00558                         for (ipAddr = &ptr->IpAddressList; ipAddr && !linkUp;
00559                              ipAddr = ipAddr->Next)
00560                             if (PL_strcmp(ipAddr->IpAddress.String, "0.0.0.0"))
00561                                 linkUp = PR_TRUE;
00562                     }
00563                 }
00564             }
00565             mLinkUp = linkUp;
00566             mStatusKnown = PR_TRUE;
00567             free(adapters);
00568         }
00569     }
00570     return ret;
00571 }
00572 
00573 DWORD
00574 nsNotifyAddrListener::CheckAdaptersAddresses(void)
00575 {
00576     static const DWORD flags =
00577         GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_ANYCAST |
00578         GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
00579 
00580     if (!sGetAdaptersAddresses)
00581         return ERROR_NOT_SUPPORTED;
00582 
00583     ULONG len = 0;
00584 
00585     DWORD ret = sGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len);
00586     if (ret == ERROR_BUFFER_OVERFLOW) {
00587         PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES) malloc(len);
00588         if (addresses) {
00589             ret = sGetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &len);
00590             if (ret == ERROR_SUCCESS) {
00591                 PIP_ADAPTER_ADDRESSES ptr;
00592                 BOOL linkUp = FALSE;
00593 
00594                 for (ptr = addresses; !linkUp && ptr; ptr = ptr->Next) {
00595                     if (ptr->OperStatus == IfOperStatusUp &&
00596                             ptr->IfType != IF_TYPE_SOFTWARE_LOOPBACK)
00597                         linkUp = TRUE;
00598                 }
00599                 mLinkUp = linkUp;
00600                 mStatusKnown = TRUE;
00601             }
00602             free(addresses);
00603         }
00604     }
00605     return ret;
00606 }
00607 
00613 void
00614 nsNotifyAddrListener::CheckLinkStatus(void)
00615 {
00616     DWORD ret;
00617     const char *event;
00618 
00619     ret = CheckAdaptersAddresses();
00620     if (ret == ERROR_NOT_SUPPORTED)
00621         ret = CheckAdaptersInfo();
00622     if (ret == ERROR_NOT_SUPPORTED)
00623         ret = CheckIPAddrTable();
00624     if (ret != ERROR_SUCCESS)
00625         mLinkUp = PR_TRUE; // I can't tell, so assume there's a link
00626 
00627     if (mStatusKnown)
00628         event = mLinkUp ? NS_NETWORK_LINK_DATA_UP : NS_NETWORK_LINK_DATA_DOWN;
00629     else
00630         event = NS_NETWORK_LINK_DATA_UNKNOWN;
00631     SendEventToUI(event);
00632 }