windows-nt/Source/XPSP1/NT/inetsrv/iis/setup/osrc/wolfpack.cpp
2020-09-26 16:20:57 +08:00

2047 lines
65 KiB
C++

#include "stdafx.h"
#include "wolfpack.h"
#ifndef _CHICAGO_
#include <windows.h>
#include <stdio.h>
#include <clusapi.h>
#include <resapi.h>
#include <helper.h>
#define INITIAL_RESOURCE_NAME_SIZE 256 // In characters not in bytes
#define IIS_RESOURCE_TYPE_NAME L"IIS Server Instance"
#define SMTP_RESOURCE_TYPE_NAME L"SMTP Server Instance"
#define NNTP_RESOURCE_TYPE_NAME L"NNTP Server Instance"
#define MAX_OFFLINE_RETRIES 5 // Number of times to try and take a resources offline before giving up
#define DELAY_BETWEEN_CALLS_TO_OFFLINE 1000*2 // in milliseconds
CONST LPCWSTR scClusterPath = _T("System\\CurrentControlSet\\Services\\ClusSvc");
CONST LPCWSTR scClusterPath2 = _T("System\\CurrentControlSet\\Services\\ClusSvc\\Parameters");
CStringList gcstrListOfClusResources;
int g_ClusterSVCExist = -1; // -1 = not checked, 1 = exist, 0 = not exist
typedef DWORD
(WINAPI *PFN_RESUTILFINDSZPROPERTY)(
IN LPVOID lpTheProperty,
IN OUT LPDWORD nInBufferSize,
IN LPCWSTR lpszResourceTypeName,
OUT LPVOID lpOutBuffer);
typedef DWORD
(WINAPI *PFN_RESUTILFINDDWORDPROPERTY)(
IN LPVOID lpTheProperty,
IN OUT LPDWORD nInBufferSize,
IN LPCWSTR lpszResourceTypeName,
OUT LPDWORD pdwPropertyValue);
typedef DWORD
(WINAPI *PFN_CLUSTERRESOURCECONTROL)(
IN HRESOURCE hResource,
IN HNODE hNode,
IN DWORD dwControlCode,
IN LPVOID lpInBuffer,
IN OUT DWORD nInBufferSize,
OUT LPVOID lpOutBuffer,
IN OUT DWORD nOutBufferSize,
OUT LPDWORD lpBytesReturned
);
typedef HCLUSTER
(WINAPI *PFN_OPENCLUSTER)(
IN LPCWSTR lpszClusterName
);
typedef BOOL
(WINAPI *PFN_CLOSECLUSTER)(
IN HCLUSTER hCluster
);
typedef DWORD
(WINAPI *PFN_CREATECLUSTERRESOURCETYPE)(
IN HCLUSTER hCluster,
IN LPCWSTR lpszResourceTypeName,
IN LPCWSTR lpszDisplayName,
IN LPCWSTR lpszResourceTypeDll,
IN DWORD dwLooksAlivePollInterval,
IN DWORD dwIsAlivePollInterval
);
typedef DWORD
(WINAPI *PFN_DELETECLUSTERRESOURCETYPE)(
IN HCLUSTER hCluster,
IN LPCWSTR lpszResourceTypeName
);
typedef HCLUSENUM
(WINAPI
*PFN_ClusterOpenEnum)(
IN HCLUSTER hCluster,
IN DWORD dwType
);
typedef DWORD
(WINAPI
*PFN_ClusterEnum)(
IN HCLUSENUM hEnum,
IN DWORD dwIndex,
OUT LPDWORD lpdwType,
OUT LPWSTR lpszName,
IN OUT LPDWORD lpcbName
);
typedef DWORD
(WINAPI
*PFN_ClusterCloseEnum)(
IN HCLUSENUM hEnum
);
typedef HRESOURCE
(WINAPI
*PFN_OpenClusterResource)(
IN HCLUSTER hCluster,
IN LPCWSTR lpszResourceName
);
typedef BOOL
(WINAPI
*PFN_CloseClusterResource)(
IN HRESOURCE hResource
);
typedef DWORD
(WINAPI
*PFN_DeleteClusterResource)(
IN HRESOURCE hResource
);
typedef DWORD
(WINAPI
*PFN_OfflineClusterResource)(
IN HRESOURCE hResource
);
typedef HKEY
(WINAPI
*PFN_GetClusterResourceKey)(
IN HRESOURCE hResource,
IN REGSAM samDesired
);
typedef LONG
(WINAPI
*PFN_ClusterRegCloseKey)(
IN HKEY hKey
);
typedef LONG
(WINAPI
*PFN_ClusterRegQueryValue)(
IN HKEY hKey,
IN LPCWSTR lpszValueName,
OUT LPDWORD lpValueType,
OUT LPBYTE lpData,
IN OUT LPDWORD lpcbData
);
typedef CLUSTER_RESOURCE_STATE
(WINAPI
*PFN_GetClusterResourceState)(
IN HRESOURCE hResource,
OUT OPTIONAL LPWSTR lpszNodeName,
IN OUT LPDWORD lpcbNodeName,
OUT OPTIONAL LPWSTR lpszGroupName,
IN OUT LPDWORD lpcbGroupName
);
typedef DWORD
(WINAPI *PFN_DLLREGISTERCLUADMINEXTENSION)(
IN HCLUSTER hCluster
);
typedef DWORD
(WINAPI *PFN_DLLUNREGISTERCLUADMINEXTENSION)(
IN HCLUSTER hCluster
);
void ListOfClusResources_Add(TCHAR * szEntry)
{
//Add entry to the list if not already there
if (_tcsicmp(szEntry, _T("")) != 0)
{
// Add it if it is not already there.
if (TRUE != IsThisStringInThisCStringList(gcstrListOfClusResources, szEntry))
{
gcstrListOfClusResources.AddTail(szEntry);
//iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("ListOfClusResources_Add:%s\n"),szEntry));
}
}
return;
}
INT ListOfClusResources_Check(TCHAR * szEntry)
{
int iReturn = FALSE;
//Add entry to the list if not already there
if (_tcsicmp(szEntry, _T("")) != 0)
{
// Return true if it's in there!
iReturn = IsThisStringInThisCStringList(gcstrListOfClusResources, szEntry);
}
return iReturn;
}
BOOL
RegisterIisServerInstanceResourceType(
LPWSTR pszResType,
LPWSTR pszResTypeDisplayName,
LPWSTR pszPath,
LPWSTR pszAdminPath
)
{
HCLUSTER hC;
DWORD dwErr = ERROR_SUCCESS;
HINSTANCE hClusapi;
PFN_OPENCLUSTER pfnOpenCluster;
PFN_CLOSECLUSTER pfnCloseCluster;
PFN_CREATECLUSTERRESOURCETYPE pfnCreateClusterResourceType;
HRESULT hres;
if ( hClusapi = LoadLibrary( L"clusapi.dll" ) )
{
pfnOpenCluster = (PFN_OPENCLUSTER)GetProcAddress( hClusapi, "OpenCluster" );
pfnCloseCluster = (PFN_CLOSECLUSTER)GetProcAddress( hClusapi, "CloseCluster" );
pfnCreateClusterResourceType = (PFN_CREATECLUSTERRESOURCETYPE)GetProcAddress( hClusapi, "CreateClusterResourceType" );
if ( pfnOpenCluster &&
pfnCloseCluster &&
pfnCreateClusterResourceType )
{
if ( hC = pfnOpenCluster( NULL ) )
{
hres = pfnCreateClusterResourceType(
hC,
pszResType,
pszResType,
pszPath,
5000,
60000 );
if ( SUCCEEDED( hres ) )
{
HINSTANCE hAdmin;
PFN_DLLREGISTERCLUADMINEXTENSION pfnDllRegisterCluAdminExtension;
if ( hAdmin = LoadLibrary( pszAdminPath ) )
{
pfnDllRegisterCluAdminExtension =
(PFN_DLLREGISTERCLUADMINEXTENSION)GetProcAddress( hAdmin, "DllRegisterCluAdminExtension" );
if ( pfnDllRegisterCluAdminExtension )
{
if ( FAILED(hres = pfnDllRegisterCluAdminExtension( hC )) )
{
dwErr = hres;
}
}
else
{
dwErr = GetLastError();
}
FreeLibrary( hAdmin );
}
else
{
dwErr = GetLastError();
}
}
else
{
dwErr = hres;
}
pfnCloseCluster( hC );
if ( dwErr )
{
SetLastError( dwErr );
}
}
}
else
{
dwErr = GetLastError();
}
FreeLibrary( hClusapi );
}
else
{
dwErr = GetLastError();
}
return dwErr == ERROR_SUCCESS ? TRUE : FALSE;
}
BOOL
UnregisterIisServerInstanceResourceType(
LPWSTR pszResType,
LPWSTR pszAdminPath,
BOOL bGrabVRootFromResourceAndAddToIISVRoot,
BOOL bDeleteAfterMove
)
{
CStringArray cstrArryName, cstrArryPath;
CStringArray cstrArryNameftp, cstrArryPathftp;
HCLUSTER hC;
DWORD dwErr = ERROR_SUCCESS;
HINSTANCE hClusapi;
PFN_OPENCLUSTER pfnOpenCluster;
PFN_CLOSECLUSTER pfnCloseCluster;
PFN_DELETECLUSTERRESOURCETYPE pfnDeleteClusterResourceType;
PFN_ClusterOpenEnum pfnClusterOpenEnum;
PFN_ClusterEnum pfnClusterEnum;
PFN_ClusterCloseEnum pfnClusterCloseEnum;
PFN_OpenClusterResource pfnOpenClusterResource;
PFN_CloseClusterResource pfnCloseClusterResource;
PFN_DeleteClusterResource pfnDeleteClusterResource;
PFN_OfflineClusterResource pfnOfflineClusterResource;
PFN_GetClusterResourceKey pfnGetClusterResourceKey;
PFN_ClusterRegCloseKey pfnClusterRegCloseKey;
PFN_ClusterRegQueryValue pfnClusterRegQueryValue;
PFN_GetClusterResourceState pfnGetClusterResourceState;
HRESULT hres;
HCLUSENUM hClusEnum;
WCHAR * pawchResName = NULL;
WCHAR awchResName[256];
WCHAR awchResType[256];
DWORD dwEnum;
DWORD dwType;
DWORD dwStrLen;
HRESOURCE hRes;
HKEY hKey;
BOOL fDel;
DWORD dwRetry;
hClusapi = NULL;
hClusapi = LoadLibrary(L"clusapi.dll");
if (!hClusapi)
{
hClusapi = NULL;
iisDebugOut((LOG_TYPE_ERROR, _T("UnregisterIisServerInstanceResourceType:LoadLib clusapi.dll failed.\n")));
goto UnregisterIisServerInstanceResourceType_Exit;
}
pfnOpenCluster = (PFN_OPENCLUSTER)GetProcAddress( hClusapi, "OpenCluster" );
pfnCloseCluster = (PFN_CLOSECLUSTER)GetProcAddress( hClusapi, "CloseCluster" );
pfnDeleteClusterResourceType = (PFN_DELETECLUSTERRESOURCETYPE)GetProcAddress( hClusapi, "DeleteClusterResourceType" );
pfnClusterOpenEnum = (PFN_ClusterOpenEnum)GetProcAddress( hClusapi, "ClusterOpenEnum" );
pfnClusterEnum = (PFN_ClusterEnum)GetProcAddress( hClusapi, "ClusterEnum" );
pfnClusterCloseEnum = (PFN_ClusterCloseEnum)GetProcAddress( hClusapi, "ClusterCloseEnum" );
pfnOpenClusterResource = (PFN_OpenClusterResource)GetProcAddress( hClusapi, "OpenClusterResource" );
pfnCloseClusterResource = (PFN_CloseClusterResource)GetProcAddress( hClusapi, "CloseClusterResource" );
pfnDeleteClusterResource = (PFN_DeleteClusterResource)GetProcAddress( hClusapi, "DeleteClusterResource" );
pfnOfflineClusterResource = (PFN_OfflineClusterResource)GetProcAddress( hClusapi, "OfflineClusterResource" );
pfnGetClusterResourceKey = (PFN_GetClusterResourceKey)GetProcAddress( hClusapi, "GetClusterResourceKey" );
pfnClusterRegCloseKey = (PFN_ClusterRegCloseKey)GetProcAddress( hClusapi, "ClusterRegCloseKey" );
pfnClusterRegQueryValue = (PFN_ClusterRegQueryValue)GetProcAddress( hClusapi, "ClusterRegQueryValue" );
pfnGetClusterResourceState = (PFN_GetClusterResourceState)GetProcAddress( hClusapi, "GetClusterResourceState" );
if ( !pfnOpenCluster ||
!pfnCloseCluster ||
!pfnDeleteClusterResourceType ||
!pfnClusterOpenEnum ||
!pfnClusterEnum ||
!pfnClusterCloseEnum ||
!pfnOpenClusterResource ||
!pfnCloseClusterResource ||
!pfnDeleteClusterResource ||
!pfnOfflineClusterResource ||
!pfnGetClusterResourceKey ||
!pfnClusterRegCloseKey ||
!pfnClusterRegQueryValue ||
!pfnGetClusterResourceState )
{
iisDebugOut((LOG_TYPE_ERROR, _T("UnregisterIisServerInstanceResourceType:clusapi.dll missing export function.failure.\n")));
goto UnregisterIisServerInstanceResourceType_Exit;
}
hC = pfnOpenCluster(NULL);
// if we can't open the cluster, then maybe there are none.
if (!hC) {goto UnregisterIisServerInstanceResourceType_Exit;}
// Delete all resources of type pszResType
hClusEnum = pfnClusterOpenEnum(hC, CLUSTER_ENUM_RESOURCE);
if (hClusEnum != NULL)
{
dwEnum = 0;
int iClusterEnumReturn = ERROR_SUCCESS;
// allocate the initial buffer for pawchResName
dwStrLen = 256 * sizeof(WCHAR);
pawchResName = NULL;
pawchResName = (WCHAR *) malloc( dwStrLen );
if (!pawchResName)
{
iisDebugOut((LOG_TYPE_ERROR, _T("UnregisterIisServerInstanceResourceType: malloc FAILED.out of memory.\n")));
goto UnregisterIisServerInstanceResourceType_Exit;
}
do
{
iClusterEnumReturn = ERROR_SUCCESS;
iClusterEnumReturn = pfnClusterEnum( hClusEnum, dwEnum, &dwType, pawchResName, &dwStrLen );
if (iClusterEnumReturn != ERROR_SUCCESS)
{
// Check if failed because it needs more space.
if (iClusterEnumReturn == ERROR_MORE_DATA)
{
// dwStrLen should be set to the required length returned from pfnClusterEnum
dwStrLen = (dwStrLen + 1) * sizeof(WCHAR);
pawchResName = (WCHAR *) realloc(pawchResName, dwStrLen);
if (!pawchResName)
{
iisDebugOut((LOG_TYPE_ERROR, _T("UnregisterIisServerInstanceResourceType: realloc FAILED.out of memory.\n")));
goto UnregisterIisServerInstanceResourceType_Exit;
}
// try it again.
iClusterEnumReturn = ERROR_SUCCESS;
iClusterEnumReturn = pfnClusterEnum( hClusEnum, dwEnum, &dwType, pawchResName, &dwStrLen );
if (iClusterEnumReturn != ERROR_SUCCESS)
{
iisDebugOut((LOG_TYPE_ERROR, _T("UnregisterIisServerInstanceResourceType: FAILED.err=0x%x.\n"), iClusterEnumReturn));
break;
}
}
else
{
if (iClusterEnumReturn != ERROR_NO_MORE_ITEMS)
{
// failed for some other reason than no more data
iisDebugOut((LOG_TYPE_ERROR, _T("UnregisterIisServerInstanceResourceType: FAILED.err=0x%x.\n"), iClusterEnumReturn));
}
break;
}
}
// proceed
if ( hRes = pfnOpenClusterResource( hC, pawchResName ) )
{
if ( hKey = pfnGetClusterResourceKey( hRes, KEY_READ ) )
{
dwStrLen = sizeof(awchResType)/sizeof(WCHAR);
// Check if it's for 'our' type of key (pszResType)
fDel = pfnClusterRegQueryValue( hKey, L"Type", &dwType, (LPBYTE)awchResType, &dwStrLen ) == ERROR_SUCCESS && !wcscmp( awchResType, pszResType );
pfnClusterRegCloseKey( hKey );
if ( fDel )
{
if (bDeleteAfterMove)
{
// Take the resource off line so that we can actually delete it, i guess.
pfnOfflineClusterResource( hRes );
for ( dwRetry = 0 ;dwRetry < 30 && pfnGetClusterResourceState( hRes,NULL,&dwStrLen,NULL,&dwStrLen ) != ClusterResourceOffline; ++dwRetry )
{
Sleep( 1000 );
}
}
// At this point we have successfully got the cluster to go offline
if (bGrabVRootFromResourceAndAddToIISVRoot)
{
// At this point we have successfully got the cluster to go offline
// Get the vroot names and path's here and stick into the arrays....
GetClusterIISVRoot(hRes, L"W3SVC", cstrArryName, cstrArryPath);
// Do it for FTP now.
GetClusterIISVRoot(hRes, L"MSFTPSVC", cstrArryNameftp, cstrArryPathftp);
// No need to do it for gopher since there is none.
//GetClusterIISVRoot(hRes, L"GOPHERSVC", cstrArryName, cstrArryPath);
}
// We have saved all the important data into our Array's
// now it's okay to delete the Resource
if (bDeleteAfterMove)
{
pfnDeleteClusterResource( hRes );
}
}
}
pfnCloseClusterResource( hRes );
}
// Increment to the next one
++dwEnum;
} while(TRUE);
pfnClusterCloseEnum( hClusEnum );
}
if (bDeleteAfterMove)
{
dwErr = pfnDeleteClusterResourceType(hC,pszResType );
HINSTANCE hAdmin;
if ( hAdmin = LoadLibrary( pszAdminPath ) )
{
PFN_DLLUNREGISTERCLUADMINEXTENSION pfnDllUnregisterCluAdminExtension;
pfnDllUnregisterCluAdminExtension = (PFN_DLLUNREGISTERCLUADMINEXTENSION)GetProcAddress( hAdmin, "DllUnregisterCluAdminExtension" );
if ( pfnDllUnregisterCluAdminExtension )
{
if ( FAILED(hres = pfnDllUnregisterCluAdminExtension( hC )) )
{
dwErr = hres;
}
}
else
{
dwErr = GetLastError();
}
FreeLibrary( hAdmin );
}
else
{
dwErr = GetLastError();
}
}
pfnCloseCluster( hC );
if (dwErr)
{SetLastError( dwErr );}
UnregisterIisServerInstanceResourceType_Exit:
// Copy these to the iis virtual root registry....
MoveVRootToIIS3Registry(REG_W3SVC,cstrArryName,cstrArryPath);
// Copy these to the iis virtual root registry....
MoveVRootToIIS3Registry(REG_MSFTPSVC,cstrArryNameftp,cstrArryPathftp);
if (hClusapi) {FreeLibrary(hClusapi);}
if (pawchResName) {free(pawchResName);}
return dwErr == ERROR_SUCCESS ? TRUE : FALSE;
}
void TestClusterRead(LPWSTR pszClusterName)
{
iisDebugOut_Start(_T("TestClusterRead"));
LPWSTR pszResType = L"IIS Virtual Root";
CStringArray cstrArryName, cstrArryPath;
CStringArray cstrArryNameftp, cstrArryPathftp;
HCLUSTER hC;
DWORD dwErr = ERROR_SUCCESS;
HINSTANCE hClusapi;
PFN_OPENCLUSTER pfnOpenCluster;
PFN_CLOSECLUSTER pfnCloseCluster;
PFN_DELETECLUSTERRESOURCETYPE pfnDeleteClusterResourceType;
PFN_ClusterOpenEnum pfnClusterOpenEnum;
PFN_ClusterEnum pfnClusterEnum;
PFN_ClusterCloseEnum pfnClusterCloseEnum;
PFN_OpenClusterResource pfnOpenClusterResource;
PFN_CloseClusterResource pfnCloseClusterResource;
PFN_DeleteClusterResource pfnDeleteClusterResource;
PFN_OfflineClusterResource pfnOfflineClusterResource;
PFN_GetClusterResourceKey pfnGetClusterResourceKey;
PFN_ClusterRegCloseKey pfnClusterRegCloseKey;
PFN_ClusterRegQueryValue pfnClusterRegQueryValue;
PFN_GetClusterResourceState pfnGetClusterResourceState;
HRESULT hres;
HCLUSENUM hClusEnum;
WCHAR * pawchResName = NULL;
WCHAR awchResName[256];
WCHAR awchResType[256];
DWORD dwEnum;
DWORD dwType;
DWORD dwStrLen;
HRESOURCE hRes;
HKEY hKey;
BOOL fDel;
DWORD dwRetry;
hClusapi = NULL;
hClusapi = LoadLibrary(L"clusapi.dll");
if (!hClusapi)
{
hClusapi = NULL;
iisDebugOut((LOG_TYPE_TRACE, _T("fail 1\n")));
goto TestClusterRead_Exit;
}
pfnOpenCluster = (PFN_OPENCLUSTER)GetProcAddress( hClusapi, "OpenCluster" );
pfnCloseCluster = (PFN_CLOSECLUSTER)GetProcAddress( hClusapi, "CloseCluster" );
pfnDeleteClusterResourceType = (PFN_DELETECLUSTERRESOURCETYPE)GetProcAddress( hClusapi, "DeleteClusterResourceType" );
pfnClusterOpenEnum = (PFN_ClusterOpenEnum)GetProcAddress( hClusapi, "ClusterOpenEnum" );
pfnClusterEnum = (PFN_ClusterEnum)GetProcAddress( hClusapi, "ClusterEnum" );
pfnClusterCloseEnum = (PFN_ClusterCloseEnum)GetProcAddress( hClusapi, "ClusterCloseEnum" );
pfnOpenClusterResource = (PFN_OpenClusterResource)GetProcAddress( hClusapi, "OpenClusterResource" );
pfnCloseClusterResource = (PFN_CloseClusterResource)GetProcAddress( hClusapi, "CloseClusterResource" );
pfnDeleteClusterResource = (PFN_DeleteClusterResource)GetProcAddress( hClusapi, "DeleteClusterResource" );
pfnOfflineClusterResource = (PFN_OfflineClusterResource)GetProcAddress( hClusapi, "OfflineClusterResource" );
pfnGetClusterResourceKey = (PFN_GetClusterResourceKey)GetProcAddress( hClusapi, "GetClusterResourceKey" );
pfnClusterRegCloseKey = (PFN_ClusterRegCloseKey)GetProcAddress( hClusapi, "ClusterRegCloseKey" );
pfnClusterRegQueryValue = (PFN_ClusterRegQueryValue)GetProcAddress( hClusapi, "ClusterRegQueryValue" );
pfnGetClusterResourceState = (PFN_GetClusterResourceState)GetProcAddress( hClusapi, "GetClusterResourceState" );
if ( !pfnOpenCluster ||
!pfnCloseCluster ||
!pfnDeleteClusterResourceType ||
!pfnClusterOpenEnum ||
!pfnClusterEnum ||
!pfnClusterCloseEnum ||
!pfnOpenClusterResource ||
!pfnCloseClusterResource ||
!pfnDeleteClusterResource ||
!pfnOfflineClusterResource ||
!pfnGetClusterResourceKey ||
!pfnClusterRegCloseKey ||
!pfnClusterRegQueryValue ||
!pfnGetClusterResourceState )
{
iisDebugOut((LOG_TYPE_TRACE, _T("fail 2\n")));
goto TestClusterRead_Exit;
}
iisDebugOut((LOG_TYPE_TRACE, _T("try to open cluster=%s\n"),pszClusterName));
// try to open the cluster on the computer
if ( hC = pfnOpenCluster( pszClusterName ) )
{
//
// Delete all resources of type pszResType
//
if ( (hClusEnum = pfnClusterOpenEnum( hC, CLUSTER_ENUM_RESOURCE )) != NULL )
{
dwEnum = 0;
int iClusterEnumReturn = ERROR_SUCCESS;
// allocate the initial buffer for pawchResName
dwStrLen = 256 * sizeof(WCHAR);
pawchResName = NULL;
pawchResName = (LPTSTR) malloc( dwStrLen );
if (!pawchResName)
{
iisDebugOut((LOG_TYPE_ERROR, _T("TestClusterRead: malloc FAILED.out of memory.\n")));
goto TestClusterRead_Exit;
}
do
{
iClusterEnumReturn = pfnClusterEnum( hClusEnum, dwEnum, &dwType, pawchResName, &dwStrLen );
if (iClusterEnumReturn != ERROR_SUCCESS)
{
// Check if failed because it needs more space.
if (iClusterEnumReturn == ERROR_MORE_DATA)
{
// dwStrLen should be set to the required length returned from pfnClusterEnum
dwStrLen = (dwStrLen + 1) * sizeof(WCHAR);
pawchResName = (LPTSTR) realloc(pawchResName, dwStrLen);
if (!pawchResName)
{
iisDebugOut((LOG_TYPE_ERROR, _T("TestClusterRead: realloc FAILED.out of memory.\n")));
goto TestClusterRead_Exit;
}
// try it again.
iClusterEnumReturn = pfnClusterEnum( hClusEnum, dwEnum, &dwType, pawchResName, &dwStrLen );
if (iClusterEnumReturn != ERROR_SUCCESS)
{
iisDebugOut((LOG_TYPE_ERROR, _T("TestClusterRead: FAILED.err=0x%x.\n"), iClusterEnumReturn));
break;
}
}
else
{
if (iClusterEnumReturn != ERROR_NO_MORE_ITEMS)
{
// failed for some other reason.
iisDebugOut((LOG_TYPE_ERROR, _T("TestClusterRead: FAILED.err=0x%x.\n"), iClusterEnumReturn));
}
break;
}
}
// proceed
if ( hRes = pfnOpenClusterResource( hC, pawchResName ) )
{
if ( hKey = pfnGetClusterResourceKey( hRes, KEY_READ ) )
{
dwStrLen = sizeof(awchResType)/sizeof(WCHAR);
fDel = pfnClusterRegQueryValue( hKey, L"Type", &dwType, (LPBYTE)awchResType, &dwStrLen ) == ERROR_SUCCESS && !wcscmp( awchResType, pszResType );
iisDebugOut((LOG_TYPE_TRACE, _T("TestClusterRead():ClusterRegQueryValue:%s."),awchResType));
pfnClusterRegCloseKey( hKey );
if ( fDel )
{
/*
pfnOfflineClusterResource( hRes );
for ( dwRetry = 0 ; dwRetry < 30 && pfnGetClusterResourceState( hRes,NULL,&dwStrLen,NULL,&dwStrLen ) != ClusterResourceOffline; ++dwRetry )
{
Sleep( 1000 );
}
*/
// At this point we have successfully got the cluster to go offline
// Get the vroot names and path's here and stick into the arrays....
GetClusterIISVRoot(hRes, L"W3SVC", cstrArryName, cstrArryPath);
// Do it for FTP now.
GetClusterIISVRoot(hRes, L"MSFTPSVC", cstrArryNameftp, cstrArryPathftp);
// No need to do it for gopher since there is none.
//GetClusterIISVRoot(hRes, L"GOPHERSVC", cstrArryName, cstrArryPath);
}
}
pfnCloseClusterResource( hRes );
}
// Increment to the next one
++dwEnum;
} while(TRUE);
pfnClusterCloseEnum( hClusEnum );
}
//dwErr = pfnDeleteClusterResourceType(hC,pszResType );
pfnCloseCluster( hC );
if (dwErr)
{SetLastError( dwErr );}
}
else
{
iisDebugOut((LOG_TYPE_TRACE, _T("fail 3\n")));
}
TestClusterRead_Exit:
// Copy these to the iis virtual root registry....
MoveVRootToIIS3Registry(REG_W3SVC,cstrArryName,cstrArryPath);
// Copy these to the iis virtual root registry....
MoveVRootToIIS3Registry(REG_MSFTPSVC,cstrArryNameftp,cstrArryPathftp);
if (hClusapi) {FreeLibrary(hClusapi);}
if (pawchResName) {free(pawchResName);}
iisDebugOut_End(_T("TestClusterRead"));
return;
}
/****************************************************************************************
*
* Function: GetClusterIISVRoot
*
* Args: [in] hResource , the resource whos info should be added to the list
*
* Retrurn: GetLastError, on error
*
****************************************************************************************/
int GetClusterIISVRoot(HRESOURCE hResource, LPWSTR pszTheServiceType, CStringArray &strArryOfVrootNames, CStringArray &strArryOfVrootData)
{
//iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: start\n")));
int iReturn = FALSE;
HINSTANCE hClusapi;
HINSTANCE hResutils;
PFN_CLUSTERRESOURCECONTROL pfnClusterResourceControl;
PFN_RESUTILFINDSZPROPERTY pfnResUtilFindSzProperty;
PFN_RESUTILFINDDWORDPROPERTY pfnResUtilFindDwordProperty;
//
// Initial size of the buffer
//
DWORD dwBufferSize = 256;
//
// The requested buffer size, and the number of bytes actually in the returned buffer
//
DWORD dwRequestedBufferSize = dwBufferSize;
//
// Result from the call to the cluster resource control function
//
DWORD dwResult;
//
// Buffer that holds the property list for this resource
//
LPVOID lpvPropList = NULL;
//
// The Proivate property that is being read
//
LPWSTR lpwszPrivateProp = NULL;
hClusapi = LoadLibrary( L"clusapi.dll" );
if (!hClusapi)
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: failed to loadlib clusapi.dll\n")));
goto GetIISVRoot_Exit;
}
pfnClusterResourceControl = (PFN_CLUSTERRESOURCECONTROL)GetProcAddress( hClusapi, "ClusterResourceControl" );
if (!pfnClusterResourceControl)
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: failed to GetProcAddress clusapi.dll:ClusterResourceControl\n")));
goto GetIISVRoot_Exit;
}
hResutils = LoadLibrary( L"resutils.dll" );
if (!hResutils)
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: failed to loadlib resutils.dll\n")));
goto GetIISVRoot_Exit;
}
pfnResUtilFindSzProperty = (PFN_RESUTILFINDSZPROPERTY)GetProcAddress( hResutils, "ResUtilFindSzProperty" );
if (!pfnResUtilFindSzProperty)
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: failed to GetProcAddress resutils.dll:ResUtilFindSzProperty\n")));
goto GetIISVRoot_Exit;
}
pfnResUtilFindDwordProperty = (PFN_RESUTILFINDDWORDPROPERTY)GetProcAddress( hResutils, "ResUtilFindDwordProperty" );
if (!pfnResUtilFindDwordProperty)
{
iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: failed to GetProcAddress resutils.dll:ResUtilFindDwordProperty\n")));
goto GetIISVRoot_Exit;
}
//
// Allocate memory for the resource type
//
lpvPropList = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize * sizeof(WCHAR) );
if( lpvPropList == NULL)
{
lpvPropList = NULL;
iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: E_OUTOFMEMORY\n")));
goto GetIISVRoot_Exit;
}
//
// Allocate memory for the Property
//
lpwszPrivateProp = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (_MAX_PATH+_MAX_PATH+1) * sizeof(WCHAR) );
if( lpwszPrivateProp == NULL)
{
lpvPropList = NULL;
iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: E_OUTOFMEMORY\n")));
goto GetIISVRoot_Exit;
}
//
// Get the resource's private properties (Service , InstanceId)
//
while( 1 )
{
dwResult = pfnClusterResourceControl(hResource,NULL,CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,NULL,0,lpvPropList,dwBufferSize,&dwRequestedBufferSize );
if( ERROR_SUCCESS == dwResult )
{
// ---------------------
// what the entries are:
// AccessMask (dword) = 5
// Alias (string) = "virtual dir name"
// Directory (string) = "c:\la\lalalala"
// ServiceName (string) = W3SVC, MSFTPSVC, GOPHERSVC
// ---------------------
//
// Get the "ServiceName" entry
//
dwResult = pfnResUtilFindSzProperty( lpvPropList, &dwRequestedBufferSize, L"ServiceName", &lpwszPrivateProp);
if( dwResult != ERROR_SUCCESS )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Couldn't get 'ServiceName' property.fail\n")));
goto GetIISVRoot_Exit;
}
if (_wcsicmp(lpwszPrivateProp, pszTheServiceType) == 0)
{
// okay, we want to do stuff with this one!!!
DWORD dwAccessMask;
CString csAlias;
CString csDirectory;
TCHAR szMyBigPath[_MAX_PATH + 20];
DWORD dwPrivateProp = 0;
dwRequestedBufferSize = sizeof(DWORD);
// get the Access Mask.
dwResult = pfnResUtilFindDwordProperty( lpvPropList, &dwRequestedBufferSize, L"AccessMask", &dwPrivateProp);
if( dwResult != ERROR_SUCCESS )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Couldn't get 'AccessMask' property.fail\n")));
goto GetIISVRoot_Exit;
}
dwAccessMask = dwPrivateProp;
// get the Alias
dwResult = pfnResUtilFindSzProperty( lpvPropList, &dwRequestedBufferSize, L"Alias", &lpwszPrivateProp);
if( dwResult != ERROR_SUCCESS )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Couldn't get 'Alias' property.fail\n")));
goto GetIISVRoot_Exit;
}
csAlias = lpwszPrivateProp;
// Get the Directory
dwResult = pfnResUtilFindSzProperty( lpvPropList, &dwRequestedBufferSize, L"Directory", &lpwszPrivateProp);
if( dwResult != ERROR_SUCCESS )
{
iisDebugOut((LOG_TYPE_ERROR, _T("Couldn't get 'Directory' property.fail\n")));
goto GetIISVRoot_Exit;
}
TCHAR thepath[_MAX_PATH];
TCHAR * pmypath;
csDirectory = lpwszPrivateProp;
// make sure it's a valid directory name!
if (0 != GetFullPathName(lpwszPrivateProp, _MAX_PATH, thepath, &pmypath))
{csDirectory = thepath;}
// --------------------
// formulate the string
// --------------------
//
// Put the Name into the array.
//
// "/Alias"
strArryOfVrootNames.Add(csAlias);
//
// "C:\inetpub\ASPSamp,,5"
//
_stprintf(szMyBigPath,_T("%s,,%d"),csDirectory, dwAccessMask);
strArryOfVrootData.Add(szMyBigPath);
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("Entry=[%s] '%s=%s'\n"),pszTheServiceType,csAlias,szMyBigPath));
}
goto GetIISVRoot_Exit;
}
if( ERROR_MORE_DATA == dwResult )
{
//
// Set the buffer size to the required size reallocate the buffer
//
dwBufferSize = ++dwRequestedBufferSize;
lpvPropList = (LPWSTR) HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, lpvPropList, dwBufferSize * sizeof(WCHAR) );
if ( lpvPropList == NULL)
{
// out of memory!!!!
goto GetIISVRoot_Exit;
}
}
}
GetIISVRoot_Exit:
if (lpwszPrivateProp)
{HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, lpwszPrivateProp);}
if (lpvPropList)
{HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, lpvPropList);}
//iisDebugOut((LOG_TYPE_ERROR, _T("GetClusterIISVRoot: end\n")));
return iReturn;
}
// REG_W3SVC, REG_MSFTPSVC
void MoveVRootToIIS3Registry(CString strRegPath, CStringArray &strArryOfVrootNames, CStringArray &strArryOfVrootData)
{
int nArrayItems = 0;
int i = 0;
strRegPath +=_T("\\Parameters\\Virtual Roots");
CRegKey regVR( HKEY_LOCAL_MACHINE, strRegPath);
if ((HKEY) regVR)
{
nArrayItems = (int)strArryOfVrootNames.GetSize();
// if the CString arrays are empty then we won't ever process anything (nArrayItems is 1 based)
for (i = 0; i < nArrayItems; i++ )
{
regVR.SetValue(strArryOfVrootNames[i], strArryOfVrootData[i]);
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("Array[%d]:%s=%s\n"),i,strArryOfVrootNames[i], strArryOfVrootData[i]));
}
}
return;
}
void Upgrade_WolfPack()
{
iisDebugOut_Start(_T("Upgrade_WolfPack"),LOG_TYPE_TRACE);
CRegKey regClusSvc(HKEY_LOCAL_MACHINE, scClusterPath, KEY_READ);
if ( (HKEY)regClusSvc )
{
CString csPath;
TCHAR szPath[MAX_PATH];
if (regClusSvc.QueryValue(_T("ImagePath"), csPath) == NERR_Success)
{
// string is formatted like this
// %SystemRoot%\cluster\clusprxy.exe
// Find the last \ and trim and paste the new file name on
csPath = csPath.Left(csPath.ReverseFind('\\'));
if ( csPath.IsEmpty() )
{
ASSERT(TRUE);
return;
}
csPath += _T("\\iisclex3.dll");
if ( ExpandEnvironmentStrings( (LPCTSTR)csPath,szPath,sizeof(szPath)/sizeof(TCHAR)))
{
// in iis3.0 the resources were called 'IIS Virtual Root'
// in iis4.0 it is something else (iis50 is the same as iis4)
UnregisterIisServerInstanceResourceType(L"IIS Virtual Root",(LPTSTR)szPath,TRUE,TRUE);
}
else
{
ASSERT(TRUE);
}
}
ProcessSection(g_pTheApp->m_hInfHandle, _T("Wolfpack_Upgrade"));
}
iisDebugOut_End(_T("Upgrade_WolfPack"),LOG_TYPE_TRACE);
}
/****************************************************
*
* Known "problem": If a resource doesn't come offline after the five
* retries than the function continues to try to take the other iis resources
* offline but there is no error reported. You could change this pretty simply I think.
*
*****************************************************/
DWORD BringALLIISClusterResourcesOffline()
{
//
// The return code
//
DWORD dwError = ERROR_SUCCESS;
//
// Handle for the cluster
//
HCLUSTER hCluster = NULL;
//
// Handle for the cluster enumerator
//
HCLUSENUM hClusResEnum = NULL;
//
// Handle to a resource
//
HRESOURCE hResource = NULL;
//
// The index of the resources we're taking offline
//
DWORD dwResourceIndex = 0;
//
// The type cluster object being enumerated returned by the ClusterEnum function
//
DWORD dwObjectType = 0;
//
// The name of the cluster resource returned by the ClusterEnum function
//
LPWSTR lpwszResourceName = NULL;
//
// The return code from the call to ClusterEnum
//
DWORD dwResultClusterEnum = ERROR_SUCCESS;
//
// The size of the buffer (in characters) that is used to hold the resource name's length
//
DWORD dwResourceNameBufferLength = INITIAL_RESOURCE_NAME_SIZE;
//
// Size of the resource name passed to and returned by the ClusterEnum function
//
DWORD dwClusterEnumResourceNameLength = dwResourceNameBufferLength;
BOOL iClusDependsOnIISServices = FALSE;
//
// Open the cluster
//
if ( !(hCluster = OpenCluster(NULL)) )
{
dwError = GetLastError();
// This will fail with RPC_S_SERVER_UNAVAILABLE "The RPC server is unavailable" if there is no cluster on this system
if (hCluster == NULL)
{
if ( (dwError != RPC_S_SERVER_UNAVAILABLE) &&
(dwError != EPT_S_NOT_REGISTERED ) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOffline:OpenCluster failed err=0x%x.\n"),dwError));
}
}
else
{
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOffline:OpenCluster failed err=0x%x.\n"),dwError));
}
goto clean_up;
}
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("BringALLIISClusterResourcesOffline:start.\n")));
//
// Get Enumerator for the cluster resouces
//
if ( !(hClusResEnum = ClusterOpenEnum( hCluster, CLUSTER_ENUM_RESOURCE )) )
{
dwError = GetLastError();
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOffline:ClusterOpenEnum failed err=0x%x.\n"),dwError));
goto clean_up;
}
//
// Enumerate the Resources in the cluster
//
//
// Allocate memory to hold the cluster resource name as we enumerate the resources
//
if ( !(lpwszResourceName = (LPWSTR) LocalAlloc(LPTR, dwResourceNameBufferLength * sizeof(WCHAR))) )
{
dwError = GetLastError();
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOffline:LocalAlloc failed err=0x%x.\n"),dwError));
goto clean_up;
}
//
// Enumerate all of the resources in the cluster and take the IIS Server Instance's offline
//
while( ERROR_NO_MORE_ITEMS !=
(dwResultClusterEnum = ClusterEnum(hClusResEnum,
dwResourceIndex,
&dwObjectType,
lpwszResourceName,
&dwClusterEnumResourceNameLength )) )
{
//
// If we have a resource's name
//
if( ERROR_SUCCESS == dwResultClusterEnum )
{
if ( !(hResource = OpenClusterResource( hCluster, lpwszResourceName )) )
{
dwError = GetLastError();
break;
}
// If the resource type is "IIS Server Instance", or some other one that is
// dependent upon the iis services, then we need to stop it.
iClusDependsOnIISServices = CheckForIISDependentClusters(hResource);
if (iClusDependsOnIISServices)
{
CLUSTER_RESOURCE_STATE TheState = GetClusterResourceState(hResource,NULL,0,NULL,0);
if (TheState == ClusterResourceOnline || TheState == ClusterResourceOnlinePending)
{
HKEY hKey;
if ( hKey = GetClusterResourceKey( hResource, KEY_READ ) )
{
//
// Get the resource name.
//
LPWSTR lpwsResourceName = NULL;
lpwsResourceName = GetParameter( hKey, L"Name" );
if ( lpwsResourceName != NULL )
{
// this is a resource which we will try to stop
// so we should save the name somewhere in like a global list
iisDebugOut((LOG_TYPE_TRACE, _T("OfflineClusterResource:'%s'\n"),lpwsResourceName));
ListOfClusResources_Add(lpwsResourceName);
}
if (lpwsResourceName){LocalFree((LPWSTR) lpwsResourceName);}
ClusterRegCloseKey(hKey);
}
//
// If the resource doesn't come offline quickly then wait
//
if ( ERROR_IO_PENDING == OfflineClusterResource( hResource ) )
{
for(int iRetry=0; iRetry < MAX_OFFLINE_RETRIES; iRetry++)
{
Sleep( DELAY_BETWEEN_CALLS_TO_OFFLINE );
if ( ERROR_SUCCESS == OfflineClusterResource( hResource ) )
{
break;
}
}
}
}
CloseClusterResource( hResource );
}
dwResourceIndex++;
}
//
// If the buffer wasn't large enough then retry with a larger buffer
//
if( ERROR_MORE_DATA == dwResultClusterEnum )
{
//
// Set the buffer size to the required size reallocate the buffer
//
LPWSTR lpwszResourceNameTmp = lpwszResourceName;
//
// After returning from ClusterEnum dwClusterEnumResourceNameLength
// doesn't include the null terminator character
//
dwResourceNameBufferLength = dwClusterEnumResourceNameLength + 1;
if ( !(lpwszResourceName =
(LPWSTR) LocalReAlloc (lpwszResourceName, dwResourceNameBufferLength * sizeof(WCHAR), 0)) )
{
dwError = GetLastError();
LocalFree( lpwszResourceNameTmp );
lpwszResourceNameTmp = NULL;
break;
}
}
//
// Reset dwResourceNameLength with the size of the number of characters in the buffer
// You have to do this because everytime you call ClusterEnum is sets your buffer length
// argument to the number of characters in the string it's returning.
//
dwClusterEnumResourceNameLength = dwResourceNameBufferLength;
}
clean_up:
if ( lpwszResourceName )
{
LocalFree( lpwszResourceName );
lpwszResourceName = NULL;
}
if ( hClusResEnum )
{
ClusterCloseEnum( hClusResEnum );
hClusResEnum = NULL;
}
if ( hCluster )
{
CloseCluster( hCluster );
hCluster = NULL;
}
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("BringALLIISClusterResourcesOffline:end.ret=0x%x\n"),dwError));
return dwError;
}
DWORD BringALLIISClusterResourcesOnline()
{
//
// The return code
//
DWORD dwError = ERROR_SUCCESS;
//
// Handle for the cluster
//
HCLUSTER hCluster = NULL;
//
// Handle for the cluster enumerator
//
HCLUSENUM hClusResEnum = NULL;
//
// Handle to a resource
//
HRESOURCE hResource = NULL;
//
// The index of the resources we're taking offline
//
DWORD dwResourceIndex = 0;
//
// The type cluster object being enumerated returned by the ClusterEnum function
//
DWORD dwObjectType = 0;
//
// The name of the cluster resource returned by the ClusterEnum function
//
LPWSTR lpwszResourceName = NULL;
//
// The return code from the call to ClusterEnum
//
DWORD dwResultClusterEnum = ERROR_SUCCESS;
//
// The size of the buffer (in characters) that is used to hold the resource name's length
//
DWORD dwResourceNameBufferLength = INITIAL_RESOURCE_NAME_SIZE;
//
// Size of the resource name passed to and returned by the ClusterEnum function
//
DWORD dwClusterEnumResourceNameLength = dwResourceNameBufferLength;
BOOL iClusDependsOnIISServices = FALSE;
//
// Open the cluster
//
if ( !(hCluster = OpenCluster(NULL)) )
{
dwError = GetLastError();
// This will fail with RPC_S_SERVER_UNAVAILABLE "The RPC server is unavailable" if there is no cluster on this system
if (hCluster == NULL)
{
if ( (dwError != RPC_S_SERVER_UNAVAILABLE) &&
(dwError != EPT_S_NOT_REGISTERED ) )
{
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOnline:OpenCluster failed err=0x%x.\n"),dwError));
}
}
else
{
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOnline:OpenCluster failed err=0x%x.\n"),dwError));
}
goto clean_up;
}
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("BringALLIISClusterResourcesOnline:end.ret=0x%x\n"),dwError));
//
// Get Enumerator for the cluster resouces
//
if ( !(hClusResEnum = ClusterOpenEnum( hCluster, CLUSTER_ENUM_RESOURCE )) )
{
dwError = GetLastError();
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOnline:ClusterOpenEnum failed err=0x%x.\n"),dwError));
goto clean_up;
}
//
// Enumerate the Resources in the cluster
//
//
// Allocate memory to hold the cluster resource name as we enumerate the resources
//
if ( !(lpwszResourceName = (LPWSTR) LocalAlloc(LPTR, dwResourceNameBufferLength * sizeof(WCHAR))) )
{
dwError = GetLastError();
iisDebugOut((LOG_TYPE_ERROR, _T("BringALLIISClusterResourcesOnline:LocalAlloc failed err=0x%x.\n"),dwError));
goto clean_up;
}
//
// Enumerate all of the resources in the cluster and take the IIS Server Instance's offline
//
while( ERROR_NO_MORE_ITEMS !=
(dwResultClusterEnum = ClusterEnum(hClusResEnum,
dwResourceIndex,
&dwObjectType,
lpwszResourceName,
&dwClusterEnumResourceNameLength )) )
{
//
// If we have a resource's name
//
if( ERROR_SUCCESS == dwResultClusterEnum )
{
if ( !(hResource = OpenClusterResource( hCluster, lpwszResourceName )) )
{
dwError = GetLastError();
break;
}
// If the resource type is "IIS Server Instance", or some other one that is
// dependent upon the iis services, then we probably stopped, it.
iClusDependsOnIISServices = CheckForIISDependentClusters(hResource);
if (iClusDependsOnIISServices)
{
CLUSTER_RESOURCE_STATE TheState = GetClusterResourceState(hResource,NULL,0,NULL,0);
if (TheState == ClusterResourceOffline || TheState == ClusterResourceOfflinePending)
{
int iRestart = FALSE;
LPWSTR lpwsResourceName = NULL;
HKEY hKey;
if ( hKey = GetClusterResourceKey( hResource, KEY_READ ) )
{
//
// Get the resource name.
//
lpwsResourceName = GetParameter( hKey, L"Name" );
if ( lpwsResourceName != NULL )
{
iRestart = ListOfClusResources_Check(lpwsResourceName);
}
ClusterRegCloseKey(hKey);
}
if (TRUE == iRestart)
{
iisDebugOut((LOG_TYPE_TRACE, _T("OnlineClusterResource:'%s'.\n"),lpwsResourceName));
OnlineClusterResource(hResource);
if (lpwsResourceName){LocalFree((LPWSTR) lpwsResourceName);}
}
}
}
CloseClusterResource( hResource );
dwResourceIndex++;
}
//
// If the buffer wasn't large enough then retry with a larger buffer
//
if( ERROR_MORE_DATA == dwResultClusterEnum )
{
//
// Set the buffer size to the required size reallocate the buffer
//
LPWSTR lpwszResourceNameTmp = lpwszResourceName;
//
// After returning from ClusterEnum dwClusterEnumResourceNameLength
// doesn't include the null terminator character
//
dwResourceNameBufferLength = dwClusterEnumResourceNameLength + 1;
if ( !(lpwszResourceName =
(LPWSTR) LocalReAlloc (lpwszResourceName, dwResourceNameBufferLength * sizeof(WCHAR), 0)) )
{
dwError = GetLastError();
LocalFree( lpwszResourceNameTmp );
lpwszResourceNameTmp = NULL;
break;
}
}
//
// Reset dwResourceNameLength with the size of the number of characters in the buffer
// You have to do this because everytime you call ClusterEnum is sets your buffer length
// argument to the number of characters in the string it's returning.
//
dwClusterEnumResourceNameLength = dwResourceNameBufferLength;
}
clean_up:
if ( lpwszResourceName )
{
LocalFree( lpwszResourceName );
lpwszResourceName = NULL;
}
if ( hClusResEnum )
{
ClusterCloseEnum( hClusResEnum );
hClusResEnum = NULL;
}
if ( hCluster )
{
CloseCluster( hCluster );
hCluster = NULL;
}
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("BringALLIISClusterResourcesOnline:end.ret=0x%x\n"),dwError));
return dwError;
}
LPWSTR GetParameter(
IN HKEY ClusterKey,
IN LPCWSTR ValueName
)
/*++
Routine Description:
Reads a REG_SZ parameter from the cluster regitry, and allocates the
necessary storage for it.
Arguments:
ClusterKey - supplies the cluster key where the parameter is stored.
ValueName - supplies the name of the value.
Return Value:
A pointer to a buffer containing the parameter value on success.
NULL on failure.
--*/
{
LPWSTR value = NULL;
DWORD valueLength;
DWORD valueType;
DWORD status;
valueLength = 0;
status = ClusterRegQueryValue( ClusterKey,ValueName,&valueType,NULL,&valueLength );
if ( (status != ERROR_SUCCESS) && (status != ERROR_MORE_DATA) )
{
SetLastError(status);
return(NULL);
}
if ( valueType == REG_SZ )
{
valueLength += sizeof(UNICODE_NULL);
}
value = (LPWSTR) LocalAlloc(LMEM_FIXED, valueLength);
if ( value == NULL )
{return(NULL);}
status = ClusterRegQueryValue(ClusterKey,ValueName,&valueType,(LPBYTE)value,&valueLength);
if ( status != ERROR_SUCCESS)
{
LocalFree(value);
SetLastError(status);
value = NULL;
}
return(value);
}
INT CheckForIISDependentClusters(HRESOURCE hResource)
{
INT iReturn = FALSE;
// If the resource type is "IIS Server Instance",
// "SMTP Server Instance" or "NNTP Server Instance" then take it offline
iReturn = ResUtilResourceTypesEqual(IIS_RESOURCE_TYPE_NAME, hResource);
if (!iReturn){iReturn = ResUtilResourceTypesEqual(SMTP_RESOURCE_TYPE_NAME, hResource);}
if (!iReturn){iReturn = ResUtilResourceTypesEqual(NNTP_RESOURCE_TYPE_NAME, hResource);}
// check for other ones which might be listed in the inf file!
if (!iReturn && g_pTheApp->m_hInfHandle)
{
CStringList strList;
CString csTheSection = _T("ClusterResType_DependsonIIS");
if (GetSectionNameToDo(g_pTheApp->m_hInfHandle, csTheSection))
{
if (ERROR_SUCCESS == FillStrListWithListOfSections(g_pTheApp->m_hInfHandle, strList, csTheSection))
{
// loop thru the list returned back
if (strList.IsEmpty() == FALSE)
{
POSITION pos;
CString csEntry;
pos = strList.GetHeadPosition();
while (pos)
{
csEntry = strList.GetAt(pos);
int iTempReturn = FALSE;
iTempReturn = ResUtilResourceTypesEqual(csEntry, hResource);
if (iTempReturn)
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("CheckForIISDependentClusters:yes='%s'\n"),csEntry));
iReturn = TRUE;
break;
}
strList.GetNext(pos);
}
}
}
}
}
return iReturn;
}
DWORD WINAPI DoesThisServiceTypeExistInCluster(PVOID pInfo)
{
INT iTemp = FALSE;
CLUSTER_SVC_INFO_FILL_STRUCT * pMyStructOfInfo;
pMyStructOfInfo = (CLUSTER_SVC_INFO_FILL_STRUCT *) pInfo;
//pMyStructOfInfo->szTheClusterName
//pMyStructOfInfo->pszTheServiceType
//pMyStructOfInfo->csTheReturnServiceResName
//pMyStructOfInfo->dwReturnStatus
//
// The return code
//
DWORD dwReturn = ERROR_NOT_FOUND;
pMyStructOfInfo->dwReturnStatus = dwReturn;
//
// Handle for the cluster
//
HCLUSTER hCluster = NULL;
//
// Handle for the cluster enumerator
//
HCLUSENUM hClusResEnum = NULL;
//
// Handle to a resource
//
HRESOURCE hResource = NULL;
//
// The index of the resources we're taking offline
//
DWORD dwResourceIndex = 0;
//
// The type cluster object being enumerated returned by the ClusterEnum function
//
DWORD dwObjectType = 0;
//
// The name of the cluster resource returned by the ClusterEnum function
//
LPWSTR lpwszResourceName = NULL;
//
// The return code from the call to ClusterEnum
//
DWORD dwResultClusterEnum = ERROR_SUCCESS;
//
// The size of the buffer (in characters) that is used to hold the resource name's length
//
DWORD dwResourceNameBufferLength = INITIAL_RESOURCE_NAME_SIZE;
//
// Size of the resource name passed to and returned by the ClusterEnum function
//
DWORD dwClusterEnumResourceNameLength = dwResourceNameBufferLength;
//
// Open the cluster
//
hCluster = OpenCluster(pMyStructOfInfo->szTheClusterName);
if( !hCluster )
{
dwReturn = GetLastError();
goto DoesThisServiceTypeExistInCluster_Exit;
}
//
// Get Enumerator for the cluster resouces
//
if ( !(hClusResEnum = ClusterOpenEnum( hCluster, CLUSTER_ENUM_RESOURCE )) )
{
dwReturn = GetLastError();
goto DoesThisServiceTypeExistInCluster_Exit;
}
//
// Enumerate the Resources in the cluster
//
//
// Allocate memory to hold the cluster resource name as we enumerate the resources
//
if ( !(lpwszResourceName = (LPWSTR) LocalAlloc(LPTR, dwResourceNameBufferLength * sizeof(WCHAR))) )
{
dwReturn = GetLastError();
goto DoesThisServiceTypeExistInCluster_Exit;
}
//
// Enumerate all of the resources in the cluster
//
while( ERROR_NO_MORE_ITEMS != (dwResultClusterEnum = ClusterEnum(hClusResEnum,dwResourceIndex,&dwObjectType,lpwszResourceName,&dwClusterEnumResourceNameLength)) )
{
//
// If we have a resource's name
//
if( ERROR_SUCCESS == dwResultClusterEnum )
{
if ( !(hResource = OpenClusterResource( hCluster, lpwszResourceName )) )
{
dwReturn = GetLastError();
break;
}
// If the resource type is "IIS Server Instance", or one that depends upon iis like smtp or nntp then
// check further to see if they have our services (W3SVC or MSFTPSVC)
iTemp = ResUtilResourceTypesEqual(IIS_RESOURCE_TYPE_NAME, hResource);
if (!iTemp){iTemp = ResUtilResourceTypesEqual(SMTP_RESOURCE_TYPE_NAME, hResource);}
if (!iTemp){iTemp = ResUtilResourceTypesEqual(NNTP_RESOURCE_TYPE_NAME, hResource);}
if (TRUE == iTemp)
{
// if the resource hangs it will hang on this call
pMyStructOfInfo->dwReturnStatus = ERROR_INVALID_BLOCK;
if (ERROR_SUCCESS == IsResourceThisTypeOfService(hResource, pMyStructOfInfo->pszTheServiceType))
{
CString csResName;
//
// Yes! we found it
//
dwReturn = ERROR_SUCCESS;
// Display the resource name for fun
if (TRUE == GetClusterResName(hResource, &csResName))
{
// copy it to the return string
*pMyStructOfInfo->csTheReturnServiceResName = csResName;
}
CloseClusterResource( hResource );
goto DoesThisServiceTypeExistInCluster_Exit;
}
dwReturn = ERROR_NOT_FOUND;
CloseClusterResource( hResource );
}
dwResourceIndex++;
}
//
// If the buffer wasn't large enough then retry with a larger buffer
//
if( ERROR_MORE_DATA == dwResultClusterEnum )
{
//
// Set the buffer size to the required size reallocate the buffer
//
LPWSTR lpwszResourceNameTmp = lpwszResourceName;
//
// After returning from ClusterEnum dwClusterEnumResourceNameLength
// doesn't include the null terminator character
//
dwResourceNameBufferLength = dwClusterEnumResourceNameLength + 1;
if ( !(lpwszResourceName =
(LPWSTR) LocalReAlloc (lpwszResourceName, dwResourceNameBufferLength * sizeof(WCHAR), 0)) )
{
dwReturn = GetLastError();
LocalFree( lpwszResourceNameTmp );
lpwszResourceNameTmp = NULL;
break;
}
}
//
// Reset dwResourceNameLength with the size of the number of characters in the buffer
// You have to do this because everytime you call ClusterEnum is sets your buffer length
// argument to the number of characters in the string it's returning.
//
dwClusterEnumResourceNameLength = dwResourceNameBufferLength;
}
DoesThisServiceTypeExistInCluster_Exit:
if ( lpwszResourceName )
{
LocalFree( lpwszResourceName );
lpwszResourceName = NULL;
}
if ( hClusResEnum )
{
ClusterCloseEnum( hClusResEnum );
hClusResEnum = NULL;
}
if ( hCluster )
{
CloseCluster( hCluster );
hCluster = NULL;
}
pMyStructOfInfo->dwReturnStatus = dwReturn;
return dwReturn;
}
DWORD IsResourceThisTypeOfService(HRESOURCE hResource, LPWSTR pszTheServiceType)
{
DWORD dwReturn = ERROR_NOT_FOUND;
HINSTANCE hClusapi = NULL;
HINSTANCE hResutils = NULL;
PFN_CLUSTERRESOURCECONTROL pfnClusterResourceControl;
PFN_RESUTILFINDSZPROPERTY pfnResUtilFindSzProperty;
//
// Initial size of the buffer
//
DWORD dwBufferSize = 256;
//
// The requested buffer size, and the number of bytes actually in the returned buffer
//
DWORD dwRequestedBufferSize = dwBufferSize;
//
// Result from the call to the cluster resource control function
//
DWORD dwResult;
//
// Buffer that holds the property list for this resource
//
LPVOID lpvPropList = NULL;
//
// The Proivate property that is being read
//
LPWSTR lpwszPrivateProp = NULL;
//
// Load cluster dll's
//
hClusapi = LoadLibrary( L"clusapi.dll" );
if (!hClusapi)
{
dwReturn = TYPE_E_CANTLOADLIBRARY;
goto IsResourceThisTypeOfService_Exit;
}
pfnClusterResourceControl = (PFN_CLUSTERRESOURCECONTROL)GetProcAddress( hClusapi, "ClusterResourceControl" );
if (!pfnClusterResourceControl)
{
dwReturn = ERROR_PROC_NOT_FOUND;
goto IsResourceThisTypeOfService_Exit;
}
hResutils = LoadLibrary( L"resutils.dll" );
if (!hResutils)
{
dwReturn = TYPE_E_CANTLOADLIBRARY;
goto IsResourceThisTypeOfService_Exit;
}
pfnResUtilFindSzProperty = (PFN_RESUTILFINDSZPROPERTY)GetProcAddress( hResutils, "ResUtilFindSzProperty" );
if (!pfnResUtilFindSzProperty)
{
dwReturn = ERROR_PROC_NOT_FOUND;
goto IsResourceThisTypeOfService_Exit;
}
//
// Allocate memory for the resource type
//
lpvPropList = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize * sizeof(WCHAR) );
if( lpvPropList == NULL)
{
lpvPropList = NULL;
dwReturn = E_OUTOFMEMORY;
goto IsResourceThisTypeOfService_Exit;
}
//
// Allocate memory for the Property
//
lpwszPrivateProp = (LPWSTR) HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (_MAX_PATH+_MAX_PATH+1) * sizeof(WCHAR) );
if( lpwszPrivateProp == NULL)
{
lpvPropList = NULL;
dwReturn = E_OUTOFMEMORY;
goto IsResourceThisTypeOfService_Exit;
}
//
// Get the resource's private properties (Service , InstanceId)
//
while( 1 )
{
dwResult = pfnClusterResourceControl(hResource,NULL,CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,NULL,0,lpvPropList,dwBufferSize,&dwRequestedBufferSize );
if( ERROR_SUCCESS == dwResult )
{
// ---------------------
// what the entries are:
// AccessMask (dword) = 5
// Alias (string) = "virtual dir name"
// Directory (string) = "c:\la\lalalala"
// ServiceName (string) = W3SVC, MSFTPSVC, GOPHERSVC
// ---------------------
//
// Get the "ServiceName" entry
//
dwResult = pfnResUtilFindSzProperty( lpvPropList, &dwRequestedBufferSize, L"ServiceName", &lpwszPrivateProp);
if( dwResult != ERROR_SUCCESS )
{
dwReturn = dwResult;
goto IsResourceThisTypeOfService_Exit;
}
if (_wcsicmp(lpwszPrivateProp, pszTheServiceType) == 0)
{
// Okay, we found at least 1 service name that matches
// the one that was passed -- which we're supposed to look for
// return success
dwReturn = ERROR_SUCCESS;
}
goto IsResourceThisTypeOfService_Exit;
}
if( ERROR_MORE_DATA == dwResult )
{
//
// Set the buffer size to the required size reallocate the buffer
//
dwBufferSize = ++dwRequestedBufferSize;
lpvPropList = (LPWSTR) HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, lpvPropList, dwBufferSize * sizeof(WCHAR) );
if ( lpvPropList == NULL)
{
dwReturn = E_OUTOFMEMORY;
goto IsResourceThisTypeOfService_Exit;
}
}
}
IsResourceThisTypeOfService_Exit:
if (lpwszPrivateProp)
{HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, lpwszPrivateProp);}
if (lpvPropList)
{HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, lpvPropList);}
if (hClusapi)
{FreeLibrary(hClusapi);}
if (hResutils)
{FreeLibrary(hClusapi);}
return dwReturn;
}
INT GetClusterResName(HRESOURCE hResource, CString * csReturnedName)
{
int iReturn = FALSE;
HKEY hKey;
if ( hKey = GetClusterResourceKey( hResource, KEY_READ ) )
{
//
// Get the resource name.
//
LPWSTR lpwsResourceName = NULL;
lpwsResourceName = GetParameter( hKey, L"Name" );
if ( lpwsResourceName != NULL )
{
//wcscpy(csReturnedName,lpwsResourceName);
*csReturnedName = lpwsResourceName;
iReturn = TRUE;
}
if (lpwsResourceName){LocalFree((LPWSTR) lpwsResourceName);}
ClusterRegCloseKey(hKey);
}
return iReturn;
}
INT DoClusterServiceCheck(CLUSTER_SVC_INFO_FILL_STRUCT * pMyStructOfInfo)
{
int iReturn = FALSE;
DWORD ThreadID = 0;
DWORD status = 0;
HANDLE hMyThread = CreateThread(NULL,0,DoesThisServiceTypeExistInCluster,pMyStructOfInfo,0,&ThreadID);
if (hMyThread)
{
// wait for 30 secs only
DWORD res = WaitForSingleObject(hMyThread,30*1000);
if (res == WAIT_TIMEOUT)
{
iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("ERROR DoClusterServiceCheck thread never finished...\n")));
GetExitCodeThread(hMyThread, &status);
if (status == STILL_ACTIVE)
{
if (hMyThread != NULL)
{TerminateThread(hMyThread, 0);}
}
}
else
{
GetExitCodeThread(hMyThread, &status);
if (status == STILL_ACTIVE)
{
if (hMyThread != NULL)
{TerminateThread(hMyThread, 0);}
}
else
{
if (ERROR_SUCCESS == status)
{iReturn = TRUE;}
}
if (hMyThread != NULL)
{CloseHandle(hMyThread);}
}
}
return iReturn;
}
INT DoesClusterServiceExist(void)
{
if (-1 == g_ClusterSVCExist)
{
CRegKey regClusSvc(HKEY_LOCAL_MACHINE, scClusterPath2, KEY_READ);
if ( (HKEY) regClusSvc )
{
g_ClusterSVCExist = 1;
}
else
{
g_ClusterSVCExist = 0;
}
}
return g_ClusterSVCExist;
}
#endif //_CHICAGO_