////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000-2001 Microsoft Corporation // // Module Name: // CClusCfgServer.cpp // // Description: // This file contains the definition of the CClusCfgServer class. // // The class CClusCfgServer is the implementations of the // IClusCfgServer interface. // // Documentation: // // Header File: // CClusCfgServer.h // // Maintained By: // Galen Barbee (GalenB) 03-FEB-2000 // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Include Files ////////////////////////////////////////////////////////////////////////////// #include "pch.h" #include "CClusCfgServer.h" #include "PrivateInterfaces.h" #include "CClusCfgNodeInfo.h" #include "CEnumClusCfgManagedResources.h" #include "CClusCfgCallback.h" #include "EventName.h" #include #include #include #include ////////////////////////////////////////////////////////////////////////////// // Constant Definitions ////////////////////////////////////////////////////////////////////////////// DEFINE_THISCLASS( "CClusCfgServer" ); #define CLEANUP_LOCK_NAME L"Global\\Microsoft Cluster Configuration Cleanup Lock" //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer class ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::S_HrCreateInstance // // Description: // Create a CClusCfgServer instance. // // Arguments: // ppunkOut - // // Return Values: // Pointer to CClusCfgServer instance. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::S_HrCreateInstance( IUnknown ** ppunkOut ) { TraceFunc( "" ); HRESULT hr; CClusCfgServer * pccs = NULL; if ( ppunkOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if: // // KB: Since this is usually the start of the "server" thread, // we will cause it to read its thread settings here. // TraceInitializeThread( L"ServerThread" ); pccs = new CClusCfgServer(); if ( pccs == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if: error allocating object hr = THR( pccs->HrInit() ); if ( FAILED( hr ) ) { goto Cleanup; } // if: HrInit() failed hr = THR( pccs->TypeSafeQI( IUnknown, ppunkOut ) ); Cleanup: if ( FAILED( hr ) ) { LogMsg( L"[SRV] CClusCfgServer::S_HrCreateInstance() failed. (hr = %#08x)", hr ); } // if: if ( pccs != NULL ) { pccs->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::S_HrCreateInstance ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::CClusCfgServer // // Description: // Constructor of the CClusCfgServer class. This initializes // the m_cRef variable to 1 instead of 0 to account of possible // QueryInterface failure in DllGetClassObject. // // Arguments: // None. // // Return Value: // None. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// CClusCfgServer::CClusCfgServer( void ) : m_cRef( 1 ) , m_pIWbemServices( NULL ) , m_lcid( LOCALE_NEUTRAL ) , m_fCanBeClustered( TRUE ) { TraceFunc( "" ); // Increment the count of components in memory so the DLL hosting this // object cannot be unloaded. InterlockedIncrement( &g_cObjects ); Assert( m_picccCallback == NULL ); Assert( m_punkNodeInfo == NULL ); Assert( m_punkEnumResources == NULL ); Assert( m_punkNetworksEnum == NULL ); Assert( m_bstrNodeName == NULL ); Assert( !m_fUsePolling ); Assert( m_bstrBindingString == NULL ); TraceFuncExit(); } //*** CClusCfgServer::CClusCfgServer ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::~CClusCfgServer // // Description: // Destructor of the CClusCfgServer class. // // Arguments: // None. // // Return Value: // None. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// CClusCfgServer::~CClusCfgServer( void ) { TraceFunc( "" ); TraceSysFreeString( m_bstrNodeName ); TraceSysFreeString( m_bstrBindingString ); if ( m_pIWbemServices != NULL ) { m_pIWbemServices->Release(); } // if: if ( m_punkNodeInfo != NULL ) { m_punkNodeInfo->Release(); } // if: if ( m_punkEnumResources != NULL ) { m_punkEnumResources->Release(); } // if: if ( m_punkNetworksEnum != NULL ) { m_punkNetworksEnum->Release(); } // if: if ( m_picccCallback != NULL ) { m_picccCallback->Release(); } // if: // There's going to be one less component in memory. Decrement component count. InterlockedDecrement( &g_cObjects ); TraceFuncExit(); } //*** CClusCfgServer::~CClusCfgServer //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer -- IUknkown interface. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP_( ULONG ) // CClusCfgServer:: [IUNKNOWN] AddRef // // Description: // Increment the reference count of this object by one. // // Arguments: // None. // // Return Value: // The new reference count. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_( ULONG ) CClusCfgServer::AddRef( void ) { TraceFunc( "[IUnknown]" ); InterlockedIncrement( & m_cRef ); RETURN( m_cRef ); } //*** CClusCfgServer::AddRef ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP_( ULONG ) // CClusCfgServer:: [IUNKNOWN] Release // // Description: // Decrement the reference count of this object by one. // // Arguments: // None. // // Return Value: // The new reference count. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_( ULONG ) CClusCfgServer::Release( void ) { TraceFunc( "[IUnknown]" ); LONG cRef; cRef = InterlockedDecrement( &m_cRef ); if ( cRef == 0 ) { TraceDo( delete this ); } // if: reference count equal to zero RETURN( cRef ); } //*** CClusCfgServer::Release ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer:: [INKNOWN] QueryInterface // // Description: // Query this object for the passed in interface. // // Arguments: // IN REFIID riid, // Id of interface requested. // // OUT void ** ppv // Pointer to the requested interface. // // Return Value: // S_OK // If the interface is available on this object. // // E_NOINTERFACE // If the interface is not available. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::QueryInterface( REFIID riid, void ** ppv ) { TraceQIFunc( riid, ppv ); HRESULT hr = E_NOINTERFACE; if ( IsEqualIID( riid, IID_IUnknown ) ) { *ppv = static_cast< IClusCfgServer * >( this ); hr = S_OK; } // if: IUnknown else if ( IsEqualIID( riid, IID_IClusCfgServer ) ) { *ppv = TraceInterface( __THISCLASS__, IClusCfgServer, this, 0 ); hr = S_OK; } // else if: else if ( IsEqualIID( riid, IID_IClusCfgInitialize ) ) { *ppv = TraceInterface( __THISCLASS__, IClusCfgInitialize, this, 0 ); hr = S_OK; } // else if: else if ( IsEqualIID( riid, IID_IClusCfgCapabilities ) ) { *ppv = TraceInterface( __THISCLASS__, IClusCfgCapabilities, this, 0 ); hr = S_OK; } // else if: else if ( IsEqualIID( riid, IID_IClusCfgPollingCallbackInfo ) ) { *ppv = TraceInterface( __THISCLASS__, IClusCfgPollingCallbackInfo, this, 0 ); hr = S_OK; } // else if: else if ( IsEqualIID( riid, IID_IClusCfgVerify ) ) { *ppv = TraceInterface( __THISCLASS__, IClusCfgVerify, this, 0 ); hr = S_OK; } // else if: if ( SUCCEEDED( hr ) ) { ((IUnknown *) *ppv)->AddRef( ); } // if: success QIRETURN_IGNORESTDMARSHALLING( hr, riid ); } //*** CClusCfgServer::QueryInterface //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer -- IClusCfgInitialize interface. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::Initialize // // Description: // Initialize this component. // // Arguments: // IN IUknown * punkCallbackIn // // IN LCID lcidIn // // Return Value: // S_OK // Success // // E_POINTER // The punkCallbackIn param is NULL. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::Initialize( IUnknown * punkCallbackIn, LCID lcidIn ) { TraceFunc( "[IClusCfgInitialize]" ); Assert( m_picccCallback != NULL ); TraceInitializeThread( L"ClusCfgServerFlags" ); HRESULT hr = S_OK; IUnknown * punk = NULL; IClusCfgCallback * piccc = NULL; // this is NULL when we are polling callback IClusCfgNodeInfo * piccni = NULL; IClusCfgClusterInfo * piccci = NULL; // hr = STHR( HrCheckSecurity() ); // if ( FAILED( hr ) ) // { // goto Cleanup; // } // if: m_lcid = lcidIn; // // If we are passed a callback object then we need to get its IClusCfgCallback // interface so we can pass it into our callback object when it's initialized // below. // if ( punkCallbackIn != NULL ) { Assert( !m_fUsePolling ); hr = THR( punkCallbackIn->TypeSafeQI( IClusCfgCallback, &piccc ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: } // if: else { Assert( m_fUsePolling ); if ( m_fUsePolling == FALSE ) { hr = THR( E_INVALIDARG ); goto Cleanup; } // if: } // else: // // Initialize our internal callback object passing it either the passed in // callback object's callback interface or NULL if we are polling. // hr = THR( m_picccCallback->TypeSafeQI( IUnknown, &punk ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( HrSetInitialize( punk, piccc, m_lcid ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // // KB: 24-JUL-2000 GalenB // // If we are being initialized on this interface then we are going to run this server local // to the node. // hr = THR( HrInitializeForLocalServer() ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // // Precreate the node info so we can get the cluster info object and determine if the cluster service // is running on this node or not. // hr = THR( HrCreateClusterNodeInfo() ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( m_punkNodeInfo->TypeSafeQI( IClusCfgNodeInfo, &piccni ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // // This could return HRESUTL_FROM_WIN32( ERROR_CLUSTER_NODE_DOWN ) and that // tells us that the cluster service is not running on this node. The // middletier needs to know this so it doesn't call us on this node // anymore. // hr = THR( piccni->GetClusterConfigInfo( &piccci ) ); Cleanup: if ( m_picccCallback != NULL ) { STATUS_REPORT( TASKID_Major_Establish_Connection, TASKID_Minor_Server_Initialized, IDS_NOTIFY_SERVER_INITIALIZED, hr ); } // if: if ( piccci != NULL ) { piccci->Release(); } // if: if ( piccni != NULL ) { piccni->Release(); } // if: if ( piccc != NULL ) { piccc->Release(); } // if: if ( punk != NULL ) { punk->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::Initialize //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer -- IClusCfgServer interface. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::GetClusterNodeInfo // // Description: // Get information about the computer on which this object is present. // // Arguments: // OUT IClusCfgNodeInfo ** ppClusterNodeInfoOut // Catches the node info object. // // Return Value: // S_OK // Success // // E_POINTER // The out param was NULL. // // E_OUTOFMEMORY // The IClusCfgNodeInfo object could not be allocated. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::GetClusterNodeInfo( IClusCfgNodeInfo ** ppClusterNodeInfoOut ) { TraceFunc( "[IClusCfgServer]" ); HRESULT hr = S_OK; if ( ppClusterNodeInfoOut == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT( TASKID_Major_Check_Node_Feasibility, TASKID_Minor_GetClusterNodeInfo, IDS_ERROR_NULL_POINTER, hr ); goto Cleanup; } // if: if ( m_punkNodeInfo != NULL ) { hr = S_OK; goto SkipCreate; } // if: hr = THR( HrCreateClusterNodeInfo() ); SkipCreate: if ( SUCCEEDED( hr ) ) { Assert( m_punkNodeInfo != NULL ); hr = THR( m_punkNodeInfo->TypeSafeQI( IClusCfgNodeInfo, ppClusterNodeInfoOut ) ); } // if: Cleanup: if ( FAILED( hr ) ) { STATUS_REPORT( TASKID_Major_Check_Node_Feasibility, TASKID_Minor_Server_GetClusterNodeInfo, IDS_ERROR_NODE_INFO_CREATE, hr ); } // if: else { STATUS_REPORT( TASKID_Major_Check_Node_Feasibility, TASKID_Minor_Server_GetClusterNodeInfo, IDS_NODE_INFO_CREATE, hr ); } // else: HRETURN( hr ); } //*** CClusCfgServer::GetClusterNodeInfo ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::GetManagedResourcesEnum // // Description: // Get an enumeration of the devices on this computer that can be // managed by the cluster service. // // Arguments: // OUT IEnumClusCfgManagedResources ** ppEnumManagedResourcesOut // Catches the CEnumClusCfgManagedResources object. // // Return Value: // S_OK // Success // // E_POINTER // The out param was NULL. // // E_OUTOFMEMORY // The CEnumClusCfgManagedResources object could not be allocated. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::GetManagedResourcesEnum( IEnumClusCfgManagedResources ** ppEnumManagedResourcesOut ) { TraceFunc( "[IClusCfgServer]" ); HRESULT hr = S_OK; if ( ppEnumManagedResourcesOut == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_GetManagedResourcesEnum, IDS_ERROR_NULL_POINTER, hr ); goto Cleanup; } // if: if ( m_punkEnumResources != NULL ) { m_punkEnumResources->Release(); m_punkEnumResources = NULL; } // if: hr = THR( CEnumClusCfgManagedResources::S_HrCreateInstance( &m_punkEnumResources ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: m_punkEnumResources = TraceInterface( L"CEnumClusCfgManagedResources", IUnknown, m_punkEnumResources, 1 ); hr = THR( HrSetInitialize( m_punkEnumResources, m_picccCallback, m_lcid ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( HrSetWbemServices( m_punkEnumResources, m_pIWbemServices ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( m_punkEnumResources->TypeSafeQI( IEnumClusCfgManagedResources, ppEnumManagedResourcesOut ) ); Cleanup: if ( FAILED( hr ) ) { STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetManagedResourcesEnum, IDS_ERROR_MANAGED_RESOURCE_ENUM_CREATE, hr ); } // if: else { STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetManagedResourcesEnum, IDS_MANAGED_RESOURCE_ENUM_CREATE, hr ); } // else: HRETURN( hr ); } //*** CClusCfgServer::GetManagedResourcesEnum ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::GetNetworksEnum // // Description: // Get an enumeration of all the networks on this computer. // // Arguments: // OUT IEnumClusCfgNetworks ** ppEnumNetworksOut // Catches the CEnumClusCfgNetworks object. // // Return Value: // S_OK // Success // // E_POINTER // The out param was NULL. // // E_OUTOFMEMORY // The CEnumClusCfgNetworks object could not be allocated. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::GetNetworksEnum( IEnumClusCfgNetworks ** ppEnumNetworksOut ) { TraceFunc( "[IClusCfgServer]" ); HRESULT hr = S_OK; if ( ppEnumNetworksOut == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_GetNetworksEnum, IDS_ERROR_NULL_POINTER, hr ); goto Cleanup; } // if: if ( m_punkNetworksEnum != NULL ) { m_punkNetworksEnum->Release(); m_punkNetworksEnum = NULL; } // if: hr = THR( HrCreateNetworksEnum( m_picccCallback, m_lcid, m_pIWbemServices, &m_punkNetworksEnum ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( m_punkNetworksEnum->TypeSafeQI( IEnumClusCfgNetworks, ppEnumNetworksOut ) ); Cleanup: if ( FAILED( hr ) ) { STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetNetworksEnum, IDS_ERROR_NETWORKS_ENUM_CREATE, hr ); } // if: else { STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetNetworksEnum, IDS_NETWORKS_ENUM_CREATE, hr ); } // else: HRETURN( hr ); } //*** CClusCfgServer::GetNetworksEnum ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::CommitChanges // // Description: // Commit the changes to the node. // // Arguments: // // // Return Value: // S_OK // Success // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::CommitChanges( void ) { TraceFunc( "[IClusCfgServer]" ); HRESULT hr = S_OK; HRESULT hrTemp = S_OK; IClusCfgInitialize * pcci = NULL; IClusCfgClusterInfo * pClusCfgClusterInfo = NULL; ECommitMode ecmCommitChangesMode = cmUNKNOWN; IClusCfgNodeInfo * piccni = NULL; IPostCfgManager * ppcm = NULL; IUnknown * punkCallback = NULL; HANDLE heventPostCfgCompletion = NULL; IEnumClusCfgManagedResources * peccmr = NULL; MULTI_QI mqiInterfaces[] = { { &IID_IClusCfgBaseCluster, NULL, S_OK }, { &IID_IClusCfgInitialize, NULL, S_OK } }; hr = THR( m_picccCallback->TypeSafeQI( IUnknown, &punkCallback ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // // KB: First, get a pointer to the IClusCfgNodeInfo interface. Use this to get // a pointer to the IClusCfgClusterInfo interface to see what action needs // to be committed. // if ( m_punkNodeInfo == NULL ) { hr = THR( GetClusterNodeInfo( &piccni ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: } // if: else { hr = THR( m_punkNodeInfo->TypeSafeQI( IClusCfgNodeInfo, &piccni ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the pointer to the IClusCfgNodeInfo interface } // else: hr = THR( piccni->GetClusterConfigInfo( &pClusCfgClusterInfo ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the pointer to the IClusCfgClusterInfo interface hr = STHR( pClusCfgClusterInfo->GetCommitMode( &ecmCommitChangesMode ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: Assert( ecmCommitChangesMode != cmUNKNOWN ); // // Create and initialize the BaseClusterAction component // hr = THR( CoCreateInstanceEx( CLSID_ClusCfgBaseCluster, NULL, CLSCTX_SERVER, NULL, ARRAYSIZE( mqiInterfaces ), mqiInterfaces ) ); if ( FAILED( hr ) && ( hr != CO_S_NOTALLINTERFACES ) ) { LOG_STATUS_REPORT( L"Failed to CoCreate Base Cluster Actions", hr ); goto Cleanup; } // if: CoCreateInstanceEx() failed hr = THR( mqiInterfaces[ 0 ].hr ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get a pointer to the IClusCfgBaseCluster interface // // Check if we got a pointer to the IClusCfgInitialize interface hr = mqiInterfaces[ 1 ].hr; if ( hr == S_OK ) { hr = THR( ((IClusCfgInitialize *) mqiInterfaces[ 1 ].pItf)->Initialize( punkCallback, m_lcid ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: something went wrong during initialization } // if: we got a pointer to the IClusCfgInitialize interface else { if ( hr != E_NOINTERFACE ) { goto Cleanup; } // if: the interface is supported, but something else went wrong. } // if: we did not get a pointer to the IClusCfgInitialize interface // // Create and initialize the Post configuration manager // hr = THR( CoCreateInstance( CLSID_ClusCfgPostConfigManager, NULL, CLSCTX_SERVER, TypeSafeParams( IPostCfgManager, &ppcm ) ) ); if ( FAILED( hr ) ) { // // TODO: gpease 11-JUN-2000 // Notify the UI layer. What are the major and minor task ids? // LOG_STATUS_REPORT( L"Failed to CoCreate the Post Configuration Manager", hr ); goto Cleanup; } // Check if this component supports the callback interface. hrTemp = THR( ppcm->TypeSafeQI( IClusCfgInitialize, &pcci ) ); if ( FAILED( hrTemp ) ) { LOG_STATUS_REPORT( L"Could not get a pointer to the IClusCfgInitialize interface. This post configuration manager does not support initialization", hr ); } // if: the callback interface is not supported else { // Initialize this component. hr = THR( pcci->Initialize( punkCallback, m_lcid ) ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"Could not initialize the post configuration manager", hr ); goto Cleanup; } // if: the initialization failed } // else: the callback interface is supported if ( m_punkEnumResources != NULL ) { hr = THR( m_punkEnumResources->TypeSafeQI( IEnumClusCfgManagedResources, &peccmr ) ); } // if: else { Assert( ( ecmCommitChangesMode != cmCREATE_CLUSTER ) && ( ecmCommitChangesMode != cmADD_NODE_TO_CLUSTER) ); hr = THR( GetManagedResourcesEnum( &peccmr ) ); } // else: // // If we are here, then the BaseCluster and Post configuration components were successfully // created and initialized. Now perform the desired action. // if ( ( ecmCommitChangesMode == cmCREATE_CLUSTER ) || ( ecmCommitChangesMode == cmADD_NODE_TO_CLUSTER ) ) { if ( !m_fCanBeClustered ) { // // TODO: 01-JUN-2000 GalenB // // Need better error code... What is the major and minor taskids? // hr = S_FALSE; LOG_STATUS_REPORT( L"It was previously determined that this node cannot be clustered.", hr ); goto Cleanup; } // if: this node cannot be part of a cluster // // If the cluster service is being started for the first time, as a part // of adding this node to a cluster (forming or joining), then we have // to wait till the post-configuration steps are completed before we // can send out notifications. Create an event that indicates that post configuration // has completed. // TraceFlow1( "Trying to create an event named '%s'.", POSTCONFIG_COMPLETE_EVENT_NAME ); // Create an event in the unsignalled state. heventPostCfgCompletion = CreateEvent( NULL // event security attributes , TRUE // manual-reset event , FALSE // create in unsignaled state , POSTCONFIG_COMPLETE_EVENT_NAME ); if ( heventPostCfgCompletion == NULL ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) ); LogMsg( L"[SRV] Error %#08x occurred trying to create an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); TraceFlow2( "Error %#08x occurred trying to create an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); goto Cleanup; } // if: we could not get a handle to the event // Reset the event, just as a safetly measure, in case the event already existed before the call above. if ( ResetEvent( heventPostCfgCompletion ) == 0 ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) ); LogMsg( L"[SRV] Error %#08x occurred trying to unsignal an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); TraceFlow2( "Error %#08x occurred trying to unsignal an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); goto Cleanup; } // if: ResetEvent() failed() } // if: we are forming or joining if ( ecmCommitChangesMode == cmCREATE_CLUSTER ) { // Commit the base cluster hr = THR( HrFormCluster( pClusCfgClusterInfo, (( IClusCfgBaseCluster * ) mqiInterfaces[ 0 ].pItf) ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // Commit the post configuration steps hr = THR( ppcm->CommitChanges( peccmr, pClusCfgClusterInfo ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // Signal the event to indicate that post configuration is complete. if ( SetEvent( heventPostCfgCompletion ) == 0 ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) ); LogMsg( L"[SRV] Error %#08x occurred trying to signal an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); TraceFlow2( "Error %#08x occurred trying to signal an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); goto Cleanup; } // if: SetEvent() failed() } // if: we are forming a cluster. else if ( ecmCommitChangesMode == cmADD_NODE_TO_CLUSTER ) { // Commit the base cluster hr = THR( HrJoinToCluster( pClusCfgClusterInfo, (( IClusCfgBaseCluster * ) mqiInterfaces[ 0 ].pItf) ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // Commit the post configuration steps hr = THR( ppcm->CommitChanges( peccmr, pClusCfgClusterInfo ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: // Signal the event to indicate that post configuration is complete. if ( SetEvent( heventPostCfgCompletion ) == 0 ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) ); LogMsg( L"[SRV] Error %#08x occurred trying to signal an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); TraceFlow2( "Error %#08x occurred trying to signal an event named '%ls'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME ); goto Cleanup; } // if: SetEvent() failed() } // else if: we are joining a cluster else if ( ecmCommitChangesMode == cmCLEANUP_NODE_AFTER_EVICT ) { // This node has been evicted - clean it up. hr = THR( HrEvictedFromCluster( ppcm, peccmr, pClusCfgClusterInfo, (( IClusCfgBaseCluster * ) mqiInterfaces[ 0 ].pItf) ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: } // else if: we have just been evicted from a cluster Cleanup: if ( punkCallback != NULL ) { punkCallback->Release(); } // if: if ( pcci != NULL ) { pcci->Release(); } // if: if ( ppcm != NULL ) { ppcm->Release( ); } // if: if ( peccmr != NULL ) { peccmr->Release( ); } // if: if ( mqiInterfaces[ 0 ].pItf != NULL ) { mqiInterfaces[ 0 ].pItf->Release(); } // if: if ( mqiInterfaces[ 1 ].pItf != NULL ) { mqiInterfaces[ 1 ].pItf->Release(); } // if: if ( pClusCfgClusterInfo != NULL ) { pClusCfgClusterInfo->Release(); } // if: if ( piccni != NULL ) { piccni->Release(); } // if: if ( heventPostCfgCompletion != NULL ) { // If we had created this event, then signal this event to let the // startup notification thread proceed. SetEvent( heventPostCfgCompletion ); CloseHandle( heventPostCfgCompletion ); } // if: if ( FAILED( hr ) ) { STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_CommitChanges, IDS_ERROR_COMMIT_CHANGES, hr ); } // if: else { STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_CommitChanges, IDS_COMMIT_CHANGES, hr ); } // else: HRETURN( hr ); } //*** CClusCfgServer::CommitChanges ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::GetBindingString // // Description: // Get the binding string for this server. // // Arguments: // // Return Value: // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::GetBindingString( BSTR * pbstrBindingStringOut ) { TraceFunc( "[IClusCfgServer]" ); HRESULT hr = S_OK; if ( pbstrBindingStringOut == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetBindingString_Pointer, IDS_ERROR_NULL_POINTER, hr ); goto Cleanup; } // if: if ( m_bstrBindingString == NULL ) { hr = S_FALSE; LOG_STATUS_REPORT1( TASKID_Minor_Server_GetBindingString_NULL, L"Binding string is NULL. Must be a local connection.", hr ); goto Cleanup; } // if: *pbstrBindingStringOut = SysAllocString( m_bstrBindingString ); if ( *pbstrBindingStringOut == NULL ) { hr = THR( E_OUTOFMEMORY ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetBindingString_Memory, IDS_ERROR_OUTOFMEMORY, hr ); } // if: Cleanup: HRETURN( hr ); } //*** CClusCfgServer::GetBindingString ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::SetBindingString // // Description: // Set the binding string of this server. // // Arguments: // // Return Value: // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::SetBindingString( LPCWSTR pcszBindingStringIn ) { TraceFunc1( "[IClusCfgServer] pcszBindingStringIn = '%ls'", pcszBindingStringIn == NULL ? L"" : pcszBindingStringIn ); HRESULT hr = S_OK; BSTR bstr = NULL; if ( pcszBindingStringIn == NULL ) { hr = THR( E_INVALIDARG ); goto Cleanup; } // if: bstr = TraceSysAllocString( pcszBindingStringIn ); if ( bstr == NULL ) { hr = THR( E_OUTOFMEMORY ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_SetBindingString_Server, IDS_ERROR_OUTOFMEMORY, hr ); goto Cleanup; } // if: TraceSysFreeString( m_bstrBindingString ); m_bstrBindingString = bstr; Cleanup: HRETURN( hr ); } //*** CClusCfgServer::SetBindingString //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer class -- IClusCfgCapabilities interfaces. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::CanNodeBeClustered // // Description: // Can this node be added to a cluster? // // Arguments: // // // Return Value: // S_OK // Node can be clustered. // // S_FALSE // Node cannot be clustered. // // other HRESULTs // The call failed. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::CanNodeBeClustered( void ) { TraceFunc( "[IClusCfgServer]" ); HRESULT hr; ICatInformation * pici = NULL; CATID rgCatIds[ 1 ]; IEnumCLSID * pieclsids = NULL; IClusCfgCapabilities * piccc = NULL; CLSID clsid; ULONG cFetched; IUnknown * punk = NULL; // // KB: 10-SEP-2000 GalenB // // Last ditch effort to clean up a node that is in a bad state before trying // to add it into a cluster. // hr = STHR( HrHasNodeBeenEvicted() ); if ( hr == S_OK ) { hr = THR( HrCleanUpNode() ) ; if ( FAILED( hr ) ) { goto Cleanup; } // if: } // if: else if ( FAILED( hr ) ) { goto Cleanup; } // else if: rgCatIds[ 0 ] = CATID_ClusCfgCapabilities; hr = THR( CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatInformation, (void **) &pici ) ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"Failed to CoCreate CLSID_StdComponentCategoriesMgr component", hr ); goto Cleanup; } hr = THR( pici->EnumClassesOfCategories( 1, rgCatIds, 0, NULL, &pieclsids ) ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"Failed to get enumerator for the IClusCfgClusterCapabilites components", hr ); goto Cleanup; } // if: for ( ; ; ) { hr = STHR( pieclsids->Next( 1, &clsid, &cFetched ) ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"IClusCfgClusterCapabilites component enumerator failed", hr ); break; } // if: if ( ( hr == S_FALSE ) && ( cFetched == 0 ) ) { hr = S_OK; break; } // if: hr = THR( HrCoCreateInternalInstance( clsid, NULL, CLSCTX_ALL, IID_IClusCfgCapabilities, (void **) &piccc ) ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"Failed to CoCreate IClusCfgClusterCapabilites component", hr ); continue; } // if: hr = THR( piccc->TypeSafeQI( IUnknown, &punk ) ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"Failed to QI IClusCfgClusterCapabilites component for IUnknown", hr ); piccc->Release(); piccc = NULL; continue; } // if: hr = THR( HrSetInitialize( punk, m_picccCallback, m_lcid ) ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"Failed to initialize IClusCfgClusterCapabilites component", hr ); piccc->Release(); piccc = NULL; punk->Release(); punk = NULL; continue; } // if: punk->Release(); punk = NULL; hr = STHR( piccc->CanNodeBeClustered() ); if ( FAILED( hr ) ) { LOG_STATUS_REPORT( L"IClusCfgClusterCapabilites component failed in CanNodeBeClustered()", hr ); piccc->Release(); piccc = NULL; continue; } // if: if ( hr == S_FALSE ) { m_fCanBeClustered = false; } // if: piccc->Release(); piccc = NULL; } // for: if ( !m_fCanBeClustered ) { hr = S_FALSE; } // if: Cleanup: if ( punk != NULL ) { punk->Release(); } // if: if ( piccc != NULL ) { piccc->Release(); } // if: if ( pieclsids != NULL ) { pieclsids->Release(); } // if: if ( pici != NULL ) { pici->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::CanNodeBeClustered //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer class -- IClusCfgPollingCallbackInfo interface. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::GetCallback // // Description: // Return the pointer to the embedded polling callback object. // // Arguments: // ppiccpcOut // // Return Value: // S_OK // Success // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::GetCallback( IClusCfgPollingCallback ** ppiccpcOut ) { TraceFunc( "[IClusCfgServer]" ); Assert( m_picccCallback != NULL ); HRESULT hr = S_OK; if ( ppiccpcOut == NULL ) { hr = THR( E_POINTER ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_GetCallback, IDS_ERROR_NULL_POINTER, hr ); goto Cleanup; } // if: hr = THR( m_picccCallback->TypeSafeQI( IClusCfgPollingCallback, ppiccpcOut ) ); Cleanup: HRETURN( hr ); } //*** CClusCfgServer::GetCallback ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::SetPollingMode // // Description: // Set the polling mode of the callback. // // Arguments: // fPollingModeIn // // Return Value: // S_OK // Success // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::SetPollingMode( BOOL fPollingModeIn ) { TraceFunc( "[IClusCfgServer]" ); Assert( m_picccCallback != NULL ); HRESULT hr = S_OK; IClusCfgSetPollingCallback * piccspc = NULL; m_fUsePolling = fPollingModeIn; hr = THR( m_picccCallback->TypeSafeQI( IClusCfgSetPollingCallback, &piccspc ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( piccspc->SetPollingMode( m_fUsePolling ) ); Cleanup: if ( piccspc != NULL ) { piccspc->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::SetPollingMode //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer class -- IClusCfgVerify interface. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::VerifyCredentials // // Description: // Validate the passed in credentials. // // Arguments: // // Return Value: // S_OK // The credentials are valid. // // other HRESULTs // The call failed. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::VerifyCredentials( LPCWSTR pcszNameIn, LPCWSTR pcszDomainIn, LPCWSTR pcszPasswordIn ) { TraceFunc( "[IClusCfgVerify]" ); HRESULT hr = S_OK; HANDLE hToken = NULL; // // Logon the passed in user to ensure that it is valid. // // // KB: 04 May 2000 GalenB // // New for Whistler... You no longer have to grant your processes TCB privilege. But it doesn't seem to work! // if ( !LogonUserW( const_cast< LPWSTR >( pcszNameIn ) , const_cast< LPWSTR >( pcszDomainIn ) , const_cast< LPWSTR >( pcszPasswordIn ) , LOGON32_LOGON_NETWORK , LOGON32_PROVIDER_DEFAULT , &hToken ) ) { DWORD sc; sc = TW32( GetLastError() ); hr = HRESULT_FROM_WIN32( sc ); } // if: if ( hToken != NULL ) { CloseHandle( hToken ); } // if: HRETURN( hr ); } //*** CClusCfgServer::VerifyCredentials ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::VerifyConnectionToCluster // // Description: // Verify that that this server is the same as the passed in server. // // Arguments: // pcszClusterNameIn // // Return Value: // S_OK // This is the server. // // S_FALSE // This is not the server. // // other HRESULTs // The call failed. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::VerifyConnectionToCluster( LPCWSTR pcszClusterNameIn ) { TraceFunc1( "[IClusCfgVerify] pcszClusterNameIn = '%ls'", pcszClusterNameIn ); DWORD sc; DWORD dwClusterState; HRESULT hr = S_FALSE; HCLUSTER hCluster = NULL; BSTR bstrClusterName = NULL; BSTR bstrDomainName = NULL; WCHAR * psz = NULL; size_t cch; // // Test arguments // if ( pcszClusterNameIn == NULL ) { goto InvalidArg; } // if: // // See if we are clustered. // sc = TW32( GetNodeClusterState( NULL, &dwClusterState ) ); if ( sc != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( sc ); goto Cleanup; } // if : GetClusterState() failed // // If the current cluster node state is running or not running then this node is part of a cluster. // if ( ( dwClusterState != ClusterStateNotRunning ) && ( dwClusterState != ClusterStateRunning ) ) { hr = S_FALSE; goto Cleanup; } // if: // // Open the cluster to get the cluster's name. // hCluster = OpenCluster( NULL ); if ( hCluster == NULL ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_VerifyConnection_OpenCluster, IDS_ERROR_OPEN_CLUSTER_FAILED, hr ); goto Cleanup; } // if: // // Try to get the cluster's name. // hr = THR( HrGetClusterInformation( hCluster, &bstrClusterName, NULL ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: cch = wcslen( bstrClusterName ); // // See if the domain name was given. // psz = wcschr( pcszClusterNameIn, L'.' ); if ( psz == NULL ) { // // If no domain was given, see if it matches the cluster's name. // if ( _wcsicmp( bstrClusterName, pcszClusterNameIn ) == 0 ) { hr = S_OK; goto Cleanup; } // if: goto Cleanup; } // if: // // If if the cluster name matches. // if ( (size_t) ( psz - pcszClusterNameIn ) != cch ) { goto Cleanup; // nope } // if: if ( ( wcslen( pcszClusterNameIn ) < cch ) || ( memcmp( bstrClusterName, pcszClusterNameIn, cch ) != 0 ) ) { goto Cleanup; } // if: // // Make sure we are in the same domain. // hr = THR( HrGetComputerName( ComputerNameDnsDomain, &bstrDomainName ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: psz++; if ( _wcsicmp( bstrDomainName, psz ) == 0 ) { hr = S_OK; goto Cleanup; } // if: Assert( hr == S_FALSE ); goto Cleanup; InvalidArg: hr = THR( E_INVALIDARG ); STATUS_REPORT( TASKID_Major_Find_Devices, TASKID_Minor_VerifyConnection_InvalidArg, IDS_ERROR_INVALIDARG, hr ); goto Cleanup; Cleanup: if ( hr == S_FALSE ) { LOG_STATUS_REPORT( L"Server name does not match what client is expecting.", hr ); } // if: else if ( hr == S_OK ) { LOG_STATUS_REPORT( L"Server name matches what client is expecting.", hr ); } // else if: if ( hCluster != NULL ) { CloseCluster( hCluster ); } // if: TraceSysFreeString( bstrClusterName ); TraceSysFreeString( bstrDomainName ); HRETURN( hr ); } // ClusCfgServer::VerifyConnection ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::VerifyConnectionToNode // // Description: // Verify that that this server is the same as the passed in server. // // Arguments: // pcszNodeNameIn // // Return Value: // S_OK // This is the server. // // S_FALSE // This is not the server. // // other HRESULTs // The call failed. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CClusCfgServer::VerifyConnectionToNode( LPCWSTR pcszNodeNameIn ) { TraceFunc1( "[IClusCfgVerify] pcszNodeNameIn = '%ls'", pcszNodeNameIn ); HRESULT hr = S_FALSE; LPWSTR psz; // // Test arguments // if ( pcszNodeNameIn == NULL ) { goto InvalidArg; } // if: // // Test state. // if ( m_bstrNodeName == NULL ) { goto OutOfMemory; } // if: // // See if it matches the nodes name. // if ( _wcsicmp( pcszNodeNameIn, m_bstrNodeName ) == 0 ) { hr = S_OK; goto Cleanup; } // if: // // If there isn't a domain attached to the node name, then check only // the hostname. // psz = wcschr( pcszNodeNameIn, L'.' ); if ( psz == NULL ) { if ( _wcsnicmp( pcszNodeNameIn, m_bstrNodeName, wcslen( pcszNodeNameIn ) ) == 0 ) { hr = S_OK; goto Cleanup; } // if: } // if: Assert( hr == S_FALSE ); goto Cleanup; InvalidArg: LogMsg( L"[SRV] VerifyConnection - Invalid argument." ); hr = THR( E_INVALIDARG ); goto Cleanup; OutOfMemory: LogMsg( L"[SRV] VerifyConnection - out of memory." ); hr = E_OUTOFMEMORY; Cleanup: if ( hr == S_FALSE ) { LogMsg( L"[SRV] VerifyConnection - Server name does not match what client is expecting." ); } // if: else if ( hr == S_OK ) { LogMsg( L"[SRV] VerifyConnection - Server name matches what client is expecting." ); } // else if: HRETURN( hr ); } // ClusCfgServer::VerifyConnection //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CClusCfgServer class -- Private Methods. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrInit // // Description: // Initialize this component. // // Arguments: // // // Return Value: // S_OK // Success // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrInit( void ) { TraceFunc( "" ); HRESULT hr = S_FALSE; IUnknown * punk = NULL; hr = THR( CClusCfgCallback::S_HrCreateInstance( &punk ) ); if ( FAILED ( hr ) ) { LogMsg( L"[SRV] Could not create CClusCfgCallback. (hr = %#08x)", hr ); goto Cleanup; } // if: hr = THR( punk->TypeSafeQI( IClusCfgCallback, &m_picccCallback ) ); if ( FAILED( hr ) ) { LogMsg( L"[SRV] Could not QI callback for a punk. (hr = %#08x)", hr ); goto Cleanup; } // if: hr = THR( HrGetComputerName( ComputerNameDnsFullyQualified, &m_bstrNodeName ) ); Cleanup: if ( punk != NULL ) { punk->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::HrInit ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrInitializeForLocalServer // // Description: // Initialize this component. // // Arguments: // // // Return Value: // S_OK // Success // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrInitializeForLocalServer( void ) { TraceFunc( "" ); HRESULT hr = S_OK; IWbemLocator * pIWbemLocator = NULL; BSTR bstrNameSpace = NULL; hr = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pIWbemLocator ); if ( FAILED( hr ) ) { STATUS_REPORT( TASKID_Major_Establish_Connection, TASKID_Minor_HrInitializeForLocalServer_WbemLocator, IDS_ERROR_WBEM_LOCATOR_CREATE_FAILED, hr ); goto Cleanup; } // if: bstrNameSpace = TraceSysAllocString( L"\\\\.\\root\\cimv2" ); if ( bstrNameSpace == NULL ) { hr = THR( E_OUTOFMEMORY ); STATUS_REPORT( TASKID_Major_Establish_Connection, TASKID_Minor_HrInitializeForLocalServer_Memory, IDS_ERROR_OUTOFMEMORY, hr ); goto Cleanup; } // if: hr = THR( pIWbemLocator->ConnectServer( bstrNameSpace, NULL, // using current account for simplicity NULL, // using current password for simplicity NULL, // locale 0L, // securityFlags, reserved must be 0 NULL, // authority (domain for NTLM) NULL, // context &m_pIWbemServices ) ); if ( FAILED( hr ) ) { STATUS_REPORT( TASKID_Major_Establish_Connection, TASKID_Minor_WBEM_Connection_Failure, IDS_ERROR_WBEM_CONNECTION_FAILURE, hr ); goto Cleanup; } // if: hr = THR( HrSetBlanket() ); if ( FAILED( hr ) ) { STATUS_REPORT( TASKID_Major_Establish_Connection, TASKID_Minor_HrInitializeForLocalServer_Blanket, IDS_ERROR_WBEM_BLANKET_FAILURE, hr ); goto Cleanup; } // if: Cleanup: TraceSysFreeString( bstrNameSpace ); if ( pIWbemLocator != NULL ) { pIWbemLocator->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::HrInitializeForLocalServer ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrSetBlanket // // Description: // Adjusts the security blanket on the IWbemServices pointer. // // Arguments: // None. // // Return Value: // // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrSetBlanket( void ) { TraceFunc( "" ); Assert( m_pIWbemServices != NULL ); HRESULT hr = S_FALSE; if ( m_pIWbemServices ) { IClientSecurity * pCliSec; hr = THR( m_pIWbemServices->TypeSafeQI( IClientSecurity, &pCliSec ) ); if ( SUCCEEDED( hr ) ) { hr = THR( pCliSec->SetBlanket( m_pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE ) ); pCliSec->Release(); } // if: } // if: HRETURN( hr ); } //*** CClusCfgServer::HrSetBlanket ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrFormCluster // // Description: // Form a new cluster. // // Arguments: // None. // // Return Value: // // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrFormCluster( IClusCfgClusterInfo * piccciIn, IClusCfgBaseCluster * piccbcaIn ) { TraceFunc( "" ); HRESULT hr; BSTR bstrClusterName = NULL; BSTR bstrClusterBindingString = NULL; BSTR bstrClusterAccountName = NULL; BSTR bstrClusterAccountPwd = NULL; BSTR bstrClusterAccountDomain = NULL; BSTR bstrClusterIPNetwork = NULL; ULONG ulClusterIPAddress = 0; ULONG ulClusterIPSubnetMask = 0; IClusCfgCredentials * picccServiceAccount = NULL; IClusCfgNetworkInfo * piccni = NULL; // // Get the parameters required to form a cluster. // hr = THR( piccciIn->GetName( &bstrClusterName ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the name of the cluster TraceMemoryAddBSTR( bstrClusterName ); hr = STHR( piccciIn->GetBindingString( &bstrClusterBindingString ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the binding string of the cluster. TraceMemoryAddBSTR( bstrClusterBindingString ); hr = THR( piccciIn->GetClusterServiceAccountCredentials( &picccServiceAccount ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the cluster service account credentials hr = THR( picccServiceAccount->GetCredentials( &bstrClusterAccountName, &bstrClusterAccountDomain, &bstrClusterAccountPwd ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the service account name. domain and password. TraceMemoryAddBSTR( bstrClusterAccountName ); TraceMemoryAddBSTR( bstrClusterAccountDomain ); TraceMemoryAddBSTR( bstrClusterAccountPwd ); hr = THR( piccciIn->GetIPAddress( &ulClusterIPAddress ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the cluster IP address hr = THR( piccciIn->GetSubnetMask( &ulClusterIPSubnetMask ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the cluster subnet mask hr = THR( piccciIn->GetNetworkInfo( &piccni ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the network info of the network the cluster name should be on. hr = THR( piccni->GetName( &bstrClusterIPNetwork ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the name of the cluster name network. TraceMemoryAddBSTR( bstrClusterIPNetwork ); // // Indicate that a cluster should be formed when Commit() is called. // hr = THR( piccbcaIn->SetForm( bstrClusterName , bstrClusterBindingString , bstrClusterAccountName , bstrClusterAccountPwd , bstrClusterAccountDomain , ulClusterIPAddress , ulClusterIPSubnetMask , bstrClusterIPNetwork ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: SetForm() failed. // Initiate cluster formation. hr = THR( piccbcaIn->Commit() ); Cleanup: TraceSysFreeString( bstrClusterName ); TraceSysFreeString( bstrClusterBindingString ); TraceSysFreeString( bstrClusterAccountName ); TraceSysFreeString( bstrClusterAccountPwd ); TraceSysFreeString( bstrClusterAccountDomain ); TraceSysFreeString( bstrClusterIPNetwork ); if ( piccni != NULL ) { piccni->Release(); } // if: if ( picccServiceAccount != NULL ) { picccServiceAccount->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::HrFormCluster ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrJoinToCluster // // Description: // Join a node to a cluster. // // Arguments: // None. // // Return Value: // // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrJoinToCluster( IClusCfgClusterInfo * piccciIn, IClusCfgBaseCluster * piccbcaIn ) { TraceFunc( "" ); HRESULT hr; BSTR bstrClusterName = NULL; BSTR bstrClusterBindingString = NULL; BSTR bstrClusterAccountName = NULL; BSTR bstrClusterAccountPwd = NULL; BSTR bstrClusterAccountDomain = NULL; IClusCfgCredentials * picccServiceAccount = NULL; // // Get the parameters required to form a cluster. // hr = THR( piccciIn->GetName( &bstrClusterName ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the name of the cluster TraceMemoryAddBSTR( bstrClusterName ); hr = THR( piccciIn->GetBindingString( &bstrClusterBindingString ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the cluster binding string. TraceMemoryAddBSTR( bstrClusterBindingString ); hr = THR( piccciIn->GetClusterServiceAccountCredentials( &picccServiceAccount ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the cluster service account credentials hr = THR( picccServiceAccount->GetCredentials( &bstrClusterAccountName, &bstrClusterAccountDomain, &bstrClusterAccountPwd ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not get the service account name. domain and password. TraceMemoryAddBSTR( bstrClusterAccountName ); TraceMemoryAddBSTR( bstrClusterAccountDomain ); TraceMemoryAddBSTR( bstrClusterAccountPwd ); // // Indicate that a cluster should be formed when Commit() is called. // hr = THR( piccbcaIn->SetJoin( bstrClusterName, bstrClusterBindingString, bstrClusterAccountName, bstrClusterAccountPwd, bstrClusterAccountDomain ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: SetJoin() failed. // Initiate joining of the node to the cluster. hr = THR( piccbcaIn->Commit() ); Cleanup: TraceSysFreeString( bstrClusterName ); TraceSysFreeString( bstrClusterBindingString ); TraceSysFreeString( bstrClusterAccountName ); TraceSysFreeString( bstrClusterAccountPwd ); TraceSysFreeString( bstrClusterAccountDomain ); if ( picccServiceAccount != NULL ) { picccServiceAccount->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::HrJoinToCluster ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrEvictedFromCluster // // Description: // Cleanup after a node has been evicted from a cluster. If another cleanup // session is in progress, wait for it to complete and then attempt cleanup. // In this way, if the other cleanup failed, this will retry it. If it had // suceeded, this will do nothing. // // This function first calls the CommitChanges() method of the PostConfigManager // (which will inform resource types and memberset listeners that this node // has been evicted). It then cleans up the base cluster. // // Arguments: // IPostCfgManager * ppcmIn // Pointer to the IPostCfgManager interface // // IEnumClusCfgManagedResources * peccmrIn // Argument needed by the IPostCfgManager::CommitChanges() // // IClusCfgClusterInfo * piccciIn // Pointer to the cluster info // // IClusCfgBaseCluster * piccbcaIn // Pointer to the IClusCfgBaseCluster interface that is used to clean up // the base cluster. // // Return Value: // S_OK // If everything went well // // other HRESULTs // If the call failed // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrEvictedFromCluster( IPostCfgManager * ppcmIn, IEnumClusCfgManagedResources * peccmrIn, IClusCfgClusterInfo * piccciIn, IClusCfgBaseCluster * piccbcaIn ) { TraceFunc( "" ); HRESULT hr = S_OK; DWORD dwStatus = ERROR_SUCCESS; HANDLE hsCleanupLock = NULL; HANDLE heventCleanupComplete = NULL; bool fLockAcquired = false; DWORD dwClusterState; HKEY hNodeStateKey = NULL; DWORD dwEvictState = 1; TraceFlow( "Trying to create cleanup lock." ); // First, try and acquire a lock, so that two cleanup operations cannot overlap. hsCleanupLock = CreateSemaphore( NULL, 1, 1, CLEANUP_LOCK_NAME ); if ( hsCleanupLock == NULL ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) ); TraceFlow1( "Error %#x occurred trying to create the cleanup lock.", hr ); LogMsg( "Error %#08x occurred trying to create the cleanup lock.", hr ); goto Cleanup; } // CreateSemaphore() failed TraceFlow( "Created cleanup lock. Now, trying to acquire it." ); LogMsg( "Trying to acquire cleanup lock." ); do { // Wait for any message sent or posted to this queue // or for our lock to be released. dwStatus = MsgWaitForMultipleObjects( 1 , &hsCleanupLock , FALSE , 300000 // If this lock has not been released in 5 minutes, abort. , QS_ALLINPUT ); // The result tells us the type of event we have. if ( dwStatus == ( WAIT_OBJECT_0 + 1 ) ) { MSG msg; // Read all of the messages in this next loop, // removing each message as we read it. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 ) { // If it is a quit message, we are done pumping messages. if ( msg.message == WM_QUIT) { TraceFlow( "Get a WM_QUIT message. Cleanup message pump loop." ); break; } // if: we got a WM_QUIT message // Otherwise, dispatch the message. DispatchMessage( &msg ); } // while: there are still messages in the window message queue } // if: we have a message in the window message queue else { if ( dwStatus == WAIT_OBJECT_0 ) { fLockAcquired = true; LogMsg( "Cleanup lock acquired." ); TraceFlow( "Our lock has been granted. Exiting wait loop." ); break; } // else if: our lock is signaled else { if ( dwStatus == -1 ) { hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) ); LogMsg( "Error %#x occurred trying to wait for our lock to be granted.", hr ); TraceFlow1( "Error %#x occurred trying to wait for our lock to be granted.", hr ); } // if: MsgWaitForMultipleObjects() returned an error else { hr = THR( HRESULT_FROM_WIN32( dwStatus ) ); LogMsg( "An error occurred trying to wait for our lock to be granted. Status code is %#x.", dwStatus ); TraceFlow1( "An error occurred trying to wait for our lock to be granted. Status code is %#x.", dwStatus ); } // else: an unexpected value was returned by MsgWaitForMultipleObjects() break; } // else: an unexpected result } // else: MsgWaitForMultipleObjects() exited for a reason other than a waiting message } while( true ); // do-while: loop infinitely if ( FAILED( hr ) ) { goto Cleanup; } // if: we could not acquire the cleanup lock // Check if the install state is correct before invoking post configuration manager. dwStatus = TW32( GetNodeClusterState( NULL, &dwClusterState ) ); if ( dwStatus != ERROR_SUCCESS ) { TraceFlow1( "Error %#x occurred trying to determine the installation state of this node.", dwStatus ); LogMsg( "Error %#x occurred trying to determine the installation state of this node.", dwStatus ); hr = HRESULT_FROM_WIN32( dwStatus ); goto Cleanup; } // if : GetClusterState() failed // Check if this node is part of a cluster. if ( ( dwClusterState != ClusterStateNotRunning ) && ( dwClusterState != ClusterStateRunning ) ) { TraceFlow( "This node is not part of a cluster - no cleanup is necessary." ); LogMsg( "This node is not part of a cluster - no cleanup is necessary." ); goto Cleanup; } // if: this node is not part of a cluster // // Set a registry value indicating that this node has been evicted. // If, for some reason, the cleanup could not be completed, the cluster // service will check this flag the next time it comes up and restarts // cleanup. // dwStatus = TW32( RegOpenKeyEx( HKEY_LOCAL_MACHINE , CLUSREG_KEYNAME_NODE_DATA , 0 , KEY_ALL_ACCESS , &hNodeStateKey ) ); if ( dwStatus != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( dwStatus ); LogMsg( "Error %#08x occurred trying to open a registry key to set a value indicating that this node has been evicted.", hr ); TraceFlow1( "Error %#08x occurred trying to open a registry key to set a value indicating that this node has been evicted.", hr ); goto Cleanup; } // if: RegOpenKeyEx() has failed dwStatus = TW32( RegSetValueEx( hNodeStateKey , CLUSREG_NAME_EVICTION_STATE , 0 , REG_DWORD , reinterpret_cast< const BYTE * >( &dwEvictState ) , sizeof( dwEvictState ) ) ); if ( dwStatus != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( dwStatus ); LogMsg( "Error %#08x occurred trying to set a registry value indicating that this node has been evicted.", hr ); TraceFlow1( "Error %#08x occurred trying to set a registry value indicating that this node has been evicted.", hr ); goto Cleanup; } // if: RegSetValueEx() has failed // Commit the post configuration steps first hr = THR( ppcmIn->CommitChanges( peccmrIn, piccciIn ) ); if ( FAILED( hr ) ) { TraceFlow1( "Error %#x occurred calling IPostCfgManager::CommitChanges().", hr ); LogMsg( "Error %#x occurred during the post configuration step of cleanup.", hr); goto Cleanup; } // if: post configuration failed TraceFlow( "IPostCfgManager::CommitChanges() completed successfully during cleanup." ); hr = THR( piccbcaIn->SetCleanup() ); if ( FAILED( hr ) ) { TraceFlow1( "Error %#x occurred calling IClusCfgBaseCluster::SetCleanup().", hr ); LogMsg( "Error %#x occurred initiating cleanup of the base cluster.", hr); goto Cleanup; } // if: SetCleanup() failed // Initiate the cleanup hr = THR( piccbcaIn->Commit() ); if ( FAILED( hr ) ) { TraceFlow1( "Error %#x occurred calling IClusCfgBaseCluster::CommitChanges().", hr ); LogMsg( "Error %#x occurred trying to cleanup the base cluster.", hr); goto Cleanup; } // if: base cluster cleanup failed TraceFlow( "Base cluster successfully cleaned up." ); // If we are here, then cleanup has completed successfully. If some other process is waiting // for cleanup to complete, release that process by signaling an event. { // Open the event. Note, if this event does not already exist, then it means that nobody is // waiting on this event. So, it is ok for OpenEvent to fail. heventCleanupComplete = OpenEvent( EVENT_ALL_ACCESS, FALSE, SUCCESSFUL_CLEANUP_EVENT_NAME ); if ( heventCleanupComplete == NULL ) { dwStatus = GetLastError(); TraceFlow1( "Status %#x was returned trying to open the cleanup completion event. This just means that no process is waiting on this event.", dwStatus ); LogMsg( "Status %#x was returned trying to open the cleanup completion event. This just means that no process is waiting on this event.", dwStatus ); goto Cleanup; } // if: OpenEvent() failed if ( PulseEvent( heventCleanupComplete ) == FALSE ) { // Error, but not fatal. hr should still be S_OK. dwStatus = TW32( GetLastError() ); TraceFlow1( "Error %#x occurred trying to pulse the cleanup completion event. This is not a fatal error.", dwStatus ); LogMsg( "Error %#x occurred trying to pulse the cleanup completion event. This is not a fatal error.", dwStatus ); goto Cleanup; } // if: PulseEvent() failed TraceFlow( "Cleanup completion event has been set." ); } Cleanup: if ( heventCleanupComplete == NULL ) { CloseHandle( heventCleanupComplete ); } // if: we had opened the cleanup complete event if ( hsCleanupLock != NULL ) { if ( fLockAcquired ) { ReleaseSemaphore( hsCleanupLock, 1, NULL ); LogMsg( "Cleanup lock released." ); TraceFlow( "Cleanup lock released." ); } // if: we have acquired the semaphore but not released it yet CloseHandle( hsCleanupLock ); } // if: we had created a cleanup lock if ( hNodeStateKey != NULL ) { RegCloseKey( hNodeStateKey ); } // if: we had opened the node state registry key HRETURN( hr ); } //*** CClusCfgServer::HrEvictedFromCluster ////////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrHasNodeBeenEvicted // // Description: // Has this node been evicted? // // Arguments: // // // Return Value: // S_OK // The node needs to be cleanedup. // // S_FALSE // The node does not need to be cleanup. // // Win32 error as HRESULT. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrHasNodeBeenEvicted( void ) { TraceFunc( "" ); HRESULT hr = S_FALSE; DWORD sc; DWORD dwClusterState; BOOL fEvicted = false; sc = TW32( GetNodeClusterState( NULL, &dwClusterState ) ); if ( sc != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( sc ); goto Cleanup; } // if : GetClusterState() failed // // If the cluster service is not running then we need to check if we should // clean it up or not. // if ( dwClusterState == ClusterStateNotRunning ) { sc = TW32( ClRtlHasNodeBeenEvicted( &fEvicted ) ); if ( sc != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( sc ); goto Cleanup; } // if: if ( fEvicted ) { hr = S_OK; } // if: } // if: Cleanup: HRETURN( hr ); } //*** CClusCfgServer::HrHasNodeBeenEvicted ///////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrCleanUpNode // // Description: // Cleanup this node because it was evicted. // // Arguments: // None. // // Return Value: // S_OK // Success. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrCleanUpNode( void ) { TraceFunc( "" ); HRESULT hr = S_OK; IClusCfgEvictCleanup * pcceEvict = NULL; hr = THR( CoCreateInstance( CLSID_ClusCfgEvictCleanup , NULL , CLSCTX_LOCAL_SERVER , __uuidof( pcceEvict ) , reinterpret_cast< void ** >( &pcceEvict ) ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: the ClusCfgEvictCleanup object could not be created hr = THR( pcceEvict->CleanupLocalNode( 0 ) ); // 0 means "cleanup immediately" if ( FAILED( hr ) ) { goto Cleanup; } // if: an error occurred during cleanup Cleanup: if ( pcceEvict != NULL ) { pcceEvict->Release(); } // if: HRETURN( hr ); } //*** CClusCfgServer::HrCleanUpNode ///////////////////////////////////////////////////////////////////////////// //++ // // CClusCfgServer::HrCreateClusterNodeInfo // // Description: // Create the cluster node info object and store it in the member // variable. // // Arguments: // None. // // Return Value: // S_OK // Success. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CClusCfgServer::HrCreateClusterNodeInfo( void ) { TraceFunc( "" ); Assert( m_punkNodeInfo == NULL ); HRESULT hr = S_OK; hr = THR( CClusCfgNodeInfo::S_HrCreateInstance( &m_punkNodeInfo ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: m_punkNodeInfo = TraceInterface( L"CClusCfgNodeInfo", IUnknown, m_punkNodeInfo, 1 ); hr = THR( HrSetInitialize( m_punkNodeInfo, m_picccCallback, m_lcid ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( HrSetWbemServices( m_punkNodeInfo, m_pIWbemServices ) ); Cleanup: HRETURN( hr ); } //*** CClusCfgServer::HrCreateClusterNodeInfo