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.

1865 lines
49 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corp.
  3. Module Name:
  4. clusres.c
  5. Abstract:
  6. Resource DLL for Remote Storage Server
  7. Author:
  8. Ravisankar Pudipeddi (ravisp) 1 Sept 1999
  9. Revision History:
  10. --*/
  11. #pragma comment(lib, "clusapi.lib")
  12. #pragma comment(lib, "resutils.lib")
  13. #define UNICODE 1
  14. #include <windows.h>
  15. #include <resapi.h>
  16. #include <stdio.h>
  17. #include "userenv.h"
  18. #include "winsvc.h"
  19. #include "aclapi.h"
  20. #define LOG_CURRENT_MODULE LOG_MODULE_RSCLUSTER
  21. #define SERVICES_ROOT L"SYSTEM\\CurrentControlSet\\Services\\"
  22. #define DBG_PRINT printf
  23. #pragma warning( disable : 4115 ) // named type definition in parentheses
  24. #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
  25. #pragma warning( disable : 4214 ) // nonstandard extension used : bit field types other than int
  26. #pragma warning( default : 4214 ) // nonstandard extension used : bit field types other than int
  27. #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
  28. #pragma warning( default : 4115 ) // named type definition in parentheses
  29. //
  30. // Type and constant definitions.
  31. //
  32. #define RSCLUSTER_RESNAME L"Remote Storage Server"
  33. #define RSCLUSTER_SVCNAME TEXT("Remote_Storage_Server")
  34. // Handle to service controller, set by the first create resource call.
  35. SC_HANDLE g_ScHandle = NULL;
  36. typedef struct _RSCLUSTER_RESOURCE {
  37. RESID ResId; // for validation
  38. HRESOURCE hResource;
  39. SC_HANDLE ServiceHandle;
  40. RESOURCE_HANDLE ResourceHandle;
  41. HKEY ResourceKey;
  42. HKEY ParametersKey;
  43. LPWSTR ResourceName;
  44. CLUS_WORKER PendingThread;
  45. BOOL Online;
  46. CLUS_WORKER OnlineThread;
  47. CLUSTER_RESOURCE_STATE State;
  48. DWORD dwServicePid;
  49. HANDLE hSem;
  50. } RSCLUSTER_RESOURCE, *PRSCLUSTER_RESOURCE;
  51. //
  52. // Global data.
  53. //
  54. // Event Logging routine.
  55. PLOG_EVENT_ROUTINE g_LogEvent = NULL;
  56. // Resource Status routine for pending Online and Offline calls.
  57. PSET_RESOURCE_STATUS_ROUTINE g_SetResourceStatus = NULL;
  58. // Forward reference to our RESAPI function table.
  59. extern CLRES_FUNCTION_TABLE g_RSClusterFunctionTable;
  60. //
  61. // RSCluster resource read-write private properties.
  62. //
  63. RESUTIL_PROPERTY_ITEM
  64. RSClusterResourcePrivateProperties[] = {
  65. { 0 }
  66. };
  67. //
  68. // Function prototypes.
  69. //
  70. DWORD
  71. WINAPI
  72. Startup(
  73. IN LPCWSTR ResourceType,
  74. IN DWORD MinVersionSupported,
  75. IN DWORD MaxVersionSupported,
  76. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  77. IN PLOG_EVENT_ROUTINE LogEvent,
  78. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  79. );
  80. RESID
  81. WINAPI
  82. RSClusterOpen(
  83. IN LPCWSTR ResourceName,
  84. IN HKEY ResourceKey,
  85. IN RESOURCE_HANDLE ResourceHandle
  86. );
  87. VOID
  88. WINAPI
  89. RSClusterClose(
  90. IN RESID ResourceId
  91. );
  92. DWORD
  93. WINAPI
  94. RSClusterOnline(
  95. IN RESID ResourceId,
  96. IN OUT PHANDLE EventHandle
  97. );
  98. DWORD
  99. WINAPI
  100. RSClusterOnlineThread(
  101. PCLUS_WORKER WorkerPtr,
  102. IN PRSCLUSTER_RESOURCE ResourceEntry
  103. );
  104. DWORD
  105. WINAPI
  106. RSClusterOffline(
  107. IN RESID ResourceId
  108. );
  109. DWORD
  110. RSClusterOfflineThread(
  111. PCLUS_WORKER pWorker,
  112. IN PRSCLUSTER_RESOURCE ResourceEntry
  113. );
  114. VOID
  115. WINAPI
  116. RSClusterTerminate(
  117. IN RESID ResourceId
  118. );
  119. DWORD
  120. RSClusterDoTerminate(
  121. IN PRSCLUSTER_RESOURCE ResourceEntry
  122. );
  123. BOOL
  124. WINAPI
  125. RSClusterLooksAlive(
  126. IN RESID ResourceId
  127. );
  128. BOOL
  129. WINAPI
  130. RSClusterIsAlive(
  131. IN RESID ResourceId
  132. );
  133. BOOL
  134. RSClusterCheckIsAlive(
  135. IN PRSCLUSTER_RESOURCE ResourceEntry
  136. );
  137. DWORD
  138. WINAPI
  139. RSClusterResourceControl(
  140. IN RESID ResourceId,
  141. IN DWORD ControlCode,
  142. IN PVOID InBuffer,
  143. IN DWORD InBufferSize,
  144. OUT PVOID OutBuffer,
  145. IN DWORD OutBufferSize,
  146. OUT LPDWORD BytesReturned
  147. );
  148. BOOLEAN
  149. WINAPI
  150. DllMain(
  151. IN HINSTANCE DllHandle,
  152. IN DWORD Reason,
  153. IN LPVOID Reserved
  154. )
  155. /*++
  156. Routine Description:
  157. Main DLL entry point.
  158. Arguments:
  159. DllHandle - DLL instance handle.
  160. Reason - Reason for being called.
  161. Reserved - Reserved argument.
  162. Return Value:
  163. TRUE - Success.
  164. FALSE - Failure.
  165. --*/
  166. {
  167. switch( Reason ) {
  168. case DLL_PROCESS_ATTACH:
  169. DisableThreadLibraryCalls( DllHandle );
  170. break;
  171. case DLL_PROCESS_DETACH:
  172. break;
  173. }
  174. return(TRUE);
  175. } // DllMain
  176. DWORD
  177. WINAPI
  178. Startup(
  179. IN LPCWSTR ResourceType,
  180. IN DWORD MinVersionSupported,
  181. IN DWORD MaxVersionSupported,
  182. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  183. IN PLOG_EVENT_ROUTINE LogEvent,
  184. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  185. )
  186. /*++
  187. Routine Description:
  188. Startup the resource DLL. This routine verifies that at least one
  189. currently supported version of the resource DLL is between
  190. MinVersionSupported and MaxVersionSupported. If not, then the resource
  191. DLL should return ERROR_REVISION_MISMATCH.
  192. If more than one version of the resource DLL interface is supported by
  193. the resource DLL, then the highest version (up to MaxVersionSupported)
  194. should be returned as the resource DLL's interface. If the returned
  195. version is not within range, then startup fails.
  196. The ResourceType is passed in so that if the resource DLL supports more
  197. than one ResourceType, it can pass back the correct function table
  198. associated with the ResourceType.
  199. Arguments:
  200. ResourceType - The type of resource requesting a function table.
  201. MinVersionSupported - The minimum resource DLL interface version
  202. supported by the cluster software.
  203. MaxVersionSupported - The maximum resource DLL interface version
  204. supported by the cluster software.
  205. SetResourceStatus - Pointer to a routine that the resource DLL should
  206. call to update the state of a resource after the Online or Offline
  207. routine returns a status of ERROR_IO_PENDING.
  208. LogEvent - Pointer to a routine that handles the reporting of events
  209. from the resource DLL.
  210. FunctionTable - Returns a pointer to the function table defined for the
  211. version of the resource DLL interface returned by the resource DLL.
  212. Return Value:
  213. ERROR_SUCCESS - The operation was successful.
  214. ERROR_MOD_NOT_FOUND - The resource type is unknown by this DLL.
  215. ERROR_REVISION_MISMATCH - The version of the cluster service doesn't
  216. match the versrion of the DLL.
  217. Win32 error code - The operation failed.
  218. --*/
  219. {
  220. if ( (MinVersionSupported > CLRES_VERSION_V1_00) ||
  221. (MaxVersionSupported < CLRES_VERSION_V1_00) ) {
  222. return(ERROR_REVISION_MISMATCH);
  223. }
  224. if ( lstrcmpiW( ResourceType, RSCLUSTER_RESNAME ) != 0 ) {
  225. return(ERROR_MOD_NOT_FOUND);
  226. }
  227. if ( !g_LogEvent ) {
  228. g_LogEvent = LogEvent;
  229. g_SetResourceStatus = SetResourceStatus;
  230. }
  231. *FunctionTable = &g_RSClusterFunctionTable;
  232. return(ERROR_SUCCESS);
  233. } // Startup
  234. RESID
  235. WINAPI
  236. RSClusterOpen(
  237. IN LPCWSTR ResourceName,
  238. IN HKEY ResourceKey,
  239. IN RESOURCE_HANDLE ResourceHandle
  240. )
  241. /*++
  242. Routine Description:
  243. Open routine for RSCluster resources.
  244. Open the specified resource (create an instance of the resource).
  245. Allocate all structures necessary to bring the specified resource
  246. online.
  247. Arguments:
  248. ResourceName - Supplies the name of the resource to open.
  249. ResourceKey - Supplies handle to the resource's cluster configuration
  250. database key.
  251. ResourceHandle - A handle that is passed back to the resource monitor
  252. when the SetResourceStatus or LogEvent method is called. See the
  253. description of the SetResourceStatus and LogEvent methods on the
  254. RSClusterStatup routine. This handle should never be closed or used
  255. for any purpose other than passing it as an argument back to the
  256. Resource Monitor in the SetResourceStatus or LogEvent callback.
  257. Return Value:
  258. RESID of created resource.
  259. NULL on failure.
  260. --*/
  261. {
  262. DWORD status;
  263. DWORD disposition;
  264. RESID resid = 0;
  265. HKEY parametersKey = NULL;
  266. // how many do I need actually??
  267. HKEY resKey = NULL;
  268. PRSCLUSTER_RESOURCE resourceEntry = NULL;
  269. HCLUSTER hCluster;
  270. // Semaphore security
  271. PSID pSystemSID = NULL;
  272. PSID pAdminSID = NULL;
  273. PACL pACL = NULL;
  274. PSECURITY_DESCRIPTOR pSD = NULL;
  275. #define CLUSTER_SEMAPHORE_NUM_ACE 2
  276. EXPLICIT_ACCESS ea[CLUSTER_SEMAPHORE_NUM_ACE];
  277. SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
  278. SECURITY_ATTRIBUTES sa;
  279. //
  280. // Open the Parameters registry key for this resource.
  281. //
  282. status = ClusterRegCreateKey( ResourceKey,
  283. L"Parameters",
  284. 0,
  285. KEY_ALL_ACCESS,
  286. NULL,
  287. &parametersKey,
  288. &disposition );
  289. if ( status != ERROR_SUCCESS ) {
  290. (g_LogEvent)(
  291. ResourceHandle,
  292. LOG_ERROR,
  293. L"Unable to open Parameters key. Error: %1!u!.\n",
  294. status );
  295. goto exit;
  296. }
  297. status = ClusterRegOpenKey( ResourceKey,
  298. L"",
  299. KEY_READ,
  300. &resKey);
  301. if (status != ERROR_SUCCESS) {
  302. (g_LogEvent)(ResourceHandle,
  303. LOG_ERROR,
  304. L"Unable to open resource key. Error: %1!u!.\n",
  305. status );
  306. goto error_exit;
  307. }
  308. if ( g_ScHandle == NULL ) {
  309. g_ScHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
  310. if ( g_ScHandle == NULL ) {
  311. status = GetLastError();
  312. (g_LogEvent)(
  313. ResourceHandle,
  314. LOG_ERROR,
  315. L"Failed to open service control manager, error %1!u!.\n",
  316. status);
  317. goto error_exit;
  318. }
  319. }
  320. resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(RSCLUSTER_RESOURCE) );
  321. if ( resourceEntry == NULL ) {
  322. status = GetLastError();
  323. (g_LogEvent)(
  324. ResourceHandle,
  325. LOG_ERROR,
  326. L"Unable to allocate resource entry structure. Error: %1!u!.\n",
  327. status );
  328. goto exit;
  329. }
  330. ZeroMemory( resourceEntry, sizeof(RSCLUSTER_RESOURCE) );
  331. resourceEntry->ResId = (RESID)resourceEntry; // for validation
  332. resourceEntry->ResourceHandle = ResourceHandle;
  333. resourceEntry->ParametersKey = parametersKey;
  334. resourceEntry->State = ClusterResourceOffline;
  335. resourceEntry->ResourceKey = resKey;
  336. resourceEntry->hSem= NULL;
  337. resourceEntry->ResourceName = LocalAlloc( LMEM_FIXED, (lstrlenW( ResourceName ) + 1) * sizeof(WCHAR) );
  338. if ( resourceEntry->ResourceName == NULL ) {
  339. goto exit;
  340. }
  341. lstrcpyW( resourceEntry->ResourceName, ResourceName );
  342. //
  343. // Create SD that allows access only to local-system and admin
  344. //
  345. memset(ea, 0, sizeof(EXPLICIT_ACCESS) * CLUSTER_SEMAPHORE_NUM_ACE);
  346. if (! AllocateAndInitializeSid( &SIDAuthNT, 2,
  347. SECURITY_BUILTIN_DOMAIN_RID,
  348. DOMAIN_ALIAS_RID_ADMINS,
  349. 0, 0, 0, 0, 0, 0,
  350. &pAdminSID) ) {
  351. status = GetLastError();
  352. goto error_exit;
  353. }
  354. ea[0].grfAccessPermissions = FILE_ALL_ACCESS;
  355. ea[0].grfAccessMode = SET_ACCESS;
  356. ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  357. ea[0].Trustee.pMultipleTrustee = NULL;
  358. ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  359. ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  360. ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  361. ea[0].Trustee.ptstrName = (LPTSTR) pAdminSID;
  362. if (! AllocateAndInitializeSid( &SIDAuthNT, 1,
  363. SECURITY_LOCAL_SYSTEM_RID,
  364. 0, 0, 0, 0, 0, 0, 0,
  365. &pSystemSID) ) {
  366. status = GetLastError();
  367. goto error_exit;
  368. }
  369. ea[1].grfAccessPermissions = FILE_ALL_ACCESS;
  370. ea[1].grfAccessMode = SET_ACCESS;
  371. ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  372. ea[1].Trustee.pMultipleTrustee = NULL;
  373. ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  374. ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  375. ea[1].Trustee.TrusteeType = TRUSTEE_IS_USER;
  376. ea[1].Trustee.ptstrName = (LPTSTR) pSystemSID;
  377. if ((status = SetEntriesInAcl(CLUSTER_SEMAPHORE_NUM_ACE, ea, NULL, &pACL)) != ERROR_SUCCESS) {
  378. goto error_exit;
  379. }
  380. pSD = (PSECURITY_DESCRIPTOR)LocalAlloc( LMEM_FIXED, SECURITY_DESCRIPTOR_MIN_LENGTH);
  381. if (! pSD) {
  382. status = ERROR_OUTOFMEMORY;
  383. goto error_exit;
  384. }
  385. if (! InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
  386. status = GetLastError();
  387. goto error_exit;
  388. }
  389. if (! SetSecurityDescriptorDacl(
  390. pSD,
  391. TRUE, // fDaclPresent flag
  392. pACL,
  393. FALSE // not a default DACL
  394. ) ) {
  395. status = GetLastError();
  396. goto error_exit;
  397. }
  398. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  399. sa.lpSecurityDescriptor = pSD;
  400. sa.bInheritHandle = FALSE;
  401. resourceEntry->hSem=CreateSemaphore(&sa,0,1,L"RemoteStorageServer");
  402. status=GetLastError();
  403. if(resourceEntry->hSem)
  404. {
  405. if(status==ERROR_ALREADY_EXISTS)
  406. {
  407. (g_LogEvent)(
  408. ResourceHandle,
  409. LOG_ERROR,
  410. L"Remote Storage is controlled by another resource. Error: %2!u!.\n",status );
  411. CloseHandle(resourceEntry->hSem);
  412. resourceEntry->hSem = NULL;
  413. goto error_exit;
  414. }
  415. }
  416. else
  417. {
  418. (g_LogEvent)(
  419. ResourceHandle,
  420. LOG_ERROR,
  421. L"Unable to create semaphore for Remote Storage Server Service . Error: %2!u!.\n",status );
  422. goto error_exit;
  423. }
  424. status = ERROR_SUCCESS;
  425. hCluster = OpenCluster(NULL);
  426. if (hCluster == NULL) {
  427. status = GetLastError();
  428. (g_LogEvent)(
  429. ResourceHandle,
  430. LOG_ERROR,
  431. L"Failed to open cluster, error %1!u!.",
  432. status );
  433. goto error_exit;
  434. }
  435. resourceEntry->hResource = OpenClusterResource(hCluster, ResourceName);
  436. status = GetLastError();
  437. CloseCluster(hCluster);
  438. if ( resourceEntry->hResource == NULL ) {
  439. (g_LogEvent)(
  440. ResourceHandle,
  441. LOG_ERROR,
  442. L"Failed to open resource, error %1!u!.", status );
  443. goto error_exit;
  444. }
  445. resid = (RESID)resourceEntry;
  446. error_exit:
  447. exit:
  448. if ( resid == 0 ) {
  449. if ( parametersKey != NULL ) {
  450. ClusterRegCloseKey( parametersKey );
  451. }
  452. if ( resourceEntry != NULL ) {
  453. LocalFree( resourceEntry->ResourceName );
  454. LocalFree( resourceEntry );
  455. }
  456. }
  457. if (pAdminSID) {
  458. FreeSid(pAdminSID);
  459. }
  460. if (pSystemSID) {
  461. FreeSid(pSystemSID);
  462. }
  463. if (pACL) {
  464. LocalFree(pACL);
  465. }
  466. if (pSD) {
  467. LocalFree(pSD);
  468. }
  469. if ( status != ERROR_SUCCESS ) {
  470. SetLastError( status );
  471. }
  472. return(resid);
  473. } // RSClusterOpen
  474. VOID
  475. WINAPI
  476. RSClusterClose(
  477. IN RESID ResourceId
  478. )
  479. /*++
  480. Routine Description:
  481. Close routine for RSCluster resources.
  482. Close the specified resource and deallocate all structures, etc.,
  483. allocated in the Open call. If the resource is not in the offline state,
  484. then the resource should be taken offline (by calling Terminate) before
  485. the close operation is performed.
  486. Arguments:
  487. ResourceId - Supplies the RESID of the resource to close.
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. PRSCLUSTER_RESOURCE resourceEntry;
  493. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  494. if ( resourceEntry == NULL ) {
  495. DBG_PRINT( "RSCluster: Close request for a nonexistent resource id %p\n",
  496. ResourceId );
  497. return;
  498. }
  499. if ( resourceEntry->ResId != ResourceId ) {
  500. (g_LogEvent)(
  501. resourceEntry->ResourceHandle,
  502. LOG_ERROR,
  503. L"Close resource sanity check failed! ResourceId = %1!u!.\n",
  504. ResourceId );
  505. return;
  506. }
  507. #ifdef LOG_VERBOSE
  508. (g_LogEvent)(
  509. resourceEntry->ResourceHandle,
  510. LOG_INFORMATION,
  511. L"Close request.\n" );
  512. #endif
  513. if ( resourceEntry->ParametersKey ) {
  514. ClusterRegCloseKey( resourceEntry->ParametersKey );
  515. }
  516. RSClusterTerminate( ResourceId );
  517. ClusterRegCloseKey( resourceEntry->ParametersKey );
  518. ClusterRegCloseKey( resourceEntry->ResourceKey );
  519. CloseClusterResource( resourceEntry->hResource );
  520. CloseHandle(resourceEntry->hSem);
  521. LocalFree( resourceEntry->ResourceName );
  522. LocalFree( resourceEntry );
  523. } // RSClusterClose
  524. DWORD
  525. WINAPI
  526. RSClusterOnline(
  527. IN RESID ResourceId,
  528. IN OUT PHANDLE EventHandle
  529. )
  530. /*++
  531. Routine Description:
  532. Online routine for RSCluster resources.
  533. Bring the specified resource online (available for use). The resource
  534. DLL should attempt to arbitrate for the resource if it is present on a
  535. shared medium, like a shared SCSI bus.
  536. Arguments:
  537. ResourceId - Supplies the resource id for the resource to be brought
  538. online (available for use).
  539. EventHandle - Returns a signalable handle that is signaled when the
  540. resource DLL detects a failure on the resource. This argument is
  541. NULL on input, and the resource DLL returns NULL if asynchronous
  542. notification of failures is not supported, otherwise this must be
  543. the address of a handle that is signaled on resource failures.
  544. Return Value:
  545. ERROR_SUCCESS - The operation was successful, and the resource is now
  546. online.
  547. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  548. ERROR_RESOURCE_NOT_AVAILABLE - If the resource was arbitrated with some
  549. other systems and one of the other systems won the arbitration.
  550. ERROR_IO_PENDING - The request is pending, a thread has been activated
  551. to process the online request. The thread that is processing the
  552. online request will periodically report status by calling the
  553. SetResourceStatus callback method, until the resource is placed into
  554. the ClusterResourceOnline state (or the resource monitor decides to
  555. timeout the online request and Terminate the resource. This pending
  556. timeout value is settable and has a default value of 3 minutes.).
  557. Win32 error code - The operation failed.
  558. --*/
  559. {
  560. DWORD status;
  561. PRSCLUSTER_RESOURCE resourceEntry;
  562. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  563. if ( resourceEntry == NULL ) {
  564. DBG_PRINT( "RSCluster: Online request for a nonexistent resource id %p.\n",
  565. ResourceId );
  566. return(ERROR_RESOURCE_NOT_FOUND);
  567. }
  568. if ( resourceEntry->ResId != ResourceId ) {
  569. (g_LogEvent)(
  570. resourceEntry->ResourceHandle,
  571. LOG_ERROR,
  572. L"Online service sanity check failed! ResourceId = %1!u!.\n",
  573. ResourceId );
  574. return(ERROR_RESOURCE_NOT_FOUND);
  575. }
  576. #ifdef LOG_VERBOSE
  577. (g_LogEvent)(
  578. resourceEntry->ResourceHandle,
  579. LOG_INFORMATION,
  580. L"Online request.\n" );
  581. #endif
  582. resourceEntry->State = ClusterResourceOffline;
  583. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  584. status = ClusWorkerCreate( &resourceEntry->OnlineThread,
  585. (PWORKER_START_ROUTINE)RSClusterOnlineThread,
  586. resourceEntry );
  587. if ( status != ERROR_SUCCESS ) {
  588. resourceEntry->State = ClusterResourceFailed;
  589. (g_LogEvent)(
  590. resourceEntry->ResourceHandle,
  591. LOG_ERROR,
  592. L"Online: Unable to start thread, status %1!u!.\n",
  593. status
  594. );
  595. } else {
  596. status = ERROR_IO_PENDING;
  597. }
  598. return(status);
  599. } // RSClusterOnline
  600. DWORD
  601. WINAPI
  602. RSClusterOnlineThread(
  603. PCLUS_WORKER WorkerPtr,
  604. IN PRSCLUSTER_RESOURCE ResourceEntry
  605. )
  606. /*++
  607. Routine Description:
  608. Worker function which brings a resource from the resource table online.
  609. This function is executed in a separate thread.
  610. Arguments:
  611. WorkerPtr - Supplies the worker structure
  612. ResourceEntry - A pointer to the RSCLUSTER_RESOURCE block for this resource.
  613. Returns:
  614. ERROR_SUCCESS - The operation completed successfully.
  615. Win32 error code - The operation failed.
  616. --*/
  617. {
  618. SERVICE_STATUS_PROCESS ServiceStatus;
  619. LPWSTR * serviceArgArray = NULL;
  620. DWORD serviceArgCount = 0;
  621. DWORD valueSize;
  622. LPVOID Environment = NULL;
  623. WCHAR * p;
  624. LPSERVICE_FAILURE_ACTIONS pSvcFailureActions = NULL;
  625. DWORD cbBytesNeeded, i;
  626. LPQUERY_SERVICE_CONFIG lpquerysvcconfig=NULL;
  627. HANDLE processToken = NULL;
  628. RESOURCE_STATUS resourceStatus;
  629. DWORD status = ERROR_SUCCESS;
  630. ResUtilInitializeResourceStatus( &resourceStatus );
  631. resourceStatus.ResourceState = ClusterResourceFailed;
  632. // resourceStatus.WaitHint = 0;
  633. resourceStatus.CheckPoint = 1;
  634. ResourceEntry->dwServicePid = 0;
  635. ResourceEntry->ServiceHandle = OpenService( g_ScHandle,
  636. RSCLUSTER_SVCNAME,
  637. SERVICE_ALL_ACCESS );
  638. if ( ResourceEntry->ServiceHandle == NULL ) {
  639. status = GetLastError();
  640. (g_LogEvent)(
  641. ResourceEntry->ResourceHandle,
  642. LOG_ERROR,
  643. L"Failed to open service, error = %1!u!.\n",
  644. status );
  645. goto error_exit;
  646. }
  647. valueSize = sizeof(QUERY_SERVICE_CONFIG);
  648. AllocSvcConfig:
  649. lpquerysvcconfig=(LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_FIXED, valueSize);
  650. if(lpquerysvcconfig==NULL){
  651. status = GetLastError();
  652. (g_LogEvent)(
  653. ResourceEntry->ResourceHandle,
  654. LOG_ERROR,
  655. L"Remote Storage Server: Failed to allocate memory for query_service_config, error = %1!u!.\n",
  656. status );
  657. goto error_exit;
  658. }
  659. if (!QueryServiceConfig(ResourceEntry->ServiceHandle,
  660. lpquerysvcconfig,
  661. valueSize,
  662. &cbBytesNeeded))
  663. {
  664. status=GetLastError();
  665. if (status != ERROR_INSUFFICIENT_BUFFER){
  666. (g_LogEvent)(ResourceEntry->ResourceHandle,
  667. LOG_ERROR,
  668. L"Remote Storage Server: Failed to query service configuration, error= %1!u!.\n",
  669. status );
  670. goto error_exit;
  671. }
  672. status=ERROR_SUCCESS;
  673. LocalFree(lpquerysvcconfig);
  674. lpquerysvcconfig=NULL;
  675. valueSize = cbBytesNeeded;
  676. goto AllocSvcConfig;
  677. }
  678. if (lpquerysvcconfig->dwStartType == SERVICE_DISABLED)
  679. {
  680. (g_LogEvent)(
  681. ResourceEntry->ResourceHandle,
  682. LOG_ERROR,
  683. L"Remote Storage Server: the service is DISABLED\n");
  684. status=ERROR_SERVICE_DISABLED;
  685. goto error_exit;
  686. }
  687. ChangeServiceConfig( ResourceEntry->ServiceHandle,
  688. SERVICE_NO_CHANGE,
  689. SERVICE_DEMAND_START, // Manual start
  690. SERVICE_NO_CHANGE,
  691. NULL,
  692. NULL,
  693. NULL,
  694. NULL,
  695. NULL,
  696. NULL,
  697. NULL );
  698. if (!(QueryServiceConfig2(ResourceEntry->ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS,
  699. (LPBYTE)&valueSize, sizeof(DWORD), &cbBytesNeeded)))
  700. {
  701. status = GetLastError();
  702. if (status != ERROR_INSUFFICIENT_BUFFER)
  703. {
  704. (g_LogEvent)(
  705. ResourceEntry->ResourceHandle,
  706. LOG_ERROR,
  707. L"Remote Storage Server: Failed to query service configuration for size, error= %1!u!.\n",
  708. status );
  709. goto error_exit;
  710. }
  711. else
  712. status = ERROR_SUCCESS;
  713. }
  714. pSvcFailureActions = (LPSERVICE_FAILURE_ACTIONS)LocalAlloc(LMEM_FIXED, cbBytesNeeded);
  715. if ( pSvcFailureActions == NULL ) {
  716. status = GetLastError();
  717. (g_LogEvent)(
  718. ResourceEntry->ResourceHandle,
  719. LOG_ERROR,
  720. L"Remote Storage Server: Failed to allocate memory, error = %1!u!.\n",
  721. status );
  722. goto error_exit;
  723. }
  724. if (!(QueryServiceConfig2(ResourceEntry->ServiceHandle, SERVICE_CONFIG_FAILURE_ACTIONS,
  725. (LPBYTE)pSvcFailureActions, cbBytesNeeded, &cbBytesNeeded)))
  726. {
  727. (g_LogEvent)(
  728. ResourceEntry->ResourceHandle,
  729. LOG_ERROR,
  730. L"Remote Storage Server: Failed to query service configuration, error = %1!u!.\n",
  731. status );
  732. goto error_exit;
  733. }
  734. for (i=0; i<pSvcFailureActions->cActions;i++)
  735. {
  736. if (pSvcFailureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
  737. pSvcFailureActions->lpsaActions[i].Type = SC_ACTION_NONE;
  738. }
  739. ChangeServiceConfig2(ResourceEntry->ServiceHandle,
  740. SERVICE_CONFIG_FAILURE_ACTIONS,
  741. pSvcFailureActions);
  742. if ( 0 )
  743. {
  744. Environment = ResUtilGetEnvironmentWithNetName( ResourceEntry->hResource );
  745. }
  746. else
  747. {
  748. BOOL success;
  749. OpenProcessToken( GetCurrentProcess(), MAXIMUM_ALLOWED, &processToken );
  750. success = CreateEnvironmentBlock(&Environment, processToken, FALSE );
  751. if ( processToken != NULL ) {
  752. CloseHandle( processToken );
  753. }
  754. if ( !success ) {
  755. status = GetLastError();
  756. goto error_exit;
  757. }
  758. }
  759. if (Environment != NULL) {
  760. HKEY ServicesKey;
  761. HKEY hKey;
  762. p = (WCHAR *)Environment;
  763. while (*p) {
  764. while (*p++) {
  765. }
  766. }
  767. valueSize = (DWORD)((PUCHAR)p - (PUCHAR)Environment) +
  768. sizeof(WCHAR);
  769. status = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  770. SERVICES_ROOT,
  771. 0,
  772. KEY_READ,
  773. &ServicesKey );
  774. if (status != ERROR_SUCCESS) {
  775. (g_LogEvent)(
  776. ResourceEntry->ResourceHandle,
  777. LOG_ERROR,
  778. L"Failed to open services key, error = %1!u!.\n",
  779. status );
  780. goto error_exit;
  781. }
  782. status = RegOpenKeyExW( ServicesKey,
  783. RSCLUSTER_SVCNAME,
  784. 0,
  785. KEY_READ | KEY_WRITE,
  786. &hKey );
  787. RegCloseKey(ServicesKey);
  788. if (status != ERROR_SUCCESS) {
  789. (g_LogEvent)(
  790. ResourceEntry->ResourceHandle,
  791. LOG_ERROR,
  792. L"Failed to open service key, error = %1!u!.\n",
  793. status );
  794. goto error_exit;
  795. }
  796. status = RegSetValueExW( hKey,
  797. L"Environment",
  798. 0,
  799. REG_MULTI_SZ,
  800. Environment,
  801. valueSize );
  802. RegCloseKey(hKey);
  803. if (status != ERROR_SUCCESS) {
  804. (g_LogEvent)(
  805. ResourceEntry->ResourceHandle,
  806. LOG_ERROR,
  807. L"Failed to set service environment value, error = %1!u!.\n",
  808. status );
  809. goto error_exit;
  810. }
  811. }
  812. if ( !StartServiceW( ResourceEntry->ServiceHandle,
  813. serviceArgCount,
  814. serviceArgArray ) )
  815. {
  816. status = GetLastError();
  817. if (status != ERROR_SERVICE_ALREADY_RUNNING) {
  818. (g_LogEvent)(ResourceEntry->ResourceHandle,
  819. LOG_ERROR,
  820. L"Failed to start service. Error: %1!u!.\n",
  821. status );
  822. status = ERROR_SERVICE_NEVER_STARTED;
  823. goto error_exit;
  824. }
  825. // add code to stop the service that is running
  826. // and start the service again..
  827. }
  828. while (!ClusWorkerCheckTerminate(WorkerPtr)) {
  829. if (!QueryServiceStatusEx(
  830. ResourceEntry->ServiceHandle,
  831. SC_STATUS_PROCESS_INFO, (LPBYTE)&ServiceStatus,
  832. sizeof(SERVICE_STATUS_PROCESS), &cbBytesNeeded ) )
  833. {
  834. status = GetLastError();
  835. (g_LogEvent)(
  836. ResourceEntry->ResourceHandle,
  837. LOG_ERROR,
  838. L"Query Service Status failed %1!u!.\n",
  839. status );
  840. goto error_exit;
  841. }
  842. if ( ServiceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  843. break;
  844. }
  845. Sleep(250);
  846. }
  847. if (ClusWorkerCheckTerminate(WorkerPtr)) {
  848. goto error_exit;
  849. }
  850. if ( ServiceStatus.dwCurrentState != SERVICE_RUNNING ) {
  851. (g_LogEvent)(
  852. ResourceEntry->ResourceHandle,
  853. LOG_ERROR,
  854. L"Failed to start service. Error: %1!u!.\n",
  855. ERROR_SERVICE_NEVER_STARTED );
  856. status = ERROR_SERVICE_NEVER_STARTED;
  857. goto error_exit;
  858. }
  859. resourceStatus.ResourceState = ClusterResourceOnline;
  860. if (!(ServiceStatus.dwServiceFlags & SERVICE_RUNS_IN_SYSTEM_PROCESS)) {
  861. ResourceEntry->dwServicePid = ServiceStatus.dwProcessId;
  862. }
  863. (g_LogEvent)(
  864. ResourceEntry->ResourceHandle,
  865. LOG_INFORMATION,
  866. L"Service is now on line.\n" );
  867. error_exit:
  868. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  869. &resourceStatus );
  870. if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
  871. ResourceEntry->Online = TRUE;
  872. } else {
  873. ResourceEntry->Online = FALSE;
  874. }
  875. // more setting here to ensure no problems
  876. ResourceEntry->State = resourceStatus.ResourceState;
  877. //cleanup
  878. if (pSvcFailureActions)
  879. LocalFree(pSvcFailureActions);
  880. if (lpquerysvcconfig)
  881. LocalFree(lpquerysvcconfig);
  882. LocalFree( serviceArgArray );
  883. if (Environment != NULL) {
  884. DestroyEnvironmentBlock(Environment);
  885. }
  886. return(status);
  887. } // RSClusterOnlineThread
  888. DWORD
  889. WINAPI
  890. RSClusterOffline(
  891. IN RESID ResourceId
  892. )
  893. /*++
  894. Routine Description:
  895. Offline routine for RSCluster resources.
  896. Take the specified resource offline gracefully (unavailable for use).
  897. Wait for any cleanup operations to complete before returning.
  898. Arguments:
  899. ResourceId - Supplies the resource id for the resource to be shutdown
  900. gracefully.
  901. Return Value:
  902. ERROR_SUCCESS - The request completed successfully and the resource is
  903. offline.
  904. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  905. ERROR_IO_PENDING - The request is still pending, a thread has been
  906. activated to process the offline request. The thread that is
  907. processing the offline will periodically report status by calling
  908. the SetResourceStatus callback method, until the resource is placed
  909. into the ClusterResourceOffline state (or the resource monitor decides
  910. to timeout the offline request and Terminate the resource).
  911. Win32 error code - Will cause the resource monitor to log an event and
  912. call the Terminate routine.
  913. --*/
  914. {
  915. // extra code here
  916. DWORD status;
  917. PRSCLUSTER_RESOURCE resourceEntry;
  918. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  919. if ( resourceEntry == NULL ) {
  920. DBG_PRINT( "RSCluster: Offline request for a nonexistent resource id %p\n",
  921. ResourceId );
  922. return(ERROR_RESOURCE_NOT_FOUND);
  923. }
  924. if ( resourceEntry->ResId != ResourceId ) {
  925. (g_LogEvent)(
  926. resourceEntry->ResourceHandle,
  927. LOG_ERROR,
  928. L"Offline resource sanity check failed! ResourceId = %1!u!.\n",
  929. ResourceId );
  930. return(ERROR_RESOURCE_NOT_FOUND);
  931. }
  932. #ifdef LOG_VERBOSE
  933. (g_LogEvent)(
  934. resourceEntry->ResourceHandle,
  935. LOG_INFORMATION,
  936. L"Offline request.\n" );
  937. #endif
  938. ClusWorkerTerminate( &resourceEntry->PendingThread );
  939. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  940. (PWORKER_START_ROUTINE)RSClusterOfflineThread,
  941. resourceEntry );
  942. if ( status == ERROR_SUCCESS ) {
  943. status = ERROR_IO_PENDING;
  944. }
  945. return(status);
  946. } // RSClusterOffline
  947. DWORD
  948. RSClusterOfflineThread(
  949. PCLUS_WORKER pWorker,
  950. IN PRSCLUSTER_RESOURCE ResourceEntry
  951. )
  952. /*++
  953. Routine Description:
  954. Brings remote storage service resource offline
  955. Arguments:
  956. Worker - Supplies the worker structure
  957. Context - A pointer to the DiskInfo block for this resource.
  958. Returns:
  959. ERROR_SUCCESS if successful.
  960. Win32 error code on failure.
  961. --*/
  962. {
  963. RESOURCE_STATUS resourceStatus;
  964. DWORD retryTick = 300; // 300 msec at a time
  965. DWORD status = ERROR_SUCCESS;
  966. BOOL didStop = FALSE;
  967. SERVICE_STATUS ServiceStatus;
  968. ResUtilInitializeResourceStatus( &resourceStatus );
  969. resourceStatus.ResourceState = ClusterResourceFailed;
  970. //resourceStatus.WaitHint = 0;
  971. resourceStatus.CheckPoint = 1;
  972. if ( ResourceEntry->ServiceHandle == NULL )
  973. {
  974. resourceStatus.ResourceState = ClusterResourceOffline;
  975. goto FnExit;
  976. }
  977. while (!ClusWorkerCheckTerminate(pWorker)) {
  978. status = (ControlService(
  979. ResourceEntry->ServiceHandle,
  980. (didStop
  981. ? SERVICE_CONTROL_INTERROGATE
  982. : SERVICE_CONTROL_STOP),
  983. &ServiceStatus )
  984. ? NO_ERROR
  985. : GetLastError());
  986. if (status == NO_ERROR) {
  987. didStop = TRUE;
  988. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  989. (g_LogEvent)(
  990. ResourceEntry->ResourceHandle,
  991. LOG_INFORMATION,
  992. L"Service stopped.\n" );
  993. //set the status
  994. ResourceEntry->Online = FALSE;
  995. resourceStatus.ResourceState = ClusterResourceOffline;
  996. CloseServiceHandle( ResourceEntry->ServiceHandle );
  997. ResourceEntry->ServiceHandle = NULL;
  998. ResourceEntry->dwServicePid = 0;
  999. (g_LogEvent)(
  1000. ResourceEntry->ResourceHandle,
  1001. LOG_INFORMATION,
  1002. L"Service is now offline.\n" );
  1003. break;
  1004. }
  1005. }
  1006. if (status == ERROR_EXCEPTION_IN_SERVICE ||
  1007. status == ERROR_PROCESS_ABORTED ||
  1008. status == ERROR_SERVICE_NOT_ACTIVE) {
  1009. (g_LogEvent)(
  1010. ResourceEntry->ResourceHandle,
  1011. LOG_INFORMATION,
  1012. L"Service died or not active any more; status = %1!u!.\n",
  1013. status);
  1014. ResourceEntry->Online = FALSE;
  1015. resourceStatus.ResourceState = ClusterResourceOffline;
  1016. CloseServiceHandle( ResourceEntry->ServiceHandle );
  1017. ResourceEntry->ServiceHandle = NULL;
  1018. ResourceEntry->dwServicePid = 0;
  1019. (g_LogEvent)(
  1020. ResourceEntry->ResourceHandle,
  1021. LOG_INFORMATION,
  1022. L"Service is now offline.\n" );
  1023. break;
  1024. }
  1025. (g_LogEvent)(
  1026. ResourceEntry->ResourceHandle,
  1027. LOG_INFORMATION,
  1028. L"Offline: retrying...\n" );
  1029. Sleep(retryTick);
  1030. }
  1031. FnExit:
  1032. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  1033. &resourceStatus );
  1034. return(status);
  1035. } // RSClusterOfflineThread
  1036. VOID
  1037. WINAPI
  1038. RSClusterTerminate(
  1039. IN RESID ResourceId
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. Terminate routine for RSCluster resources.
  1044. Take the specified resource offline immediately (the resource is
  1045. unavailable for use).
  1046. Arguments:
  1047. ResourceId - Supplies the resource id for the resource to be brought
  1048. offline.
  1049. Return Value:
  1050. None.
  1051. --*/
  1052. {
  1053. // extra code here
  1054. PRSCLUSTER_RESOURCE resourceEntry;
  1055. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  1056. if ( resourceEntry == NULL ) {
  1057. DBG_PRINT( "RSCluster: Terminate request for a nonexistent resource id %p\n",
  1058. ResourceId );
  1059. return;
  1060. }
  1061. if ( resourceEntry->ResId != ResourceId ) {
  1062. (g_LogEvent)(
  1063. resourceEntry->ResourceHandle,
  1064. LOG_ERROR,
  1065. L"Terminate resource sanity check failed! ResourceId = %1!u!.\n",
  1066. ResourceId );
  1067. return;
  1068. }
  1069. #ifdef LOG_VERBOSE
  1070. (g_LogEvent)(
  1071. resourceEntry->ResourceHandle,
  1072. LOG_INFORMATION,
  1073. L"Terminate request.\n" );
  1074. #endif
  1075. RSClusterDoTerminate( resourceEntry );
  1076. resourceEntry->State = ClusterResourceOffline;
  1077. } // RSClusterTerminate
  1078. DWORD
  1079. RSClusterDoTerminate(
  1080. IN PRSCLUSTER_RESOURCE resourceEntry
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. Do the actual Terminate work for RSCluster resources.
  1085. Arguments:
  1086. ResourceEntry - Supplies resource entry for resource to be terminated
  1087. Return Value:
  1088. ERROR_SUCCESS - The request completed successfully and the resource is
  1089. offline.
  1090. Win32 error code - Will cause the resource monitor to log an event and
  1091. call the Terminate routine.
  1092. --*/
  1093. {
  1094. DWORD status = ERROR_SUCCESS;
  1095. SERVICE_STATUS ServiceStatus;
  1096. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  1097. ClusWorkerTerminate( &resourceEntry->PendingThread );
  1098. if ( resourceEntry->ServiceHandle != NULL )
  1099. {
  1100. DWORD dwRetryCount= 100;
  1101. BOOL didStop = FALSE;
  1102. DWORD dwRetryTick = 300; // 300 msec at a time
  1103. DWORD dwStatus;
  1104. while (dwRetryCount--)
  1105. {
  1106. (g_LogEvent)(
  1107. resourceEntry->ResourceHandle,
  1108. LOG_INFORMATION,
  1109. L"RSClusterTerminate : calling SCM\n" );
  1110. dwStatus = (ControlService(
  1111. resourceEntry->ServiceHandle,
  1112. (didStop
  1113. ? SERVICE_CONTROL_INTERROGATE
  1114. : SERVICE_CONTROL_STOP),
  1115. &ServiceStatus )
  1116. ? NO_ERROR
  1117. : GetLastError());
  1118. if (dwStatus == NO_ERROR)
  1119. {
  1120. didStop = TRUE;
  1121. if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
  1122. {
  1123. (g_LogEvent)(
  1124. resourceEntry->ResourceHandle,
  1125. LOG_INFORMATION,
  1126. L"Service stopped.\n" );
  1127. //set the status
  1128. resourceEntry->Online = FALSE;
  1129. resourceEntry->dwServicePid = 0;
  1130. break;
  1131. }
  1132. }
  1133. if (dwStatus == ERROR_EXCEPTION_IN_SERVICE ||
  1134. dwStatus == ERROR_PROCESS_ABORTED ||
  1135. dwStatus == ERROR_SERVICE_NOT_ACTIVE)
  1136. {
  1137. (g_LogEvent)(
  1138. resourceEntry->ResourceHandle,
  1139. LOG_INFORMATION,
  1140. L"Service died; status = %1!u!.\n",
  1141. dwStatus);
  1142. //set the status
  1143. resourceEntry->Online = FALSE;
  1144. resourceEntry->dwServicePid = 0;
  1145. break;
  1146. }
  1147. (g_LogEvent)(
  1148. resourceEntry->ResourceHandle,
  1149. LOG_INFORMATION,
  1150. L"RSClusterTerminate: retrying...\n" );
  1151. Sleep(dwRetryTick);
  1152. }
  1153. if (resourceEntry->dwServicePid)
  1154. {
  1155. HANDLE hSvcProcess = NULL;
  1156. hSvcProcess = OpenProcess(PROCESS_TERMINATE,
  1157. FALSE, resourceEntry->dwServicePid);
  1158. if (hSvcProcess)
  1159. {
  1160. (g_LogEvent)(
  1161. resourceEntry->ResourceHandle,
  1162. LOG_INFORMATION,
  1163. L"RSClusterTerminate: terminating processid=%1!u!\n",
  1164. resourceEntry->dwServicePid);
  1165. TerminateProcess(hSvcProcess, 0);
  1166. CloseHandle(hSvcProcess);
  1167. }
  1168. }
  1169. CloseServiceHandle( resourceEntry->ServiceHandle );
  1170. resourceEntry->ServiceHandle = NULL;
  1171. resourceEntry->dwServicePid = 0;
  1172. }
  1173. resourceEntry->Online = FALSE;
  1174. // //
  1175. resourceEntry->State = ClusterResourceOffline;
  1176. /*
  1177. if ( status == ERROR_SUCCESS ) {
  1178. ResourceEntry->State = ClusterResourceOffline;
  1179. }
  1180. return(status);
  1181. */
  1182. return(ERROR_SUCCESS);
  1183. } // RSClusterDoTerminate
  1184. BOOL
  1185. WINAPI
  1186. RSClusterLooksAlive(
  1187. IN RESID ResourceId
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. LooksAlive routine for RSCluster resources.
  1192. Perform a quick check to determine if the specified resource is probably
  1193. online (available for use). This call should not block for more than
  1194. 300 ms, preferably less than 50 ms.
  1195. Arguments:
  1196. ResourceId - Supplies the resource id for the resource to polled.
  1197. Return Value:
  1198. TRUE - The specified resource is probably online and available for use.
  1199. FALSE - The specified resource is not functioning normally.
  1200. --*/
  1201. {
  1202. PRSCLUSTER_RESOURCE resourceEntry;
  1203. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  1204. if ( resourceEntry == NULL ) {
  1205. DBG_PRINT("RSCluster: LooksAlive request for a nonexistent resource id %p\n",
  1206. ResourceId );
  1207. return(FALSE);
  1208. }
  1209. if ( resourceEntry->ResId != ResourceId ) {
  1210. (g_LogEvent)(
  1211. resourceEntry->ResourceHandle,
  1212. LOG_ERROR,
  1213. L"LooksAlive sanity check failed! ResourceId = %1!u!.\n",
  1214. ResourceId );
  1215. return(FALSE);
  1216. }
  1217. #ifdef LOG_VERBOSE
  1218. (g_LogEvent)(
  1219. resourceEntry->ResourceHandle,
  1220. LOG_INFORMATION,
  1221. L"LooksAlive request.\n" );
  1222. #endif
  1223. //
  1224. return(RSClusterCheckIsAlive( resourceEntry ));
  1225. } // RSClusterLooksAlive
  1226. BOOL
  1227. WINAPI
  1228. RSClusterIsAlive(
  1229. IN RESID ResourceId
  1230. )
  1231. /*++
  1232. Routine Description:
  1233. IsAlive routine for RSCluster resources.
  1234. Perform a thorough check to determine if the specified resource is online
  1235. (available for use). This call should not block for more than 400 ms,
  1236. preferably less than 100 ms.
  1237. Arguments:
  1238. ResourceId - Supplies the resource id for the resource to polled.
  1239. Return Value:
  1240. TRUE - The specified resource is online and functioning normally.
  1241. FALSE - The specified resource is not functioning normally.
  1242. --*/
  1243. {
  1244. PRSCLUSTER_RESOURCE resourceEntry;
  1245. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  1246. if ( resourceEntry == NULL ) {
  1247. DBG_PRINT("RSCluster: IsAlive request for a nonexistent resource id %p\n",
  1248. ResourceId );
  1249. return(FALSE);
  1250. }
  1251. if ( resourceEntry->ResId != ResourceId ) {
  1252. (g_LogEvent)(
  1253. resourceEntry->ResourceHandle,
  1254. LOG_ERROR,
  1255. L"IsAlive sanity check failed! ResourceId = %1!u!.\n",
  1256. ResourceId );
  1257. return(FALSE);
  1258. }
  1259. #ifdef LOG_VERBOSE
  1260. (g_LogEvent)(
  1261. resourceEntry->ResourceHandle,
  1262. LOG_INFORMATION,
  1263. L"IsAlive request.\n" );
  1264. #endif
  1265. return(RSClusterCheckIsAlive( resourceEntry ));
  1266. } // RSClusterIsAlive
  1267. BOOL
  1268. RSClusterCheckIsAlive(
  1269. IN PRSCLUSTER_RESOURCE resourceEntry
  1270. )
  1271. /*++
  1272. Routine Description:
  1273. Check to see if the resource is alive for RSCluster resources.
  1274. Arguments:
  1275. ResourceEntry - Supplies the resource entry for the resource to polled.
  1276. Return Value:
  1277. TRUE - The specified resource is online and functioning normally.
  1278. FALSE - The specified resource is not functioning normally.
  1279. --*/
  1280. {
  1281. SERVICE_STATUS ServiceStatus;
  1282. DWORD status = TRUE;
  1283. if ( !QueryServiceStatus( resourceEntry->ServiceHandle,
  1284. &ServiceStatus ) ) {
  1285. (g_LogEvent)(
  1286. resourceEntry->ResourceHandle,
  1287. LOG_ERROR,
  1288. L"Query Service Status failed %1!u!.\n",
  1289. GetLastError() );
  1290. return(FALSE);
  1291. }
  1292. if ( (ServiceStatus.dwCurrentState != SERVICE_RUNNING) &&
  1293. (ServiceStatus.dwCurrentState != SERVICE_START_PENDING) ) {
  1294. status = FALSE;
  1295. }
  1296. if (!status) {
  1297. (g_LogEvent)(
  1298. resourceEntry->ResourceHandle,
  1299. LOG_ERROR,
  1300. L"Failed the IsAlive test. Current State is %1!u!.\n",
  1301. ServiceStatus.dwCurrentState );
  1302. }
  1303. return(status);
  1304. } // RSClusterCheckIsAlive
  1305. DWORD
  1306. WINAPI
  1307. RSClusterResourceControl(
  1308. IN RESID ResourceId,
  1309. IN DWORD ControlCode,
  1310. IN PVOID InBuffer,
  1311. IN DWORD InBufferSize,
  1312. OUT PVOID OutBuffer,
  1313. IN DWORD OutBufferSize,
  1314. OUT LPDWORD BytesReturned
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. ResourceControl routine for RSCluster resources.
  1319. Perform the control request specified by ControlCode on the specified
  1320. resource.
  1321. Arguments:
  1322. ResourceId - Supplies the resource id for the specific resource.
  1323. ControlCode - Supplies the control code that defines the action
  1324. to be performed.
  1325. InBuffer - Supplies a pointer to a buffer containing input data.
  1326. InBufferSize - Supplies the size, in bytes, of the data pointed
  1327. to by InBuffer.
  1328. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1329. OutBufferSize - Supplies the size, in bytes, of the available space
  1330. pointed to by OutBuffer.
  1331. BytesReturned - Returns the number of bytes of OutBuffer actually
  1332. filled in by the resource. If OutBuffer is too small, BytesReturned
  1333. contains the total number of bytes for the operation to succeed.
  1334. Return Value:
  1335. ERROR_SUCCESS - The function completed successfully.
  1336. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  1337. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1338. In some cases, this allows the cluster software to perform the work.
  1339. Win32 error code - The function failed.
  1340. --*/
  1341. {
  1342. DWORD status;
  1343. PRSCLUSTER_RESOURCE resourceEntry;
  1344. resourceEntry = (PRSCLUSTER_RESOURCE)ResourceId;
  1345. if ( resourceEntry == NULL ) {
  1346. DBG_PRINT("RSCluster: ResourceControl request for a nonexistent resource id %p\n",
  1347. ResourceId );
  1348. return(ERROR_RESOURCE_NOT_FOUND);
  1349. }
  1350. if ( resourceEntry->ResId != ResourceId ) {
  1351. (g_LogEvent)(
  1352. resourceEntry->ResourceHandle,
  1353. LOG_ERROR,
  1354. L"ResourceControl sanity check failed! ResourceId = %1!u!.\n",
  1355. ResourceId );
  1356. return(ERROR_RESOURCE_NOT_FOUND);
  1357. }
  1358. switch ( ControlCode ) {
  1359. case CLUSCTL_RESOURCE_UNKNOWN:
  1360. *BytesReturned = 0;
  1361. status = ERROR_SUCCESS;
  1362. break;
  1363. default:
  1364. status = ERROR_INVALID_FUNCTION;
  1365. break;
  1366. }
  1367. return(status);
  1368. } // RSClusterResourceControl
  1369. //***********************************************************
  1370. //
  1371. // Define Function Table
  1372. //
  1373. //***********************************************************
  1374. CLRES_V1_FUNCTION_TABLE( g_RSClusterFunctionTable, // Name
  1375. CLRES_VERSION_V1_00, // Version
  1376. RSCluster, // Prefix
  1377. NULL, // Arbitrate
  1378. NULL, // Release
  1379. RSClusterResourceControl, // ResControl
  1380. NULL); // ResTypeControl