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.

1225 lines
39 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // EvictCleanup.cpp
  7. //
  8. // Description:
  9. // This file contains the implementation of the CEvictCleanup
  10. // class.
  11. //
  12. // Documentation:
  13. // TODO: fill in pointer to external documentation
  14. //
  15. // Header File:
  16. // EvictCleanup.h
  17. //
  18. // Maintained By:
  19. // Galen Barbee (GalenB) 15-JUN-2000
  20. //
  21. //////////////////////////////////////////////////////////////////////////////
  22. //////////////////////////////////////////////////////////////////////////////
  23. // Include Files
  24. //////////////////////////////////////////////////////////////////////////////
  25. // The precompiled header for this library
  26. #include "pch.h"
  27. // For the GetNodeClusterState() API
  28. #include <clusapi.h>
  29. // The header file for this class
  30. #include "EvictCleanup.h"
  31. // For IClusCfgNodeInfo and related interfaces
  32. #include <ClusCfgServer.h>
  33. // For IClusCfgServer and related interfaces
  34. #include <ClusCfgPrivate.h>
  35. // For CClCfgSrvLogger
  36. #include <Logger.h>
  37. // For SUCCESSFUL_CLEANUP_EVENT_NAME
  38. #include "EventName.h"
  39. //////////////////////////////////////////////////////////////////////////////
  40. // Macro Definitions
  41. //////////////////////////////////////////////////////////////////////////////
  42. DEFINE_THISCLASS( "CEvictCleanup" );
  43. //////////////////////////////////////////////////////////////////////////////
  44. //++
  45. //
  46. // CEvictCleanup::CEvictCleanup()
  47. //
  48. // Description:
  49. // Constructor of the CEvictCleanup class. This initializes
  50. // the m_cRef variable to 1 instead of 0 to account of possible
  51. // QueryInterface failure in DllGetClassObject.
  52. //
  53. // Arguments:
  54. // None.
  55. //
  56. // Return Value:
  57. // None.
  58. //
  59. // Remarks:
  60. // None.
  61. //
  62. //--
  63. //////////////////////////////////////////////////////////////////////////////
  64. CEvictCleanup::CEvictCleanup( void )
  65. : m_cRef( 1 )
  66. {
  67. TraceFunc( "" );
  68. // Increment the count of components in memory so the DLL hosting this
  69. // object cannot be unloaded.
  70. InterlockedIncrement( &g_cObjects );
  71. TraceFlow1( "Component count = %d.", g_cObjects );
  72. TraceFuncExit();
  73. } //*** CEvictCleanup::CEvictCleanup
  74. //////////////////////////////////////////////////////////////////////////////
  75. //++
  76. //
  77. // CEvictCleanup::~CEvictCleanup()
  78. //
  79. // Description:
  80. // Destructor of the CEvictCleanup class.
  81. //
  82. // Arguments:
  83. // None.
  84. //
  85. // Return Value:
  86. // None.
  87. //
  88. // Remarks:
  89. // None.
  90. //
  91. //--
  92. //////////////////////////////////////////////////////////////////////////////
  93. CEvictCleanup::~CEvictCleanup( void )
  94. {
  95. TraceFunc( "" );
  96. if ( m_plLogger != NULL )
  97. {
  98. m_plLogger->Release();
  99. }
  100. TraceSysFreeString( m_bstrNodeName );
  101. // There's going to be one less component in memory. Decrement component count.
  102. InterlockedDecrement( &g_cObjects );
  103. TraceFlow1( "Component count = %d.", g_cObjects );
  104. TraceFuncExit();
  105. } //*** CEvictCleanup::~CEvictCleanup
  106. //////////////////////////////////////////////////////////////////////////////
  107. //++
  108. //
  109. // HRESULT
  110. // CEvictCleanup::S_HrCreateInstance(
  111. // IUnknown ** ppunkOut
  112. // )
  113. //
  114. // Description:
  115. // Creates a CEvictCleanup instance.
  116. //
  117. // Arguments:
  118. // ppunkOut
  119. // The IUnknown interface of the new object.
  120. //
  121. // Return Values:
  122. // S_OK
  123. // Success.
  124. //
  125. // E_OUTOFMEMORY
  126. // Not enough memory to create the object.
  127. //
  128. // other HRESULTs
  129. // Object initialization failed.
  130. //
  131. //--
  132. //////////////////////////////////////////////////////////////////////////////
  133. HRESULT
  134. CEvictCleanup::S_HrCreateInstance( IUnknown ** ppunkOut )
  135. {
  136. TraceFunc( "" );
  137. HRESULT hr = E_INVALIDARG;
  138. CEvictCleanup * pEvictCleanup = NULL;
  139. // Allocate memory for the new object.
  140. pEvictCleanup = new CEvictCleanup();
  141. if ( pEvictCleanup == NULL )
  142. {
  143. ::LogMsg( "EvictCleanup: Could not allocate memory for a evict cleanup object." );
  144. TraceFlow( "Could not allocate memory for a evict cleanup object." );
  145. hr = THR( E_OUTOFMEMORY );
  146. goto Cleanup;
  147. } // if: out of memory
  148. // Initialize the new object.
  149. hr = THR( pEvictCleanup->HrInit( ) );
  150. if ( FAILED( hr ) )
  151. {
  152. ::LogMsg( "EvictCleanup: Error %#08x occurred initializing a evict cleanup object.", hr );
  153. TraceFlow1( "Error %#08x occurred initializing a evict cleanup object.", hr );
  154. goto Cleanup;
  155. } // if: the object could not be initialized
  156. hr = THR( pEvictCleanup->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( ppunkOut ) ) );
  157. TraceFlow1( "*ppunkOut = %p.", *ppunkOut );
  158. Cleanup:
  159. if ( pEvictCleanup != NULL )
  160. {
  161. pEvictCleanup->Release();
  162. } // if: the pointer to the resource type object is not NULL
  163. HRETURN( hr );
  164. } //*** CEvictCleanup::S_HrCreateInstance()
  165. //////////////////////////////////////////////////////////////////////////////
  166. //++
  167. //
  168. // STDMETHODIMP_( ULONG )
  169. // CEvictCleanup::AddRef()
  170. //
  171. // Description:
  172. // Increment the reference count of this object by one.
  173. //
  174. // Arguments:
  175. // None.
  176. //
  177. // Return Value:
  178. // The new reference count.
  179. //
  180. // Remarks:
  181. // None.
  182. //
  183. //--
  184. //////////////////////////////////////////////////////////////////////////////
  185. STDMETHODIMP_( ULONG )
  186. CEvictCleanup::AddRef( void )
  187. {
  188. TraceFunc( "[IUnknown]" );
  189. InterlockedIncrement( &m_cRef );
  190. TraceFlow1( "m_cRef = %d", m_cRef );
  191. RETURN( m_cRef );
  192. } //*** CEvictCleanup::AddRef()
  193. //////////////////////////////////////////////////////////////////////////////
  194. //++
  195. //
  196. // STDMETHODIMP_( ULONG )
  197. // CEvictCleanup::Release()
  198. //
  199. // Description:
  200. // Decrement the reference count of this object by one.
  201. //
  202. // Arguments:
  203. // None.
  204. //
  205. // Return Value:
  206. // The new reference count.
  207. //
  208. // Remarks:
  209. // None.
  210. //
  211. //--
  212. //////////////////////////////////////////////////////////////////////////////
  213. STDMETHODIMP_( ULONG )
  214. CEvictCleanup::Release( void )
  215. {
  216. TraceFunc( "[IUnknown]" );
  217. LONG cRef;
  218. InterlockedDecrement( &m_cRef );
  219. cRef = m_cRef;
  220. TraceFlow1( "m_cRef = %d", m_cRef );
  221. if ( m_cRef == 0 )
  222. {
  223. TraceDo( delete this );
  224. } // if: reference count decremented to zero
  225. RETURN( cRef );
  226. } //*** CEvictCleanup::Release()
  227. //////////////////////////////////////////////////////////////////////////////
  228. //++
  229. //
  230. // STDMETHODIMP
  231. // CEvictCleanup::QueryInterface()
  232. //
  233. // Description:
  234. // Decrement the reference count of this object by one.
  235. //
  236. // Arguments:
  237. // IN REFIID riidIn
  238. // Id of interface requested.
  239. //
  240. // OUT void ** ppvOut
  241. // Pointer to the requested interface.
  242. //
  243. // Return Value:
  244. // S_OK
  245. // If the interface is available on this object.
  246. //
  247. // E_NOINTERFACE
  248. // If the interface is not available.
  249. //
  250. // Remarks:
  251. // None.
  252. //
  253. //--
  254. //////////////////////////////////////////////////////////////////////////////
  255. STDMETHODIMP
  256. CEvictCleanup::QueryInterface( REFIID riidIn, void ** ppvOut )
  257. {
  258. TraceQIFunc( riidIn, ppvOut );
  259. HRESULT hr = S_OK;
  260. if ( ppvOut != NULL )
  261. {
  262. if ( IsEqualIID( riidIn, IID_IUnknown ) )
  263. {
  264. *ppvOut = static_cast< IClusCfgEvictCleanup * >( this );
  265. } // if: IUnknown
  266. else if ( IsEqualIID( riidIn, IID_IClusCfgEvictCleanup ) )
  267. {
  268. *ppvOut = TraceInterface( __THISCLASS__, IClusCfgEvictCleanup, this, 0 );
  269. } // else if: IClusCfgEvictCleanup
  270. else if ( IsEqualIID( riidIn, IID_IClusCfgCallback ) )
  271. {
  272. *ppvOut = TraceInterface( __THISCLASS__, IClusCfgCallback, this, 0 );
  273. } // else if: IClusCfgCallback
  274. else
  275. {
  276. hr = E_NOINTERFACE;
  277. } // else
  278. if ( SUCCEEDED( hr ) )
  279. {
  280. ((IUnknown *) *ppvOut)->AddRef( );
  281. } // if: success
  282. else
  283. {
  284. *ppvOut = NULL;
  285. } // else: something failed
  286. } // if: the output pointer was valid
  287. else
  288. {
  289. hr = E_INVALIDARG; // TODO: DavidP 02-OCT-2000 Shouldn't this be E_NOINTERFACE?
  290. } // else: the output pointer is invalid
  291. QIRETURN_IGNORESTDMARSHALLING( hr, riidIn );
  292. } //*** CEvictCleanup::QueryInterface()
  293. //////////////////////////////////////////////////////////////////////////////
  294. //++
  295. //
  296. // CEvictCleanup::HrInit()
  297. //
  298. // Description:
  299. // Second phase of a two phase constructor.
  300. //
  301. // Arguments:
  302. // None.
  303. //
  304. // Return Value:
  305. // S_OK
  306. // If the call succeeded
  307. //
  308. // Other HRESULTs
  309. // If the call failed.
  310. //
  311. //--
  312. //////////////////////////////////////////////////////////////////////////////
  313. HRESULT
  314. CEvictCleanup::HrInit( void )
  315. {
  316. TraceFunc( "" );
  317. HRESULT hr = S_OK;
  318. //
  319. // Save off the local computer name.
  320. //
  321. hr = THR( HrGetComputerName( ComputerNameDnsFullyQualified, &m_bstrNodeName ) );
  322. if ( FAILED( hr ) )
  323. goto Cleanup;
  324. //
  325. // Get a ClCfgSrv ILogger instance.
  326. //
  327. hr = CClCfgSrvLogger::S_HrGetLogger( &m_plLogger );
  328. if ( FAILED( hr ) )
  329. goto Cleanup;
  330. Cleanup:
  331. HRETURN( hr );
  332. } //*** CEvictCleanup::HrInit()
  333. //////////////////////////////////////////////////////////////////////////////
  334. //++
  335. //
  336. // CEvictCleanup::CleanupLocalNode()
  337. //
  338. // Description:
  339. // This method performs the clean up actions on the local node after
  340. // it has been evicted from a cluster, so that the node can go back
  341. // to its "pre-clustered" state.
  342. //
  343. // Arguments:
  344. // DWORD dwDelayIn
  345. // Number of milliseconds that this method will wait before starting
  346. // cleanup. If some other process cleans up this node while this thread
  347. // is waiting, the wait is terminated. If this value is zero, this method
  348. // will attempt to clean up this node immediately.
  349. //
  350. // Return Values:
  351. // S_OK
  352. // Success.
  353. //
  354. // Other HRESULTs
  355. // The call failed.
  356. //
  357. //--
  358. //////////////////////////////////////////////////////////////////////////////
  359. HRESULT
  360. CEvictCleanup::CleanupLocalNode( DWORD dwDelayIn )
  361. {
  362. TraceFunc( "[IClusCfgEvictCleanup]" );
  363. HRESULT hr = S_OK;
  364. IClusCfgServer * pccsClusCfgServer = NULL;
  365. IClusCfgNodeInfo * pccniNodeInfo = NULL;
  366. IClusCfgInitialize * pcciInitialize = NULL;
  367. IClusCfgClusterInfo * pccciClusterInfo = NULL;
  368. IUnknown * punkCallback = NULL;
  369. HANDLE heventCleanupComplete = NULL;
  370. DWORD dwClusterState;
  371. DWORD dwError;
  372. #if 0
  373. bool fWaitForDebugger = true;
  374. while ( fWaitForDebugger )
  375. {
  376. Sleep( 3000 );
  377. } // while: waiting for the debugger to break in
  378. #endif
  379. LogMsg( L"EvictCleanup: Trying to cleanup local node." );
  380. TraceFlow( "Trying to cleanup local node." );
  381. // If the caller has requested a delayed cleanup, wait.
  382. if ( dwDelayIn > 0 )
  383. {
  384. LogMsg( L"EvictCleanup: Delayed cleanup requested. Delaying for %1!d! milliseconds.", dwDelayIn );
  385. TraceFlow1( "Delayed cleanup requested. Delaying for %d milliseconds.", dwDelayIn );
  386. heventCleanupComplete = CreateEvent(
  387. NULL // security attributes
  388. , TRUE // manual reset event
  389. , FALSE // initial state is non-signaled
  390. , SUCCESSFUL_CLEANUP_EVENT_NAME // event name
  391. );
  392. if ( heventCleanupComplete == NULL )
  393. {
  394. dwError = TW32( GetLastError() );
  395. hr = HRESULT_FROM_WIN32( dwError );
  396. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to create the cleanup completion event.", dwError );
  397. TraceFlow1( "Error %#08x occurred trying to create the cleanup completion event.", dwError );
  398. goto Cleanup;
  399. } // if: CreateEvent() failed
  400. // Wait for this event to get signaled or until dwDelayIn milliseconds are up.
  401. do
  402. {
  403. // Wait for any message sent or posted to this queue
  404. // or for our event to be signaled.
  405. dwError = MsgWaitForMultipleObjects(
  406. 1
  407. , &heventCleanupComplete
  408. , FALSE
  409. , dwDelayIn // If no one has signaled this event in dwDelayIn milliseconds, abort.
  410. , QS_ALLINPUT
  411. );
  412. // The result tells us the type of event we have.
  413. if ( dwError == ( WAIT_OBJECT_0 + 1 ) )
  414. {
  415. MSG msg;
  416. // Read all of the messages in this next loop,
  417. // removing each message as we read it.
  418. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 )
  419. {
  420. // If it is a quit message, we are done pumping messages.
  421. if ( msg.message == WM_QUIT)
  422. {
  423. TraceFlow( "Get a WM_QUIT message. Exit message pump loop." );
  424. break;
  425. } // if: we got a WM_QUIT message
  426. // Otherwise, dispatch the message.
  427. DispatchMessage( &msg );
  428. } // while: there are still messages in the window message queue
  429. } // if: we have a message in the window message queue
  430. else
  431. {
  432. if ( dwError == WAIT_OBJECT_0 )
  433. {
  434. TraceFlow( "Some other process has cleaned up this node while we were waiting. Exiting wait loop." );
  435. LogMsg( L"EvictCleanup: Some other process has cleaned up this node while we were waiting. Exiting wait loop." );
  436. } // if: our event is signaled
  437. else if ( dwError == WAIT_TIMEOUT )
  438. {
  439. LogMsg( L"EvictCleanup: The wait of %1!d! milliseconds is over. Proceeding with cleanup.", dwDelayIn );
  440. TraceFlow1( "The wait of %d milliseconds is over. Proceeding with cleanup.", dwDelayIn );
  441. } // else if: we timed out
  442. else if ( dwError == -1 )
  443. {
  444. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  445. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to wait for an event to be signaled.", hr );
  446. TraceFlow1( "Error %#08x occurred trying to wait for the cleanup completion event to be signaled.", hr );
  447. } // else if: MsgWaitForMultipleObjects() returned an error
  448. else
  449. {
  450. hr = THR( HRESULT_FROM_WIN32( dwError ) );
  451. LogMsg( L"EvictCleanup: An error occurred trying to wait for an event to be signaled. Status code is %1!#08x!.", dwError );
  452. TraceFlow1( "An error occurred trying to wait for the cleanup completion event to be signaled. Status code is %#08x.", dwError );
  453. } // else: an unexpected value was returned by MsgWaitForMultipleObjects()
  454. break;
  455. } // else: MsgWaitForMultipleObjects() exited for a reason other than a waiting message
  456. }
  457. while( true ); // do-while: loop infinitely
  458. if ( FAILED( hr ) )
  459. {
  460. goto Cleanup;
  461. } // if: something went wrong while waiting
  462. TraceFlow1( "Delay of %d milliseconds completed.", dwDelayIn );
  463. } // if: the caller has requested delayed cleanup
  464. TraceFlow( "Check node cluster state." );
  465. // Check the node cluster state
  466. dwError = TW32( GetNodeClusterState( NULL, &dwClusterState ) );
  467. if ( dwError != ERROR_SUCCESS )
  468. {
  469. hr = HRESULT_FROM_WIN32( dwError );
  470. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to get the state of the cluster service on this node.", hr );
  471. TraceFlow1( "Error %#08x occurred trying to get the state of the cluster service on this node.", hr );
  472. goto Cleanup;
  473. } // if: we could not get the node cluster state
  474. if ( ( dwClusterState != ClusterStateNotRunning ) && ( dwClusterState != ClusterStateRunning ) )
  475. {
  476. LogMsg( L"EvictCleanup: This node is not part of a cluster - no cleanup is necessary." );
  477. TraceFlow( "This node is not part of a cluster - no cleanup is necessary." );
  478. goto Cleanup;
  479. } // if: this node is not part of a cluster
  480. TraceFlow( "Stopping the cluster service." );
  481. //
  482. // NOTE: GetNodeClusterState() returns ClusterStateNotRunning if the cluster service is not in the
  483. // SERVICE_RUNNING state. However, this does not mean that the service is not running, since it could
  484. // be in the SERVICE_PAUSED, SERVICE_START_PENDING, etc. states.
  485. //
  486. // So, try and stop the service anyway. Query for the service state 300 times, once every 1000 ms.
  487. //
  488. dwError = TW32( DwStopService( L"ClusSvc", 1000, 300 ) );
  489. hr = HRESULT_FROM_WIN32( dwError );
  490. if ( FAILED( hr ) )
  491. {
  492. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to stop the cluster service. Aborting cleanup.", dwError );
  493. TraceFlow1( "Error %#08x occurred trying to stop the cluster service. Aborting cleanup.", dwError );
  494. goto Cleanup;
  495. } // if: we could not stop the cluster service in the specified time
  496. //
  497. // If we are here, the cluster service is not running any more.
  498. // Create the ClusCfgServer component
  499. //
  500. hr = THR(
  501. CoCreateInstance(
  502. CLSID_ClusCfgServer
  503. , NULL
  504. , CLSCTX_INPROC_SERVER
  505. , __uuidof( pcciInitialize )
  506. , reinterpret_cast< void ** >( &pcciInitialize )
  507. )
  508. );
  509. if ( FAILED( hr ) )
  510. {
  511. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to create the cluster configuration server.", hr );
  512. TraceFlow1( "Error %#08x occurred trying to create the cluster configuration server.", hr );
  513. goto Cleanup;
  514. } // if: we could not create the ClusCfgServer component
  515. hr = THR( TypeSafeQI( IUnknown, &punkCallback ) );
  516. if ( FAILED( hr ) )
  517. {
  518. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to get an IUnknown interface pointer to the IClusCfgCallback interface.", hr );
  519. TraceFlow1( "Error %#08x occurred trying to get an IUnknown interface pointer to the IClusCfgCallback interface.", hr );
  520. goto Cleanup;
  521. } // if:
  522. hr = THR( pcciInitialize->Initialize( punkCallback, LOCALE_SYSTEM_DEFAULT ) );
  523. if ( FAILED( hr ) )
  524. {
  525. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to initialize the cluster configuration server.", hr );
  526. TraceFlow1( "Error %#08x occurred trying to initialize the cluster configuration server.", hr );
  527. goto Cleanup;
  528. } // if: IClusCfgInitialize::Initialize() failed
  529. hr = THR( pcciInitialize->QueryInterface< IClusCfgServer >( &pccsClusCfgServer ) );
  530. if ( FAILED( hr ) )
  531. {
  532. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to get a pointer to the cluster configuration server.", hr );
  533. TraceFlow1( "Error %#08x occurred trying to get a pointer to the cluster configuration server interface.", hr );
  534. goto Cleanup;
  535. } // if: we could not get a pointer to the IClusCfgServer interface
  536. hr = THR( pccsClusCfgServer->GetClusterNodeInfo( &pccniNodeInfo ) );
  537. if ( FAILED( hr ) )
  538. {
  539. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to get the node information.", hr );
  540. TraceFlow1( "Error %#08x occurred trying to get a pointer to the IClusCfgNodeInfo interface.", hr );
  541. goto Cleanup;
  542. } // if: we could not get a pointer to the IClusCfgNodeInfo interface
  543. hr = THR( pccniNodeInfo->GetClusterConfigInfo( &pccciClusterInfo ) );
  544. if ( FAILED( hr ) )
  545. {
  546. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to get the cluster information.", hr );
  547. TraceFlow1( "Error %#08x occurred trying to get a pointer to the IClusCfgClusterInfo interface.", hr );
  548. goto Cleanup;
  549. } // if: we could not get a pointer to the IClusCfgClusterInfo interface
  550. hr = THR( pccciClusterInfo->SetCommitMode( cmCLEANUP_NODE_AFTER_EVICT ) );
  551. if ( FAILED( hr ) )
  552. {
  553. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to set the cluster commit mode.", hr );
  554. TraceFlow1( "Error %#08x occurred trying to call IClusCfgClusterInfo::SetCommitMode() interface.", hr );
  555. goto Cleanup;
  556. } // if: IClusCfgClusterInfo::SetEvictMode() failed
  557. TraceFlow( "Starting cleanup of this node." );
  558. // Do the cleanup
  559. hr = THR( pccsClusCfgServer->CommitChanges() );
  560. if ( FAILED( hr ) )
  561. {
  562. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to clean up after evict.", hr );
  563. TraceFlow1( "Error %#08x occurred trying to clean up after evict.", hr );
  564. goto Cleanup;
  565. } // if: an error occurred trying to clean up after evict
  566. LogMsg( L"EvictCleanup: Local node cleaned up successfully." );
  567. TraceFlow( "Local node cleaned up successfully." );
  568. Cleanup:
  569. //
  570. // Clean up
  571. //
  572. if ( punkCallback != NULL )
  573. {
  574. punkCallback->Release();
  575. } // if: we had queried for an IUnknown pointer on our IClusCfgCallback interface
  576. if ( pccsClusCfgServer != NULL )
  577. {
  578. pccsClusCfgServer->Release();
  579. } // if: we had created the ClusCfgServer component
  580. if ( pccniNodeInfo != NULL )
  581. {
  582. pccniNodeInfo->Release();
  583. } // if: we had acquired a pointer to the node info interface
  584. if ( pcciInitialize != NULL )
  585. {
  586. pcciInitialize->Release();
  587. } // if: we had acquired a pointer to the initialization interface
  588. if ( pccciClusterInfo != NULL )
  589. {
  590. pccciClusterInfo->Release();
  591. } // if: we had acquired a pointer to the cluster info interface
  592. if ( heventCleanupComplete == NULL )
  593. {
  594. CloseHandle( heventCleanupComplete );
  595. } // if: we had created the cleanup complete event
  596. HRETURN( hr );
  597. } //*** CEvictCleanup::CleanupLocalNode()
  598. //////////////////////////////////////////////////////////////////////////////
  599. //++
  600. //
  601. // CEvictCleanup::CleanupRemoteNode()
  602. //
  603. // Description:
  604. // This method performs the clean up actions on a remote node after
  605. // it has been evicted from a cluster, so that the node can go back
  606. // to its "pre-clustered" state.
  607. //
  608. // Arguments:
  609. // const WCHAR * pcszEvictedNodeNameIn
  610. // Name of the node that has just been evicted. This can be the
  611. // NetBios name of the node, the fully qualified domain name or
  612. // the node IP address. If NULL, the local machine is cleaned up.
  613. //
  614. // DWORD dwDelayIn
  615. // Number of milliseconds that this method will wait before starting
  616. // cleanup. If some other process cleans up this node while this thread
  617. // is waiting, the wait is terminated. If this value is zero, this method
  618. // will attempt to clean up this node immediately.
  619. //
  620. // Return Values:
  621. // S_OK
  622. // Success.
  623. //
  624. // Other HRESULTs
  625. // The call failed.
  626. //
  627. //--
  628. //////////////////////////////////////////////////////////////////////////////
  629. HRESULT
  630. CEvictCleanup::CleanupRemoteNode( const WCHAR * pcszEvictedNodeNameIn, DWORD dwDelayIn )
  631. {
  632. TraceFunc( "[IClusCfgEvictCleanup]" );
  633. HRESULT hr = S_OK;
  634. IClusCfgEvictCleanup * pcceEvict = NULL;
  635. MULTI_QI mqiInterfaces[] =
  636. {
  637. { &IID_IClusCfgEvictCleanup, NULL, S_OK },
  638. };
  639. COSERVERINFO csiServerInfo;
  640. COSERVERINFO * pcsiServerInfoPtr = &csiServerInfo;
  641. if ( pcszEvictedNodeNameIn == NULL )
  642. {
  643. LogMsg( L"EvictCleanup: The local node will be cleaned up." );
  644. TraceFlow( "The local node will be cleaned up." );
  645. pcsiServerInfoPtr = NULL;
  646. } // if: we have to cleanup the local node
  647. else
  648. {
  649. LogMsg( L"EvictCleanup: The remote node to be cleaned up is '%1!ws!'.", pcszEvictedNodeNameIn );
  650. TraceFlow1( "The remote node to be cleaned up is '%ws'.", pcszEvictedNodeNameIn );
  651. csiServerInfo.dwReserved1 = 0;
  652. csiServerInfo.pwszName = const_cast< LPWSTR >( pcszEvictedNodeNameIn );
  653. csiServerInfo.pAuthInfo = NULL;
  654. csiServerInfo.dwReserved2 = 0;
  655. } // else: we have to clean up a remote node
  656. // Instantiate this component remotely
  657. hr = THR(
  658. CoCreateInstanceEx(
  659. CLSID_ClusCfgEvictCleanup
  660. , NULL
  661. , CLSCTX_LOCAL_SERVER
  662. , pcsiServerInfoPtr
  663. , sizeof( mqiInterfaces ) / sizeof( mqiInterfaces[0] )
  664. , mqiInterfaces
  665. )
  666. );
  667. if ( FAILED( hr ) )
  668. {
  669. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to instantiate the evict processing component. For example, the evicted node may be down right now or not accessible.", hr );
  670. TraceFlow1( "Error %#08x occurred trying to instantiate the evict processing component.", hr );
  671. goto Cleanup;
  672. } // if: we could not instantiate the evict processing component
  673. // Make the evict call.
  674. pcceEvict = reinterpret_cast< IClusCfgEvictCleanup * >( mqiInterfaces[0].pItf );
  675. hr = THR( pcceEvict->CleanupLocalNode( dwDelayIn ) );
  676. if ( FAILED( hr ) )
  677. {
  678. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to initiate evict processing.", hr );
  679. TraceFlow1( "Error %#08x occurred trying to initiate evict processing.", hr );
  680. goto Cleanup;
  681. } // if: we could not initiate evict processing
  682. Cleanup:
  683. //
  684. // Clean up
  685. //
  686. if ( pcceEvict != NULL )
  687. {
  688. pcceEvict->Release();
  689. } // if: we had got a pointer to the IClusCfgEvictCleanup interface
  690. HRETURN( hr );
  691. } //*** CEvictCleanup::CleanupRemoteNode()
  692. //////////////////////////////////////////////////////////////////////////////
  693. //++
  694. //
  695. // void
  696. // CEvictCleanup::DwStopService()
  697. //
  698. // Description:
  699. // Instructs the SCM to stop a service. This function tests
  700. // cQueryCountIn times to see if the service has stopped, checking
  701. // every ulQueryIntervalMilliSecIn milliseconds.
  702. //
  703. // Arguments:
  704. // pcszServiceNameIn
  705. // Name of the service to stop
  706. //
  707. // ulQueryIntervalMilliSecIn
  708. // Number of milliseconds between checking to see if the service
  709. // has stopped. The default value is 500 milliseconds.
  710. //
  711. // cQueryCountIn
  712. // The number of times this function will query the service (not
  713. // including an initial query) to see if it has stopped. The default
  714. // value is 10 times.
  715. //
  716. // Return Value:
  717. // ERROR_SUCCESS
  718. // Success.
  719. //
  720. // Other Win32 error codes
  721. // The call failed.
  722. //--
  723. //////////////////////////////////////////////////////////////////////////////
  724. DWORD
  725. CEvictCleanup::DwStopService(
  726. const WCHAR * pcszServiceNameIn
  727. , ULONG ulQueryIntervalMilliSecIn
  728. , ULONG cQueryCountIn
  729. )
  730. {
  731. TraceFunc( "" );
  732. DWORD dwError = ERROR_SUCCESS;
  733. SC_HANDLE schSCMHandle = NULL;
  734. SC_HANDLE schServiceHandle = NULL;
  735. SERVICE_STATUS ssStatus;
  736. bool fStopped = false;
  737. UINT cNumberOfQueries = 0;
  738. LogMsg( L"EvictCleanup: Attempting to stop the '%1!ws!' service.", pcszServiceNameIn );
  739. TraceFlow1( "Attempting to stop the '%ws' service.", pcszServiceNameIn );
  740. // Open a handle to the service control manager.
  741. schSCMHandle = OpenSCManager( NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS );
  742. if ( schSCMHandle == NULL )
  743. {
  744. dwError = TW32( GetLastError() );
  745. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to open a handle to the service control manager.", dwError );
  746. TraceFlow1( "Error %#08x occurred trying to open a handle to the service control manager.", dwError );
  747. goto Cleanup;
  748. } // if: we could not open a handle to the service control mananger
  749. // Open a handle to the service.
  750. schServiceHandle = OpenService(
  751. schSCMHandle
  752. , pcszServiceNameIn
  753. , SERVICE_STOP | SERVICE_QUERY_STATUS
  754. );
  755. // Check if we could open a handle to the service.
  756. if ( schServiceHandle == NULL )
  757. {
  758. // We could not get a handle to the service.
  759. dwError = GetLastError();
  760. // Check if the service exists.
  761. if ( dwError == ERROR_SERVICE_DOES_NOT_EXIST )
  762. {
  763. // Nothing needs to be done here.
  764. LogMsg( L"EvictCleanup: The '%1!ws!' service does not exist, so it is not running. Nothing needs to be done to stop it.", pcszServiceNameIn );
  765. TraceFlow1( "The '%ws' service does not exist, so it is not running. Nothing needs to be done to stop it.", pcszServiceNameIn );
  766. dwError = ERROR_SUCCESS;
  767. } // if: the service does not exist
  768. else
  769. {
  770. // Something else has gone wrong.
  771. TW32( dwError );
  772. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to open the '%2!ws!' service.", dwError, pcszServiceNameIn );
  773. TraceFlow2( "Error %#08x occurred trying to open the '%ws' service.", dwError, pcszServiceNameIn );
  774. } // else: the service exists
  775. goto Cleanup;
  776. } // if: the handle to the service could not be opened.
  777. TraceFlow( "Querying the service for its initial state." );
  778. // Query the service for its initial state.
  779. ZeroMemory( &ssStatus, sizeof( ssStatus ) );
  780. if ( QueryServiceStatus( schServiceHandle, &ssStatus ) == 0 )
  781. {
  782. dwError = TW32( GetLastError() );
  783. LogMsg( L"EvictCleanup: Error %1!#08x! occurred while trying to query the initial state of the '%2!ws!' service.", dwError, pcszServiceNameIn );
  784. TraceFlow2( "Error %#08x occurred while trying to query the initial state of the '%ws' service.", dwError, pcszServiceNameIn );
  785. goto Cleanup;
  786. } // if: we could not query the service for its status.
  787. // If the service has stopped, we have nothing more to do.
  788. if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
  789. {
  790. // Nothing needs to be done here.
  791. LogMsg( L"EvictCleanup: The '%1!ws!' service is not running. Nothing needs to be done to stop it.", pcszServiceNameIn );
  792. TraceFlow1( "The '%ws' service is not running. Nothing needs to be done to stop it.", pcszServiceNameIn );
  793. goto Cleanup;
  794. } // if: the service has stopped.
  795. // If we are here, the service is running.
  796. TraceFlow( "The service is running." );
  797. //
  798. // Try and stop the service.
  799. //
  800. // If the service is stopping on its own, no need to send the stop control code.
  801. if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
  802. {
  803. TraceFlow( "The service is stopping on its own. The stop control code will not be sent." );
  804. } // if: the service is stopping already
  805. else
  806. {
  807. TraceFlow( "The stop control code will be sent after 30 seconds." );
  808. ZeroMemory( &ssStatus, sizeof( ssStatus ) );
  809. if ( ControlService( schServiceHandle, SERVICE_CONTROL_STOP, &ssStatus ) == 0 )
  810. {
  811. dwError = GetLastError();
  812. if ( dwError == ERROR_SERVICE_NOT_ACTIVE )
  813. {
  814. LogMsg( L"EvictCleanup: The '%1!ws!' service is not running. Nothing more needs to be done here.", pcszServiceNameIn );
  815. TraceFlow1( "The '%ws' service is not running. Nothing more needs to be done here.", pcszServiceNameIn );
  816. // The service is not running. Change the error code to success.
  817. dwError = ERROR_SUCCESS;
  818. } // if: the service is already running.
  819. else
  820. {
  821. TW32( dwError );
  822. LogMsg( L"EvictCleanup: Error %1!#08x! occurred trying to stop the '%2!ws!' service.", dwError, pcszServiceNameIn );
  823. TraceFlow2( "Error %#08x occurred trying to stop the '%ws' service.", dwError, pcszServiceNameIn );
  824. }
  825. // There is nothing else to do.
  826. goto Cleanup;
  827. } // if: an error occurred trying to stop the service.
  828. } // else: the service has to be instructed to stop
  829. // Query the service for its state now and wait till the timeout expires
  830. cNumberOfQueries = 0;
  831. do
  832. {
  833. // Query the service for its status.
  834. ZeroMemory( &ssStatus, sizeof( ssStatus ) );
  835. if ( QueryServiceStatus( schServiceHandle, &ssStatus ) == 0 )
  836. {
  837. dwError = TW32( GetLastError() );
  838. LogMsg( L"EvictCleanup: Error %1!#08x! occurred while trying to query the state of the '%2!ws!' service.", dwError, pcszServiceNameIn );
  839. TraceFlow2( "Error %#08x occurred while trying to query the state of the '%ws' service.", dwError, pcszServiceNameIn );
  840. break;
  841. } // if: we could not query the service for its status.
  842. // If the service has stopped, we have nothing more to do.
  843. if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
  844. {
  845. // Nothing needs to be done here.
  846. TraceFlow( "The service has been stopped." );
  847. fStopped = true;
  848. dwError = ERROR_SUCCESS;
  849. break;
  850. } // if: the service has stopped.
  851. // Check if the timeout has expired
  852. if ( cNumberOfQueries >= cQueryCountIn )
  853. {
  854. TraceFlow( "The service stop wait timeout has expired." );
  855. break;
  856. } // if: number of queries has exceeded the maximum specified
  857. TraceFlow2(
  858. "Waiting for %d milliseconds before querying service status again. %d such queries remaining."
  859. , ulQueryIntervalMilliSecIn
  860. , cQueryCountIn - cNumberOfQueries
  861. );
  862. ++cNumberOfQueries;
  863. // Wait for the specified time.
  864. Sleep( ulQueryIntervalMilliSecIn );
  865. }
  866. while ( true ); // while: loop infinitely
  867. if ( dwError != ERROR_SUCCESS )
  868. {
  869. goto Cleanup;
  870. } // if: something went wrong.
  871. if ( ! fStopped )
  872. {
  873. dwError = TW32( ERROR_SERVICE_REQUEST_TIMEOUT );
  874. LogMsg( L"EvictCleanup: The '%1!ws!' service has not stopped even after %2!d! queries.", pcszServiceNameIn, cQueryCountIn );
  875. TraceFlow2( "The '%ws' service has not stopped even after %d queries.", pcszServiceNameIn, cQueryCountIn );
  876. goto Cleanup;
  877. } // if: the maximum number of queries have been made and the service is not running.
  878. LogMsg( L"EvictCleanup: The '%1!ws!' service was successfully stopped.", pcszServiceNameIn );
  879. TraceFlow1( "The '%ws' service was successfully stopped.", pcszServiceNameIn );
  880. Cleanup:
  881. if ( dwError != ERROR_SUCCESS )
  882. {
  883. LogMsg( L"EvictCleanup: Error %1!#08x! has occurred trying to stop the '%2!ws!' service.", dwError, pcszServiceNameIn );
  884. TraceFlow2( "Error %#08x has occurred trying to stop the '%ws' service.", dwError, pcszServiceNameIn );
  885. } // if: something has gone wrong
  886. //
  887. // Cleanup
  888. //
  889. if ( schSCMHandle != NULL )
  890. {
  891. CloseServiceHandle( schSCMHandle );
  892. } // if: we had opened a handle to the service control manager
  893. if ( schServiceHandle != NULL )
  894. {
  895. CloseServiceHandle( schServiceHandle );
  896. } // if: we had opened a handle to the service being stopped
  897. RETURN( dwError );
  898. } //*** CEvictCleanup::DwStopService()
  899. //****************************************************************************
  900. //
  901. // IClusCfgCallback
  902. //
  903. //****************************************************************************
  904. //////////////////////////////////////////////////////////////////////////////
  905. //++
  906. //
  907. // CEvictCleanup::SendStatusReport(
  908. // LPCWSTR pcszNodeNameIn
  909. // , CLSID clsidTaskMajorIn
  910. // , CLSID clsidTaskMinorIn
  911. // , ULONG ulMinIn
  912. // , ULONG ulMaxIn
  913. // , ULONG ulCurrentIn
  914. // , HRESULT hrStatusIn
  915. // , LPCWSTR pcszDescriptionIn
  916. // , FILETIME * pftTimeIn
  917. // , LPCWSTR pcszReferenceIn
  918. // )
  919. //
  920. // Description:
  921. //
  922. // Arguments:
  923. //
  924. // Return Value:
  925. //
  926. // Remarks:
  927. // None.
  928. //
  929. //--
  930. //////////////////////////////////////////////////////////////////////////////
  931. STDMETHODIMP
  932. CEvictCleanup::SendStatusReport(
  933. LPCWSTR pcszNodeNameIn
  934. , CLSID clsidTaskMajorIn
  935. , CLSID clsidTaskMinorIn
  936. , ULONG ulMinIn
  937. , ULONG ulMaxIn
  938. , ULONG ulCurrentIn
  939. , HRESULT hrStatusIn
  940. , LPCWSTR pcszDescriptionIn
  941. , FILETIME * pftTimeIn
  942. , LPCWSTR pcszReferenceIn
  943. )
  944. {
  945. TraceFunc1( "[IClusCfgCallback] pcszDescriptionIn = '%s'", pcszDescriptionIn == NULL ? TEXT("<null>") : pcszDescriptionIn );
  946. HRESULT hr = S_OK;
  947. if ( pcszNodeNameIn == NULL )
  948. {
  949. pcszNodeNameIn = m_bstrNodeName;
  950. } // if:
  951. TraceMsg( mtfFUNC, L"pcszNodeNameIn = %s", pcszNodeNameIn );
  952. TraceMsgGUID( mtfFUNC, "clsidTaskMajorIn ", clsidTaskMajorIn );
  953. TraceMsgGUID( mtfFUNC, "clsidTaskMinorIn ", clsidTaskMinorIn );
  954. TraceMsg( mtfFUNC, L"ulMinIn = %u", ulMinIn );
  955. TraceMsg( mtfFUNC, L"ulMaxIn = %u", ulMaxIn );
  956. TraceMsg( mtfFUNC, L"ulCurrentIn = %u", ulCurrentIn );
  957. TraceMsg( mtfFUNC, L"hrStatusIn = %#x", hrStatusIn );
  958. TraceMsg( mtfFUNC, L"pcszDescriptionIn = '%ws'", ( pcszDescriptionIn ? pcszDescriptionIn : L"<null>" ) );
  959. //
  960. // TODO: 21 NOV 2000 GalenB
  961. //
  962. // How do we log pftTimeIn?
  963. //
  964. TraceMsg( mtfFUNC, L"pcszReferenceIn = '%ws'", ( pcszReferenceIn ? pcszReferenceIn : L"<null>" ) );
  965. hr = THR( CClCfgSrvLogger::S_HrLogStatusReport(
  966. m_plLogger
  967. , pcszNodeNameIn
  968. , clsidTaskMajorIn
  969. , clsidTaskMinorIn
  970. , ulMinIn
  971. , ulMaxIn
  972. , ulCurrentIn
  973. , hrStatusIn
  974. , pcszDescriptionIn
  975. , pftTimeIn
  976. , pcszReferenceIn
  977. ) );
  978. HRETURN( hr );
  979. } //*** CEvictCleanup::SendStatusReport()
  980. //////////////////////////////////////////////////////////////////////////////
  981. //++
  982. //
  983. // void
  984. // CEvictCleanup::LogMsg(
  985. // LPCWSTR pszLogMsgIn
  986. // , ...
  987. // )
  988. //
  989. // Description:
  990. // Wraps call to LogMsg on the logger object.
  991. //
  992. // Arguments:
  993. // pszLogMsgIn - Format string.
  994. // ... - Arguments.
  995. //
  996. // Return Values:
  997. // None.
  998. //
  999. //--
  1000. //////////////////////////////////////////////////////////////////////////////
  1001. void
  1002. CEvictCleanup::LogMsg(
  1003. LPCWSTR pszLogMsgIn
  1004. , ...
  1005. )
  1006. {
  1007. TraceFunc( "" );
  1008. Assert( pszLogMsgIn != NULL );
  1009. Assert( m_plLogger != NULL );
  1010. HRESULT hr = S_OK;
  1011. BSTR bstrLogMsg = NULL;
  1012. LPWSTR pszLogMsg = NULL;
  1013. DWORD cch;
  1014. va_list valist;
  1015. va_start( valist, pszLogMsgIn );
  1016. cch = FormatMessage(
  1017. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1018. | FORMAT_MESSAGE_FROM_STRING
  1019. , pszLogMsgIn
  1020. , 0
  1021. , 0
  1022. , (LPWSTR) &pszLogMsg
  1023. , 0
  1024. , &valist
  1025. );
  1026. va_end( valist );
  1027. if ( cch == 0 )
  1028. goto Win32Error;
  1029. bstrLogMsg = TraceSysAllocStringLen( pszLogMsg, cch );
  1030. if ( bstrLogMsg == NULL )
  1031. goto OutOfMemory;
  1032. m_plLogger->LogMsg( bstrLogMsg );
  1033. Cleanup:
  1034. LocalFree( pszLogMsg );
  1035. TraceSysFreeString( bstrLogMsg );
  1036. TraceFuncExit();
  1037. Win32Error:
  1038. hr = HRESULT_FROM_WIN32( TW32( GetLastError( ) ) );
  1039. goto Cleanup;
  1040. OutOfMemory:
  1041. hr = E_OUTOFMEMORY;
  1042. goto Cleanup;
  1043. } //*** CEvictCleanup::LogMsg()