Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1258 lines
38 KiB

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