/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1999 - 1999 **/ /**********************************************************************/ /* cluster.cpp handles starting/stopping cluster resources FILE HISTORY: */ //define USE_CCLUSPROPLIST // tells Clushead.h to compile for the CClusPropList class //include "clushead.h" // the Sample Include Header #include "stdafx.h" #include "cluster.h" #include "objplus.h" #include "ipaddres.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif DynamicDLL g_ClusDLL( _T("CLUSAPI.DLL"), g_apchClusFunctionNames ); DynamicDLL g_ResUtilsDLL( _T("RESUTILS.DLL"), g_apchResUtilsFunctionNames ); ////////////////////////////////////////////////////////////////////// // // ControlClusterService() // // Finds the cluster name using the following procedure: // 1. Opens a handle to the local cluster (using NULL cluster name). // 1. Enumerates the resources in the cluster. // 2. Checks each resource to see if it is the core // Network Name resource. // 5. Finds the cluster name by retrieving the private properties // of the core Network Name resource. // 6. Online/Offline the service // // Arguments: ServiceName, start/stop flag // // Return value: Error code // ////////////////////////////////////////////////////////////////////// DWORD ControlClusterService(LPCTSTR pszComputer, LPCTSTR pszResourceType, LPCTSTR pszServiceDesc, BOOL fStart) { HCLUSTER hCluster = NULL; // cluster handle HCLUSENUM hClusEnum = NULL; // enumeration handle HRESOURCE hRes = NULL; // resource handle DWORD dwError = ERROR_SUCCESS; // captures return values DWORD dwIndex = 0; // enumeration index; incremented to loop through all resources DWORD dwResFlags = 0; // describes the flags set for a resource DWORD dwEnumType = CLUSTER_ENUM_RESOURCE; // bitmask describing the cluster object(s) to enumerate DWORD cchResNameSize = 0; // actual size (count of characters) of lpszResName DWORD cchResNameAlloc = MAX_NAME_SIZE; // allocated size of lpszResName; MAX_NAME_SIZE = 256 (defined in clushead.h) LPWSTR lpszResName = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // enumerated resource name LPWSTR lpszResType = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // the resource type of the current resource name BOOL bDoLoop = TRUE; // loop exit condition int iResult = 0; // for return values if ( !g_ClusDLL.LoadFunctionPointers() ) return dwError; // // Open a cluster handle. // The NULL cluster name opens a handle to the local cluster. // hCluster = ((OPENCLUSTER) g_ClusDLL[CLUS_OPEN_CLUSTER])( pszComputer ); if (hCluster == NULL) { dwError = GetLastError(); Trace1("OpenCluster failed %d!", dwError ); goto ExitFunc; } // // Open an enumeration handle // hClusEnum = ((CLUSTEROPENENUM) g_ClusDLL[CLUS_CLUSTER_OPEN_ENUM])( hCluster, dwEnumType ); if (hClusEnum == NULL) { dwError = GetLastError(); Trace1( "ClusterOpenEnum failed %d", dwError ); goto ExitFunc; } // // Enumeration loop // while( bDoLoop == TRUE ) { // // Reset the name size for each iteration // cchResNameSize = cchResNameAlloc; // // Enumerate resource # // dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum, dwIndex, &dwEnumType, lpszResName, &cchResNameSize ); // // If the lpszResName buffer was too small, reallocate // according to the size returned by cchResNameSize // if ( dwError == ERROR_MORE_DATA ) { LocalFree( lpszResName ); cchResNameAlloc = cchResNameSize; lpszResName = (LPWSTR) LocalAlloc( LPTR, cchResNameAlloc ); dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum, dwIndex, &dwEnumType, lpszResName, &cchResNameSize ); } // // Exit loop on any non-success. // Includes ERROR_NO_MORE_ITEMS (no more objects to enumerate) // if ( dwError != ERROR_SUCCESS ) break; // // Open resource handle // hRes = ((OPENCLUSTERRESOURCE) g_ClusDLL[CLUS_OPEN_CLUSTER_RESOURCE])( hCluster, lpszResName ); if (hRes == NULL) { dwError = GetLastError(); Trace1 ( "OpenClusterResource failed %d", dwError); goto ExitFunc; } // // Get the resource type. // dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, lpszResType, cchResNameAlloc, &cchResNameSize); // // Reallocation routine if lpszResType is too small // if ( dwError == ERROR_MORE_DATA ) { LocalFree( lpszResType ); cchResNameAlloc = cchResNameSize; lpszResType = (LPWSTR) LocalAlloc( LPTR, cchResNameAlloc ); dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, lpszResType, cchResNameAlloc, &cchResNameSize); } if ( dwError != ERROR_SUCCESS ) break; if ( lstrcmpi( lpszResType, pszResourceType ) == 0 ) { // // do the online/offline stuff here // if (fStart) { dwError = StartResource(pszComputer, hRes, pszServiceDesc); } else { dwError = StopResource(pszComputer, hRes, pszServiceDesc); } bDoLoop = FALSE; } ((CLOSECLUSTERRESOURCE) g_ClusDLL[CLUS_CLOSE_CLUSTER_RESOURCE])( hRes ); dwIndex++; // increment the enumeration index } // end Enumeration Loop ExitFunc: if ( hClusEnum != NULL ) ((CLUSTERCLOSEENUM) g_ClusDLL[CLUS_CLUSTER_CLOSE_ENUM])( hClusEnum ); if ( hCluster != NULL ) ((CLOSECLUSTER) g_ClusDLL[CLUS_CLOSE_CLUSTER])( hCluster ); LocalFree( lpszResName ); LocalFree( lpszResType ); return dwError; } ////////////////////////////////////////////////////////////////////// // // FIsComputerInRunningCluster() // // Determines if the given machine is in a running cluster // // Arguments: Computer Name // // Return value: Error code // ////////////////////////////////////////////////////////////////////// BOOL FIsComputerInRunningCluster(LPCTSTR pszComputer) { DWORD dwClusterState = 0; DWORD dwError = ERROR_SUCCESS; BOOL fInRunningCluster = FALSE; if ( !g_ClusDLL.LoadFunctionPointers() ) return dwError; dwError = ((GETNODECLUSTERSTATE) g_ClusDLL[CLUS_GET_NODE_CLUSTER_STATE])( pszComputer, &dwClusterState ); if (dwError == ERROR_SUCCESS) { if (dwClusterState == ClusterStateRunning) fInRunningCluster = TRUE; } return fInRunningCluster; } DWORD StartResource(LPCTSTR pszComputer, HRESOURCE hResource, LPCTSTR pszServiceDesc) { DWORD dwError = ERROR_SUCCESS; if ( !g_ClusDLL.LoadFunctionPointers() ) return dwError; dwError = ((ONLINECLUSTERRESOURCE) g_ClusDLL[CLUS_ONLINE_CLUSTER_RESOURCE])( hResource ); if ( dwError == ERROR_IO_PENDING ) { // // Put up the dialog with the funky spinning thing to // let the user know that something is happening // CServiceCtrlDlg dlgServiceCtrl(hResource, pszComputer, pszServiceDesc, TRUE); dlgServiceCtrl.DoModal(); dwError = dlgServiceCtrl.m_dwErr; } return dwError; } DWORD StopResource(LPCTSTR pszComputer, HRESOURCE hResource, LPCTSTR pszServiceDesc) { DWORD dwError = ERROR_SUCCESS; if ( !g_ClusDLL.LoadFunctionPointers() ) return dwError; dwError = ((OFFLINECLUSTERRESOURCE) g_ClusDLL[CLUS_OFFLINE_CLUSTER_RESOURCE])( hResource ); if ( dwError == ERROR_IO_PENDING ) { // // Put up the dialog with the funky spinning thing to // let the user know that something is happening // CServiceCtrlDlg dlgServiceCtrl(hResource, pszComputer, pszServiceDesc, FALSE); dlgServiceCtrl.DoModal(); dwError = dlgServiceCtrl.m_dwErr; } return dwError; } ////////////////////////////////////////////////////////////////////// // // GetClusterResourceIp() // // Finds the cluster name using the following procedure: // 1. Opens a handle to the local cluster (using NULL cluster name). // 1. Enumerates the resources in the cluster. // 2. Checks each resource to see if it is the core // Network Name resource. // 5. Finds the cluster name by retrieving the private properties // of the core Network Name resource. // // Arguments: ServiceName // // Return value: Error code // ////////////////////////////////////////////////////////////////////// DWORD GetClusterResourceIp(LPCTSTR pszComputer, LPCTSTR pszResourceType, CString & strAddress) { HCLUSTER hCluster = NULL; // cluster handle HCLUSENUM hClusEnum = NULL; // enumeration handle HRESOURCE hRes = NULL; // resource handle HRESOURCE hResIp = NULL; // resource handle DWORD dwError = ERROR_SUCCESS; // captures return values DWORD dwIndex = 0; // enumeration index; incremented to loop through all resources DWORD dwResFlags = 0; // describes the flags set for a resource DWORD dwEnumType = CLUSTER_ENUM_RESOURCE; // bitmask describing the cluster object(s) to enumerate DWORD cchResNameSize = 0; // actual size (count of characters) of lpszResName DWORD cchResNameAlloc = MAX_NAME_SIZE; // allocated size of lpszResName; MAX_NAME_SIZE = 256 (defined in clushead.h) LPWSTR lpszResName = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // enumerated resource name LPWSTR lpszResType = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // the resource type of the current resource name BOOL bDoLoop = TRUE; // loop exit condition HKEY hkeyProvider = NULL; HRESENUM hResEnum = NULL; int ienum; LPWSTR pwszName = NULL; DWORD cchName; DWORD cchmacName; DWORD dwRetType; LPWSTR lpszResIpType = NULL; strAddress.Empty(); if ( !g_ClusDLL.LoadFunctionPointers() ) return dwError; // // Open a cluster handle. // The NULL cluster name opens a handle to the local cluster. // hCluster = ((OPENCLUSTER) g_ClusDLL[CLUS_OPEN_CLUSTER])( pszComputer ); if (hCluster == NULL) { dwError = GetLastError(); Trace1("OpenCluster failed %d!", dwError ); goto ExitFunc; } // // Open an enumeration handle // hClusEnum = ((CLUSTEROPENENUM) g_ClusDLL[CLUS_CLUSTER_OPEN_ENUM])( hCluster, dwEnumType ); if (hClusEnum == NULL) { dwError = GetLastError(); Trace1( "ClusterOpenEnum failed %d", dwError ); goto ExitFunc; } // // Enumeration loop // while( bDoLoop == TRUE ) { // // Reset the name size for each iteration // cchResNameSize = cchResNameAlloc; // // Enumerate resource # // dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum, dwIndex, &dwEnumType, lpszResName, &cchResNameSize ); // // If the lpszResName buffer was too small, reallocate // according to the size returned by cchResNameSize // if ( dwError == ERROR_MORE_DATA ) { LocalFree( lpszResName ); cchResNameAlloc = cchResNameSize; lpszResName = (LPWSTR) LocalAlloc( LPTR, cchResNameAlloc ); dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum, dwIndex, &dwEnumType, lpszResName, &cchResNameSize ); } // // Exit loop on any non-success. // Includes ERROR_NO_MORE_ITEMS (no more objects to enumerate) // if ( dwError != ERROR_SUCCESS ) break; // // Open resource handle // hRes = ((OPENCLUSTERRESOURCE) g_ClusDLL[CLUS_OPEN_CLUSTER_RESOURCE])( hCluster, lpszResName ); if (hRes == NULL) { dwError = GetLastError(); Trace1 ( "OpenClusterResource failed %d", dwError); goto ExitFunc; } dwError = GetResourceType(hRes, &lpszResType, cchResNameAlloc, &cchResNameSize); if ( dwError != ERROR_SUCCESS ) break; if ( lstrcmpi( lpszResType, pszResourceType ) == 0 ) { // found the right resource, enum dependencies and find the IP hResEnum = ((CLUSTERRESOURCEOPENENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_OPEN_ENUM])( hRes, CLUSTER_RESOURCE_ENUM_DEPENDS); if (hResEnum) { // Allocate a name buffer. cchmacName = 128; pwszName = new WCHAR[cchmacName]; // Loop through the enumeration and add each dependent resource to the list. for (ienum = 0 ; ; ienum++) { // Get the next item in the enumeration. cchName = cchmacName; dwError = ((CLUSTERRESOURCEENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_ENUM])( hResEnum, ienum, &dwRetType, pwszName, &cchName); if (dwError == ERROR_MORE_DATA) { delete [] pwszName; cchmacName = ++cchName; pwszName = new WCHAR[cchmacName]; dwError = ((CLUSTERRESOURCEENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_ENUM])( hResEnum, ienum, &dwRetType, pwszName, &cchName); } // if: name buffer was too small if (dwError == ERROR_NO_MORE_ITEMS) { break; } else if (dwError != ERROR_SUCCESS) { break; } ASSERT(dwRetType == CLUSTER_RESOURCE_ENUM_DEPENDS); // // Open resource handle // hResIp = ((OPENCLUSTERRESOURCE) g_ClusDLL[CLUS_OPEN_CLUSTER_RESOURCE])( hCluster, pwszName ); if (hResIp == NULL) { dwError = GetLastError(); Trace1 ( "OpenClusterResource failed %d", dwError); break; } lpszResIpType = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); dwError = GetResourceType(hResIp, &lpszResIpType, MAX_NAME_SIZE, NULL); if ( dwError != ERROR_SUCCESS ) break; if ( lstrcmpiW( lpszResIpType, _T("IP Address") ) == 0 ) { GetResourceIpAddress(hResIp, strAddress); bDoLoop = FALSE; } // if: IP Address resource found ((CLOSECLUSTERRESOURCE) g_ClusDLL[CLUS_CLOSE_CLUSTER_RESOURCE])( hResIp ); LocalFree( lpszResIpType ); hResIp = NULL; lpszResIpType = NULL; if (!strAddress.IsEmpty()) break; // found it } // for: each dependency delete [] pwszName; dwError = ((CLUSTERRESOURCECLOSEENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CLOSE_ENUM])( hResEnum ); } } ((CLOSECLUSTERRESOURCE) g_ClusDLL[CLUS_CLOSE_CLUSTER_RESOURCE])( hRes ); dwIndex++; // increment the enumeration index } // end Enumeration Loop ExitFunc: if ( hClusEnum != NULL ) ((CLUSTERCLOSEENUM) g_ClusDLL[CLUS_CLUSTER_CLOSE_ENUM])( hClusEnum ); if ( hCluster != NULL ) ((CLOSECLUSTER) g_ClusDLL[CLUS_CLOSE_CLUSTER])( hCluster ); LocalFree( lpszResName ); LocalFree( lpszResType ); return dwError; } DWORD GetResourceType(HRESOURCE hRes, LPWSTR * ppszName, DWORD dwBufSizeIn, DWORD * pdwBufSizeOut) { DWORD dwError = ERROR_SUCCESS; DWORD cchResNameSize = dwBufSizeIn; DWORD cchResNameSizeNeeded = 0; // // Figure out how big a buffer we need. // dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, *ppszName, cchResNameSize, &cchResNameSizeNeeded); // // Reallocation routine if lpszResType is too small // if ( dwError == ERROR_MORE_DATA ) { cchResNameSize = cchResNameSizeNeeded; LocalFree(*ppszName); *ppszName = (LPWSTR) LocalAlloc( LPTR, cchResNameSize ); dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes, NULL, CLUSCTL_RESOURCE_GET_RESOURCE_TYPE, NULL, 0, *ppszName, cchResNameSize, &cchResNameSizeNeeded); } if (pdwBufSizeOut) *pdwBufSizeOut = cchResNameSizeNeeded; return dwError; } DWORD GetResourceIpAddress(HRESOURCE hRes, CString & strAddress) { DWORD dwError = ERROR_SUCCESS; DWORD cbProps; PVOID pvProps = NULL; LPWSTR pszIPAddress = NULL; // Loop to avoid goto's. do { // // Get the size of the private properties from the resource. // dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes, NULL, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES, NULL, 0, NULL, 0, &cbProps); if ( (dwError != ERROR_SUCCESS) || (cbProps == 0) ) { if ( dwError == ERROR_SUCCESS ) { dwError = ERROR_INVALID_DATA; } // if: no properties available break; } // if: error getting size of properties or no properties available // // Allocate the property buffer. // pvProps = LocalAlloc( LMEM_FIXED, cbProps ); if ( pvProps == NULL ) { dwError = GetLastError(); break; } // if: error allocating memory // // Get the private properties from the resource. // dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes, NULL, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES, NULL, 0, pvProps, cbProps, &cbProps); if ( dwError != ERROR_SUCCESS ) { break; } // if: error getting private properties // // Find the Address property. // dwError = FindSzProp(pvProps, cbProps, L"Address", &pszIPAddress); if ( dwError != ERROR_SUCCESS ) { break; } // if: error finding the Address property } while ( 0 ); // // Cleanup. // strAddress = pszIPAddress; LocalFree( pvProps ); return dwError; } DWORD FindSzProp ( LPVOID pvProps, DWORD cbProps, LPCWSTR pszTarget, LPWSTR * ppszOut ) { BOOL DoLoop = TRUE; // loop exit condition BOOL Found = FALSE; // tests whether property has been found DWORD dwError = ERROR_SUCCESS; // for return values DWORD cbOffset = 0; // offset to next entry in the value list DWORD cbPosition = 0; // tracks the advance through the value list buffer CLUSPROP_BUFFER_HELPER ListEntry; // to parse the list // // Set the pb member to the start of the list // ListEntry.pb = (BYTE *) pvProps; // // Main loop: // 1. Check syntax of current list entry // 2. If it is a property name, check that we have the right property. // 3. If it is a binary value, check that we found the right name. // 4. Advance the position counter and test vs. size of list. // do { switch( *ListEntry.pdw ) // check the syntax of the entry { case CLUSPROP_SYNTAX_NAME: // // If this is the Security property, flag Found as TRUE. // The next pass through the loop should yield the Security value. // if ( lstrcmpi( ListEntry.pName->sz, pszTarget ) == 0 ) { Trace0( "Found name.\n" ); Found = TRUE; } else { Found = FALSE; } // // Calculate offset to next entry. Note the use of ALIGN_CLUSPROP // cbOffset = sizeof( *ListEntry.pName ) + ALIGN_CLUSPROP( ListEntry.pName->cbLength ); break; case CLUSPROP_SYNTAX_LIST_VALUE_DWORD: cbOffset = sizeof( *ListEntry.pDwordValue ); // ALIGN_CLUSPROP not used; value is already DWORD-aligned break; case CLUSPROP_SYNTAX_LIST_VALUE_SZ: if ( Found == TRUE) { if (ppszOut) { *ppszOut = ListEntry.pStringValue->sz; } DoLoop = FALSE; } else { Trace0( "Found something else.\n" ); cbOffset = sizeof( *ListEntry.pStringValue ) + ALIGN_CLUSPROP( ListEntry.pStringValue->cbLength ); } break; case CLUSPROP_SYNTAX_LIST_VALUE_BINARY: // this is what we're looking for cbOffset = sizeof( *ListEntry.pBinaryValue ) + ALIGN_CLUSPROP( ListEntry.pBinaryValue->cbLength ); break; case CLUSPROP_SYNTAX_ENDMARK: default: cbOffset = sizeof( DWORD ); break; } // // Verify that the offset to the next entry is // within the value list buffer, then advance // the CLUSPROP_BUFFER_HELPER pointer. // cbPosition += cbOffset; if ( cbPosition > cbProps ) break; ListEntry.pb += cbOffset; } while ( DoLoop ); if (Found) return 0; else return 1; } DWORD GetClusterInfo( LPCTSTR pszClusIp, CString &strClusName, DWORD * pdwClusIp) { DWORD dwErr = ERROR_SUCCESS; HCLUSTER hCluster; CIpAddress ipClus(pszClusIp); strClusName.Empty(); *pdwClusIp = (LONG)ipClus; hCluster = ((OPENCLUSTER) g_ClusDLL[CLUS_OPEN_CLUSTER])(pszClusIp); if (hCluster == NULL) { dwErr = GetLastError(); } else { DWORD dwClusNameLen; dwClusNameLen = 0; dwErr = ((GETCLUSTERINFORMATION) g_ClusDLL[CLUS_GET_CLUSTER_INFORMATION])( hCluster, NULL, &dwClusNameLen, NULL); if (dwClusNameLen > 0) { LPTSTR pClusName; dwClusNameLen++; pClusName = strClusName.GetBuffer((dwClusNameLen)*sizeof(WCHAR)); dwErr = ((GETCLUSTERINFORMATION) g_ClusDLL[CLUS_GET_CLUSTER_INFORMATION])( hCluster, pClusName, &dwClusNameLen, NULL); strClusName.ReleaseBuffer(); } ((CLOSECLUSTER) g_ClusDLL[CLUS_CLOSE_CLUSTER])(hCluster); } return dwErr; }