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);
|
|||
|
}
|
|||
|
|