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
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
|