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.

1527 lines
36 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. dummyiis.c
  5. Abstract:
  6. This file was adapted from \nt\private\cluster\resdll\dummy\dummy.c. It
  7. implements an NT Cluster resource DLL for the IIS Virtual Root resource type.
  8. This resource does nothing except read the value "Parameters\Failed" from the
  9. resource definition in the registry on each poll to determine whether or not the resource
  10. has failed.
  11. The DLL is to be installed during UPGRADE from NT 4.0. It will become obsolete
  12. with the availability of a IIS Virtual Root resource DLL that works with IIS 5.
  13. Author:
  14. John Vert (jvert) 5-Dec-1995
  15. Revision History:
  16. C. Brent Thomas (a-brentt) 29-May-1998
  17. Adapted for IIS Virtual Root reaource type.
  18. --*/
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include "clusapi.h"
  22. #include "resapi.h"
  23. //
  24. // Local Types.
  25. //
  26. typedef enum TimerType {
  27. TimerNotUsed,
  28. TimerErrorPending,
  29. TimerOnlinePending,
  30. TimerOfflinePending
  31. };
  32. typedef struct {
  33. DWORD Flags;
  34. CLUSTER_RESOURCE_STATE State;
  35. HANDLE SignalEvent;
  36. HANDLE TimerThreadWakeup;
  37. HANDLE ThreadHandle;
  38. HKEY ParametersKey;
  39. RESID ResourceId;
  40. DWORD TimerType;
  41. RESOURCE_HANDLE ResourceHandle;
  42. DWORD PendTime;
  43. } DUMMY_RESOURCE, *PDUMMY_RESOURCE;
  44. // 10 dwords ( 0x28 offset )
  45. //
  46. // Constants
  47. //
  48. #define DUMMY_RESOURCE_BLOCK_SIZE 4
  49. #define DUMMY_FLAG_VALID 0x00000001
  50. #define DUMMY_FLAG_ASYNC 0x00000002 // Asynchronous failure mode
  51. #define DUMMY_FLAG_PENDING 0x00000004 // Pending mode on shutdown
  52. #define DUMMY_PARAMETER_FAILED L"Failed"
  53. #define DUMMY_PARAMETER_ASYNC L"Asynchronous"
  54. #define DUMMY_PARAMETER_PENDING L"Pending"
  55. #define DUMMY_PARAMETER_OPENSFAIL L"OpensFail"
  56. #define DUMMY_PARAMETER_PENDTIME L"PendTime"
  57. #define DUMMY_PRINT printf
  58. //
  59. // Macros
  60. //
  61. #define AsyncMode(Resource) (Resource->Flags & DUMMY_FLAG_ASYNC)
  62. #define PendingMode(Resource) (Resource->Flags & DUMMY_FLAG_PENDING)
  63. #define EnterAsyncMode(Resource) (Resource->Flags |= DUMMY_FLAG_ASYNC)
  64. #define DummyAcquireResourceLock() \
  65. { \
  66. DWORD status; \
  67. status = WaitForSingleObject(DummyResourceSemaphore, INFINITE); \
  68. }
  69. #define DummyReleaseResourceLock() \
  70. { \
  71. ReleaseSemaphore(DummyResourceSemaphore, 1, NULL); \
  72. }
  73. //
  74. // Local Variables
  75. //
  76. PDUMMY_RESOURCE DummyResourceList = NULL;
  77. DWORD DummyResourceListSize = DUMMY_RESOURCE_BLOCK_SIZE;
  78. HANDLE DummyResourceSemaphore = NULL;
  79. PLOG_EVENT_ROUTINE LogEvent;
  80. PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus;
  81. extern CLRES_FUNCTION_TABLE DumbFunctionTable;
  82. //
  83. // Local utility functions
  84. //
  85. DWORD
  86. DummyInit(
  87. VOID
  88. )
  89. /*++
  90. Routine Description:
  91. Allocates and initializes global system resources for the Dummy resource.
  92. Arguments:
  93. None.
  94. Return Value:
  95. A Win32 error code.
  96. --*/
  97. {
  98. DWORD status;
  99. DummyResourceSemaphore = CreateSemaphore(NULL, 0, 1 , NULL);
  100. if (DummyResourceSemaphore == NULL) {
  101. status = GetLastError();
  102. DUMMY_PRINT(
  103. "DUMMY: unable to create resource mutex, error %u\n",
  104. status
  105. );
  106. return(status);
  107. }
  108. if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
  109. ReleaseSemaphore( DummyResourceSemaphore, 1, NULL );
  110. }
  111. DummyResourceList = LocalAlloc(
  112. LMEM_FIXED,
  113. DummyResourceListSize * sizeof(DUMMY_RESOURCE)
  114. );
  115. if (DummyResourceList == NULL) {
  116. DUMMY_PRINT("DUMMY: unable to allocate resource list\n");
  117. status = ERROR_NOT_ENOUGH_MEMORY;
  118. CloseHandle(DummyResourceSemaphore);
  119. DummyResourceSemaphore = NULL;
  120. return(status);
  121. }
  122. ZeroMemory(
  123. DummyResourceList,
  124. DummyResourceListSize * sizeof(DUMMY_RESOURCE)
  125. );
  126. return(NO_ERROR);
  127. } // DummyInit
  128. VOID
  129. DummyCleanup(
  130. VOID
  131. )
  132. /*++
  133. Routine Description:
  134. Deallocates any system resources in use by the Dummy resource.
  135. Arguments:
  136. None.
  137. Return Value:
  138. None.
  139. --*/
  140. {
  141. if (DummyResourceList != NULL) {
  142. LocalFree(DummyResourceList);
  143. DummyResourceList = NULL;
  144. }
  145. if (DummyResourceSemaphore != NULL) {
  146. CloseHandle(DummyResourceSemaphore);
  147. DummyResourceSemaphore = NULL;
  148. }
  149. return;
  150. } // DummyCleanup
  151. PDUMMY_RESOURCE
  152. DummyAllocateResource(
  153. OUT RESID *ResourceId
  154. )
  155. /*++
  156. Routine Description:
  157. Allocates a resource structure from the free pool.
  158. Arguments:
  159. ResourceId - Filled in with the RESID for the allocated resource
  160. on return.
  161. Return Value:
  162. A pointer to the allocated resource, or NULL on error.
  163. --*/
  164. {
  165. PDUMMY_RESOURCE resource = NULL;
  166. PDUMMY_RESOURCE newList;
  167. DWORD i;
  168. DWORD newSize = DummyResourceListSize +
  169. DUMMY_RESOURCE_BLOCK_SIZE;
  170. for (i=1; i < DummyResourceListSize; i++) {
  171. if (!(DummyResourceList[i].Flags & DUMMY_FLAG_VALID)) {
  172. resource = DummyResourceList + i;
  173. *ResourceId = (RESID)ULongToPtr( i );
  174. break;
  175. }
  176. }
  177. if (resource == NULL) {
  178. newList = LocalReAlloc(
  179. DummyResourceList,
  180. newSize * sizeof(DUMMY_RESOURCE),
  181. LMEM_MOVEABLE
  182. );
  183. if (newList == NULL) {
  184. return(NULL);
  185. }
  186. DummyResourceList = newList;
  187. resource = DummyResourceList + DummyResourceListSize;
  188. *ResourceId = (RESID) ULongToPtr( DummyResourceListSize );
  189. DummyResourceListSize = newSize;
  190. ZeroMemory(resource, DUMMY_RESOURCE_BLOCK_SIZE * sizeof(DUMMY_RESOURCE));
  191. }
  192. ZeroMemory(resource, sizeof(DUMMY_RESOURCE));
  193. resource->Flags = DUMMY_FLAG_VALID;
  194. return(resource);
  195. } // DummyAllocateResource
  196. VOID
  197. DummyFreeResource(
  198. IN PDUMMY_RESOURCE Resource
  199. )
  200. /*++
  201. Routine Description:
  202. Returns a resource structure to the free pool.
  203. Arguments:
  204. Resource - A pointer to the resource structure to free.
  205. Return Value:
  206. None.
  207. --*/
  208. {
  209. Resource->Flags = 0;
  210. return;
  211. } // DummyFreeResource
  212. PDUMMY_RESOURCE
  213. DummyFindResource(
  214. IN RESID ResourceId
  215. )
  216. /*++
  217. Routine Description:
  218. Locates the Dummy resource structure identified by a RESID.
  219. Arguments:
  220. ResourceId - The RESID of the resource to locate.
  221. Return Value:
  222. A pointer to the resource strucuture, or NULL on error.
  223. --*/
  224. {
  225. DWORD index = PtrToUlong(ResourceId);
  226. PDUMMY_RESOURCE resource = NULL;
  227. if (index < DummyResourceListSize) {
  228. if (DummyResourceList[index].Flags & DUMMY_FLAG_VALID) {
  229. resource = DummyResourceList + index;
  230. }
  231. }
  232. return(resource);
  233. } // DummyFindResource
  234. DWORD
  235. DummyTimerThread(
  236. IN LPVOID Context
  237. )
  238. /*++
  239. Routine Description:
  240. Starts a timer thread to wait and signal failures
  241. Arguments:
  242. Context - A pointer to the DummyResource block for this resource.
  243. Returns:
  244. ERROR_SUCCESS if successful.
  245. Win32 error code on failure.
  246. --*/
  247. {
  248. PDUMMY_RESOURCE resource = (PDUMMY_RESOURCE)Context;
  249. RESOURCE_STATUS resourceStatus;
  250. SYSTEMTIME time;
  251. DWORD delay;
  252. DWORD status;
  253. (LogEvent)(
  254. NULL,
  255. LOG_INFORMATION,
  256. L"TimerThread Entry\n");
  257. //
  258. // If we are not running in async failure mode, or
  259. // pending mode then exit now.
  260. //
  261. if ( !AsyncMode(resource) && !PendingMode(resource) ) {
  262. return(ERROR_SUCCESS);
  263. }
  264. more_pending:
  265. ResUtilInitializeResourceStatus( &resourceStatus );
  266. //
  267. // Otherwise, get system time for random delay.
  268. //
  269. if (resource->PendTime == 0) {
  270. GetSystemTime(&time);
  271. delay = (time.wMilliseconds + time.wSecond) * 6;
  272. } else {
  273. delay = resource->PendTime * 1000;
  274. }
  275. // Use longer delays for errors
  276. if ( resource->TimerType == TimerErrorPending ) {
  277. delay = delay*10;
  278. }
  279. //
  280. // This routine is either handling an Offline Pending or an error timeout.
  281. //
  282. switch ( resource->TimerType ) {
  283. case TimerOnlinePending:
  284. (LogEvent)(
  285. resource->ResourceHandle,
  286. LOG_INFORMATION,
  287. L"Will complete online in approximately %1!u! seconds\n",
  288. (delay+500)/1000);
  289. resourceStatus.ResourceState = ClusterResourceOnline;
  290. resourceStatus.WaitHint = 0;
  291. resourceStatus.CheckPoint = 1;
  292. status = WaitForSingleObject( resource->TimerThreadWakeup, delay );
  293. //
  294. // Either the terminate routine was called, or we timed out.
  295. // If we timed out, then indicate that we've completed.
  296. //
  297. if ( status == WAIT_TIMEOUT ) {
  298. GetSystemTime(&time);
  299. (LogEvent)(
  300. resource->ResourceHandle,
  301. LOG_INFORMATION,
  302. L"Online resource state transition complete at %1!02d!:%2!02d!:%3!02d!.%4!03d!\n",
  303. time.wHour,
  304. time.wMinute,
  305. time.wSecond,
  306. time.wMilliseconds);
  307. resource->State = ClusterResourceOnline;
  308. (SetResourceStatus)(resource->ResourceHandle,
  309. &resourceStatus);
  310. if ( AsyncMode( resource ) ) {
  311. resource->TimerType = TimerErrorPending;
  312. goto more_pending;
  313. }
  314. } else {
  315. (LogEvent)(
  316. resource->ResourceHandle,
  317. LOG_INFORMATION,
  318. L"Online pending terminated\n");
  319. if ( resource->State == ClusterResourceOffline ) {
  320. resource->TimerType = TimerOfflinePending;
  321. goto more_pending;
  322. }
  323. }
  324. break;
  325. case TimerOfflinePending:
  326. (LogEvent)(
  327. resource->ResourceHandle,
  328. LOG_INFORMATION,
  329. L"Will complete offline in approximately %1!u! seconds\n",
  330. (delay+500)/1000);
  331. resourceStatus.ResourceState = ClusterResourceOffline;
  332. resourceStatus.WaitHint = 0;
  333. resourceStatus.CheckPoint = 1;
  334. status = WaitForSingleObject( resource->TimerThreadWakeup, delay );
  335. //
  336. // Either the terminate routine was called, or we timed out.
  337. // If we timed out, then indicate that we've completed.
  338. //
  339. if ( status == WAIT_TIMEOUT ) {
  340. GetSystemTime(&time);
  341. (LogEvent)(
  342. resource->ResourceHandle,
  343. LOG_INFORMATION,
  344. L"Offline resource state transition complete at %1!02d!:%2!02d!:%3!02d!.%4!03d!\n",
  345. time.wHour,
  346. time.wMinute,
  347. time.wSecond,
  348. time.wMilliseconds);
  349. resource->State = ClusterResourceOffline;
  350. (SetResourceStatus)(resource->ResourceHandle,
  351. &resourceStatus);
  352. } else {
  353. (LogEvent)(
  354. resource->ResourceHandle,
  355. LOG_INFORMATION,
  356. L"Offline pending terminated\n");
  357. }
  358. break;
  359. case TimerErrorPending:
  360. (LogEvent)(
  361. resource->ResourceHandle,
  362. LOG_INFORMATION,
  363. L"Will fail in approximately %1!u! seconds\n",
  364. (delay+500)/1000);
  365. if ( !ResetEvent( resource->SignalEvent ) ) {
  366. (LogEvent)(
  367. resource->ResourceHandle,
  368. LOG_ERROR,
  369. L"Failed to reset the signal event\n");
  370. resource->ThreadHandle = NULL;
  371. return(ERROR_GEN_FAILURE);
  372. }
  373. status = WaitForSingleObject( resource->TimerThreadWakeup, delay );
  374. //
  375. // Either the terminate routine was called, or we timed out.
  376. // If we timed out, then signal the waiting event.
  377. //
  378. if ( status == WAIT_TIMEOUT ) {
  379. (LogEvent)(
  380. resource->ResourceHandle,
  381. LOG_INFORMATION,
  382. L"Failed randomly\n");
  383. resource->TimerType = TimerNotUsed;
  384. SetEvent( resource->SignalEvent );
  385. } else {
  386. if ( resource->State == ClusterResourceOfflinePending ) {
  387. resource->TimerType = TimerOfflinePending;
  388. goto more_pending;
  389. }
  390. }
  391. break;
  392. default:
  393. (LogEvent)(
  394. resource->ResourceHandle,
  395. LOG_ERROR,
  396. L"DummyTimer internal error, timer %1!u!\n",
  397. resource->TimerType);
  398. break;
  399. }
  400. (LogEvent)(
  401. resource->ResourceHandle,
  402. LOG_INFORMATION,
  403. L"TimerThread Exit\n");
  404. resource->TimerType = TimerNotUsed;
  405. resource->ThreadHandle = NULL;
  406. return(ERROR_SUCCESS);
  407. } // DummyTimerThread
  408. //
  409. // Public Functions
  410. //
  411. BOOL
  412. WINAPI
  413. DummyDllEntryPoint(
  414. IN HINSTANCE DllHandle,
  415. IN DWORD Reason,
  416. IN LPVOID Reserved
  417. )
  418. /*++
  419. Routine Description:
  420. Initialization & cleanup routine for Dummy resource DLL.
  421. Arguments:
  422. DllHandle - Handle to the DLL.
  423. Reason - The reason this routine is being invoked.
  424. Return Value:
  425. On PROCESS_ATTACH: TRUE if the DLL initialized successfully
  426. FALSE if it did not.
  427. The return value from all other calls is ignored.
  428. --*/
  429. {
  430. DWORD status;
  431. switch(Reason) {
  432. case DLL_PROCESS_ATTACH:
  433. status = DummyInit();
  434. if (status != NO_ERROR) {
  435. SetLastError(status);
  436. return(FALSE);
  437. }
  438. break;
  439. case DLL_PROCESS_DETACH:
  440. DummyCleanup();
  441. break;
  442. default:
  443. break;
  444. }
  445. return(TRUE);
  446. } // DummyDllEntryPoint
  447. //
  448. // Define the resource Name
  449. //
  450. #define IIS_RESOURCE_NAME L"IIS Virtual Root"
  451. DWORD
  452. WINAPI
  453. Startup(
  454. IN LPCWSTR ResourceType,
  455. IN DWORD MinVersionSupported,
  456. IN DWORD MaxVersionSupported,
  457. IN PSET_RESOURCE_STATUS_ROUTINE pSetResourceStatus,
  458. IN PLOG_EVENT_ROUTINE pLogEvent,
  459. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  460. )
  461. /*++
  462. Routine Description:
  463. Startup a particular resource type. This means verifying the version
  464. requested, and returning the function table for this resource type.
  465. Arguments:
  466. ResourceType - Supplies the type of resource.
  467. MinVersionSupported - The minimum version number supported by the cluster
  468. service on this system.
  469. MaxVersionSupported - The maximum version number supported by the cluster
  470. service on this system.
  471. FunctionTable - Returns the Function Table for this resource type.
  472. Return Value:
  473. ERROR_SUCCESS if successful.
  474. A Win32 error code on failure.
  475. --*/
  476. {
  477. if ( lstrcmpiW( ResourceType, IIS_RESOURCE_NAME ) != 0 )
  478. {
  479. return (ERROR_UNKNOWN_REVISION);
  480. }
  481. LogEvent = pLogEvent;
  482. SetResourceStatus = pSetResourceStatus;
  483. if ( (MinVersionSupported <= CLRES_VERSION_V1_00) &&
  484. (MaxVersionSupported >= CLRES_VERSION_V1_00) )
  485. {
  486. *FunctionTable = &DumbFunctionTable;
  487. return (ERROR_SUCCESS);
  488. }
  489. return (ERROR_REVISION_MISMATCH);
  490. } // Startup
  491. RESID
  492. WINAPI
  493. DumbOpen(
  494. IN LPCWSTR ResourceName,
  495. IN HKEY ResourceKey,
  496. IN RESOURCE_HANDLE ResourceHandle
  497. )
  498. /*++
  499. Routine Description:
  500. Open (initialize) routine for Dummy resource
  501. Arguments:
  502. ResourceName - supplies the resource name
  503. ResourceKey - supplies a handle to the resource's cluster registry key
  504. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  505. is called.
  506. SetResourceStatus - a routine to call to update status for the resource.
  507. LogEvent - a routine to call to log an event for this resource.
  508. Return Value:
  509. RESID of created resource
  510. NULL on failure
  511. --*/
  512. {
  513. DWORD status;
  514. HKEY parametersKey = NULL;
  515. PDUMMY_RESOURCE resource = NULL;
  516. RESID resourceId = 0;
  517. DWORD asyncMode = FALSE;
  518. DWORD valueSize;
  519. DWORD valueType;
  520. DWORD pendingMode = FALSE;
  521. DWORD opensFail = FALSE;
  522. DWORD pendingTime = 0;
  523. status = ClusterRegOpenKey(ResourceKey,
  524. L"Parameters",
  525. KEY_READ,
  526. &parametersKey);
  527. if (status != NO_ERROR) {
  528. (LogEvent)(
  529. ResourceHandle,
  530. LOG_ERROR,
  531. L"Unable to open parameters key, status %1!u!\n",
  532. status);
  533. return(0);
  534. }
  535. //
  536. // Find out if we should just fail the open request.
  537. //
  538. valueSize = sizeof(opensFail);
  539. status = ClusterRegQueryValue(parametersKey,
  540. DUMMY_PARAMETER_OPENSFAIL,
  541. &valueType,
  542. (PBYTE)&opensFail,
  543. &valueSize);
  544. if ( status != NO_ERROR ) {
  545. opensFail = FALSE;
  546. }
  547. if ( opensFail ) {
  548. ClusterRegCloseKey(parametersKey);
  549. return(NULL);
  550. }
  551. //
  552. // Find out whether we should run in async failure mode.
  553. //
  554. valueSize = sizeof(asyncMode);
  555. status = ClusterRegQueryValue(parametersKey,
  556. DUMMY_PARAMETER_ASYNC,
  557. &valueType,
  558. (PBYTE)&asyncMode,
  559. &valueSize);
  560. if (status != NO_ERROR) {
  561. asyncMode = FALSE;
  562. }
  563. //
  564. // Find out whether we should return Pending on shutdown.
  565. //
  566. valueSize = sizeof(pendingMode);
  567. status = ClusterRegQueryValue(parametersKey,
  568. DUMMY_PARAMETER_PENDING,
  569. &valueType,
  570. (PBYTE)&pendingMode,
  571. &valueSize);
  572. if (status != NO_ERROR) {
  573. pendingMode = FALSE;
  574. } else {
  575. //
  576. // See if there is a defined time period
  577. //
  578. valueSize = sizeof(pendingTime);
  579. status = ClusterRegQueryValue(parametersKey,
  580. DUMMY_PARAMETER_PENDTIME,
  581. &valueType,
  582. (PBYTE)&pendingTime,
  583. &valueSize);
  584. }
  585. //
  586. // Now go allocate a resource structure.
  587. //
  588. DummyAcquireResourceLock();
  589. resource = DummyAllocateResource(&resourceId);
  590. if (resource == NULL) {
  591. (LogEvent)(
  592. ResourceHandle,
  593. LOG_ERROR,
  594. L"Unable to allocate resource structure\n");
  595. DummyReleaseResourceLock();
  596. ClusterRegCloseKey(parametersKey);
  597. return(0);
  598. }
  599. resource->State = ClusterResourceOffline;
  600. resource->ParametersKey = parametersKey;
  601. resource->ResourceId = resourceId;
  602. //
  603. // Copy stuff for returning pending status.
  604. //
  605. resource->ResourceHandle = ResourceHandle;
  606. DummyReleaseResourceLock();
  607. //
  608. // Create a TimerThreadWakeup event if needed.
  609. //
  610. if ( pendingMode || asyncMode ) {
  611. resource->TimerThreadWakeup = CreateEvent(NULL, FALSE, FALSE, NULL);
  612. if ( resource->TimerThreadWakeup == NULL ) {
  613. DummyFreeResource( resource );
  614. (LogEvent)(
  615. ResourceHandle,
  616. LOG_ERROR,
  617. L"Failed to create timer thread wakeup event\n");
  618. ClusterRegCloseKey(parametersKey);
  619. return(0);
  620. }
  621. }
  622. if ( pendingMode ) {
  623. resource->Flags |= DUMMY_FLAG_PENDING;
  624. resource->PendTime = pendingTime;
  625. }
  626. if ( asyncMode ) {
  627. EnterAsyncMode( resource );
  628. resource->SignalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  629. if ( resource->SignalEvent == NULL ) {
  630. DummyFreeResource( resource );
  631. (LogEvent)(
  632. ResourceHandle,
  633. LOG_ERROR,
  634. L"Failed to create a timer event\n");
  635. ClusterRegCloseKey(parametersKey);
  636. return(0);
  637. }
  638. }
  639. return(resourceId);
  640. } // DumbOpen
  641. DWORD
  642. WINAPI
  643. DumbOnline(
  644. IN RESID ResourceId,
  645. IN OUT PHANDLE EventHandle
  646. )
  647. /*++
  648. Routine Description:
  649. Online routine for Dummy resource.
  650. Arguments:
  651. ResourceId - supplies resource id to be brought online
  652. EventHandle - supplies a pointer to a handle to signal on error.
  653. Return Value:
  654. ERROR_SUCCESS if successful.
  655. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  656. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  657. acquire 'ownership'.
  658. Win32 error code if other failure.
  659. --*/
  660. {
  661. PDUMMY_RESOURCE resource;
  662. DWORD status = ERROR_SUCCESS;
  663. DWORD threadId;
  664. SYSTEMTIME time;
  665. (LogEvent)(
  666. NULL,
  667. LOG_INFORMATION,
  668. L"Online Entry\n");
  669. DummyAcquireResourceLock();
  670. resource = DummyFindResource(ResourceId);
  671. if (resource == NULL) {
  672. status = ERROR_RESOURCE_NOT_FOUND;
  673. DUMMY_PRINT("DUMMY Online: resource %u not found.\n", PtrToUlong(ResourceId));
  674. } else {
  675. if ( resource->TimerType != TimerNotUsed ) {
  676. (LogEvent)(
  677. resource->ResourceHandle,
  678. LOG_ERROR,
  679. L"Timer still running!\n");
  680. DummyReleaseResourceLock();
  681. return(ERROR_GEN_FAILURE);
  682. }
  683. if ( PendingMode( resource ) ) {
  684. if ( !resource->ThreadHandle ) {
  685. resource->TimerType = TimerOnlinePending;
  686. resource->ThreadHandle = CreateThread(
  687. NULL,
  688. 0,
  689. DummyTimerThread,
  690. resource,
  691. 0,
  692. &threadId
  693. );
  694. if ( resource->ThreadHandle == NULL ) {
  695. (LogEvent)(
  696. resource->ResourceHandle,
  697. LOG_ERROR,
  698. L"Failed to start timer thread.\n");
  699. resource->TimerType = TimerNotUsed;
  700. status = ERROR_GEN_FAILURE;
  701. } else {
  702. CloseHandle( resource->ThreadHandle );
  703. }
  704. status = ERROR_IO_PENDING;
  705. }
  706. if ( AsyncMode(resource) && (status != ERROR_GEN_FAILURE) ) {
  707. *EventHandle = resource->SignalEvent;
  708. }
  709. } else if ( AsyncMode( resource ) ) {
  710. if ( !ResetEvent( resource->TimerThreadWakeup ) ) {
  711. (LogEvent)(
  712. resource->ResourceHandle,
  713. LOG_ERROR,
  714. L"Failed to reset timer wakeup event\n");
  715. status = ERROR_GEN_FAILURE;
  716. } else if ( !resource->ThreadHandle ) {
  717. resource->ThreadHandle = CreateThread(
  718. NULL,
  719. 0,
  720. DummyTimerThread,
  721. resource,
  722. 0,
  723. &threadId
  724. );
  725. if ( resource->ThreadHandle == NULL ) {
  726. (LogEvent)(
  727. resource->ResourceHandle,
  728. LOG_ERROR,
  729. L"Failed to start timer thread.\n");
  730. status = ERROR_GEN_FAILURE;
  731. } else {
  732. CloseHandle(resource->ThreadHandle);
  733. }
  734. resource->TimerType = TimerErrorPending;
  735. }
  736. //
  737. // If we are successful, then return our signal event.
  738. //
  739. if ( status == ERROR_SUCCESS ) {
  740. *EventHandle = resource->SignalEvent;
  741. }
  742. }
  743. }
  744. if ( status == ERROR_SUCCESS ) {
  745. resource->State = ClusterResourceOnline;
  746. GetSystemTime(&time);
  747. (LogEvent)(
  748. resource->ResourceHandle,
  749. LOG_INFORMATION,
  750. L"Online at %1!02d!:%2!02d!:%3!02d!.%4!03d!\n",
  751. time.wHour,
  752. time.wMinute,
  753. time.wSecond,
  754. time.wMilliseconds);
  755. } else if ( status == ERROR_IO_PENDING ) {
  756. resource->State = ClusterResourceOnlinePending;
  757. }
  758. (LogEvent)(
  759. resource->ResourceHandle,
  760. LOG_INFORMATION,
  761. L"Online Exit\n");
  762. DummyReleaseResourceLock();
  763. return(status);
  764. } // DumbOnline
  765. VOID
  766. WINAPI
  767. DumbTerminate(
  768. IN RESID ResourceId
  769. )
  770. /*++
  771. Routine Description:
  772. Terminate routine for Dummy resource.
  773. Arguments:
  774. ResourceId - supplies resource id to be terminated
  775. Return Value:
  776. None.
  777. --*/
  778. {
  779. PDUMMY_RESOURCE resource;
  780. (LogEvent)(
  781. NULL,
  782. LOG_INFORMATION,
  783. L"Terminate Entry\n");
  784. DummyAcquireResourceLock();
  785. resource = DummyFindResource(ResourceId);
  786. if (resource == NULL) {
  787. DUMMY_PRINT("DUMMY Terminate: resource %u not found\n", PtrToUlong(ResourceId));
  788. }
  789. else {
  790. resource->State = ClusterResourceFailed;
  791. if ( resource->TimerType != TimerNotUsed ) {
  792. SetEvent( resource->TimerThreadWakeup );
  793. }
  794. (LogEvent)(
  795. resource->ResourceHandle,
  796. LOG_INFORMATION,
  797. L"Terminated\n");
  798. }
  799. (LogEvent)(
  800. resource->ResourceHandle,
  801. LOG_INFORMATION,
  802. L"Terminate Exit\n");
  803. resource->ThreadHandle = NULL;
  804. DummyReleaseResourceLock();
  805. return;
  806. } // DumbTerminate
  807. DWORD
  808. WINAPI
  809. DumbOffline(
  810. IN RESID ResourceId
  811. )
  812. /*++
  813. Routine Description:
  814. Offline routine for Dummy resource.
  815. Arguments:
  816. ResourceId - supplies the resource it to be taken offline
  817. Return Value:
  818. ERROR_SUCCESS - always successful.
  819. --*/
  820. {
  821. DWORD status = ERROR_SUCCESS;
  822. DWORD threadId;
  823. PDUMMY_RESOURCE resource;
  824. (LogEvent)(
  825. NULL,
  826. LOG_INFORMATION,
  827. L"Offline Entry\n");
  828. DumbTerminate(ResourceId);
  829. //
  830. // Now check if we are to return pending...
  831. //
  832. DummyAcquireResourceLock();
  833. resource = DummyFindResource(ResourceId);
  834. if (resource == NULL) {
  835. DUMMY_PRINT("DUMMY Offline: resource %u not found\n", PtrToUlong(ResourceId));
  836. } else {
  837. resource->State = ClusterResourceOfflinePending;
  838. if ( resource->TimerType != TimerNotUsed ) {
  839. DummyReleaseResourceLock();
  840. return(ERROR_IO_PENDING);
  841. }
  842. resource->State = ClusterResourceOffline;
  843. if ( PendingMode(resource) ) {
  844. //CL_ASSERT( resource->ThreadHandle == NULL );
  845. if ( !ResetEvent( resource->TimerThreadWakeup ) ) {
  846. (LogEvent)(
  847. resource->ResourceHandle,
  848. LOG_ERROR,
  849. L"Failed to reset pending wakeup event\n");
  850. status = ERROR_GEN_FAILURE;
  851. } else if ( !resource->ThreadHandle ) {
  852. resource->ThreadHandle = CreateThread(
  853. NULL,
  854. 0,
  855. DummyTimerThread,
  856. resource,
  857. 0,
  858. &threadId
  859. );
  860. if ( resource->ThreadHandle == NULL ) {
  861. (LogEvent)(
  862. resource->ResourceHandle,
  863. LOG_ERROR,
  864. L"Failed to start pending timer thread.\n");
  865. status = GetLastError();
  866. } else {
  867. CloseHandle( resource->ThreadHandle );
  868. resource->TimerType = TimerOfflinePending;
  869. status = ERROR_IO_PENDING;
  870. resource->State = ClusterResourceOfflinePending;
  871. }
  872. }
  873. }
  874. }
  875. (LogEvent)(
  876. resource->ResourceHandle,
  877. LOG_INFORMATION,
  878. L"Offline Exit\n");
  879. DummyReleaseResourceLock();
  880. return(status);
  881. } // DumbOffline
  882. BOOL
  883. WINAPI
  884. DumbIsAlive(
  885. IN RESID ResourceId
  886. )
  887. /*++
  888. Routine Description:
  889. IsAlive routine for Dummy resource.
  890. Arguments:
  891. ResourceId - supplies the resource id to be polled.
  892. Return Value:
  893. TRUE - Resource is alive and well
  894. FALSE - Resource is toast.
  895. --*/
  896. {
  897. SYSTEMTIME Time;
  898. PDUMMY_RESOURCE resource;
  899. BOOLEAN returnValue = FALSE;
  900. DWORD failed = FALSE;
  901. DWORD status;
  902. DWORD ValueType;
  903. DWORD ValueSize;
  904. DummyAcquireResourceLock();
  905. resource = DummyFindResource(ResourceId);
  906. if (resource == NULL) {
  907. DUMMY_PRINT("DUMMY IsAlive: resource %u not found.\n", PtrToUlong(ResourceId));
  908. DummyReleaseResourceLock();
  909. return(FALSE);
  910. }
  911. GetSystemTime(&Time);
  912. ValueSize = sizeof(failed);
  913. status = ClusterRegQueryValue(resource->ParametersKey,
  914. DUMMY_PARAMETER_FAILED,
  915. &ValueType,
  916. (PBYTE)&failed,
  917. &ValueSize);
  918. if (status != NO_ERROR) {
  919. if (resource->State == ClusterResourceFailed) {
  920. failed = TRUE;
  921. }
  922. }
  923. if (resource->State == ClusterResourceFailed) {
  924. if (!failed) {
  925. (LogEvent)(
  926. resource->ResourceHandle,
  927. LOG_INFORMATION,
  928. L"Recovered at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
  929. Time.wHour,
  930. Time.wMinute,
  931. Time.wSecond,
  932. Time.wMilliseconds);
  933. resource->State = ClusterResourceOnline;
  934. }
  935. else {
  936. (LogEvent)(
  937. resource->ResourceHandle,
  938. LOG_INFORMATION,
  939. L"Is Dead at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
  940. Time.wHour,
  941. Time.wMinute,
  942. Time.wSecond,
  943. Time.wMilliseconds);
  944. }
  945. }
  946. else if (resource->State == ClusterResourceOnline) {
  947. if (failed) {
  948. (LogEvent)(
  949. resource->ResourceHandle,
  950. LOG_INFORMATION,
  951. L"Failed at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
  952. Time.wHour,
  953. Time.wMinute,
  954. Time.wSecond,
  955. Time.wMilliseconds);
  956. resource->State = ClusterResourceFailed;
  957. }
  958. else {
  959. (LogEvent)(
  960. resource->ResourceHandle,
  961. LOG_INFORMATION,
  962. L"Is Alive at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
  963. Time.wHour,
  964. Time.wMinute,
  965. Time.wSecond,
  966. Time.wMilliseconds);
  967. }
  968. }
  969. else {
  970. (LogEvent)(
  971. resource->ResourceHandle,
  972. LOG_INFORMATION,
  973. L"Resource state %1!u! during IsAlive poll at %2!2d!:%3!02d!:%4!02d!.%5!03d! !!!!\n",
  974. resource->State,
  975. Time.wHour,
  976. Time.wMinute,
  977. Time.wSecond,
  978. Time.wMilliseconds);
  979. }
  980. returnValue = (resource->State == ClusterResourceOnline) ? TRUE : FALSE;
  981. DummyReleaseResourceLock();
  982. return(returnValue);
  983. } // DumbIsAlive
  984. BOOL
  985. WINAPI
  986. DumbLooksAlive(
  987. IN RESID ResourceId
  988. )
  989. /*++
  990. Routine Description:
  991. LooksAlive routine for Dummy resource.
  992. Arguments:
  993. ResourceId - supplies the resource id to be polled.
  994. Return Value:
  995. TRUE - Resource looks like it is alive and well
  996. FALSE - Resource looks like it is toast.
  997. --*/
  998. {
  999. SYSTEMTIME Time;
  1000. PDUMMY_RESOURCE resource;
  1001. BOOLEAN returnValue = FALSE;
  1002. DWORD failed = FALSE;
  1003. DWORD status;
  1004. DWORD ValueType;
  1005. DWORD ValueSize;
  1006. DummyAcquireResourceLock();
  1007. resource = DummyFindResource(ResourceId);
  1008. if (resource == NULL) {
  1009. DUMMY_PRINT("DUMMY LooksAlive: resource %u not found.\n", PtrToUlong(ResourceId));
  1010. DummyReleaseResourceLock();
  1011. return(FALSE);
  1012. }
  1013. GetSystemTime(&Time);
  1014. ValueSize = sizeof(failed);
  1015. status = ClusterRegQueryValue(resource->ParametersKey,
  1016. DUMMY_PARAMETER_FAILED,
  1017. &ValueType,
  1018. (PBYTE)&failed,
  1019. &ValueSize);
  1020. if (status != NO_ERROR) {
  1021. if (resource->State == ClusterResourceFailed) {
  1022. failed = TRUE;
  1023. }
  1024. }
  1025. if (resource->State == ClusterResourceFailed) {
  1026. if (!failed) {
  1027. (LogEvent)(
  1028. resource->ResourceHandle,
  1029. LOG_INFORMATION,
  1030. L"Recovered at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
  1031. Time.wHour,
  1032. Time.wMinute,
  1033. Time.wSecond,
  1034. Time.wMilliseconds);
  1035. resource->State = ClusterResourceOnline;
  1036. }
  1037. else {
  1038. (LogEvent)(
  1039. resource->ResourceHandle,
  1040. LOG_INFORMATION,
  1041. L"Looks Dead at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
  1042. Time.wHour,
  1043. Time.wMinute,
  1044. Time.wSecond,
  1045. Time.wMilliseconds);
  1046. }
  1047. }
  1048. else if (resource->State == ClusterResourceOnline) {
  1049. if (failed) {
  1050. (LogEvent)(
  1051. resource->ResourceHandle,
  1052. LOG_INFORMATION,
  1053. L"Failed at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
  1054. resource->ResourceHandle,
  1055. LOG_INFORMATION,
  1056. Time.wHour,
  1057. Time.wMinute,
  1058. Time.wSecond,
  1059. Time.wMilliseconds);
  1060. resource->State = ClusterResourceFailed;
  1061. }
  1062. else {
  1063. (LogEvent)(
  1064. resource->ResourceHandle,
  1065. LOG_INFORMATION,
  1066. L"Looks Alive at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
  1067. Time.wHour,
  1068. Time.wMinute,
  1069. Time.wSecond,
  1070. Time.wMilliseconds);
  1071. }
  1072. }
  1073. else {
  1074. (LogEvent)(
  1075. resource->ResourceHandle,
  1076. LOG_INFORMATION,
  1077. L"Resource state %1!u! during LooksAlive poll at %2!2d!:%3!02d!:%4!02d!.%5!03d! !!!!\n",
  1078. resource->State,
  1079. Time.wHour,
  1080. Time.wMinute,
  1081. Time.wSecond,
  1082. Time.wMilliseconds);
  1083. }
  1084. returnValue = (resource->State == ClusterResourceOnline) ? TRUE : FALSE;
  1085. DummyReleaseResourceLock();
  1086. return(returnValue);
  1087. } // DumbLooksAlive
  1088. VOID
  1089. WINAPI
  1090. DumbClose(
  1091. IN RESID ResourceId
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. Close routine for Dummy resource.
  1096. Arguments:
  1097. ResourceId - supplies resource id to be closed.
  1098. Return Value:
  1099. None.
  1100. --*/
  1101. {
  1102. PDUMMY_RESOURCE resource;
  1103. PLIST_ENTRY entry;
  1104. DummyAcquireResourceLock();
  1105. resource = DummyFindResource(ResourceId);
  1106. if (resource == NULL) {
  1107. DUMMY_PRINT("DUMMY: Close, resource %u not found\n", PtrToUlong(ResourceId));
  1108. }
  1109. else {
  1110. if ( resource->TimerThreadWakeup != NULL ) {
  1111. CloseHandle( resource->TimerThreadWakeup );
  1112. }
  1113. if ( resource->SignalEvent != NULL ) {
  1114. CloseHandle( resource->SignalEvent );
  1115. }
  1116. ClusterRegCloseKey(resource->ParametersKey);
  1117. DummyFreeResource(resource);
  1118. }
  1119. DummyReleaseResourceLock();
  1120. (LogEvent)(
  1121. resource->ResourceHandle,
  1122. LOG_INFORMATION,
  1123. L"Closed.\n");
  1124. return;
  1125. } // DumbClose
  1126. //
  1127. // Define Function Table
  1128. //
  1129. CLRES_V1_FUNCTION_TABLE( DumbFunctionTable,
  1130. CLRES_VERSION_V1_00,
  1131. Dumb,
  1132. NULL,
  1133. NULL,
  1134. NULL,
  1135. NULL );