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.
 
 
 
 
 
 

429 lines
16 KiB

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999-2002 Microsoft Corporation
//
// Module Name:
// CNode.cpp
//
// Description:
// Contains the definition of the CNode class.
//
// Maintained By:
// David Potter (DavidP) 14-JU-2001
// Vij Vasu (Vvasu) 08-MAR-2000
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
// The precompiled header.
#include "Pch.h"
// The header for this file
#include "CNode.h"
// For the CRegistryKey class
#include "CRegistryKey.h"
// For the CStr class
#include "CStr.h"
//////////////////////////////////////////////////////////////////////////////
// Macros
//////////////////////////////////////////////////////////////////////////////
// Names of the sections in the main INF file which deal with node configuration
// and cleanup.
#define NODE_CONFIG_INF_SECTION L"Node_Create"
#define NODE_CLEANUP_INF_SECTION L"Node_Cleanup"
// Registry key storing the list of connections for the cluster administrator
#define CLUADMIN_CONNECTIONS_KEY_NAME L"Software\\Microsoft\\Cluster Administrator\\Connections"
// Name of the registry value storing the list of connections for the cluster administrator
#define CLUADMIN_CONNECTIONS_VALUE_NAME L"Connections"
//////////////////////////////////////////////////////////////////////////////
//++
//
// CNode::CNode
//
// Description:
// Constructor of the CNode class
//
// Arguments:
// pbcaParentActionIn
// Pointer to the base cluster action of which this action is a part.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CAssert
// If the parameters are incorrect.
//
// Any exceptions thrown by underlying functions
//
//--
//////////////////////////////////////////////////////////////////////////////
CNode::CNode(
CBaseClusterAction * pbcaParentActionIn
)
: m_pbcaParentAction( pbcaParentActionIn )
, m_fChangedConnectionsList( false )
{
TraceFunc( "" );
if ( m_pbcaParentAction == NULL)
{
LogMsg( "[BC] Pointers to the parent action is NULL. Throwing an exception." );
THROW_ASSERT(
E_INVALIDARG
, "CNode::CNode() => Required input pointer in NULL"
);
} // if: the parent action pointer is NULL
TraceFuncExit();
} //*** CNode::CNode
//////////////////////////////////////////////////////////////////////////////
//++
//
// CNode::~CNode
//
// Description:
// Destructor of the CNode class.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by underlying functions
//
//--
//////////////////////////////////////////////////////////////////////////////
CNode::~CNode( void )
{
TraceFunc( "" );
TraceFuncExit();
} //*** CNode::~CNode
//////////////////////////////////////////////////////////////////////////////
//++
//
// CNode::Configure
//
// Description:
// Make the changes that need to be made when a node becomes part of a
// cluster.
//
// Arguments:
// rcstrClusterNameIn
// Name of the cluster being configured.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CRuntimeError
// If any of the APIs fail.
//
// Any that are thrown by the underlying functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CNode::Configure( const CStr & rcstrClusterNameIn )
{
TraceFunc( "" );
WCHAR * pszConnectionsValue = NULL;
DWORD cbConnectionsValueSize = 0;
DWORD cchOldListLen = 0;
CRegistryKey rkConnectionsKey;
//
// Validate the parameter
//
if ( rcstrClusterNameIn.FIsEmpty() )
{
LogMsg( "[BC] The name of the cluster is empty. Throwing an exception." );
THROW_ASSERT( E_INVALIDARG, "The name of the cluster cannot be empty." );
} // if: the cluster name is not valid
LogMsg( "[BC] Attempting to make miscellaneous changes to the node." );
// Process the registry keys.
if ( SetupInstallFromInfSection(
NULL // optional, handle of a parent window
, m_pbcaParentAction->HGetMainInfFileHandle() // handle to the INF file
, NODE_CONFIG_INF_SECTION // name of the Install section
, SPINST_REGISTRY // which lines to install from section
, NULL // optional, key for registry installs
, NULL // optional, path for source files
, NULL // optional, specifies copy behavior
, NULL // optional, specifies callback routine
, NULL // optional, callback routine context
, NULL // optional, device information set
, NULL // optional, device info structure
) == FALSE
)
{
DWORD sc = TW32( GetLastError() );
LogMsg( "[BC] Error %#08x returned from SetupInstallFromInfSection() while trying to make miscellaneous changes to the node. Throwing an exception.", sc );
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_NODE_CONFIG );
} // if: SetupInstallFromInfSection failed
//
// Add the name of the cluster that this node is a part of to the list of connections
// that will be opened when the cluster administrator is started on this node.
// The list of connections is a comma separated list of cluster names.
//
LogMsg( "[BC] Adding the cluster name '%s' to the list of cluadmin connections.", rcstrClusterNameIn.PszData() );
// Reset the state.
m_fChangedConnectionsList = false;
m_sszOldConnectionsList.PRelease();
LogMsg( "[BC] Trying to read the existing Cluster Administrator remembered connections list." );
// Open the cluster administrator connections key. Create it if it does not exist.
rkConnectionsKey.CreateKey(
HKEY_CURRENT_USER
, CLUADMIN_CONNECTIONS_KEY_NAME
);
try
{
// Try and get the current value
rkConnectionsKey.QueryValue(
CLUADMIN_CONNECTIONS_VALUE_NAME
, reinterpret_cast< LPBYTE * >( &pszConnectionsValue )
, &cbConnectionsValueSize
);
} // try: to read the "Connections" value
catch( CRuntimeError & crte )
{
// Check if this error occurred because the value did not exist
if ( crte.HrGetErrorCode() == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) )
{
LogMsg( "[BC] The registry value '%s' does not exist. This is ok and is not an error.", CLUADMIN_CONNECTIONS_VALUE_NAME );
cchOldListLen = 0;
} // if: the value does not exist
else
{
throw;
} // else: something else is wrong - rethrow the exception
} // catch: the run time error that occurred
// Number of characters in the old list, including the terminating NULL.
cchOldListLen = cbConnectionsValueSize / sizeof( *pszConnectionsValue );
if ( cchOldListLen <= 1 )
{
LogMsg( "[BC] There are no existing Cluster Administrator remembered connections. Creating a new list with just one name in it." );
// Write the cluster name to the value
rkConnectionsKey.SetValue(
CLUADMIN_CONNECTIONS_VALUE_NAME
, REG_SZ
, reinterpret_cast< const BYTE * >( rcstrClusterNameIn.PszData() )
, ( rcstrClusterNameIn.NGetLen() + 1 ) * sizeof( WCHAR )
);
// We have changed the connections list.
m_fChangedConnectionsList = true;
} // if: there are no existing connections
else
{
WCHAR * pszSubString = NULL;
bool fIsInList = false;
LogMsg( "[BC] The existing list of Cluster Administrator remembered connections is '%s'.", pszConnectionsValue );
//
// Is the cluster name already in the list of connections?
//
pszSubString = wcsstr( pszConnectionsValue, rcstrClusterNameIn.PszData() );
while ( pszSubString != NULL )
{
//
// The cluster name is a substring of the list.
// Make sure that the cluster name is not a proper substring of an cluster name already in the list.
//
if ( (
( pszSubString == pszConnectionsValue ) // the substring was found at the beginning of the string
|| ( *( pszSubString - 1 ) == L',' ) // or the character before the substring is a comma
) // AND
&& ( ( *( pszSubString + rcstrClusterNameIn.NGetLen() ) == L'\0' ) // the character after the substring is a '\0'
|| ( *( pszSubString + rcstrClusterNameIn.NGetLen() ) == L',' ) // or character after the substring is a comma
)
)
{
fIsInList = true;
break;
} // if: the cluster name is not a proper substring of a cluster name that is already in the list
// Continue searching.
pszSubString = wcsstr( pszSubString + rcstrClusterNameIn.NGetLen(), rcstrClusterNameIn.PszData() );
} // while: the cluster name is a substring of the list of existing connections
if ( fIsInList )
{
// Nothing more to be done.
LogMsg( "[BC] The '%s' cluster is already in the list of remembered Cluster Administrator connections.", rcstrClusterNameIn.PszData() );
goto Cleanup;
} // if: the cluster name is already in the list
LogMsg( "[BC] The '%s' cluster is not in the list of remembered Cluster Administrator connections.", rcstrClusterNameIn.PszData() );
// Store the current value in the member variable for restoration in case of error.
m_sszOldConnectionsList.Assign( pszConnectionsValue );
// Set the new connections value.
{
// Define a string to hold the new connections value. Preallocate its buffer.
CStr strNewConnectionsValue(
cchOldListLen // length of the old list ( including terminating '\0' )
+ 1 // for the comma
+ rcstrClusterNameIn.NGetLen() // length of the cluster name( including terminating '\0' )
);
//
// Construct the new list
//
strNewConnectionsValue = rcstrClusterNameIn;
strNewConnectionsValue += L",";
strNewConnectionsValue += m_sszOldConnectionsList.PMem();
LogMsg( "[BC] Writing the new list of remembered Cluster Administrator connections '%s'.", strNewConnectionsValue.PszData() );
// Write the new list.
rkConnectionsKey.SetValue(
CLUADMIN_CONNECTIONS_VALUE_NAME
, REG_SZ
, reinterpret_cast< const BYTE * >( strNewConnectionsValue.PszData() )
, ( strNewConnectionsValue.NGetLen() + 1 ) * sizeof( WCHAR )
);
// We have changed the connections list.
m_fChangedConnectionsList = true;
}
} // else: there are existing connections
Cleanup:
LogMsg( "[BC] The changes were made successfully." );
TraceFuncExit();
} //*** CNode::Configure
//////////////////////////////////////////////////////////////////////////////
//++
//
// CNode::Cleanup
//
// Description:
// Clean up the changes made to this node when it became part of a cluster.
// Note that the changes made during Configure() are not really undone here -
// we just bring the node back to an acceptable state. This is because,
// without a transactional registry, it will be very diffult to get
// the registry back to the exact state it was in before Configure() was
// called.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any that are thrown by the underlying functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CNode::Cleanup( void )
{
TraceFunc( "" );
LogMsg( "[BC] Attempting to cleanup changes made when this node was made a part of a cluster." );
// Process the registry keys.
if ( SetupInstallFromInfSection(
NULL // optional, handle of a parent window
, m_pbcaParentAction->HGetMainInfFileHandle() // handle to the INF file
, NODE_CLEANUP_INF_SECTION // name of the Install section
, SPINST_REGISTRY // which lines to install from section
, NULL // optional, key for registry installs
, NULL // optional, path for source files
, NULL // optional, specifies copy behavior
, NULL // optional, specifies callback routine
, NULL // optional, callback routine context
, NULL // optional, device information set
, NULL // optional, device info structure
) == FALSE
)
{
DWORD sc = TW32( GetLastError() );
LogMsg( "[BC] Error %#08x was returned from SetupInstallFromInfSection() while trying to clean up miscellaneous changes. Throwing an exception.", sc );
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_NODE_CLEANUP );
} // if: SetupInstallFromInfSection failed
if ( m_fChangedConnectionsList )
{
LogMsg( "[BC] Restoring the list of remembered Cluster Administrator connections to '%s'", m_sszOldConnectionsList.PMem() );
// Open the cluster administrator connections key.
CRegistryKey rkConnectionsKey(
HKEY_CURRENT_USER
, CLUADMIN_CONNECTIONS_KEY_NAME
);
// If there wasn't a previous value, delete the value we set.
// Otherwise, set the value back to the old value.
if ( m_sszOldConnectionsList.PMem() == NULL )
{
// Delete the value.
rkConnectionsKey.DeleteValue( CLUADMIN_CONNECTIONS_VALUE_NAME );
} // if: no old value existed
else
{
// Write the old list back.
rkConnectionsKey.SetValue(
CLUADMIN_CONNECTIONS_VALUE_NAME
, REG_SZ
, reinterpret_cast< const BYTE * >( m_sszOldConnectionsList.PMem() )
, ( (UINT) wcslen( m_sszOldConnectionsList.PMem() ) + 1 ) * sizeof( WCHAR )
);
} // else: old value existed
} // if: we changed the list of cluadmin connections
LogMsg( "[BC] The cleanup was successfully." );
TraceFuncExit();
} //*** CNode::Cleanup