Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2395 lines
57 KiB

/*++
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