|
|
/*++
Copyright (c) 1992-1996 Microsoft Corporation
Module Name:
iisutil.c
Abstract:
IIS Resource utility routine DLL
Author:
Pete Benoit (v-pbenoi) 12-SEP-1996
Revision History:
--*/
#include "iisutil.h"
#if defined(_DEBUG_SUPPORT)
#include <time.h>
#endif
#include <pudebug.h>
IMSAdminBase* CMetaData::g_pMBCom; CRITICAL_SECTION CMetaData::g_cs;
VOID FreeIISResource( IN LPIIS_RESOURCE ResourceEntry )
/*++
Routine Description:
Free all the storage for a IIS_RESOURCE
Arguments:
vr - virtual root to free
Return Value:
NONE
--*/
{ if (ResourceEntry != NULL) { if ( ResourceEntry->ResourceName != NULL ) { LocalFree( ResourceEntry->ResourceName ); ResourceEntry->ResourceName = NULL; } #if 0
if ( ResourceEntry->ResourceHandle != NULL ) { CloseClusterResource( ResourceEntry->ResourceHandle ); } #endif
if ( ResourceEntry->ParametersKey != NULL ) { ClusterRegCloseKey( ResourceEntry->ParametersKey ); ResourceEntry->ParametersKey = NULL; }
if ( ResourceEntry->Params.ServiceName != NULL ) { LocalFree( ResourceEntry->Params.ServiceName); ResourceEntry->Params.ServiceName = NULL; }
if ( ResourceEntry->Params.InstanceId != NULL ) { LocalFree( ResourceEntry->Params.InstanceId); ResourceEntry->Params.InstanceId = NULL; }
if ( ResourceEntry->Params.MDPath != NULL ) { LocalFree( ResourceEntry->Params.MDPath); ResourceEntry->Params.MDPath = NULL; }
} // ResourceEntry != NULL
} // FreeIISResource
VOID DestructIISResource( IN LPIIS_RESOURCE ResourceEntry )
/*++
Routine Description:
Free all the storage for a ResourceEntry and the ResourceEntry
Arguments:
vr - virtual root to free
Return Value:
NONE
--*/ { if (ResourceEntry != NULL) { FreeIISResource(ResourceEntry); LocalFree(ResourceEntry); } // ResourceEntry != NULL
} // DestructIISResource
DWORD GetServerBindings( LPWSTR MDPath, DWORD dwServiceType, SOCKADDR* psaServer, LPDWORD pdwPort ) /*++
Routine Description: Read the first ip address and port number form the ServerBindings property for a particlar branch of the metabase
Arguments: MDPath : the particular branch of the metabase to read the information from (ex. /LM/W3SVC/1) dwServiceType : the service type id pszServer : the structure to save the ip address pdwPort : the returned port number Return Value:
sucess : ERROR_SUCCESS failure : the win32 error code of the failure --*/ { DWORD dwStatus = ERROR_SUCCESS; DWORD dwR = 0; DWORD dwW = 0; TCHAR * achBindings = NULL; INT cBindingsSize = sizeof(TCHAR)*1024; TCHAR * pB = NULL; TCHAR * pP = NULL; DWORD cL = 0; BOOL bGetBindingsStatus = FALSE ; //
// allocate space for the server bindings string
//
if( !(achBindings = (TCHAR*)LocalAlloc(LMEM_FIXED, cBindingsSize)) ) { dwStatus = GetLastError(); TR( (DEBUG_BUFFER,"[GetServerBindings] Can't allocate memory for server bindings info. (%d)\n",dwStatus) ); } if ( achBindings ) { //
// Get binding info from metabase
//
CMetaData MD; if ( MD.Open( MDPath ) ) { dwR = cBindingsSize; if( !(bGetBindingsStatus = MD.GetMultisz( L"", MD_SERVER_BINDINGS, IIS_MD_UT_SERVER, achBindings, &dwR )) ) { dwStatus = GetLastError(); if ( ERROR_INSUFFICIENT_BUFFER == dwStatus ) { TR( (DEBUG_BUFFER,"[GetServerBindings] Buffer too small, reallocating\n") ); //
// (# 296798) If the original binding's buffer size is too small so realloc memory to the required size
//
TCHAR* achBindingsNew = (TCHAR*)LocalReAlloc(achBindings, dwR, 0); if( !achBindingsNew ) { dwStatus = GetLastError(); LocalFree (achBindings); achBindings = NULL; } else { achBindings = achBindingsNew; bGetBindingsStatus = MD.GetMultisz( L"", MD_SERVER_BINDINGS, IIS_MD_UT_SERVER, achBindings, &dwR ); } } else { //
// error getting server bindings information from the metabase
//
TR( (DEBUG_BUFFER,"[GetServerBindings] error getting server bindings information (%d)\n", dwStatus) ); } } MD.Close(); } else { dwStatus = GetLastError(); TR( (DEBUG_BUFFER,"[GetServerBindings] failed to open MD, error %08x\n", dwStatus) ); } }
//
// not getting server bindings information is a serious error
//
if ( !bGetBindingsStatus ) { TR( (DEBUG_BUFFER,"[GetServerBindings] error getting server bindings infomation (%d) \n", dwStatus ) ); } else { TR( (DEBUG_BUFFER,"[GetServerBindings] got server bindings string (%S) \n", achBindings ) ); (*pdwPort) = DEFAULT_PORT[dwServiceType]; ZeroMemory( psaServer, sizeof(SOCKADDR) ); ((SOCKADDR_IN*)psaServer)->sin_family = AF_INET; ((SOCKADDR_IN*)psaServer)->sin_addr.s_net = 127; ((SOCKADDR_IN*)psaServer)->sin_addr.s_impno = 1;
//
// Each binding is of the form "addr:port:hostname"
// we look only at addr & port
//
// use the 1st valid binding ( i.e. contains ':' )
//
dwR /= sizeof(WCHAR); for ( pB = achBindings ; *pB && dwR ; ) { if ( (cL = wcslen( pB ) + 1 ) > dwR ) { break; } if ( (pP = wcschr( pB, L':' )) ) { SOCKADDR sa; INT cL = sizeof(sa); pP[0] = '\0'; if ( achBindings[0] && WSAStringToAddress( achBindings, AF_INET, NULL, &sa, &cL ) == 0 ) { memcpy( psaServer, &sa, cL ); } else { TR( (DEBUG_BUFFER,"[GetServerBindings] WSAStringToAddress failed converting string (%S) \n", achBindings ) ); } if ( iswdigit(pP[1]) ) { (*pdwPort) = wcstoul( pP + 1, NULL, 0 ); } TR( (DEBUG_BUFFER,"[GetServerBindings] found binding addr %S %u.%u.%u.%u port %u\n", achBindings, ((SOCKADDR_IN*)psaServer)->sin_addr.s_net, ((SOCKADDR_IN*)psaServer)->sin_addr.s_host, ((SOCKADDR_IN*)psaServer)->sin_addr.s_lh, ((SOCKADDR_IN*)psaServer)->sin_addr.s_impno, (*pdwPort) ) );
goto found_bindings; } pB += cL; dwR -= cL; } }
found_bindings: if( achBindings ) { LocalFree(achBindings); achBindings = NULL; } return dwStatus ; } // GetServerBindings
CHAR IsAliveRequest[]="TRACK / HTTP/1.1\r\nHost: CLUSIIS\r\nConnection: close\r\nContent-length: 0\r\n\r\n"; // # 292727
DWORD VerifyIISService( IN LPWSTR MDPath, IN DWORD ServiceType, IN DWORD dwPort, IN SOCKADDR saServer, IN PLOG_EVENT_ROUTINE LogEvent )
/*++
Routine Description:
Verify that the IIS service is running and that it has virtual roots contained in the resource Steps: 1. get server instance binding info 2. connect to server, send HTTP request & wait for response
Arguments:
Resource - supplies the resource id
IsAliveFlag - says this is an IsAlive call
Return Value:
TRUE - if service is running and service contains resources virtual roots
FALSE - service is in any other state
--*/ { DWORD status = ERROR_SUCCESS; DWORD dwR; DWORD dwW; SOCKET s; CHAR IsAliveResponse[1024]; TR( (DEBUG_BUFFER,"[IISVerify] Enter\n") );
TR( (DEBUG_BUFFER,"[IISVerify] checking address %S : %u.%u.%u.%u port %u\n", MDPath, ((SOCKADDR_IN*)&saServer)->sin_addr.s_net, ((SOCKADDR_IN*)&saServer)->sin_addr.s_host, ((SOCKADDR_IN*)&saServer)->sin_addr.s_lh, ((SOCKADDR_IN*)&saServer)->sin_addr.s_impno, dwPort ) );
if ( (s = TcpSockConnectToHost( &saServer, dwPort, CHECK_IS_ALIVE_CONNECT_TIMEOUT )) != NULL ) { if ( ServiceType == IIS_SERVICE_TYPE_W3 ) { //
// If this is W3 then attempt to send a request and get response from server.
//
if ( TcpSockSend( s, IsAliveRequest, sizeof(IsAliveRequest), &dwW, CHECK_IS_ALIVE_SEND_TIMEOUT ) && TcpSockRecv( s, IsAliveResponse, sizeof(IsAliveResponse), &dwR, CHECK_IS_ALIVE_SEND_TIMEOUT ) && dwR > 5 ) { status = ERROR_SUCCESS; TcpSockClose( s ); goto finished_check; } else { TR( (DEBUG_BUFFER,"[IISVerify] failed HTTP request\n") ); status = ERROR_SERVICE_NOT_ACTIVE; } } else if ( ServiceType == IIS_SERVICE_TYPE_SMTP ) { //
// If this is SMTP then check the reply code.
// (220: service ready)
//
if ( TcpSockRecv( s, IsAliveResponse, sizeof(IsAliveResponse), &dwR, CHECK_IS_ALIVE_SEND_TIMEOUT ) && strncmp( IsAliveResponse, "220", 3 ) == 0 ) { status = ERROR_SUCCESS; TcpSockClose( s ); goto finished_check; } else { TR( (DEBUG_BUFFER,"[IISVerify] failed SMTP request, response:%S\n", IsAliveResponse) ); status = ERROR_SERVICE_NOT_ACTIVE; } } else if ( ServiceType == IIS_SERVICE_TYPE_NNTP ) { //
// If this is NNTP then check the reply code.
// (200: service ready - posting allowed) or
// (201: service ready - no posting allowed)
//
if ( TcpSockRecv( s, IsAliveResponse, sizeof(IsAliveResponse), &dwR, CHECK_IS_ALIVE_SEND_TIMEOUT ) && ( strncmp( IsAliveResponse, "200", 3 ) == 0 || strncmp( IsAliveResponse, "201", 3 ) == 0 ) ) { status = ERROR_SUCCESS; TcpSockClose( s ); goto finished_check; } else { TR( (DEBUG_BUFFER,"[IISVerify] failed NNTP request, response:%S\n", IsAliveResponse) ); status = ERROR_SERVICE_NOT_ACTIVE; } } else { status = ERROR_SUCCESS; TcpSockClose( s ); goto finished_check; } TcpSockClose( s ); } else { TR( (DEBUG_BUFFER,"[IISVerify] failed to connect port %d\n", dwPort) ); status = ERROR_SERVICE_NOT_ACTIVE; } finished_check:
//
// Check to see if there was an error
//
if ( status != ERROR_SUCCESS ) { TR( (DEBUG_BUFFER,"[IISVerify] FALSE (%d), Leave\n", status) ); #if defined(DBG_CANT_VERIFY)
g_fDbgCantVerify = TRUE; #endif
} else { TR( (DEBUG_BUFFER,"[IISVerify] TRUE, Leave\n") ); } return status;
} // VerifyIISService
LPWSTR GetClusterResourceType( HRESOURCE hResource, LPIIS_RESOURCE ResourceEntry, IN PLOG_EVENT_ROUTINE LogEvent )
/*++
Routine Description:
Returns the resource type for the resource
Arguments:
hResource - handle to a resource
Return Value:
TRUE - if service is running and service contains resources virtual roots
FALSE - service is in any other state
--*/ { DWORD dwType = 0; DWORD dwSize = MAX_DEFAULT_WSTRING_SIZE; WCHAR lpzTypeName[MAX_DEFAULT_WSTRING_SIZE]; LPWSTR TypeName = NULL; HKEY hKey = NULL; LONG status;
(LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[GetClusterResourceType] entry\n"); //
// Valid resource now open the reg and get it's type
//
hKey = GetClusterResourceKey(hResource,KEY_READ); if (hKey == NULL) { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[GetClusterResourceType] Unable to open resource key = %1!u!\n",GetLastError());
return(NULL); }
//
// Got a valid key now get the type
//
status = ClusterRegQueryValue(hKey,L"Type",&dwType,(LPBYTE)lpzTypeName,&dwSize);
if (status == ERROR_SUCCESS) { TypeName = (WCHAR*)LocalAlloc(LMEM_FIXED,(dwSize+16)*sizeof(WCHAR)); if (TypeName != NULL) { wcscpy(TypeName,lpzTypeName); } // TypeName != NULL
} else { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[GetClusterResourceType] Unable to Query Value = %1!u!\n",status); }
ClusterRegCloseKey(hKey);
(LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[GetClusterResourceType] TypeName = %1!ws!\n",TypeName);
return TypeName;
}// end GetClusterResourceType
HRESOURCE ClusterGetResourceDependency( IN LPCWSTR ResourceName, IN LPCWSTR ResourceType, IN LPIIS_RESOURCE ResourceEntry, IN PLOG_EVENT_ROUTINE LogEvent )
/*++
Routine Description:
Returns a dependent resource
Arguments:
ResourceName - the resource
ResourceType - the type of resource that it depends on
Return Value:
NULL - error (use GetLastError() to get further info)
NON-NULL - Handle to a resource of type ResourceType
--*/ { HCLUSTER hCluster = NULL; HRESOURCE hResource = NULL; HRESOURCE hResDepends = NULL; HRESENUM hResEnum = NULL; DWORD dwType = 0; DWORD dwIndex = 0; DWORD dwSize = MAX_DEFAULT_WSTRING_SIZE; WCHAR lpszName[MAX_DEFAULT_WSTRING_SIZE]; LPWSTR ResTypeName = NULL; DWORD status;
//
// Open the cluster
//
hCluster = OpenCluster(NULL); if (hCluster == NULL) { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[ClusterGetResourceDependency] Unable to OpenCluster status = %1!u!\n",GetLastError());
return(NULL); }
//
// Open the resource
//
hResource = OpenClusterResource(hCluster,ResourceName); if (hResource == NULL) { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[ClusterGetResourceDependency] Unable to OpenClusterResource status = %1!u!\n",GetLastError());
goto error_exit; }
//
// Open the depends on enum
//
hResEnum = ClusterResourceOpenEnum(hResource,CLUSTER_RESOURCE_ENUM_DEPENDS); if (hResEnum == NULL) { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[ClusterGetResourceDependency] Unsuccessful ClusterResourceOpenEnum status = %1!u!\n",GetLastError());
goto error_exit; }
//
// Enumerate all the depends on keys
//
do { dwSize = MAX_DEFAULT_WSTRING_SIZE; status = ClusterResourceEnum(hResEnum,dwIndex++,&dwType,lpszName,&dwSize); if ((status != ERROR_SUCCESS) && (status != ERROR_MORE_DATA)) { //
// This checks to see if NO dependencies were found
//
if ((status == ERROR_NO_MORE_ITEMS) && (dwIndex == 1)) { SetLastError( ERROR_NO_DATA ); } else { SetLastError( status ); } goto error_exit; }
//
// Determine the type of resource found
//
hResDepends = OpenClusterResource(hCluster,lpszName); if (hResDepends == NULL) { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[ClusterGetResourceDependency] Unsuccessful OpenClusterResource status = %1!u!\n",GetLastError()); } else { //
// Valid resource now open the reg and get it's type
//
ResTypeName = GetClusterResourceType(hResDepends,ResourceEntry,LogEvent); if (ResTypeName == NULL) { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[ClusterGetResourceDependency] Unsuccessful GetClusterResourceType status = %1!u!\n",GetLastError()); } else { //
// Compare the types and look for a match
//
if ( (_wcsicmp(ResTypeName,ResourceType)) == 0) { //
//Found a match
//
goto success_exit;
} // END _wcsicmp(ResTypeName,ResourceType)
} // END if ResourceTypeName != NULL
} // END if hResDepends != NULL
//
// Close all handles, key's
//
if (hResDepends != NULL) { CloseClusterResource(hResDepends); hResDepends = NULL; } } while ((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA));
if (hResDepends == NULL) { (LogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"[ClusterGetResourceDependency] Unsuccessful resource enum status = %1!u! %2!x! last error = %3!u!\n",status,status,GetLastError()); } success_exit: error_exit: //
// At this point hResDepends is NULL if no match or non-null (success)
//
if (hCluster != NULL) { CloseCluster(hCluster); } if (hResource != NULL) { CloseClusterResource(hResource); } if (hResEnum != NULL) { ClusterResourceCloseEnum(hResEnum); }
return hResDepends; } // ClusterGetResourceDependency
DWORD SetInstanceState( IN PCLUS_WORKER pWorker, IN LPIIS_RESOURCE ResourceEntry, IN RESOURCE_STATUS* presourceStatus, IN CLUSTER_RESOURCE_STATE TargetState, IN LPWSTR TargetStateString, IN DWORD dwMdPropControl, IN DWORD dwMdPropTarget )
/*++
Routine Description:
Set the server instance to te requested state ( start / stop )
Arguments:
pWorker - thread context to monitor for cancel request ResourceEntry - ptr to IIS server instance resource ctx presourceStatus - ptr to struct to be updated with new status TargetState - cluster API target state dwMdPropControl - IIS metabase property value for request to server dwMdPropTarget - IIS metabase property value for target state
Return Value:
Win32 error code, ERROR_SUCCESS if success
--*/
{ DWORD status = ERROR_SERVICE_NOT_ACTIVE; int retry; DWORD dwS; DWORD dwEnabled;
CMetaData MD;
TR( (DEBUG_BUFFER,"[SetInstanceState] Enter\n") );
if ( MD.Open( ResourceEntry->Params.MDPath, TRUE, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) {
//
// Reenable clustering. If we are receiving this notification we know
// enabled should be set to true.
//
if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwEnabled, 0 ) || dwEnabled == 0 ) { TR( (DEBUG_BUFFER,"[SetInstanceState] cluster not enabled\n") );
if ( !MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 1, 0 ) ) { TR( (DEBUG_BUFFER,"[SetInstanceState] failed to re-enable cluster\n") ); } }
if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) ) { TR( (DEBUG_BUFFER,"[SetInstanceState] state prob is %d\n",dwS) ); } else { TR( (DEBUG_BUFFER,"[SetInstanceState] failed to probe server state\n") ); dwS = 0xffffffff; }
if ( dwS != dwMdPropTarget ) { if ( MD.SetDword( L"", MD_CLUSTER_SERVER_COMMAND, IIS_MD_UT_SERVER, dwMdPropControl, 0 ) ) { MD.Close(); TR( (DEBUG_BUFFER,"[SetInstanceState] command set to %d\n",dwMdPropControl) );
for ( retry = (TargetState == ClusterResourceOnline) ? IISCLUS_ONLINE_TIMEOUT :IISCLUS_OFFLINE_TIMEOUT ; retry-- ; ) { if ( ClusWorkerCheckTerminate(pWorker) ) { status = ERROR_OPERATION_ABORTED; break; }
if ( MD.GetDword( ResourceEntry->Params.MDPath, MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) ) { if ( dwS == dwMdPropTarget ) { status = ERROR_SUCCESS; break; } TR( (DEBUG_BUFFER,"[SetInstanceState] state is %d, waiting for %d\n",dwS,dwMdPropTarget) ); } else { TR( (DEBUG_BUFFER,"[SetInstanceState] failed to get server state\n") ); break; }
Sleep(SERVER_START_DELAY); }
} else { TR( (DEBUG_BUFFER,"[SetInstanceState] failed to set server command to %d\n",dwMdPropControl) ); MD.Close(); } } else { status = ERROR_SUCCESS; MD.Close(); } } else { if ( g_hEventLog && TargetState == ClusterResourceOnline ) { LPCTSTR aErrStr[3]; WCHAR aErrCode[32];
_ultow( GetLastError(), aErrCode, 10 );
aErrStr[0] = ResourceEntry->Params.ServiceName; aErrStr[1] = ResourceEntry->Params.InstanceId; aErrStr[2] = aErrCode;
ReportEvent( g_hEventLog, EVENTLOG_ERROR_TYPE, 0, IISCL_EVENT_CANT_OPEN_METABASE, NULL, sizeof(aErrStr) / sizeof(LPCTSTR), 0, aErrStr, NULL ); }
TR( (DEBUG_BUFFER,"[SetInstanceState] failed to open %S, error %08x\n",ResourceEntry->Params.MDPath, GetLastError()) ); }
if ( status != ERROR_SUCCESS ) { //
// Error
//
(g_IISLogEvent)( ResourceEntry->ResourceHandle, LOG_ERROR, L"Error %1!u! cannot bring resource %2!ws! %3!ws!.\n", status, ResourceEntry->ResourceName, TargetStateString );
presourceStatus->ResourceState = ClusterResourceFailed; ResourceEntry->State = ClusterResourceFailed; } else { //
// Success, update state, log message
//
presourceStatus->ResourceState = TargetState; ResourceEntry->State = TargetState;
TR( (DEBUG_BUFFER,"[SetInstanceState] Setting Metadata Path:%S ResourceEntry->State:%d\n", ResourceEntry->Params.MDPath, TargetState) );
(g_IISLogEvent)( ResourceEntry->ResourceHandle, LOG_INFORMATION, L"Success bringing resource %1!ws! %2!ws!.\n", ResourceEntry->ResourceName, TargetStateString ); }
TR( (DEBUG_BUFFER,"[SetInstanceState] status = %d, Leave\n",status) );
return status; }
DWORD InstanceEnableCluster( LPWSTR pwszServiceName, LPWSTR pwszInstanceId )
/*++
Routine Description:
Ensure server instance in state consistent with cluster membership. If not already part of a cluster, stop instance & flag it as cluster enabled
Arguments:
pwszServiceName - IIS service name ( e.g. W3SVC ) pwszInstanceId - IIS serverr instance ID
Return Value:
win32 error code or ERROR_SUCCESS if success
--*/
{ DWORD status = ERROR_SERVICE_NOT_ACTIVE; int retry; DWORD dwS; TCHAR achMDPath[80]; DWORD dwL;
dwL = wsprintf( achMDPath, L"/LM/%s/%s", pwszServiceName, pwszInstanceId );
CMetaData MD;
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] for %S, Enter\n", achMDPath ) );
if ( MD.Open( achMDPath, TRUE, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) { //
// ensure instance is marked as cluster enabled
//
if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwS, 0 ) || dwS == 0 ) { if ( MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 1, 0 ) ) { if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) ) { TR( (DEBUG_BUFFER,"[InstanceEnableCluster] state prob is %d\n",dwS) ); } else { TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to probe server state\n") ); dwS = 0xffffffff; }
MD.Close(); if ( dwS != MD_SERVER_STATE_STOPPED ) { if ( MD.Open( achMDPath, TRUE, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) && MD.SetDword( L"", MD_CLUSTER_SERVER_COMMAND, IIS_MD_UT_SERVER, MD_SERVER_COMMAND_STOP, 0 ) ) {
TR( (DEBUG_BUFFER,"[InstanceEnableCluster] command set to %d\n",MD_SERVER_COMMAND_STOP) );
for ( retry = 30 ; retry-- ; ) { if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) ) { if ( dwS == MD_SERVER_STATE_STOPPED ) { status = ERROR_SUCCESS; break; } TR( (DEBUG_BUFFER,"[InstanceEnableCluster] state is %d, waiting for %d\n",dwS,MD_SERVER_STATE_STOPPED) ); } else { TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to get server state\n") ); break; }
Sleep(SERVER_START_DELAY); } } else { TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_STOP) ); } } else { status = ERROR_SUCCESS; } } else { TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to set cluster enabled\n") ); } } } else { TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to open %S, error %08x\n",achMDPath, GetLastError()) ); } TR( (DEBUG_BUFFER,"[InstanceEnableCluster] status = %d, Leave\n",status) );
MD.Close(); return status; }
DWORD InstanceDisableCluster( LPWSTR pwszServiceName, LPWSTR pwszInstanceId )
/*++
Routine Description:
Ensure server instance in state consistent with cluster membership. If already part of a cluster, stop instance & remove its cluster enabled flag.
Arguments:
pwszServiceName - IIS service name ( e.g. W3SVC ) pwszInstanceId - IIS serverr instance ID
Return Value:
win32 error code or ERROR_SUCCESS if success
--*/
{ DWORD status = ERROR_SERVICE_NOT_ACTIVE; int retry; DWORD dwS; TCHAR achMDPath[80]; DWORD dwL;
dwL = wsprintf( achMDPath, L"/LM/%s/%s", pwszServiceName, pwszInstanceId );
CMetaData MD;
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] for %S, Enter\n", achMDPath ) );
if ( MD.Open( achMDPath, TRUE, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) { //
// ensure instance is marked as cluster enabled
//
if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwS, 0 ) || ( dwS == 0) ) { MD.Close(); return status; }
if ( MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 0, 0 ) ) { if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) ) { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] state prob is %d\n",dwS) ); } else { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to probe server state\n") ); dwS = 0xffffffff; }
MD.Close(); if ( dwS != MD_SERVER_STATE_STOPPED ) { if ( MD.Open( achMDPath, TRUE, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) && MD.SetDword( L"", MD_SERVER_COMMAND, IIS_MD_UT_SERVER, MD_SERVER_COMMAND_STOP, 0 )) {
TR( (DEBUG_BUFFER,"[InstanceDisableCluster] command set to %d\n",MD_SERVER_COMMAND_STOP) );
for ( retry = 30 ; retry-- ; ) { if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) ) { if ( dwS == MD_SERVER_STATE_STOPPED ) { break; } TR( (DEBUG_BUFFER,"[InstanceDisableCluster] state is %d, waiting for %d\n",dwS,MD_SERVER_STATE_STOPPED) ); } else { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to get server state\n") ); break; }
Sleep(SERVER_START_DELAY); } } else { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_STOP) ); }
MD.Close();
//
// restart the server
//
if ( MD.Open( achMDPath, TRUE, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) && MD.SetDword( L"", MD_SERVER_COMMAND, IIS_MD_UT_SERVER, MD_SERVER_COMMAND_START, 0 )) { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] set server command to %d\n",MD_SERVER_COMMAND_START) ); } else { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_START) ); }
status = ERROR_SUCCESS; } } else { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set cluster disbled\n") ); } } else { TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to open %S, error %08x\n",achMDPath, GetLastError()) ); }
MD.Close(); TR( (DEBUG_BUFFER,"[InstanceDisableCluster] status = %d, Leave\n",status) );
return status; }
BOOL CMetaData::Open( LPWSTR pszPath, BOOL fReconnect, DWORD dwFlags ) /*++
Routine Description:
Opens the metabase
Arguments:
pszPath - Path to open dwFlags - Open flags
Return:
TRUE if success, FALSE on error, (call GetLastError())
--*/ { HRESULT hRes;
TR( (DEBUG_BUFFER,"[MDOpen] %S\n",pszPath) );
if ( !GetCoInit() ) { TR( (DEBUG_BUFFER,"[MDOpen] calling CoInit\n") ); hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED); if ( FAILED(hRes) ) { TR( (DEBUG_BUFFER,"[MD:GetMD::CoInitializeEx] error %08x\n",HRESULTTOWIN32( hRes )) ); SetLastError( HRESULTTOWIN32( hRes ) ); return FALSE; } SetCoInit( TRUE ); }
EnterCriticalSection( &g_cs );
for ( int retry = 2 ; retry-- ; ) { if ( !GetMD() ) { LeaveCriticalSection( &g_cs ); TR( (DEBUG_BUFFER,"[MDOpen] can't get MD interface\n") ); return FALSE; }
TR( (DEBUG_BUFFER,"[MDOpen] before OpenKey\n") );
hRes = g_pMBCom->OpenKey( METADATA_MASTER_ROOT_HANDLE, pszPath, dwFlags, MB_TIMEOUT, &m_hMB );
if ( SUCCEEDED( hRes ) ) { LeaveCriticalSection( &g_cs ); TR( (DEBUG_BUFFER,"[MDOpen] OK, leave\n") ); return TRUE; }
if ( !fReconnect ) { break; }
TR( (DEBUG_BUFFER,"[MDOpen] error %d, fReconnect=%d\n",HRESULTTOWIN32( hRes ),fReconnect) ); if ( HRESULTTOWIN32( hRes ) == RPC_S_SERVER_UNAVAILABLE || HRESULTTOWIN32( hRes ) == RPC_S_CALL_FAILED_DNE ) { ReleaseMD(); } else { break; } }
SetLastError( HRESULTTOWIN32( hRes ) );
LeaveCriticalSection( &g_cs ); return FALSE; }
BOOL CMetaData::Close( VOID )
/*++
Routine Description:
Close opened handle to metadata
Arguments:
None
Return Value:
TRUE if success, otherwise FALSE
--*/
{ if ( m_hMB ) { g_pMBCom->CloseKey( m_hMB ); m_hMB = NULL; }
return TRUE; }
BOOL CMetaData::SetData( LPWSTR pszPath, DWORD dwPropID, DWORD dwUserType, DWORD dwDataType, VOID * pvData, DWORD cbData, DWORD dwFlags )
/*++
Routine Description:
Sets a metadata property on an openned metabase
Arguments:
pszPath - Path to set data on dwPropID - Metabase property ID dwUserType - User type for this property dwDataType - Type of data being set (dword, string etc) pvData - Pointer to data cbData - Size of data dwFlags - Inheritance flags
Return:
TRUE if success, FALSE on error, (call GetLastError())
--*/
{ METADATA_RECORD mdRecord; HRESULT hRes;
mdRecord.dwMDIdentifier = dwPropID; mdRecord.dwMDAttributes = dwFlags; mdRecord.dwMDUserType = dwUserType; mdRecord.dwMDDataType = dwDataType; mdRecord.dwMDDataLen = cbData; mdRecord.pbMDData = (PBYTE) pvData;
EnterCriticalSection( &g_cs );
if ( !GetMD() ) { LeaveCriticalSection( &g_cs ); return FALSE; }
hRes = g_pMBCom->SetData( m_hMB, pszPath, &mdRecord );
if ( SUCCEEDED( hRes )) { LeaveCriticalSection( &g_cs ); return TRUE; }
SetLastError( HRESULTTOWIN32( hRes ) );
LeaveCriticalSection( &g_cs ); return FALSE; }
BOOL CMetaData::GetData( LPWSTR pszPath, DWORD dwPropID, DWORD dwUserType, DWORD dwDataType, VOID * pvData, DWORD * pcbData, DWORD dwFlags )
/*++
Routine Description:
Retrieves a metadata property on an openned metabase
Arguments:
pszPath - Path to set data on dwPropID - Metabase property ID dwUserType - User type for this property dwDataType - Type of data being set (dword, string etc) pvData - Pointer to data pcbData - Size of pvData, receives size of object dwFlags - Inheritance flags
Return:
TRUE if success, FALSE on error, (call GetLastError())
--*/
{ METADATA_RECORD mdRecord; HRESULT hRes; DWORD dwRequiredLen; BOOL fConvert;
mdRecord.pbMDData = (PBYTE) pvData; mdRecord.dwMDDataLen = *pcbData; mdRecord.dwMDIdentifier = dwPropID; mdRecord.dwMDAttributes = dwFlags; mdRecord.dwMDUserType = dwUserType; mdRecord.dwMDDataType = dwDataType;
EnterCriticalSection( &g_cs );
if ( !GetMD() ) { LeaveCriticalSection( &g_cs ); return FALSE; }
hRes = g_pMBCom->GetData( m_hMB, pszPath, &mdRecord, &dwRequiredLen );
if ( SUCCEEDED( hRes )) { LeaveCriticalSection( &g_cs );
*pcbData = mdRecord.dwMDDataLen;
return TRUE; }
LeaveCriticalSection( &g_cs );
*pcbData = dwRequiredLen;
SetLastError( HRESULTTOWIN32( hRes ) );
return FALSE; }
BOOL CMetaData::Init( )
/*++
Routine Description:
Initialize access to metadata
Arguments:
None
Return Value:
TRUE if success, otherwise FALSE
--*/
{ INITIALIZE_CRITICAL_SECTION( &g_cs ); g_pMBCom = NULL;
return TRUE; }
BOOL CMetaData::Terminate( )
/*++
Routine Description:
Terminate access to metadata
Arguments:
None
Return Value:
TRUE if success, otherwise FALSE
--*/
{ DeleteCriticalSection( &g_cs ); if ( g_pMBCom ) { if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) { return FALSE; } g_pMBCom->Release(); g_pMBCom = NULL; }
return TRUE; }
BOOL CMetaData::GetMD( )
/*++
Routine Description:
Initialize interface pointer to DCOM metabase object
Arguments:
None
Return Value:
TRUE if success, otherwise FALSE
--*/
{ if ( g_pMBCom == NULL ) { HRESULT hRes; hRes = CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_SERVER, IID_IMSAdminBase, (void**) &g_pMBCom);
TR( (DEBUG_BUFFER,"[MD:GetMD] called cocreate\n") ); if ( hRes == CO_E_NOTINITIALIZED ) { TR( (DEBUG_BUFFER,"[MD:GetMD] call coinit\n") ); hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED); if ( FAILED(hRes) ) { TR( (DEBUG_BUFFER,"[MD:GetMD::CoInitializeEx] error %08x\n",HRESULTTOWIN32( hRes )) ); SetLastError( HRESULTTOWIN32( hRes ) ); return FALSE; } hRes = CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_SERVER, IID_IMSAdminBase, (void**) &g_pMBCom); }
if ( FAILED(hRes) ) { TR( (DEBUG_BUFFER,"[MD:GetMD] error %08x\n",HRESULTTOWIN32( hRes )) ); SetLastError( HRESULTTOWIN32( hRes ) ); return FALSE; } }
return TRUE; }
BOOL CMetaData::ReleaseMD( )
/*++
Routine Description:
Release interface pointer to DCOM metabase object
Arguments:
None
Return Value:
TRUE if success, otherwise FALSE
--*/
{ if ( g_pMBCom ) { g_pMBCom->Release(); g_pMBCom = NULL; }
return TRUE; }
SOCKET TcpSockConnectToHost( SOCKADDR* psaServer, DWORD dwPort, DWORD dwTimeOut )
/*++
Routine Description:
Create a TCP connection to specified port on specified machine
Arguments:
psaServer - target address dwPort - target port to connect to dwTimeOut - time out for connection ( in seconds )
Return Value:
socket or NULL if error
--*/
{ SOCKET sNew; BOOL fWrite = FALSE; INT serr = 0; SOCKADDR_IN inAddr; PSOCKADDR addr; INT addrLength;
sNew = WSASocket( AF_INET, SOCK_STREAM, 0, NULL, // protocol info
0, // Group ID = 0 => no constraints
WSA_FLAG_OVERLAPPED // completion port notifications
);
if ( sNew == INVALID_SOCKET ) { TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] failed WSASocket, error %08x\n",GetLastError()) ); return NULL; }
addrLength = sizeof(inAddr);
ZeroMemory(&inAddr, addrLength); inAddr.sin_family = AF_INET; inAddr.sin_port = 0;
((PSOCKADDR_IN)psaServer)->sin_port = (unsigned short)htons((unsigned short)dwPort );
//
// Bind an address to socket
//
if ( bind( sNew, (PSOCKADDR)&inAddr, addrLength ) == 0 && WSAConnect( sNew, (PSOCKADDR)psaServer, addrLength, NULL, NULL, NULL, NULL ) == 0 && WaitForSocketWorker( INVALID_SOCKET, sNew, NULL, &fWrite, dwTimeOut ) == 0 ) { return sNew; }
TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] failed connect, error %08x\n",GetLastError()) ); closesocket( sNew );
return NULL; }
VOID TcpSockClose( SOCKET hSocket )
/*++
Routine Description:
Close a socket opened by TcpSockConnectToLocalHost
Arguments:
hSocket - socket opened by TcpSockConnectToLocalHost
Return Value:
Nothing
--*/
{ closesocket( hSocket ); }
BOOL TcpSockSend( IN SOCKET sock, IN LPVOID pBuffer, IN DWORD cbBuffer, OUT PDWORD pcbTotalSent, IN DWORD nTimeout )
/*++
Description: Do async socket send
Arguments: sock - socket pBuffer - buffer to send cbBuffer - size of buffer pcbTotalSent - bytes sent nTimeout - timeout in seconds to use
Returns: FALSE if there is any error. TRUE otherwise
--*/
{ INT serr = 0; INT cbSent; DWORD dwBytesSent = 0; ULONG one;
//
// Loop until there's no more data to send.
//
while( cbBuffer > 0 ) { //
// Wait for the socket to become writeable.
//
BOOL fWrite = FALSE;
serr = WaitForSocketWorker( INVALID_SOCKET, sock, NULL, &fWrite, nTimeout );
if( serr == 0 ) { //
// Write a block to the socket.
//
cbSent = send( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
if( cbSent < 0 ) { //
// Socket error.
//
serr = WSAGetLastError(); } else { dwBytesSent += (DWORD)cbSent; } }
if( serr != 0 ) { TR( (DEBUG_BUFFER,"[TcpSockSend] failed send, error %08x\n",serr) ); break; }
pBuffer = (LPVOID)( (LPBYTE)pBuffer + cbSent ); cbBuffer -= (DWORD)cbSent; }
if(pcbTotalSent) { *pcbTotalSent = dwBytesSent; }
return (serr == 0);
} // SockSend
BOOL TcpSockRecv( IN SOCKET sock, IN LPVOID pBuffer, IN DWORD cbBuffer, OUT LPDWORD pbReceived, IN DWORD nTimeout )
/*++
Description: Do async socket recv
Arguments: sock - The target socket. pBuffer - Will receive the data. cbBuffer - The size (in bytes) of the buffer. pbReceived - Will receive the actual number of bytes nTimeout - timeout in seconds
Returns: TRUE, if successful
--*/
{ INT serr = 0; DWORD cbTotal = 0; INT cbReceived; DWORD dwBytesRecv = 0;
ULONG one; BOOL fRead = FALSE;
//
// Wait for the socket to become readable.
//
serr = WaitForSocketWorker( sock, INVALID_SOCKET, &fRead, NULL, nTimeout );
if( serr == 0 ) { //
// Read a block from the socket.
//
cbReceived = recv( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
if( cbReceived < 0 ) { //
// Socket error.
//
serr = WSAGetLastError(); } else { cbTotal = cbReceived; } } else { TR( (DEBUG_BUFFER,"[TcpSockRecv] failed send, error %08x\n",serr) ); }
if( serr == 0 ) { //
// Return total byte count to caller.
//
*pbReceived = cbTotal; }
return (serr == 0);
} // SockRecv
INT WaitForSocketWorker( IN SOCKET sockRead, IN SOCKET sockWrite, IN LPBOOL pfRead, IN LPBOOL pfWrite, IN DWORD nTimeout )
/*++
Description: Wait routine NOTES: Any (but not all) sockets may be INVALID_SOCKET. For each socket that is INVALID_SOCKET, the corresponding pf* parameter may be NULL.
Arguments: sockRead - The socket to check for readability. sockWrite - The socket to check for writeability. pfRead - Will receive TRUE if sockRead is readable. pfWrite - Will receive TRUE if sockWrite is writeable. nTimeout - timeout in seconds
Returns: SOCKERR - 0 if successful, !0 if not. Will return WSAETIMEDOUT if the timeout period expired.
--*/
{ INT serr = 0; TIMEVAL timeout; LPTIMEVAL ptimeout; fd_set fdsRead; fd_set fdsWrite; INT res;
//
// Ensure we got valid parameters.
//
if( ( sockRead == INVALID_SOCKET ) && ( sockWrite == INVALID_SOCKET ) ) {
return WSAENOTSOCK; }
timeout.tv_sec = (LONG )nTimeout;
if( timeout.tv_sec == 0 ) {
//
// If the connection timeout == 0, then we have no timeout.
// So, we block and wait for the specified conditions.
//
ptimeout = NULL;
} else {
//
// The connectio timeout is > 0, so setup the timeout structure.
//
timeout.tv_usec = 0;
ptimeout = &timeout; }
for( ; ; ) {
//
// Setup our socket sets.
//
FD_ZERO( &fdsRead ); FD_ZERO( &fdsWrite );
if( sockRead != INVALID_SOCKET ) {
FD_SET( sockRead, &fdsRead ); *pfRead = FALSE; }
if( sockWrite != INVALID_SOCKET ) {
FD_SET( sockWrite, &fdsWrite ); *pfWrite = FALSE; }
//
// Wait for one of the conditions to be met.
//
res = select( 0, &fdsRead, &fdsWrite, NULL, ptimeout );
if( res == 0 ) {
//
// Timeout.
//
serr = WSAETIMEDOUT; break;
} else if( res == SOCKET_ERROR ) {
//
// Bad news.
//
serr = WSAGetLastError(); TR( (DEBUG_BUFFER,"[WaitForSocketWorker] failed send, error %08x\n",serr) ); break; } else { BOOL fSomethingWasSet = FALSE;
if( pfRead != NULL ) {
*pfRead = FD_ISSET( sockRead, &fdsRead ); fSomethingWasSet = TRUE; }
if( pfWrite != NULL ) { *pfWrite = FD_ISSET( sockWrite, &fdsWrite ); fSomethingWasSet = TRUE; }
if( fSomethingWasSet ) {
//
// Success.
//
serr = 0; break; } else { //
// select() returned with neither a timeout, nor
// an error, nor any bits set. This feels bad...
//
continue; } } }
return serr;
} // WaitForSocketWorker()
#if defined(_DEBUG_SUPPORT)
void TimeStamp( FILE* f ) { time_t t = time( NULL ); struct tm *pTm;
if ( pTm = localtime( &t ) ) { fprintf( f, "%02d:%02d:%02d> ", pTm->tm_hour, pTm->tm_min, pTm->tm_sec ); } }
void InitDebug( ) { char achPath[MAX_PATH]; HKEY hKey; DWORD dwValue; DWORD dwType; DWORD dwLen; BOOL fDoDebug = FALSE; BOOL fAppend = TRUE; INT cL = 0; LPSTR pTmp;
//
// get debug flag from registry
//
if ( RegOpenKey( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters", &hKey ) == ERROR_SUCCESS ) { TR( (DEBUG_BUFFER,"[InitDebug] opened key\n") ); dwLen = sizeof( dwValue ); if ( RegQueryValueEx( hKey, L"ClusterDebugMode", NULL, &dwType, (LPBYTE)&dwValue, &dwLen ) == ERROR_SUCCESS && dwType == REG_DWORD ) { fDoDebug = !!dwValue; }
dwLen = sizeof( dwValue ); if ( RegQueryValueEx( hKey, L"ClusterDebugAppendToFile", NULL, &dwType, (LPBYTE)&dwValue, &dwLen ) == ERROR_SUCCESS && dwType == REG_DWORD ) { fAppend = !!dwValue; }
dwLen = sizeof( achPath ); if ( RegQueryValueExA( hKey, "ClusterDebugPath", NULL, &dwType, (LPBYTE)achPath, &dwLen ) == ERROR_SUCCESS && dwType == REG_SZ ) { if ( dwLen ) { cL = dwLen - 1; if ( cL && achPath[cL-1] != '\\' ) { achPath[cL++] = '\\'; } } }
RegCloseKey( hKey ); }
if ( fDoDebug && cL ) { memcpy( achPath + cL, "iisclus.trc", sizeof("iisclus.trc") ); debug_file = fopen(achPath, fAppend ? "a" : "w" ); } }
#endif
DWORD WINAPI ResUtilReadProperties( IN HKEY RegistryKey, IN const PRESUTIL_PROPERTY_ITEM PropertyTable, IN OUT LPBYTE OutParams, IN RESOURCE_HANDLE ResourceHandle, IN PLOG_EVENT_ROUTINE LogEvent )
/*++
Routine Description:
Read properties based on a property table.
Arguments:
RegistryKey - Supplies the cluster key where the properties are stored.
PropertyTable - Pointer to the property table to process.
OutParams - Parameter block to read into.
ResourceHandle - Handle for the resource fo which properties are being read.
LogEvent - Function to call to log events to the cluster log.
Return Value:
ERROR_SUCCESS - Properties read successfully.
ERROR_INVALID_DATA - Required property not present.
--*/
{ PRESUTIL_PROPERTY_ITEM propertyItem = PropertyTable; HKEY key; DWORD status = ERROR_SUCCESS; LPWSTR pszInValue; LPBYTE pbInValue; DWORD dwInValue; LPWSTR * ppszOutValue; LPBYTE * ppbOutValue; LPDWORD pdwOutValue;
while ( propertyItem->Name != NULL ) { //
// If the value resides at a different location, create the key.
//
if ( propertyItem->KeyName != NULL ) {
DWORD disposition;
status = ClusterRegCreateKey( RegistryKey, propertyItem->KeyName, 0, KEY_ALL_ACCESS, NULL, &key, &disposition ); if ( status != ERROR_SUCCESS ) { return(status); } } else { key = RegistryKey; }
switch ( propertyItem->Format ) { case CLUSPROP_FORMAT_DWORD: pdwOutValue = (LPDWORD) &OutParams[propertyItem->Offset]; status = ResUtilGetDwordValue( RegistryKey, propertyItem->Name, pdwOutValue, propertyItem->Default ); if ( (status == ERROR_FILE_NOT_FOUND) && !(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) { *pdwOutValue = propertyItem->Default; } break;
case CLUSPROP_FORMAT_SZ: case CLUSPROP_FORMAT_EXPAND_SZ: ppszOutValue = (LPWSTR*) &OutParams[propertyItem->Offset]; pszInValue = ResUtilGetSzValue( RegistryKey, propertyItem->Name ); if ( pszInValue == NULL ) { status = GetLastError(); if ( (status == ERROR_FILE_NOT_FOUND) && !(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) { if ( *ppszOutValue != NULL ) { LocalFree( *ppszOutValue ); *ppszOutValue = NULL; }
// If a default is specified, copy it.
if ( propertyItem->lpDefault != NULL ) { *ppszOutValue = (LPWSTR)LocalAlloc( LMEM_FIXED, (lstrlenW( (LPCWSTR) propertyItem->lpDefault ) + 1) * sizeof(WCHAR) ); if ( *ppszOutValue == NULL ) { status = GetLastError(); } else { lstrcpyW( *ppszOutValue, (LPCWSTR) propertyItem->lpDefault ); } } } } else { if ( *ppszOutValue != NULL ) { LocalFree( *ppszOutValue ); } *ppszOutValue = pszInValue; } break;
case CLUSPROP_FORMAT_MULTI_SZ: case CLUSPROP_FORMAT_BINARY: ppbOutValue = (LPBYTE*) &OutParams[propertyItem->Offset]; pdwOutValue = (PDWORD) &OutParams[propertyItem->Offset+sizeof(LPBYTE*)]; status = ResUtilGetBinaryValue( RegistryKey, propertyItem->Name, &pbInValue, &dwInValue ); if ( status == ERROR_SUCCESS ) { if ( *ppbOutValue != NULL ) { LocalFree( *ppbOutValue ); } *ppbOutValue = pbInValue; *pdwOutValue = dwInValue; } else if ( (status == ERROR_FILE_NOT_FOUND) && !(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) { if ( *ppbOutValue != NULL ) { LocalFree( *ppbOutValue ); *ppbOutValue = NULL; *pdwOutValue = 0; }
// If a default is specified, copy it.
if ( propertyItem->lpDefault != NULL ) { *ppbOutValue = (LPBYTE)LocalAlloc( LMEM_FIXED, propertyItem->Minimum ); if ( *ppbOutValue == NULL ) { status = GetLastError(); } else { memcpy( *ppbOutValue, propertyItem->lpDefault, propertyItem->Minimum ); *pdwOutValue = propertyItem->Minimum; } } } break; }
//
// Close the key if we opened it.
//
if ( (propertyItem->KeyName != NULL) && (key != NULL) ) { ClusterRegCloseKey( key ); }
//
// Handle any errors that occurred.
//
if ( status != ERROR_SUCCESS ) { (LogEvent)( ResourceHandle, LOG_ERROR, L"Unable to read the '%1' property. Error: %2!u!.\n", propertyItem->Name, status ); if ( propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED ) { if ( status == ERROR_FILE_NOT_FOUND ) { status = ERROR_INVALID_DATA; } break; } else { status = ERROR_SUCCESS; } }
//
// Advance to the next property.
//
propertyItem++; }
return(status);
} // ResUtilReadProperties
|