|
|
/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
sensapi.cxx
Abstract:
Implementation of the SENS Connectivity APIs. These are just stubs which call into SENS to do the actual work.
Author:
Gopal Parupudi <GopalP>
[Notes:]
optional-notes
Revision History:
GopalP 12/4/1997 Start.
--*/
#include <common.hxx>
#include <windows.h>
#include <api.h>
#include <sensapi.h>
#include <sensapi.hxx>
#include <cache.hxx>
//
// Globals
//
RPC_BINDING_HANDLE ghSens; CRITICAL_SECTION gSensapiLock; DWORD gdwCacheLastUpdatedTime; DWORD gdwCacheFirstReadTime; HANDLE ghSensFileMap; PSENS_CACHE gpSensCache;
BOOL IsNetworkAlive( OUT LPDWORD lpdwFlags ) /*++
Routine Description:
We try to find out if this machine has any network connectivity.
Arguments:
lpdwFlags - Receives information regarding the nature of the machine's network connectivity. It can be on of the following: o NETWORK_ALIVE_WAN o NETWORK_ALIVE_LAN
Notes:
a. This is available only for TCP/IP b. This API does not generate any Network traffic.
Return Value:
TRUE, if there is network connectivity
FALSE, otherwise. Use GetLastError() to retrieve more error information.
--*/ { BOOL bNetState; RPC_STATUS RpcStatus; DWORD fNetNature; DWORD dwLastError;
// Basic parameter checks
if (lpdwFlags == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
// OUT parameter intialization.
*lpdwFlags = 0x0; fNetNature = 0x0; dwLastError = ERROR_SUCCESS; bNetState = FALSE;
if (TRUE == ReadConnectivityCache(lpdwFlags)) { return TRUE; }
//
// Need to contact SENS for information.
//
RpcStatus = DoRpcSetup();
//
// Try to get the state information.
//
if (RPC_S_OK == RpcStatus) { RpcStatus = RPC_IsNetworkAlive( ghSens, &fNetNature, &bNetState, &dwLastError ); }
if ( (RPC_S_OK != RpcStatus) || (RPC_S_SERVER_UNAVAILABLE == dwLastError)) { //
// An RPC failure occurred. We treat this as a success and
// set to return values to default values.
//
bNetState = TRUE; fNetNature = NETWORK_ALIVE_LAN;
if (RPC_S_OK != RpcStatus) { dwLastError = RpcStatus; } }
ASSERT((bNetState == TRUE) || (bNetState == FALSE)); ASSERT(fNetNature <= (NETWORK_ALIVE_LAN | NETWORK_ALIVE_WAN | NETWORK_ALIVE_AOL));
*lpdwFlags = fNetNature; SetLastError(dwLastError);
// Since we retrieved information from SENS directly, reset the flag that
// that indicates that we read from the cache.
gdwCacheFirstReadTime = 0x0;
return (bNetState); }
#if !defined(SENS_CHICAGO)
BOOL IsDestinationReachableA( LPCSTR lpszDestination, LPQOCINFO lpQOCInfo ) /*++
Routine Description:
Given the name of a destination (IP Address, UNC, URL etc), we try to see if it is reachable.
Arguments:
lpszDestination - The destination (an ANSI string) whose rechability is of interest.
lpQOCInfo - Pointer to a buffer that will receive Quality of Connection (QOC) Information. Can be NULL if QOC is not desired.
Notes:
a. This is available only for TCP/IP
Return Value:
TRUE, if the destination is reachable.
FALSE, otherwise. Use GetLastError() to retrieve more error information.
--*/ { BOOL bReachable; NTSTATUS NtStatus; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; size_t uiLength;
// Basic parameter checks
if ( (lpszDestination == NULL) || ((uiLength = strlen(lpszDestination)) > MAX_DESTINATION_LENGTH) || (uiLength == 0)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
// OUT parameter intialization.
bReachable = FALSE;
RtlInitAnsiString(&AnsiString, (PSZ)lpszDestination);
NtStatus = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE ); if (!NT_SUCCESS(NtStatus)) { SetLastError(ERROR_OUTOFMEMORY); // Only possible error.
return bReachable; }
// Call the Unicode version.
bReachable = IsDestinationReachableW( UnicodeString.Buffer, lpQOCInfo );
ASSERT((bReachable == TRUE) || (bReachable == FALSE));
RtlFreeUnicodeString(&UnicodeString);
return (bReachable); }
BOOL IsDestinationReachableW( LPCWSTR lpszDestination, LPQOCINFO lpQOCInfo ) /*++
Routine Description:
Given the name of a destination (IP Address, UNC, URL etc), we try to see if it is reachable.
Arguments:
lpszDestination - The destination (a UNICODE string) whose rechability is of interest.
lpQOCInfo - Pointer to a buffer that will receive Quality of Connection (QOC) Information. Can be NULL if QOC is not desired.
Notes:
a. This is available only for TCP/IP
Return Value:
TRUE, if the destination is reachable.
FALSE, otherwise. Use GetLastError() to retrieve more error information.
--*/ { BOOL bReachable; RPC_STATUS RpcStatus; DWORD dwLastError; DWORD dwCallerQOCInfoSize; size_t uiLength;
// Basic parameter checks
if ( (lpszDestination == NULL) || ((uiLength = wcslen(lpszDestination)) > MAX_DESTINATION_LENGTH) || (uiLength == 0)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
// OUT parameter intialization.
dwLastError = ERROR_SUCCESS; bReachable = FALSE; if (lpQOCInfo != NULL) { dwCallerQOCInfoSize = lpQOCInfo->dwSize; memset(lpQOCInfo, 0, lpQOCInfo->dwSize); lpQOCInfo->dwSize = dwCallerQOCInfoSize; }
RpcStatus = DoRpcSetup();
//
// Try to get the state information.
//
if (RPC_S_OK == RpcStatus) { RpcStatus = RPC_IsDestinationReachableW( ghSens, (PSENS_CHAR) lpszDestination, lpQOCInfo, &bReachable, &dwLastError ); }
if ( (RPC_S_OK != RpcStatus) || (RPC_S_SERVER_UNAVAILABLE == dwLastError)) { //
// An RPC failure occurred. We treat this as a success and
// set to return values to default values.
//
if (lpQOCInfo != NULL) { lpQOCInfo->dwFlags = NETWORK_ALIVE_LAN; lpQOCInfo->dwInSpeed = DEFAULT_LAN_BANDWIDTH; lpQOCInfo->dwOutSpeed = DEFAULT_LAN_BANDWIDTH; } bReachable = TRUE;
if (RPC_S_OK != RpcStatus) { dwLastError = RpcStatus; } }
ASSERT((bReachable == TRUE) || (bReachable == FALSE));
SetLastError(dwLastError);
return (bReachable); }
#else // SENS_CHICAGO
BOOL IsDestinationReachableA( LPCSTR lpszDestination, LPQOCINFO lpQOCInfo ) /*++
Routine Description:
Given the name of a destination (IP Address, UNC, URL etc), we try to see if it is reachable.
Arguments:
lpszDestination - The destination (a UNICODE string) whose rechability is of interest.
lpQOCInfo - Pointer to a buffer that will receive Quality of Connection (QOC) Information. Can be NULL if QOC is not desired.
Notes:
a. This is available only for TCP/IP
Return Value:
TRUE, if the destination is reachable.
FALSE, otherwise. Use GetLastError() to retrieve more error information.
--*/ { BOOL bReachable; RPC_STATUS RpcStatus; DWORD dwLastError; DWORD dwCallerQOCInfoSize; size_t uiLength;
// Basic parameter checks
if ( (lpszDestination == NULL) || ((uiLength = strlen(lpszDestination)) > MAX_DESTINATION_LENGTH) || (uiLength == 0)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
// OUT parameter intialization.
dwLastError = ERROR_SUCCESS; bReachable = FALSE; if (lpQOCInfo != NULL) { dwCallerQOCInfoSize = lpQOCInfo->dwSize; memset(lpQOCInfo, 0, lpQOCInfo->dwSize); lpQOCInfo->dwSize = dwCallerQOCInfoSize; }
RpcStatus = DoRpcSetup();
//
// Try to get the state information.
//
if (RPC_S_OK == RpcStatus) { RpcStatus = RPC_IsDestinationReachableA( ghSens, (LPSTR) lpszDestination, lpQOCInfo, &bReachable, &dwLastError ); }
if ( (RPC_S_OK != RpcStatus) || (RPC_S_SERVER_UNAVAILABLE == dwLastError)) { //
// An RPC failure occurred. We treat this as a success and
// set to return values to default values.
//
if (lpQOCInfo != NULL) { lpQOCInfo->dwFlags = NETWORK_ALIVE_LAN; lpQOCInfo->dwInSpeed = DEFAULT_LAN_BANDWIDTH; lpQOCInfo->dwOutSpeed = DEFAULT_LAN_BANDWIDTH; } bReachable = TRUE;
if (RPC_S_OK != RpcStatus) { dwLastError = RpcStatus; } }
ASSERT((bReachable == TRUE) || (bReachable == FALSE));
SetLastError(dwLastError);
return (bReachable); }
BOOL IsDestinationReachableW( LPCWSTR lpszDestination, LPQOCINFO lpQOCInfo ) /*++
Routine Description:
This is just a stub on Win9x platforms. It returns FALSE always. This is provided for consistency between NT and Win9x platforms.
Arguments:
lpszDestination - The destination (a UNICODE string) whose rechability is of interest.
lpQOCInfo - Pointer to a buffer that will receive Quality of Connection (QOC) Information. Can be NULL if QOC is not desired.
Return Value:
FALSE, always. Use GetLastError() to retrieve more error information.
--*/ { SetLastError(ERROR_NOT_SUPPORTED);
return FALSE; }
#endif // SENS_CHICAGO
inline RPC_STATUS DoRpcSetup( void ) /*++
Routine Description:
Do the miscellaneous work to talk to SENS via RPC.
Arguments:
None.
Return Value:
None.
--*/ { RPC_STATUS status; SENS_CHAR * BindingString; RPC_BINDING_HANDLE hServer = NULL;
status = RPC_S_OK; BindingString = NULL;
if (ghSens != NULL) { return (status); }
RequestLock();
if (ghSens != NULL) { ReleaseLock(); return (status); }
status = RpcStringBindingCompose( NULL, // NULL ObjUuid
SENS_PROTSEQ, NULL, // Local machine
SENS_ENDPOINT, NULL, // No Options
&BindingString );
if (BindingString) { status = RpcBindingFromStringBinding(BindingString, &hServer); }
if (status == RPC_S_OK) { RPC_SECURITY_QOS RpcSecQos;
RpcSecQos.Version= RPC_C_SECURITY_QOS_VERSION_1; RpcSecQos.ImpersonationType= RPC_C_IMP_LEVEL_IMPERSONATE; RpcSecQos.IdentityTracking= RPC_C_QOS_IDENTITY_DYNAMIC; RpcSecQos.Capabilities= RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
status= RpcBindingSetAuthInfoEx(hServer, L"NT Authority\\System", RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_WINNT, NULL, RPC_C_AUTHZ_NONE, (RPC_SECURITY_QOS *)&RpcSecQos);
if (RPC_S_OK != status) { RpcBindingFree(&hServer); hServer = NULL; } }
ghSens = hServer; ReleaseLock();
if (BindingString != NULL) { RpcStringFree(&BindingString); }
return (status); }
BOOL MapSensCacheView( void ) /*++
Routine Description:
Prepare to read SENS information cache.
Arguments:
None.
Notes:
Should call it under a lock.
Return Value:
TRUE, if successful.
FALSE, otherwise.
--*/ { //
// First, open the SENS cache file mapping object
//
ghSensFileMap = OpenFileMapping( FILE_MAP_READ, // Protection for mapping object
FALSE, // Inherit flag
SENS_CACHE_NAME // Name of the file mapping object
); if (NULL == ghSensFileMap) { goto Cleanup; } //
// Map a view of SENS cache into the address space
//
gpSensCache = (PSENS_CACHE) MapViewOfFile( ghSensFileMap, // Map file object
FILE_MAP_READ, // Access mode
0, // High-order 32 bits of file offset
0, // Low-order 32 bits of file offset
0 // Number of bytes to map
); if (NULL == gpSensCache) { goto Cleanup; }
ASSERT(gpSensCache->dwCacheVer >= SENS_CACHE_VERSION); ASSERT(gpSensCache->dwCacheSize >= sizeof(SENS_CACHE));
return TRUE;
Cleanup: //
// Cleanup
//
if (ghSensFileMap != NULL) { CloseHandle(ghSensFileMap); } if (gpSensCache != NULL) { UnmapViewOfFile(gpSensCache); }
ghSensFileMap = NULL; gpSensCache = NULL;
return FALSE; }
void UnmapSensCacheView( void ) /*++
Routine Description:
Cleanup resources related to SENS information cache.
Arguments:
None.
Notes:
None.
Return Value:
None.
--*/ { BOOL bStatus;
//
// Unmap the view of SENS cache from the address space
//
if (gpSensCache != NULL) { bStatus = UnmapViewOfFile(gpSensCache); ASSERT(bStatus); }
//
// Close File Mapping object
//
if (ghSensFileMap != NULL) { bStatus = CloseHandle(ghSensFileMap); ASSERT(bStatus); } }
BOOL ReadConnectivityCache( OUT LPDWORD lpdwFlags ) /*++
Routine Description:
Try to read SENS connectivity cache. Talk to SENS iff one of the following conditions is TRUE:
o Failed to read the connectivity cache. o Read the cache but connectivity state is FALSE. o Read the cache and connectivity state is TRUE but stale. o Read the cache and there is updated information available.
Arguments:
lpdwFlags - OUT parameter that contains the connectivity state.
Return Value:
TRUE, successfully got cached information.
FALSE, SENS needs to be contacted.
--*/ { DWORD dwNow;
dwNow = GetTickCount();
RequestLock();
// Failed to initialize/read Sens Cache
if ( (NULL == gpSensCache) && (FALSE == MapSensCacheView())) { goto Cleanup; }
// Cache has been updated since we last read. Note that dwLastUpdateTime
// can wrap around.
if (gpSensCache->dwLastUpdateTime != gdwCacheLastUpdatedTime) { gdwCacheLastUpdatedTime = gpSensCache->dwLastUpdateTime; goto Cleanup; }
// It's been a while.
if ( (gdwCacheFirstReadTime != 0x0) && (dwNow - gdwCacheFirstReadTime) > CACHE_VALID_INTERVAL) { goto Cleanup; }
// Cached state is FALSE
if (0x0 == gpSensCache->dwLastUpdateState) { goto Cleanup; }
*lpdwFlags = gpSensCache->dwLastUpdateState; if (0 == gdwCacheFirstReadTime) { gdwCacheFirstReadTime = dwNow; } ASSERT(gdwCacheLastUpdatedTime == gpSensCache->dwLastUpdateTime);
ReleaseLock();
SetLastError(ERROR_SUCCESS);
return TRUE;
Cleanup: //
// Cleanup
//
ReleaseLock();
// Don't need to SetLastError() as we will go to SENS to retrieve it.
return FALSE; }
extern "C" int APIENTRY DllMain( IN HINSTANCE hInstance, IN DWORD dwReason, IN LPVOID lpvReserved ) /*++
Routine Description:
This routine will get called either when a process attaches to this dll or when a process detaches from this dll.
Return Value:
TRUE - Initialization successfully occurred.
FALSE - Insufficient memory is available for the process to attach to this dll.
--*/ { BOOL bSuccess; RPC_STATUS RpcStatus;
switch (dwReason) { case DLL_PROCESS_ATTACH: // Disable Thread attach/detach calls
bSuccess = DisableThreadLibraryCalls(hInstance); ASSERT(bSuccess == TRUE);
// Initialize the lock
InitializeCriticalSection(&gSensapiLock); break;
case DLL_PROCESS_DETACH: // Clean the lock
DeleteCriticalSection(&gSensapiLock);
// Cleanup cache related resources
UnmapSensCacheView();
// Cleanup RPC Binding handle
if (ghSens != NULL) { RpcStatus = RpcBindingFree(&ghSens); ASSERT(RPC_S_OK == RpcStatus); } break;
}
return(TRUE); }
|