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.
 
 
 
 
 
 

596 lines
14 KiB

/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
dest.cxx
Abstract:
Code to keep track of reachability of the list destinations specified
in Event System's Reachability Event subscriptions.
Author:
Gopal Parupudi <GopalP>
[Notes:]
optional-notes
Revision History:
GopalP 10/31/1997 Start.
--*/
#include <precomp.hxx>
//
// Constants
//
#define SENS_REACHABILITY_POLLING_INTERVAL 5*60*1000 // 5 minutes
#define SENS_REACHABILITY_FIRST_SCAN_TIME 5*60*1000 // 5 minutes
//
// Globals
//
LIST *gpReachList;
HANDLE ghReachTimer;
BOOL
StartReachabilityEngine(
void
)
/*++
Routine Description:
Start the Destination reachability engine.
Arguments:
None.
Return Value:
TRUE, if successful.
FALSE, otherwise.
--*/
{
BOOL bRetVal;
bRetVal = TRUE; // Note it is TRUE, by default.
SensPrintA(SENS_INFO, ("StartReachabilityEngine(): Starting...\n"));
RequestSensLock();
if (ghReachTimer != NULL)
{
SensPrintA(SENS_INFO, ("StartReachabilityEngine(): Engine "
"already started!\n"));
goto Cleanup;
}
//
// Create a timer object to poll for destination reachability
//
SensSetTimerQueueTimer(
bRetVal, // Bool return on NT5
ghReachTimer, // Handle return on IE5
NULL, // Use default process timer queue
ReachabilityPollingRoutine, // Callback
NULL, // Parameter
SENS_REACHABILITY_FIRST_SCAN_TIME, // Time from now when timer should fire
SENS_REACHABILITY_POLLING_INTERVAL,// Time inbetween firings of this timer
0x0 // No Flags.
);
if (SENS_TIMER_CREATE_FAILED(bRetVal, ghReachTimer))
{
SensPrintA(SENS_INFO, ("StartReachabilityEngine(): SensCancelTimerQueueTimer("
"Reachability) failed!\n"));
bRetVal = FALSE;
goto Cleanup;
}
Cleanup:
//
// Cleanup
//
ReleaseSensLock();
SensPrintA(SENS_INFO, ("StartReachabilityEngine(): Returning %s\n",
bRetVal ? "TRUE" : "FALSE"));
return bRetVal;
}
BOOL
StopReachabilityEngine(
void
)
/*++
Routine Description:
Start the Destination reachability engine.
Arguments:
None.
Return Value:
TRUE, if successful.
FALSE, otherwise.
--*/
{
BOOL bStatus;
bStatus = TRUE; // Note it is TRUE, by default.
SensPrintA(SENS_INFO, ("StopReachabilityEngine(): Stopping...\n"));
RequestSensLock();
//
// Remove Reachability polling timer
//
if (NULL != ghReachTimer)
{
bStatus = SensCancelTimerQueueTimer(NULL, ghReachTimer, NULL);
ghReachTimer = NULL;
SensPrintA(SENS_INFO, ("StopReachabilityEngine(): SensCancelTimerQueueTimer("
"Reachability) %s\n", bStatus ? "succeeded" : "failed!"));
}
ReleaseSensLock();
SensPrintA(SENS_INFO, ("StopReachabilityEngine(): Returning %s\n",
bStatus ? "TRUE" : "FALSE"));
return bStatus;
}
BOOL
InitReachabilityEngine(
void
)
/*++
Routine Description:
Initialize the Reachability polling mechanism.
Arguments:
None.
Return Value:
TRUE, if successful.
FALSE, otherwise.
--*/
{
BOOL bRetVal;
bRetVal = FALSE;
//
// Initialize the list of destinations
//
gpReachList = new LIST();
if (NULL == gpReachList)
{
goto Cleanup;
}
bRetVal = StartReachabilityEngine();
Cleanup:
//
// Cleanup
//
return bRetVal;
}
SENS_TIMER_CALLBACK_RETURN
ReachabilityPollingRoutine(
PVOID pvIgnore,
BOOLEAN bIgnore
)
/*++
Routine Description:
This routine is called periodically to walk through the reachability list
to see if the destinations are reachable.
Arguments:
pvIgnore - Ignored.
bIgnore - Ignored.
Return Value:
None.
--*/
{
PNODE pTemp;
DWORD OldState;
QOCINFO DestQOCInfo;
DWORD dwLastError;
char *DestinationA;
static BOOL bGotDestinations = FALSE;
//
// Get the list of destinations, if necessary.
//
if (FALSE == bGotDestinations)
{
HRESULT hr;
hr = GetDestinationsFromSubscriptions();
if (SUCCEEDED(hr))
{
bGotDestinations = TRUE;
}
else
{
SensPrintA(SENS_ERR, ("InitReachabilityPolling(): GetDestinations"
"FromSubscriptions() failed with 0x%x.\n", hr));
}
}
SensPrintA(SENS_INFO, ("ReachabilityPollingRoutine(): Checking "
"Destinations for reachability.\n"));
// PERF NOTE: Critsec held too long!
gpReachList->RequestLock();
if (gpReachList->IsEmpty() == TRUE)
{
StopReachabilityEngine();
gpReachList->ReleaseLock();
return;
}
//
// Loop through all destinations checking for reachability.
//
pTemp = gpReachList->pHead;
while (pTemp != NULL)
{
error_status_t status;
// Save old reachability state.
OldState = pTemp->State;
//
// Is it Reachable?
//
dwLastError = ERROR_SUCCESS;
DestQOCInfo.dwSize = sizeof(QOCINFO);
status = RPC_IsDestinationReachableW(
NULL,
pTemp->Destination,
&DestQOCInfo,
(LPBOOL) &pTemp->State,
&dwLastError
);
ASSERT(status == RPC_S_OK);
if ( (pTemp->State != OldState)
&& (dwLastError == ERROR_SUCCESS))
{
// Fire the Event!
SENSEVENT_REACH Data;
Data.eType = SENS_EVENT_REACH;
Data.bReachable = pTemp->State;
Data.Destination = pTemp->Destination;
memcpy(&Data.QocInfo, &DestQOCInfo, DestQOCInfo.dwSize);
// NOTE: Set the following field appropriately. This is the best we can do.
Data.strConnection = DEFAULT_LAN_CONNECTION_NAME;
SensFireEvent((PVOID)&Data);
}
if (dwLastError != ERROR_SUCCESS)
{
SensPrintW(SENS_INFO, (L"ReachabilityPollingRoutine(): %s is not reachable - %d\n",
pTemp->Destination, dwLastError));
if (ERROR_INVALID_PARAMETER == dwLastError)
{
// Remove the destination from further reachability checks.
gpReachList->DeleteByDest(pTemp->Destination);
}
}
pTemp = pTemp->Next;
} // while()
gpReachList->ReleaseLock();
//
// Dump the list
//
gpReachList->Print();
}
HRESULT
GetDestinationsFromSubscriptions(
void
)
/*++
Routine Description:
Retrieve the names of destinations from Reachability subscriptions and
insert into the Reachability List.
Arguments:
None.
Return Value:
S_OK, on success.
HRESULT, on failure.
--*/
{
HRESULT hr;
int errorIndex;
LONG lCount;
BSTR bstrPropertyName;
BSTR bstrEventClassID;
VARIANT variantPropertyValue;
WCHAR wszQuery[MAX_QUERY_SIZE];
LPOLESTR strGuid;
IEventSystem *pIEventSystem;
IEventSubscription *pIEventSubscription;
IEventObjectCollection *pSubscriptionCollection;
IEnumEventObject *pIEnumEventObject;
hr = S_OK;
lCount = 0;
errorIndex = 0;
strGuid = NULL;
bstrPropertyName = NULL;
bstrEventClassID = NULL;
pIEventSystem = NULL;
pIEventSubscription = NULL;
pSubscriptionCollection = NULL;
pIEnumEventObject = NULL;
// Get a new IEventSystem object to play with.
hr = CoCreateInstance(
CLSID_CEventSystem,
NULL,
CLSCTX_SERVER,
IID_IEventSystem,
(LPVOID *) &pIEventSystem
);
if (FAILED(hr))
{
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): failed to create ")
SENS_STRING("IEventSystem - hr = <%x>\n"), hr));
goto Cleanup;
}
//
// Form the query.
//
// (EventClassID = NetEventClassID) AND
// ( (MethodName = 'DestinationReachable')
// OR (MethodName = 'DestinationReachableNoQocInfo'))
//
AllocateBstrFromGuid(bstrEventClassID, SENSGUID_EVENTCLASS_NETWORK);
wcscpy(wszQuery, SENS_BSTR("(EventClassID"));
wcscat(wszQuery, SENS_BSTR("="));
wcscat(wszQuery, bstrEventClassID);
wcscat(wszQuery, SENS_BSTR(") AND (("));
wcscat(wszQuery, SENS_BSTR("MethodName = \'"));
wcscat(wszQuery, DESTINATION_REACHABLE_METHOD);
wcscat(wszQuery, SENS_BSTR("\') OR ("));
wcscat(wszQuery, SENS_BSTR("MethodName = \'"));
wcscat(wszQuery, DESTINATION_REACHABLE_NOQOC_METHOD);
wcscat(wszQuery, SENS_BSTR("\'))"));
hr = pIEventSystem->Query(
PROGID_EventSubscriptionCollection,
wszQuery,
&errorIndex,
(LPUNKNOWN *) &pSubscriptionCollection
);
if (FAILED(hr))
{
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): failed to Query() ")
SENS_STRING("- hr = <%x>\n"), hr));
SensPrint(SENS_ERR, (SENS_STRING("errorIndex = %d\n"), errorIndex));
goto Cleanup;
}
SensPrint(SENS_ERR, (SENS_STRING("Query = %s, hr = 0x%x\n"), wszQuery, hr));
#if DBG
hr = pSubscriptionCollection->get_Count(&lCount);
if (FAILED(hr))
{
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
SENS_STRING("get_Count() returned hr = <%x>\n"), hr));
goto Cleanup;
}
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
SENS_STRING("Found %d Reachability subscriptions.\n"), lCount));
if (0 == lCount)
{
goto Cleanup;
}
#endif // DBG
// Get a new Enum object to play with.
hr = pSubscriptionCollection->get_NewEnum(
(IEnumEventObject **) &pIEnumEventObject
);
if (FAILED(hr))
{
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
SENS_STRING("get_NewEnum() returned hr = <%x>\n"), hr));
goto Cleanup;
}
hr = S_OK;
hr = pIEnumEventObject->Reset();
//
// Extract each destination name and insert into list.
//
while (S_OK == hr)
{
ULONG cElements = 1;
hr = pIEnumEventObject->Next(
cElements,
(LPUNKNOWN *) &pIEventSubscription,
&cElements
);
if ( (S_OK != hr)
|| (1 != cElements))
{
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
SENS_STRING("Next() failed hr = <%x>, count = %d\n"), hr, cElements));
goto Cleanup;
}
//
// Try to get the value for Publisher property - bstrDestination
//
VariantInit(&variantPropertyValue);
AllocateBstrFromString(bstrPropertyName, PROPERTY_DESTINATION);
hr = pIEventSubscription->GetPublisherProperty(
bstrPropertyName,
&variantPropertyValue
);
if (hr == S_OK)
{
// Found the property!
gpReachList->InsertByDest(variantPropertyValue.bstrVal);
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
SENS_STRING("Added to Reachability List: %s\n"),
variantPropertyValue.bstrVal));
goto ProcessNextSubscription;
}
//
// Now, try to get the value for Publisher property - bstrDestinationNoQOC
//
FreeBstr(bstrPropertyName);
VariantInit(&variantPropertyValue);
AllocateBstrFromString(bstrPropertyName, PROPERTY_DESTINATION_NOQOC);
hr = pIEventSubscription->GetPublisherProperty(
bstrPropertyName,
&variantPropertyValue
);
if (hr == S_OK)
{
// Found the property!
gpReachList->InsertByDest(variantPropertyValue.bstrVal);
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
SENS_STRING("Added to Reachability List: %s\n"),
variantPropertyValue.bstrVal));
goto ProcessNextSubscription;
}
SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): failed to get ")
SENS_STRING("PublisherProperty - hr = <%x>\n"), hr));
ProcessNextSubscription:
VariantClear(&variantPropertyValue);
FreeBstr(bstrPropertyName);
pIEventSubscription->Release();
pIEventSubscription = NULL;
hr = S_OK;
} // while()
Cleanup:
//
// Cleanup
//
if (pIEventSystem)
{
pIEventSystem->Release();
}
if (pIEventSubscription)
{
pIEventSubscription->Release();
}
if (pSubscriptionCollection)
{
pSubscriptionCollection->Release();
}
if (pIEnumEventObject)
{
pIEnumEventObject->Release();
}
FreeBstr(bstrEventClassID);
FreeStr(strGuid);
return (hr);
}