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.
 
 
 
 
 
 

782 lines
17 KiB

/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
apiproc.cxx
Abstract:
This file contains the implementations of all the RPC Server
Manager routines exported by SENS.
Author:
Gopal Parupudi <GopalP>
[Notes:]
optional-notes
Revision History:
GopalP 10/11/1997 Start.
--*/
#include <precomp.hxx>
#include <notify.h>
error_status_t
RPC_IsNetworkAlive(
IN handle_t hRpc,
OUT LPDWORD lpdwFlags,
OUT LPBOOL lpbAlive,
OUT LPDWORD lpdwLastError
)
/*++
Routine Description:
Get the current Network State that is maintained by this service.
If either WAN or LAN connectivity is not present, we try to re-evaluate
and update the state, if possible.
Arguments:
hRpc - The RPC Binding handle.
lpdwFlags - The flags indicating which type of network connectivity is
present. The possible values are
NETWORK_ALIVE_WAN
NETWORK_ALIVE_LAN
lpbAlive - Boolean indicating whether the network is alive or not.
lpdwLastError - The out parameter that holds the error code returned
from GetLastError() when there is no network connectivity.
Return Value:
RPC_S_OK, normally.
RPC Error, if there is an RPC-related problem.
--*/
{
DWORD dwNow;
DWORD fNetNature;
BOOL bNetAlive;
BOOL bLanAlive;
BOOL bWanAlive;
DWORD dwWanLastError;
DWORD dwLanLastError;
DWORD dwNetState;
//
// Some basic argument checks
//
if (NULL == lpdwLastError)
{
return RPC_S_INVALID_ARG;
}
if ( (NULL == lpdwFlags)
|| (NULL == lpbAlive))
{
*lpdwLastError = ERROR_INVALID_PARAMETER;
return RPC_S_OK;
}
*lpdwFlags = 0x0;
*lpbAlive = FALSE;
*lpdwLastError = ERROR_SUCCESS;
dwNow = GetTickCount();
fNetNature = 0x0;
dwNetState = 0;
bLanAlive = FALSE;
bWanAlive = FALSE;
bNetAlive = FALSE;
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
SensPrintA(SENS_INFO, ("RPC_IsNetworkAlive() - Current Statistics"
"\n\tLAN State (%s), LAN (%d sec),"
"\n\tWAN State (%s) WAN Time (%d sec)\n",
gdwLANState ? "TRUE" : "FALSE",
(dwNow - gdwLastLANTime)/1000,
gdwWANState ? "TRUE" : "FALSE",
(dwNow - gdwLastWANTime)/1000)
);
#if defined(AOL_PLATFORM)
SensPrintA(SENS_INFO, (""
"\n\tAOL State (%s) AOL Time (%d sec)\n",
gdwAOLState ? "TRUE" : "FALSE",
(dwNow - gdwLastWANTime)/1000));
#endif // AOL_PLATFORM
//
// First, get information about the WAN
//
if ((dwNow - gdwLastWANTime) > MAX_WAN_INTERVAL)
{
SensPrintA(SENS_INFO, ("WAN State information expired. Trying again.\n"));
// WAN state is stale, refresh it.
bWanAlive = EvaluateWanConnectivity(&dwWanLastError);
if (bWanAlive)
{
fNetNature |= NETWORK_ALIVE_WAN;
bNetAlive = TRUE;
}
else
{
*lpdwLastError = MapLastError(dwWanLastError);
}
}
else
{
// Return the WAN state.
if (gdwWANState)
{
fNetNature |= NETWORK_ALIVE_WAN;
bNetAlive = TRUE;
bWanAlive = TRUE;
}
}
#if defined(AOL_PLATFORM)
if (bWanAlive && gdwAOLState)
{
fNetNature |= NETWORK_ALIVE_AOL;
}
#endif // AOL_PLATFORM
//
// If we can determine both types of connectivity at this stage, return.
//
if ( ((dwNow - gdwLastLANTime) <= MAX_LAN_INTERVAL)
&& (gdwLANState == TRUE))
{
fNetNature |= NETWORK_ALIVE_LAN;
bNetAlive = TRUE;
*lpdwFlags = fNetNature;
*lpbAlive = bNetAlive;
*lpdwLastError = ERROR_SUCCESS;
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
return (RPC_S_OK);
}
//
// One of the following is TRUE at this stage.
//
// a. Information about LAN is stale.
// b. Information about LAN is current but there is no LAN connectivity.
// So, we go and check for it again.
//
if (gdwLANState == FALSE)
{
SensPrintA(SENS_INFO, ("LAN State either stale or there is no connectivity. Trying again.\n"));
}
else
{
SensPrintA(SENS_INFO, ("LAN State information expired. Trying again.\n"));
}
bLanAlive = EvaluateLanConnectivity(&dwLanLastError);
if (bLanAlive)
{
fNetNature |= NETWORK_ALIVE_LAN;
bNetAlive = TRUE;
}
else
{
*lpdwLastError = MapLastError(dwLanLastError);
}
*lpdwFlags = fNetNature;
*lpbAlive = bNetAlive;
if (bNetAlive)
{
*lpdwLastError = ERROR_SUCCESS;
}
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
return (RPC_S_OK);
}
error_status_t
RPC_IsDestinationReachableW(
IN handle_t h,
IN wchar_t * lpszDestination,
IN OUT LPQOCINFO lpQOCInfo,
OUT LPBOOL lpbReachable,
OUT LPDWORD lpdwLastError
)
/*++
Routine Description:
Check to see if the given destination is reachable. If so, return Quality
Of Connection (QOC) information, if necessary.
Arguments:
hRpc - The RPC Binding handle.
lpszDestination - The destination whose reachability is of interest.
lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
(QOC) Information. Can be NULL if QOC is not desired.
lpbReachable - Boolean indicating whether the destination is reachable
or not.
lpdwLastError - The out parameter that holds the error code returned
from GetLastError() when the destination is not reachable.
Notes:
This function does nothing on Win9x platforms. It should never be called on Win9x
platforms.
Return Value:
RPC_S_OK, normally.
RPC Error, if there is an RPC-related problem.
--*/
{
BOOL bPingStatus;
BOOL bFound;
DWORD dwStatus;
DWORD dwIpAddress;
DWORD dwReachGLE;
ULONG ulRTT;
size_t uiLength;
#if !defined(SENS_CHICAGO)
//
// Some basic argument checks
//
if (NULL == lpdwLastError)
{
return RPC_S_INVALID_ARG;
}
if ( (NULL == lpszDestination)
|| (NULL == lpbReachable))
{
// Not likely.
*lpdwLastError = ERROR_INVALID_PARAMETER;
return RPC_S_OK;
}
uiLength = wcslen(lpszDestination);
if ( (uiLength > MAX_DESTINATION_LENGTH)
|| (uiLength == 0))
{
*lpbReachable = FALSE;
*lpdwLastError = ERROR_INVALID_PARAMETER;
return RPC_S_OK;
}
*lpdwLastError = ERROR_SUCCESS;
*lpbReachable = FALSE;
ulRTT = 0;
dwStatus = 0;
dwIpAddress = 0;
dwReachGLE = ERROR_SUCCESS;
bPingStatus = FALSE;
bFound = FALSE;
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
SensPrint(SENS_INFO, (SENS_STRING("RPC_IsDestinationReachableW(%s, 0x%x) called.\n"),
lpszDestination, lpQOCInfo));
dwStatus = ResolveName(lpszDestination, &dwIpAddress);
if (dwStatus)
{
*lpdwLastError = MapLastError(dwStatus);
*lpbReachable = FALSE;
SensPrint(SENS_INFO, (SENS_STRING("The Destination %s cannot be resolved - %d\n"),
lpszDestination, dwStatus));
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
return RPC_S_OK;
}
SensPrint(SENS_INFO, (SENS_STRING("Destination \"%s\" is resolved as 0x%x\n"),
lpszDestination, dwIpAddress));
bFound = CheckForReachability(
dwIpAddress,
lpQOCInfo,
&dwReachGLE
);
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
*lpbReachable = bFound;
*lpdwLastError = MapLastError(dwReachGLE);
#endif // SENS_CHICAGO
return RPC_S_OK;
}
error_status_t
RPC_IsDestinationReachableA(
IN handle_t h,
IN char * lpszDestination,
IN OUT LPQOCINFO lpQOCInfo,
OUT LPBOOL lpbReachable,
OUT LPDWORD lpdwLastError
)
/*++
Routine Description:
Check to see if the given destination is reachable. If so, return Quality
Of Connection (QOC) information, if necessary.
Arguments:
hRpc - The RPC Binding handle.
lpszDestination - The destination whose reachability is of interest.
lpQOCInfo - Pointer to a buffer that will receive Quality of Connection
(QOC) Information. Can be NULL if QOC is not desired.
lpbReachable - Boolean indicating whether the destination is reachable
or not.
lpdwLastError - The out parameter that holds the error code returned
from GetLastError() when the destination is not reachable.
Notes:
This function does nothing on NT platforms. It should never be called on NT
platforms.
Return Value:
RPC_S_OK, normally.
RPC Error, if there is an RPC-related problem.
--*/
{
BOOL bPingStatus;
BOOL bFound;
DWORD dwStatus;
DWORD dwIpAddress;
DWORD dwReachGLE;
ULONG ulRTT;
size_t uiLength;
#if defined(SENS_CHICAGO)
//
// Some basic argument checks
//
if (NULL == lpdwLastError)
{
return RPC_S_INVALID_ARG;
}
if ( (NULL == lpszDestination)
|| (NULL == lpbReachable))
{
// Not likely.
*lpdwLastError = ERROR_INVALID_PARAMETER;
return RPC_S_OK;
}
uiLength = strlen(lpszDestination);
if ( (uiLength > MAX_DESTINATION_LENGTH)
|| (uiLength == 0))
{
*lpbReachable = FALSE;
*lpdwLastError = ERROR_INVALID_PARAMETER;
return RPC_S_OK;
}
*lpdwLastError = ERROR_SUCCESS;
*lpbReachable = FALSE;
ulRTT = 0;
dwStatus = 0;
dwIpAddress = 0;
dwReachGLE = ERROR_SUCCESS;
bPingStatus = FALSE;
bFound = FALSE;
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
SensPrint(SENS_INFO, (SENS_STRING("RPC_IsDestinationReachableA(%s, 0x%x) called.\n"),
lpszDestination, lpQOCInfo));
dwStatus = ResolveName(lpszDestination, &dwIpAddress);
if (dwStatus)
{
*lpdwLastError = MapLastError(dwStatus);
*lpbReachable = FALSE;
SensPrint(SENS_INFO, (SENS_STRING("The Destination %s cannot be resolved - %d\n"),
lpszDestination, dwStatus));
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
return RPC_S_OK;
}
SensPrint(SENS_INFO, (SENS_STRING("Destination \"%s\" is resolved as 0x%x\n"),
lpszDestination, dwIpAddress));
bFound = CheckForReachability(
dwIpAddress,
lpQOCInfo,
&dwReachGLE
);
SensPrintA(SENS_INFO, ("--------------------------------------------------------------\n"));
*lpbReachable = bFound;
*lpdwLastError = MapLastError(dwReachGLE);
#endif // SENS_CHICAGO
return RPC_S_OK;
}
error_status_t
RPC_SensNotifyWinlogonEvent(
handle_t h,
PSENS_NOTIFY_WINLOGON pEvent
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
SENSEVENT_WINLOGON Data;
switch (pEvent->eType)
{
case SENS_NOTIFY_WINLOGON_LOGON:
Data.eType = SENS_EVENT_LOGON;
break;
case SENS_NOTIFY_WINLOGON_LOGOFF:
Data.eType = SENS_EVENT_LOGOFF;
break;
case SENS_NOTIFY_WINLOGON_STARTSHELL:
Data.eType = SENS_EVENT_STARTSHELL;
break;
case SENS_NOTIFY_WINLOGON_POSTSHELL:
Data.eType = SENS_EVENT_POSTSHELL;
break;
case SENS_NOTIFY_WINLOGON_SESSION_DISCONNECT:
Data.eType = SENS_EVENT_SESSION_DISCONNECT;
break;
case SENS_NOTIFY_WINLOGON_SESSION_RECONNECT:
Data.eType = SENS_EVENT_SESSION_RECONNECT;
break;
case SENS_NOTIFY_WINLOGON_LOCK:
// If already locked, there is nothing to do.
if (TRUE == gdwLocked)
{
return RPC_S_OK;
}
// Update info in cache.
gdwLocked = TRUE;
UpdateSensCache(LOCK);
Data.eType = SENS_EVENT_LOCK;
break;
case SENS_NOTIFY_WINLOGON_UNLOCK:
// If already unlocked, there is nothing to do.
if (FALSE == gdwLocked)
{
return RPC_S_OK;
}
// Update info in cache.
gdwLocked = FALSE;
UpdateSensCache(LOCK);
Data.eType = SENS_EVENT_UNLOCK;
break;
case SENS_NOTIFY_WINLOGON_STARTSCREENSAVER:
Data.eType = SENS_EVENT_STARTSCREENSAVER;
break;
case SENS_NOTIFY_WINLOGON_STOPSCREENSAVER:
Data.eType = SENS_EVENT_STOPSCREENSAVER;
break;
default:
SensPrintA(SENS_WARN, ("BOGUS WINLOGON EVENT\n"));
ASSERT(0 && "BOGUS WINLOGON EVENT");
return RPC_S_OK;
}
memcpy(&Data.Info, &pEvent->Info, sizeof(WINLOGON_INFO));
//
// PERFORMANCE NOTE:
//
// o We want the Logoff event to be synchronous. That is, until all
// the subscribers to this event are done handling this event,
// System Logoff should not occur.
// o As of today, LCE fires events to the subscribers on the publishers
// thread. If we fire on a threadpool thread, it will release the
// publisher thread which will go and allow System Logoff to continue.
// o This has performance implications. We need to make sure that we
// don't impact System Logoff time when there are no subscriptions
// to this event.
//
if (SENS_EVENT_LOGOFF != Data.eType)
{
// Queue workitem to threadpool
SensFireEvent(&Data);
}
else
{
PVOID pAllocatedData;
pAllocatedData = AllocateEventData(&Data);
if (NULL == pAllocatedData)
{
SensPrintA(SENS_ERR, ("RPC_NotifyWinlogonEvent(): Failed to allocate Event Data!\n"));
return (RPC_S_OUT_OF_MEMORY);
}
// Synchronously call LCE and then free allocated Data.
SensFireEventHelper(pAllocatedData);
}
return (RPC_S_OK);
}
error_status_t
RPC_SensNotifyRasEvent(
handle_t h,
PSENS_NOTIFY_RAS pEvent
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DWORD dwIgnore;
SENSEVENT_RAS Data;
switch (pEvent->eType)
{
case SENS_NOTIFY_RAS_STARTED:
Data.eType = SENS_EVENT_RAS_STARTED;
break;
case SENS_NOTIFY_RAS_STOPPED:
Data.eType = SENS_EVENT_RAS_STOPPED;
break;
case SENS_NOTIFY_RAS_CONNECT:
Data.eType = SENS_EVENT_RAS_CONNECT;
break;
case SENS_NOTIFY_RAS_DISCONNECT:
Data.eType = SENS_EVENT_RAS_DISCONNECT;
break;
case SENS_NOTIFY_RAS_DISCONNECT_PENDING:
Data.eType = SENS_EVENT_RAS_DISCONNECT_PENDING;
break;
default:
SensPrintA(SENS_WARN, ("\t| BOGUS RAS EVENT - Type is %d\n", pEvent->eType));
return RPC_S_OK;
}
Data.hConnection = pEvent->hConnection;
SensFireEvent(&Data);
EvaluateConnectivity(TYPE_WAN);
return (RPC_S_OK);
}
error_status_t
RPC_SensNotifyNetconEvent(
handle_t h,
PSENS_NOTIFY_NETCON_P pEvent
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
SENSEVENT_LAN Data;
switch (pEvent->eType)
{
case SENS_NOTIFY_LAN_CONNECT:
Data.eType = SENS_EVENT_LAN_CONNECT;
break;
case SENS_NOTIFY_LAN_DISCONNECT:
Data.eType = SENS_EVENT_LAN_DISCONNECT;
break;
default:
SensPrintA(SENS_WARN, ("\t| BOGUS LAN EVENT - Type is %d\n", pEvent->eType));
return RPC_S_OK;
}
Data.Name = pEvent->Name;
Data.Status = pEvent->Status;
Data.Type = pEvent->Type;
// Force a recalculation of LAN Connectivity
gdwLastLANTime -= (MAX_LAN_INTERVAL + 1);
SensFireEvent(&Data);
EvaluateConnectivity(TYPE_LAN);
return (RPC_S_OK);
}
DWORD
MapLastError(
DWORD dwInGLE
)
/*++
Routine Description:
This rountine maps the GLEs returned by the SENS Connecitivity engine to
GLEs that describe the failure of the SENS APIs more accurately.
Arguments:
dwInGLE - The GLE that needs to be mapped
Return Value:
The mapped (and better) GLE.
--*/
{
DWORD dwOutGLE;
switch (dwInGLE)
{
//
// When IP stack is not present, we typically get these errors.
//
case ERROR_INVALID_FUNCTION:
case ERROR_NOT_SUPPORTED:
dwOutGLE = ERROR_NO_NETWORK;
break;
//
// No mapping by default.
//
default:
dwOutGLE = dwInGLE;
break;
} // switch
return dwOutGLE;
}