Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

519 lines
12 KiB

/*++
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;
}