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

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. dest.cxx
  5. Abstract:
  6. Code to keep track of reachability of the list destinations specified
  7. in Event System's Reachability Event subscriptions.
  8. Author:
  9. Gopal Parupudi <GopalP>
  10. [Notes:]
  11. optional-notes
  12. Revision History:
  13. GopalP 10/31/1997 Start.
  14. --*/
  15. #include <precomp.hxx>
  16. //
  17. // Constants
  18. //
  19. #define SENS_REACHABILITY_POLLING_INTERVAL 5*60*1000 // 5 minutes
  20. #define SENS_REACHABILITY_FIRST_SCAN_TIME 5*60*1000 // 5 minutes
  21. //
  22. // Globals
  23. //
  24. LIST *gpReachList;
  25. HANDLE ghReachTimer;
  26. BOOL
  27. StartReachabilityEngine(
  28. void
  29. )
  30. /*++
  31. Routine Description:
  32. Start the Destination reachability engine.
  33. Arguments:
  34. None.
  35. Return Value:
  36. TRUE, if successful.
  37. FALSE, otherwise.
  38. --*/
  39. {
  40. BOOL bRetVal;
  41. bRetVal = TRUE; // Note it is TRUE, by default.
  42. SensPrintA(SENS_INFO, ("StartReachabilityEngine(): Starting...\n"));
  43. RequestSensLock();
  44. if (ghReachTimer != NULL)
  45. {
  46. SensPrintA(SENS_INFO, ("StartReachabilityEngine(): Engine "
  47. "already started!\n"));
  48. goto Cleanup;
  49. }
  50. //
  51. // Create a timer object to poll for destination reachability
  52. //
  53. SensSetTimerQueueTimer(
  54. bRetVal, // Bool return on NT5
  55. ghReachTimer, // Handle return on IE5
  56. NULL, // Use default process timer queue
  57. ReachabilityPollingRoutine, // Callback
  58. NULL, // Parameter
  59. SENS_REACHABILITY_FIRST_SCAN_TIME, // Time from now when timer should fire
  60. SENS_REACHABILITY_POLLING_INTERVAL,// Time inbetween firings of this timer
  61. 0x0 // No Flags.
  62. );
  63. if (SENS_TIMER_CREATE_FAILED(bRetVal, ghReachTimer))
  64. {
  65. SensPrintA(SENS_INFO, ("StartReachabilityEngine(): SensCancelTimerQueueTimer("
  66. "Reachability) failed!\n"));
  67. bRetVal = FALSE;
  68. goto Cleanup;
  69. }
  70. Cleanup:
  71. //
  72. // Cleanup
  73. //
  74. ReleaseSensLock();
  75. SensPrintA(SENS_INFO, ("StartReachabilityEngine(): Returning %s\n",
  76. bRetVal ? "TRUE" : "FALSE"));
  77. return bRetVal;
  78. }
  79. BOOL
  80. StopReachabilityEngine(
  81. void
  82. )
  83. /*++
  84. Routine Description:
  85. Start the Destination reachability engine.
  86. Arguments:
  87. None.
  88. Return Value:
  89. TRUE, if successful.
  90. FALSE, otherwise.
  91. --*/
  92. {
  93. BOOL bStatus;
  94. bStatus = TRUE; // Note it is TRUE, by default.
  95. SensPrintA(SENS_INFO, ("StopReachabilityEngine(): Stopping...\n"));
  96. RequestSensLock();
  97. //
  98. // Remove Reachability polling timer
  99. //
  100. if (NULL != ghReachTimer)
  101. {
  102. bStatus = SensCancelTimerQueueTimer(NULL, ghReachTimer, NULL);
  103. ghReachTimer = NULL;
  104. SensPrintA(SENS_INFO, ("StopReachabilityEngine(): SensCancelTimerQueueTimer("
  105. "Reachability) %s\n", bStatus ? "succeeded" : "failed!"));
  106. }
  107. ReleaseSensLock();
  108. SensPrintA(SENS_INFO, ("StopReachabilityEngine(): Returning %s\n",
  109. bStatus ? "TRUE" : "FALSE"));
  110. return bStatus;
  111. }
  112. BOOL
  113. InitReachabilityEngine(
  114. void
  115. )
  116. /*++
  117. Routine Description:
  118. Initialize the Reachability polling mechanism.
  119. Arguments:
  120. None.
  121. Return Value:
  122. TRUE, if successful.
  123. FALSE, otherwise.
  124. --*/
  125. {
  126. BOOL bRetVal;
  127. bRetVal = FALSE;
  128. //
  129. // Initialize the list of destinations
  130. //
  131. gpReachList = new LIST();
  132. if (NULL == gpReachList)
  133. {
  134. goto Cleanup;
  135. }
  136. bRetVal = StartReachabilityEngine();
  137. Cleanup:
  138. //
  139. // Cleanup
  140. //
  141. return bRetVal;
  142. }
  143. SENS_TIMER_CALLBACK_RETURN
  144. ReachabilityPollingRoutine(
  145. PVOID pvIgnore,
  146. BOOLEAN bIgnore
  147. )
  148. /*++
  149. Routine Description:
  150. This routine is called periodically to walk through the reachability list
  151. to see if the destinations are reachable.
  152. Arguments:
  153. pvIgnore - Ignored.
  154. bIgnore - Ignored.
  155. Return Value:
  156. None.
  157. --*/
  158. {
  159. PNODE pTemp;
  160. DWORD OldState;
  161. QOCINFO DestQOCInfo;
  162. DWORD dwLastError;
  163. char *DestinationA;
  164. static BOOL bGotDestinations = FALSE;
  165. //
  166. // Get the list of destinations, if necessary.
  167. //
  168. if (FALSE == bGotDestinations)
  169. {
  170. HRESULT hr;
  171. hr = GetDestinationsFromSubscriptions();
  172. if (SUCCEEDED(hr))
  173. {
  174. bGotDestinations = TRUE;
  175. }
  176. else
  177. {
  178. SensPrintA(SENS_ERR, ("InitReachabilityPolling(): GetDestinations"
  179. "FromSubscriptions() failed with 0x%x.\n", hr));
  180. }
  181. }
  182. SensPrintA(SENS_INFO, ("ReachabilityPollingRoutine(): Checking "
  183. "Destinations for reachability.\n"));
  184. // PERF NOTE: Critsec held too long!
  185. gpReachList->RequestLock();
  186. if (gpReachList->IsEmpty() == TRUE)
  187. {
  188. StopReachabilityEngine();
  189. gpReachList->ReleaseLock();
  190. return;
  191. }
  192. //
  193. // Loop through all destinations checking for reachability.
  194. //
  195. pTemp = gpReachList->pHead;
  196. while (pTemp != NULL)
  197. {
  198. error_status_t status;
  199. // Save old reachability state.
  200. OldState = pTemp->State;
  201. //
  202. // Is it Reachable?
  203. //
  204. dwLastError = ERROR_SUCCESS;
  205. DestQOCInfo.dwSize = sizeof(QOCINFO);
  206. status = RPC_IsDestinationReachableW(
  207. NULL,
  208. pTemp->Destination,
  209. &DestQOCInfo,
  210. (LPBOOL) &pTemp->State,
  211. &dwLastError
  212. );
  213. ASSERT(status == RPC_S_OK);
  214. if ( (pTemp->State != OldState)
  215. && (dwLastError == ERROR_SUCCESS))
  216. {
  217. // Fire the Event!
  218. SENSEVENT_REACH Data;
  219. Data.eType = SENS_EVENT_REACH;
  220. Data.bReachable = pTemp->State;
  221. Data.Destination = pTemp->Destination;
  222. memcpy(&Data.QocInfo, &DestQOCInfo, DestQOCInfo.dwSize);
  223. // NOTE: Set the following field appropriately. This is the best we can do.
  224. Data.strConnection = DEFAULT_LAN_CONNECTION_NAME;
  225. SensFireEvent((PVOID)&Data);
  226. }
  227. if (dwLastError != ERROR_SUCCESS)
  228. {
  229. SensPrintW(SENS_INFO, (L"ReachabilityPollingRoutine(): %s is not reachable - %d\n",
  230. pTemp->Destination, dwLastError));
  231. if (ERROR_INVALID_PARAMETER == dwLastError)
  232. {
  233. // Remove the destination from further reachability checks.
  234. gpReachList->DeleteByDest(pTemp->Destination);
  235. }
  236. }
  237. pTemp = pTemp->Next;
  238. } // while()
  239. gpReachList->ReleaseLock();
  240. //
  241. // Dump the list
  242. //
  243. gpReachList->Print();
  244. }
  245. HRESULT
  246. GetDestinationsFromSubscriptions(
  247. void
  248. )
  249. /*++
  250. Routine Description:
  251. Retrieve the names of destinations from Reachability subscriptions and
  252. insert into the Reachability List.
  253. Arguments:
  254. None.
  255. Return Value:
  256. S_OK, on success.
  257. HRESULT, on failure.
  258. --*/
  259. {
  260. HRESULT hr;
  261. int errorIndex;
  262. LONG lCount;
  263. BSTR bstrPropertyName;
  264. BSTR bstrEventClassID;
  265. VARIANT variantPropertyValue;
  266. WCHAR wszQuery[MAX_QUERY_SIZE];
  267. LPOLESTR strGuid;
  268. IEventSystem *pIEventSystem;
  269. IEventSubscription *pIEventSubscription;
  270. IEventObjectCollection *pSubscriptionCollection;
  271. IEnumEventObject *pIEnumEventObject;
  272. hr = S_OK;
  273. lCount = 0;
  274. errorIndex = 0;
  275. strGuid = NULL;
  276. bstrPropertyName = NULL;
  277. bstrEventClassID = NULL;
  278. pIEventSystem = NULL;
  279. pIEventSubscription = NULL;
  280. pSubscriptionCollection = NULL;
  281. pIEnumEventObject = NULL;
  282. // Get a new IEventSystem object to play with.
  283. hr = CoCreateInstance(
  284. CLSID_CEventSystem,
  285. NULL,
  286. CLSCTX_SERVER,
  287. IID_IEventSystem,
  288. (LPVOID *) &pIEventSystem
  289. );
  290. if (FAILED(hr))
  291. {
  292. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): failed to create ")
  293. SENS_STRING("IEventSystem - hr = <%x>\n"), hr));
  294. goto Cleanup;
  295. }
  296. //
  297. // Form the query.
  298. //
  299. // (EventClassID = NetEventClassID) AND
  300. // ( (MethodName = 'DestinationReachable')
  301. // OR (MethodName = 'DestinationReachableNoQocInfo'))
  302. //
  303. AllocateBstrFromGuid(bstrEventClassID, SENSGUID_EVENTCLASS_NETWORK);
  304. wcscpy(wszQuery, SENS_BSTR("(EventClassID"));
  305. wcscat(wszQuery, SENS_BSTR("="));
  306. wcscat(wszQuery, bstrEventClassID);
  307. wcscat(wszQuery, SENS_BSTR(") AND (("));
  308. wcscat(wszQuery, SENS_BSTR("MethodName = \'"));
  309. wcscat(wszQuery, DESTINATION_REACHABLE_METHOD);
  310. wcscat(wszQuery, SENS_BSTR("\') OR ("));
  311. wcscat(wszQuery, SENS_BSTR("MethodName = \'"));
  312. wcscat(wszQuery, DESTINATION_REACHABLE_NOQOC_METHOD);
  313. wcscat(wszQuery, SENS_BSTR("\'))"));
  314. hr = pIEventSystem->Query(
  315. PROGID_EventSubscriptionCollection,
  316. wszQuery,
  317. &errorIndex,
  318. (LPUNKNOWN *) &pSubscriptionCollection
  319. );
  320. if (FAILED(hr))
  321. {
  322. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): failed to Query() ")
  323. SENS_STRING("- hr = <%x>\n"), hr));
  324. SensPrint(SENS_ERR, (SENS_STRING("errorIndex = %d\n"), errorIndex));
  325. goto Cleanup;
  326. }
  327. SensPrint(SENS_ERR, (SENS_STRING("Query = %s, hr = 0x%x\n"), wszQuery, hr));
  328. #if DBG
  329. hr = pSubscriptionCollection->get_Count(&lCount);
  330. if (FAILED(hr))
  331. {
  332. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
  333. SENS_STRING("get_Count() returned hr = <%x>\n"), hr));
  334. goto Cleanup;
  335. }
  336. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
  337. SENS_STRING("Found %d Reachability subscriptions.\n"), lCount));
  338. if (0 == lCount)
  339. {
  340. goto Cleanup;
  341. }
  342. #endif // DBG
  343. // Get a new Enum object to play with.
  344. hr = pSubscriptionCollection->get_NewEnum(
  345. (IEnumEventObject **) &pIEnumEventObject
  346. );
  347. if (FAILED(hr))
  348. {
  349. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
  350. SENS_STRING("get_NewEnum() returned hr = <%x>\n"), hr));
  351. goto Cleanup;
  352. }
  353. hr = S_OK;
  354. hr = pIEnumEventObject->Reset();
  355. //
  356. // Extract each destination name and insert into list.
  357. //
  358. while (S_OK == hr)
  359. {
  360. ULONG cElements = 1;
  361. hr = pIEnumEventObject->Next(
  362. cElements,
  363. (LPUNKNOWN *) &pIEventSubscription,
  364. &cElements
  365. );
  366. if ( (S_OK != hr)
  367. || (1 != cElements))
  368. {
  369. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
  370. SENS_STRING("Next() failed hr = <%x>, count = %d\n"), hr, cElements));
  371. goto Cleanup;
  372. }
  373. //
  374. // Try to get the value for Publisher property - bstrDestination
  375. //
  376. VariantInit(&variantPropertyValue);
  377. AllocateBstrFromString(bstrPropertyName, PROPERTY_DESTINATION);
  378. hr = pIEventSubscription->GetPublisherProperty(
  379. bstrPropertyName,
  380. &variantPropertyValue
  381. );
  382. if (hr == S_OK)
  383. {
  384. // Found the property!
  385. gpReachList->InsertByDest(variantPropertyValue.bstrVal);
  386. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
  387. SENS_STRING("Added to Reachability List: %s\n"),
  388. variantPropertyValue.bstrVal));
  389. goto ProcessNextSubscription;
  390. }
  391. //
  392. // Now, try to get the value for Publisher property - bstrDestinationNoQOC
  393. //
  394. FreeBstr(bstrPropertyName);
  395. VariantInit(&variantPropertyValue);
  396. AllocateBstrFromString(bstrPropertyName, PROPERTY_DESTINATION_NOQOC);
  397. hr = pIEventSubscription->GetPublisherProperty(
  398. bstrPropertyName,
  399. &variantPropertyValue
  400. );
  401. if (hr == S_OK)
  402. {
  403. // Found the property!
  404. gpReachList->InsertByDest(variantPropertyValue.bstrVal);
  405. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): ")
  406. SENS_STRING("Added to Reachability List: %s\n"),
  407. variantPropertyValue.bstrVal));
  408. goto ProcessNextSubscription;
  409. }
  410. SensPrint(SENS_ERR, (SENS_STRING("GetDestinationsFromSubscriptions(): failed to get ")
  411. SENS_STRING("PublisherProperty - hr = <%x>\n"), hr));
  412. ProcessNextSubscription:
  413. VariantClear(&variantPropertyValue);
  414. FreeBstr(bstrPropertyName);
  415. pIEventSubscription->Release();
  416. pIEventSubscription = NULL;
  417. hr = S_OK;
  418. } // while()
  419. Cleanup:
  420. //
  421. // Cleanup
  422. //
  423. if (pIEventSystem)
  424. {
  425. pIEventSystem->Release();
  426. }
  427. if (pIEventSubscription)
  428. {
  429. pIEventSubscription->Release();
  430. }
  431. if (pSubscriptionCollection)
  432. {
  433. pSubscriptionCollection->Release();
  434. }
  435. if (pIEnumEventObject)
  436. {
  437. pIEnumEventObject->Release();
  438. }
  439. FreeBstr(bstrEventClassID);
  440. FreeStr(strGuid);
  441. return (hr);
  442. }