Leaked source code of windows server 2003
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.

1552 lines
49 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. notify.c
  5. Abstract:
  6. Public interface for cluster notification API
  7. Author:
  8. John Vert (jvert) 19-Mar-1996
  9. Revision History:
  10. --*/
  11. #include "clusapip.h"
  12. //
  13. // Define some handy constants
  14. //
  15. #define FILTER_NODE (CLUSTER_CHANGE_NODE_STATE | \
  16. CLUSTER_CHANGE_NODE_DELETED | \
  17. CLUSTER_CHANGE_NODE_ADDED | \
  18. CLUSTER_CHANGE_NODE_PROPERTY)
  19. #define NOT_FILTER_NODE (~(FILTER_NODE |CLUSTER_CHANGE_HANDLE_CLOSE))
  20. #define FILTER_REGISTRY (CLUSTER_CHANGE_REGISTRY_NAME | \
  21. CLUSTER_CHANGE_REGISTRY_ATTRIBUTES | \
  22. CLUSTER_CHANGE_REGISTRY_VALUE | \
  23. CLUSTER_CHANGE_REGISTRY_SUBTREE)
  24. #define NOT_FILTER_REGISTRY (~(FILTER_REGISTRY |CLUSTER_CHANGE_HANDLE_CLOSE))
  25. #define FILTER_RESOURCE (CLUSTER_CHANGE_RESOURCE_STATE | \
  26. CLUSTER_CHANGE_RESOURCE_DELETED | \
  27. CLUSTER_CHANGE_RESOURCE_ADDED | \
  28. CLUSTER_CHANGE_RESOURCE_PROPERTY)
  29. #define NOT_FILTER_RESOURCE (~(FILTER_RESOURCE | CLUSTER_CHANGE_HANDLE_CLOSE))
  30. #define FILTER_GROUP (CLUSTER_CHANGE_GROUP_STATE | \
  31. CLUSTER_CHANGE_GROUP_DELETED | \
  32. CLUSTER_CHANGE_GROUP_ADDED | \
  33. CLUSTER_CHANGE_GROUP_PROPERTY)
  34. #define NOT_FILTER_GROUP (~(FILTER_GROUP | CLUSTER_CHANGE_HANDLE_CLOSE))
  35. #define FILTER_NETWORK (CLUSTER_CHANGE_NETWORK_STATE | \
  36. CLUSTER_CHANGE_NETWORK_DELETED | \
  37. CLUSTER_CHANGE_NETWORK_ADDED | \
  38. CLUSTER_CHANGE_NETWORK_PROPERTY)
  39. #define NOT_FILTER_NETWORK (~(FILTER_NETWORK | CLUSTER_CHANGE_HANDLE_CLOSE))
  40. #define FILTER_NETINTERFACE (CLUSTER_CHANGE_NETINTERFACE_STATE | \
  41. CLUSTER_CHANGE_NETINTERFACE_DELETED | \
  42. CLUSTER_CHANGE_NETINTERFACE_ADDED | \
  43. CLUSTER_CHANGE_NETINTERFACE_PROPERTY)
  44. #define NOT_FILTER_NETINTERFACE (~(FILTER_NETINTERFACE | CLUSTER_CHANGE_HANDLE_CLOSE))
  45. #define FILTER_CLUSTER (CLUSTER_CHANGE_CLUSTER_STATE | \
  46. CLUSTER_CHANGE_CLUSTER_RECONNECT)
  47. #define NOT_FILTER_CLUSTER (~(FILTER_CLUSTER | CLUSTER_CHANGE_HANDLE_CLOSE))
  48. //
  49. // Define prototypes for functions local to this module
  50. //
  51. VOID
  52. DestroyNotify(
  53. IN PCNOTIFY Notify
  54. );
  55. VOID
  56. DestroySession(
  57. IN PCNOTIFY_SESSION Session
  58. );
  59. PCNOTIFY_SESSION
  60. CreateNotifySession(
  61. IN PCNOTIFY Notify,
  62. IN PCLUSTER Cluster
  63. );
  64. DWORD
  65. AddEventToSession(
  66. IN PCNOTIFY_SESSION Session,
  67. IN PVOID Object,
  68. IN DWORD dwFilter,
  69. IN DWORD_PTR dwNotifyKey
  70. );
  71. DWORD
  72. NotifyThread(
  73. IN LPVOID lpThreadParameter
  74. );
  75. DWORD
  76. GetClusterNotifyCallback(
  77. IN PLIST_ENTRY ListEntry,
  78. IN OUT PVOID Context
  79. );
  80. HCHANGE
  81. WINAPI
  82. CreateClusterNotifyPort(
  83. IN OPTIONAL HCHANGE hChange,
  84. IN OPTIONAL HCLUSTER hCluster,
  85. IN DWORD dwFilter,
  86. IN DWORD_PTR dwNotifyKey
  87. )
  88. /*++
  89. Routine Description:
  90. Creates a cluster notification port to be used for notification of
  91. cluster state changes.
  92. Arguments:
  93. hChange - Optionally supplies a handle to an existing cluster notification
  94. port. If present, the specified notification events will be added
  95. to the existing port.
  96. hCluster - Optionally supplies a handle to the cluster. If not present, an
  97. empty notification port will be created. CreateClusterNotifyPort
  98. and RegisterClusterNotify may be used later to add notification
  99. events to the notification port.
  100. dwFilter - Supplies the events that will be delivered to the
  101. notification port. Any events of the specified type will be
  102. delivered to the notification port. Currently defined event
  103. types are:
  104. CLUSTER_CHANGE_NODE_STATE
  105. CLUSTER_CHANGE_NODE_DELETED
  106. CLUSTER_CHANGE_NODE_ADDED
  107. CLUSTER_CHANGE_RESOURCE_STATE
  108. CLUSTER_CHANGE_RESOURCE_DELETED
  109. CLUSTER_CHANGE_RESOURCE_ADDED
  110. CLUSTER_CHANGE_GROUP_STATE
  111. CLUSTER_CHANGE_GROUP_DELETED
  112. CLUSTER_CHANGE_GROUP_ADDED
  113. CLUSTER_CHANGE_RESOURCE_TYPE_DELETED
  114. CLUSTER_CHANGE_RESOURCE_TYPE_ADDED
  115. CLUSTER_CHANGE_QUORUM_STATE
  116. dwNotifyKey - Supplies the notification key to be returned as
  117. part of the notification event.
  118. Return Value:
  119. If the function is successful, the return value is a handle of the
  120. change notification object.
  121. If the function fails, the return value is NULL. To get extended error
  122. information, call GetLastError.
  123. --*/
  124. {
  125. PCNOTIFY Notify;
  126. PCLUSTER Cluster;
  127. DWORD Status;
  128. PCNOTIFY_SESSION Session;
  129. if (hChange == INVALID_HANDLE_VALUE) {
  130. //
  131. // This is a newly created notification session
  132. //
  133. Notify = LocalAlloc(LMEM_FIXED, sizeof(CNOTIFY));
  134. if (Notify == NULL) {
  135. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  136. return(NULL);
  137. }
  138. InitializeListHead(&Notify->SessionList);
  139. InitializeListHead(&Notify->OrphanedEventList);
  140. InitializeCriticalSection(&Notify->Lock);
  141. ClRtlInitializeQueue(&Notify->Queue);
  142. #ifdef _WIN64
  143. ClRtlInitializeHash(&Notify->NotifyKeyHash);
  144. #else
  145. ZeroMemory(&Notify->NotifyKeyHash,sizeof(CL_HASH));
  146. #endif
  147. if (hCluster == INVALID_HANDLE_VALUE) {
  148. //
  149. // Caller has asked for an empty notification port.
  150. //
  151. return((HCHANGE)Notify);
  152. }
  153. } else {
  154. //
  155. // This is an existing notification port that the specified
  156. // cluster should be added to.
  157. //
  158. Notify = (PCNOTIFY)hChange;
  159. if ((hCluster == INVALID_HANDLE_VALUE) ||
  160. (hCluster == NULL)) {
  161. SetLastError(ERROR_INVALID_PARAMETER);
  162. return(NULL);
  163. }
  164. }
  165. Cluster = (PCLUSTER)hCluster;
  166. //
  167. // Chittur Subbaraman (chitturs) - 4/11/2000
  168. //
  169. // Make sure the cluster lock is acquired before the notify lock.
  170. // If this order is violated, it could be a potential source of
  171. // hard-to-track deadlocks.
  172. //
  173. EnterCriticalSection(&Cluster->Lock);
  174. EnterCriticalSection(&Notify->Lock);
  175. Session = CreateNotifySession(Notify, Cluster);
  176. if (Session == NULL) {
  177. Status = GetLastError();
  178. LeaveCriticalSection(&Notify->Lock);
  179. LeaveCriticalSection(&Cluster->Lock);
  180. if (hChange == INVALID_HANDLE_VALUE) {
  181. DestroyNotify(Notify);
  182. }
  183. SetLastError(Status);
  184. return(NULL);
  185. }
  186. Status = AddEventToSession(Session,
  187. NULL,
  188. dwFilter,
  189. dwNotifyKey);
  190. LeaveCriticalSection(&Notify->Lock);
  191. LeaveCriticalSection(&Cluster->Lock);
  192. if (Status != ERROR_SUCCESS) {
  193. if (hChange == INVALID_HANDLE_VALUE) {
  194. DestroyNotify(Notify);
  195. }
  196. SetLastError(Status);
  197. return(NULL);
  198. }
  199. TIME_PRINT(("CreateClusterNotifyPort: Returning Notify=0x%08lx\n",
  200. Notify));
  201. return((HCHANGE)Notify);
  202. }
  203. PCNOTIFY_SESSION
  204. CreateNotifySession(
  205. IN PCNOTIFY Notify,
  206. IN PCLUSTER Cluster
  207. )
  208. /*++
  209. Routine Description:
  210. This routine finds a notification session to the specified cluster.
  211. If a session already exists, it is found and used. If a session does
  212. not exist, a new one is created.
  213. The Notify lock must be held.
  214. Arguments:
  215. Notify - Supplies the notification port.
  216. Cluster - Supplies the cluster that the session should be opened to.
  217. Return Value:
  218. A pointer to the notification session.
  219. NULL on error, GetLastError() will return the specific error code.
  220. --*/
  221. {
  222. PLIST_ENTRY ListEntry;
  223. PCNOTIFY_SESSION Session;
  224. error_status_t Status = ERROR_SUCCESS;
  225. //
  226. // First, try to find an existing session.
  227. //
  228. ListEntry = Notify->SessionList.Flink;
  229. while (ListEntry != &Notify->SessionList) {
  230. Session = CONTAINING_RECORD(ListEntry,
  231. CNOTIFY_SESSION,
  232. ListEntry);
  233. if (Session->Cluster == Cluster) {
  234. TIME_PRINT(("CreateNotifySession: found a matching session\n"));
  235. //
  236. // Found a match, return it directly.
  237. //
  238. return(Session);
  239. }
  240. ListEntry = ListEntry->Flink;
  241. }
  242. //
  243. // There is no existing session. Go ahead and create a new one.
  244. //
  245. Session = LocalAlloc(LMEM_FIXED, sizeof(CNOTIFY_SESSION));
  246. if (Session == NULL) {
  247. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  248. return(NULL);
  249. }
  250. TIME_PRINT(("CreateNotifySession: Calling ApiCreateNotify\n"));
  251. WRAP_NULL(Session->hNotify,
  252. (ApiCreateNotify(Cluster->RpcBinding, &Status)),
  253. &Status,
  254. Cluster);
  255. if ((Session->hNotify == NULL) || (Status != ERROR_SUCCESS)) {
  256. LocalFree(Session);
  257. SetLastError(Status);
  258. return(NULL);
  259. }
  260. InitializeListHead(&Session->EventList);
  261. Session->Cluster = Cluster;
  262. Session->ParentNotify = Notify;
  263. Session->Destroyed = FALSE;
  264. //
  265. // Spin up the notification thread for this session.
  266. //
  267. Session->NotifyThread = CreateThread(NULL,
  268. 0,
  269. NotifyThread,
  270. Session,
  271. 0,
  272. NULL);
  273. if (Session->NotifyThread == NULL) {
  274. Status = GetLastError();
  275. ApiCloseNotify(&Session->hNotify);
  276. LocalFree(Session);
  277. SetLastError(Status);
  278. return(NULL);
  279. }
  280. InsertHeadList(&Notify->SessionList, &Session->ListEntry);
  281. EnterCriticalSection(&Cluster->Lock);
  282. InsertHeadList(&Cluster->SessionList, &Session->ClusterList);
  283. LeaveCriticalSection(&Cluster->Lock);
  284. TIME_PRINT(("CreateNotifySession: Session=0x%08lx hNotifyRpc=0x%08lx Thread=0x%08lx\n",
  285. Session, Session->hNotify, NotifyThread));
  286. return(Session);
  287. }
  288. DWORD
  289. NotifyThread(
  290. IN LPVOID lpThreadParameter
  291. )
  292. /*++
  293. Routine Description:
  294. Notification thread that gets notification messages from the cluster
  295. and reposts them to the client-side notify queue.
  296. Arguments:
  297. lpThreadParameter - Supplies the CNOTIFY_SESSION structure to be monitored
  298. Return Value:
  299. None.
  300. --*/
  301. {
  302. PCNOTIFY_SESSION Session = (PCNOTIFY_SESSION)lpThreadParameter;
  303. PCLUSTER Cluster = Session->Cluster;
  304. PLIST_ENTRY ListEntry;
  305. PCNOTIFY_EVENT Event;
  306. DWORD Status = ERROR_INVALID_HANDLE_STATE;
  307. error_status_t rpc_error;
  308. PCNOTIFY_PACKET Packet;
  309. LPWSTR Name;
  310. do {
  311. if (Session->Destroyed)
  312. {
  313. TIME_PRINT(("NotifyThread: Session 0x%08lx destroyed\n",
  314. Session));
  315. break;
  316. }
  317. Packet = LocalAlloc(LMEM_FIXED, sizeof(CNOTIFY_PACKET));
  318. if (Packet == NULL) {
  319. Status = ERROR_NOT_ENOUGH_MEMORY;
  320. break;
  321. }
  322. Packet->Status = ERROR_SUCCESS;
  323. Packet->Name = NULL;
  324. TIME_PRINT(("NotifyThread: Calling ApiGetNotify, hNotify=0x%08lx\n",
  325. Session->hNotify));
  326. WRAP_CHECK(Status,
  327. (ApiGetNotify(Session->hNotify,
  328. INFINITE,
  329. &Packet->KeyId,
  330. &Packet->Filter,
  331. &Packet->StateSequence,
  332. &Packet->Name)),
  333. Session->Cluster,
  334. !Session->Destroyed);
  335. if (Status != ERROR_SUCCESS)
  336. {
  337. TIME_PRINT(("NotifyThread : ApiGetNotify on hNotify=0x%08lx returns %u\n",
  338. Session->hNotify, Status));
  339. //if the error is due to a reconnect, hide it and map it to success
  340. if ((Status == ERROR_NO_MORE_ITEMS) && (Session->hNotify != NULL))
  341. {
  342. //set the status to sucess again - this might happen on a
  343. //reconnect and then we do want to continue
  344. //so we retry apigetnotify again
  345. Status = ERROR_SUCCESS;
  346. LocalFree(Packet);
  347. TIME_PRINT(("NotifyThread : Reconnect map error to success\n"));
  348. }
  349. else
  350. {
  351. //when can we be sure that the cluster is dead?
  352. //If session is null(reconnect failed) OR
  353. //If the cluster is marked dead(reconnect failed after session was established) OR
  354. //If the cluster is dead, and wrap returns RPC_S_SERVER_UNAVAILABLE
  355. //if so, we can terminate this thread because the thread
  356. //maps to a cluster
  357. //what do we document, if this returns error, call closeclusternotifyport
  358. if ((Session->hNotify == NULL) ||
  359. (Session->Cluster->Flags & CLUS_DEAD) ||
  360. (Status == RPC_S_SERVER_UNAVAILABLE))
  361. {
  362. //SS: it is not clear why we post this event
  363. //multiple times??? Chittur, any ideas????
  364. //Does this mean that if you register for the
  365. //same filter twice, you get the event twice?
  366. // We should probably hold the cluster lock here
  367. EnterCriticalSection(&Cluster->Lock);
  368. //That seems bizarre.
  369. //
  370. // Something horrible has happened, probably the cluster has crashed.
  371. //
  372. // Run down the notify list for this cluster and post a packet for
  373. // each registered notify event for CLUSTER_CHANGE_CLUSTER_STATE
  374. //
  375. Name = Cluster->ClusterName;
  376. ListEntry = Cluster->NotifyList.Flink;
  377. while (ListEntry != &Cluster->NotifyList) {
  378. Event = CONTAINING_RECORD(ListEntry,
  379. CNOTIFY_EVENT,
  380. ObjectList);
  381. if (Event->dwFilter & CLUSTER_CHANGE_CLUSTER_STATE) {
  382. if (Packet == NULL) {
  383. Packet = LocalAlloc(LMEM_FIXED, sizeof(CNOTIFY_PACKET));
  384. if (Packet == NULL) {
  385. LeaveCriticalSection(&Cluster->Lock);
  386. return(ERROR_NOT_ENOUGH_MEMORY);
  387. }
  388. }
  389. //SS: Dont know what the Status was meant for
  390. //It looks like it is not being used
  391. Packet->Status = ERROR_SUCCESS;
  392. Packet->Filter = CLUSTER_CHANGE_CLUSTER_STATE;
  393. Packet->KeyId = Event->EventId;
  394. Packet->Name = MIDL_user_allocate((lstrlenW(Name)+1)*sizeof(WCHAR));
  395. if (Packet->Name != NULL) {
  396. lstrcpyW(Packet->Name, Name);
  397. }
  398. TIME_PRINT(("NotifyThread - posting CLUSTER_CHANGE_CLUSTER_STATE to notify queue\n"));
  399. ClRtlInsertTailQueue(&Session->ParentNotify->Queue,
  400. &Packet->ListEntry);
  401. Packet = NULL;
  402. }
  403. ListEntry = ListEntry->Flink;
  404. }
  405. LeaveCriticalSection(&Cluster->Lock);
  406. //cluster is dead, map the error to success
  407. Status = ERROR_SUCCESS;
  408. //break out of the loop to terminate this thread
  409. TIME_PRINT(("NotifyThread : Cluster is dead, break to exit notify thread\n"));
  410. LocalFree(Packet);
  411. break;
  412. }
  413. else
  414. {
  415. //it is some other error, the user must
  416. //call closeclusternotify port to clean up
  417. //this thread
  418. //free the packet
  419. LocalFree(Packet);
  420. }
  421. }
  422. }
  423. else
  424. {
  425. //
  426. // Post this onto the notification queue
  427. //
  428. ClRtlInsertTailQueue(&Session->ParentNotify->Queue,
  429. &Packet->ListEntry);
  430. }
  431. } while ( Status == ERROR_SUCCESS );
  432. return(Status);
  433. }
  434. DWORD
  435. AddEventToSession(
  436. IN PCNOTIFY_SESSION Session,
  437. IN PVOID Object,
  438. IN DWORD dwFilter,
  439. IN DWORD_PTR dwNotifyKey
  440. )
  441. /*++
  442. Routine Description:
  443. Adds a specific event to a cluster notification session
  444. Arguments:
  445. Notify - Supplies the notify object
  446. Object - Supplies the specific object, NULL if it is the cluster.
  447. dwFilter - Supplies the type of events
  448. dwNotifyKey - Supplies the notification key to be returned.
  449. Return Value:
  450. ERROR_SUCCESS if successful
  451. Win32 error code otherwise.
  452. --*/
  453. {
  454. PCNOTIFY_EVENT NotifyEvent;
  455. PCLUSTER Cluster;
  456. PLIST_ENTRY NotifyList;
  457. DWORD Status;
  458. Cluster = Session->Cluster;
  459. NotifyEvent = LocalAlloc(LMEM_FIXED, sizeof(CNOTIFY_EVENT));
  460. if (NotifyEvent == NULL) {
  461. return(ERROR_NOT_ENOUGH_MEMORY);
  462. }
  463. NotifyEvent->Session = Session;
  464. NotifyEvent->dwFilter = dwFilter;
  465. NotifyEvent->dwNotifyKey = dwNotifyKey;
  466. NotifyEvent->Object = Object;
  467. #ifdef _WIN64
  468. NotifyEvent->EventId = 0;
  469. Status = ClRtlInsertTailHash(&Session->ParentNotify->NotifyKeyHash,
  470. NotifyEvent, &NotifyEvent->EventId);
  471. if (ERROR_SUCCESS != Status) {
  472. LocalFree(NotifyEvent);
  473. return(Status);
  474. }
  475. #else
  476. NotifyEvent->EventId=(DWORD)NotifyEvent;
  477. #endif
  478. WRAP(Status,
  479. (RegisterNotifyEvent(Session,
  480. NotifyEvent,
  481. &NotifyList)),
  482. Cluster);
  483. if (Status != ERROR_SUCCESS) {
  484. #ifdef _WIN64
  485. ClRtlRemoveEntryHash(&Session->ParentNotify->NotifyKeyHash,
  486. NotifyEvent->EventId);
  487. #endif
  488. LocalFree(NotifyEvent);
  489. return(Status);
  490. }
  491. //
  492. // Add this notification event to the appropriate lists so it can be
  493. // recreated when the cluster node fails.
  494. //
  495. EnterCriticalSection(&Cluster->Lock);
  496. EnterCriticalSection(&Session->ParentNotify->Lock);
  497. InsertHeadList(&Session->EventList, &NotifyEvent->ListEntry);
  498. InsertHeadList(NotifyList, &NotifyEvent->ObjectList);
  499. LeaveCriticalSection(&Session->ParentNotify->Lock);
  500. LeaveCriticalSection(&Cluster->Lock);
  501. return(ERROR_SUCCESS);
  502. }
  503. DWORD
  504. RegisterNotifyEvent(
  505. IN PCNOTIFY_SESSION Session,
  506. IN PCNOTIFY_EVENT Event,
  507. OUT OPTIONAL PLIST_ENTRY *pNotifyList
  508. )
  509. /*++
  510. Routine Description:
  511. Common routine for registering a notification event on
  512. a cluster session
  513. Arguments:
  514. Session - Supplies the notification session the event
  515. should be added to.
  516. Event - Supplies the event to be added to the session.
  517. NotifyList - if present, returns the list that the notification
  518. event should be added to.
  519. Return Value:
  520. ERROR_SUCCESS if successful
  521. Win32 error otherwise.
  522. --*/
  523. {
  524. DWORD Status;
  525. if (Event->Object == NULL) {
  526. TIME_PRINT(("RegisterNotifyEvent : Calling ApiAddNotifyCluster\n"));
  527. Status = ApiAddNotifyCluster(Session->hNotify,
  528. Session->Cluster->hCluster,
  529. Event->dwFilter,
  530. Event->EventId);
  531. if (ARGUMENT_PRESENT(pNotifyList)) {
  532. *pNotifyList = &Session->Cluster->NotifyList;
  533. }
  534. } else if (Event->dwFilter & FILTER_NODE) {
  535. Status = ApiAddNotifyNode(Session->hNotify,
  536. ((PCNODE)(Event->Object))->hNode,
  537. Event->dwFilter,
  538. Event->EventId,
  539. &Event->StateSequence);
  540. if (ARGUMENT_PRESENT(pNotifyList)) {
  541. *pNotifyList = &((PCNODE)(Event->Object))->NotifyList;
  542. }
  543. } else if (Event->dwFilter & FILTER_RESOURCE) {
  544. Status = ApiAddNotifyResource(Session->hNotify,
  545. ((PCRESOURCE)(Event->Object))->hResource,
  546. Event->dwFilter,
  547. Event->EventId,
  548. &Event->StateSequence);
  549. if (ARGUMENT_PRESENT(pNotifyList)) {
  550. *pNotifyList = &((PCRESOURCE)(Event->Object))->NotifyList;
  551. }
  552. } else if (Event->dwFilter & FILTER_GROUP) {
  553. Status = ApiAddNotifyGroup(Session->hNotify,
  554. ((PCGROUP)(Event->Object))->hGroup,
  555. Event->dwFilter,
  556. Event->EventId,
  557. &Event->StateSequence);
  558. if (ARGUMENT_PRESENT(pNotifyList)) {
  559. *pNotifyList = &((PCGROUP)(Event->Object))->NotifyList;
  560. }
  561. } else if (Event->dwFilter & FILTER_NETWORK) {
  562. Status = ApiAddNotifyNetwork(Session->hNotify,
  563. ((PCNETWORK)(Event->Object))->hNetwork,
  564. Event->dwFilter,
  565. Event->EventId,
  566. &Event->StateSequence);
  567. if (ARGUMENT_PRESENT(pNotifyList)) {
  568. *pNotifyList = &((PCNETWORK)(Event->Object))->NotifyList;
  569. }
  570. } else if (Event->dwFilter & FILTER_NETINTERFACE) {
  571. Status = ApiAddNotifyNetInterface(Session->hNotify,
  572. ((PCNETINTERFACE)(Event->Object))->hNetInterface,
  573. Event->dwFilter,
  574. Event->EventId,
  575. &Event->StateSequence);
  576. if (ARGUMENT_PRESENT(pNotifyList)) {
  577. *pNotifyList = &((PCNETINTERFACE)(Event->Object))->NotifyList;
  578. }
  579. } else if (Event->dwFilter & FILTER_REGISTRY) {
  580. Status = ApiAddNotifyKey(Session->hNotify,
  581. ((PCKEY)(Event->Object))->RemoteKey,
  582. Event->EventId,
  583. Event->dwFilter & ~CLUSTER_CHANGE_REGISTRY_SUBTREE,
  584. (Event->dwFilter & CLUSTER_CHANGE_REGISTRY_SUBTREE) ? TRUE : FALSE);
  585. if (ARGUMENT_PRESENT(pNotifyList)) {
  586. *pNotifyList = &((PCKEY)(Event->Object))->NotifyList;
  587. }
  588. } else if (Event->dwFilter & FILTER_CLUSTER) {
  589. Status = ERROR_SUCCESS;
  590. if (ARGUMENT_PRESENT(pNotifyList)) {
  591. *pNotifyList = &Session->Cluster->NotifyList;
  592. }
  593. }
  594. else {
  595. return(ERROR_INVALID_PARAMETER);
  596. }
  597. TIME_PRINT(("RegisterNotifyEvent :returned 0x%08lx\n",
  598. Status));
  599. return(Status);
  600. }
  601. DWORD
  602. ReRegisterNotifyEvent(
  603. IN PCNOTIFY_SESSION Session,
  604. IN PCNOTIFY_EVENT Event,
  605. OUT OPTIONAL PLIST_ENTRY *pNotifyList
  606. )
  607. /*++
  608. Routine Description:
  609. Common routine for re-registering a notification event on
  610. a cluster session. The only difference between this and
  611. RegisterNotifyEvent is that this passes the SessionState
  612. DWORD to the server, which will cause an immediate notification
  613. trigger if it does not match.
  614. Arguments:
  615. Session - Supplies the notification session the event
  616. should be added to.
  617. Event - Supplies the event to be added to the session.
  618. NotifyList - if present, returns the list that the notification
  619. event should be added to.
  620. Return Value:
  621. ERROR_SUCCESS if successful
  622. Win32 error otherwise.
  623. --*/
  624. {
  625. DWORD Status;
  626. if (Event->Object == NULL) {
  627. Status = ApiAddNotifyCluster(Session->hNotify,
  628. Session->Cluster->hCluster,
  629. Event->dwFilter,
  630. Event->EventId);
  631. if (ARGUMENT_PRESENT(pNotifyList)) {
  632. *pNotifyList = &Session->Cluster->NotifyList;
  633. }
  634. } else if (Event->dwFilter & FILTER_NODE) {
  635. Status = ApiReAddNotifyNode(Session->hNotify,
  636. ((PCNODE)(Event->Object))->hNode,
  637. Event->dwFilter,
  638. Event->EventId,
  639. Event->StateSequence);
  640. if (ARGUMENT_PRESENT(pNotifyList)) {
  641. *pNotifyList = &((PCNODE)(Event->Object))->NotifyList;
  642. }
  643. } else if (Event->dwFilter & FILTER_RESOURCE) {
  644. Status = ApiReAddNotifyResource(Session->hNotify,
  645. ((PCRESOURCE)(Event->Object))->hResource,
  646. Event->dwFilter,
  647. Event->EventId,
  648. Event->StateSequence);
  649. if (ARGUMENT_PRESENT(pNotifyList)) {
  650. *pNotifyList = &((PCRESOURCE)(Event->Object))->NotifyList;
  651. }
  652. } else if (Event->dwFilter & FILTER_GROUP) {
  653. Status = ApiReAddNotifyGroup(Session->hNotify,
  654. ((PCGROUP)(Event->Object))->hGroup,
  655. Event->dwFilter,
  656. Event->EventId,
  657. Event->StateSequence);
  658. if (ARGUMENT_PRESENT(pNotifyList)) {
  659. *pNotifyList = &((PCGROUP)(Event->Object))->NotifyList;
  660. }
  661. } else if (Event->dwFilter & FILTER_NETWORK) {
  662. Status = ApiReAddNotifyNetwork(Session->hNotify,
  663. ((PCNETWORK)(Event->Object))->hNetwork,
  664. Event->dwFilter,
  665. Event->EventId,
  666. Event->StateSequence);
  667. if (ARGUMENT_PRESENT(pNotifyList)) {
  668. *pNotifyList = &((PCNETWORK)(Event->Object))->NotifyList;
  669. }
  670. } else if (Event->dwFilter & FILTER_NETINTERFACE) {
  671. Status = ApiReAddNotifyNetInterface(Session->hNotify,
  672. ((PCNETINTERFACE)(Event->Object))->hNetInterface,
  673. Event->dwFilter,
  674. Event->EventId,
  675. Event->StateSequence);
  676. if (ARGUMENT_PRESENT(pNotifyList)) {
  677. *pNotifyList = &((PCNETINTERFACE)(Event->Object))->NotifyList;
  678. }
  679. } else if (Event->dwFilter & FILTER_REGISTRY) {
  680. Status = ApiAddNotifyKey(Session->hNotify,
  681. ((PCKEY)(Event->Object))->RemoteKey,
  682. Event->EventId,
  683. Event->dwFilter & ~CLUSTER_CHANGE_REGISTRY_SUBTREE,
  684. (Event->dwFilter & CLUSTER_CHANGE_REGISTRY_SUBTREE) ? TRUE : FALSE);
  685. if (ARGUMENT_PRESENT(pNotifyList)) {
  686. *pNotifyList = &((PCKEY)(Event->Object))->NotifyList;
  687. }
  688. } else if (Event->dwFilter & FILTER_CLUSTER) {
  689. Status = ERROR_SUCCESS;
  690. if (ARGUMENT_PRESENT(pNotifyList)) {
  691. *pNotifyList = &Session->Cluster->NotifyList;
  692. }
  693. }
  694. else {
  695. return(ERROR_INVALID_PARAMETER);
  696. }
  697. return(Status);
  698. }
  699. VOID
  700. DestroyNotify(
  701. IN PCNOTIFY Notify
  702. )
  703. /*++
  704. Routine Description:
  705. Cleans up and frees all allocations and references associated with
  706. a notification session.
  707. Arguments:
  708. Notify - supplies the CNOTIFY structure to be destroyed
  709. Return Value:
  710. None.
  711. --*/
  712. {
  713. PCNOTIFY_SESSION Session;
  714. PLIST_ENTRY ListEntry;
  715. PLIST_ENTRY EventList;
  716. PCRESOURCE Resource;
  717. PCGROUP Group;
  718. PCNODE Node;
  719. PCLUSTER Cluster;
  720. PCNOTIFY_EVENT Event;
  721. LIST_ENTRY QueueEntries;
  722. PCNOTIFY_PACKET Packet;
  723. //
  724. // Rundown each session associated with this notification session
  725. //
  726. while (!IsListEmpty(&Notify->SessionList)) {
  727. ListEntry = RemoveHeadList(&Notify->SessionList);
  728. Session = CONTAINING_RECORD(ListEntry,
  729. CNOTIFY_SESSION,
  730. ListEntry);
  731. Cluster = Session->Cluster;
  732. EnterCriticalSection(&Cluster->Lock);
  733. //
  734. // Rundown each event registered on this session.
  735. //
  736. while (!IsListEmpty(&Session->EventList)) {
  737. EventList = RemoveHeadList(&Session->EventList);
  738. Event = CONTAINING_RECORD(EventList,
  739. CNOTIFY_EVENT,
  740. ListEntry);
  741. RemoveEntryList(&Event->ObjectList);
  742. LocalFree(Event);
  743. }
  744. DestroySession(Session);
  745. LeaveCriticalSection(&Cluster->Lock);
  746. }
  747. //
  748. // Rundown any outstanding notifications remaining on the queue
  749. //
  750. ClRtlRundownQueue(&Notify->Queue, &QueueEntries);
  751. while (!IsListEmpty(&QueueEntries)) {
  752. ListEntry = RemoveHeadList(&QueueEntries);
  753. Packet = CONTAINING_RECORD(ListEntry,
  754. CNOTIFY_PACKET,
  755. ListEntry);
  756. MIDL_user_free(Packet->Name);
  757. LocalFree(Packet);
  758. }
  759. //
  760. // Now that we know there are no outstanding references to the orphaned
  761. // events, free up anything on that list.
  762. //
  763. while (!IsListEmpty(&Notify->OrphanedEventList)) {
  764. ListEntry = RemoveHeadList(&Notify->OrphanedEventList);
  765. Event = CONTAINING_RECORD(ListEntry,
  766. CNOTIFY_EVENT,
  767. ListEntry);
  768. LocalFree(Event);
  769. }
  770. DeleteCriticalSection(&Notify->Lock);
  771. ClRtlDeleteQueue(&Notify->Queue);
  772. #ifdef _WIN64
  773. ClRtlDeleteHash(&Notify->NotifyKeyHash);
  774. #endif
  775. LocalFree(Notify);
  776. }
  777. DWORD
  778. WINAPI
  779. RegisterClusterNotify(
  780. IN HCHANGE hChange,
  781. IN DWORD dwFilterType,
  782. IN HANDLE hObject,
  783. IN DWORD_PTR dwNotifyKey
  784. )
  785. /*++
  786. Routine Description:
  787. Adds a specific notification type to a cluster notification port. This allows
  788. an application to register for notification events that affect only a particular
  789. cluster object. The currently supported specific cluster objects are nodes,
  790. resources, and groups.
  791. Arguments:
  792. hChange - Supplies the change notification object.
  793. dwFilterType - Supplies the type of object that the specific notification
  794. events should be delivered for. hObject is a handle to an object
  795. of this type. Currently supported specific filters include:
  796. CLUSTER_CHANGE_NODE_STATE - hObject is an HNODE
  797. CLUSTER_CHANGE_RESOURCE_STATE - hObject is an HRESOURCE
  798. CLUSTER_CHANGE_GROUP_STATE - hObject is an HGROUP
  799. CLUSTER_CHANGE_REGISTRY_NAME \
  800. CLUSTER_CHANGE_REGISTRY_ATTRIBUTES \ - hObject is an HKEY
  801. CLUSTER_CHANGE_REGISTRY_VALUE /
  802. CLUSTER_CHANGE_REGISTRY_SUBTREE /
  803. hObject - Supplies the handle to the specific object of the type specified
  804. by dwFilterType.
  805. dwNotifyKey - Supplies the notification key to be returned as
  806. part of the notification event.
  807. Return Value:
  808. ERROR_SUCCESS if successful.
  809. Win32 error code otherwise.
  810. --*/
  811. {
  812. PCNOTIFY Notify;
  813. PCLUSTER Cluster;
  814. PCNOTIFY_SESSION Session;
  815. DWORD dwStatus;
  816. if (dwFilterType & FILTER_NODE) {
  817. if (dwFilterType & NOT_FILTER_NODE) {
  818. return(ERROR_INVALID_PARAMETER);
  819. }
  820. Cluster = ((PCNODE)hObject)->Cluster;
  821. } else if (dwFilterType & FILTER_RESOURCE) {
  822. if (dwFilterType & NOT_FILTER_RESOURCE) {
  823. return(ERROR_INVALID_PARAMETER);
  824. }
  825. Cluster = ((PCRESOURCE)hObject)->Cluster;
  826. } else if (dwFilterType & FILTER_GROUP) {
  827. if (dwFilterType & NOT_FILTER_GROUP) {
  828. return(ERROR_INVALID_PARAMETER);
  829. }
  830. Cluster = ((PCGROUP)hObject)->Cluster;
  831. } else if (dwFilterType & FILTER_NETWORK) {
  832. if (dwFilterType & NOT_FILTER_NETWORK) {
  833. return(ERROR_INVALID_PARAMETER);
  834. }
  835. Cluster = ((PCNETWORK)hObject)->Cluster;
  836. } else if (dwFilterType & FILTER_NETINTERFACE) {
  837. if (dwFilterType & NOT_FILTER_NETINTERFACE) {
  838. return(ERROR_INVALID_PARAMETER);
  839. }
  840. Cluster = ((PCNETINTERFACE)hObject)->Cluster;
  841. } else if (dwFilterType & FILTER_REGISTRY) {
  842. if (dwFilterType & NOT_FILTER_REGISTRY) {
  843. return(ERROR_INVALID_PARAMETER);
  844. }
  845. Cluster = ((PCKEY)hObject)->Cluster;
  846. } else if (dwFilterType & FILTER_CLUSTER){
  847. if (dwFilterType & NOT_FILTER_CLUSTER){
  848. return(ERROR_INVALID_PARAMETER);
  849. }
  850. Cluster = (PCLUSTER)hObject;
  851. } else {
  852. return(ERROR_INVALID_PARAMETER);
  853. }
  854. Notify = (PCNOTIFY)hChange;
  855. EnterCriticalSection(&Cluster->Lock);
  856. EnterCriticalSection(&Notify->Lock);
  857. Session = CreateNotifySession(Notify, Cluster);
  858. if (Session == NULL) {
  859. LeaveCriticalSection(&Notify->Lock);
  860. LeaveCriticalSection(&Cluster->Lock);
  861. return(GetLastError());
  862. }
  863. dwStatus = AddEventToSession(Session,
  864. hObject,
  865. dwFilterType,
  866. dwNotifyKey);
  867. LeaveCriticalSection(&Notify->Lock);
  868. LeaveCriticalSection(&Cluster->Lock);
  869. return( dwStatus );
  870. }
  871. DWORD
  872. WINAPI
  873. GetClusterNotify(
  874. IN HCHANGE hChange,
  875. OUT DWORD_PTR *lpdwNotifyKey,
  876. OUT LPDWORD lpdwFilterType,
  877. OUT OPTIONAL LPWSTR lpszName,
  878. IN OUT LPDWORD lpcchName,
  879. IN DWORD dwMilliseconds
  880. )
  881. /*++
  882. Routine Description:
  883. Returns the next event from a cluster notification port.
  884. Arguments:
  885. hChange - Supplies the cluster notification port.
  886. lpdwNotifyKey - Returns the notification key for the notification event.
  887. This is the key passed to CreateClusterNotifyPort or RegisterClusterNotify.
  888. lpdwFilterType - Returns the type of the notification event.
  889. lpszName - Optionally returns the name of the object that triggered the notification
  890. event.
  891. lpcchName - Supplies the length (in characters) of the lpszName buffer. This length
  892. includes the space for any trailing NULL.
  893. Returns the length (in characters) of the name written into the lpszName
  894. buffer. This length does not include the trailing NULL.
  895. dwMilliseconds - Supplies an optional timeout value that specifies
  896. how long the caller is willing to wait for the cluster notification event.
  897. Return Value:
  898. ERROR_SUCCESS if successful. If lpszName is NULL we return success and fill in
  899. lpcchName with the size. If lpcchName is NULL we return ERROR_MORE_DATA.
  900. ERROR_MORE_DATA if the buffer is too small.
  901. Win32 error code otherwise.
  902. --*/
  903. {
  904. PCNOTIFY_PACKET Packet;
  905. PLIST_ENTRY ListEntry;
  906. PCNOTIFY Notify = (PCNOTIFY)hChange;
  907. DWORD Length;
  908. DWORD Status;
  909. PCNOTIFY_EVENT Event;
  910. PVOID BufferArray[2];
  911. BufferArray[0] = lpszName;
  912. BufferArray[1] = lpcchName;
  913. //
  914. // ListEntry will be NULL under the following conditions (as determined by the ret value from
  915. // GetClusterNotifyCallback):
  916. //
  917. // lpszName == NULL, lpcchName != NULL (looking for a buffer size) (ERROR_MORE_DATA)
  918. // lpszName != NULL, lpcchName != NULL, and *lpcchName <= Length (ERROR_MORE_DATA)
  919. //
  920. ListEntry = ClRtlRemoveHeadQueueTimeout(&Notify->Queue, dwMilliseconds, GetClusterNotifyCallback,BufferArray);
  921. if (ListEntry == NULL) {
  922. //
  923. // The queue has been rundown or a timeout has occurred, or the buffer isn't big enough.
  924. //
  925. Status = GetLastError();
  926. if (lpszName==NULL && lpcchName!=NULL) {
  927. //
  928. // We returned ERROR_MORE_DATA from GetClusterNotifyCallback to prevent a dequeueing,
  929. // but we want to return ERROR_SUCCESS because a buffer wasn't specified (maintains
  930. // consistency with the other Cluster APIs)
  931. //
  932. Status = ERROR_SUCCESS;
  933. }
  934. return(Status);
  935. }
  936. Packet = CONTAINING_RECORD(ListEntry,
  937. CNOTIFY_PACKET,
  938. ListEntry);
  939. #ifdef _WIN64
  940. Event = (PCNOTIFY_EVENT)ClRtlGetEntryHash(&Notify->NotifyKeyHash,
  941. Packet->KeyId);
  942. if (Event == NULL) {
  943. //
  944. // The entry is missing
  945. //
  946. MIDL_user_free(Packet->Name);
  947. LocalFree(Packet);
  948. //
  949. // should not happen unless the memory is corrupted
  950. //
  951. return(ERROR_NOT_FOUND);
  952. }
  953. #else
  954. Event = (PCNOTIFY_EVENT)Packet->KeyId;
  955. #endif
  956. Event->StateSequence = Packet->StateSequence;
  957. *lpdwNotifyKey = Event->dwNotifyKey;
  958. *lpdwFilterType = Packet->Filter;
  959. if (ARGUMENT_PRESENT(lpszName)) {
  960. MylstrcpynW(lpszName, Packet->Name, *lpcchName);
  961. Length = lstrlenW(Packet->Name);
  962. if (Length < *lpcchName) {
  963. *lpcchName = Length;
  964. }
  965. }
  966. MIDL_user_free(Packet->Name);
  967. LocalFree(Packet);
  968. return(ERROR_SUCCESS);
  969. }
  970. BOOL
  971. WINAPI
  972. CloseClusterNotifyPort(
  973. IN HCHANGE hChange
  974. )
  975. /*++
  976. Routine Description:
  977. Closes a handle of a change notification object.
  978. Arguments:
  979. hChange - Supplies a handle of a cluster change notification object
  980. to close.
  981. Return Value:
  982. If the function is successful, the return value is TRUE.
  983. If the function fails, the return value is FALSE. To get extended error
  984. information, call GetLastError.
  985. Remarks:
  986. --*/
  987. {
  988. PCNOTIFY Notify = (PCNOTIFY)hChange;
  989. DestroyNotify(Notify);
  990. return(TRUE);
  991. }
  992. VOID
  993. RundownNotifyEvents(
  994. IN PLIST_ENTRY ListHead,
  995. IN LPCWSTR lpszName
  996. )
  997. /*++
  998. Routine Description:
  999. Cleans up any notification events on the specified list.
  1000. Arguments:
  1001. ListHead - Supplies the head of the list of notification events.
  1002. lpszName - Supplies the name that should be used to post the handle close
  1003. event.
  1004. Return Value:
  1005. None.
  1006. --*/
  1007. {
  1008. PCNOTIFY_EVENT Event;
  1009. PLIST_ENTRY ListEntry;
  1010. PCRITICAL_SECTION Lock;
  1011. PCNOTIFY_PACKET Packet;
  1012. while (!IsListEmpty(ListHead)) {
  1013. ListEntry = RemoveHeadList(ListHead);
  1014. Event = CONTAINING_RECORD(ListEntry,
  1015. CNOTIFY_EVENT,
  1016. ObjectList);
  1017. //
  1018. // Allocate a notification packet for delivering the handle
  1019. // close notification.
  1020. //
  1021. if (Event->dwFilter & CLUSTER_CHANGE_HANDLE_CLOSE) {
  1022. Packet = LocalAlloc(LMEM_FIXED, sizeof(CNOTIFY_PACKET));
  1023. if (Packet != NULL) {
  1024. Packet->Status = ERROR_SUCCESS;
  1025. Packet->KeyId = Event->EventId;
  1026. Packet->Filter = (DWORD)CLUSTER_CHANGE_HANDLE_CLOSE;
  1027. Packet->StateSequence = Event->StateSequence;
  1028. Packet->Name = MIDL_user_allocate((lstrlenW(lpszName)+1)*sizeof(WCHAR));
  1029. if (Packet->Name == NULL) {
  1030. LocalFree(Packet);
  1031. Packet = NULL;
  1032. } else {
  1033. lstrcpyW(Packet->Name, lpszName);
  1034. ClRtlInsertTailQueue(&Event->Session->ParentNotify->Queue,
  1035. &Packet->ListEntry);
  1036. }
  1037. }
  1038. }
  1039. Lock = &Event->Session->ParentNotify->Lock;
  1040. EnterCriticalSection(Lock);
  1041. RemoveEntryList(&Event->ListEntry);
  1042. //
  1043. // Note that we cannot just free the Event structure since there may be
  1044. // notification packets that reference this event in either the server-side
  1045. // or client-side queues. Instead we store it on the orphaned event list.
  1046. // It will be cleaned up when the session is closed or when a reconnect
  1047. // occurs. If we had some way to flush out the event queue we could use
  1048. // that instead.
  1049. //
  1050. InsertTailList(&Event->Session->ParentNotify->OrphanedEventList, &Event->ListEntry);
  1051. if (IsListEmpty(&Event->Session->EventList)) {
  1052. DestroySession(Event->Session);
  1053. }
  1054. LeaveCriticalSection(Lock);
  1055. }
  1056. }
  1057. VOID
  1058. DestroySession(
  1059. IN PCNOTIFY_SESSION Session
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. Destroys and cleans up an empty notification session. This
  1064. means closing the RPC context handle and waiting for the
  1065. notification thread to terminate itself. The session will
  1066. be removed from the notification ports list. The session
  1067. must be empty.
  1068. N.B. The cluster lock must be held.
  1069. Arguments:
  1070. Session - Supplies the session to be destroyed.
  1071. Return Value:
  1072. None.
  1073. --*/
  1074. {
  1075. DWORD dwStatus = ERROR_SUCCESS;
  1076. //
  1077. // Chittur Subbaraman (chitturs) - 4/19/2000
  1078. //
  1079. // In order to prevent the NotifyThread from calling ApiGetNotify
  1080. // during or after the context handle is destroyed, we split
  1081. // the notification port close into two steps. In the first step,
  1082. // we merely unblock the ApiGetNotify call and then wait for
  1083. // the NotifyThread to terminate without freeing the context handle.
  1084. // In the next step, after making sure that the NotifyThread has
  1085. // terminated, we free the context handle. This avoids an AV in RPC
  1086. // code caused by the ApiGetNotify call being made during or soon after
  1087. // the context handle is freed.
  1088. //
  1089. Session->Destroyed = TRUE;
  1090. TIME_PRINT(("Destroy session: Session 0x%08lx marked as destroyed\n",
  1091. Session));
  1092. //
  1093. // If the cluster is not dead, try to unblock the ApiGetNotify call.
  1094. //
  1095. if ( !( Session->Cluster->Flags & CLUS_DEAD ) &&
  1096. ( Session->hNotify != NULL ) )
  1097. {
  1098. TIME_PRINT(("Destroy session: Call ApiUnblockGetNotifyThread before NotifyThread termination, hNotify = 0x%08lx\n",
  1099. Session->hNotify));
  1100. dwStatus = ApiUnblockGetNotifyCall( Session->hNotify );
  1101. }
  1102. //
  1103. // If the ApiUnblockGetNotifyThread returned RPC_S_PROCNUM_OUT_OF_RANGE,
  1104. // it means you are talking to a server that does not support that
  1105. // API. Revert to the old (buggy) behavior then.
  1106. //
  1107. if ( dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
  1108. {
  1109. TIME_PRINT(("Destroy session: Call ApiCloseNotify before NotifyThread termination, hNotify = 0x%08lx\n",
  1110. Session->hNotify));
  1111. if ( ApiCloseNotify( &Session->hNotify ) != ERROR_SUCCESS )
  1112. {
  1113. TIME_PRINT(("Destroy session: Call RpcSmDestroyClientContext since ApiCloseNotify failed before terminating NotifyThread, hNotify = 0x%08lx\n",
  1114. Session->hNotify));
  1115. RpcSmDestroyClientContext( &Session->hNotify );
  1116. }
  1117. }
  1118. RemoveEntryList( &Session->ListEntry );
  1119. RemoveEntryList( &Session->ClusterList );
  1120. //
  1121. // Drop the critical section as the notification thread might be
  1122. // stuck waiting on it. Since the session has been removed from
  1123. // the cluster list, nobody can get to it anymore.
  1124. //
  1125. LeaveCriticalSection( &Session->Cluster->Lock );
  1126. WaitForSingleObject( Session->NotifyThread, INFINITE );
  1127. CloseHandle( Session->NotifyThread );
  1128. //
  1129. // Reacquire the cluster lock.
  1130. //
  1131. EnterCriticalSection( &Session->Cluster->Lock );
  1132. //
  1133. // If the ApiUnblockGetNotifyThread was successfully executed or
  1134. // it could not be made since the cluster was dead, then perform
  1135. // the context handle cleanup. Note that cleaning up the context
  1136. // handle here is safe since we know that the NotifyThread has
  1137. // terminated at this point and wouldn't use it any more.
  1138. //
  1139. if ( dwStatus != RPC_S_PROCNUM_OUT_OF_RANGE )
  1140. {
  1141. if ( Session->Cluster->Flags & CLUS_DEAD )
  1142. {
  1143. TIME_PRINT(("Destroy session: Call RpcSmDestroyClientContext after terminating NotifyThread, hNotify = 0x%08lx\n",
  1144. Session->hNotify));
  1145. if ( Session->hNotify != NULL )
  1146. {
  1147. RpcSmDestroyClientContext( &Session->hNotify );
  1148. }
  1149. } else
  1150. {
  1151. TIME_PRINT(("Destroy session: Call ApiCloseNotify after terminating NotifyThread, hNotify = 0x%08lx\n",
  1152. Session->hNotify));
  1153. dwStatus = ApiCloseNotify( &Session->hNotify );
  1154. if ( dwStatus != ERROR_SUCCESS )
  1155. {
  1156. TIME_PRINT(("Destroy session: Call RpcSmDestroyClientContext since ApiCloseNotify failed after terminating NotifyThread, hNotify = 0x%08lx\n",
  1157. Session->hNotify));
  1158. RpcSmDestroyClientContext( &Session->hNotify );
  1159. }
  1160. }
  1161. }
  1162. LocalFree( Session );
  1163. }
  1164. DWORD
  1165. GetClusterNotifyCallback(
  1166. IN PLIST_ENTRY ListEntry,
  1167. IN OUT PVOID pvContext
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. Check ListEntry to determine whether the buffer is big enough to contain the Name
  1172. Arguments:
  1173. ListEntry - Supplies the event to convert to a CNOTIFY_PACKET.
  1174. Context - A len 2 PVOID array containing the buffer pointer and a DWORD ptr to the
  1175. buffer length. On output the buffer len ptr contains the number of chars
  1176. needed.
  1177. Return Value:
  1178. ERROR_SUCCESS - The buffer is large enough to put the Name into.
  1179. ERROR_MORE_DATA - The buffer is too small.
  1180. --*/
  1181. {
  1182. PCNOTIFY_PACKET Packet;
  1183. DWORD Length;
  1184. LPWSTR pBuffer;
  1185. DWORD* pBufferLength;
  1186. PVOID *Context = (PVOID*)pvContext;
  1187. DWORD Status;
  1188. ASSERT( pvContext != NULL );
  1189. pBuffer = (LPWSTR)(Context[0]);
  1190. pBufferLength = (DWORD*)(Context[1]);
  1191. //
  1192. // Check the Name buffer size
  1193. //
  1194. Packet = CONTAINING_RECORD( ListEntry,
  1195. CNOTIFY_PACKET,
  1196. ListEntry );
  1197. //
  1198. // Nested if's to cover the four combinations of pBufferLength and pBuffer being
  1199. // NULL and non-NULL values.
  1200. //
  1201. if ( pBufferLength == NULL) {
  1202. if (pBuffer == NULL ) {
  1203. //
  1204. // We're not interested in filling a buffer, return ERROR_SUCCESS. This will
  1205. // cause an event to be dequeued.
  1206. //
  1207. Status = ERROR_SUCCESS;
  1208. } else { // pBuffer != NULL
  1209. //
  1210. // AV to maintain pre-Whistler functionality (ugh)
  1211. //
  1212. *pBufferLength = 0;
  1213. Status = ERROR_INVALID_PARAMETER;
  1214. }
  1215. } else {
  1216. //
  1217. // pBufferLength != NULL;
  1218. //
  1219. Length = wcslen( Packet->Name );
  1220. if (pBuffer == NULL ) {
  1221. //
  1222. // We're only interested in getting a buffer size, return ERROR_MORE_DATA to
  1223. // signify that we're not to dequeue an event. This will be re-interpreted in
  1224. // GetClusterNotify.
  1225. //
  1226. *pBufferLength = Length;
  1227. Status = ERROR_MORE_DATA;
  1228. } else { // pBuffer != NULL
  1229. //
  1230. // We need to determine whether the buffer is big enough - that determines
  1231. // whether we return ERROR_SUCCESS (it is) or ERROR_MORE_DATA (it isn't)
  1232. //
  1233. if (Length < *pBufferLength) {
  1234. //
  1235. // Success - the buffer is large enough.
  1236. //
  1237. Status = ERROR_SUCCESS;
  1238. } else {
  1239. //
  1240. // Failure - the buffer was too small. A buffer was specified, so we need to
  1241. // return ERROR_MORE_DATA.
  1242. //
  1243. *pBufferLength = Length;
  1244. Status = ERROR_MORE_DATA;
  1245. }
  1246. } // if: pBuffer == NULL
  1247. } // if: pBufferLength == NULL
  1248. return Status;
  1249. } //*** GetClusterNotifyCallback