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.

506 lines
15 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // Cleanup.cpp
  7. //
  8. // Abstract:
  9. // Implementation of the functions related to cleaning up a node that has
  10. // been evicted.
  11. //
  12. // Author:
  13. // Vijayendra Vasu (vvasu) 17-AUG-2000
  14. //
  15. // Revision History:
  16. // None.
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #define UNICODE 1
  20. #define _UNICODE 1
  21. /////////////////////////////////////////////////////////////////////////////
  22. // Include files
  23. /////////////////////////////////////////////////////////////////////////////
  24. #include "clusrtlp.h"
  25. #include <objbase.h>
  26. #include <ClusCfgGuids.h>
  27. #include <ClusCfgServer.h>
  28. #include <ClusCfgClient.h>
  29. #include <clusrtl.h>
  30. #include <clusudef.h>
  31. /////////////////////////////////////////////////////////////////////////////
  32. //++
  33. //
  34. // ClRtlCleanupNode()
  35. //
  36. // Routine Description:
  37. // Cleanup a node that has been evicted. This method tries to instantiate
  38. // the cleanup COM component locally (even if a remote node is being cleaned up)
  39. // and will therefore not work if called from computer which do not have this
  40. // component registered.
  41. //
  42. // Arguments:
  43. // const WCHAR * pcszEvictedNodeNameIn
  44. // Name of the node on which cleanup is to be initiated. If this is NULL
  45. // the local node is cleaned up.
  46. //
  47. // DWORD dwDelayIn
  48. // Number of milliseconds that will elapse before cleanup is started
  49. // on the target node. If some other process cleans up the target node while
  50. // delay is in progress, the delay is terminated. If this value is zero,
  51. // the node is cleaned up immediately.
  52. //
  53. // DWORD dwTimeoutIn
  54. // Number of milliseconds that this method will wait for cleanup to complete.
  55. // This timeout is independent of the delay above, so if dwDelayIn is greater
  56. // than dwTimeoutIn, this method will most probably timeout. Once initiated,
  57. // however, cleanup will run to completion - this method just may not wait for it
  58. // to complete.
  59. //
  60. // Return Value:
  61. // S_OK
  62. // If the cleanup operations were successful
  63. //
  64. // RPC_S_CALLPENDING
  65. // If cleanup is not complete in dwTimeoutIn milliseconds
  66. //
  67. // Other HRESULTS
  68. // In case of error
  69. //
  70. //--
  71. /////////////////////////////////////////////////////////////////////////////
  72. HRESULT ClRtlCleanupNode(
  73. const WCHAR * pcszEvictedNodeNameIn
  74. , DWORD dwDelayIn
  75. , DWORD dwTimeoutIn
  76. )
  77. {
  78. HRESULT hr = S_OK;
  79. HRESULT hrInit;
  80. IClusCfgEvictCleanup * pcceEvict = NULL;
  81. ICallFactory * pcfCallFactory = NULL;
  82. ISynchronize * psSync = NULL;
  83. AsyncIClusCfgEvictCleanup * paicceAsyncEvict = NULL;
  84. //
  85. // Initialize COM - make sure it really init'ed or that we're just trying
  86. // to change modes on the calling thread. Attempting to change to mode
  87. // is not reason to fail this function.
  88. //
  89. hrInit = CoInitializeEx( NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
  90. if ( ( hrInit != S_OK ) && ( hrInit != S_FALSE ) && ( hrInit != RPC_E_CHANGED_MODE ) )
  91. {
  92. hr = hrInit;
  93. goto Exit;
  94. } // if:
  95. hr = CoCreateInstance(
  96. CLSID_ClusCfgEvictCleanup
  97. , NULL
  98. , CLSCTX_LOCAL_SERVER
  99. , __uuidof( pcceEvict )
  100. , reinterpret_cast< void ** >( &pcceEvict )
  101. );
  102. if ( FAILED( hr ) )
  103. {
  104. goto Cleanup;
  105. } // if: we could not get a pointer to synchronous evict interface
  106. hr = pcceEvict->QueryInterface( __uuidof( pcfCallFactory ), reinterpret_cast< void ** >( &pcfCallFactory ) );
  107. if ( FAILED( hr ) )
  108. {
  109. goto Cleanup;
  110. } // if: we could not get a pointer to the call factory interface
  111. hr = pcfCallFactory->CreateCall(
  112. __uuidof( paicceAsyncEvict )
  113. , NULL
  114. , __uuidof( paicceAsyncEvict )
  115. , reinterpret_cast< IUnknown ** >( &paicceAsyncEvict )
  116. );
  117. if ( FAILED( hr ) )
  118. {
  119. goto Cleanup;
  120. } // if: we could not get a pointer to the asynchronous evict interface
  121. hr = paicceAsyncEvict->QueryInterface< ISynchronize >( &psSync );
  122. if ( FAILED( hr ) )
  123. {
  124. goto Cleanup;
  125. } // if: we could not get a pointer to the synchronization interface
  126. // Initiate cleanup
  127. if ( pcszEvictedNodeNameIn != NULL )
  128. {
  129. hr = paicceAsyncEvict->Begin_CleanupRemoteNode( pcszEvictedNodeNameIn, dwDelayIn );
  130. } // if: we are cleaning up a remote node
  131. else
  132. {
  133. hr = paicceAsyncEvict->Begin_CleanupLocalNode( dwDelayIn );
  134. } // else: we are cleaning up the local node
  135. if ( FAILED( hr ) )
  136. {
  137. goto Cleanup;
  138. } // if: we could not initiate cleanup
  139. // Wait for specified time.
  140. hr = psSync->Wait( 0, dwTimeoutIn );
  141. if ( FAILED( hr ) || ( hr == RPC_S_CALLPENDING ) )
  142. {
  143. goto Cleanup;
  144. } // if: we could not wait till cleanup completed
  145. // Finish cleanup
  146. if ( pcszEvictedNodeNameIn != NULL )
  147. {
  148. hr = paicceAsyncEvict->Finish_CleanupRemoteNode();
  149. } // if: we are cleaning up a remote node
  150. else
  151. {
  152. hr = paicceAsyncEvict->Finish_CleanupLocalNode();
  153. } // else: we are cleaning up the local node
  154. Cleanup:
  155. //
  156. // Free acquired resources
  157. //
  158. if ( pcceEvict != NULL )
  159. {
  160. pcceEvict->Release();
  161. } // if: we had obtained a pointer to the synchronous evict interface
  162. if ( pcfCallFactory != NULL )
  163. {
  164. pcfCallFactory->Release();
  165. } // if: we had obtained a pointer to the call factory interface
  166. if ( psSync != NULL )
  167. {
  168. psSync->Release();
  169. } // if: we had obtained a pointer to the synchronization interface
  170. if ( paicceAsyncEvict != NULL )
  171. {
  172. paicceAsyncEvict->Release();
  173. } // if: we had obtained a pointer to the asynchronous evict interface
  174. //
  175. // Did the call to CoInitializeEx() above succeed? If it did then
  176. // we need to call CoUnitialize(). Mode changed means we don't need
  177. // to call CoUnitialize().
  178. //
  179. if ( hrInit != RPC_E_CHANGED_MODE )
  180. {
  181. CoUninitialize();
  182. } // if:
  183. Exit:
  184. return hr;
  185. } //*** ClRtlCleanupNode()
  186. /////////////////////////////////////////////////////////////////////////////
  187. //++
  188. //
  189. // ClRtlAsyncCleanupNode()
  190. //
  191. // Routine Description:
  192. // Cleanup a node that has been evicted. This method does not initiate
  193. // any COM component on the machine on which this call is made and therefore,
  194. // does not require the cleanup COM component to be registered on the local
  195. // machine.
  196. //
  197. // Arguments:
  198. // const WCHAR * pcszEvictedNodeNameIn
  199. // Name of the node on which cleanup is to be initiated. If this is NULL
  200. // the local node is cleaned up.
  201. //
  202. // DWORD dwDelayIn
  203. // Number of milliseconds that will elapse before cleanup is started
  204. // on the target node. If some other process cleans up the target node while
  205. // delay is in progress, the delay is terminated. If this value is zero,
  206. // the node is cleaned up immediately.
  207. //
  208. // DWORD dwTimeoutIn
  209. // Number of milliseconds that this method will wait for cleanup to complete.
  210. // This timeout is independent of the delay above, so if dwDelayIn is greater
  211. // than dwTimeoutIn, this method will most probably timeout. Once initiated,
  212. // however, cleanup will run to completion - this method just may not wait for it
  213. // to complete.
  214. //
  215. // Return Value:
  216. // S_OK
  217. // If the cleanup operations were successful
  218. //
  219. // RPC_S_CALLPENDING
  220. // If cleanup is not complete in dwTimeoutIn milliseconds
  221. //
  222. // Other HRESULTS
  223. // In case of error
  224. //
  225. //--
  226. /////////////////////////////////////////////////////////////////////////////
  227. HRESULT ClRtlAsyncCleanupNode(
  228. const WCHAR * pcszEvictedNodeNameIn
  229. , DWORD dwDelayIn
  230. , DWORD dwTimeoutIn
  231. )
  232. {
  233. HRESULT hr = S_OK;
  234. HRESULT hrInit = S_OK;
  235. IDispatch * pDisp = NULL;
  236. //
  237. // Initialize COM - make sure it really init'ed or that we're just trying
  238. // to change modes on the calling thread. Attempting to change to mode
  239. // is not reason to fail this function.
  240. //
  241. hrInit = CoInitializeEx( NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
  242. if ( ( hrInit != S_OK ) && ( hrInit != S_FALSE ) && ( hrInit != RPC_E_CHANGED_MODE ) )
  243. {
  244. hr = hrInit;
  245. goto Exit;
  246. } // if:
  247. MULTI_QI mqiInterfaces[] =
  248. {
  249. { &IID_IDispatch, NULL, S_OK },
  250. };
  251. COSERVERINFO csiServerInfo;
  252. COSERVERINFO * pcsiServerInfoPtr = &csiServerInfo;
  253. if ( pcszEvictedNodeNameIn == NULL )
  254. {
  255. pcsiServerInfoPtr = NULL;
  256. } // if: we have to cleanup the local node
  257. else
  258. {
  259. csiServerInfo.dwReserved1 = 0;
  260. csiServerInfo.pwszName = const_cast< LPWSTR >( pcszEvictedNodeNameIn );
  261. csiServerInfo.pAuthInfo = NULL;
  262. csiServerInfo.dwReserved2 = 0;
  263. } // else: we have to clean up a remote node
  264. //
  265. // Instantiate this component on the evicted node.
  266. //
  267. hr = CoCreateInstanceEx(
  268. CLSID_ClusCfgAsyncEvictCleanup
  269. , NULL
  270. , CLSCTX_LOCAL_SERVER
  271. , pcsiServerInfoPtr
  272. , sizeof( mqiInterfaces ) / sizeof( mqiInterfaces[0] )
  273. , mqiInterfaces
  274. );
  275. if ( FAILED( hr ) )
  276. {
  277. goto Cleanup;
  278. } // if: we could not instantiate the evict processing component
  279. pDisp = reinterpret_cast< IDispatch * >( mqiInterfaces[ 0 ].pItf );
  280. {
  281. OLECHAR * pszMethodName = L"CleanupNode";
  282. DISPID dispidCleanupNode;
  283. VARIANT vResult;
  284. VARIANTARG rgvaCleanupNodeArgs[ 3 ];
  285. DISPPARAMS dpCleanupNodeParams = {
  286. rgvaCleanupNodeArgs
  287. , NULL
  288. , sizeof( rgvaCleanupNodeArgs ) / sizeof( rgvaCleanupNodeArgs[ 0 ] )
  289. , 0
  290. };
  291. // Get the dispatch id of the CleanupNode() method.
  292. hr = pDisp->GetIDsOfNames( IID_NULL, &pszMethodName, 1, LOCALE_SYSTEM_DEFAULT, &dispidCleanupNode );
  293. if ( FAILED( hr ) )
  294. {
  295. goto Cleanup;
  296. } // if: we could not get the dispid of the CleanupNode() method
  297. //
  298. // Initialize the arguments. Note, the parameters are stored in the reverse order in the array.
  299. //
  300. // Initialize the return value.
  301. VariantInit( &vResult );
  302. // The first parameter is the name of the node.
  303. VariantInit( &rgvaCleanupNodeArgs[ 2 ] );
  304. rgvaCleanupNodeArgs[ 2 ].vt = VT_BSTR;
  305. rgvaCleanupNodeArgs[ 2 ].bstrVal = NULL;
  306. // The second parameter is the delay.
  307. VariantInit( &rgvaCleanupNodeArgs[ 1 ] );
  308. rgvaCleanupNodeArgs[ 1 ].vt = VT_UI4;
  309. rgvaCleanupNodeArgs[ 1 ].ulVal = dwDelayIn;
  310. // The third parameter is the timeout.
  311. VariantInit( &rgvaCleanupNodeArgs[ 0 ] );
  312. rgvaCleanupNodeArgs[ 0 ].vt = VT_UI4;
  313. rgvaCleanupNodeArgs[ 0 ].ulVal = dwTimeoutIn;
  314. //
  315. // Invoke the CleanupNode() method.
  316. //
  317. hr = pDisp->Invoke(
  318. dispidCleanupNode
  319. , IID_NULL
  320. , LOCALE_SYSTEM_DEFAULT
  321. , DISPATCH_METHOD
  322. , &dpCleanupNodeParams
  323. , &vResult
  324. , NULL
  325. , NULL
  326. );
  327. if ( FAILED( hr ) )
  328. {
  329. goto Cleanup;
  330. } // if: we could not invoke the CleanupNode() method
  331. hr = vResult.scode;
  332. if ( FAILED( hr ) )
  333. {
  334. goto Cleanup;
  335. } // if: CleanupNode() failed
  336. } // block:
  337. Cleanup:
  338. //
  339. // Free acquired resources
  340. //
  341. if ( pDisp != NULL )
  342. {
  343. pDisp->Release();
  344. } // if: we had obtained a pointer to the IDispatch interface
  345. //
  346. // Did the call to CoInitializeEx() above succeed? If it did then
  347. // we need to call CoUnitialize(). Mode changed means we don't need
  348. // to call CoUnitialize().
  349. //
  350. if ( hrInit != RPC_E_CHANGED_MODE )
  351. {
  352. CoUninitialize();
  353. } // if:
  354. Exit:
  355. return hr;
  356. } //*** ClRtlAsyncCleanupNode()
  357. /////////////////////////////////////////////////////////////////////////////
  358. //++
  359. //
  360. // ClRtlHasNodeBeenEvicted()
  361. //
  362. // Routine Description:
  363. // Finds out if a registry value indicating that this node has been
  364. // evicted, is set or not
  365. //
  366. // Arguments:
  367. // BOOL * pfNodeEvictedOut
  368. // Pointer to the boolean variable that will be set to TRUE if
  369. // the node has been evicted, but not cleaned up and FALSE
  370. // otherwise
  371. //
  372. // Return Value:
  373. // ERROR_SUCCESS
  374. // If the eviction state could be successfully determined.
  375. //
  376. // Other Win32 error codes
  377. // In case of error
  378. //
  379. //--
  380. /////////////////////////////////////////////////////////////////////////////
  381. DWORD ClRtlHasNodeBeenEvicted( BOOL * pfNodeEvictedOut )
  382. {
  383. DWORD dwError = ERROR_SUCCESS;
  384. HKEY hNodeStateKey = NULL;
  385. do
  386. {
  387. DWORD dwEvictState = 0;
  388. DWORD dwType;
  389. DWORD dwSize;
  390. // Validate parameter
  391. if ( pfNodeEvictedOut == NULL )
  392. {
  393. dwError = ERROR_INVALID_PARAMETER;
  394. break;
  395. } // if: the output parameter is invalid
  396. // Initialize output.
  397. *pfNodeEvictedOut = FALSE;
  398. // Open a registry key that holds a value indicating that this node has been evicted.
  399. dwError = RegOpenKeyEx(
  400. HKEY_LOCAL_MACHINE
  401. , CLUSREG_KEYNAME_NODE_DATA
  402. , 0
  403. , KEY_ALL_ACCESS
  404. , &hNodeStateKey
  405. );
  406. if ( dwError != ERROR_SUCCESS )
  407. {
  408. break;
  409. } // if: RegOpenKeyEx() has failed
  410. // Read the required registry value
  411. dwSize = sizeof( dwEvictState );
  412. dwError = RegQueryValueEx(
  413. hNodeStateKey
  414. , CLUSREG_NAME_EVICTION_STATE
  415. , 0
  416. , &dwType
  417. , reinterpret_cast< BYTE * >( &dwEvictState )
  418. , &dwSize
  419. );
  420. if ( dwError == ERROR_FILE_NOT_FOUND )
  421. {
  422. // This is ok - absence of the value indicates that this node has not been evicted.
  423. dwEvictState = 0;
  424. dwError = ERROR_SUCCESS;
  425. } // if: RegQueryValueEx did not find the value
  426. else if ( dwError != ERROR_SUCCESS )
  427. {
  428. break;
  429. } // else if: RegQueryValueEx() has failed
  430. *pfNodeEvictedOut = ( dwEvictState == 0 ) ? FALSE : TRUE;
  431. }
  432. while( false ); // dummy do-while loop to avoid gotos
  433. //
  434. // Free acquired resources
  435. //
  436. if ( hNodeStateKey != NULL )
  437. {
  438. RegCloseKey( hNodeStateKey );
  439. } // if: we had opened the node state registry key
  440. return dwError;
  441. } //*** ClRtlHasNodeBeenEvicted()