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.

1068 lines
28 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. evtlog.c
  5. Abstract:
  6. Contains all the routines for supporting cluster wide eventlogging.
  7. Author:
  8. Sunita Shrivastava (sunitas) 24-Apr-1996
  9. Revision History:
  10. --*/
  11. #include "evtlogp.h"
  12. #include "simpleq.h"
  13. #include "nm.h" // to get NmLocalNodeIdString //
  14. #include "dm.h"
  15. //since the eventlog replication requires services.exe calling into the
  16. //cluster service
  17. LPWSTR g_pszServicesPath = NULL;
  18. DWORD g_dwServicesPid = 0;
  19. //
  20. // Local data
  21. //
  22. #define OUTGOING_PROPAGATION_ENABLED 0x00000001
  23. //#define INCOMING_PROPAGATION_ENABLED 0x00000002
  24. #define TRACE_EVERYTHING_ENABLED 0x00001000
  25. #define PROPAGATION_ENABLED OUTGOING_PROPAGATION_ENABLED
  26. static WORD LastFailHour = -1;
  27. static WORD LastFailDay = -1;
  28. static BITSET EvpUpNodeSet = 0;
  29. static SIMPLEQUEUE IncomingQueue;
  30. static SIMPLEQUEUE OutgoingQueue;
  31. static CLRTL_WORK_ITEM EvtlogWriterWorkItem;
  32. static CLRTL_WORK_ITEM EvtBroadcasterWorkItem;
  33. static DWORD DefaultNodePropagate = PROPAGATION_ENABLED;
  34. static DWORD DefaultClusterPropagate = PROPAGATION_ENABLED;
  35. #define AsyncEvtlogReplication CLUSTER_MAKE_VERSION(NT5_MAJOR_VERSION,1978)
  36. #define OUTGOING_QUEUE_SIZE (16384)
  37. #define OUTGOING_QUEUE_NAME L"System Event Replication Output Queue"
  38. #define INCOMING_QUEUE_SIZE (OUTGOING_QUEUE_SIZE * 3)
  39. #define INCOMING_QUEUE_NAME L"System Event Replication Input Queue"
  40. #define DROPPED_DATA_NOTIFY_INTERVAL (2*60) // in seconds (2mins)
  41. #define CHECK_CLUSTER_REGISTRY_EVERY 10 // seconds
  42. #define EVTLOG_TRACE_EVERYTHING 1
  43. #ifdef EVTLOG_TRACE_EVERYTHING
  44. # define EvtlogPrint(__evtlogtrace__) \
  45. do { if (EventlogTraceEverything) {ClRtlLogPrint __evtlogtrace__;} } while(0)
  46. #else
  47. # define EvtLogPrint(x)
  48. #endif
  49. DWORD EventlogTraceEverything = 0;
  50. RPC_BINDING_HANDLE EvtRpcBindings[ClusterMinNodeId + ClusterDefaultMaxNodes];
  51. BOOLEAN EvInitialized = FALSE;
  52. /////////////// Forward Declarations ////////////////
  53. DWORD
  54. InitializeQueues(
  55. VOID
  56. );
  57. VOID
  58. DestroyQueues(
  59. VOID);
  60. VOID
  61. ReadRegistryKeys(
  62. VOID);
  63. VOID
  64. PeriodicRegistryCheck(
  65. VOID);
  66. ///////////// End of forward Declarations ////////////
  67. /****
  68. @doc EXTERNAL INTERFACES CLUSSVC EVTLOG
  69. ****/
  70. /****
  71. @func DWORD | EvInitialize| This initializes the cluster
  72. wide eventlog replicating services.
  73. @rdesc Returns a result code. ERROR_SUCCESS on success.
  74. @comm
  75. @xref <f EvShutdown>
  76. ****/
  77. DWORD EvInitialize()
  78. {
  79. DWORD i;
  80. WCHAR wServicesName[] = L"services.exe";
  81. WCHAR wCallerModuleName[] = L"\\system32\\";
  82. WCHAR wCallerPath[MAX_PATH + 1];
  83. LPWSTR pszServicesPath;
  84. DWORD dwNumChar;
  85. DWORD dwStatus = ERROR_SUCCESS;
  86. //
  87. // Initialize Per-node information
  88. //
  89. for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++) {
  90. EvtRpcBindings[i] = NULL;
  91. }
  92. //get the path name for %windir%\system32\services.exe
  93. dwNumChar = GetWindowsDirectoryW(wCallerPath, MAX_PATH);
  94. if(dwNumChar == 0)
  95. {
  96. dwStatus = GetLastError();
  97. goto FnExit;
  98. }
  99. //need to allocate more memory
  100. pszServicesPath = LocalAlloc(LMEM_FIXED, (sizeof(WCHAR) *
  101. (lstrlenW(wCallerPath) + lstrlenW(wCallerModuleName) +
  102. lstrlenW(wServicesName) + 1)));
  103. if (!pszServicesPath)
  104. {
  105. dwStatus = GetLastError();
  106. goto FnExit;
  107. }
  108. lstrcpyW(pszServicesPath, wCallerPath);
  109. lstrcatW(pszServicesPath, wCallerModuleName);
  110. lstrcatW(pszServicesPath, wServicesName);
  111. g_pszServicesPath = pszServicesPath;
  112. EvInitialized = TRUE;
  113. FnExit:
  114. return(dwStatus);
  115. } // EvInitialize
  116. /****
  117. @doc EXTERNAL INTERFACES CLUSSVC EVTLOG
  118. ****/
  119. /****
  120. @func DWORD | EvOnline| This finishes initializing the cluster
  121. wide eventlog replicating services.
  122. @rdesc Returns a result code. ERROR_SUCCESS on success.
  123. @comm This calls ElfrRegisterClusterSvc() and calls EvpPropPendingEvents()
  124. to propagate events logged since the start of the eventlog service.
  125. @xref <f EvShutdown>
  126. ****/
  127. DWORD EvOnline()
  128. {
  129. DWORD dwError=ERROR_SUCCESS;
  130. PPACKEDEVENTINFO pPackedEventInfo=NULL;
  131. DWORD dwEventInfoSize;
  132. DWORD dwSequence;
  133. CLUSTER_NODE_STATE state;
  134. DWORD i;
  135. PNM_NODE node;
  136. ClRtlLogPrint(LOG_NOISE, "[EVT] EvOnline\n");
  137. dwError = InitializeQueues();
  138. if (dwError != ERROR_SUCCESS) {
  139. return dwError;
  140. }
  141. //
  142. // Register for node up/down events.
  143. //
  144. dwError = EpRegisterEventHandler(
  145. (CLUSTER_EVENT_NODE_UP | CLUSTER_EVENT_NODE_DOWN_EX),
  146. EvpClusterEventHandler
  147. );
  148. if (dwError != ERROR_SUCCESS) {
  149. ClRtlLogPrint(LOG_NOISE,
  150. "[EVT] EvInitialize : Failed to register for cluster events, status %1!u!\n",
  151. dwError);
  152. return(dwError);
  153. }
  154. //
  155. // Initialize Per-node information
  156. //
  157. for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++)
  158. {
  159. if (i != NmLocalNodeId) {
  160. node = NmReferenceNodeById(i);
  161. if (node != NULL) {
  162. DWORD version = NmGetNodeHighestVersion(node);
  163. state = NmGetNodeState(node);
  164. if ( (state == ClusterNodeUp) ||
  165. (state == ClusterNodePaused)
  166. )
  167. {
  168. if (version >= AsyncEvtlogReplication) {
  169. BitsetAdd(EvpUpNodeSet, i);
  170. ClRtlLogPrint(LOG_NOISE,
  171. "[EVT] Node up: %1!u!, new UpNodeSet: %2!04x!\n",
  172. i,
  173. EvpUpNodeSet
  174. );
  175. } else {
  176. ClRtlLogPrint(LOG_NOISE,
  177. "[EVT] Evtlog replication is not allowed for node %1!u! (version %2!x!)\n",
  178. i,
  179. version
  180. );
  181. }
  182. }
  183. OmDereferenceObject(node);
  184. }
  185. }
  186. }
  187. //TODO :: SS - currently the eventlog propagation api
  188. //has been added to clusapi. In future, if we need
  189. //to define a general purpose interface for communication
  190. //with other services on the same system, then we need
  191. //to register and advertize that interface here.
  192. //call the event logger to get routines that have been logged so far.
  193. ClRtlLogPrint(LOG_NOISE, "[EVT] EvOnline : calling ElfRegisterClusterSvc\n");
  194. dwError = ElfRegisterClusterSvc(NULL, &dwEventInfoSize, &pPackedEventInfo);
  195. if (dwError != ERROR_SUCCESS)
  196. {
  197. ClRtlLogPrint(LOG_CRITICAL,
  198. "[EVT] EvOnline : ElfRegisterClusterSvc returned %1!u!\n",
  199. dwError);
  200. return(dwError);
  201. }
  202. //post them to other nodes in the cluster
  203. if (pPackedEventInfo && dwEventInfoSize)
  204. {
  205. ClRtlLogPrint(LOG_NOISE,
  206. "[EVT] EvOnline: pPackedEventInfo->ulSize=%1!d! pPackedEventInfo->ulNulEventsForLogFile=%2!d!\r\n",
  207. pPackedEventInfo->ulSize, pPackedEventInfo->ulNumEventsForLogFile);
  208. EvpPropPendingEvents(dwEventInfoSize, pPackedEventInfo);
  209. MIDL_user_free ( pPackedEventInfo );
  210. }
  211. return (dwError);
  212. }
  213. /****
  214. @func DWORD | EvCreateRpcBindings| This creates an RPC binding
  215. for a specified node.
  216. @rdesc Returns a result code. ERROR_SUCCESS on success.
  217. @comm
  218. @xref
  219. ****/
  220. DWORD
  221. EvCreateRpcBindings(
  222. PNM_NODE Node
  223. )
  224. {
  225. DWORD Status;
  226. RPC_BINDING_HANDLE BindingHandle;
  227. CL_NODE_ID NodeId = NmGetNodeId(Node);
  228. ClRtlLogPrint(LOG_NOISE,
  229. "[EVT] Creating RPC bindings for node %1!u!.\n",
  230. NodeId
  231. );
  232. //
  233. // Main binding
  234. //
  235. if (EvtRpcBindings[NodeId] != NULL) {
  236. //
  237. // Reuse the old binding.
  238. //
  239. Status = ClMsgVerifyRpcBinding(EvtRpcBindings[NodeId]);
  240. if (Status != ERROR_SUCCESS) {
  241. ClRtlLogPrint(LOG_ERROR,
  242. "[EVT] Failed to verify 1st RPC binding for node %1!u!, status %2!u!.\n",
  243. NodeId,
  244. Status
  245. );
  246. return(Status);
  247. }
  248. }
  249. else {
  250. //
  251. // Create a new binding
  252. //
  253. Status = ClMsgCreateRpcBinding(
  254. Node,
  255. &(EvtRpcBindings[NodeId]),
  256. 0 );
  257. if (Status != ERROR_SUCCESS) {
  258. ClRtlLogPrint(LOG_ERROR,
  259. "[EVT] Failed to create 1st RPC binding for node %1!u!, status %2!u!.\n",
  260. NodeId,
  261. Status
  262. );
  263. return(Status);
  264. }
  265. }
  266. return(ERROR_SUCCESS);
  267. } // EvCreateRpcBindings
  268. /****
  269. @func DWORD | EvShutdown| This deinitializes the cluster
  270. wide eventlog replication services.
  271. @rdesc Returns a result code. ERROR_SUCCESS on success.
  272. @comm The cluster register deregisters with the eventlog service.
  273. @xref <f EvInitialize>
  274. ****/
  275. DWORD EvShutdown(void)
  276. {
  277. DWORD dwError=ERROR_SUCCESS;
  278. if (EvInitialized) {
  279. PPACKEDEVENTINFO pPackedEventInfo;
  280. DWORD dwEventInfoSize;
  281. DWORD i;
  282. ClRtlLogPrint(LOG_NOISE,
  283. "[EVT] EvShutdown\r\n");
  284. //call the event logger to get routines that have been logged so far.
  285. ElfDeregisterClusterSvc(NULL);
  286. DestroyQueues();
  287. // TODO [GorN 9/23/1999]
  288. // When DestroyQueues starts doing what it is supposed to do,
  289. // (i.e. flush/wait/destroy), enable the code below
  290. #if 0
  291. //
  292. // Free per-node information
  293. //
  294. for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++) {
  295. if (EvtRpcBindings[i] != NULL) {
  296. ClMsgDeleteRpcBinding(EvtRpcBindings[i]);
  297. EvtRpcBindings[i] = NULL;
  298. }
  299. }
  300. #endif
  301. }
  302. return (dwError);
  303. }
  304. /****
  305. @func DWORD | EvpClusterEventHandler| Handler for internal cluster
  306. events.
  307. @rdesc Returns a result code. ERROR_SUCCESS on success.
  308. @comm
  309. @xref <f EvInitialize>
  310. ****/
  311. DWORD
  312. EvpClusterEventHandler(
  313. IN CLUSTER_EVENT Event,
  314. IN PVOID Context
  315. )
  316. {
  317. DWORD NodeId;
  318. if (Event == CLUSTER_EVENT_NODE_UP) {
  319. PNM_NODE node = (PNM_NODE) Context;
  320. CL_NODE_ID nodeId = NmGetNodeId(node);
  321. DWORD version = NmGetNodeHighestVersion(node);
  322. if ( version >= AsyncEvtlogReplication )
  323. {
  324. BitsetAdd(EvpUpNodeSet, nodeId);
  325. ClRtlLogPrint(LOG_NOISE,
  326. "[EVT] Node up: %1!u!, new UpNodeSet: %2!04x!\n",
  327. nodeId,
  328. EvpUpNodeSet
  329. );
  330. } else {
  331. ClRtlLogPrint(LOG_NOISE,
  332. "[EVT] Evtlog replication is not allowed for node %1!u! (version %2!x!)\n",
  333. nodeId,
  334. version
  335. );
  336. }
  337. }
  338. else if (Event == CLUSTER_EVENT_NODE_DOWN_EX) {
  339. BITSET downedNodes = (BITSET)((ULONG_PTR)Context);
  340. BitsetSubtract(EvpUpNodeSet, downedNodes);
  341. ClRtlLogPrint(LOG_NOISE,
  342. "[EVT] Nodes down: %1!04X!, new UpNodeSet: %2!04x!\n",
  343. downedNodes,
  344. EvpUpNodeSet
  345. );
  346. }
  347. return(ERROR_SUCCESS);
  348. }
  349. /****
  350. @func DWORD | s_EvPropEvents| This is the server entry point for
  351. receiving eventlog information from other nodes of the cluster
  352. and logging them locally.
  353. @parm IN handle_t | IDL_handle | The rpc binding handle. Unused.
  354. @parm IN DWORD | dwEventInfoSize | the size of the packed event info structure.
  355. @parm IN UCHAR | *pBuffer| A pointer to the packed
  356. eventinfo structure.
  357. @rdesc returns ERROR_SUCCESS if successful else returns the error code.
  358. @comm This function calls ElfWriteClusterEvents() to log the event propagted
  359. from another node.
  360. @xref
  361. ****/
  362. DWORD
  363. s_EvPropEvents(
  364. IN handle_t IDL_handle,
  365. IN DWORD dwEventInfoSize,
  366. IN UCHAR *pBuffer
  367. )
  368. {
  369. PUCHAR end = pBuffer + dwEventInfoSize;
  370. if ( dwEventInfoSize >= sizeof(DWORD) && dwEventInfoSize == (*(PDWORD)pBuffer)) {
  371. ClRtlLogPrint(LOG_UNUSUAL,
  372. "[EVT] Improperly formed packet received of size %1!u!.\n",
  373. dwEventInfoSize
  374. );
  375. return ERROR_SUCCESS;
  376. }
  377. #ifdef CLUSTER_BETA
  378. EvtlogPrint((LOG_NOISE, "[EVT] s_EvPropEvents. dwEventInfoSize=%1!d!\r\n",
  379. dwEventInfoSize));
  380. #endif
  381. while (pBuffer < end) {
  382. BOOL success;
  383. success = SimpleQueueTryAdd(&IncomingQueue, SQB_PAYLOADSIZE(pBuffer), SQB_PAYLOAD(pBuffer));
  384. if ( !success ) {
  385. EvtlogPrint((LOG_NOISE, "[EVT] s_EvPropEvents. Put(IncomingQ,%1!d!) failed. empty=%2!d!\n",
  386. SQB_PAYLOADSIZE(pBuffer), IncomingQueue.Empty) );
  387. }
  388. pBuffer = SQB_NEXTBLOCK(pBuffer);
  389. }
  390. return(ERROR_SUCCESS);
  391. }
  392. /****
  393. @func DWORD | EvpPropPendingEvents| This is called to propagate all the pending
  394. events since the start of the system. And then to propagate any events
  395. generated during the life of the cluster.
  396. @parm IN DWORD | dwEventInfoSize | the size of the packed event info structure.
  397. @parm IN PPACKEDEVENTINFO | pPackedEventInfo| A pointer to the packed
  398. eventinfo structure.
  399. @rdesc returns ERROR_SUCCESS if successful else returns the error code.
  400. @comm This function is called during initialization when a cluster is being formed.
  401. @xref
  402. ****/
  403. DWORD EvpPropPendingEvents(
  404. IN DWORD dwEventInfoSize,
  405. IN PPACKEDEVENTINFO pPackedEventInfo)
  406. {
  407. BOOL success;
  408. success = SimpleQueueTryAdd(&OutgoingQueue, dwEventInfoSize, pPackedEventInfo);
  409. if ( !success ) {
  410. EvtlogPrint((LOG_NOISE, "[EVT] EvpPropPendingEvents: Put(OutgoingQ,%1!d!) failed. empty=%2!d!\n",
  411. dwEventInfoSize, OutgoingQueue.Empty));
  412. }
  413. return ERROR_SUCCESS;
  414. }
  415. /****
  416. @func DWORD | s_ApiEvPropEvents | This is called to propagate eventlogs from
  417. the local system to all other nodes of the cluster.
  418. @parm handle_t | IDL_handle | Not used.
  419. @parm DWORD | dwEventInfoSize | The number of bytes in the following structure.
  420. @parm UCHAR * | pPackedEventInfo | Pointer to a byte structure containing the
  421. PACKEDEVENTINFO structure.
  422. @rdesc Returns ERROR_SUCCESS if successfully propagated events,
  423. else returns the error code.
  424. @comm Currently this function is called for every eventlogged by the eventlog
  425. service. Only the processes running in the SYSTEM account can call this
  426. function.
  427. @xref
  428. ****/
  429. error_status_t
  430. s_ApiEvPropEvents(
  431. IN handle_t IDL_handle,
  432. IN DWORD dwEventInfoSize,
  433. IN UCHAR *pPackedEventInfo
  434. )
  435. {
  436. DWORD dwError = ERROR_SUCCESS;
  437. BOOL bIsLocalSystemAccount;
  438. #if 0
  439. //
  440. // Chittur Subbaraman (chitturs) - 11/7/1999
  441. //
  442. // Modify this function to use ClRtlIsCallerAccountLocalSystemAccount
  443. // instead of GetUserName which
  444. // (1) used to hang in security audit enabled systems if security
  445. // audit log attempts to write to the event log at the time we
  446. // made that API call since that API and the security audit log
  447. // are mutually exclusive for some portions, and
  448. // (2) wrongly checked for an unlocalizable output value "SYSTEM"
  449. // from that API in order to grant access to the client.
  450. //
  451. //
  452. // Impersonate the client.
  453. //
  454. if ( ( dwError = RpcImpersonateClient( IDL_handle ) ) != RPC_S_OK )
  455. {
  456. ClRtlLogPrint( LOG_ERROR,
  457. "[EVT] s_ApiEvPropEvents: Error %1!d! trying to impersonate caller...\n",
  458. dwError
  459. );
  460. goto FnExit;
  461. }
  462. //
  463. // Check that the caller's account is local system account
  464. //
  465. if ( ( dwError = ClRtlIsCallerAccountLocalSystemAccount(
  466. &bIsLocalSystemAccount ) != ERROR_SUCCESS ) )
  467. {
  468. RpcRevertToSelf();
  469. ClRtlLogPrint( LOG_ERROR,
  470. "[EVT] s_ApiEvPropEvents: Error %1!d! trying to check caller's account...\n",
  471. dwError);
  472. goto FnExit;
  473. }
  474. if ( !bIsLocalSystemAccount )
  475. {
  476. RpcRevertToSelf();
  477. dwError = ERROR_ACCESS_DENIED;
  478. ClRtlLogPrint( LOG_ERROR,
  479. "[EVT] s_ApiEvPropEvents: Caller's account is not local system account, denying access...\n");
  480. goto FnExit;
  481. }
  482. RpcRevertToSelf();
  483. #endif
  484. //
  485. // All security checks have passed. Drop the eventlog info into
  486. // the queue.
  487. //
  488. if ( dwEventInfoSize && pPackedEventInfo )
  489. {
  490. dwError = EvpPropPendingEvents( dwEventInfoSize,
  491. ( PPACKEDEVENTINFO ) pPackedEventInfo );
  492. }
  493. return( dwError );
  494. }
  495. VOID
  496. EvtlogWriter(
  497. IN PCLRTL_WORK_ITEM WorkItem,
  498. IN DWORD Status,
  499. IN DWORD BytesTransferred,
  500. IN ULONG_PTR IoContext
  501. )
  502. /*++
  503. Routine Description:
  504. This work item reads events from the
  505. incoming queue and writes them to EventLog service
  506. Arguments:
  507. Not used.
  508. Return Value:
  509. None
  510. --*/
  511. {
  512. PVOID begin, end;
  513. SYSTEMTIME localTime;
  514. DWORD eventsWritten = 0;
  515. #ifdef CLUSTER_BETA
  516. EvtlogPrint( (LOG_NOISE, "[EVT] EvtlogWriter Work Item fired.\n") );
  517. #endif
  518. do {
  519. DWORD dwError;
  520. if ( !SimpleQueueReadOne(&IncomingQueue, &begin, &end) )
  521. {
  522. break;
  523. }
  524. #ifdef CLUSTER_BETA
  525. EvtlogPrint( (LOG_NOISE, "[EVT] EvtlogWriter got %1!d!.\n",
  526. (PUCHAR)end - (PUCHAR)begin ) );
  527. #endif
  528. dwError = ElfWriteClusterEvents(
  529. NULL,
  530. SQB_PAYLOADSIZE(begin),
  531. (PPACKEDEVENTINFO)SQB_PAYLOAD(begin) );
  532. if ( dwError != ERROR_SUCCESS ) {
  533. GetLocalTime( &localTime );
  534. // LastFailHour is initialized to -1, which should not equal any wHour!
  535. // LastFailDay is initialized to -1, which should not equal any wDay!
  536. if ( (LastFailHour != localTime.wHour) || (LastFailDay != localTime.wDay) ) {
  537. LastFailHour = localTime.wHour;
  538. LastFailDay = localTime.wDay;
  539. ClRtlLogPrint(LOG_UNUSUAL,
  540. "[EVT] ElfWriteClusterEvents failed: status = %1!u!\n",
  541. dwError);
  542. }
  543. }
  544. PeriodicRegistryCheck();
  545. } while ( SimpleQueueReadComplete(&IncomingQueue, end) );
  546. #ifdef CLUSTER_BETA
  547. EvtlogPrint( (LOG_NOISE, "[EVT] EvtlogWriter: done.\n" ) );
  548. #endif
  549. if ( eventsWritten > 0 ) {
  550. EvtlogPrint( (LOG_NOISE, "[EVT] EvtlogWriter: wrote %u events to system event log.\n", eventsWritten ) );
  551. }
  552. CheckForDroppedData(&IncomingQueue, FALSE);
  553. }
  554. VOID
  555. EvtBroadcaster(
  556. IN PCLRTL_WORK_ITEM WorkItem,
  557. IN DWORD Status,
  558. IN DWORD BytesTransferred,
  559. IN ULONG_PTR IoContext
  560. )
  561. /*++
  562. Routine Description:
  563. This work item reads events from the
  564. outgoing queue and RPCs them to all active nodes
  565. Arguments:
  566. Not used.
  567. Return Value:
  568. None
  569. --*/
  570. {
  571. PVOID begin, end;
  572. #ifdef CLUSTER_BETA
  573. EvtlogPrint( (LOG_NOISE, "[EVT] EvtBroadcaster Work Item fired.\n") );
  574. #endif
  575. do {
  576. DWORD i;
  577. if( !SimpleQueueReadAll(&OutgoingQueue, &begin, &end) )
  578. {
  579. break;
  580. }
  581. #ifdef CLUSTER_BETA
  582. EvtlogPrint((LOG_NOISE, "[EVT] EvtBroadcaster got %1!d!.\n",
  583. (PUCHAR)end - (PUCHAR)begin ) );
  584. #endif
  585. for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++)
  586. {
  587. if (BitsetIsMember(i, EvpUpNodeSet) && (i != NmLocalNodeId))
  588. {
  589. DWORD dwError;
  590. CL_ASSERT(EvtRpcBindings[i] != NULL);
  591. NmStartRpc(i);
  592. dwError = EvPropEvents(EvtRpcBindings[i],
  593. (DWORD)((PUCHAR)end - (PUCHAR)begin),
  594. (PBYTE)begin);
  595. NmEndRpc(i);
  596. if ( dwError != ERROR_SUCCESS ) {
  597. ClRtlLogPrint(LOG_UNUSUAL,
  598. "[EVT] EvpPropPendingEvents: EvPropEvents for node %1!u! "
  599. "failed. status %2!u!\n",
  600. i,
  601. dwError);
  602. NmDumpRpcExtErrorInfo(dwError);
  603. }
  604. }
  605. }
  606. PeriodicRegistryCheck();
  607. } while ( SimpleQueueReadComplete(&OutgoingQueue, end) );
  608. #ifdef CLUSTER_BETA
  609. EvtlogPrint( (LOG_NOISE, "[EVT] EvtBroadcaster: done.\n" ) );
  610. #endif
  611. CheckForDroppedData(&OutgoingQueue, FALSE);
  612. }
  613. VOID
  614. OutgoingQueueDataAvailable(
  615. IN PSIMPLEQUEUE q
  616. )
  617. /*++
  618. Routine Description:
  619. This routine is called by the queue to notify
  620. that there are data in the queue available for processing
  621. Arguments:
  622. q - which queue has data
  623. Return Value:
  624. None
  625. --*/
  626. {
  627. DWORD status = ClRtlPostItemWorkQueue(
  628. CsDelayedWorkQueue,
  629. &EvtBroadcasterWorkItem,
  630. 0,
  631. 0
  632. );
  633. if (status != ERROR_SUCCESS) {
  634. ClRtlLogPrint(LOG_CRITICAL,
  635. "[EVT] OutgoingQueueDataAvailable, PostWorkItem failed, error %1!u! !\n",
  636. status);
  637. }
  638. }
  639. VOID
  640. IncomingQueueDataAvailable(
  641. IN PSIMPLEQUEUE q
  642. )
  643. /*++
  644. Routine Description:
  645. This routine is called by the queue to notify
  646. that there are data in the queue available for processing
  647. Arguments:
  648. q - which queue has data
  649. Return Value:
  650. None
  651. --*/
  652. {
  653. DWORD status = ClRtlPostItemWorkQueue(
  654. CsDelayedWorkQueue,
  655. &EvtlogWriterWorkItem,
  656. 0,
  657. 0
  658. );
  659. if (status != ERROR_SUCCESS) {
  660. ClRtlLogPrint(LOG_CRITICAL,
  661. "[EVT] IncomingQueueDataAvailable, PostWorkItem failed, error %1!u! !\n",
  662. status);
  663. }
  664. }
  665. VOID
  666. DroppedDataNotify(
  667. IN PWCHAR QueueName,
  668. IN DWORD DroppedDataCount,
  669. IN DWORD DroppedDataSize
  670. )
  671. /*++
  672. Routine Description:
  673. This routine is called by the queue to notify
  674. that some data were lost because the queue was full
  675. Arguments:
  676. QueueName - Queue Name
  677. DataCount - How many chunks of data were lost
  678. DataSize - Total size fo the lost data
  679. Return Value:
  680. None
  681. --*/
  682. {
  683. WCHAR count[32];
  684. WCHAR size[32];
  685. ClRtlLogPrint(LOG_UNUSUAL,
  686. "[EVT] %1!ws!: dropped %2!d!, total dropped size %3!d!.\n",
  687. QueueName,
  688. DroppedDataCount,
  689. DroppedDataSize );
  690. wsprintfW(count+0, L"%u", DroppedDataCount);
  691. wsprintfW(size+0, L"%u", DroppedDataSize);
  692. ClusterLogEvent3(LOG_UNUSUAL,
  693. LOG_CURRENT_MODULE,
  694. __FILE__,
  695. __LINE__,
  696. EVTLOG_DATA_DROPPED,
  697. 0,
  698. NULL,
  699. QueueName,
  700. count,
  701. size);
  702. }
  703. ////////////////////////////////////////////////////////////////////////////
  704. LARGE_INTEGER RegistryCheckInterval;
  705. LARGE_INTEGER NextRegistryCheckAt;
  706. DWORD
  707. InitializeQueues(
  708. VOID)
  709. {
  710. DWORD status, OutgoingQueueStatus;
  711. status =
  712. SimpleQueueInitialize(
  713. &OutgoingQueue,
  714. OUTGOING_QUEUE_SIZE,
  715. OUTGOING_QUEUE_NAME,
  716. OutgoingQueueDataAvailable,
  717. DroppedDataNotify,
  718. DROPPED_DATA_NOTIFY_INTERVAL // seconds //
  719. );
  720. if (status != ERROR_SUCCESS) {
  721. ClRtlLogPrint(LOG_CRITICAL,
  722. "[EVT] Failed to create '%1!ws!', error %2!u!.\n",
  723. OUTGOING_QUEUE_NAME, status );
  724. }
  725. OutgoingQueueStatus = status;
  726. status =
  727. SimpleQueueInitialize(
  728. &IncomingQueue,
  729. INCOMING_QUEUE_SIZE,
  730. INCOMING_QUEUE_NAME,
  731. IncomingQueueDataAvailable,
  732. DroppedDataNotify,
  733. DROPPED_DATA_NOTIFY_INTERVAL // seconds //
  734. );
  735. if (status != ERROR_SUCCESS) {
  736. ClRtlLogPrint(LOG_CRITICAL,
  737. "[EVT] Failed to create '%1!ws!', error %2!u!.\n",
  738. INCOMING_QUEUE_NAME, status );
  739. }
  740. ClRtlInitializeWorkItem(
  741. &EvtBroadcasterWorkItem,
  742. EvtBroadcaster,
  743. (PVOID) &OutgoingQueue
  744. );
  745. ClRtlInitializeWorkItem(
  746. &EvtlogWriterWorkItem,
  747. EvtlogWriter,
  748. (PVOID) &IncomingQueue
  749. );
  750. RegistryCheckInterval.QuadPart = Int32x32To64(10 * 1000 * 1000, CHECK_CLUSTER_REGISTRY_EVERY);
  751. NextRegistryCheckAt.QuadPart = 0;
  752. ReadRegistryKeys();
  753. return OutgoingQueueStatus;
  754. }
  755. ////////////////////////////////////////////////////////////////////////////
  756. VOID
  757. DestroyQueues(
  758. VOID)
  759. {
  760. CheckForDroppedData(&IncomingQueue, TRUE);
  761. CheckForDroppedData(&OutgoingQueue, TRUE);
  762. // [GN] TODO
  763. // Add proper destruction of queues
  764. }
  765. VOID
  766. ReadRegistryKeys(
  767. VOID)
  768. /*
  769. *
  770. */
  771. {
  772. HDMKEY nodeKey;
  773. DWORD NodePropagate;
  774. DWORD ClusterPropagate;
  775. static DWORD OldPropagateState = 0xCAFEBABE;
  776. DWORD status;
  777. nodeKey = DmOpenKey(
  778. DmNodesKey,
  779. NmLocalNodeIdString,
  780. KEY_READ
  781. );
  782. if (nodeKey != NULL) {
  783. status = DmQueryDword(
  784. nodeKey,
  785. CLUSREG_NAME_CLUS_EVTLOG_PROPAGATION,
  786. &NodePropagate,
  787. &DefaultNodePropagate
  788. );
  789. if (status != ERROR_SUCCESS) {
  790. ClRtlLogPrint(
  791. LOG_UNUSUAL,
  792. "[EVT] Unable to query propagation mode for local node, status %1!u!.\n",
  793. status
  794. );
  795. }
  796. DmCloseKey(nodeKey);
  797. }
  798. else {
  799. ClRtlLogPrint(
  800. LOG_UNUSUAL,
  801. "[EVT] Unable to open database key to local node, status %1!u!. Assuming default settings.\n",
  802. GetLastError());
  803. NodePropagate = DefaultNodePropagate;
  804. }
  805. status = DmQueryDword(
  806. DmClusterParametersKey,
  807. CLUSREG_NAME_CLUS_EVTLOG_PROPAGATION,
  808. &ClusterPropagate,
  809. &DefaultClusterPropagate
  810. );
  811. if (status != ERROR_SUCCESS) {
  812. ClRtlLogPrint(
  813. LOG_UNUSUAL,
  814. "[EVT] Unable to query global propagation mode, status %1!u!.\n",
  815. status
  816. );
  817. }
  818. NodePropagate &= ClusterPropagate;
  819. if (NodePropagate != OldPropagateState) {
  820. ClRtlLogPrint(
  821. LOG_UNUSUAL,
  822. "[EVT] Set propagation state to %1!04x!\n", NodePropagate
  823. );
  824. if (NodePropagate & OUTGOING_PROPAGATION_ENABLED) {
  825. if (OutgoingQueue.Begin) {
  826. OutgoingQueue.Enabled = 1;
  827. }
  828. } else {
  829. OutgoingQueue.Enabled = 0;
  830. }
  831. #if 0
  832. if (NodePropagate & INCOMING_PROPAGATION_ENABLED) {
  833. if (IncomingQueue.Begin) {
  834. IncomingQueue.Enabled = 1;
  835. }
  836. } else {
  837. IncomingQueue.Enabled = 0;
  838. }
  839. #endif
  840. if(NodePropagate & TRACE_EVERYTHING_ENABLED) {
  841. EventlogTraceEverything = 1;
  842. } else {
  843. EventlogTraceEverything = 0;
  844. }
  845. OldPropagateState = NodePropagate;
  846. }
  847. }
  848. VOID
  849. PeriodicRegistryCheck(
  850. VOID)
  851. {
  852. LARGE_INTEGER currentTime;
  853. GetSystemTimeAsFileTime( (LPFILETIME)&currentTime);
  854. if( currentTime.QuadPart > NextRegistryCheckAt.QuadPart ) {
  855. ReadRegistryKeys();
  856. NextRegistryCheckAt.QuadPart = currentTime.QuadPart + RegistryCheckInterval.QuadPart;
  857. }
  858. }