520 lines
12 KiB
C++
520 lines
12 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1997 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
wan.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This is the source file relating to the WAN-specific routines of the
|
|||
|
Connectivity APIs implementation.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Gopal Parupudi <GopalP>
|
|||
|
|
|||
|
[Notes:]
|
|||
|
|
|||
|
optional-notes
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
GopalP 10/11/1997 Start.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include <precomp.hxx>
|
|||
|
|
|||
|
//
|
|||
|
// Typedefs
|
|||
|
//
|
|||
|
typedef DWORD (APIENTRY *LPFN_RAS_ENUM)(LPRASCONN, LPDWORD, LPDWORD);
|
|||
|
typedef BOOL (APIENTRY *LPFN_DO_CONNECTOIDS_EXIST)(void);
|
|||
|
typedef DWORD (APIENTRY *LPFN_RAS_CONNECTION_NOTIFICATION)(HRASCONN, HANDLE, DWORD);
|
|||
|
typedef DWORD (APIENTRY *LPFN_RAS_GET_CONNECT_STATUS)(HRASCONN, LPRASCONNSTATUS);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Constants
|
|||
|
//
|
|||
|
#define RAS_DLL SENS_STRING("RasApi32.dll")
|
|||
|
#define WININET_DLL SENS_STRING("Wininet.dll")
|
|||
|
|
|||
|
#if !defined(SENS_CHICAGO)
|
|||
|
#define RAS_ENUM "RasEnumConnectionsW"
|
|||
|
#define RAS_CONNECTION_NOTIFICATION "RasConnectionNotificationW"
|
|||
|
#else // SENS_CHICAGO
|
|||
|
#define RAS_ENUM "RasEnumConnectionsA"
|
|||
|
#define RAS_CONNECTION_NOTIFICATION "RasConnectionNotificationA"
|
|||
|
#define RAS_GET_CONNECT_STATUS "RasGetConnectStatusA"
|
|||
|
#define DO_CONNECTOIDS_EXIST (LPCSTR) 101 // Ordinal 101
|
|||
|
#endif // SENS_CHICAGO
|
|||
|
|
|||
|
#if (WINVER < 0x401)
|
|||
|
#define RASCN_Connection 0x00000001
|
|||
|
#define RASCN_Disconnection 0x00000002
|
|||
|
#endif // WINVER < 0x401
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Globals
|
|||
|
//
|
|||
|
|
|||
|
// Common
|
|||
|
long gdwLastWANTime;
|
|||
|
long gdwWANState;
|
|||
|
BOOL gbIsRasInstalled;
|
|||
|
LPFN_RAS_ENUM glpfnRasEnumConnections;
|
|||
|
LPFN_RAS_CONNECTION_NOTIFICATION glpfnRasConnectionNotification;
|
|||
|
|
|||
|
// IE5-specific
|
|||
|
#if !defined(SENS_NT5)
|
|||
|
HANDLE ghRasEvents[2];
|
|||
|
HANDLE ghConnectWait;
|
|||
|
HANDLE ghDisconnectWait;
|
|||
|
#endif // SENS_NT5
|
|||
|
|
|||
|
// Win9x-specific
|
|||
|
#if defined(SENS_CHICAGO)
|
|||
|
LPFN_RAS_GET_CONNECT_STATUS glpfnRasGetConnectStatus;
|
|||
|
#endif // SENS_CHICAGO
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
inline void
|
|||
|
LoadRasIfNecessary(
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Load RAS DLL, if necessary.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HMODULE hDLL;
|
|||
|
|
|||
|
//
|
|||
|
// See if RAS DLL is already loaded.
|
|||
|
//
|
|||
|
if (NULL != glpfnRasEnumConnections)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do the necessary work.
|
|||
|
//
|
|||
|
hDLL = LoadLibrary(RAS_DLL);
|
|||
|
if (hDLL != NULL)
|
|||
|
{
|
|||
|
glpfnRasEnumConnections = (LPFN_RAS_ENUM) GetProcAddress(hDLL, RAS_ENUM);
|
|||
|
glpfnRasConnectionNotification = (LPFN_RAS_CONNECTION_NOTIFICATION)
|
|||
|
GetProcAddress(hDLL, RAS_CONNECTION_NOTIFICATION);
|
|||
|
#if defined(SENS_CHICAGO)
|
|||
|
glpfnRasGetConnectStatus = (LPFN_RAS_GET_CONNECT_STATUS)
|
|||
|
GetProcAddress(hDLL, RAS_GET_CONNECT_STATUS);
|
|||
|
#endif // SENS_CHICAGO
|
|||
|
|
|||
|
if (
|
|||
|
(NULL == glpfnRasEnumConnections)
|
|||
|
#if defined(SENS_CHICAGO)
|
|||
|
&& (NULL == glpfnRasGetConnectStatus)
|
|||
|
#endif // SENS_CHICAGO
|
|||
|
)
|
|||
|
{
|
|||
|
// Both entrypoints are NULL. Can't do much with RAS now.
|
|||
|
FreeLibrary(hDLL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SensPrintA(SENS_INFO, ("[SENS] LoadRasIfNecessary(): RAS DLL is %spresent.\n",
|
|||
|
(glpfnRasEnumConnections ? "" : "NOT ")));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DoWanSetup(
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Do minimal WAN Setup.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE, if successful.
|
|||
|
|
|||
|
FALSE, otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD dwLastError;
|
|||
|
DWORD dwCurrentRasState;
|
|||
|
BOOL bStatus;
|
|||
|
|
|||
|
dwLastError = 0;
|
|||
|
dwCurrentRasState = 0;
|
|||
|
bStatus = FALSE;
|
|||
|
glpfnRasEnumConnections = NULL;
|
|||
|
glpfnRasConnectionNotification = NULL;
|
|||
|
gbIsRasInstalled = FALSE;
|
|||
|
bStatus = TRUE;
|
|||
|
|
|||
|
Cleanup:
|
|||
|
//
|
|||
|
// Cleanup
|
|||
|
//
|
|||
|
return bStatus;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
IsRasInstalled(
|
|||
|
OUT LPDWORD lpdwState,
|
|||
|
OUT LPDWORD lpdwLastError
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Check to see if RAS is installed. If so, return it's current state.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
lpdwState - If Ras is installed, this parameter contains the current state
|
|||
|
of the RasMan service.
|
|||
|
|
|||
|
lpdwLastError - If RAS is not active or installed, it retuns the GLE.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE, if Ras is installed.
|
|||
|
|
|||
|
FALSE, otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (TRUE == gbIsRasInstalled)
|
|||
|
{
|
|||
|
*lpdwState = SERVICE_RUNNING; // For NT
|
|||
|
*lpdwLastError = ERROR_SUCCESS;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
static SC_HANDLE hSCM; // Cache the handle.
|
|||
|
static SC_HANDLE hRasMan; // Cache the handle.
|
|||
|
|
|||
|
BOOL bRetValue;
|
|||
|
SERVICE_STATUS ServiceStatus;
|
|||
|
|
|||
|
bRetValue = FALSE;
|
|||
|
*lpdwState = 0;
|
|||
|
*lpdwLastError = ERROR_SUCCESS;
|
|||
|
|
|||
|
if (NULL == hSCM)
|
|||
|
{
|
|||
|
hSCM = OpenSCManager(
|
|||
|
NULL, // Local machine
|
|||
|
NULL, // Default database - SERVICES_ACTIVE_DATABASE
|
|||
|
SC_MANAGER_ALL_ACCESS // NOTE: Only for Administrators
|
|||
|
);
|
|||
|
if (NULL == hSCM)
|
|||
|
{
|
|||
|
SensPrintA(SENS_ERR, ("OpenSCManager() returned %d\n", *lpdwLastError));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (hRasMan == NULL)
|
|||
|
{
|
|||
|
hRasMan = OpenService(
|
|||
|
hSCM, // Handle to SCM database
|
|||
|
RAS_MANAGER, // Name of the service to start
|
|||
|
SERVICE_QUERY_STATUS // Type of access requested
|
|||
|
);
|
|||
|
if (NULL == hRasMan)
|
|||
|
{
|
|||
|
SensPrintA(SENS_ERR, ("OpenService() returned %d\n", *lpdwLastError));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
memset(&ServiceStatus, 0, sizeof(SERVICE_STATUS));
|
|||
|
|
|||
|
bRetValue = QueryServiceStatus(
|
|||
|
hRasMan,
|
|||
|
&ServiceStatus
|
|||
|
);
|
|||
|
ASSERT(bRetValue == TRUE);
|
|||
|
|
|||
|
if (FALSE == bRetValue)
|
|||
|
{
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
*lpdwState = ServiceStatus.dwCurrentState;
|
|||
|
|
|||
|
gbIsRasInstalled = TRUE;
|
|||
|
|
|||
|
SensPrintA(SENS_ERR, ("IsRasInstalled(): RASMAN state is %d\n",
|
|||
|
*lpdwState));
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
Cleanup:
|
|||
|
//
|
|||
|
// Cleanup
|
|||
|
//
|
|||
|
*lpdwLastError = GetLastError();
|
|||
|
|
|||
|
if (hSCM)
|
|||
|
{
|
|||
|
CloseServiceHandle(hSCM);
|
|||
|
hSCM = NULL;
|
|||
|
}
|
|||
|
if (hRasMan)
|
|||
|
{
|
|||
|
CloseServiceHandle(hRasMan);
|
|||
|
hRasMan = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL WINAPI
|
|||
|
EvaluateWanConnectivity(
|
|||
|
OUT LPDWORD lpdwLastError
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL bWanAlive;
|
|||
|
BOOL bRasInstalled;
|
|||
|
DWORD dwNow;
|
|||
|
DWORD dwCurrentRasState;
|
|||
|
SERVICE_STATUS ServiceStatus;
|
|||
|
PWCHAR szEntryName;
|
|||
|
DWORD dwLocalLastError;
|
|||
|
|
|||
|
dwNow = GetTickCount();
|
|||
|
bWanAlive = FALSE;
|
|||
|
dwCurrentRasState = 0;
|
|||
|
dwLocalLastError = ERROR_NO_NETWORK;
|
|||
|
|
|||
|
if (lpdwLastError)
|
|||
|
{
|
|||
|
*lpdwLastError = dwLocalLastError;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
lpdwLastError = &dwLocalLastError;
|
|||
|
}
|
|||
|
|
|||
|
szEntryName = new WCHAR[RAS_MaxEntryName + 1];
|
|||
|
if (!szEntryName )
|
|||
|
{
|
|||
|
*lpdwLastError = ERROR_OUTOFMEMORY;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
wcscpy(szEntryName, DEFAULT_WAN_CONNECTION_NAME);
|
|||
|
|
|||
|
//
|
|||
|
// If RasManager is running, it implies that there "might" be one or more
|
|||
|
// active RAS connections.
|
|||
|
//
|
|||
|
bRasInstalled = IsRasInstalled(&dwCurrentRasState, lpdwLastError);
|
|||
|
|
|||
|
if (TRUE == bRasInstalled)
|
|||
|
{
|
|||
|
LoadRasIfNecessary();
|
|||
|
}
|
|||
|
|
|||
|
if ( (bRasInstalled)
|
|||
|
&& (dwCurrentRasState == SERVICE_RUNNING)
|
|||
|
&& (glpfnRasEnumConnections != NULL))
|
|||
|
{
|
|||
|
DWORD dwRasStatus;
|
|||
|
DWORD cBytes;
|
|||
|
DWORD cBytesOld;
|
|||
|
DWORD cConnections;
|
|||
|
RASCONN *pRasConn;
|
|||
|
|
|||
|
dwRasStatus = 0x0;
|
|||
|
cConnections = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Start with loop with a single structure. Will loop and realloc if we need
|
|||
|
// a larger buffer.
|
|||
|
//
|
|||
|
cBytesOld = 0;
|
|||
|
cBytes = sizeof(RASCONN);
|
|||
|
pRasConn = NULL;
|
|||
|
dwRasStatus = ERROR_BUFFER_TOO_SMALL;
|
|||
|
|
|||
|
//
|
|||
|
// Loop till RasEnumConnections() succeeds or returns with an error
|
|||
|
// other than ERROR_BUFFER_TOO_SMALL.
|
|||
|
//
|
|||
|
while (ERROR_BUFFER_TOO_SMALL == dwRasStatus)
|
|||
|
{
|
|||
|
ASSERT(cBytes > cBytesOld);
|
|||
|
ASSERT(pRasConn == NULL);
|
|||
|
|
|||
|
// Allocate the buffer
|
|||
|
pRasConn = (RASCONN *) new char[cBytes];
|
|||
|
if (pRasConn == NULL)
|
|||
|
{
|
|||
|
delete szEntryName;
|
|||
|
*lpdwLastError = ERROR_OUTOFMEMORY;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
pRasConn[0].dwSize = sizeof(RASCONN);
|
|||
|
cBytesOld = cBytes;
|
|||
|
|
|||
|
dwRasStatus = (*glpfnRasEnumConnections)(
|
|||
|
pRasConn,
|
|||
|
&cBytes,
|
|||
|
&cConnections
|
|||
|
);
|
|||
|
|
|||
|
// Free the too small buffer.
|
|||
|
if (ERROR_BUFFER_TOO_SMALL == dwRasStatus)
|
|||
|
{
|
|||
|
delete pRasConn;
|
|||
|
pRasConn = NULL;
|
|||
|
SensPrintA(SENS_WARN, ("RasEnumConnections(): reallocing buffer to be %d bytes\n", cBytes));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((0 == dwRasStatus) &&
|
|||
|
(cConnections > 0))
|
|||
|
{
|
|||
|
bWanAlive = TRUE;
|
|||
|
SensPrintA(SENS_INFO, ("RasEnumConnections(%d) successful connections (%d)\n", cBytes, cConnections));
|
|||
|
|
|||
|
// P3 BUG: we're only dealing with one RAS connection for now
|
|||
|
SensPrintA(SENS_INFO, ("\tConnection name: %s\n", pRasConn->szEntryName));
|
|||
|
|
|||
|
wcscpy(szEntryName, pRasConn->szEntryName);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (dwRasStatus != 0)
|
|||
|
{
|
|||
|
*lpdwLastError = dwRasStatus;
|
|||
|
}
|
|||
|
SensPrintA(SENS_ERR, ("RasEnumConnections() returned %d - "
|
|||
|
"connections (%d)\n", dwRasStatus, cConnections));
|
|||
|
}
|
|||
|
|
|||
|
// Delete the RASCONN structure.
|
|||
|
delete pRasConn;
|
|||
|
|
|||
|
} // if (bRasInstalled)
|
|||
|
|
|||
|
|
|||
|
SensPrintA(SENS_INFO, ("EvaluateWanConnectivity() returning %s, GLE of %d\n",
|
|||
|
bWanAlive ? "TRUE" : "FALSE", *lpdwLastError));
|
|||
|
|
|||
|
|
|||
|
if (InterlockedExchange(&gdwWANState, bWanAlive) != bWanAlive)
|
|||
|
{
|
|||
|
//
|
|||
|
// WAN Connectivity state changed.
|
|||
|
//
|
|||
|
BOOL bSuccess;
|
|||
|
DWORD dwActiveWanInterfaceSpeed;
|
|||
|
DWORD dwLastError;
|
|||
|
SENSEVENT_NETALIVE Data;
|
|||
|
|
|||
|
dwLastError = ERROR_SUCCESS;
|
|||
|
dwActiveWanInterfaceSpeed = 0x0;
|
|||
|
|
|||
|
if (bWanAlive)
|
|||
|
{
|
|||
|
bSuccess = GetActiveWanInterfaceStatistics(
|
|||
|
&dwLastError,
|
|||
|
&dwActiveWanInterfaceSpeed
|
|||
|
);
|
|||
|
#ifdef SENS_NT5
|
|||
|
// Will always fire on NT4/Win9x (due to bugs). Can fire on NT5.
|
|||
|
SensPrintA(SENS_WARN, ("GetActiveWanInterfaceStatistics() returned"
|
|||
|
" FALSE, using defaults!\n"));
|
|||
|
#endif // SENS_NT5
|
|||
|
}
|
|||
|
|
|||
|
Data.eType = SENS_EVENT_NETALIVE;
|
|||
|
Data.bAlive = bWanAlive;
|
|||
|
memset(&Data.QocInfo, 0x0, sizeof(QOCINFO));
|
|||
|
Data.QocInfo.dwSize = sizeof(QOCINFO);
|
|||
|
Data.QocInfo.dwFlags = NETWORK_ALIVE_WAN;
|
|||
|
Data.QocInfo.dwInSpeed = dwActiveWanInterfaceSpeed;
|
|||
|
Data.QocInfo.dwOutSpeed = dwActiveWanInterfaceSpeed;
|
|||
|
Data.strConnection = szEntryName;
|
|||
|
|
|||
|
UpdateSensCache(WAN);
|
|||
|
|
|||
|
SensFireEvent((PVOID)&Data);
|
|||
|
}
|
|||
|
|
|||
|
if (bWanAlive)
|
|||
|
{
|
|||
|
InterlockedExchange(&gdwLastWANTime, dwNow);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
InterlockedExchange(&gdwLastWANTime, 0x0);
|
|||
|
}
|
|||
|
|
|||
|
SensPrintA(SENS_INFO, ("RasEventNotifyRoutine(%d) - WAN Time is %d msec\n", dwNow, gdwLastWANTime));
|
|||
|
|
|||
|
delete szEntryName;
|
|||
|
|
|||
|
return bWanAlive;
|
|||
|
}
|