Bug 465158 - Minefield Nightly fails to initiate dial-up login when using internet connection sharing, r=cbiesinger

This commit is contained in:
Honza Bambas 2009-03-18 15:52:31 +01:00
Родитель 417896cb6b
Коммит 4596cdf3f9
4 изменённых файлов: 224 добавлений и 55 удалений

Просмотреть файл

@ -167,6 +167,7 @@ nsIOService::nsIOService()
, mOfflineForProfileChange(PR_FALSE)
, mSettingOffline(PR_FALSE)
, mSetOfflineValue(PR_FALSE)
, mShutdown(PR_FALSE)
, mManageOfflineStatus(PR_TRUE)
, mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY)
, mContentSniffers(NS_CONTENT_SNIFFER_CATEGORY)
@ -617,6 +618,11 @@ nsIOService::GetOffline(PRBool *offline)
NS_IMETHODIMP
nsIOService::SetOffline(PRBool offline)
{
// When someone wants to go online (!offline) after we got XPCOM shutdown
// throw ERROR_NOT_AVAILABLE to prevent return to online state.
if (mShutdown && !offline)
return NS_ERROR_NOT_AVAILABLE;
// 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
@ -834,6 +840,11 @@ nsIOService::Observe(nsISupports *subject,
}
}
else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
// Remember we passed XPCOM shutdown notification to prevent any
// changes of the offline status from now. We must not allow going
// online after this point.
mShutdown = PR_TRUE;
SetOffline(PR_TRUE);
// Break circular reference.
@ -950,6 +961,9 @@ nsIOService::TrackNetworkLinkStatusForOffline()
"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) {

Просмотреть файл

@ -140,6 +140,8 @@ private:
PRPackedBool mSettingOffline;
PRPackedBool mSetOfflineValue;
PRPackedBool mShutdown;
nsCOMPtr<nsPISocketTransportService> mSocketTransportService;
nsCOMPtr<nsPIDNSService> mDNSService;
nsCOMPtr<nsIProtocolProxyService2> mProxyService;

Просмотреть файл

@ -41,9 +41,9 @@
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
#include <winsock2.h>
#include <NetCon.h>
#include <objbase.h>
#include <iprtrmib.h>
#include <time.h>
#include "prmem.h"
#include "plstr.h"
#include "nsThreadUtils.h"
@ -51,6 +51,7 @@
#include "nsServiceManagerUtils.h"
#include "nsNotifyAddrListener.h"
#include "nsString.h"
#include "nsAutoPtr.h"
#include <iptypes.h>
#include <iphlpapi.h>
@ -62,48 +63,65 @@ 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);
typedef void (WINAPI *NcFreeNetconPropertiesFunc)(NETCON_PROPERTIES*);
static HMODULE sIPHelper;
static HMODULE sIPHelper, sNetshell;
static GetAdaptersAddressesFunc sGetAdaptersAddresses;
static GetAdaptersInfoFunc sGetAdaptersInfo;
static GetIfEntryFunc sGetIfEntry;
static GetIpAddrTableFunc sGetIpAddrTable;
static NotifyAddrChangeFunc sNotifyAddrChange;
static NcFreeNetconPropertiesFunc sNcFreeNetconProperties;
static void InitIPHelperLibrary(void)
{
if (sIPHelper)
return;
sIPHelper = LoadLibraryW(L"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");
if (!sIPHelper) {
sIPHelper = LoadLibraryW(L"iphlpapi.dll");
if (sIPHelper) {
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)
static void InitNetshellLibrary(void)
{
if (!sIPHelper)
return;
if (!sNetshell) {
sNetshell = LoadLibraryW(L"Netshell.dll");
if (sNetshell) {
sNcFreeNetconProperties = (NcFreeNetconPropertiesFunc)
GetProcAddress(sNetshell, "NcFreeNetconProperties");
}
}
}
sGetAdaptersAddresses = nsnull;
sGetAdaptersInfo = nsnull;
sGetIfEntry = nsnull;
sGetIpAddrTable = nsnull;
sNotifyAddrChange = nsnull;
static void FreeDynamicLibraries(void)
{
if (sIPHelper)
{
sGetAdaptersAddresses = nsnull;
sGetAdaptersInfo = nsnull;
sGetIfEntry = nsnull;
sGetIpAddrTable = nsnull;
sNotifyAddrChange = nsnull;
FreeLibrary(sIPHelper);
sIPHelper = nsnull;
FreeLibrary(sIPHelper);
sIPHelper = nsnull;
}
if (sNetshell) {
sNcFreeNetconProperties = nsnull;
FreeLibrary(sNetshell);
sNetshell = nsnull;
}
}
NS_IMPL_THREADSAFE_ISUPPORTS3(nsNotifyAddrListener,
@ -114,22 +132,27 @@ NS_IMPL_THREADSAFE_ISUPPORTS3(nsNotifyAddrListener,
nsNotifyAddrListener::nsNotifyAddrListener()
: mLinkUp(PR_TRUE) // assume true by default
, mStatusKnown(PR_FALSE)
, mCheckAttempted(PR_FALSE)
, mShutdownEvent(nsnull)
{
mOSVerInfo.dwOSVersionInfoSize = sizeof(mOSVerInfo);
GetVersionEx(&mOSVerInfo);
InitIPHelperLibrary();
}
nsNotifyAddrListener::~nsNotifyAddrListener()
{
NS_ASSERTION(!mThread, "nsNotifyAddrListener thread shutdown failed");
FreeIPHelperLibrary();
FreeDynamicLibraries();
}
NS_IMETHODIMP
nsNotifyAddrListener::GetIsLinkUp(PRBool *aIsUp)
{
if (!mCheckAttempted && !mStatusKnown) {
mCheckAttempted = PR_TRUE;
CheckLinkStatus();
}
*aIsUp = mLinkUp;
return NS_OK;
}
@ -151,6 +174,8 @@ nsNotifyAddrListener::Run()
OVERLAPPED overlapped = { 0 };
PRBool shuttingDown = PR_FALSE;
InitIPHelperLibrary();
overlapped.hEvent = ev;
while (!shuttingDown) {
HANDLE h;
@ -318,7 +343,9 @@ nsNotifyAddrListener::CheckIPAddrTable(void)
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)
table->table[i].dwAddr != 0 &&
// Nor a loopback
table->table[i].dwAddr != 0x0100007F)
linkUp = PR_TRUE;
}
mLinkUp = linkUp;
@ -350,7 +377,11 @@ nsNotifyAddrListener::CheckAdaptersInfo(void)
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) {
if (!adapters)
return ERROR_OUTOFMEMORY;
ret = sGetAdaptersInfo(adapters, &adaptersLen);
if (ret == ERROR_SUCCESS) {
PRBool linkUp = PR_FALSE;
PIP_ADAPTER_INFO ptr;
@ -368,9 +399,11 @@ nsNotifyAddrListener::CheckAdaptersInfo(void)
else {
PIP_ADDR_STRING ipAddr;
for (ipAddr = &ptr->IpAddressList; ipAddr && !linkUp;
ipAddr = ipAddr->Next)
if (PL_strcmp(ipAddr->IpAddress.String, "0.0.0.0"))
ipAddr = ipAddr->Next) {
if (PL_strcmp(ipAddr->IpAddress.String, "0.0.0.0")) {
linkUp = PR_TRUE;
}
}
}
}
}
@ -382,6 +415,113 @@ nsNotifyAddrListener::CheckAdaptersInfo(void)
return ret;
}
BOOL
nsNotifyAddrListener::CheckIsGateway(PIP_ADAPTER_ADDRESSES aAdapter)
{
if (!aAdapter->FirstUnicastAddress)
return FALSE;
LPSOCKADDR aAddress = aAdapter->FirstUnicastAddress->Address.lpSockaddr;
if (!aAddress)
return FALSE;
PSOCKADDR_IN in_addr = (PSOCKADDR_IN)aAddress;
PRBool isGateway = (aAddress->sa_family == AF_INET &&
in_addr->sin_addr.S_un.S_un_b.s_b1 == 192 &&
in_addr->sin_addr.S_un.S_un_b.s_b2 == 168 &&
in_addr->sin_addr.S_un.S_un_b.s_b3 == 0 &&
in_addr->sin_addr.S_un.S_un_b.s_b4 == 1);
if (isGateway)
isGateway = CheckICSStatus(aAdapter->FriendlyName);
return isGateway;
}
BOOL
nsNotifyAddrListener::CheckICSStatus(PWCHAR aAdapterName)
{
InitNetshellLibrary();
// This method enumerates all privately shared connections and checks if some
// of them has the same name as the one provided in aAdapterName. If such
// connection is found in the collection the adapter is used as ICS gateway
BOOL isICSGatewayAdapter = FALSE;
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
return FALSE;
nsRefPtr<INetSharingManager> netSharingManager;
hr = CoCreateInstance(
CLSID_NetSharingManager,
NULL,
CLSCTX_INPROC_SERVER,
IID_INetSharingManager,
getter_AddRefs(netSharingManager));
nsRefPtr<INetSharingPrivateConnectionCollection> privateCollection;
if (SUCCEEDED(hr)) {
hr = netSharingManager->get_EnumPrivateConnections(
ICSSC_DEFAULT,
getter_AddRefs(privateCollection));
}
nsRefPtr<IEnumNetSharingPrivateConnection> privateEnum;
if (SUCCEEDED(hr)) {
nsRefPtr<IUnknown> privateEnumUnknown;
hr = privateCollection->get__NewEnum(getter_AddRefs(privateEnumUnknown));
if (SUCCEEDED(hr)) {
hr = privateEnumUnknown->QueryInterface(
IID_IEnumNetSharingPrivateConnection,
getter_AddRefs(privateEnum));
}
}
if (SUCCEEDED(hr)) {
ULONG fetched;
VARIANT connectionVariant;
while (!isICSGatewayAdapter &&
SUCCEEDED(hr = privateEnum->Next(1, &connectionVariant,
&fetched)) &&
fetched) {
if (connectionVariant.vt != VT_UNKNOWN) {
// We should call VariantClear here but it needs to link
// with oleaut32.lib that produces a Ts incrase about 10ms
// that is undesired. As it is quit unlikely the result would
// be of a different type anyway, let's pass the variant
// unfreed here.
NS_ERROR("Variant of unexpected type, expecting VT_UNKNOWN, we probably leak it!");
continue;
}
nsRefPtr<INetConnection> connection;
hr = connectionVariant.punkVal->QueryInterface(
IID_INetConnection,
getter_AddRefs(connection));
connectionVariant.punkVal->Release();
NETCON_PROPERTIES *properties;
if (SUCCEEDED(hr))
hr = connection->GetProperties(&properties);
if (SUCCEEDED(hr)) {
if (!wcscmp(properties->pszwName, aAdapterName))
isICSGatewayAdapter = TRUE;
if (sNcFreeNetconProperties)
sNcFreeNetconProperties(properties);
}
}
}
CoUninitialize();
return isICSGatewayAdapter;
}
DWORD
nsNotifyAddrListener::CheckAdaptersAddresses(void)
{
@ -392,28 +532,36 @@ nsNotifyAddrListener::CheckAdaptersAddresses(void)
if (!sGetAdaptersAddresses)
return ERROR_NOT_SUPPORTED;
ULONG len = 0;
ULONG len = 16384;
DWORD ret = sGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len);
PIP_ADAPTER_ADDRESSES addresses = (PIP_ADAPTER_ADDRESSES) malloc(len);
if (!addresses)
return ERROR_OUTOFMEMORY;
DWORD ret = sGetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &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);
}
free(addresses);
addresses = (PIP_ADAPTER_ADDRESSES) malloc(len);
if (!addresses)
return ERROR_BUFFER_OVERFLOW;
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 &&
!CheckIsGateway(ptr))
linkUp = TRUE;
}
mLinkUp = linkUp;
mStatusKnown = TRUE;
}
free(addresses);
return ret;
}

Просмотреть файл

@ -39,6 +39,8 @@
#define NSNOTIFYADDRLISTENER_H_
#include <windows.h>
#include <winsock2.h>
#include <iptypes.h>
#include "nsINetworkLinkService.h"
#include "nsIRunnable.h"
#include "nsIObserver.h"
@ -74,6 +76,7 @@ protected:
PRPackedBool mLinkUp;
PRPackedBool mStatusKnown;
PRPackedBool mCheckAttempted;
nsresult Shutdown(void);
nsresult SendEventToUI(const char *aEventID);
@ -82,6 +85,8 @@ protected:
DWORD CheckIPAddrTable(void);
DWORD CheckAdaptersInfo(void);
DWORD CheckAdaptersAddresses(void);
BOOL CheckIsGateway(PIP_ADAPTER_ADDRESSES aAdapter);
BOOL CheckICSStatus(PWCHAR aAdapterName);
void CheckLinkStatus(void);
nsCOMPtr<nsIThread> mThread;