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.
649 lines
17 KiB
649 lines
17 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Module Name:
|
|
// CIISClusCfg.cpp
|
|
//
|
|
// Description:
|
|
// Main implementation for the IClusCfgStartupListener sample program.
|
|
//
|
|
// Maintained By:
|
|
// Galen Barbee (GalenB) 24-SEP-2001
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Include Files
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Pch.h"
|
|
#include "IISClusCfg.h"
|
|
|
|
#include <lm.h> // Required for the references in this module.
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Globals
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static PCWSTR g_apszResourceTypesToDelete[] =
|
|
{
|
|
L"IIS Server Instance",
|
|
L"SMTP Server Instance",
|
|
L"NNTP Server Instance",
|
|
L"IIS Virtual Root",
|
|
|
|
//
|
|
// KB: 18-JUN-2002 GalenB
|
|
//
|
|
// Since we don't think we are going to be sending this component to
|
|
// IIS it is simpler and faster to add this non IIS resource type to this
|
|
// component. If this component is ever handed off to IIS then we
|
|
// need to remove this resource type from this table.
|
|
//
|
|
|
|
L"Time Service",
|
|
NULL
|
|
};
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CIISClusCfg class
|
|
//
|
|
//***************************************************************************
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// static
|
|
// CIISClusCfg::S_HrCreateInstance
|
|
//
|
|
// Description:
|
|
// Create a CIISClusCfg instance.
|
|
//
|
|
// Arguments:
|
|
// riidIn - ID of the interface to return.
|
|
// ppunkOut - The IUnknown interface of the new object.
|
|
//
|
|
// Return Values:
|
|
// S_OK
|
|
// Success.
|
|
//
|
|
// E_POINTER
|
|
// ppunkOut was NULL.
|
|
//
|
|
// E_OUTOFMEMORY
|
|
// Not enough memory to create the object.
|
|
//
|
|
// other HRESULTs
|
|
// Object initialization failed.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CIISClusCfg::S_HrCreateInstance(
|
|
IUnknown ** ppunkOut
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CIISClusCfg * pmsl = NULL;
|
|
|
|
if ( ppunkOut == NULL )
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
pmsl = new CIISClusCfg();
|
|
if ( pmsl == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
} // if: error allocating object
|
|
|
|
hr = pmsl->HrInit();
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: HrInit() failed
|
|
|
|
hr = pmsl->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( ppunkOut ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: QI failed
|
|
|
|
Cleanup:
|
|
|
|
if ( pmsl != NULL )
|
|
{
|
|
pmsl->Release();
|
|
} // if:
|
|
|
|
return hr;
|
|
|
|
} //*** CIISClusCfg::S_HrCreateInstance
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CIISClusCfg::S_HrRegisterCatIDSupport
|
|
//
|
|
// Description:
|
|
// Registers/unregisters this class with the categories that it
|
|
// belongs to.
|
|
//
|
|
// Arguments:
|
|
// picrIn
|
|
// Used to register/unregister our CATID support.
|
|
//
|
|
// fCreateIn
|
|
// When true we are registering the server. When false we are
|
|
// un-registering the server.
|
|
//
|
|
// Return Values:
|
|
// S_OK
|
|
// Success.
|
|
//
|
|
// E_INVALIDARG
|
|
// The passed in ICatRgister pointer was NULL.
|
|
//
|
|
// other HRESULTs
|
|
// Registration/Unregistration failed.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CIISClusCfg::S_HrRegisterCatIDSupport(
|
|
ICatRegister * picrIn,
|
|
BOOL fCreateIn
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CATID rgCatIds[ 2 ];
|
|
|
|
if ( picrIn == NULL )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
rgCatIds[ 0 ] = CATID_ClusCfgStartupListeners;
|
|
rgCatIds[ 1 ] = CATID_ClusCfgEvictListeners;
|
|
|
|
if ( fCreateIn )
|
|
{
|
|
hr = picrIn->RegisterClassImplCategories( CLSID_IISClusCfg, RTL_NUMBER_OF( rgCatIds ), rgCatIds );
|
|
} // if: registering
|
|
|
|
//
|
|
// KB: 24-SEP-2001 GalenB
|
|
//
|
|
// This code is not needed since this component has been temporarily placed in ClusCfgSrv.dll. Our
|
|
// cleanup code does a tree delete the whole registry key and that cleanups up the CATID stuff.
|
|
//
|
|
|
|
/*
|
|
else
|
|
{
|
|
hr = picrIn->UnRegisterClassImplCategories( CLSID_IISClusCfg, ARRAYSIZE( rgCatIds ), rgCatIds );
|
|
} // else: unregistering
|
|
*/
|
|
|
|
Cleanup:
|
|
|
|
return hr;
|
|
|
|
} //*** CIISClusCfg::S_HrRegisterCatIDSupport
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CIISClusCfg::CIISClusCfg
|
|
//
|
|
// Description:
|
|
// Constructor of CIISClusCfg. Initializes m_cRef to 1 to avoid
|
|
// problems when called from DllGetClassObject. Increments the global
|
|
// object count to avoid DLL unload.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CIISClusCfg::CIISClusCfg( void )
|
|
: m_cRef( 1 )
|
|
{
|
|
//
|
|
// Increment the count of components in memory so the DLL hosting this
|
|
// object cannot be unloaded.
|
|
//
|
|
|
|
InterlockedIncrement( &g_cObjects );
|
|
|
|
} //*** CIISClusCfg::CIISClusCfg
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CIISClusCfg::~CIISClusCfg
|
|
//
|
|
// Description:
|
|
// Destructor of CIISClusCfg. Decrements the global object count.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CIISClusCfg::~CIISClusCfg( void )
|
|
{
|
|
// There's going to be one less component in memory.
|
|
// Decrement component count.
|
|
InterlockedDecrement( &g_cObjects );
|
|
|
|
} //*** CIISClusCfg::~CIISClusCfg
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// IUnknown interface
|
|
//
|
|
//***************************************************************************
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// [IUnknown]
|
|
// CIISClusCfg::AddRef
|
|
//
|
|
// Description:
|
|
// Increment the reference count of this object by one.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// The new reference count.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_( ULONG )
|
|
CIISClusCfg::AddRef( void )
|
|
{
|
|
return InterlockedIncrement( &m_cRef );
|
|
|
|
} //*** CIISClusCfg::AddRef
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// [IUnknown]
|
|
// CIISClusCfg::Release
|
|
//
|
|
// Description:
|
|
// Decrement the reference count of this object by one.
|
|
// If this reaches 0, the object will be automatically deleted.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// The new reference count.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_( ULONG )
|
|
CIISClusCfg::Release( void )
|
|
{
|
|
LONG cRef;
|
|
|
|
cRef = InterlockedDecrement( &m_cRef );
|
|
if ( cRef == 0 )
|
|
{
|
|
delete this;
|
|
} // if:
|
|
|
|
return cRef;
|
|
|
|
} //*** CIISClusCfg::Release
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// [IUnknown]
|
|
// CIISClusCfg::QueryInterface
|
|
//
|
|
// Description:
|
|
// Query this object for the passed in interface.
|
|
// This class implements the following interfaces:
|
|
//
|
|
// IUnknown
|
|
// IClusCfgStarutpListener
|
|
//
|
|
// Arguments:
|
|
// riidIn - Id of interface requested.
|
|
// ppvOut - Pointer to the requested interface. NULL if unsupported.
|
|
//
|
|
// Return Value:
|
|
// S_OK - If the interface is available on this object.
|
|
// E_POINTER - ppvOut was NULL.
|
|
// E_NOINTERFACE - If the interface is not available.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CIISClusCfg::QueryInterface(
|
|
REFIID riidIn
|
|
, void ** ppvOut
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Validate arguments.
|
|
//
|
|
|
|
if ( ppvOut == NULL )
|
|
{
|
|
hr = E_POINTER;
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Handle known interfaces.
|
|
//
|
|
|
|
if ( IsEqualIID( riidIn, IID_IUnknown ) )
|
|
{
|
|
//
|
|
// We static_cast to IClusCfgStartupListener* to avoid conflicts
|
|
// if this class should inherit IUnknown from more than one
|
|
// interface.
|
|
//
|
|
|
|
*ppvOut = static_cast< IClusCfgStartupListener * >( this );
|
|
} // if:
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgStartupListener ) )
|
|
{
|
|
*ppvOut = static_cast< IClusCfgStartupListener * >( this );
|
|
} // else if:
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgEvictListener ) )
|
|
{
|
|
*ppvOut = static_cast< IClusCfgEvictListener * >( this );
|
|
} // else if:
|
|
else
|
|
{
|
|
*ppvOut = NULL;
|
|
hr = E_NOINTERFACE;
|
|
} // else:
|
|
|
|
//
|
|
// Add a reference to the interface if successful.
|
|
//
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
//
|
|
// We will return an interface pointer, so the reference counter needs to
|
|
// be incremented.
|
|
//
|
|
|
|
((IUnknown *) *ppvOut)->AddRef();
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
return hr;
|
|
|
|
} //*** CIISClusCfg::QueryInterface
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CIISClusCfg::HrCleanupResourceTypes
|
|
//
|
|
// Description:
|
|
// This function will clean up any resource types leftover from a Windows 2000
|
|
// cluster installation which are no longer supported.
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Operation completed successfully.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CIISClusCfg::HrCleanupResourceTypes( void )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD sc = ERROR_SUCCESS;
|
|
HCLUSTER hCluster = NULL;
|
|
WCHAR szClusterName[ MAX_PATH ];
|
|
DWORD cchClusterName = RTL_NUMBER_OF( szClusterName );
|
|
CLUSTERVERSIONINFO clusterInfo;
|
|
PCWSTR * ppszResType;
|
|
|
|
//
|
|
// Open the local cluster service. We can do this since we are running on the
|
|
// node that evicted the node, not the node that was evicted...
|
|
//
|
|
|
|
hCluster = OpenCluster( NULL );
|
|
if ( hCluster == NULL )
|
|
{
|
|
sc = GetLastError();
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
LogMsg( L"[IISCLUSCFG] Error opening connection to local cluster service. (hr = %#08x)", hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Check if the entire cluster is running Windows Server 2003 (NT 5.1).
|
|
//
|
|
|
|
sc = GetClusterInformation( hCluster, szClusterName, &cchClusterName, &clusterInfo );
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
LogMsg( L"[IISCLUSCFG] Error getting the cluster version information. (hr = %#08x)", hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// If the whole cluster is Windows Server 2003, then the highest version will be NT51, and
|
|
// the lowest version will be NT5. This is because ClusterHighestVersion is set to the
|
|
// min of the highest version that all nodes can "speak", and ClusterLowestVersion is set to the
|
|
// max of the lowest version that all nodes can speak.
|
|
//
|
|
|
|
if ( ( CLUSTER_GET_MAJOR_VERSION( clusterInfo.dwClusterHighestVersion ) == NT51_MAJOR_VERSION )
|
|
&& ( CLUSTER_GET_MAJOR_VERSION( clusterInfo.dwClusterLowestVersion ) == NT5_MAJOR_VERSION ) )
|
|
{
|
|
//
|
|
// We don't need to enumerate resources to make sure
|
|
// that no IIS resources exist before we delete the resource types. The deletion
|
|
// of a resource type will fail if resources of that type exist.
|
|
//
|
|
|
|
for ( ppszResType = g_apszResourceTypesToDelete; *ppszResType != NULL; ++ppszResType )
|
|
{
|
|
//
|
|
// ERROR_SUCCESS: successful deletion.
|
|
//
|
|
// ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND: no problem. The resource type didn't exist,
|
|
// so this must be a fresh Windows Server 2003 installation, not an upgrade.
|
|
//
|
|
// ERROR_DIR_NOT_EMPTY: a resource of that type exists. In this case we require manual
|
|
// intervention by an administrator.
|
|
|
|
sc = DeleteClusterResourceType( hCluster, *ppszResType );
|
|
if ( sc == ERROR_SUCCESS )
|
|
{
|
|
LogMsg( L"[IISCLUSCFG] Successfully deleted resource type \"%ws\". (hr = %#08x)", *ppszResType, HRESULT_FROM_WIN32( sc ) );
|
|
continue;
|
|
} // if: resource type was deleted.
|
|
else if ( sc == ERROR_DIR_NOT_EMPTY )
|
|
{
|
|
LogMsg( L"[IISCLUSCFG] Could not delete resource type \"%ws\" because there are resources of this type. Trying the next resource type in the table... (hr = %#08x)", *ppszResType, HRESULT_FROM_WIN32( sc ) );
|
|
continue;
|
|
} // else if: resources of this type exist.
|
|
else if ( sc == ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND )
|
|
{
|
|
LogMsg( L"[IISCLUSCFG] Could not delete resource type \"%ws\" because the resource type was not found. Trying the next resource type in the table... (hr = %#08x)", *ppszResType, HRESULT_FROM_WIN32( sc ) );
|
|
continue;
|
|
} // else if: resource type was not found.
|
|
else
|
|
{
|
|
//
|
|
// We failed to delete the resource type.
|
|
//
|
|
|
|
//
|
|
// Keep track of the last failure.
|
|
// But don't bail out. Keep deleting the other types.
|
|
//
|
|
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
LogMsg( L"[IISCLUSCFG] Unexpected error deleting resource type \"%ws\". Trying the next resource type in the table... (hr = %#08x)", *ppszResType, hr );
|
|
} // else: some unknown error.
|
|
} // for: each resource type in the table.
|
|
} // if: this cluster is 100% Windows Server 2003.
|
|
|
|
Cleanup:
|
|
|
|
if ( hCluster != NULL )
|
|
{
|
|
CloseCluster( hCluster );
|
|
} // if:
|
|
|
|
return hr;
|
|
|
|
} //*** CIISClusCfg::HrCleanupResourceTypes
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// [IClusCfgStartupListener]
|
|
// CIISClusCfg::Notify
|
|
//
|
|
// Description:
|
|
// This function gets called just after the cluster service has started.
|
|
//
|
|
// Arguments:
|
|
// punkIn
|
|
// Pointer to a COM object that implements
|
|
// IClusCfgResourceTypeCreate.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Operation completed successfully.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CIISClusCfg::Notify(
|
|
IUnknown * /*unused: punkIn*/ )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LogMsg( L"[IISCLUSCFG] Entering startup notify... (hr = %#08x)", hr );
|
|
|
|
hr = HrCleanupResourceTypes();
|
|
|
|
LogMsg( L"[IISCLUSCFG] Leaving startup notify... (hr = %#08x)", hr );
|
|
|
|
return hr;
|
|
|
|
} //*** IISClusCfg::Notify
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// [IClusCfgEvictListener]
|
|
// CIISClusCfg::EvictNotify
|
|
//
|
|
// Description:
|
|
// This function gets called after a node has been evicted.
|
|
//
|
|
// Arguments:
|
|
// pcszNodeNameIn
|
|
// The name of the node that has been evicted.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Operation completed successfully.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CIISClusCfg::EvictNotify(
|
|
PCWSTR /* unused: pcszNodeNameIn */ )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LogMsg( L"[IISCLUSCFG] Entering evict cleanup notify... (hr = %#08x)", hr );
|
|
|
|
hr = HrCleanupResourceTypes();
|
|
|
|
LogMsg( L"[IISCLUSCFG] Leaving evict cleanup notify... (hr = %#08x)", hr );
|
|
|
|
return hr;
|
|
|
|
} //*** IISClusCfg::EvictNotify
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// Private methods
|
|
//
|
|
//***************************************************************************
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CIISClusCfg::HrInit
|
|
//
|
|
// Description:
|
|
// Initialize this component.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// S_OK - Operation completed successfully.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CIISClusCfg::HrInit( void )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// IUnknown
|
|
//Assert( m_cRef == 1 );
|
|
|
|
return hr;
|
|
|
|
} //*** CIISClusCfg::HrInit
|