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.

2399 lines
70 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name:
  4. resource.c
  5. Abstract:
  6. Implements the management of the resource list. This includes
  7. adding resources to the list and deleting them from the list.
  8. Author:
  9. John Vert (jvert) 1-Dec-1995
  10. Revision History:
  11. Sivaprasad Padisetty (sivapad) 06-18-1997 Added the COM support
  12. --*/
  13. #include "resmonp.h"
  14. #include "stdio.h"
  15. #define RESMON_MODULE RESMON_MODULE_RMAPI
  16. //
  17. // Local data
  18. //
  19. //
  20. // Function prototypes local to this module
  21. //
  22. LPWSTR
  23. GetParameter(
  24. IN HKEY ClusterKey,
  25. IN LPCWSTR ValueName
  26. );
  27. //
  28. // Local functions
  29. //
  30. DWORD s_RmLoadResourceTypeDll(
  31. IN handle_t IDL_handle,
  32. IN LPCWSTR lpszResourceType,
  33. IN LPCWSTR lpszDllName
  34. )
  35. {
  36. RESDLL_FNINFO ResDllFnInfo;
  37. #ifdef COMRES
  38. RESDLL_INTERFACES ResDllInterfaces;
  39. #endif
  40. DWORD dwStatus;
  41. dwStatus = RmpLoadResType(
  42. lpszResourceType,
  43. lpszDllName,
  44. &ResDllFnInfo,
  45. #ifdef COMRES
  46. &ResDllInterfaces,
  47. #endif
  48. NULL);
  49. if (ResDllFnInfo.hDll)
  50. FreeLibrary(ResDllFnInfo.hDll);
  51. #ifdef COMRES
  52. if (ResDllInterfaces.pClusterResource)
  53. IClusterResource_Release (ResDllInterfaces.pClusterResource) ;
  54. if (ResDllInterfaces.pClusterQuorumResource)
  55. IClusterQuorumResource_Release (ResDllInterfaces.pClusterQuorumResource) ;
  56. if (ResDllInterfaces.pClusterResControl)
  57. IClusterResControl_Release (
  58. ResDllInterfaces.pClusterResControl
  59. ) ;
  60. #endif //COMRES
  61. return(dwStatus);
  62. }
  63. RESID
  64. s_RmCreateResource(
  65. IN handle_t IDL_handle,
  66. IN LPCWSTR DllName,
  67. IN LPCWSTR ResourceType,
  68. IN LPCWSTR ResourceId,
  69. IN DWORD LooksAlivePoll,
  70. IN DWORD IsAlivePoll,
  71. IN RM_NOTIFY_KEY NotifyKey,
  72. IN DWORD PendingTimeout,
  73. OUT LPDWORD Status
  74. )
  75. /*++
  76. Routine Description:
  77. Creates a resource to be monitored by the resource monitor.
  78. This involves allocating necessary structures, and loading its DLL.
  79. This does *NOT* insert the resource into the monitoring list or
  80. attempt to bring the resource on-line.
  81. Arguments:
  82. IDL_handle - Supplies RPC binding handle, currently unused
  83. DllName - Supplies the name of the resource DLL
  84. ResourceType - Supplies the type of resource
  85. ResourceId - Supplies the Id of this specific resource
  86. LooksAlivePoll - Supplies the LooksAlive poll interval
  87. IsAlivePoll - Supplies the IsAlive poll interval
  88. PendingTimeout - Supplies the Pending Timeout value for this resource
  89. NotifyKey - Supplies a key to be passed to the notification
  90. callback if this resource's state changes.
  91. Return Value:
  92. ResourceId - Returns a unique identifer to be used to identify
  93. this resource for later operations.
  94. --*/
  95. {
  96. PRESOURCE Resource=NULL;
  97. DWORD Error;
  98. HKEY ResKey;
  99. PSTARTUP_ROUTINE Startup;
  100. PCLRES_FUNCTION_TABLE FunctionTable;
  101. DWORD quorumCapable;
  102. DWORD valueType;
  103. DWORD valueData;
  104. DWORD valueSize;
  105. DWORD retry;
  106. DWORD Reason;
  107. LPWSTR pszDllName = (LPWSTR) DllName;
  108. CL_ASSERT(IsAlivePoll != 0);
  109. Resource = RmpAlloc(sizeof(RESOURCE));
  110. if (Resource == NULL) {
  111. Error = ERROR_NOT_ENOUGH_MEMORY;
  112. CL_LOGFAILURE(Error);
  113. goto ErrorExit;
  114. }
  115. ZeroMemory( Resource, sizeof(RESOURCE) );
  116. //Resource->Dll = NULL;
  117. //Resource->Flags = 0;
  118. //Resource->DllName = NULL;
  119. //Resource->ResourceType = NULL;
  120. //Resource->ResourceId = NULL;
  121. //Resource->ResourceName = NULL;
  122. //Resource->TimerEvent = NULL;
  123. //Resource->OnlineEvent = NULL;
  124. //Resource->IsArbitrated = FALSE;
  125. Resource->Signature = RESOURCE_SIGNATURE;
  126. Resource->NotifyKey = NotifyKey;
  127. Resource->LooksAlivePollInterval = LooksAlivePoll;
  128. Resource->IsAlivePollInterval = IsAlivePoll;
  129. Resource->State = ClusterResourceOffline;
  130. if ( PendingTimeout <= 10 ) {
  131. Resource->PendingTimeout = PENDING_TIMEOUT;
  132. } else {
  133. Resource->PendingTimeout = PendingTimeout;
  134. }
  135. Resource->DllName = RmpAlloc((lstrlenW(DllName) + 1)*sizeof(WCHAR));
  136. if (Resource->DllName == NULL) {
  137. Error = ERROR_NOT_ENOUGH_MEMORY;
  138. CL_LOGFAILURE(Error);
  139. goto ErrorExit;
  140. }
  141. lstrcpyW(Resource->DllName, DllName);
  142. Resource->ResourceType = RmpAlloc((lstrlenW(ResourceType) + 1)*sizeof(WCHAR));
  143. if (Resource->ResourceType == NULL) {
  144. Error = ERROR_NOT_ENOUGH_MEMORY;
  145. CL_LOGFAILURE(Error);
  146. goto ErrorExit;
  147. }
  148. lstrcpyW(Resource->ResourceType, ResourceType);
  149. Resource->ResourceId = RmpAlloc((lstrlenW(ResourceId) + 1)*sizeof(WCHAR));
  150. if (Resource->ResourceId == NULL) {
  151. Error = ERROR_NOT_ENOUGH_MEMORY;
  152. CL_LOGFAILURE(Error);
  153. goto ErrorExit;
  154. }
  155. lstrcpyW(Resource->ResourceId, ResourceId);
  156. // Expand any environment variables included in the DLL path name.
  157. if ( wcschr( DllName, L'%' ) != NULL ) {
  158. pszDllName = ClRtlExpandEnvironmentStrings( DllName );
  159. if ( pszDllName == NULL ) {
  160. Error = GetLastError();
  161. ClRtlLogPrint(LOG_UNUSUAL, "[RM] Error expanding environment strings in '%1!ls!, error %2!u!.\n",
  162. DllName,
  163. Error);
  164. goto ErrorExit;
  165. }
  166. }
  167. //
  168. // Load the specified DLL and find the required entrypoints.
  169. //
  170. Resource->Dll = LoadLibraryW(pszDllName);
  171. if (Resource->Dll == NULL) {
  172. #ifdef COMRES
  173. HRESULT hr ;
  174. CLSID clsid ;
  175. Error = GetLastError(); // Save the previous error. Return it instead of COM error on failure
  176. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error loading resource dll %1!ws!, error %2!u!.\n",
  177. pszDllName, Error);
  178. hr = CLSIDFromProgID(DllName, &clsid) ;
  179. if (FAILED (hr))
  180. {
  181. ClRtlLogPrint(LOG_CRITICAL, "[RM] CLSIDFromProgID %1!ws!, hr = %2!u!.\n",
  182. DllName, hr);
  183. hr = CLSIDFromString( (LPWSTR) DllName, //Pointer to the string representation of the CLSID
  184. &clsid//Pointer to the CLSID
  185. );
  186. if (FAILED (hr))
  187. {
  188. ClRtlLogPrint(LOG_CRITICAL, "[RM] CLSIDFromString Also failed %1!ws!, hr = %2!u!.\n",
  189. DllName, hr);
  190. goto ComError ;
  191. }
  192. }
  193. if ((hr = CoCreateInstance (&clsid, NULL, CLSCTX_ALL, &IID_IClusterResource, (LPVOID *) &Resource->pClusterResource)) != S_OK)
  194. {
  195. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error CoCreateInstance Prog ID %1!ws!, error %2!u!.\n", DllName, hr);
  196. goto ComError ;
  197. }
  198. Resource->dwType = RESMON_TYPE_COM ;
  199. hr = IClusterResource_QueryInterface (Resource->pClusterResource, &IID_IClusterQuorumResource,
  200. &Resource->pClusterQuorumResource) ;
  201. if (FAILED(hr))
  202. Resource->pClusterQuorumResource = NULL ;
  203. quorumCapable = (Resource->pClusterQuorumResource)?1:0 ;
  204. hr = IClusterResource_QueryInterface (
  205. Resource->pClusterResource,
  206. &IID_IClusterResControl,
  207. &Resource->pClusterResControl
  208. ) ;
  209. if (FAILED(hr))
  210. Resource->pClusterResControl = NULL ;
  211. goto comOpened ;
  212. ComError:
  213. #else
  214. Error = GetLastError();
  215. #endif
  216. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error loading resource dll %1!ws!, error %2!u!.\n",
  217. DllName, Error);
  218. CL_LOGFAILURE(Error);
  219. ClusterLogEvent2(LOG_CRITICAL,
  220. LOG_CURRENT_MODULE,
  221. __FILE__,
  222. __LINE__,
  223. RMON_CANT_LOAD_RESTYPE,
  224. sizeof(Error),
  225. &Error,
  226. DllName,
  227. ResourceType);
  228. goto ErrorExit;
  229. }
  230. #ifdef COMRES
  231. else {
  232. Resource->dwType = RESMON_TYPE_DLL ;
  233. }
  234. comOpened:
  235. #endif
  236. //
  237. // Invoke debugger if one is specified.
  238. //
  239. if ( RmpDebugger ) {
  240. //
  241. // Wait for debugger to come online.
  242. //
  243. retry = 100;
  244. while ( retry-- &&
  245. !IsDebuggerPresent() ) {
  246. Sleep(100);
  247. }
  248. OutputDebugStringA("[RM] Just loaded resource DLL ");
  249. OutputDebugStringW(DllName);
  250. OutputDebugStringA("\n");
  251. DebugBreak();
  252. }
  253. #ifdef COMRES
  254. if (Resource->dwType == RESMON_TYPE_DLL)
  255. {
  256. #endif
  257. //
  258. // We must have a startup routine to find all the other functions.
  259. //
  260. Startup = (PSTARTUP_ROUTINE)GetProcAddress(Resource->Dll,
  261. STARTUP_ROUTINE);
  262. if ( Startup != NULL ) {
  263. FunctionTable = NULL;
  264. RmpSetMonitorState(RmonStartingResource, Resource);
  265. try {
  266. Error = (Startup)( ResourceType,
  267. CLRES_VERSION_V1_00,
  268. CLRES_VERSION_V1_00,
  269. RmpSetResourceStatus,
  270. RmpLogEvent,
  271. &FunctionTable );
  272. } except (EXCEPTION_EXECUTE_HANDLER) {
  273. Error = GetExceptionCode();
  274. }
  275. RmpSetMonitorState(RmonIdle, NULL);
  276. if ( Error != ERROR_SUCCESS ) {
  277. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup call to %1!ws!, error %2!u!.\n",
  278. DllName, Error );
  279. ClusterLogEvent2(LOG_CRITICAL,
  280. LOG_CURRENT_MODULE,
  281. __FILE__,
  282. __LINE__,
  283. RMON_CANT_INIT_RESTYPE,
  284. sizeof(Error),
  285. &Error,
  286. DllName,
  287. ResourceType);
  288. goto ErrorExit;
  289. }
  290. Error = ERROR_INVALID_DATA;
  291. if ( FunctionTable == NULL ) {
  292. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, FunctionTable is NULL!\n");
  293. Reason = 0;
  294. ClusterLogEvent2(LOG_CRITICAL,
  295. LOG_CURRENT_MODULE,
  296. __FILE__,
  297. __LINE__,
  298. RMON_RESTYPE_BAD_TABLE,
  299. sizeof(Reason),
  300. &Reason,
  301. DllName,
  302. ResourceType);
  303. goto ErrorExit;
  304. }
  305. if ( FunctionTable->Version != CLRES_VERSION_V1_00 ) {
  306. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, Invalid Version Number!\n");
  307. Reason = 1;
  308. ClusterLogEvent2(LOG_CRITICAL,
  309. LOG_CURRENT_MODULE,
  310. __FILE__,
  311. __LINE__,
  312. RMON_RESTYPE_BAD_TABLE,
  313. sizeof(Reason),
  314. &Reason,
  315. DllName,
  316. ResourceType);
  317. goto ErrorExit;
  318. }
  319. if ( FunctionTable->TableSize != CLRES_V1_FUNCTION_SIZE ) {
  320. ClRtlLogPrint(LOG_CRITICAL, "[RM] Error on Startup return, Invalid function table size!\n");
  321. Reason = 2;
  322. ClusterLogEvent2(LOG_CRITICAL,
  323. LOG_CURRENT_MODULE,
  324. __FILE__,
  325. __LINE__,
  326. RMON_RESTYPE_BAD_TABLE,
  327. sizeof(Reason),
  328. &Reason,
  329. DllName,
  330. ResourceType);
  331. goto ErrorExit;
  332. }
  333. #ifdef COMRES
  334. Resource->pOpen = FunctionTable->V1Functions.Open;
  335. Resource->pClose = FunctionTable->V1Functions.Close;
  336. Resource->pOnline = FunctionTable->V1Functions.Online;
  337. Resource->pOffline = FunctionTable->V1Functions.Offline;
  338. Resource->pTerminate = FunctionTable->V1Functions.Terminate;
  339. Resource->pLooksAlive = FunctionTable->V1Functions.LooksAlive;
  340. Resource->pIsAlive = FunctionTable->V1Functions.IsAlive;
  341. Resource->pArbitrate = FunctionTable->V1Functions.Arbitrate;
  342. Resource->pRelease = FunctionTable->V1Functions.Release;
  343. Resource->pResourceControl = FunctionTable->V1Functions.ResourceControl;
  344. Resource->pResourceTypeControl = FunctionTable->V1Functions.ResourceTypeControl;
  345. Error = ERROR_INVALID_DATA;
  346. if ( Resource->pOpen == NULL ) {
  347. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Open routine for resource dll %1!ws!\n",
  348. DllName);
  349. goto ErrorExit;
  350. }
  351. if ( Resource->pClose == NULL ) {
  352. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Close routine for resource dll %1!ws!\n",
  353. DllName);
  354. goto ErrorExit;
  355. }
  356. if ( Resource->pOnline == NULL ) {
  357. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Online routine for resource dll %1!ws!\n",
  358. DllName);
  359. goto ErrorExit;
  360. }
  361. if ( Resource->pOffline == NULL ) {
  362. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Offline routine for resource dll %1!ws!\n",
  363. DllName);
  364. goto ErrorExit;
  365. }
  366. if ( Resource->pTerminate == NULL ) {
  367. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Terminate routine for resource dll %1!ws!\n",
  368. DllName);
  369. goto ErrorExit;
  370. }
  371. if ( Resource->pLooksAlive == NULL ) {
  372. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null LooksAlive routine for resource dll %1!ws!\n",
  373. DllName);
  374. goto ErrorExit;
  375. }
  376. if ( Resource->pIsAlive == NULL ) {
  377. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null IsAlive routine for resource dll %1!ws!\n",
  378. DllName);
  379. goto ErrorExit;
  380. }
  381. } else {
  382. ClRtlLogPrint(LOG_CRITICAL, "[RM] Could not find startup routine in resource DLL %1!ws!.\n",
  383. DllName);
  384. Error = ERROR_INVALID_DATA;
  385. goto ErrorExit;
  386. }
  387. if ( (Resource->pArbitrate) &&
  388. (Resource->pRelease) ) {
  389. quorumCapable = 1;
  390. } else {
  391. quorumCapable = 0;
  392. }
  393. }
  394. #else // COMRES
  395. Resource->Open = FunctionTable->V1Functions.Open;
  396. Resource->Close = FunctionTable->V1Functions.Close;
  397. Resource->Online = FunctionTable->V1Functions.Online;
  398. Resource->Offline = FunctionTable->V1Functions.Offline;
  399. Resource->Terminate = FunctionTable->V1Functions.Terminate;
  400. Resource->LooksAlive = FunctionTable->V1Functions.LooksAlive;
  401. Resource->IsAlive = FunctionTable->V1Functions.IsAlive;
  402. Resource->Arbitrate = FunctionTable->V1Functions.Arbitrate;
  403. Resource->Release = FunctionTable->V1Functions.Release;
  404. Resource->ResourceControl = FunctionTable->V1Functions.ResourceControl;
  405. Resource->ResourceTypeControl = FunctionTable->V1Functions.ResourceTypeControl;
  406. Error = ERROR_INVALID_DATA;
  407. if ( Resource->Open == NULL ) {
  408. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Open routine for resource dll %1!ws!\n",
  409. pszDllName);
  410. goto ErrorExit;
  411. }
  412. if ( Resource->Close == NULL ) {
  413. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Close routine for resource dll %1!ws!\n",
  414. pszDllName);
  415. goto ErrorExit;
  416. }
  417. if ( Resource->Online == NULL ) {
  418. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Online routine for resource dll %1!ws!\n",
  419. pszDllName);
  420. goto ErrorExit;
  421. }
  422. if ( Resource->Offline == NULL ) {
  423. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Offline routine for resource dll %1!ws!\n",
  424. pszDllName);
  425. goto ErrorExit;
  426. }
  427. if ( Resource->Terminate == NULL ) {
  428. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null Terminate routine for resource dll %1!ws!\n",
  429. pszDllName);
  430. goto ErrorExit;
  431. }
  432. if ( Resource->LooksAlive == NULL ) {
  433. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null LooksAlive routine for resource dll %1!ws!\n",
  434. pszDllName);
  435. goto ErrorExit;
  436. }
  437. if ( Resource->IsAlive == NULL ) {
  438. ClRtlLogPrint(LOG_CRITICAL, "[RM] Startup returned null IsAlive routine for resource dll %1!ws!\n",
  439. pszDllName);
  440. goto ErrorExit;
  441. }
  442. } else {
  443. ClRtlLogPrint(LOG_CRITICAL, "[RM] Could not find startup routine in resource DLL %1!ws!.\n",
  444. pszDllName);
  445. Error = ERROR_INVALID_DATA;
  446. goto ErrorExit;
  447. }
  448. if ( (Resource->Arbitrate) &&
  449. (Resource->Release) ) {
  450. quorumCapable = 1;
  451. } else {
  452. quorumCapable = 0;
  453. }
  454. #endif // COMRES
  455. Resource->State = ClusterResourceOffline;
  456. //
  457. // Open the resource's cluster registry key so that it can
  458. // be easily accessed from the Create entrypoint.
  459. //
  460. Error = ClusterRegOpenKey(RmpResourcesKey,
  461. ResourceId,
  462. KEY_READ,
  463. &ResKey);
  464. if (Error != ERROR_SUCCESS) {
  465. CL_LOGFAILURE(Error);
  466. goto ErrorExit;
  467. }
  468. //
  469. // Get the resource name.
  470. //
  471. Resource->ResourceName = GetParameter( ResKey, CLUSREG_NAME_RES_NAME );
  472. if ( Resource->ResourceName == NULL ) {
  473. Error = GetLastError();
  474. ClusterRegCloseKey(ResKey);
  475. ClRtlLogPrint(LOG_UNUSUAL, "[RM] Error reading resource name for %1!ws!, error %2!u!.\n",
  476. Resource->ResourceId, Error);
  477. CL_LOGFAILURE(Error);
  478. goto ErrorExit;
  479. }
  480. //
  481. // Call Open entrypoint.
  482. // This is done with the lock held to serialize calls to the
  483. // resource DLL and serialize access to the shared memory region.
  484. //
  485. AcquireListLock();
  486. RmpSetMonitorState(RmonInitializingResource, Resource);
  487. //
  488. // N.B. This is the only call that we make without locking the
  489. // eventlist lock! We can't, because we don't know that the event
  490. // list is yet.
  491. //
  492. try {
  493. #ifdef COMRES
  494. Resource->Id = RESMON_OPEN (Resource, ResKey) ;
  495. #else
  496. Resource->Id = (Resource->Open)(Resource->ResourceName,
  497. ResKey,
  498. Resource );
  499. #endif
  500. } except (EXCEPTION_EXECUTE_HANDLER) {
  501. SetLastError(GetExceptionCode());
  502. Resource->Id = 0;
  503. }
  504. if (Resource->Id == 0) {
  505. Error = GetLastError();
  506. } else {
  507. Error = RmpInsertResourceList(Resource, NULL);
  508. }
  509. //set the monitor state and close the key
  510. RmpSetMonitorState(RmonIdle, NULL);
  511. ClusterRegCloseKey(ResKey);
  512. if (Error != ERROR_SUCCESS)
  513. {
  514. //CL_LOGFAILURE(Error);
  515. ClRtlLogPrint(LOG_UNUSUAL, "[RM] RmpInsertResourceList failed, returned %1!u!\n",
  516. Error);
  517. ReleaseListLock();
  518. goto ErrorExit;
  519. }
  520. ReleaseListLock();
  521. if (Resource->Id == 0) {
  522. ClRtlLogPrint(LOG_CRITICAL, "[RM] Open of resource %1!ws! returned null!\n",
  523. Resource->ResourceName);
  524. if ( Error == ERROR_SUCCESS ) {
  525. Error = ERROR_RESOURCE_NOT_FOUND;
  526. }
  527. //CL_LOGFAILURE(Error);
  528. goto ErrorExit;
  529. }
  530. *Status = ERROR_SUCCESS;
  531. if ( pszDllName != DllName ) {
  532. LocalFree( pszDllName );
  533. }
  534. //
  535. // Resource object has been successfully loaded into memory and
  536. // its entrypoints determined. We now have a valid RESID that
  537. // can be used in subsequent calls.
  538. //
  539. return((RESID)Resource);
  540. ErrorExit:
  541. if (Resource != NULL) {
  542. if (Resource->Dll != NULL) {
  543. FreeLibrary(Resource->Dll);
  544. }
  545. #ifdef COMRES
  546. if (Resource->pClusterResource)
  547. IClusterResource_Release (Resource->pClusterResource) ;
  548. if (Resource->pClusterQuorumResource)
  549. IClusterQuorumResource_Release (Resource->pClusterQuorumResource) ;
  550. if (Resource->pClusterResControl)
  551. IClusterResControl_Release (
  552. Resource->pClusterResControl
  553. ) ;
  554. #endif
  555. RmpFree(Resource->DllName);
  556. RmpFree(Resource->ResourceType);
  557. RmpFree(Resource->ResourceName);
  558. RmpFree(Resource->ResourceId);
  559. RmpFree(Resource);
  560. }
  561. if ( pszDllName != DllName ) {
  562. LocalFree( pszDllName );
  563. }
  564. ClRtlLogPrint(LOG_CRITICAL, "[RM] Failed creating resource %1!ws!, error %2!u!.\n",
  565. ResourceId, Error);
  566. *Status = Error;
  567. return(0);
  568. } // RmCreateResource
  569. VOID
  570. s_RmCloseResource(
  571. IN OUT RESID *ResourceId
  572. )
  573. /*++
  574. Routine Description:
  575. Closes the specified resource. This includes removing it from the poll list,
  576. freeing any associated memory, and unloading its DLL.
  577. Arguments:
  578. ResourceId - Supplies a pointer to the resource ID. This will be set to
  579. NULL after cleanup is complete to indicate to RPC that the
  580. client side context can be destroyed.
  581. Return Value:
  582. None.
  583. --*/
  584. {
  585. PRESOURCE Resource;
  586. BOOL Closed;
  587. Resource = (PRESOURCE)*ResourceId;
  588. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  589. CL_ASSERT(Resource->Flags & RESOURCE_INSERTED);
  590. AcquireListLock();
  591. if (Resource->ListEntry.Flink != NULL) {
  592. RmpRemoveResourceList(Resource);
  593. Closed = FALSE;
  594. } else {
  595. Closed = TRUE;
  596. }
  597. ReleaseListLock();
  598. if (!Closed) {
  599. //
  600. // Call the DLL to close the resource.
  601. //
  602. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  603. //
  604. // If the Online Thread is still pending, wait a little bit for it.
  605. //
  606. if ( Resource->TimerEvent ) {
  607. SetEvent( Resource->TimerEvent );
  608. Resource->TimerEvent = NULL;
  609. }
  610. Resource->dwEntryPoint = RESDLL_ENTRY_CLOSE;
  611. try {
  612. #ifdef COMRES
  613. RESMON_CLOSE (Resource) ;
  614. #else
  615. (Resource->Close)(Resource->Id);
  616. #endif
  617. } except (EXCEPTION_EXECUTE_HANDLER) {
  618. }
  619. Resource->dwEntryPoint = 0;
  620. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  621. }
  622. Resource->Signature = 0;
  623. if ( Resource->OnlineEvent ) {
  624. SetEvent( Resource->OnlineEvent );
  625. CloseHandle( Resource->OnlineEvent );
  626. Resource->OnlineEvent = NULL;
  627. }
  628. //
  629. // Free the resource dll.
  630. //
  631. #ifdef COMRES
  632. if (Resource->dwType == RESMON_TYPE_DLL)
  633. {
  634. FreeLibrary(Resource->Dll);
  635. }
  636. else
  637. {
  638. IClusterResource_Release (Resource->pClusterResource) ;
  639. if (Resource->pClusterQuorumResource)
  640. IClusterQuorumResource_Release (Resource->pClusterQuorumResource) ;
  641. if (Resource->pClusterResControl)
  642. IClusterResControl_Release (
  643. Resource->pClusterResControl
  644. ) ;
  645. }
  646. #else
  647. FreeLibrary(Resource->Dll);
  648. #endif
  649. RmpFree(Resource->DllName);
  650. RmpFree(Resource->ResourceType);
  651. RmpFree(Resource->ResourceName);
  652. RmpFree(Resource->ResourceId);
  653. RmpFree(Resource);
  654. *ResourceId = NULL;
  655. } // RmCloseResource
  656. VOID
  657. RPC_RESID_rundown(
  658. IN RESID Resource
  659. )
  660. /*++
  661. Routine Description:
  662. RPC rundown procedure for a RESID. Just closes the handle.
  663. Arguments:
  664. Resource - supplies the RESID that is to be rundown.
  665. Return Value:
  666. None.
  667. --*/
  668. {
  669. //
  670. // Chittur Subbaraman (chitturs) - 5/10/2001
  671. //
  672. // Don't do anything on RPC rundown. If clussvc dies, then resmon main thread detects it and
  673. // runs down (close, terminate) resources. Merely, closing the resource here may cause
  674. // it to be delivered when resource dlls don't expect it.
  675. //
  676. #if 0
  677. s_RmCloseResource(&Resource);
  678. #endif
  679. } // RESID_rundown
  680. error_status_t
  681. s_RmChangeResourceParams(
  682. IN RESID ResourceId,
  683. IN DWORD LooksAlivePoll,
  684. IN DWORD IsAlivePoll,
  685. IN DWORD PendingTimeout
  686. )
  687. /*++
  688. Routine Description:
  689. Changes the poll intervals defined for a resource.
  690. Arguments:
  691. ResourceId - Supplies the resource ID.
  692. LooksAlivePoll - Supplies the new LooksAlive poll in ms units
  693. IsAlivePoll - Supplies the new IsAlive poll in ms units
  694. Return Value:
  695. ERROR_SUCCESS if successful
  696. Win32 error otherwise
  697. --*/
  698. {
  699. PRESOURCE Resource;
  700. BOOL Inserted;
  701. //
  702. // If the resmon is shutting down, just return since you can't trust any resource structures
  703. // accessed below.
  704. //
  705. if ( RmpShutdown ) return ( ERROR_SUCCESS );
  706. Resource = (PRESOURCE)ResourceId;
  707. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  708. AcquireListLock();
  709. Inserted = (Resource->Flags & RESOURCE_INSERTED);
  710. if (Inserted) {
  711. //
  712. // Remove the resource from the list, update its properties,
  713. // and reinsert it. The reinsertion will put it back in the
  714. // right spot to reflect the new poll intervals.
  715. //
  716. RmpRemoveResourceList(Resource);
  717. }
  718. Resource->LooksAlivePollInterval = LooksAlivePoll;
  719. Resource->IsAlivePollInterval = IsAlivePoll;
  720. Resource->PendingTimeout = PendingTimeout;
  721. if (Inserted) {
  722. RmpInsertResourceList( Resource,
  723. (PPOLL_EVENT_LIST) Resource->EventList);
  724. }
  725. ReleaseListLock();
  726. return(ERROR_SUCCESS);
  727. } // RmChangeResourcePoll
  728. error_status_t
  729. s_RmArbitrateResource(
  730. IN RESID ResourceId
  731. )
  732. /*++
  733. Routine Description:
  734. Arbitrate for the resource.
  735. Arguments:
  736. ResourceId - Supplies the resource to be arbitrated.
  737. Return Value:
  738. ERROR_SUCCESS if successful.
  739. A Win32 error code on failure.
  740. --*/
  741. {
  742. PRESOURCE Resource;
  743. DWORD status;
  744. Resource = (PRESOURCE)ResourceId;
  745. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  746. #ifdef COMRES
  747. if (Resource->dwType == RESMON_TYPE_DLL)
  748. {
  749. if ( (Resource->pArbitrate == NULL) ||
  750. (Resource->pRelease == NULL) ) {
  751. return(ERROR_NOT_QUORUM_CAPABLE);
  752. }
  753. }
  754. else
  755. {
  756. if (!Resource->pClusterQuorumResource)
  757. return(ERROR_NOT_QUORUM_CAPABLE);
  758. }
  759. #else
  760. if ( (Resource->Arbitrate == NULL) ||
  761. (Resource->Release == NULL) ) {
  762. return(ERROR_NOT_QUORUM_CAPABLE);
  763. }
  764. #endif
  765. //
  766. // Chittur Subbaraman (chitturs) - 10/15/99
  767. //
  768. // Commenting out lock acquisition - This is done so that the
  769. // arbitration request can proceed into the disk resource without
  770. // any blockage. There have been cases where either some resource
  771. // gets blocked in its "IsAlive" with this lock held or the resmon
  772. // itself calling into clussvc to set a property (for instance) and
  773. // this call gets blocked there. This results in an arbitration stall
  774. // and the clussvc on this node dies. Note that arbitrate only needs to
  775. // be serialized with release and the disk resource is supposed
  776. // to take care of that.
  777. //
  778. #if 0
  779. //
  780. // Lock the resource list and attempt to bring the resource on-line.
  781. // The lock is required to synchronize access to the resource list and
  782. // to serialize any calls to resource DLLs. Only one thread may be
  783. // calling a resource DLL at any time. This prevents resource DLLs
  784. // from having to worry about being thread-safe.
  785. //
  786. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  787. #else
  788. //
  789. // Try to acquire spin lock for synchronizing with resource rundown.
  790. // Return failure if you cannot get the lock.
  791. //
  792. if ( !RmpAcquireSpinLock( Resource, FALSE ) ) return ( ERROR_BUSY );
  793. #endif
  794. //
  795. // Update shared state to indicate we are arbitrating a resource
  796. //
  797. RmpSetMonitorState(RmonArbitrateResource, Resource);
  798. #ifdef COMRES
  799. status = RESMON_ARBITRATE (Resource, RmpLostQuorumResource) ;
  800. #else
  801. status = (Resource->Arbitrate)(Resource->Id,
  802. RmpLostQuorumResource);
  803. #endif
  804. if (status == ERROR_SUCCESS) {
  805. Resource->IsArbitrated = TRUE;
  806. }
  807. RmpSetMonitorState(RmonIdle, NULL);
  808. #if 0
  809. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  810. #else
  811. RmpReleaseSpinLock( Resource );
  812. #endif
  813. return(status);
  814. } // s_RmArbitrateResource(
  815. error_status_t
  816. s_RmReleaseResource(
  817. IN RESID ResourceId
  818. )
  819. /*++
  820. Routine Description:
  821. Release the resource.
  822. Arguments:
  823. ResourceId - Supplies the resource to be released.
  824. Return Value:
  825. ERROR_SUCCESS if successful.
  826. A Win32 error code on failure.
  827. --*/
  828. {
  829. PRESOURCE Resource;
  830. DWORD status;
  831. Resource = (PRESOURCE)ResourceId;
  832. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  833. #ifdef COMRES
  834. if (Resource->dwType == RESMON_TYPE_DLL)
  835. {
  836. if (Resource->pRelease == NULL) {
  837. return(ERROR_NOT_QUORUM_CAPABLE);
  838. }
  839. }
  840. else
  841. {
  842. if (!Resource->pClusterQuorumResource)
  843. return(ERROR_NOT_QUORUM_CAPABLE);
  844. }
  845. #else
  846. if ( Resource->Release == NULL ) {
  847. return(ERROR_NOT_QUORUM_CAPABLE);
  848. }
  849. #endif
  850. //
  851. // Lock the resource list and attempt to bring the resource on-line.
  852. // The lock is required to synchronize access to the resource list and
  853. // to serialize any calls to resource DLLs. Only one thread may be
  854. // calling a resource DLL at any time. This prevents resource DLLs
  855. // from having to worry about being thread-safe.
  856. //
  857. #if 0 // Not needed right now
  858. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  859. #endif
  860. //
  861. // Update shared state to indicate we ar arbitrating a resource
  862. //
  863. RmpSetMonitorState(RmonReleaseResource, Resource);
  864. #ifdef COMRES
  865. status = RESMON_RELEASE (Resource) ;
  866. #else
  867. status = (Resource->Release)(Resource->Id);
  868. #endif
  869. Resource->IsArbitrated = FALSE;
  870. RmpSetMonitorState(RmonIdle, NULL);
  871. #if 0 // Not needed right now
  872. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  873. #endif
  874. return(status);
  875. } // s_RmReleaseResource(
  876. error_status_t
  877. s_RmOnlineResource(
  878. IN RESID ResourceId,
  879. OUT LPDWORD pdwState
  880. )
  881. /*++
  882. Routine Description:
  883. Brings the specified resource into the online state.
  884. Arguments:
  885. ResourceId - Supplies the resource to be brought online.
  886. pdwState - The new state of the resource is returned.
  887. Return Value:
  888. --*/
  889. {
  890. PRESOURCE Resource;
  891. DWORD status;
  892. HANDLE timerThread;
  893. HANDLE eventHandle = NULL;
  894. DWORD threadId;
  895. Resource = (PRESOURCE)ResourceId;
  896. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  897. CL_ASSERT(Resource->EventHandle == NULL );
  898. *pdwState = ClusterResourceFailed;
  899. if ( Resource->State > ClusterResourcePending ) {
  900. return(ERROR_INVALID_STATE);
  901. }
  902. //
  903. // Create an event to allow the SetResourceStatus callback to synchronize
  904. // execution with this thread.
  905. //
  906. if ( Resource->OnlineEvent ) {
  907. return(ERROR_NOT_READY);
  908. }
  909. Resource->OnlineEvent = CreateEvent( NULL,
  910. FALSE,
  911. FALSE,
  912. NULL );
  913. if ( Resource->OnlineEvent == NULL ) {
  914. return(GetLastError());
  915. }
  916. //
  917. // Lock the resource list and attempt to bring the resource on-line.
  918. // The lock is required to synchronize access to the resource list and
  919. // to serialize any calls to resource DLLs. Only one thread may be
  920. // calling a resource DLL at any time. This prevents resource DLLs
  921. // from having to worry about being thread-safe.
  922. //
  923. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  924. //
  925. // Update shared state to indicate we are bringing a resource online
  926. //
  927. RmpSetMonitorState(RmonOnlineResource, Resource);
  928. //
  929. // Call Online entrypoint. Regardless of whether this succeeds or
  930. // not, the resource has been successfully added to the list. If the
  931. // online call fails, the resource immediately enters the failed state.
  932. //
  933. Resource->CheckPoint = 0;
  934. try {
  935. #ifdef COMRES
  936. status = RESMON_ONLINE (Resource, &eventHandle) ;
  937. #else
  938. status = (Resource->Online)(Resource->Id, &eventHandle);
  939. #endif
  940. } except (EXCEPTION_EXECUTE_HANDLER) {
  941. status = GetExceptionCode();
  942. }
  943. if (status == ERROR_SUCCESS) {
  944. SetEvent( Resource->OnlineEvent );
  945. CloseHandle( Resource->OnlineEvent );
  946. Resource->OnlineEvent = NULL;
  947. if ( eventHandle ) {
  948. status = RmpAddPollEvent( (PPOLL_EVENT_LIST)Resource->EventList,
  949. eventHandle,
  950. Resource );
  951. if ( status == ERROR_SUCCESS ) {
  952. Resource->State = ClusterResourceOnline;
  953. } else {
  954. CL_LOGFAILURE(status);
  955. Resource->State = ClusterResourceFailed;
  956. }
  957. } else {
  958. Resource->State = ClusterResourceOnline;
  959. }
  960. } else if ( status == ERROR_IO_PENDING ) {
  961. status = ERROR_SUCCESS;
  962. //
  963. // If the Resource DLL returns pending, then start a timer.
  964. //
  965. CL_ASSERT(Resource->TimerEvent == NULL );
  966. Resource->TimerEvent = CreateEvent( NULL,
  967. FALSE,
  968. FALSE,
  969. NULL );
  970. if ( Resource->TimerEvent == NULL ) {
  971. CL_UNEXPECTED_ERROR(status = GetLastError());
  972. } else {
  973. timerThread = CreateThread( NULL,
  974. 0,
  975. RmpTimerThread,
  976. Resource,
  977. 0,
  978. &threadId );
  979. if ( timerThread == NULL ) {
  980. CL_UNEXPECTED_ERROR(status = GetLastError());
  981. } else {
  982. //
  983. // Chittur Subbaraman (chitturs) - 1/12/99
  984. //
  985. // Raise the timer thread priority to highest. This
  986. // is necessary to avoid certain cases in which the
  987. // timer thread is sluggish to close out the timer event
  988. // handle before a second online. Note that there are
  989. // no major performance implications by doing this since
  990. // the timer thread is in a wait state most of the time.
  991. //
  992. if ( !SetThreadPriority( timerThread, THREAD_PRIORITY_HIGHEST ) )
  993. {
  994. ClRtlLogPrint(LOG_UNUSUAL,
  995. "[RM] s_RmOnlineResource: Error setting priority of timer "
  996. "thread for resource %1!ws!\n",
  997. Resource->ResourceName);
  998. CL_LOGFAILURE( GetLastError() );
  999. }
  1000. CloseHandle( timerThread );
  1001. //
  1002. // If we have an event handle, then add it to our list.
  1003. //
  1004. if ( eventHandle ) {
  1005. status = RmpAddPollEvent( (PPOLL_EVENT_LIST)Resource->EventList,
  1006. eventHandle,
  1007. Resource );
  1008. if ( status == ERROR_SUCCESS ) {
  1009. Resource->State = ClusterResourceOnlinePending;
  1010. } else {
  1011. ClRtlLogPrint(LOG_UNUSUAL,
  1012. "[RM] Failed to add event %1!u! for resource %2!ws!, error %3!u!.\n",
  1013. eventHandle,
  1014. Resource->ResourceName,
  1015. status );
  1016. CL_LOGFAILURE(status);
  1017. Resource->State = ClusterResourceFailed;
  1018. }
  1019. } else {
  1020. Resource->State = ClusterResourceOnlinePending;
  1021. //Resource->WaitHint = PENDING_TIMEOUT;
  1022. //Resource->CheckPoint = 0;
  1023. }
  1024. }
  1025. }
  1026. SetEvent( Resource->OnlineEvent );
  1027. } else {
  1028. CloseHandle( Resource->OnlineEvent );
  1029. Resource->OnlineEvent = NULL;
  1030. ClRtlLogPrint(LOG_CRITICAL, "[RM] OnlineResource failed, resource %1!ws!, status = %2!u!.\n",
  1031. Resource->ResourceName,
  1032. status);
  1033. ClusterLogEvent1(LOG_CRITICAL,
  1034. LOG_CURRENT_MODULE,
  1035. __FILE__,
  1036. __LINE__,
  1037. RMON_ONLINE_FAILED,
  1038. sizeof(status),
  1039. &status,
  1040. Resource->ResourceName);
  1041. Resource->State = ClusterResourceFailed;
  1042. }
  1043. RmpSetMonitorState(RmonIdle, NULL);
  1044. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  1045. //
  1046. // Notify poller thread that the list has changed
  1047. //
  1048. RmpSignalPoller((PPOLL_EVENT_LIST)Resource->EventList);
  1049. *pdwState = Resource->State;
  1050. return(status);
  1051. } // RmOnlineResource
  1052. VOID
  1053. s_RmTerminateResource(
  1054. IN RESID ResourceId
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. Brings the specified resource into the offline state immediately.
  1059. Arguments:
  1060. ResourceId - Supplies the resource to be brought online.
  1061. Return Value:
  1062. The new state of the resource.
  1063. --*/
  1064. {
  1065. DWORD State;
  1066. RmpOfflineResource(ResourceId, FALSE, &State);
  1067. return;
  1068. } // RmTerminateResource
  1069. error_status_t
  1070. s_RmOfflineResource(
  1071. IN RESID ResourceId,
  1072. OUT LPDWORD pdwState
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. Brings the specified resource into the offline state by shutting it
  1077. down gracefully.
  1078. Arguments:
  1079. ResourceId - Supplies the resource to be brought online.
  1080. pdwState - Returns the new state of the resource.
  1081. Return Value:
  1082. ERROR_SUCCESS if successful, else returns code.
  1083. --*/
  1084. {
  1085. return(RmpOfflineResource(ResourceId, TRUE, pdwState));
  1086. } // RmOfflineResource
  1087. error_status_t
  1088. s_RmFailResource(
  1089. IN RESID ResourceId
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. Fail the given resource.
  1094. Arguments:
  1095. ResourceId - Supplies the resource ID.
  1096. Return Value:
  1097. ERROR_SUCCESS if successful
  1098. Win32 error otherwise
  1099. --*/
  1100. {
  1101. PRESOURCE Resource;
  1102. Resource = (PRESOURCE)ResourceId;
  1103. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  1104. if ( Resource->State == ClusterResourceOnline ) {
  1105. Resource->State = ClusterResourceFailed;
  1106. RmpPostNotify(Resource, NotifyResourceStateChange);
  1107. return(ERROR_SUCCESS);
  1108. } else {
  1109. return(ERROR_RESMON_INVALID_STATE);
  1110. }
  1111. } // RmChangeResourcePoll
  1112. error_status_t
  1113. s_RmShutdownProcess(
  1114. IN handle_t IDL_handle
  1115. )
  1116. /*++
  1117. Routine Description:
  1118. Set the shutdown flag and trigger a poller thread to exit.
  1119. The termination of any poller thread will notify the main
  1120. thread to clean up and shutdown.
  1121. Arguments:
  1122. IDL_handle - Supplies RPC binding handle, currently unused
  1123. Return Value:
  1124. ERROR_SUCCESS
  1125. --*/
  1126. {
  1127. //
  1128. // Check if we've already been called here before. This can happen
  1129. // as a result of the Failover Manager calling us to perform a clean
  1130. // shutdown. The main thread also will call here, in case it is shutting
  1131. // down because of a failure of one of the threads.
  1132. //
  1133. if ( !RmpShutdown ) {
  1134. RmpShutdown = TRUE;
  1135. //
  1136. // Wake up the main thread so that it can cleanup.
  1137. //
  1138. SetEvent( RmpRewaitEvent );
  1139. }
  1140. return(ERROR_SUCCESS);
  1141. } // RmShutdownProcess
  1142. error_status_t
  1143. s_RmResourceControl(
  1144. IN RESID ResourceId,
  1145. IN DWORD ControlCode,
  1146. IN PUCHAR InBuffer,
  1147. IN DWORD InBufferSize,
  1148. OUT PUCHAR OutBuffer,
  1149. IN DWORD OutBufferSize,
  1150. OUT LPDWORD BytesReturned,
  1151. OUT LPDWORD Required
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. Process a resource control request.
  1156. Arguments:
  1157. ResourceId - the resource that is being controlled.
  1158. ControlCode - the control request, reduced to just the function code.
  1159. InBuffer - the input buffer for this control request.
  1160. InBufferSize - the size of the input buffer.
  1161. OutBuffer - the output buffer.
  1162. OutBufferSize - the size of the output buffer.
  1163. BytesReturned - the number of bytes returned.
  1164. Required - the number of bytes required if OutBuffer is not big enough.
  1165. Return Value:
  1166. ERROR_SUCCESS if successful
  1167. A Win32 error code on failure
  1168. --*/
  1169. {
  1170. PRESOURCE Resource;
  1171. DWORD status = ERROR_INVALID_FUNCTION;
  1172. Resource = (PRESOURCE)ResourceId;
  1173. CL_ASSERT(Resource->Signature == RESOURCE_SIGNATURE);
  1174. //
  1175. // Lock the resource list and send down the control request.
  1176. // The lock is required to synchronize access to the resource list and
  1177. // to serialize any calls to resource DLLs. Only one thread may be
  1178. // calling a resource DLL at any time. This prevents resource DLLs
  1179. // from having to worry about being thread-safe.
  1180. //
  1181. AcquireEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  1182. #ifdef COMRES
  1183. if (Resource->pResourceControl || Resource->pClusterResControl) {
  1184. RmpSetMonitorState(RmonResourceControl, Resource);
  1185. status = RESMON_RESOURCECONTROL( Resource,
  1186. ControlCode,
  1187. InBuffer,
  1188. InBufferSize,
  1189. OutBuffer,
  1190. OutBufferSize,
  1191. BytesReturned );
  1192. RmpSetMonitorState(RmonIdle, NULL);
  1193. }
  1194. #else
  1195. if ( Resource->ResourceControl ) {
  1196. RmpSetMonitorState(RmonResourceControl, Resource);
  1197. status = (Resource->ResourceControl)( Resource->Id,
  1198. ControlCode,
  1199. InBuffer,
  1200. InBufferSize,
  1201. OutBuffer,
  1202. OutBufferSize,
  1203. BytesReturned );
  1204. RmpSetMonitorState(RmonIdle, NULL);
  1205. }
  1206. #endif
  1207. if ( status == ERROR_INVALID_FUNCTION ) {
  1208. DWORD characteristics = CLUS_CHAR_UNKNOWN;
  1209. switch ( ControlCode ) {
  1210. case CLUSCTL_RESOURCE_GET_COMMON_PROPERTY_FMTS:
  1211. status = ResUtilGetPropertyFormats( RmpResourceCommonProperties,
  1212. OutBuffer,
  1213. OutBufferSize,
  1214. BytesReturned,
  1215. Required );
  1216. break;
  1217. case CLUSCTL_RESOURCE_GET_CLASS_INFO:
  1218. if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) {
  1219. *BytesReturned = 0;
  1220. *Required = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1221. if ( OutBuffer == NULL ) {
  1222. status = ERROR_SUCCESS;
  1223. } else {
  1224. status = ERROR_MORE_DATA;
  1225. }
  1226. } else {
  1227. PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer;
  1228. ptrResClassInfo->rc = CLUS_RESCLASS_UNKNOWN;
  1229. ptrResClassInfo->SubClass = 0;
  1230. *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1231. status = ERROR_SUCCESS;
  1232. }
  1233. break;
  1234. case CLUSCTL_RESOURCE_GET_CHARACTERISTICS:
  1235. #ifdef COMRES
  1236. if (Resource->dwType == RESMON_TYPE_DLL)
  1237. {
  1238. if ( (Resource->pArbitrate != NULL) &&
  1239. (Resource->pRelease != NULL) ) {
  1240. characteristics = CLUS_CHAR_QUORUM;
  1241. }
  1242. }
  1243. else
  1244. {
  1245. if (!Resource->pClusterQuorumResource)
  1246. characteristics = CLUS_CHAR_QUORUM;
  1247. }
  1248. #else
  1249. if ( (Resource->Arbitrate != NULL) &&
  1250. (Resource->Release != NULL) ) {
  1251. characteristics = CLUS_CHAR_QUORUM;
  1252. }
  1253. #endif
  1254. if ( OutBufferSize < sizeof(DWORD) ) {
  1255. *BytesReturned = 0;
  1256. *Required = sizeof(DWORD);
  1257. if ( OutBuffer == NULL ) {
  1258. status = ERROR_SUCCESS;
  1259. } else {
  1260. status = ERROR_MORE_DATA;
  1261. }
  1262. } else {
  1263. *BytesReturned = sizeof(DWORD);
  1264. *(LPDWORD)OutBuffer = characteristics;
  1265. status = ERROR_SUCCESS;
  1266. }
  1267. break;
  1268. case CLUSCTL_RESOURCE_GET_FLAGS:
  1269. status = RmpResourceGetFlags( Resource,
  1270. OutBuffer,
  1271. OutBufferSize,
  1272. BytesReturned,
  1273. Required );
  1274. break;
  1275. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  1276. *BytesReturned = 0;
  1277. status = ERROR_SUCCESS;
  1278. break;
  1279. case CLUSCTL_RESOURCE_ENUM_COMMON_PROPERTIES:
  1280. status = RmpResourceEnumCommonProperties( OutBuffer,
  1281. OutBufferSize,
  1282. BytesReturned,
  1283. Required );
  1284. break;
  1285. case CLUSCTL_RESOURCE_GET_RO_COMMON_PROPERTIES:
  1286. status = RmpResourceGetCommonProperties( Resource,
  1287. TRUE,
  1288. OutBuffer,
  1289. OutBufferSize,
  1290. BytesReturned,
  1291. Required );
  1292. break;
  1293. case CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES:
  1294. status = RmpResourceGetCommonProperties( Resource,
  1295. FALSE,
  1296. OutBuffer,
  1297. OutBufferSize,
  1298. BytesReturned,
  1299. Required );
  1300. break;
  1301. case CLUSCTL_RESOURCE_VALIDATE_COMMON_PROPERTIES:
  1302. status = RmpResourceValidateCommonProperties( Resource,
  1303. InBuffer,
  1304. InBufferSize );
  1305. break;
  1306. case CLUSCTL_RESOURCE_SET_COMMON_PROPERTIES:
  1307. status = RmpResourceSetCommonProperties( Resource,
  1308. InBuffer,
  1309. InBufferSize );
  1310. break;
  1311. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  1312. status = RmpResourceEnumPrivateProperties( Resource,
  1313. OutBuffer,
  1314. OutBufferSize,
  1315. BytesReturned,
  1316. Required );
  1317. break;
  1318. case CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES:
  1319. if ( OutBufferSize < sizeof(DWORD) ) {
  1320. *BytesReturned = 0;
  1321. *Required = sizeof(DWORD);
  1322. if ( OutBuffer == NULL ) {
  1323. status = ERROR_SUCCESS;
  1324. } else {
  1325. status = ERROR_MORE_DATA;
  1326. }
  1327. } else {
  1328. LPDWORD ptrDword = (LPDWORD) OutBuffer;
  1329. *ptrDword = 0;
  1330. *BytesReturned = sizeof(DWORD);
  1331. status = ERROR_SUCCESS;
  1332. }
  1333. break;
  1334. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  1335. status = RmpResourceGetPrivateProperties( Resource,
  1336. OutBuffer,
  1337. OutBufferSize,
  1338. BytesReturned,
  1339. Required );
  1340. break;
  1341. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  1342. status = RmpResourceValidatePrivateProperties( Resource,
  1343. InBuffer,
  1344. InBufferSize );
  1345. break;
  1346. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1347. status = RmpResourceSetPrivateProperties( Resource,
  1348. InBuffer,
  1349. InBufferSize );
  1350. break;
  1351. case CLUSCTL_RESOURCE_SET_NAME:
  1352. //
  1353. // Chittur Subbaraman (chitturs) - 6/28/99
  1354. //
  1355. // The setting of the name in the cluster registry is done
  1356. // in NT5 by clussvc. So, resmon does not have to do any work
  1357. // except return a success code in case a resource DLL returns
  1358. // ERROR_INVALID_FUNCTION.
  1359. //
  1360. status = ERROR_SUCCESS;
  1361. break;
  1362. default:
  1363. break;
  1364. }
  1365. } else {
  1366. // If the function is returning a buffer size without
  1367. // copying data, move this info around to satisfy RPC.
  1368. if ( *BytesReturned > OutBufferSize ) {
  1369. *Required = *BytesReturned;
  1370. *BytesReturned = 0;
  1371. status = ERROR_MORE_DATA;
  1372. }
  1373. }
  1374. if ( ( status != ERROR_SUCCESS ) &&
  1375. ( status != ERROR_MORE_DATA ) &&
  1376. ( status != ERROR_INVALID_FUNCTION ) )
  1377. {
  1378. ClRtlLogPrint(LOG_UNUSUAL,
  1379. "[RM] s_RmResourceControl: Resource <%1!ws!> control operation "
  1380. "0x%2!08lx! gives status=%3!u!...\n",
  1381. Resource->ResourceName,
  1382. ControlCode,
  1383. status);
  1384. }
  1385. ReleaseEventListLock( (PPOLL_EVENT_LIST)Resource->EventList );
  1386. return(status);
  1387. } // RmResourceControl
  1388. error_status_t
  1389. s_RmResourceTypeControl(
  1390. IN handle_t IDL_handle,
  1391. IN LPCWSTR ResourceTypeName,
  1392. IN LPCWSTR DllName,
  1393. IN DWORD ControlCode,
  1394. IN PUCHAR InBuffer,
  1395. IN DWORD InBufferSize,
  1396. OUT PUCHAR OutBuffer,
  1397. IN DWORD OutBufferSize,
  1398. OUT LPDWORD BytesReturned,
  1399. OUT LPDWORD Required
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. Process a resource type control request.
  1404. Arguments:
  1405. IDL_handle - not used.
  1406. ResourceTypeName - the resource type name that is being controlled.
  1407. DllName - the name of the dll.
  1408. ControlCode - the control request, reduced to just the function code.
  1409. InBuffer - the input buffer for this control request.
  1410. InBufferSize - the size of the input buffer.
  1411. OutBuffer - the output buffer.
  1412. OutBufferSize - the size of the output buffer.
  1413. BytesReturned - the number of bytes returned.
  1414. Required - the number of bytes required if OutBuffer is not big enough.
  1415. Return Value:
  1416. ERROR_SUCCESS if successful
  1417. A Win32 error code on failure
  1418. --*/
  1419. {
  1420. RESDLL_FNINFO ResDllFnInfo;
  1421. #ifdef COMRES
  1422. RESDLL_INTERFACES ResDllInterfaces;
  1423. #endif
  1424. DWORD status = ERROR_INVALID_FUNCTION;
  1425. DWORD characteristics = CLUS_CHAR_UNKNOWN;
  1426. status = RmpLoadResType(ResourceTypeName, DllName, &ResDllFnInfo,
  1427. #ifdef COMRES
  1428. &ResDllInterfaces,
  1429. #endif
  1430. &characteristics);
  1431. if (status != ERROR_SUCCESS)
  1432. {
  1433. return(status);
  1434. }
  1435. status = ERROR_INVALID_FUNCTION;
  1436. if (ResDllFnInfo.hDll && ResDllFnInfo.pResFnTable)
  1437. {
  1438. PRESOURCE_TYPE_CONTROL_ROUTINE resourceTypeControl = NULL ;
  1439. resourceTypeControl = ResDllFnInfo.pResFnTable->V1Functions.ResourceTypeControl;
  1440. if (resourceTypeControl)
  1441. {
  1442. RmpSetMonitorState(RmonResourceTypeControl, NULL);
  1443. status = (resourceTypeControl)( ResourceTypeName,
  1444. ControlCode,
  1445. InBuffer,
  1446. InBufferSize,
  1447. OutBuffer,
  1448. OutBufferSize,
  1449. BytesReturned );
  1450. RmpSetMonitorState(RmonIdle, NULL);
  1451. }
  1452. }
  1453. #ifdef COMRES
  1454. else if (ResDllInterfaces.pClusterResControl)
  1455. {
  1456. HRESULT hr ;
  1457. VARIANT vtIn, vtOut ;
  1458. SAFEARRAY sfIn = {1, 0, 1, 0, InBuffer, {InBufferSize, 0} } ;
  1459. SAFEARRAY sfOut = {1, FADF_FIXEDSIZE, 1, 0, OutBuffer, {OutBufferSize, 0} } ;
  1460. SAFEARRAY *psfOut = &sfOut ;
  1461. BSTR pbResourceTypeName ;
  1462. vtIn.vt = VT_ARRAY | VT_UI1 ;
  1463. vtOut.vt = VT_ARRAY | VT_UI1 | VT_BYREF ;
  1464. vtIn.parray = &sfIn ;
  1465. vtOut.pparray = &psfOut ;
  1466. pbResourceTypeName = SysAllocString (ResourceTypeName) ;
  1467. if (pbResourceTypeName == NULL)
  1468. {
  1469. CL_LOGFAILURE( ERROR_NOT_ENOUGH_MEMORY) ;
  1470. goto FnExit ; // Use the default processing
  1471. }
  1472. RmpSetMonitorState(RmonResourceTypeControl, NULL);
  1473. hr = IClusterResControl_ResourceTypeControl (
  1474. ResDllInterfaces.pClusterResControl,
  1475. pbResourceTypeName,
  1476. ControlCode,
  1477. &vtIn,
  1478. &vtOut,
  1479. BytesReturned,
  1480. &status);
  1481. RmpSetMonitorState(RmonIdle, NULL);
  1482. SysFreeString (pbResourceTypeName) ;
  1483. if (FAILED(hr))
  1484. {
  1485. CL_LOGFAILURE(hr); // Use the default processing
  1486. status = ERROR_INVALID_FUNCTION;
  1487. }
  1488. }
  1489. #endif
  1490. if ( status == ERROR_INVALID_FUNCTION ) {
  1491. switch ( ControlCode ) {
  1492. case CLUSCTL_RESOURCE_TYPE_GET_COMMON_RESOURCE_PROPERTY_FMTS:
  1493. status = ResUtilGetPropertyFormats( RmpResourceTypeCommonProperties,
  1494. OutBuffer,
  1495. OutBufferSize,
  1496. BytesReturned,
  1497. Required );
  1498. break;
  1499. case CLUSCTL_RESOURCE_TYPE_GET_CLASS_INFO:
  1500. if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) {
  1501. *BytesReturned = 0;
  1502. *Required = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1503. if ( OutBuffer == NULL ) {
  1504. status = ERROR_SUCCESS;
  1505. } else {
  1506. status = ERROR_MORE_DATA;
  1507. }
  1508. } else {
  1509. PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer;
  1510. ptrResClassInfo->rc = CLUS_RESCLASS_UNKNOWN;
  1511. ptrResClassInfo->SubClass = 0;
  1512. *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1513. status = ERROR_SUCCESS;
  1514. }
  1515. break;
  1516. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  1517. *BytesReturned = 0;
  1518. status = ERROR_SUCCESS;
  1519. break;
  1520. case CLUSCTL_RESOURCE_TYPE_GET_CHARACTERISTICS:
  1521. if ( OutBufferSize < sizeof(DWORD) ) {
  1522. *BytesReturned = 0;
  1523. *Required = sizeof(DWORD);
  1524. if ( OutBuffer == NULL ) {
  1525. status = ERROR_SUCCESS;
  1526. } else {
  1527. status = ERROR_MORE_DATA;
  1528. }
  1529. } else {
  1530. *BytesReturned = sizeof(DWORD);
  1531. *(LPDWORD)OutBuffer = characteristics;
  1532. status = ERROR_SUCCESS;
  1533. }
  1534. break;
  1535. case CLUSCTL_RESOURCE_TYPE_GET_FLAGS:
  1536. status = RmpResourceTypeGetFlags( ResourceTypeName,
  1537. OutBuffer,
  1538. OutBufferSize,
  1539. BytesReturned,
  1540. Required );
  1541. break;
  1542. case CLUSCTL_RESOURCE_TYPE_GET_REGISTRY_CHECKPOINTS:
  1543. *BytesReturned = 0;
  1544. *Required = 0;
  1545. status = ERROR_SUCCESS;
  1546. break;
  1547. case CLUSCTL_RESOURCE_TYPE_ENUM_COMMON_PROPERTIES:
  1548. status = RmpResourceTypeEnumCommonProperties( ResourceTypeName,
  1549. OutBuffer,
  1550. OutBufferSize,
  1551. BytesReturned,
  1552. Required );
  1553. break;
  1554. case CLUSCTL_RESOURCE_TYPE_GET_RO_COMMON_PROPERTIES:
  1555. status = RmpResourceTypeGetCommonProperties( ResourceTypeName,
  1556. TRUE,
  1557. OutBuffer,
  1558. OutBufferSize,
  1559. BytesReturned,
  1560. Required );
  1561. break;
  1562. case CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTIES:
  1563. status = RmpResourceTypeGetCommonProperties( ResourceTypeName,
  1564. FALSE,
  1565. OutBuffer,
  1566. OutBufferSize,
  1567. BytesReturned,
  1568. Required );
  1569. break;
  1570. case CLUSCTL_RESOURCE_TYPE_VALIDATE_COMMON_PROPERTIES:
  1571. status = RmpResourceTypeValidateCommonProperties( ResourceTypeName,
  1572. InBuffer,
  1573. InBufferSize );
  1574. break;
  1575. case CLUSCTL_RESOURCE_TYPE_SET_COMMON_PROPERTIES:
  1576. status = RmpResourceTypeSetCommonProperties( ResourceTypeName,
  1577. InBuffer,
  1578. InBufferSize );
  1579. break;
  1580. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  1581. status = RmpResourceTypeEnumPrivateProperties( ResourceTypeName,
  1582. OutBuffer,
  1583. OutBufferSize,
  1584. BytesReturned,
  1585. Required );
  1586. break;
  1587. case CLUSCTL_RESOURCE_TYPE_GET_RO_PRIVATE_PROPERTIES:
  1588. if ( OutBufferSize < sizeof(DWORD) ) {
  1589. *BytesReturned = 0;
  1590. *Required = sizeof(DWORD);
  1591. if ( OutBuffer == NULL ) {
  1592. status = ERROR_SUCCESS;
  1593. } else {
  1594. status = ERROR_MORE_DATA;
  1595. }
  1596. } else {
  1597. LPDWORD ptrDword = (LPDWORD) OutBuffer;
  1598. *ptrDword = 0;
  1599. *BytesReturned = sizeof(DWORD);
  1600. status = ERROR_SUCCESS;
  1601. }
  1602. break;
  1603. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_PROPERTIES:
  1604. status = RmpResourceTypeGetPrivateProperties( ResourceTypeName,
  1605. OutBuffer,
  1606. OutBufferSize,
  1607. BytesReturned,
  1608. Required );
  1609. break;
  1610. case CLUSCTL_RESOURCE_TYPE_VALIDATE_PRIVATE_PROPERTIES:
  1611. status = RmpResourceTypeValidatePrivateProperties( ResourceTypeName,
  1612. InBuffer,
  1613. InBufferSize );
  1614. break;
  1615. case CLUSCTL_RESOURCE_TYPE_SET_PRIVATE_PROPERTIES:
  1616. status = RmpResourceTypeSetPrivateProperties( ResourceTypeName,
  1617. InBuffer,
  1618. InBufferSize );
  1619. break;
  1620. default:
  1621. break;
  1622. }
  1623. } else {
  1624. // If the function is returning a buffer size without
  1625. // copying data, move this info around to satisfy RPC.
  1626. if ( *BytesReturned > OutBufferSize ) {
  1627. *Required = *BytesReturned;
  1628. *BytesReturned = 0;
  1629. }
  1630. if ( (status == ERROR_MORE_DATA) &&
  1631. (OutBuffer == NULL) ) {
  1632. status = ERROR_SUCCESS;
  1633. }
  1634. }
  1635. FnExit:
  1636. if (ResDllFnInfo.hDll)
  1637. FreeLibrary(ResDllFnInfo.hDll);
  1638. #ifdef COMRES
  1639. if (ResDllInterfaces.pClusterResource)
  1640. IClusterResource_Release (ResDllInterfaces.pClusterResource) ;
  1641. if (ResDllInterfaces.pClusterQuorumResource)
  1642. IClusterQuorumResource_Release (ResDllInterfaces.pClusterQuorumResource) ;
  1643. if (ResDllInterfaces.pClusterResControl)
  1644. IClusterResControl_Release (
  1645. ResDllInterfaces.pClusterResControl
  1646. ) ;
  1647. #endif
  1648. return(status);
  1649. } // RmResourceTypeControl
  1650. LPWSTR
  1651. GetParameter(
  1652. IN HKEY ClusterKey,
  1653. IN LPCWSTR ValueName
  1654. )
  1655. /*++
  1656. Routine Description:
  1657. Reads a REG_SZ parameter from the cluster regitry, and allocates the
  1658. necessary storage for it.
  1659. Arguments:
  1660. ClusterKey - supplies the cluster key where the parameter is stored.
  1661. ValueName - supplies the name of the value.
  1662. Return Value:
  1663. A pointer to a buffer containing the parameter value on success.
  1664. NULL on failure.
  1665. --*/
  1666. {
  1667. LPWSTR value;
  1668. DWORD valueLength;
  1669. DWORD valueType;
  1670. DWORD status;
  1671. valueLength = 0;
  1672. status = ClusterRegQueryValue( ClusterKey,
  1673. ValueName,
  1674. &valueType,
  1675. NULL,
  1676. &valueLength );
  1677. if ( (status != ERROR_SUCCESS) &&
  1678. (status != ERROR_MORE_DATA) ) {
  1679. SetLastError(status);
  1680. return(NULL);
  1681. }
  1682. if ( valueType == REG_SZ ) {
  1683. valueLength += sizeof(UNICODE_NULL);
  1684. }
  1685. value = LocalAlloc(LMEM_FIXED, valueLength);
  1686. if ( value == NULL ) {
  1687. return(NULL);
  1688. }
  1689. status = ClusterRegQueryValue(ClusterKey,
  1690. ValueName,
  1691. &valueType,
  1692. (LPBYTE)value,
  1693. &valueLength);
  1694. if ( status != ERROR_SUCCESS) {
  1695. LocalFree(value);
  1696. SetLastError(status);
  1697. value = NULL;
  1698. }
  1699. return(value);
  1700. } // GetParameter
  1701. #ifdef COMRES
  1702. RESID
  1703. Resmon_Open (
  1704. IN PRESOURCE Resource,
  1705. IN HKEY ResourceKey
  1706. )
  1707. {
  1708. if (Resource->dwType == RESMON_TYPE_DLL)
  1709. {
  1710. return (Resource->pOpen) (Resource->ResourceName, ResourceKey, Resource) ;
  1711. }
  1712. else
  1713. {
  1714. HRESULT hr ;
  1715. OLERESID ResId = 0 ;
  1716. BSTR pbResourceName = SysAllocString (Resource->ResourceName) ;
  1717. if (pbResourceName == NULL)
  1718. {
  1719. SetLastError ( ERROR_NOT_ENOUGH_MEMORY) ;
  1720. CL_LOGFAILURE( ERROR_NOT_ENOUGH_MEMORY) ;
  1721. goto ErrorExit ;
  1722. }
  1723. hr = IClusterResource_Open(Resource->pClusterResource, pbResourceName, (OLEHKEY)ResourceKey,
  1724. (OLERESOURCE_HANDLE)Resource, &ResId);
  1725. SysFreeString (pbResourceName) ;
  1726. if (FAILED(hr))
  1727. {
  1728. SetLastError (hr) ;
  1729. CL_LOGFAILURE(hr);
  1730. }
  1731. ErrorExit:
  1732. return (RESID) ResId ;
  1733. }
  1734. }
  1735. VOID
  1736. Resmon_Close (
  1737. IN PRESOURCE Resource
  1738. )
  1739. {
  1740. if (Resource->dwType == RESMON_TYPE_DLL)
  1741. {
  1742. (Resource->pClose) (Resource->Id) ;
  1743. }
  1744. else
  1745. {
  1746. HRESULT hr ;
  1747. hr = IClusterResource_Close (Resource->pClusterResource, (OLERESID)Resource->Id);
  1748. if (FAILED(hr))
  1749. {
  1750. SetLastError (hr) ;
  1751. CL_LOGFAILURE(hr);
  1752. }
  1753. }
  1754. }
  1755. DWORD
  1756. Resmon_Online (
  1757. IN PRESOURCE Resource,
  1758. IN OUT LPHANDLE EventHandle
  1759. )
  1760. {
  1761. if (Resource->dwType == RESMON_TYPE_DLL)
  1762. {
  1763. return (Resource->pOnline) (Resource->Id, EventHandle) ;
  1764. }
  1765. else
  1766. {
  1767. HRESULT hr ;
  1768. long lRet ;
  1769. hr = IClusterResource_Online(Resource->pClusterResource, (OLERESID)Resource->Id, (LPOLEHANDLE)EventHandle, &lRet);
  1770. if (FAILED(hr))
  1771. {
  1772. SetLastError (lRet = hr) ; // Return a error
  1773. CL_LOGFAILURE(hr);
  1774. }
  1775. return lRet ;
  1776. }
  1777. }
  1778. DWORD
  1779. Resmon_Offline (
  1780. IN PRESOURCE Resource
  1781. )
  1782. {
  1783. if (Resource->dwType == RESMON_TYPE_DLL)
  1784. {
  1785. return (Resource->pOffline) (Resource->Id) ;
  1786. }
  1787. else
  1788. {
  1789. HRESULT hr ;
  1790. long lRet ;
  1791. hr = IClusterResource_Offline(Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
  1792. if (FAILED(hr))
  1793. {
  1794. SetLastError (lRet = hr) ; // Return a error
  1795. CL_LOGFAILURE(hr);
  1796. }
  1797. return lRet ;
  1798. }
  1799. }
  1800. VOID
  1801. Resmon_Terminate (
  1802. IN PRESOURCE Resource
  1803. )
  1804. {
  1805. if (Resource->dwType == RESMON_TYPE_DLL)
  1806. {
  1807. (Resource->pTerminate) (Resource->Id) ;
  1808. }
  1809. else
  1810. {
  1811. HRESULT hr ;
  1812. hr = IClusterResource_Terminate (Resource->pClusterResource, (OLERESID)Resource->Id);
  1813. if (FAILED(hr))
  1814. {
  1815. SetLastError (hr) ;
  1816. CL_LOGFAILURE(hr);
  1817. }
  1818. }
  1819. }
  1820. BOOL
  1821. Resmon_LooksAlive (
  1822. IN PRESOURCE Resource
  1823. )
  1824. {
  1825. if (Resource->dwType == RESMON_TYPE_DLL)
  1826. {
  1827. return (Resource->pLooksAlive) (Resource->Id) ;
  1828. }
  1829. else
  1830. {
  1831. HRESULT hr ;
  1832. long lRet ;
  1833. hr = IClusterResource_LooksAlive (Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
  1834. if (FAILED(hr))
  1835. {
  1836. SetLastError (hr) ;
  1837. CL_LOGFAILURE(hr);
  1838. lRet = 0 ; // Incase of failure return 0 to indicate LooksAlive is failed.
  1839. }
  1840. return lRet ;
  1841. }
  1842. }
  1843. BOOL
  1844. Resmon_IsAlive (
  1845. IN PRESOURCE Resource
  1846. )
  1847. {
  1848. if (Resource->dwType == RESMON_TYPE_DLL)
  1849. {
  1850. return (Resource->pIsAlive) (Resource->Id) ;
  1851. }
  1852. else
  1853. {
  1854. HRESULT hr ;
  1855. long lRet ;
  1856. hr = IClusterResource_IsAlive (Resource->pClusterResource, (OLERESID)Resource->Id, &lRet);
  1857. if (FAILED(hr))
  1858. {
  1859. SetLastError (hr) ;
  1860. CL_LOGFAILURE(hr);
  1861. lRet = 0 ; // Incase of failure return 0 to indicate IsAlive is failed.
  1862. }
  1863. return lRet ;
  1864. }
  1865. }
  1866. DWORD
  1867. Resmon_Arbitrate (
  1868. IN PRESOURCE Resource,
  1869. IN PQUORUM_RESOURCE_LOST LostQuorumResource
  1870. )
  1871. {
  1872. if (Resource->dwType == RESMON_TYPE_DLL)
  1873. {
  1874. return (Resource->pArbitrate) (Resource->Id, LostQuorumResource) ;
  1875. }
  1876. else
  1877. {
  1878. HRESULT hr ;
  1879. long lRet ;
  1880. hr = IClusterQuorumResource_QuorumArbitrate(Resource->pClusterQuorumResource, (OLERESID)Resource->Id, (POLEQUORUM_RESOURCE_LOST)LostQuorumResource, &lRet);
  1881. if (FAILED(hr))
  1882. {
  1883. SetLastError (lRet = hr) ;
  1884. CL_LOGFAILURE(hr);
  1885. }
  1886. return lRet ;
  1887. }
  1888. }
  1889. DWORD
  1890. Resmon_Release (
  1891. IN PRESOURCE Resource
  1892. )
  1893. {
  1894. if (Resource->dwType == RESMON_TYPE_DLL)
  1895. {
  1896. return (Resource->pRelease) (Resource->Id) ;
  1897. }
  1898. else
  1899. {
  1900. HRESULT hr ;
  1901. long lRet ;
  1902. hr = IClusterQuorumResource_QuorumRelease(Resource->pClusterQuorumResource, (OLERESID)Resource->Id, &lRet);
  1903. if (FAILED(hr))
  1904. {
  1905. SetLastError (lRet = hr) ;
  1906. CL_LOGFAILURE(hr);
  1907. }
  1908. return lRet ;
  1909. }
  1910. }
  1911. DWORD
  1912. Resmon_ResourceControl (
  1913. IN PRESOURCE Resource,
  1914. IN DWORD ControlCode,
  1915. IN PVOID InBuffer,
  1916. IN DWORD InBufferSize,
  1917. OUT PVOID OutBuffer,
  1918. IN DWORD OutBufferSize,
  1919. OUT LPDWORD BytesReturned
  1920. )
  1921. {
  1922. if (Resource->dwType == RESMON_TYPE_DLL)
  1923. {
  1924. return (Resource->pResourceControl)( Resource->Id,
  1925. ControlCode,
  1926. InBuffer,
  1927. InBufferSize,
  1928. OutBuffer,
  1929. OutBufferSize,
  1930. BytesReturned );
  1931. }
  1932. else
  1933. {
  1934. long status ;
  1935. HRESULT hr ;
  1936. VARIANT vtIn, vtOut ;
  1937. SAFEARRAY sfIn = {1, 0, 1, 0, InBuffer, {InBufferSize, 0} } ;
  1938. SAFEARRAY sfOut = {1, FADF_FIXEDSIZE, 1, 0, OutBuffer, {OutBufferSize, 0} } ;
  1939. SAFEARRAY *psfOut = &sfOut ;
  1940. vtIn.vt = VT_ARRAY | VT_UI1 ;
  1941. vtOut.vt = VT_ARRAY | VT_UI1 | VT_BYREF ;
  1942. vtIn.parray = &sfIn ;
  1943. vtOut.pparray = &psfOut ;
  1944. hr = IClusterResControl_ResourceControl (
  1945. Resource->pClusterResControl,
  1946. (OLERESID)Resource->Id,
  1947. (long)ControlCode,
  1948. &vtIn,
  1949. &vtOut,
  1950. (long *)BytesReturned,
  1951. &status);
  1952. if (FAILED(hr))
  1953. {
  1954. CL_LOGFAILURE(hr); // Use the default processing
  1955. status = ERROR_INVALID_FUNCTION;
  1956. }
  1957. return (DWORD)status ;
  1958. }
  1959. }
  1960. #endif // COMRES