From bbe078f6ae7dd6330c0384493de72a8ca59a08d6 Mon Sep 17 00:00:00 2001 From: "tao%netscape.com" Date: Fri, 28 Jun 2002 23:03:52 +0000 Subject: [PATCH] 93002: [distribution]Conn: Use dialup networking (.DUN) when launching mozilla. r=dougt,sr=rpotts. Help Windows NT, 2000, and XP dialup a RAS connection when a network address is unreachable. (c/osmeredith) the controlling pref is "network.autodial-helper.enabled". git-svn-id: svn://10.0.0.236/trunk@124314 18797224-902f-48f8-a5cc-f745e15eee43 --- .../base/public/nsISocketTransportService.idl | 6 + mozilla/netwerk/base/src/Makefile.in | 2 + mozilla/netwerk/base/src/makefile.win | 2 + mozilla/netwerk/base/src/nsAutodialWin.cpp | 674 ++++++++++++++++++ mozilla/netwerk/base/src/nsAutodialWin.h | 176 +++++ mozilla/netwerk/base/src/nsIOService.cpp | 15 +- .../base/src/nsNativeConnectionHelper.cpp | 164 +++++ .../base/src/nsNativeConnectionHelper.h | 57 ++ .../netwerk/base/src/nsSocketTransport.cpp | 83 ++- mozilla/netwerk/base/src/nsSocketTransport.h | 2 +- .../base/src/nsSocketTransportService.cpp | 18 +- .../base/src/nsSocketTransportService.h | 3 + mozilla/netwerk/dns/src/nsDnsService.cpp | 12 +- 13 files changed, 1190 insertions(+), 24 deletions(-) create mode 100644 mozilla/netwerk/base/src/nsAutodialWin.cpp create mode 100644 mozilla/netwerk/base/src/nsAutodialWin.h create mode 100644 mozilla/netwerk/base/src/nsNativeConnectionHelper.cpp create mode 100644 mozilla/netwerk/base/src/nsNativeConnectionHelper.h diff --git a/mozilla/netwerk/base/public/nsISocketTransportService.idl b/mozilla/netwerk/base/public/nsISocketTransportService.idl index f671b0d545b..e48b1793aa5 100644 --- a/mozilla/netwerk/base/public/nsISocketTransportService.idl +++ b/mozilla/netwerk/base/public/nsISocketTransportService.idl @@ -102,6 +102,12 @@ interface nsISocketTransportService : nsISupports * A number of nsSocketTransport objects connected (this may include keep-alive idle connections) */ readonly attribute unsigned long connectedTransportCount; + + /** + * Autodial helper is enabled via pref. + */ + attribute boolean autodialEnabled; + }; %{C++ diff --git a/mozilla/netwerk/base/src/Makefile.in b/mozilla/netwerk/base/src/Makefile.in index 476b9f8c0d5..aab7004e901 100644 --- a/mozilla/netwerk/base/src/Makefile.in +++ b/mozilla/netwerk/base/src/Makefile.in @@ -77,6 +77,8 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),os2) else ifeq ($(MOZ_WIDGET_TOOLKIT),windows) CPPSRCS += nsIOServiceWin.cpp + CPPSRCS += nsNativeConnectionHelper.cpp + CPPSRCS += nsAutodialWin.cpp else CPPSRCS += nsIOServiceUnix.cpp endif diff --git a/mozilla/netwerk/base/src/makefile.win b/mozilla/netwerk/base/src/makefile.win index 50a05bed6b5..5dda629ffd0 100644 --- a/mozilla/netwerk/base/src/makefile.win +++ b/mozilla/netwerk/base/src/makefile.win @@ -68,6 +68,8 @@ CPP_OBJS = \ .\$(OBJDIR)\nsStorageTransport.obj \ .\$(OBJDIR)\nsStreamListenerTee.obj \ .\$(OBJDIR)\nsURIChecker.obj \ + .\$(OBJDIR)\nsNativeConnectionHelper.obj \ + .\$(OBJDIR)\nsAutodialWin.obj \ $(NULL) JSFILES = \ diff --git a/mozilla/netwerk/base/src/nsAutodialWin.cpp b/mozilla/netwerk/base/src/nsAutodialWin.cpp new file mode 100644 index 00000000000..869eb04f618 --- /dev/null +++ b/mozilla/netwerk/base/src/nsAutodialWin.cpp @@ -0,0 +1,674 @@ +/* ***** 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. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Meredith + * + * 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 ***** */ + +// This source is mostly a bunch of Windows API calls. It is only compiled for +// Windows builds. +#include +#include +#include "nsAutodialWin.h" +#include "prlog.h" + +// +// Log module for autodial logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=Autodial:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// + +#ifdef PR_LOGGING +static PRLogModuleInfo* gLog = nsnull; +#endif + +#define LOGD(args) PR_LOG(gLog, PR_LOG_DEBUG, args) +#define LOGE(args) PR_LOG(gLog, PR_LOG_ERROR, args) + +// Don't try to dial again within a few seconds of when user pressed cancel. +#define NO_RETRY_PERIOD_SEC 5 +PRIntervalTime nsRASAutodial::mDontRetryUntil = 0; + + +tRASPHONEBOOKDLG nsRASAutodial::mpRasPhonebookDlg = nsnull; +tRASENUMCONNECTIONS nsRASAutodial::mpRasEnumConnections = nsnull; +tRASENUMENTRIES nsRASAutodial::mpRasEnumEntries = nsnull; +tRASDIALDLG nsRASAutodial::mpRasDialDlg = nsnull; +tRASSETAUTODIALADDRESS nsRASAutodial::mpRasSetAutodialAddress = nsnull; +tRASGETAUTODIALADDRESS nsRASAutodial::mpRasGetAutodialAddress = nsnull; +HINSTANCE nsRASAutodial::mhRASdlg = nsnull; +HINSTANCE nsRASAutodial::mhRASapi32 = nsnull; + +// ctor. +nsRASAutodial::nsRASAutodial() +: mAutodialBehavior(AUTODIAL_NEVER), + mNumRASConnectionEntries(0) +{ + mOSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&mOSVerInfo); + +#ifdef PR_LOGGING + if (!gLog) + gLog = PR_NewLogModule("Autodial"); +#endif + + // We only need to dial on nt based systems. For all other platforms, + // mAutodialBehavior will remain AUTODIAL_NEVER, and we can skip + // these initializations. + if ((mOSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) + && (mOSVerInfo.dwMajorVersion >= 3)) + { + if (!mhRASdlg) + { + mhRASdlg = ::LoadLibrary("rasdlg.dll"); + if ((UINT)mhRASdlg > 32) + { + // RasPhonebookDlg + mpRasPhonebookDlg = + (tRASPHONEBOOKDLG)::GetProcAddress(mhRASdlg, "RasPhonebookDlgA"); + + // RasDialDlg + mpRasDialDlg = + (tRASDIALDLG)::GetProcAddress(mhRASdlg, "RasDialDlgA"); + + } + + if (!mhRASdlg || !mpRasPhonebookDlg || !mpRasDialDlg) + { + LOGE(("Autodial: Error loading RASDLG.DLL.")); + } + } + + if (!mhRASapi32) + { + mhRASapi32 = ::LoadLibrary("rasapi32.dll"); + if ((UINT)mhRASapi32 > 32) + { + // RasEnumConnections + mpRasEnumConnections = (tRASENUMCONNECTIONS) + ::GetProcAddress(mhRASapi32, "RasEnumConnectionsA"); + + // RasEnumEntries + mpRasEnumEntries = (tRASENUMENTRIES) + ::GetProcAddress(mhRASapi32, "RasEnumEntriesA"); + + // RasSetAutodialAddress + mpRasSetAutodialAddress = (tRASSETAUTODIALADDRESS) + ::GetProcAddress(mhRASapi32, "RasSetAutodialAddressA"); + + // RasSetAutodialAddress + mpRasGetAutodialAddress = (tRASGETAUTODIALADDRESS) + ::GetProcAddress(mhRASapi32, "RasGetAutodialAddressA"); + } + + if (!mhRASapi32 + || !mpRasEnumConnections + || !mpRasEnumEntries + || !mpRasSetAutodialAddress + || !mpRasGetAutodialAddress) + { + LOGE(("Autodial: Error loading RASAPI32.DLL.")); + } + } + + // Initializations that can be made again since RAS OS settings can + // change. + Init(); + } +} + +// dtor +nsRASAutodial::~nsRASAutodial() +{ +} + + +// Get settings from the OS. These are settings that might change during +// the OS session. Call Init() again to pick up those changes if required. +// Returns NS_ERROR_FAILURE if error or NS_OK if success. +nsresult nsRASAutodial::Init() +{ + mDefaultEntryName[0] = '\0'; + mNumRASConnectionEntries = 0; + mAutodialBehavior = QueryAutodialBehavior(); + + // No need to continue in this case. + if (mAutodialBehavior == AUTODIAL_NEVER) + { + return NS_OK; + } + + // Get the number of dialup entries in the phonebook. + mNumRASConnectionEntries = NumRASEntries(); + + // Get the name of the default entry. + nsresult result = GetDefaultEntryName(mDefaultEntryName, + RAS_MaxEntryName + 1); + + return result; +} + + +// Should we attempt to dial on a network error? Yes if the Internet Options +// configured as such. Yes if the RAS autodial service is running (we'll +// force it to dail in that case by adding the network address to its db.) +PRBool nsRASAutodial::ShouldDialOnNetworkError() +{ + // Don't try to dial again within a few seconds of when user pressed cancel. + if (mDontRetryUntil) + { + PRIntervalTime intervalNow = PR_IntervalNow(); + if (intervalNow < mDontRetryUntil) + { + LOGD(("Autodial: Not dialing: too soon.")); + return PR_FALSE; + } + } + + + return ((mAutodialBehavior == AUTODIAL_ALWAYS) + || (mAutodialBehavior == AUTODIAL_ON_NETWORKERROR) + || (mAutodialBehavior == AUTODIAL_USE_SERVICE)); +} + + +// The autodial info is set in Control Panel | Internet Options | Connections. +// The values are stored in the registry. This function gets those values from +// the registry and determines if we should never dial, always dial, or dial +// when there is no network found. +int nsRASAutodial::QueryAutodialBehavior() +{ + if (IsAutodialServiceRunning()) + return AUTODIAL_USE_SERVICE; + + HKEY hKey = 0; + LONG result = ::RegOpenKeyEx( + HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", + 0, + KEY_READ, + &hKey); + + if (result != ERROR_SUCCESS) + { + return AUTODIAL_NEVER; + } + + DWORD entryType = 0; + DWORD autodial = 0; + DWORD onDemand = 0; + DWORD paramSize = sizeof(DWORD); + + result = ::RegQueryValueEx(hKey, "EnableAutodial", nsnull, &entryType, (LPBYTE)&autodial, ¶mSize); + if (result != ERROR_SUCCESS) + { + ::RegCloseKey(hKey); + return AUTODIAL_NEVER; + } + + result = ::RegQueryValueEx(hKey, "NoNetAutodial", nsnull, &entryType, (LPBYTE)&onDemand, ¶mSize); + if (result != ERROR_SUCCESS) + { + ::RegCloseKey(hKey); + return AUTODIAL_NEVER; + } + + ::RegCloseKey(hKey); + + if (!autodial) + { + return AUTODIAL_NEVER; + } + else + { + if (onDemand) + { + return AUTODIAL_ON_NETWORKERROR; + } + else + { + return AUTODIAL_ALWAYS; + } + } +} + +// If the RAS autodial service is running, use it. Otherwise, dial +// the default RAS connection. There are two possible RAS dialogs: +// one that dials a single entry, and one that lets the user choose which +// to dial. If there is only one connection entry in the phone book, or +// there are multiple entries but one is defined as the default, we'll use +// the single entry dial dialog. If there are multiple connection entries, +// and none is specified as default, we'll bring up the diallog which lets +// the user select the connection entry to use. +nsresult nsRASAutodial::DialDefault(const char* hostName) +{ + mDontRetryUntil = 0; + + if (mAutodialBehavior == AUTODIAL_NEVER) + { + return NS_ERROR_FAILURE; + } + + // If already a RAS connection, bail. + if (IsRASConnected()) + { + LOGD(("Autodial: Not dialing: active connection.")); + return NS_OK; //NS_ERROR_FAILURE; + } + + // If no dialup connections configured, bail. + if (mNumRASConnectionEntries <= 0) + { + LOGD(("Autodial: Not dialing: no entries.")); + return NS_ERROR_FAILURE; + } + + + // If autodial service is running, let it dial. In order for it to dial + // reliably, we have to add the target address to the autodial database. + // This is the only way the autodial service dial if there is a network + // adapter installed. + // See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rras/ras4over_3dwl.asp + if (mAutodialBehavior == AUTODIAL_USE_SERVICE) + { + if (!AddAddressToAutodialDirectory(hostName)) + return NS_ERROR_FAILURE; + } + + // Do the dialing ourselves. + else + { + // If a default dial entry is configured, use it. + if (mDefaultEntryName[0] != '\0') + { + LOGD(("Autodial: Dialing default: %s.",mDefaultEntryName)); + + RASDIALDLG rasDialDlg; + memset(&rasDialDlg, 0, sizeof(RASDIALDLG)); + rasDialDlg.dwSize = sizeof(RASDIALDLG); + + NS_ASSERTION(mpRasDialDlg != nsnull, + "RAS DLLs only loaded for NT-based OSs."); + + if (!mpRasDialDlg) + { + return NS_ERROR_NULL_POINTER; + } + + PRBool dialed = + (*mpRasDialDlg)(nsnull, mDefaultEntryName, nsnull, &rasDialDlg); + if (!dialed) + { + if (rasDialDlg.dwError != 0) + { + LOGE(("Autodial ::RasDialDlg failed: Error: %d.", + rasDialDlg.dwError)); + } + else + { + mDontRetryUntil = PR_IntervalNow() + PR_SecondsToInterval(NO_RETRY_PERIOD_SEC); + LOGD(("Autodial: User cancelled dial.")); + } + return NS_ERROR_FAILURE; + } + + LOGD(("Autodial: RAS dialup connection successful.")); + } + + // If no default connection specified, open the dialup dialog that lets + // the user specifiy which connection to dial. + else + { + LOGD(("Autodial: Prompting for phonebook entry.")); + + RASPBDLG rasPBDlg; + memset(&rasPBDlg, 0, sizeof(RASPBDLG)); + rasPBDlg.dwSize = sizeof(RASPBDLG); + + NS_ASSERTION(mpRasPhonebookDlg != nsnull, + "RAS DLLs only loaded for NT-based OSs."); + + if (!mpRasPhonebookDlg) + { + return NS_ERROR_NULL_POINTER; + } + + PRBool dialed = (*mpRasPhonebookDlg)(nsnull, nsnull, &rasPBDlg); + + if (!dialed) + { + if (rasPBDlg.dwError != 0) + { + LOGE(("Autodial: ::RasPhonebookDlg failed: Error = %d.", + rasPBDlg.dwError)); + } + else + { + mDontRetryUntil = PR_IntervalNow() + PR_SecondsToInterval(NO_RETRY_PERIOD_SEC); + LOGD(("Autodial: User cancelled dial.")); + } + + return NS_ERROR_FAILURE; + } + + LOGD(("Autodial: RAS dialup connection successful.")); + } + } + + return NS_OK; + +} + +// Check to see if RAS is already connected. +PRBool nsRASAutodial::IsRASConnected() +{ + DWORD connections; + RASCONN rasConn; + rasConn.dwSize = sizeof(RASCONN); + DWORD structSize = sizeof(RASCONN); + + NS_ASSERTION(mpRasEnumConnections != nsnull, + "RAS DLLs only loaded for NT-based OSs."); + + if (!mpRasEnumConnections) + { + return NS_ERROR_NULL_POINTER; + } + + DWORD result = (*mpRasEnumConnections)(&rasConn, &structSize, &connections); + + // ERROR_BUFFER_TOO_SMALL is OK because we only need one struct. + if (result == ERROR_SUCCESS || result == ERROR_BUFFER_TOO_SMALL) + { + return (connections > 0); + } + + LOGE(("Autodial: ::RasEnumConnections failed: Error = %d", result)); + return PR_FALSE; +} + +// Get the first RAS dial entry name from the phonebook. +nsresult nsRASAutodial::GetFirstEntryName(char* entryName, int bufferSize) +{ + RASENTRYNAME rasEntryName; + rasEntryName.dwSize = sizeof(RASENTRYNAME); + DWORD cb = sizeof(RASENTRYNAME); + DWORD cEntries = 0; + + NS_ASSERTION(mpRasEnumEntries != nsnull, + "RAS DLLs only loaded for NT-based OSs."); + + if (!mpRasEnumEntries) + { + return NS_ERROR_NULL_POINTER; + } + + DWORD result = + (*mpRasEnumEntries)(nsnull, nsnull, &rasEntryName, &cb, &cEntries); + + // ERROR_BUFFER_TOO_SMALL is OK because we only need one struct. + if (result == ERROR_SUCCESS || result == ERROR_BUFFER_TOO_SMALL) + { + strncpy(entryName, rasEntryName.szEntryName, bufferSize); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +// Get the number of RAS dial entries in the phonebook. +int nsRASAutodial::NumRASEntries() +{ + RASENTRYNAME rasEntryName; + rasEntryName.dwSize = sizeof(RASENTRYNAME); + DWORD cb = sizeof(RASENTRYNAME); + DWORD cEntries = 0; + + NS_ASSERTION(mpRasEnumEntries != nsnull, + "RAS DLLs only loaded for NT-based OSs."); + + if (!mpRasEnumEntries) + { + return 0; + } + + DWORD result = + (*mpRasEnumEntries)(nsnull, nsnull, &rasEntryName, &cb, &cEntries); + + // ERROR_BUFFER_TOO_SMALL is OK because we only need one struct. + if (result == ERROR_SUCCESS || result == ERROR_BUFFER_TOO_SMALL) + { + return (int)cEntries; + } + + return 0; +} + +// Get the name of the default dial entry. +nsresult nsRASAutodial::GetDefaultEntryName(char* entryName, int bufferSize) +{ + // No RAS dialup entries. + if (mNumRASConnectionEntries <= 0) + { + return NS_ERROR_FAILURE; + } + + // Single RAS dialup entry. Use it as the default to autodail. + if (mNumRASConnectionEntries == 1) + { + return GetFirstEntryName(entryName, bufferSize); + } + + // Multiple RAS dialup entries. If a default configured in the registry, + // use it. + // + // For Windows XP: HKCU/Software/Microsoft/RAS Autodial/Default/DefaultInternet. + // or HKLM/Software/Microsoft/RAS Autodial/Default/DefaultInternet. + // For Windows 2K: HKCU/RemoteAccess/InternetProfile. + + char* key = nsnull; + char* val = nsnull; + + HKEY hKey = 0; + LONG result = 0; + + // Windows NT and 2000 + if ((mOSVerInfo.dwMajorVersion == 4) // Windows NT + || ((mOSVerInfo.dwMajorVersion == 5) && (mOSVerInfo.dwMinorVersion == 0))) // Windows 2000 + { + key = "RemoteAccess"; + val = "InternetProfile"; + + result = ::RegOpenKeyEx( + HKEY_CURRENT_USER, + key, + 0, + KEY_READ, + &hKey); + + if (result != ERROR_SUCCESS) + { + return NS_ERROR_FAILURE; + } + } + else // Windows XP + { + key = "Software\\Microsoft\\RAS Autodial\\Default"; + val = "DefaultInternet"; + + + // Try HKCU first. + result = ::RegOpenKeyEx( + HKEY_CURRENT_USER, + key, + 0, + KEY_READ, + &hKey); + + if (result != ERROR_SUCCESS) + { + // If not present, try HKLM. + result = ::RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + key, + 0, + KEY_READ, + &hKey); + + if (result != ERROR_SUCCESS) + { + return NS_ERROR_FAILURE; + } + } + } + + + DWORD entryType = 0; + DWORD buffSize = bufferSize; + + result = ::RegQueryValueEx(hKey, + val, + nsnull, + &entryType, + (LPBYTE)entryName, + &buffSize); + + ::RegCloseKey(hKey); + + + if (result != ERROR_SUCCESS) + { + // Use first entry if none configured as default. + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + + +// Determine if the autodial service is running on this PC. +PRBool nsRASAutodial::IsAutodialServiceRunning() +{ + SC_HANDLE hSCManager = + OpenSCManager(nsnull, SERVICES_ACTIVE_DATABASE, SERVICE_QUERY_STATUS); + + if (hSCManager == nsnull) + { + LOGE(("Autodial: failed to open service control manager. Error %d.", + ::GetLastError())); + + return PR_FALSE; + } + + SC_HANDLE hService = + OpenService(hSCManager, "RasAuto", SERVICE_QUERY_STATUS); + + if (hSCManager == nsnull) + { + LOGE(("Autodial: failed to open RasAuto service.")); + return PR_FALSE; + } + + SERVICE_STATUS status; + if (!QueryServiceStatus(hService, &status)) + { + LOGE(("Autodial: ::QueryServiceStatus() failed. Error: %d", + ::GetLastError())); + + return PR_FALSE; + } + + return (status.dwCurrentState == SERVICE_RUNNING); +} + +// Add the specified address to the autodial directory. +PRBool nsRASAutodial::AddAddressToAutodialDirectory(const char* hostName) +{ + NS_ASSERTION(mpRasGetAutodialAddress != nsnull, + "RAS DLLs only loaded for NT-based OSs."); + + NS_ASSERTION(mpRasSetAutodialAddress != nsnull, + "RAS DLLs only loaded for NT-based OSs."); + + if (!mpRasGetAutodialAddress || !mpRasSetAutodialAddress) + { + return PR_FALSE; + } + + // First see if there is already a db entry for this address. + DWORD size = 0; + DWORD entries = 0; + + DWORD result = (*mpRasGetAutodialAddress)(hostName, + NULL, + NULL, + &size, + &entries); + + // If there is already an entry in db for this address, return. + if (size != 0) + { + LOGD(("Autodial: Address %s already in autodial db.", hostName)); + return PR_FALSE; + } + + RASAUTODIALENTRY autodialEntry; + autodialEntry.dwSize = sizeof(RASAUTODIALENTRY); + autodialEntry.dwFlags = 0; + autodialEntry.dwDialingLocation = 1; + GetDefaultEntryName(autodialEntry.szEntry, RAS_MaxEntryName); + + result = (*mpRasSetAutodialAddress)(hostName, + 0, + &autodialEntry, + sizeof(RASAUTODIALENTRY), + 1); + + if (result != ERROR_SUCCESS) + { + LOGE(("Autodial ::RasSetAutodialAddress failed result %d.", result)); + return PR_FALSE; + } + + LOGD(("Autodial: Added address %s to RAS autodial db for entry %s.", + hostName, autodialEntry.szEntry)); + + return PR_TRUE; +} + diff --git a/mozilla/netwerk/base/src/nsAutodialWin.h b/mozilla/netwerk/base/src/nsAutodialWin.h new file mode 100644 index 00000000000..821d0cf6e36 --- /dev/null +++ b/mozilla/netwerk/base/src/nsAutodialWin.h @@ -0,0 +1,176 @@ +/* ***** 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. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Meredith + * + * 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 nsAutodialWin_h__ +#define nsAutodialWin_h__ + +#include +#include +#include +#include +#include "nscore.h" +#include "nspr.h" + +#if (WINVER < 0x401) +/* AutoDial address properties. +*/ +typedef struct tagRASAUTODIALENTRYA { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDialingLocation; + CHAR szEntry[RAS_MaxEntryName + 1]; +} RASAUTODIALENTRYA, *LPRASAUTODIALENTRYA; +typedef RASAUTODIALENTRYA RASAUTODIALENTRY, *LPRASAUTODIALENTRY; +#endif // WINVER + +// Loading the RAS DLL dynamically. +typedef DWORD (WINAPI* tRASPHONEBOOKDLG)(LPTSTR,LPTSTR,LPRASPBDLG); +typedef DWORD (WINAPI* tRASDIALDLG)(LPTSTR,LPTSTR,LPTSTR,LPRASDIALDLG); +typedef DWORD (WINAPI* tRASENUMCONNECTIONS)(LPRASCONN,LPDWORD,LPDWORD); +typedef DWORD (WINAPI* tRASENUMENTRIES)(LPTSTR,LPTSTR,LPRASENTRYNAME,LPDWORD,LPDWORD); +typedef DWORD (WINAPI* tRASSETAUTODIALADDRESS)(LPCTSTR,DWORD,LPRASAUTODIALENTRY,DWORD,DWORD); +typedef DWORD (WINAPI* tRASGETAUTODIALADDRESS)(LPCTSTR,LPDWORD,LPRASAUTODIALENTRY,LPDWORD,LPDWORD); + +// For Windows NT 4, 2000, and XP, we sometimes want to open the RAS dialup +// window ourselves, since those versions aren't very nice about it. +// See bug 93002. If the RAS autodial service is running, (Remote Access +// Auto Connection Manager, aka RasAuto) we will force it to dial +// on network error by adding the target address to the autodial +// database. If the service is not running, we will open the RAS dialogs +// instead. +// +// The OS can be configured to always dial, or dial when there is no +// connection. We implement both by dialing when a network error occurs. +// +// An object of this class checks with the OS when it is constructed and +// remembers those settings. If required, it can be resynced with +// the OS at anytime with the Init() method. At the time of implementation, +// the caller creates an object of this class each time a network error occurs. +// In this case, the initialization overhead is not significant, and it will +// guaranteed to be in sync with OS. +// +// To use, create an instance and call ShouldDialOnNetworkError() to determine +// if you should dial or not. That function only return true for the +// target OS's so the caller doesn't have to deal with OS version checking. +// + +class nsRASAutodial +{ +private: + + // + // Some helper functions to query the OS for autodial configuration. + // + + // Determine if the autodial service is running on this PC. + PRBool IsAutodialServiceRunning(); + + // Get the number of RAS connection entries configured from the OS. + int NumRASEntries(); + + // Get the name of the default connection from the OS. + nsresult GetDefaultEntryName(char* entryName, int bufferSize); + + // Get the name of the first RAS dial entry from the OS. + nsresult GetFirstEntryName(char* entryName, int bufferSize); + + // Check to see if RAS already has a dialup connection going. + PRBool IsRASConnected(); + + // Get the autodial behavior from the OS. + int QueryAutodialBehavior(); + + // Add the specified address to the autodial directory. + PRBool AddAddressToAutodialDirectory(const char* hostName); + + // + // Autodial behavior. This comes from the Windows registry, set in the ctor. + // Object won't pick up changes to the registry automatically, but can be + // refreshed at anytime by calling Init(). So if the user changed the + // autodial settings, they wouldn't be noticed unless Init() is called. + int mAutodialBehavior; + + enum { AUTODIAL_NEVER = 1 }; // Never autodial. + enum { AUTODIAL_ALWAYS = 2 }; // Always autodial as set in Internet Options. + enum { AUTODIAL_ON_NETWORKERROR = 3 }; // Autodial when a connection error occurs as set in Internet Options. + enum { AUTODIAL_USE_SERVICE = 4 }; // Use the RAS autodial service to dial. + + // Number of RAS connection entries in the phonebook. + int mNumRASConnectionEntries; + + // Default connection entry name. + char mDefaultEntryName[RAS_MaxEntryName + 1]; + + // Don't try to dial again within a few seconds of when user pressed cancel. + static PRIntervalTime mDontRetryUntil; + + // OS version info. + OSVERSIONINFO mOSVerInfo; + + // DLL instance handles. + static HINSTANCE mhRASdlg; + static HINSTANCE mhRASapi32; + + // DLL function pointers. + static tRASPHONEBOOKDLG mpRasPhonebookDlg; + static tRASENUMCONNECTIONS mpRasEnumConnections; + static tRASENUMENTRIES mpRasEnumEntries; + static tRASDIALDLG mpRasDialDlg; + static tRASSETAUTODIALADDRESS mpRasSetAutodialAddress; + static tRASGETAUTODIALADDRESS mpRasGetAutodialAddress; + +public: + + // ctor + nsRASAutodial(); + + // dtor + virtual ~nsRASAutodial(); + + // Get the autodial info from the OS and init this obj with it. Call it any + // time to refresh the object's settings from the OS. + nsresult Init(); + + // Dial the default RAS dialup connection. + nsresult DialDefault(const char* hostName); + + // Should we try to dial on network error? + PRBool ShouldDialOnNetworkError(); +}; + +#endif // !nsAutodialWin_h__ + diff --git a/mozilla/netwerk/base/src/nsIOService.cpp b/mozilla/netwerk/base/src/nsIOService.cpp index dc8d16b96c1..6ba7f562db9 100644 --- a/mozilla/netwerk/base/src/nsIOService.cpp +++ b/mozilla/netwerk/base/src/nsIOService.cpp @@ -68,6 +68,7 @@ #define PORT_PREF_PREFIX "network.security.ports." #define PORT_PREF(x) PORT_PREF_PREFIX x +#define AUTODIAL_PREF "network.autodial-helper.enabled" static NS_DEFINE_CID(kFileTransportService, NS_FILETRANSPORTSERVICE_CID); static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); @@ -220,8 +221,10 @@ nsIOService::Init() GetPrefBranch(getter_AddRefs(prefBranch)); if (prefBranch) { nsCOMPtr pbi = do_QueryInterface(prefBranch); - if (pbi) + if (pbi) { pbi->AddObserver(PORT_PREF_PREFIX, this, PR_TRUE); + pbi->AddObserver(AUTODIAL_PREF, this, PR_TRUE); + } PrefsChanged(prefBranch); } @@ -965,6 +968,16 @@ nsIOService::PrefsChanged(nsIPrefBranch *prefs, const char *pref) // ...as well as previous blocks to remove. if (!pref || PL_strcmp(pref, PORT_PREF("banned.override")) == 0) ParsePortList(prefs, PORT_PREF("banned.override"), PR_TRUE); + + if (!pref || PL_strcmp(pref, AUTODIAL_PREF) == 0) { + PRBool enableAutodial = PR_FALSE; + nsresult rv = prefs->GetBoolPref(AUTODIAL_PREF, &enableAutodial); + // If pref not found, default to disabled. + if (NS_SUCCEEDED(rv)) { + if (mSocketTransportService) + mSocketTransportService->SetAutodialEnabled(enableAutodial); + } + } } void diff --git a/mozilla/netwerk/base/src/nsNativeConnectionHelper.cpp b/mozilla/netwerk/base/src/nsNativeConnectionHelper.cpp new file mode 100644 index 00000000000..6532d93ee79 --- /dev/null +++ b/mozilla/netwerk/base/src/nsNativeConnectionHelper.cpp @@ -0,0 +1,164 @@ +/* ***** 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. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * Steve Meredith + * + * 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 "nsNativeConnectionHelper.h" +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" +#include "nsAutodialWin.h" +#include "nsIPref.h" + +static NS_DEFINE_IID(kPrefServiceCID, NS_PREF_CID); + +//----------------------------------------------------------------------------- +// nsSyncEvent - implements a synchronous event that runs on the main thread. +// +// XXX move this class into xpcom/proxy +//----------------------------------------------------------------------------- + +class nsSyncEvent +{ +public: + nsSyncEvent() {} + virtual ~nsSyncEvent() {} + + nsresult Dispatch(); + + virtual void HandleEvent() = 0; + +private: + static void* PR_CALLBACK EventHandler (PLEvent *self); + static void PR_CALLBACK EventDestructor (PLEvent *self); + +}; + +nsresult +nsSyncEvent::Dispatch() +{ + nsresult rv; + + nsCOMPtr eqs( + do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr eventQ; + rv = eqs->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE, + getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) return rv; + + PRBool onCurrentThread = PR_FALSE; + eventQ->IsQueueOnCurrentThread(&onCurrentThread); + if (onCurrentThread) { + HandleEvent(); + return NS_OK; + } + + // Otherwise build up an event and post it to the main thread's event queue + // and block before returning. + + + PLEvent *ev = new PLEvent; + if (!ev) + return NS_ERROR_OUT_OF_MEMORY; + + PL_InitEvent(ev, (void *) this, EventHandler, EventDestructor); + + // block until the event is answered + eventQ->PostSynchronousEvent(ev, nsnull); + + return NS_OK; +} + +void* PR_CALLBACK +nsSyncEvent::EventHandler(PLEvent *self) +{ + nsSyncEvent *ev = (nsSyncEvent *) PL_GetEventOwner(self); + if (ev) + ev->HandleEvent(); + + return nsnull; +} + +void PR_CALLBACK +nsSyncEvent::EventDestructor(PLEvent *self) +{ + delete self; +} + + +//----------------------------------------------------------------------------- +// nsOnConnectionFailedEvent +//----------------------------------------------------------------------------- + +class nsOnConnectionFailedEvent : public nsSyncEvent +{ +private: + nsRASAutodial mAutodial; + const char* mHostName; + +public: + nsOnConnectionFailedEvent(const char* hostname) : mRetry(PR_FALSE), mHostName(hostname) { } + + void HandleEvent(); + + PRBool mRetry; +}; + +void nsOnConnectionFailedEvent::HandleEvent() +{ + mRetry = PR_FALSE; + if (mAutodial.ShouldDialOnNetworkError()) { + mRetry = NS_SUCCEEDED(mAutodial.DialDefault(mHostName)); + } +} + + +//----------------------------------------------------------------------------- +// API typically invoked on the socket transport thread +//----------------------------------------------------------------------------- + + +PRBool +nsNativeConnectionHelper::OnConnectionFailed(const char* strHostName) +{ + nsOnConnectionFailedEvent event(strHostName); + if (NS_SUCCEEDED(event.Dispatch())) + return event.mRetry; + + return PR_FALSE; +} diff --git a/mozilla/netwerk/base/src/nsNativeConnectionHelper.h b/mozilla/netwerk/base/src/nsNativeConnectionHelper.h new file mode 100644 index 00000000000..78a252183f3 --- /dev/null +++ b/mozilla/netwerk/base/src/nsNativeConnectionHelper.h @@ -0,0 +1,57 @@ +/* ***** 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. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsNativeConnectionHelper_h__ +#define nsNativeConnectionHelper_h__ + +#include "nscore.h" + +class nsISocketTransport; + +class nsNativeConnectionHelper +{ +public: + /** + * OnConnectionFailed + * + * Return PR_TRUE if the connection should be re-attempted. + */ + static PRBool OnConnectionFailed(const char* strHostName); +}; + +#endif // !nsNativeConnectionHelper_h__ + diff --git a/mozilla/netwerk/base/src/nsSocketTransport.cpp b/mozilla/netwerk/base/src/nsSocketTransport.cpp index 2eabe5a197e..2eb4b45bc7a 100644 --- a/mozilla/netwerk/base/src/nsSocketTransport.cpp +++ b/mozilla/netwerk/base/src/nsSocketTransport.cpp @@ -63,6 +63,10 @@ #include "nsIProxyInfo.h" #include "nsProxyRelease.h" +#if defined(XP_WIN) +#include "nsNativeConnectionHelper.h" +#endif + #if defined(PR_LOGGING) static PRLogModuleInfo *gSocketTransportLog = nsnull; #endif @@ -536,7 +540,9 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags) // on connection failure, reuse next address if one exists if (mStatus == NS_ERROR_CONNECTION_REFUSED) { LOG(("connection failed [this=%x error=%x]\n", this, mStatus)); - if (TryNextAddress()) { + + // Try again? OnConnectionFailed() may exit and re-enter the monitor. + if (OnConnectionFailed(PR_TRUE)) { done = PR_TRUE; continue; } @@ -563,7 +569,9 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags) firedOnStart = mReadRequest->IsInitialized(); if (!firedOnStart && mWriteRequest) firedOnStart = mWriteRequest->IsInitialized(); - if (!firedOnStart && TryNextAddress()) { + + // Try again? OnConnectionFailed() may exit and re-enter the monitor. + if (!firedOnStart && OnConnectionFailed(PR_TRUE)) { // a little bit of hackery here so we'll end up in the // WaitConnect state... mCurrentState = eSocketState_WaitConnect; @@ -619,27 +627,60 @@ nsSocketTransport::Cancel(nsresult status) return NS_OK; } +// Try next address if param says to. Otherwise, try to use autodial. If a +// connection is made, we try the network again. Otherwise, we don't. +// Returns true to cause connection failures to try again. +// PRBool -nsSocketTransport::TryNextAddress() +nsSocketTransport::OnConnectionFailed(PRBool tryNextAddress) { - mNetAddress = mNetAddrList.GetNext(mNetAddress); - if (mNetAddress) { + LOG(("nsSocketTransport Entering OnConnectionFailed()")); + + PRBool tryAgain = PR_FALSE; + + // If required, retry using next address. + if (tryNextAddress) { + + PRNetAddr* nextNetAddress = mNetAddrList.GetNext(mNetAddress); + + if (nextNetAddress) { + mNetAddress = nextNetAddress; + #if defined(PR_LOGGING) - char buf[64]; - PR_NetAddrToString(mNetAddress, buf, sizeof(buf)); - LOG((" ...trying next address: %s\n", buf)); + char buf[64]; + PR_NetAddrToString(mNetAddress, buf, sizeof(buf)); + LOG((" ...trying next address: %s\n", buf)); #endif - PR_Close(mSocketFD); + tryAgain = PR_TRUE; + } + } + + // If not trying next address, try to make a connection using dialup. + // Retry if that connection is made. + if (!tryAgain && mService->mAutodialEnabled) { + +#if defined(XP_WIN) + PR_ExitMonitor(mMonitor); + tryAgain = nsNativeConnectionHelper::OnConnectionFailed(GetSocketHost()); + PR_EnterMonitor(mMonitor); +#endif + } + + // Prepare to try again. + if (tryAgain) + { + if (mSocketFD) + PR_Close(mSocketFD); mSocketFD = nsnull; // mask error status so we'll return to this state mStatus = NS_OK; - // need to re-enter Process() asynchronously mService->AddToWorkQ(this); - return PR_TRUE; } - return PR_FALSE; + + LOG(("nsSocketTransport Leaving OnConnectionFailed() tryAgain = %d",tryAgain)); + return tryAgain; } void @@ -1629,11 +1670,21 @@ nsSocketTransport::OnStopLookup(nsISupports *aContext, // Release our reference to the DNS Request... mDNSRequest = 0; - // If the lookup failed, set the status... - if (NS_FAILED(aStatus)) - mStatus = aStatus; - else if (mNetAddress == nsnull) + // If the lookup failed... + if (NS_FAILED(aStatus)) { + + // Retry? OnConnectionFailed() may exit and re-enter the monitor. + // Don't want to set the tryNextAddress param because DNS lookup has + // just failed so hostname has not been resolved yet. + if (aStatus != NS_BASE_STREAM_WOULD_BLOCK && OnConnectionFailed(PR_FALSE)) + mStatus = NS_OK; + else + mStatus = aStatus; + } + else if (mNetAddress == nsnull) { mStatus = NS_ERROR_ABORT; + } + // Start processing the transport again - if necessary... if (GetFlag(eSocketDNS_Wait)) { diff --git a/mozilla/netwerk/base/src/nsSocketTransport.h b/mozilla/netwerk/base/src/nsSocketTransport.h index a16b7d94131..057e35d4959 100644 --- a/mozilla/netwerk/base/src/nsSocketTransport.h +++ b/mozilla/netwerk/base/src/nsSocketTransport.h @@ -208,7 +208,7 @@ protected: nsresult doReadWrite(PRInt16 aSelectFlags); nsresult doResolveHost(); - PRBool TryNextAddress(); + PRBool OnConnectionFailed(PRBool tryNextAddress); void CompleteAsyncRead(); void CompleteAsyncWrite(); diff --git a/mozilla/netwerk/base/src/nsSocketTransportService.cpp b/mozilla/netwerk/base/src/nsSocketTransportService.cpp index 7a47b18f7de..3c5a1bef5a5 100644 --- a/mozilla/netwerk/base/src/nsSocketTransportService.cpp +++ b/mozilla/netwerk/base/src/nsSocketTransportService.cpp @@ -69,7 +69,8 @@ static NS_DEFINE_CID(kDNSService, NS_DNSSERVICE_CID); nsSocketTransportService::nsSocketTransportService () : mConnectedTransports (0), - mTotalTransports (0) + mTotalTransports (0), + mAutodialEnabled(PR_FALSE) { #if defined(PR_LOGGING) if (!gSocketTransportServiceLog) @@ -937,3 +938,18 @@ nsSocketTransportService::OnTransportConnected(const char *host, PRNetAddr *addr } #endif } + + +NS_IMETHODIMP +nsSocketTransportService::GetAutodialEnabled(PRBool *enabled) +{ + *enabled = mAutodialEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsSocketTransportService::SetAutodialEnabled(PRBool enabled) +{ + mAutodialEnabled = enabled; + return NS_OK; +} \ No newline at end of file diff --git a/mozilla/netwerk/base/src/nsSocketTransportService.h b/mozilla/netwerk/base/src/nsSocketTransportService.h index 89ec8385e5d..dc21b3f5e29 100644 --- a/mozilla/netwerk/base/src/nsSocketTransportService.h +++ b/mozilla/netwerk/base/src/nsSocketTransportService.h @@ -115,6 +115,9 @@ public: nsIDNSService *GetCachedDNSService() { return mDNSService.get(); } nsIEventQueueService *GetCachedEventQueueService() { return mEventQService.get(); } + // Pref to enable autodial helper on windows. + PRBool mAutodialEnabled; + protected: // // mHostDB maps hostname -> nsHostEntry diff --git a/mozilla/netwerk/dns/src/nsDnsService.cpp b/mozilla/netwerk/dns/src/nsDnsService.cpp index 53765e24404..81ea2e85033 100644 --- a/mozilla/netwerk/dns/src/nsDnsService.cpp +++ b/mozilla/netwerk/dns/src/nsDnsService.cpp @@ -1346,12 +1346,12 @@ nsDNSService::Run() // convert InetHostInfo to nsHostEnt lookup->ConvertHostEntry(); } - lookup->ProcessRequests(); if (lookup->IsNotCacheable()) { EvictLookup(lookup); } else { AddToEvictionQ(lookup); } + lookup->ProcessRequests(); NS_RELEASE(lookup); } @@ -1376,12 +1376,12 @@ nsDNSService::Run() // Got a request!! NS_ADDREF(lookup); // keep the lookup while we process it lookup->DoSyncLookup(); - lookup->ProcessRequests(); if (lookup->IsNotCacheable()) { EvictLookup(lookup); } else { AddToEvictionQ(lookup); } + lookup->ProcessRequests(); NS_RELEASE(lookup); } else { // Woken up without a request --> shutdown @@ -1495,7 +1495,6 @@ nsDNSService::Lookup(const char* hostName, if (NS_FAILED(rv)) goto exit; if (lookup->IsComplete()) { - lookup->ProcessRequests(); // releases and re-acquires dns lock if (lookup->IsNotCacheable()) { // non-cacheable lookups are released here. EvictLookup(lookup); @@ -1505,6 +1504,7 @@ nsDNSService::Lookup(const char* hostName, AddToEvictionQ(lookup); #endif } + lookup->ProcessRequests(); // releases and re-acquires dns lock } exit: @@ -1639,8 +1639,10 @@ nsDNSService::AbortLookups() while(lookup != &mPendingQ) { PR_REMOVE_AND_INIT_LINK(lookup); lookup->MarkComplete(NS_BINDING_ABORTED); - lookup->ProcessRequests(); + NS_ADDREF(lookup); EvictLookup(lookup); + lookup->ProcessRequests(); + NS_RELEASE(lookup); lookup = (nsDNSLookup *)PR_LIST_HEAD(&mPendingQ); } @@ -1974,12 +1976,12 @@ nsDNSService::ProcessLookup(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) FreeMsgID(lookup->mMsgID); PR_REMOVE_AND_INIT_LINK(lookup); - lookup->ProcessRequests(); if (lookup->IsNotCacheable()) { EvictLookup(lookup); } else { AddToEvictionQ(lookup); } + lookup->ProcessRequests(); NS_RELEASE(lookup); return error ? -1 : 0;