597 lines
14 KiB
C++
597 lines
14 KiB
C++
/*++
|
||
|
||
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);
|
||
}
|
||
|