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.
 
 
 
 
 
 

1863 lines
47 KiB

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2002 Microsoft Corporation
//
// Module Name:
// ClusterUtils.h
//
// Description:
// This file contains the implementations of the ClusterUtils
// functions.
//
// Maintained By:
// Galen Barbee (GalenB) 13-JUL-2001
//
//////////////////////////////////////////////////////////////////////////////
#include "Pch.h"
#include <clusrtl.h>
#include <PropList.h>
#include <StatusReports.h>
#include <CommonStrings.h>
#include <ClusRPC.h>
#include <ClusVerp.h>
#include <initguid.h>
#define STACK_ARRAY_SIZE 256
// {DD1C1DE0-F39D-46ee-BFD1-07ABF7566705}
DEFINE_GUID( TASKID_Minor_HrCheckJoiningNodeVersion_RpcStringBindingComposeW,
0xdd1c1de0, 0xf39d, 0x46ee, 0xbf, 0xd1, 0x7, 0xab, 0xf7, 0x56, 0x67, 0x5);
// {62AF0964-4B32-4067-8BF1-8903FEC95A82}
DEFINE_GUID( TASKID_Minor_HrCheckJoiningNodeVersion_RpcBindingFromStringBindingW,
0x62af0964, 0x4b32, 0x4067, 0x8b, 0xf1, 0x89, 0x3, 0xfe, 0xc9, 0x5a, 0x82);
// {D8C0BA67-D079-45ca-A28C-C4C389DB389A}
DEFINE_GUID( TASKID_Minor_HrCheckJoiningNodeVersion_RpcBindingSetAuthInfoW,
0xd8c0ba67, 0xd079, 0x45ca, 0xa2, 0x8c, 0xc4, 0xc3, 0x89, 0xdb, 0x38, 0x9a);
// {110E29E4-2072-4916-BE66-BED556F12A7B}
DEFINE_GUID( TASKID_Minor_HrCheckJoiningNodeVersion_CsRpcGetJoinVersionData_Log,
0x110e29e4, 0x2072, 0x4916, 0xbe, 0x66, 0xbe, 0xd5, 0x56, 0xf1, 0x2a, 0x7b);
// {5EB1F008-1B49-4cf0-9FE1-B1BC8F76454A}
DEFINE_GUID( TASKID_Minor_HrCheckJoiningNodeVersion_CsRpcGetJoinVersionData,
0x5eb1f008, 0x1b49, 0x4cf0, 0x9f, 0xe1, 0xb1, 0xbc, 0x8f, 0x76, 0x45, 0x4a);
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrSeparateDomainAndName
//
// Description:
//
//
// Arguments:
// bstrNameIn
// pbstrDomainOut
// pbstrNameOut
//
// Return Value:
// S_OK - Success.
// E_INVALIDARG - Required input argument not specified.
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrSeparateDomainAndName(
BSTR bstrNameIn
, BSTR * pbstrDomainOut
, BSTR * pbstrNameOut
)
{
TraceFunc( "" );
Assert( bstrNameIn != NULL );
Assert( ( pbstrDomainOut != NULL )
|| ( pbstrNameOut != NULL )
);
HRESULT hr = S_OK;
WCHAR * psz = NULL;
psz = wcschr( bstrNameIn, L'.' );
if ( psz == NULL )
{
hr = THR( E_INVALIDARG );
goto Cleanup;
} // if:
if ( pbstrDomainOut != NULL )
{
psz++; // skip the .
*pbstrDomainOut = TraceSysAllocString( psz );
if ( *pbstrDomainOut == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if:
psz--; // reset back to .
} // if:
if ( pbstrNameOut != NULL )
{
*pbstrNameOut = TraceSysAllocStringLen( bstrNameIn, (UINT) ( psz - bstrNameIn ) );
if ( *pbstrNameOut == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if:
} // if:
Cleanup:
HRETURN ( hr );
} //*** HrSeparateDomainAndName
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrAppendDomainToName
//
// Description:
//
//
// Arguments:
// bstrNameIn
// bstrDomainIn
// pbstrDomainNameOut
//
// Return Value:
// S_OK - Success.
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrAppendDomainToName(
BSTR bstrNameIn
, BSTR bstrDomainIn
, BSTR * pbstrDomainNameOut
)
{
TraceFunc( "" );
Assert( bstrNameIn != NULL );
Assert( pbstrDomainNameOut != NULL );
HRESULT hr = S_OK;
size_t cchName = 0;
// Create a fully qualified node name
if ( bstrDomainIn != NULL )
{
cchName = wcslen( bstrNameIn ) + wcslen( bstrDomainIn ) + 1 + 1;
Assert( cchName <= MAXDWORD );
*pbstrDomainNameOut = TraceSysAllocStringLen( NULL, (UINT) cchName );
if ( *pbstrDomainNameOut == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if:
hr = THR( StringCchPrintfW( *pbstrDomainNameOut, cchName, L"%ws.%ws", bstrNameIn, bstrDomainIn ) );
} // if:
else
{
*pbstrDomainNameOut = TraceSysAllocString( bstrNameIn );
if ( *pbstrDomainNameOut == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if:
hr = S_FALSE;
} // else:
Cleanup:
HRETURN( hr );
} //*** HrAppendDomainToName
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrIsCoreResource
//
// Description:
// Determines whether the resource is a core resource.
//
// Arguments:
// hResourceIn
//
// Return Value:
// S_OK - Resource is a core resource.
// S_FALSE - Resource is not a core resource.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrIsCoreResource( HRESOURCE hResourceIn )
{
TraceFunc( "" );
Assert( hResourceIn );
HRESULT hr = S_FALSE;
DWORD sc;
DWORD dwFlags = 0;
DWORD cb;
sc = TW32( ClusterResourceControl( hResourceIn, NULL, CLUSCTL_RESOURCE_GET_FLAGS, NULL, 0, &dwFlags, sizeof( dwFlags ), &cb ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
if ( dwFlags & CLUS_FLAG_CORE )
{
hr = S_OK;
} // if:
Cleanup:
HRETURN( hr );
} //*** HrIsCoreResource
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrIsResourceOfType
//
// Description:
// Find out if a resource if of a specific type.
//
// Arguments:
// hResourceIn - Handle to the resource to check.
// pszResourceTypeIn - Resource type name.
//
// Return Value:
// S_OK - Resource is of specified type.
// S_FALSE - Resource is not of specified type.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrIsResourceOfType(
HRESOURCE hResourceIn
, const WCHAR * pszResourceTypeIn
)
{
TraceFunc( "" );
Assert( hResourceIn != NULL );
Assert( pszResourceTypeIn != NULL );
HRESULT hr = S_OK;
DWORD sc;
WCHAR * pszBuf = NULL;
size_t cchBuf = 65;
DWORD cb;
int idx;
pszBuf = new WCHAR [ cchBuf ];
if ( pszBuf == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if:
for ( idx = 0; idx < 2; idx++ )
{
sc = ClusterResourceControl( hResourceIn, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, pszBuf, (DWORD)( cchBuf * sizeof( WCHAR ) ), &cb );
if ( sc == ERROR_MORE_DATA )
{
delete [] pszBuf;
pszBuf = NULL;
cchBuf = ( cb / sizeof( WCHAR ) ) + 1; // add one in case cb is an odd size...
pszBuf = new WCHAR [ cchBuf ];
if ( pszBuf == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if:
continue;
} // if:
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( TW32( sc ) );
goto Cleanup;
} // if:
break;
} // for:
if ( wcsncmp( pszBuf, pszResourceTypeIn, cchBuf ) == 0 )
{
hr = S_OK;
} // if:
else
{
hr = S_FALSE;
} // else:
Cleanup:
delete [] pszBuf;
HRETURN( hr );
} //*** HrIsResourceOfType
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetIPAddressInfo
//
// Description:
//
//
// Arguments:
// hResourceIn
// pulIPAddress
// pulSubnetMask
// pbstrNetworkName
//
// Return Value:
// S_OK - Success.
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetIPAddressInfo(
HRESOURCE hResourceIn
, ULONG * pulIPAddress
, ULONG * pulSubnetMask
, BSTR * pbstrNetworkName
)
{
TraceFunc( "" );
Assert( hResourceIn != NULL );
Assert( pulIPAddress != NULL );
Assert( pulSubnetMask != NULL );
Assert( pbstrNetworkName != NULL );
HRESULT hr = S_OK;
DWORD sc;
CClusPropList cpl;
CLUSPROP_BUFFER_HELPER cpbh;
sc = TW32( cpl.ScGetResourceProperties( hResourceIn, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
sc = TW32( cpl.ScMoveToPropertyByName( L"Address" ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
cpbh = cpl.CbhCurrentValue();
Assert( cpbh.pSyntax->dw == CLUSPROP_SYNTAX_LIST_VALUE_SZ );
sc = TW32( ClRtlTcpipStringToAddress( cpbh.pStringValue->sz, pulIPAddress ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
sc = TW32( cpl.ScMoveToPropertyByName( L"SubnetMask" ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
cpbh = cpl.CbhCurrentValue();
Assert( cpbh.pSyntax->dw == CLUSPROP_SYNTAX_LIST_VALUE_SZ );
sc = TW32( ClRtlTcpipStringToAddress( cpbh.pStringValue->sz, pulSubnetMask ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
if ( pbstrNetworkName != NULL )
{
sc = TW32( cpl.ScMoveToPropertyByName( L"Network" ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
cpbh = cpl.CbhCurrentValue();
Assert( cpbh.pSyntax->dw == CLUSPROP_SYNTAX_LIST_VALUE_SZ );
*pbstrNetworkName = TraceSysAllocString( cpbh.pStringValue->sz );
if( *pbstrNetworkName == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
}
} // if: caller wants the network name
Cleanup:
HRETURN( hr );
} //*** HrGetIPAddressInfo
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrLoadCredentials
//
// Description:
// Set credentials for the cluscfg session from an existing cluster
// service.
//
// Arguments:
// bstrMachine
// piCCSC
//
// Return Value:
// S_OK - Success.
// S_FALSE -
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrLoadCredentials(
BSTR bstrMachine
, IClusCfgSetCredentials * piCCSC
)
{
TraceFunc( "" );
Assert( bstrMachine != NULL );
Assert( piCCSC != NULL );
HRESULT hr = S_FALSE;
SC_HANDLE schSCM = NULL;
SC_HANDLE schClusSvc = NULL;
DWORD sc;
DWORD cbpqsc = 128;
DWORD cbRequired;
QUERY_SERVICE_CONFIG * pqsc = NULL;
schSCM = OpenSCManager( bstrMachine, NULL, GENERIC_READ );
if ( schSCM == NULL )
{
sc = TW32( GetLastError() );
hr = HRESULT_FROM_WIN32( hr );
goto CleanUp;
} // if:
schClusSvc = OpenService( schSCM, L"ClusSvc", GENERIC_READ );
if ( schClusSvc == NULL )
{
sc = TW32( GetLastError() );
hr = HRESULT_FROM_WIN32( hr );
goto CleanUp;
} // if:
for ( ; ; )
{
pqsc = (QUERY_SERVICE_CONFIG *) TraceAlloc( 0, cbpqsc );
if ( pqsc == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto CleanUp;
} // if:
if ( ! QueryServiceConfig( schClusSvc, pqsc, cbpqsc, &cbRequired ) )
{
sc = GetLastError();
if ( sc == ERROR_INSUFFICIENT_BUFFER )
{
TraceFree( pqsc );
pqsc = NULL;
cbpqsc = cbRequired;
continue;
} // if:
else
{
TW32( sc );
hr = HRESULT_FROM_WIN32( sc );
goto CleanUp;
} // else:
} // if:
else
{
break;
} // else:
} // for:
hr = THR( piCCSC->SetDomainCredentials( pqsc->lpServiceStartName ) );
CleanUp:
if ( schClusSvc != NULL )
{
CloseServiceHandle( schClusSvc );
} // if:
if ( schSCM != NULL )
{
CloseServiceHandle( schSCM );
} // if:
TraceFree( pqsc );
HRETURN( hr );
} //*** HrLoadCredentials
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetNodeNameHostingResource
//
// Description:
// Get the name of the node hosting the cluster resource.
//
// Arguments:
// hClusterIn
// pbstrNodeName
//
// Return Value:
// S_OK - Success.
// S_FALSE -
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetNodeNameHostingResource(
HCLUSTER hClusterIn
, HRESOURCE hResourceIn
, BSTR * pbstrNameOut
)
{
TraceFunc( "" );
Assert( hClusterIn != NULL );
Assert( hResourceIn != NULL );
Assert( pbstrNameOut != NULL );
HRESULT hr = S_FALSE;
WCHAR * pszNodeBuffer = NULL;
DWORD cchNodeNameLen;
DWORD scLastError;
//
// Get the length of the node name.
//
cchNodeNameLen = 0;
GetClusterResourceState( hResourceIn, NULL, &cchNodeNameLen, NULL, NULL ); // Ignore the returned state.
scLastError = GetLastError();
if ( scLastError != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( TW32( scLastError ) );
goto Cleanup;
}
cchNodeNameLen++; // Increment for NULL.
pszNodeBuffer = new WCHAR[ cchNodeNameLen ];
if ( pszNodeBuffer == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
}
//
// Try it again, this time we should get the actual node name.
//
GetClusterResourceState( hResourceIn, pszNodeBuffer, &cchNodeNameLen, NULL, NULL ); // Ignore the returned state.
scLastError = GetLastError();
if ( scLastError != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( TW32( scLastError ) );
goto Cleanup;
}
//
// Alloc & assign a copy of the node name to the out arg.
//
*pbstrNameOut = TraceSysAllocString( pszNodeBuffer );
if ( pbstrNameOut == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
}
hr = S_OK;
Cleanup:
delete [] pszNodeBuffer;
HRETURN( hr );
} //*** HrGetNodeNameHostingResource
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetNodeNameHostingCluster
//
// Description:
// Get the name of the node hosting the cluster service...
//
// Arguments:
// hClusterIn
// pbstrNodeName
//
// Return Value:
// S_OK - Success.
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetNodeNameHostingCluster(
HCLUSTER hClusterIn
, BSTR * pbstrNodeName
)
{
TraceFunc( "" );
Assert( hClusterIn );
HRESULT hr = S_OK;
DWORD sc;
HCLUSENUM hEnum = NULL;
DWORD idx;
DWORD dwType;
WCHAR * psz = NULL;
DWORD cchpsz = 33;
HRESOURCE hRes = NULL;
hEnum = ClusterOpenEnum( hClusterIn, CLUSTER_ENUM_RESOURCE );
if ( hEnum == NULL )
{
sc = TW32( GetLastError() );
hr = HRESULT_FROM_WIN32( sc );
goto CleanUp;
} // if:
psz = new WCHAR [ cchpsz ];
if ( psz == NULL )
{
goto OutOfMemory;
} // if:
for ( idx = 0; ; )
{
sc = ClusterEnum( hEnum, idx, &dwType, psz, &cchpsz );
if ( sc == ERROR_MORE_DATA )
{
delete [] psz;
psz = NULL;
cchpsz++;
psz = new WCHAR [ cchpsz ];
if ( psz == NULL )
{
goto OutOfMemory;
} // if:
continue;
} // if:
if ( sc == ERROR_SUCCESS )
{
hRes = OpenClusterResource( hClusterIn, psz );
if ( hRes == NULL )
{
sc = TW32( GetLastError() );
hr = HRESULT_FROM_WIN32( sc );
goto CleanUp;
} // if:
hr = STHR( HrIsResourceOfType( hRes, L"Network Name" ) );
if ( FAILED( hr ) )
{
break;
} // if:
if ( hr == S_OK )
{
hr = THR( HrIsCoreResource( hRes ) );
if ( FAILED( hr ) )
{
break;
} // if:
if ( hr == S_OK )
{
hr = THR( HrGetNodeNameHostingResource( hClusterIn, hRes, pbstrNodeName ) );
if ( FAILED( hr ) )
{
break;
} // if:
else if( hr == S_OK )
{
goto CleanUp;
}
} // if:
} // if:
CloseClusterResource( hRes );
hRes = NULL;
idx++;
continue;
} // if:
if ( sc == ERROR_NO_MORE_ITEMS )
{
hr = S_OK;
break;
} // if:
TW32( sc );
hr = HRESULT_FROM_WIN32( sc );
break;
} // for:
goto CleanUp;
OutOfMemory:
hr = THR( E_OUTOFMEMORY );
CleanUp:
delete [] psz;
if ( hRes != NULL )
{
CloseClusterResource( hRes );
} // if:
if ( hEnum != NULL )
{
ClusterCloseEnum( hEnum );
} // if:
HRETURN( hr );
} //*** HrGetNodeNameHostingCluster
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetSCSIInfo
//
// Description:
// Get the name of the node hosting the cluster service...
//
// Arguments:
// hResourceIn
// pCSAOut
// pdwSignatureOut
// pdwDiskNumberOut
//
// Return Value:
// S_OK - Success.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetSCSIInfo(
HRESOURCE hResourceIn
, CLUS_SCSI_ADDRESS * pCSAOut
, DWORD * pdwSignatureOut
, DWORD * pdwDiskNumberOut
)
{
TraceFunc( "" );
Assert( hResourceIn != NULL );
HRESULT hr = S_OK;
DWORD sc;
CClusPropValueList cpvl;
CLUSPROP_BUFFER_HELPER cpbh;
sc = TW32( cpvl.ScGetResourceValueList( hResourceIn, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO ) );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
// loop through all the properties.
sc = TW32( cpvl.ScMoveToFirstValue() );
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
do
{
if ( sc != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
cpbh = cpvl;
switch ( cpbh.pSyntax->dw )
{
case CLUSPROP_SYNTAX_PARTITION_INFO :
{
break;
} // case: CLUSPROP_SYNTAX_PARTITION_INFO
case CLUSPROP_SYNTAX_DISK_SIGNATURE :
{
*pdwSignatureOut = cpbh.pDiskSignatureValue->dw;
break;
} // case: CLUSPROP_SYNTAX_DISK_SIGNATURE
case CLUSPROP_SYNTAX_SCSI_ADDRESS :
{
pCSAOut->dw = cpbh.pScsiAddressValue->dw;
break;
} // case: CLUSPROP_SYNTAX_SCSI_ADDRESS
case CLUSPROP_SYNTAX_DISK_NUMBER :
{
*pdwDiskNumberOut = cpbh.pDiskNumberValue->dw;
break;
} // case:
} // switch:
// Move to the next item.
sc = cpvl.ScCheckIfAtLastValue();
if ( sc == ERROR_NO_MORE_ITEMS )
{
break;
}
sc = cpvl.ScMoveToNextValue();
} while ( sc == ERROR_SUCCESS );
hr = S_OK;
Cleanup:
HRETURN( hr );
} //*** HrGetSCSIInfo
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetClusterInformation
//
// Description:
// Get the cluster information. This includes the name and the version
// info.
//
// Arguments:
// hClusterIn
// pbstrClusterNameOut
// pcviOut
//
// Return Value:
// S_OK - Success.
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetClusterInformation(
HCLUSTER hClusterIn,
BSTR * pbstrClusterNameOut,
CLUSTERVERSIONINFO * pcviOut
)
{
TraceFunc( "" );
Assert( hClusterIn != NULL );
Assert( pbstrClusterNameOut != NULL );
HRESULT hr = S_OK;
DWORD sc;
WCHAR * psz = NULL;
DWORD cch = 33;
CLUSTERVERSIONINFO cvi;
cvi.dwVersionInfoSize = sizeof( cvi );
if ( pcviOut == NULL )
{
pcviOut = &cvi;
} // if:
psz = new WCHAR[ cch ];
if ( psz == NULL )
{
goto OutOfMemory;
} // if:
sc = GetClusterInformation( hClusterIn, psz, &cch, pcviOut );
if ( sc == ERROR_MORE_DATA )
{
delete [] psz;
psz = NULL;
psz = new WCHAR[ ++cch ];
if ( psz == NULL )
{
goto OutOfMemory;
} // if:
sc = GetClusterInformation( hClusterIn, psz, &cch, pcviOut );
} // if:
if ( sc != ERROR_SUCCESS )
{
hr = THR( HRESULT_FROM_WIN32( sc ) );
LogMsg( __FUNCTION__ ": GetClusterInformation() failed (hr = 0x%08x).", hr );
goto Cleanup;
} // if:
*pbstrClusterNameOut = TraceSysAllocString( psz );
if ( *pbstrClusterNameOut == NULL )
{
goto OutOfMemory;
} // if:
goto Cleanup;
OutOfMemory:
hr = THR( E_OUTOFMEMORY );
Cleanup:
delete [] psz;
HRETURN( hr );
} //*** HrGetClusterInformation
/////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetClusterResourceState
//
// Description:
//
// Arguments:
// hResourceIn
// pbstrNodeNameOut
// pbstrGroupNameOut
// pcrsStateOut
//
// Return Values:
// S_OK - Success.
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
/////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetClusterResourceState(
HRESOURCE hResourceIn
, BSTR * pbstrNodeNameOut
, BSTR * pbstrGroupNameOut
, CLUSTER_RESOURCE_STATE * pcrsStateOut
)
{
TraceFunc( "" );
Assert( hResourceIn != NULL );
HRESULT hr = S_OK;
CLUSTER_RESOURCE_STATE crsState = ClusterResourceStateUnknown;
WCHAR * pszNodeName = NULL;
DWORD cchNodeName = 33;
WCHAR * pszGroupName = NULL;
DWORD cchGroupName = 33;
pszNodeName = new WCHAR[ cchNodeName ];
if ( pszNodeName == NULL )
{
goto OutOfMemory;
} // if:
pszGroupName = new WCHAR[ cchGroupName ];
if ( pszGroupName == NULL )
{
goto OutOfMemory;
} // if:
crsState = GetClusterResourceState( hResourceIn, pszNodeName, &cchNodeName, pszGroupName, &cchGroupName );
if ( GetLastError() == ERROR_MORE_DATA )
{
crsState = ClusterResourceStateUnknown; // reset to error condition
delete [] pszNodeName;
pszNodeName = NULL;
cchNodeName++;
delete [] pszGroupName;
pszGroupName = NULL;
cchGroupName++;
pszNodeName = new WCHAR[ cchNodeName ];
if ( pszNodeName == NULL )
{
goto OutOfMemory;
} // if:
pszGroupName = new WCHAR[ cchGroupName ];
if ( pszGroupName == NULL )
{
goto OutOfMemory;
} // if:
crsState = GetClusterResourceState( hResourceIn, pszNodeName, &cchNodeName, pszGroupName, &cchGroupName );
if ( crsState == ClusterResourceStateUnknown )
{
DWORD sc;
sc = TW32( GetLastError() );
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
} // if: more data
if ( pbstrNodeNameOut != NULL )
{
*pbstrNodeNameOut = TraceSysAllocString( pszNodeName );
if ( *pbstrNodeNameOut == NULL )
{
goto OutOfMemory;
} // if:
} // if:
if ( pbstrGroupNameOut != NULL )
{
*pbstrGroupNameOut = TraceSysAllocString( pszGroupName );
if ( *pbstrGroupNameOut == NULL )
{
goto OutOfMemory;
} // if:
} // if:
if ( pcrsStateOut != NULL )
{
*pcrsStateOut = crsState;
} // if:
goto Cleanup;
OutOfMemory:
hr = THR( E_OUTOFMEMORY );
Cleanup:
delete [] pszNodeName;
delete [] pszGroupName;
HRETURN( hr );
} //*** HrGetClusterResourceState
/////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetClusterQuorumResource
//
// Description:
// Get the information about the quorum resource.
//
// Arguments:
// hClusterIn
// pbstrResourceNameOut
// pbstrDeviceNameOut
// pdwMaxQuorumLogSizeOut
//
// Return Value.:
// S_OK - Success.
// E_INVALIDARG - An input argument was not specified.
// E_OUTOFMEMORY - Couldn't allocate memory.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetClusterQuorumResource(
HCLUSTER hClusterIn
, BSTR * pbstrResourceNameOut
, BSTR * pbstrDeviceNameOut
, DWORD * pdwMaxQuorumLogSizeOut
)
{
TraceFunc( "" );
Assert( hClusterIn != NULL );
Assert( ( pbstrResourceNameOut != NULL )
|| ( pbstrDeviceNameOut != NULL )
|| ( pdwMaxQuorumLogSizeOut != NULL )
);
HRESULT hr = S_OK;
DWORD sc;
LPWSTR pszResourceName = NULL;
DWORD cchResourceName = 128;
DWORD cchTempResourceName = cchResourceName;
LPWSTR pszDeviceName = NULL;
DWORD cchDeviceName = 128;
DWORD cchTempDeviceName = cchDeviceName;
DWORD dwMaxQuorumLogSize = 0;
// Allocate the resource name buffer
pszResourceName = new WCHAR[ cchResourceName ];
if ( pszResourceName == NULL )
{
goto OutOfMemory;
} // if:
// Allocate the device name buffer
pszDeviceName = new WCHAR[ cchDeviceName ];
if ( pszDeviceName == NULL )
{
goto OutOfMemory;
} // if:
sc = GetClusterQuorumResource(
hClusterIn
, pszResourceName
, &cchTempResourceName
, pszDeviceName
, &cchTempDeviceName
, &dwMaxQuorumLogSize
);
if ( sc == ERROR_MORE_DATA )
{
delete [] pszResourceName;
pszResourceName = NULL;
cchResourceName = ++cchTempResourceName;
// Allocate the resource name buffer
pszResourceName = new WCHAR[ cchResourceName ];
if ( pszResourceName == NULL )
{
goto OutOfMemory;
} // if:
delete [] pszDeviceName;
pszDeviceName = NULL;
cchDeviceName = ++cchTempDeviceName;
// Allocate the device name buffer
pszDeviceName = new WCHAR[ cchDeviceName ];
if ( pszDeviceName == NULL )
{
goto OutOfMemory;
} // if:
sc = GetClusterQuorumResource(
hClusterIn
, pszResourceName
, &cchTempResourceName
, pszDeviceName
, &cchTempDeviceName
, &dwMaxQuorumLogSize
);
} // if:
if ( sc != ERROR_SUCCESS )
{
TW32( sc );
hr = HRESULT_FROM_WIN32( sc );
goto Cleanup;
} // if:
if ( pbstrResourceNameOut != NULL )
{
*pbstrResourceNameOut = TraceSysAllocString( pszResourceName );
if ( *pbstrResourceNameOut == NULL )
{
goto OutOfMemory;
} // if:
} // if:
if ( pbstrDeviceNameOut != NULL )
{
*pbstrDeviceNameOut = TraceSysAllocString( pszDeviceName );
if ( *pbstrDeviceNameOut == NULL )
{
goto OutOfMemory;
} // if:
} // if:
if ( pdwMaxQuorumLogSizeOut != NULL )
{
*pdwMaxQuorumLogSizeOut = dwMaxQuorumLogSize;
} // if:
goto Cleanup;
OutOfMemory:
hr = THR( E_OUTOFMEMORY );
Cleanup:
delete [] pszResourceName;
delete [] pszDeviceName;
HRETURN( hr );
} //*** HrGetClusterQuorumResource
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrReplaceTokens
//
// Description:
// Replaces all instances of the search tokens with a replacement token.
//
// Arguments:
// pwszStringInout - The string in which to perform replacements.
// pwszSearchTokenIn - The string of tokens to search for that will be replaced.
// chReplaceTokenIn - What the search tokens will be replaced with.
// pcReplacementsOut - [optional] The number of replacements performed.
//
// Return Values:
// S_OK - Success.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrReplaceTokens(
LPWSTR pwszStringInout
, LPCWSTR pwszSearchTokensIn
, WCHAR chReplaceTokenIn
, DWORD * pcReplacementsOut
)
{
TraceFunc3(
"pwszString = '%ws', pwszSearchToken: '%ws%', chReplaceToken: '%ws%'"
, ( pwszStringInout != NULL ? pwszStringInout: L"<null>" )
, pwszSearchTokensIn
, chReplaceTokenIn
);
HRESULT hr = S_OK;
DWORD cReps = 0;
WCHAR * pwszStr = NULL;
WCHAR * pwszTok = NULL;
Assert( pwszStringInout != NULL );
Assert( pwszSearchTokensIn != NULL );
//
// For each character in pwszStringInout check it against every character in
// pwszSearchTokensIn and if we find a match replace the character in
// pwszStringInout with the chReplaceTokenIn character.
//
for( pwszStr = pwszStringInout; *pwszStr != L'\0'; pwszStr++ )
{
for( pwszTok = (WCHAR *) pwszSearchTokensIn; *pwszTok != L'\0'; pwszTok++ )
{
if ( *pwszStr == *pwszTok )
{
*pwszStr = chReplaceTokenIn;
cReps++;
break;
} // if: match
} // for: each search token
} // for: each string element
if ( pcReplacementsOut != NULL )
{
*pcReplacementsOut = cReps;
}
HRETURN( hr );
} //*** HrReplaceTokens
/////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetMaxNodeCount
//
// Description:
// Get the maximum node count supported by the cluster. This value
// could be based upon the product suite, or it could be overridden
// by an entry in the cluster hive.
//
// Arguments:
// pcMaxNodesOut
//
// Return Value:
// S_OK - Success.
// S_FALSE -
// E_POINTER - An output argument was not specified.
// Other HRESULTs.
//
// Note:
// THIS ROUTINE IS NOT FUNCIONTAL AT THE MOMENT.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetMaxNodeCount(
DWORD * pcMaxNodesOut
)
{
TraceFunc( "" );
HRESULT hr = S_FALSE;
if ( pcMaxNodesOut == NULL )
{
hr = THR( E_POINTER );
goto Cleanup;
} // if:
//
// TODO: 11-OCT-2001 GalenB
//
// Need to finish this!
//
Cleanup:
HRETURN( hr );
} //*** HrGetMaxNodeCount
/////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetReferenceStringFromHResult
//
// Description:
// Return if the specified HRESULT is in our list.
//
// Arguments:
// hrIn
// pbstrReferenceStringOut
//
// Return Value:
// S_OK - Success - HRESULT is in our list.
// S_FALSE - HRESULT is not in our list.
// E_POINTER - An output argument was not specified.
// Other HRESULTs.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetReferenceStringFromHResult(
HRESULT hrIn
, BSTR * pbstrReferenceStringOut
)
{
TraceFunc( "" );
Assert( pbstrReferenceStringOut != NULL );
HRESULT hr = S_FALSE;
UINT idx;
struct MapHResultToStringId
{
HRESULT hr;
UINT ids;
};
static MapHResultToStringId s_rgmhrtsi[] =
{
{ HRESULT_FROM_WIN32( ERROR_CLUSTER_IPADDR_IN_USE ), IDS_ERROR_IP_ADDRESS_IN_USE_REF }
, { HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY ), IDS_ERROR_OUTOFMEMORY_REF }
};
for ( idx = 0 ; idx < ARRAYSIZE( s_rgmhrtsi ) ; idx++ )
{
if ( hrIn == s_rgmhrtsi[ idx ].hr )
{
hr = THR( HrLoadStringIntoBSTR( g_hInstance, s_rgmhrtsi[ idx ].ids, pbstrReferenceStringOut ) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
break;
} // if: found a match
} // for: each entry in the array
Cleanup:
HRETURN( hr );
} //*** HrGetReferenceStringFromHResult
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterUtils:HrIsClusterServiceRunning
//
// Description:
// Is cluster service running?
//
// Arguments:
// None.
//
// Return Value:
// S_OK - The cluster service is running.
// S_FALSE - The cluster service is NOT running.
// HRESULT - Something failed.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrIsClusterServiceRunning( void )
{
TraceFunc( "" );
HRESULT hr = S_FALSE;
DWORD sc;
DWORD dwClusterState;
//
// Get the cluster state of the node.
//
sc = GetNodeClusterState( NULL, &dwClusterState );
if ( ( sc != ERROR_SUCCESS ) && ( sc != ERROR_SERVICE_DOES_NOT_EXIST ) )
{
hr = HRESULT_FROM_WIN32( TW32( sc ) );
goto Cleanup;
} // if : GetClusterState() failed
if ( dwClusterState == ClusterStateRunning )
{
hr = S_OK;
} // if:
Cleanup:
HRETURN( hr );
} //*** HrIsClusterServiceRunning
/////////////////////////////////////////////////////////////////////////////
//++
//
// HrCheckJoiningNodeVersion
//
// Check a joining node's version information against that of the cluster.
//
// Arguments:
// pcwszClusterNameIn - can be null, which means to use local machine.
// dwNodeHighestVersionIn
// dwNodeLowestVersionIn
// pcccbIn - for status reporting.
//
// Return Value:
// S_OK
// The joining node is compatible.
//
// HRESULT_FROM_WIN32( ERROR_CLUSTER_INCOMPATIBLE_VERSIONS )
// The joining node is NOT compatible.
//
// Other HRESULT errors.
//
// Remarks:
//
// Get and verify the sponsor version
//
//
// From Whistler onwards, CsRpcGetJoinVersionData() will return a failure code in its last parameter
// if the version of this node is not compatible with the sponsor version. Prior to this, the last
// parameter always contained a success value and the cluster versions had to be compared subsequent to this
// call. This will, however, still have to be done as long as interoperability with Win2K
// is a requirement, since Win2K sponsors do not return an error in the last parameter.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrCheckJoiningNodeVersion(
PCWSTR pcwszClusterNameIn
, DWORD dwNodeHighestVersionIn
, DWORD dwNodeLowestVersionIn
, IClusCfgCallback * pcccbIn
)
{
TraceFunc( "" );
HRESULT hr = S_OK;
RPC_STATUS rpcs = RPC_S_OK;
RPC_BINDING_HANDLE hRPCBinding = NULL;
PWSTR pwszBindingString = NULL;
DWORD scJoinStatus = ERROR_SUCCESS;
DWORD dwSponsorNode = 0;
DWORD dwClusterHighestVersion = 0;
DWORD dwClusterLowestVersion = 0;
DWORD scRPC = ERROR_SUCCESS;
//
// Connect to this cluster with RPC.
// The parameters and logic imitate OpenCluster,
// but the RPC interface (identified by the first parameter to RpcStringBindingComposeW) is different.
//
rpcs = TW32( RpcStringBindingComposeW(
L"6e17aaa0-1a47-11d1-98bd-0000f875292e" // Special interface for CsRpcGetJoinVersionData.
, ( pcwszClusterNameIn == NULL? L"ncalrpc": L"ncadg_ip_udp" )
, const_cast< WCHAR* >( pcwszClusterNameIn )
, NULL
, NULL
, &pwszBindingString
) );
if ( rpcs != RPC_S_OK )
{
hr = HRESULT_FROM_WIN32( rpcs );
THR( HrSendStatusReport(
pcccbIn
, TASKID_Major_Client_And_Server_Log
, TASKID_Minor_HrCheckJoiningNodeVersion_RpcStringBindingComposeW
, 1
, 1
, 1
, hr
, L"HrCheckJoiningNodeVersion() RpcStringBindingComposeW() failed."
) );
goto Cleanup;
} // if
rpcs = TW32( RpcBindingFromStringBindingW( pwszBindingString, &hRPCBinding ) );
if ( rpcs != RPC_S_OK )
{
hr = HRESULT_FROM_WIN32( rpcs );
THR( HrSendStatusReport(
pcccbIn
, TASKID_Major_Client_And_Server_Log
, TASKID_Minor_HrCheckJoiningNodeVersion_RpcBindingFromStringBindingW
, 1
, 1
, 1
, hr
, L"HrCheckJoiningNodeVersion() RpcBindingFromStringBindingW() failed."
) );
goto Cleanup;
} // if
// Parameters to RpcBindingSetAuthInfoW copied from OpenCluster.
rpcs = TW32( RpcBindingSetAuthInfoW(
hRPCBinding
, NULL
, RPC_C_AUTHN_LEVEL_CONNECT
, RPC_C_AUTHN_WINNT
, NULL
, RPC_C_AUTHZ_NAME
) );
if ( rpcs != RPC_S_OK )
{
hr = HRESULT_FROM_WIN32( rpcs );
THR( HrSendStatusReport(
pcccbIn
, TASKID_Major_Client_And_Server_Log
, TASKID_Minor_HrCheckJoiningNodeVersion_RpcBindingSetAuthInfoW
, 1
, 1
, 1
, hr
, L"HrCheckJoiningNodeVersion() RpcBindingSetAuthInfoW() failed."
) );
goto Cleanup;
} // if
// Now, perform the check this function advertises.
scRPC = TW32( CsRpcGetJoinVersionData(
hRPCBinding
, 0
, dwNodeHighestVersionIn
, dwNodeLowestVersionIn
, &dwSponsorNode
, &dwClusterHighestVersion
, &dwClusterLowestVersion
, &scJoinStatus
) );
hr = HRESULT_FROM_WIN32( scRPC );
THR( HrFormatDescriptionAndSendStatusReport(
pcccbIn
, pcwszClusterNameIn
, TASKID_Major_Client_And_Server_Log
, TASKID_Minor_HrCheckJoiningNodeVersion_CsRpcGetJoinVersionData_Log
, 1
, 1
, 1
, hr
, L"( Node Highest, Node Lowest ) == ( %1!#08x!, %2!#08x! ), ( Cluster Highest, Cluster Lowest ) == ( %3!#08x!, %4!#08x! )."
, dwNodeHighestVersionIn
, dwNodeLowestVersionIn
, dwClusterHighestVersion
, dwClusterLowestVersion
) );
if ( scRPC != ERROR_SUCCESS )
{
THR( HrSendStatusReport(
pcccbIn
, TASKID_Major_Client_And_Server_Log
, TASKID_Minor_HrCheckJoiningNodeVersion_CsRpcGetJoinVersionData
, 1
, 1
, 1
, hr
, L"HrCheckJoiningNodeVersion() CsRpcGetJoinVersionData() failed."
) );
goto Cleanup;
} // if
if ( scJoinStatus == ERROR_SUCCESS )
{
DWORD dwClusterMajorVersion = CLUSTER_GET_MAJOR_VERSION( dwClusterHighestVersion );
Assert( dwClusterMajorVersion >= ( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION - 1 ) );
//
// Only want to join clusters that are no more than one version back.
//
if ( dwClusterMajorVersion < ( CLUSTER_INTERNAL_CURRENT_MAJOR_VERSION - 1 ) )
{
hr = THR( HRESULT_FROM_WIN32( ERROR_CLUSTER_INCOMPATIBLE_VERSIONS ) );
} // if
} // if
else
{
hr = THR( HRESULT_FROM_WIN32( ERROR_CLUSTER_INCOMPATIBLE_VERSIONS ) );
} // else
Cleanup:
if ( hRPCBinding != NULL )
{
RpcBindingFree( &hRPCBinding );
} // if
if ( pwszBindingString != NULL )
{
RpcStringFree( &pwszBindingString );
} // if
HRETURN( hr );
} //*** HrCheckJoiningNodeVersion
//////////////////////////////////////////////////////////////////////////////
//++
//
// HrGetNodeNames
//
// Description:
// Retrieve the names of the nodes currently in a cluster.
//
// Parameters:
// hClusterIn
// A handle to the cluster of interest. Must NOT be null.
//
// pnCountOut
// On success, *pnCountOut returns the number of nodes in the cluster.
//
// prgbstrNodeNamesOut
// On success, an array of BSTRs containing the node names.
// The caller must free each BSTR with SysFreeString, and free
// the array with CoTaskMemFree.
//
// Return Values:
// S_OK
// The out parameters contain valid information and the caller
// must free the array and the BSTRs it contains.
//
// E_OUTOFMEMORY, and other failures are possible.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
HrGetNodeNames(
HCLUSTER hClusterIn
, long * pnCountOut
, BSTR ** prgbstrNodeNamesOut
)
{
TraceFunc( "" );
HRESULT hr = S_OK;
BSTR * prgbstrNodeNames = NULL;
long idxNode = 0;
HCLUSENUM hClusEnum = NULL;
long cNodes = 0;
if ( pnCountOut != NULL )
{
*pnCountOut = 0;
} // if
if ( prgbstrNodeNamesOut != NULL )
{
*prgbstrNodeNamesOut = NULL;
} // if
if ( ( pnCountOut == NULL ) || ( prgbstrNodeNamesOut == NULL ) )
{
hr = THR( E_POINTER );
goto Cleanup;
} // if
hClusEnum = ClusterOpenEnum( hClusterIn, CLUSTER_ENUM_NODE );
if ( hClusEnum == NULL )
{
DWORD scLastError = TW32( GetLastError() );
hr = HRESULT_FROM_WIN32( scLastError );
goto Cleanup;
} // if
cNodes = ClusterGetEnumCount( hClusEnum );
if ( cNodes > 0 )
{
//
// Set up local copy of name array.
//
prgbstrNodeNames = reinterpret_cast< BSTR* >( CoTaskMemAlloc( cNodes * sizeof( BSTR ) ) );
if ( prgbstrNodeNames == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if
ZeroMemory( prgbstrNodeNames, cNodes * sizeof( BSTR ) );
for ( idxNode = 0; idxNode < cNodes; idxNode += 1 )
{
DWORD dwNodeType = 0;
WCHAR wszNodeName[ DNS_MAX_NAME_BUFFER_LENGTH ];
DWORD cchNodeName = RTL_NUMBER_OF( wszNodeName );
DWORD scEnum = ERROR_SUCCESS;
scEnum = TW32( ClusterEnum( hClusEnum, idxNode, &dwNodeType, wszNodeName, &cchNodeName ) );
if ( scEnum != ERROR_SUCCESS )
{
hr = HRESULT_FROM_WIN32( scEnum );
goto Cleanup;
} // if
prgbstrNodeNames[ idxNode ] = SysAllocString( wszNodeName );
if ( prgbstrNodeNames[ idxNode ] == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
} // if
} // for each node in the cluster
//
// Copy succeeded, so transfer ownership to caller.
//
*pnCountOut = cNodes;
*prgbstrNodeNamesOut = prgbstrNodeNames;
prgbstrNodeNames = NULL;
} // if cluster has at least one node
Cleanup:
if ( hClusEnum != NULL )
{
ClusterCloseEnum( hClusEnum );
} // if
if ( prgbstrNodeNames != NULL )
{
//
// Making local copy of array must have failed midway, so
// clean up whatever parts of it exist.
//
for ( idxNode = 0; idxNode < cNodes; ++idxNode )
{
SysFreeString( prgbstrNodeNames[ idxNode ] );
} // for
CoTaskMemFree( prgbstrNodeNames );
} // if still own local copy of array.
HRETURN( hr );
} //*** HrGetNodeNames