2858 lines
71 KiB
C++
2858 lines
71 KiB
C++
/*++
|
||
|
||
Copyright (c) 1992-1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
iis.c
|
||
|
||
Abstract:
|
||
|
||
Resource DLL for IIS. This DLL supports the following IIS services
|
||
WWW
|
||
FTP
|
||
|
||
Each instance of a resouce is an IIS instance ( a.k.a. virtual server )
|
||
Virtual root may have dependencies on IP Addresses, Physical Disks, or UNC names.
|
||
|
||
Known Limitations
|
||
|
||
|
||
Author:
|
||
|
||
Pete Benoit (v-pbenoi) 12-SEP-1996
|
||
|
||
Revision History:
|
||
|
||
Rich Demar (rdemar) 5-18-1999
|
||
|
||
--*/
|
||
|
||
|
||
#define INITGUID
|
||
#include "iisutil.h"
|
||
#include <clusapi.h>
|
||
#include <resapi.h>
|
||
//#include "resmonp.h"
|
||
//#include "clusres.h"
|
||
#include <pudebug.h>
|
||
|
||
DECLARE_DEBUG_BUFFER;
|
||
|
||
//
|
||
// Names used to start service
|
||
//
|
||
|
||
LPCWSTR ActualServiceName[] = {
|
||
L"W3SVC", // WWW
|
||
L"MSFTPSVC", // FTP
|
||
L"SMTPSVC", // SMTP
|
||
L"NNTPSVC" // NNTP
|
||
};
|
||
|
||
#define PARAM_NAME__SERVICENAME L"ServiceName"
|
||
#define PARAM_NAME__INSTANCEID L"InstanceId"
|
||
|
||
#define MAX_SCMFAILURE_RETRY 5
|
||
#define BACKOFF_MULTIPLIER 2
|
||
#define DELAY_BETWEEN_ISALIVE_CHECKS 5*1000
|
||
|
||
#define MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS 5*60*1000 // five minutes in milliseconds
|
||
|
||
//
|
||
// IIS resource private read-write parameters.
|
||
//
|
||
RESUTIL_PROPERTY_ITEM
|
||
IISResourcePrivateProperties[] = {
|
||
{ PARAM_NAME__SERVICENAME, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(IIS_PARAMS,ServiceName) },
|
||
{ PARAM_NAME__INSTANCEID, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(IIS_PARAMS,InstanceId) },
|
||
{ 0 }
|
||
};
|
||
|
||
|
||
//
|
||
// Global data.
|
||
//
|
||
|
||
CRITICAL_SECTION IISTableLock;
|
||
LIST_ENTRY IISResourceTable;
|
||
BOOL g_fIISResourceTable_HadChanged = FALSE;
|
||
CLUS_WORKER g_cwAlivePollingThread;
|
||
DWORD g_dwTickOfLastResourceCheck = 0;
|
||
DWORD g_dwTlsCoInit = 0xffffffff;
|
||
#if defined(DBG_CANT_VERIFY)
|
||
BOOL g_fDbgCantVerify = FALSE;
|
||
#endif
|
||
LONG g_lOpenRefs = 0;
|
||
bool g_fWinsockInitialized = false;
|
||
|
||
|
||
|
||
PLOG_EVENT_ROUTINE g_IISLogEvent = NULL;
|
||
PSET_RESOURCE_STATUS_ROUTINE IISSetResourceStatus = NULL;
|
||
HANDLE g_hEventLog = NULL;
|
||
|
||
extern CLRES_FUNCTION_TABLE IISFunctionTable;
|
||
|
||
|
||
//
|
||
// Forward routines
|
||
//
|
||
|
||
PWSTR
|
||
IISGetParameter(
|
||
IN HKEY ClusterKey,
|
||
IN LPCWSTR ValueName
|
||
);
|
||
|
||
BOOL
|
||
WINAPI
|
||
IISIsAlive(
|
||
IN RESID Resource
|
||
);
|
||
|
||
DWORD
|
||
IISReadParameters(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry
|
||
);
|
||
|
||
DWORD
|
||
IISBuildInternalParameters(
|
||
IN OUT IIS_PARAMS* ResourceEntry
|
||
);
|
||
|
||
VOID
|
||
IISInitializeParams(
|
||
IN OUT IIS_PARAMS* Params
|
||
);
|
||
|
||
VOID
|
||
IISFreeInternalParameters(
|
||
IN IIS_PARAMS* Params
|
||
);
|
||
|
||
|
||
LPIIS_RESOURCE
|
||
GetValidResource(
|
||
IN RESID Resource,
|
||
IN LPWSTR RoutineName
|
||
);
|
||
|
||
DWORD
|
||
IISSetPrivateResProperties(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize
|
||
);
|
||
|
||
DWORD
|
||
IISGetPrivateResProperties(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
);
|
||
|
||
DWORD
|
||
IISValidatePrivateResProperties(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PIIS_PARAMS Params
|
||
);
|
||
|
||
void
|
||
IISReplicateProperties(
|
||
IN IIS_PARAMS* lpNewParams,
|
||
IN IIS_PARAMS* lpOldParams
|
||
);
|
||
|
||
void
|
||
IISSetRemoteNodeProperties(
|
||
IN LPWSTR wcsNodeName,
|
||
IN IIS_PARAMS* lpNewParams,
|
||
IN IIS_PARAMS* lpOldParams
|
||
);
|
||
|
||
DWORD
|
||
WINAPI
|
||
IISAlivePollingThread(
|
||
IN PCLUS_WORKER pWorker,
|
||
IN LPVOID lpVoid );
|
||
|
||
|
||
//
|
||
// Function definitions
|
||
//
|
||
|
||
|
||
BOOLEAN
|
||
IISInit(
|
||
VOID
|
||
)
|
||
{
|
||
WSADATA wsaData;
|
||
INT serr;
|
||
|
||
INIT_DEBUG;
|
||
|
||
INITIALIZE_CRITICAL_SECTION(&IISTableLock);
|
||
InitializeListHead(&IISResourceTable);
|
||
|
||
|
||
g_dwTlsCoInit = TlsAlloc();
|
||
SetCoInit( FALSE );
|
||
|
||
g_hEventLog = RegisterEventSource( NULL, L"CLUSIIS4" );
|
||
|
||
//
|
||
// Initialize winsock support
|
||
//
|
||
|
||
serr = WSAStartup( MAKEWORD( 2, 0), &wsaData);
|
||
|
||
if( serr == 0 )
|
||
{
|
||
g_fWinsockInitialized = true;
|
||
}
|
||
else
|
||
{
|
||
TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] WSAStartup failed with %08x\n",serr) );
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
VOID
|
||
IISCleanup()
|
||
{
|
||
|
||
DeleteCriticalSection(&IISTableLock);
|
||
|
||
TlsFree( g_dwTlsCoInit );
|
||
|
||
if ( g_hEventLog != NULL )
|
||
{
|
||
DeregisterEventSource( g_hEventLog );
|
||
}
|
||
|
||
if (g_fWinsockInitialized)
|
||
{
|
||
WSACleanup();
|
||
}
|
||
|
||
TERMINATE_DEBUG;
|
||
}
|
||
|
||
|
||
extern "C" BOOL WINAPI
|
||
DllMain(
|
||
IN HINSTANCE DllHandle,
|
||
IN DWORD Reason,
|
||
IN LPVOID Reserved
|
||
)
|
||
{
|
||
switch( Reason )
|
||
{
|
||
|
||
case DLL_PROCESS_ATTACH:
|
||
if ( !IISInit() )
|
||
{
|
||
return(FALSE);
|
||
}
|
||
break;
|
||
|
||
case DLL_PROCESS_DETACH:
|
||
IISCleanup();
|
||
break;
|
||
|
||
case DLL_THREAD_ATTACH:
|
||
SetCoInit( FALSE );
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return(TRUE);
|
||
|
||
} // IISShareDllEntryPoint
|
||
|
||
|
||
|
||
|
||
BOOLEAN
|
||
StartIIS(
|
||
LPIIS_RESOURCE ResourceEntry
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Start the IIS service
|
||
|
||
Arguments:
|
||
ResourceEntry - resource entry structure, includes name of service
|
||
|
||
Return Value:
|
||
TRUE - Success
|
||
FALSE - Failure
|
||
|
||
--*/
|
||
{
|
||
|
||
SC_HANDLE scManagerHandle;
|
||
SC_HANDLE serviceHandle;
|
||
DWORD errorCode;
|
||
DWORD iPoll;
|
||
SERVICE_STATUS ss;
|
||
BOOL fSt = FALSE;
|
||
INT iMaxWaitTime = 1000; // One second
|
||
|
||
//
|
||
// (# 261897) IIS cluster resources are failing to come online because "OpenSCManager" is failing with error "1723"
|
||
//
|
||
srand( (unsigned int)GetCurrentThreadId() );
|
||
|
||
for(int iScmRetry=0; iScmRetry < MAX_SCMFAILURE_RETRY; iScmRetry++)
|
||
{
|
||
//
|
||
// Open the service control manager
|
||
//
|
||
|
||
scManagerHandle = OpenSCManager( NULL, // local machine
|
||
NULL, // ServicesActive database
|
||
SC_MANAGER_ALL_ACCESS ); // all access
|
||
if ( scManagerHandle == NULL )
|
||
{
|
||
if( iScmRetry == (MAX_SCMFAILURE_RETRY-1) )
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open Service Control Manager '%1!ws!'. Error: %2!u!. Reached maximum retries (%3!u!)\n",
|
||
ResourceEntry->ResourceName,
|
||
GetLastError(),
|
||
iScmRetry );
|
||
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open Service Control Manager '%1!ws!'. Error: %2!u!. Retry attempt (%3!u!)\n",
|
||
ResourceEntry->ResourceName,
|
||
GetLastError(),
|
||
iScmRetry );
|
||
}
|
||
|
||
Sleep( (DWORD)(rand() % iMaxWaitTime) );
|
||
|
||
iMaxWaitTime *= BACKOFF_MULTIPLIER;
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Open the service
|
||
//
|
||
|
||
serviceHandle = OpenService( scManagerHandle,
|
||
ResourceEntry->Params.ServiceName, // Service Name
|
||
SERVICE_ALL_ACCESS );
|
||
|
||
TR( (DEBUG_BUFFER,"[StartIIS] starting %S\n", ResourceEntry->Params.ServiceName) );
|
||
|
||
if ( serviceHandle == NULL )
|
||
{
|
||
CloseServiceHandle( scManagerHandle );
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Make sure the service is running
|
||
//
|
||
|
||
if ( !StartService( serviceHandle,
|
||
0,
|
||
NULL) )
|
||
{
|
||
|
||
errorCode = GetLastError();
|
||
|
||
if ( errorCode == ERROR_SERVICE_ALREADY_RUNNING )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[StartIIS] allready running\n") );
|
||
fSt = TRUE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for ( iPoll = 0 ; iPoll < SERVICE_START_MAX_POLL ; ++iPoll )
|
||
{
|
||
if ( !QueryServiceStatus( serviceHandle, &ss ) )
|
||
{
|
||
break;
|
||
}
|
||
|
||
if ( ss.dwCurrentState == SERVICE_RUNNING )
|
||
{
|
||
fSt = TRUE;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Give the IIS Server a second to start up
|
||
//
|
||
|
||
Sleep( SERVICE_START_POLL_DELAY );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Close open handles
|
||
//
|
||
|
||
CloseServiceHandle( serviceHandle );
|
||
CloseServiceHandle( scManagerHandle);
|
||
|
||
return (BOOLEAN)fSt;
|
||
|
||
} // StartIIS
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
Startup(
|
||
IN LPCWSTR ResourceType,
|
||
IN DWORD MinVersionSupported,
|
||
IN DWORD MaxVersionSupported,
|
||
IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
|
||
IN PLOG_EVENT_ROUTINE LogEvent,
|
||
OUT PCLRES_FUNCTION_TABLE *FunctionTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Startup a particular resource type. This means verifying the version
|
||
requested, and returning the function table for this resource type.
|
||
|
||
Arguments:
|
||
|
||
ResourceType - Supplies the type of resource.
|
||
|
||
MinVersionSupported - The minimum version number supported by the cluster
|
||
service on this system.
|
||
|
||
MaxVersionSupported - The maximum version number supported by the cluster
|
||
service on this system.
|
||
|
||
FunctionTable - Returns the Function Table for this resource type.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
|
||
A Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD serviceType = MAX_SERVICE;
|
||
DWORD i;
|
||
HRESULT hRes;
|
||
|
||
#if 1
|
||
hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||
if ( FAILED(hRes) )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[Startup] fail CoInitialize %08x\n",hRes) );
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Search for a valid service name supported by this DLL
|
||
//
|
||
for ( i = 0; i < MAX_RESOURCE_TYPE; i++ )
|
||
{
|
||
if ( lstrcmpiW( ResourceType, RESOURCE_TYPE[i] ) == 0 )
|
||
break;
|
||
}
|
||
|
||
if ( MAX_RESOURCE_TYPE == i )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[Startup] bad resource type\n") );
|
||
return ERROR_UNKNOWN_REVISION;
|
||
}
|
||
|
||
g_IISLogEvent = LogEvent;
|
||
IISSetResourceStatus = SetResourceStatus;
|
||
|
||
if ( (MinVersionSupported <= CLRES_VERSION_V1_00) &&
|
||
(MaxVersionSupported >= CLRES_VERSION_V1_00) )
|
||
{
|
||
|
||
TR( (DEBUG_BUFFER,"[Startup] OK, leave\n") );
|
||
*FunctionTable = &IISFunctionTable;
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
TR( (DEBUG_BUFFER,"[Startup] revision mismatch\n") );
|
||
return ERROR_REVISION_MISMATCH;
|
||
|
||
} // Startup
|
||
|
||
|
||
|
||
|
||
RESID
|
||
WINAPI
|
||
IISOpen(
|
||
IN LPCWSTR ResourceName,
|
||
IN HKEY ResourceKey,
|
||
IN RESOURCE_HANDLE ResourceHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Open routine for IIS resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceName - supplies the resource name
|
||
|
||
ResourceKey - Supplies handle to resource's cluster registry key.
|
||
|
||
ResourceHandle - the resource handle to be supplied with SetResourceStatus
|
||
is called.
|
||
|
||
Return Value:
|
||
|
||
RESID of created resource
|
||
Zero on failure
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD readStatus;
|
||
LPIIS_RESOURCE ResourceEntry;
|
||
DWORD count;
|
||
DWORD Index;
|
||
DWORD serviceType = MAX_SERVICE;
|
||
LPCWSTR ResourceType;
|
||
HKEY hKey;
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOpen] Enter\n") );
|
||
|
||
EnterCriticalSection(&IISTableLock);
|
||
|
||
//
|
||
// Check if IIS is installed
|
||
//
|
||
|
||
if ( ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
L"SYSTEM\\CurrentControlSet\\Services\\IISADMIN",
|
||
0,
|
||
KEY_READ,
|
||
&hKey))
|
||
{
|
||
LeaveCriticalSection(&IISTableLock);
|
||
return (RESID)0;
|
||
}
|
||
else
|
||
{
|
||
RegCloseKey(hKey);
|
||
}
|
||
|
||
if ( g_lOpenRefs == 0 )
|
||
{
|
||
if ( !CMetaData::Init() )
|
||
{
|
||
LeaveCriticalSection(&IISTableLock);
|
||
return (RESID)0;
|
||
}
|
||
}
|
||
InterlockedIncrement( &g_lOpenRefs );
|
||
LeaveCriticalSection(&IISTableLock);
|
||
|
||
ResourceEntry = (LPIIS_RESOURCE)LocalAlloc( LMEM_FIXED, sizeof(IIS_RESOURCE) );
|
||
if ( ResourceEntry == NULL )
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate IIS resource structure.\n");
|
||
TR( (DEBUG_BUFFER,"[IISOpen] can't alloc ResourceEntry\n") );
|
||
|
||
InterlockedDecrement( &g_lOpenRefs );
|
||
|
||
return (RESID)0;
|
||
}
|
||
ZeroMemory( ResourceEntry, sizeof(IIS_RESOURCE) );
|
||
ResourceEntry->Signature = IIS_RESOURCE_SIGNATURE;
|
||
|
||
//
|
||
// Set the resource handle for logging and init the virtual root entry
|
||
//
|
||
ResourceEntry->ResourceHandle = ResourceHandle;
|
||
|
||
//
|
||
// Read the Name of the resource, since the GUID is passed in.
|
||
//
|
||
|
||
ResourceEntry->ResourceName = IISGetParameter( ResourceKey, L"Name" );
|
||
|
||
if ( ResourceEntry->ResourceName == NULL )
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to read resource name.\n" );
|
||
status = ERROR_RESOURCE_NOT_FOUND;
|
||
FreeIISResource(ResourceEntry);
|
||
LocalFree( ResourceEntry );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOpen] Can't get name\n") );
|
||
InterlockedDecrement( &g_lOpenRefs );
|
||
return (RESID)0;
|
||
}
|
||
|
||
//
|
||
// Open the Parameters key for this resource.
|
||
//
|
||
status = ClusterRegOpenKey( ResourceKey,
|
||
L"Parameters",
|
||
KEY_READ,
|
||
&ResourceEntry->ParametersKey );
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open parameters key for resource. Error: %1!u!.\n",
|
||
status );
|
||
FreeIISResource( ResourceEntry );
|
||
LocalFree( ResourceEntry );
|
||
TR( (DEBUG_BUFFER,"[IISOpen] Can't open parameters\n") );
|
||
|
||
InterlockedDecrement( &g_lOpenRefs );
|
||
return (RESID)0;
|
||
}
|
||
|
||
ResourceEntry->State = ClusterResourceOffline;
|
||
|
||
//
|
||
// If instance parameters exist, check instance stopped & marked cluster enabled
|
||
//
|
||
|
||
LPWSTR pwszServiceName = IISGetParameter( ResourceEntry->ParametersKey,
|
||
PARAM_NAME__SERVICENAME );
|
||
LPWSTR pwszInstanceId = IISGetParameter( ResourceEntry->ParametersKey,
|
||
PARAM_NAME__INSTANCEID );
|
||
|
||
if ( pwszServiceName && pwszInstanceId )
|
||
{
|
||
InstanceEnableCluster( pwszServiceName, pwszInstanceId );
|
||
}
|
||
|
||
if ( pwszServiceName )
|
||
{
|
||
LocalFree(pwszServiceName);
|
||
}
|
||
if ( pwszInstanceId )
|
||
{
|
||
LocalFree(pwszInstanceId);
|
||
}
|
||
|
||
//
|
||
// Initialize the metadata path for this instance
|
||
//
|
||
ResourceEntry->Params.MDPath = NULL;
|
||
|
||
//
|
||
// Set the resource's initial state to alive
|
||
//
|
||
ResourceEntry->bAlive = TRUE ;
|
||
|
||
//
|
||
// If this is first element being added to the list than start the polling thread
|
||
//
|
||
if ( IsListEmpty (&IISResourceTable) )
|
||
{
|
||
//
|
||
// Initialize the timestamp used in the isalive/looksalive to determine if the polling thread is still running
|
||
//
|
||
InterlockedExchange( (LPLONG) &g_dwTickOfLastResourceCheck, GetTickCount() );
|
||
TR( (DEBUG_BUFFER,"[IISOpen] initialized g_dwTickOfLastResourceCheck (%d)\n", g_dwTickOfLastResourceCheck) );
|
||
|
||
if( ERROR_SUCCESS != (status = ClusWorkerCreate( &g_cwAlivePollingThread,
|
||
(PWORKER_START_ROUTINE)IISAlivePollingThread,
|
||
&IISResourceTable)) )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISOpen] Error creating IISAlivePollingThread %08x\n",status) );
|
||
return (RESID)0;
|
||
}
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOpen] created IISAlivePollingThread\n") );
|
||
}
|
||
|
||
|
||
//
|
||
// Add to resource list
|
||
//
|
||
EnterCriticalSection(&IISTableLock);
|
||
|
||
InsertHeadList( &IISResourceTable, &ResourceEntry->ListEntry );
|
||
g_fIISResourceTable_HadChanged = TRUE;
|
||
|
||
LeaveCriticalSection(&IISTableLock);
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Open request succeeded with id = %1!u!.\n",
|
||
ResourceEntry );
|
||
TR( (DEBUG_BUFFER,"[IISOpen] token=%x Leave\n", ResourceEntry) );
|
||
|
||
return (RESID)ResourceEntry;
|
||
} // IISOpen
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
IISOnlineThread(
|
||
IN PCLUS_WORKER pWorker,
|
||
IN LPIIS_RESOURCE ResourceEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings a share resource online.
|
||
|
||
Arguments:
|
||
ResourceEntry - A pointer to a IIS_RESOURCE block for this resource
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD retry;
|
||
RESOURCE_STATUS resourceStatus;
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOnlineThread] Enter\n") );
|
||
|
||
ResUtilInitializeResourceStatus( &resourceStatus );
|
||
|
||
resourceStatus.ResourceState = ClusterResourceOnlinePending;
|
||
resourceStatus.WaitHint = 0;
|
||
resourceStatus.CheckPoint = 1;
|
||
|
||
ResourceEntry->State = ClusterResourceOnlinePending;
|
||
InterlockedExchange( (LPLONG) &ResourceEntry->bAlive, TRUE );
|
||
|
||
if (IISReadParameters(ResourceEntry) != ERROR_SUCCESS)
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"ERROR [OnLineThread] Could not read resource parameters\n");
|
||
status = ERROR_RESOURCE_NOT_FOUND;
|
||
TR( (DEBUG_BUFFER,"[IISOnlineThread] can't read parameters\n") );
|
||
goto SendStatus;
|
||
}
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"INFO [OnLineThread] Service = %1!ws! InstanceId = %2!ws!\n",
|
||
ResourceEntry->Params.ServiceName,
|
||
ResourceEntry->Params.InstanceId );
|
||
|
||
//
|
||
// get the server bindings information, if this fails should be able to pick the information up in the polling thread
|
||
//
|
||
if ( ERROR_SUCCESS != (status = GetServerBindings( ResourceEntry->Params.MDPath, ResourceEntry->Params.ServiceType, &ResourceEntry->saServer, &ResourceEntry->dwPort )) )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISOnLineThread] failed to get server bindings for %S (%d)\n", ResourceEntry->Params.MDPath, status) );
|
||
}
|
||
|
||
//
|
||
// Try to Online the resources
|
||
//
|
||
//
|
||
|
||
if ( !StartIIS( ResourceEntry ) )
|
||
{
|
||
status = ERROR_SERVICE_REQUEST_TIMEOUT;
|
||
resourceStatus.ResourceState = ClusterResourceFailed;
|
||
ResourceEntry->State = ClusterResourceFailed;
|
||
TR( (DEBUG_BUFFER,"[IISOnlineThread] can't start IIS\n") );
|
||
}
|
||
else
|
||
{
|
||
status = SetInstanceState( pWorker,
|
||
ResourceEntry,
|
||
&resourceStatus,
|
||
ClusterResourceOnline,
|
||
L"online",
|
||
MD_SERVER_COMMAND_START,
|
||
MD_SERVER_STATE_STARTED );
|
||
}
|
||
|
||
SendStatus:
|
||
|
||
//
|
||
// Set the state of the resource
|
||
//
|
||
|
||
(IISSetResourceStatus)( ResourceEntry->ResourceHandle,
|
||
&resourceStatus );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOnlineThread] status = %d, Leave\n",status) );
|
||
|
||
return status;
|
||
|
||
} // IISOnlineThread
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
IISOfflineThread(
|
||
IN PCLUS_WORKER pWorker,
|
||
IN LPIIS_RESOURCE ResourceEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Brings a share resource offline.
|
||
|
||
Arguments:
|
||
ResourceEntry - A pointer to a IIS_RESOURCE block for this resource
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD retry;
|
||
RESOURCE_STATUS resourceStatus;
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOfflineThread] Enter\n") );
|
||
|
||
#if defined(DBG_CANT_VERIFY)
|
||
if ( g_fDbgCantVerify )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISOfflineThread] skip stop after failure to verify service\n") );
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
#endif
|
||
|
||
ResUtilInitializeResourceStatus( &resourceStatus );
|
||
|
||
resourceStatus.ResourceState = ClusterResourceOfflinePending;
|
||
resourceStatus.WaitHint = 0;
|
||
resourceStatus.CheckPoint = 1;
|
||
|
||
ResourceEntry->State = ClusterResourceOfflinePending;
|
||
|
||
if (IISReadParameters(ResourceEntry) != ERROR_SUCCESS)
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"ERROR [OffLineThread] Could not read resource parameters\n");
|
||
status = ERROR_RESOURCE_NOT_FOUND;
|
||
goto SendStatus;
|
||
}
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"INFO [OffLineThread] Service = %1!ws! InstanceId = %2!ws!\n",
|
||
ResourceEntry->Params.ServiceName,
|
||
ResourceEntry->Params.InstanceId );
|
||
|
||
//
|
||
// Try to Offline the resources
|
||
//
|
||
//
|
||
|
||
status = SetInstanceState( pWorker, ResourceEntry, &resourceStatus, ClusterResourceOffline, L"offline", MD_SERVER_COMMAND_STOP, MD_SERVER_STATE_STOPPED );
|
||
|
||
SendStatus:
|
||
|
||
//
|
||
// Set the state of the resource
|
||
//
|
||
|
||
(IISSetResourceStatus)( ResourceEntry->ResourceHandle,
|
||
&resourceStatus );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOfflineThread] status = %d, Leave\n",status) );
|
||
|
||
return(status);
|
||
} // IISOfflineThread
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
IISOnline(
|
||
IN RESID Resource,
|
||
IN OUT PHANDLE EventHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Online routine for IIS resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be brought online
|
||
|
||
EventHandle - supplies a pointer to a handle to signal on error.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
|
||
ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
|
||
acquire 'ownership'.
|
||
Win32 error code if other failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPIIS_RESOURCE ResourceEntry = NULL;
|
||
DWORD status;
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOnline] Enter\n") );
|
||
|
||
//
|
||
// Get a valid resource
|
||
//
|
||
|
||
ResourceEntry = GetValidResource(Resource,L"OnLine");
|
||
if ( ResourceEntry == NULL )
|
||
{
|
||
return ERROR_RESOURCE_NOT_FOUND;
|
||
}
|
||
|
||
//
|
||
// Log the online request
|
||
//
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Online request for IIS Resource %1!u! (%2!ws!).\n",
|
||
Resource,
|
||
ResourceEntry->ResourceName );
|
||
|
||
// Terminate (or wait) for workers
|
||
ClusWorkerTerminate( &ResourceEntry->OnlineThread );
|
||
ClusWorkerTerminate( &ResourceEntry->OfflineThread );
|
||
|
||
status = ClusWorkerCreate( &ResourceEntry->OnlineThread,
|
||
(PWORKER_START_ROUTINE)IISOnlineThread,
|
||
ResourceEntry );
|
||
if ( status == ERROR_SUCCESS )
|
||
{
|
||
return ERROR_IO_PENDING;
|
||
}
|
||
|
||
//
|
||
// Failure
|
||
//
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Online request failed, error %1!u!.\n",
|
||
GetLastError() );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISOnline] failed %d, Leave\n",GetLastError()) );
|
||
|
||
return status;
|
||
|
||
} // IISOnline
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
IISTerminate(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Terminate routine for IIS resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be terminated
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
LPIIS_RESOURCE ResourceEntry;
|
||
DWORD dwS;
|
||
int retry;
|
||
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] Enter\n") );
|
||
|
||
#if defined(DBG_CANT_VERIFY)
|
||
if ( g_fDbgCantVerify )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] skip stop after failure to verify service\n") );
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Get a valid resource entry, return on error
|
||
//
|
||
|
||
ResourceEntry = GetValidResource(Resource,L"Terminate");
|
||
if (ResourceEntry == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Terminate or offline request for Resource%1!u! (%2!ws!).\n",
|
||
Resource,
|
||
ResourceEntry->ResourceName );
|
||
|
||
//
|
||
// Try to take the resources offline, dont return if an error since
|
||
// the resources may be offline when terminate called
|
||
//
|
||
|
||
//
|
||
// Terminate the Online & Offline Threads
|
||
//
|
||
|
||
ClusWorkerTerminate( &ResourceEntry->OnlineThread);
|
||
ClusWorkerTerminate( &ResourceEntry->OfflineThread);
|
||
|
||
status = ERROR_SERVICE_NOT_ACTIVE;
|
||
|
||
CMetaData MD;
|
||
|
||
if ( MD.Open( ResourceEntry->Params.MDPath,
|
||
FALSE,
|
||
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
|
||
{
|
||
if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] state prob is %d\n",dwS) );
|
||
}
|
||
else
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] failed to probe server state\n") );
|
||
dwS = 0xffffffff;
|
||
}
|
||
|
||
if ( dwS != MD_SERVER_STATE_STOPPED )
|
||
{
|
||
if ( MD.SetDword( L"", MD_CLUSTER_SERVER_COMMAND, IIS_MD_UT_SERVER, MD_SERVER_COMMAND_STOP, 0 ) )
|
||
{
|
||
MD.Close();
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] command set to %d\n",MD_SERVER_COMMAND_STOP) );
|
||
status = ERROR_SUCCESS;
|
||
for ( retry = 3 ; retry-- ; )
|
||
{
|
||
if ( MD.GetDword( ResourceEntry->Params.MDPath, MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
|
||
{
|
||
if ( dwS == MD_SERVER_STATE_STOPPED )
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] failed to get server state\n") );
|
||
break;
|
||
}
|
||
|
||
Sleep(SERVER_START_DELAY);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MD.Close();
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] failed to set command to %d\n",MD_SERVER_COMMAND_STOP) );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
status = ERROR_SUCCESS;
|
||
MD.Close();
|
||
}
|
||
}
|
||
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Error removing Resource. Error %1!u!. Resource. %2!ws! Service. %3!ws!\n",
|
||
status,
|
||
ResourceEntry->ResourceName,
|
||
ResourceEntry->Params.ServiceName);
|
||
}
|
||
|
||
//
|
||
// Set status to offline
|
||
//
|
||
ResourceEntry->State = ClusterResourceOffline;
|
||
|
||
TR( (DEBUG_BUFFER,"[IISTerminate] Leave\n") );
|
||
|
||
} // IISTerminate
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
IISOffline(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Offline routine for IIS resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies the resource it to be taken offline
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - always successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPIIS_RESOURCE ResourceEntry = NULL;
|
||
DWORD status;
|
||
|
||
//
|
||
// Get a valid resource
|
||
//
|
||
ResourceEntry = GetValidResource(Resource,L"OffLine");
|
||
if ( ResourceEntry == NULL )
|
||
{
|
||
return ERROR_RESOURCE_NOT_FOUND;
|
||
}
|
||
|
||
//
|
||
// Log the online request
|
||
//
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Offline request for IIS Resource %1!u! (%2!ws!).\n",
|
||
Resource,
|
||
ResourceEntry->ResourceName );
|
||
|
||
// Terminate (or wait) for workers
|
||
ClusWorkerTerminate( &ResourceEntry->OnlineThread );
|
||
ClusWorkerTerminate( &ResourceEntry->OfflineThread );
|
||
|
||
status = ClusWorkerCreate( &ResourceEntry->OfflineThread,
|
||
(PWORKER_START_ROUTINE)IISOfflineThread,
|
||
ResourceEntry );
|
||
if ( status == ERROR_SUCCESS )
|
||
{
|
||
return ERROR_IO_PENDING;
|
||
}
|
||
|
||
//
|
||
// Failure
|
||
//
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Offline request failed, error %1!u!.\n",
|
||
GetLastError() );
|
||
|
||
return status;
|
||
|
||
} // IISOffline
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
IISIsAlive(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
IsAlive routine for IIS service resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies the resource id to be polled.
|
||
|
||
Return Value:
|
||
|
||
TRUE - if service is running
|
||
|
||
FALSE - if service is in any other state
|
||
|
||
--*/
|
||
{
|
||
LPIIS_RESOURCE ResourceEntry;
|
||
DWORD dwTickDifference = 0;
|
||
DWORD dwCurrent;
|
||
DWORD dwTickOfLastResourceCheck = 0;
|
||
|
||
//
|
||
// Get a valid resource
|
||
//
|
||
ResourceEntry = GetValidResource(Resource,L"IsAlive");
|
||
if (ResourceEntry == NULL)
|
||
{
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Save the current global tick count so it can't change during the calculation
|
||
//
|
||
dwTickOfLastResourceCheck = g_dwTickOfLastResourceCheck;
|
||
|
||
//
|
||
// Save the current tick count
|
||
//
|
||
dwCurrent = GetTickCount();
|
||
|
||
if (dwCurrent >= g_dwTickOfLastResourceCheck)
|
||
{
|
||
dwTickDifference = dwCurrent - g_dwTickOfLastResourceCheck ;
|
||
}
|
||
else
|
||
{
|
||
dwTickDifference = (0xFFFFFFFF - g_dwTickOfLastResourceCheck) + dwCurrent ;
|
||
}
|
||
|
||
//
|
||
// if the polling thread is taking too long there must be a problem
|
||
//
|
||
if ( dwTickDifference > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS)
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IsAlive] (dwTickDifference(%d) > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS) returning FALSE dwCurrent(%d) dwTickOfLastResourceCheck(%d)\n", dwTickDifference, dwCurrent, dwTickOfLastResourceCheck) );
|
||
return FALSE;
|
||
}
|
||
|
||
return ResourceEntry->bAlive ;
|
||
|
||
} // IISIsAlive
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
IISLooksAlive(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
LooksAlive routine for IIS resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies the resource id to be polled.
|
||
|
||
Return Value:
|
||
|
||
TRUE - Resource looks like it is alive and well
|
||
|
||
FALSE - Resource looks like it is toast.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LPIIS_RESOURCE ResourceEntry;
|
||
DWORD dwTickDifference = 0;
|
||
DWORD dwCurrent;
|
||
DWORD dwTickOfLastResourceCheck = 0;
|
||
|
||
//
|
||
// Get a valid resource
|
||
//
|
||
ResourceEntry = GetValidResource(Resource,L"LooksAlive");
|
||
if (ResourceEntry == NULL)
|
||
{
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// Save the current global tick count so it can't change during the calculation
|
||
//
|
||
dwTickOfLastResourceCheck = g_dwTickOfLastResourceCheck;
|
||
|
||
//
|
||
// Save the current tick count
|
||
//
|
||
dwCurrent = GetTickCount();
|
||
|
||
if (dwCurrent >= g_dwTickOfLastResourceCheck)
|
||
{
|
||
dwTickDifference = dwCurrent - g_dwTickOfLastResourceCheck ;
|
||
}
|
||
else
|
||
{
|
||
dwTickDifference = (0xFFFFFFFF - g_dwTickOfLastResourceCheck) + dwCurrent ;
|
||
}
|
||
|
||
//
|
||
// if the polling thread is taking too long there must be a problem
|
||
//
|
||
if ( dwTickDifference > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[LooksAlive] (dwTickDifference(%d) > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS) returning FALSE dwCurrent(%d) dwTickOfLastResourceCheck(%d)\n", dwTickDifference, dwCurrent, dwTickOfLastResourceCheck) );
|
||
return FALSE;
|
||
}
|
||
|
||
return ResourceEntry->bAlive ;
|
||
|
||
} // IISLooksAlive
|
||
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
IISClose(
|
||
IN RESID Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Close routine for IIS resource.
|
||
|
||
Arguments:
|
||
|
||
Resource - supplies resource id to be closed
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPIIS_RESOURCE ResourceEntry = NULL;
|
||
|
||
//
|
||
// Get a valid resource
|
||
//
|
||
ResourceEntry = GetValidResource( Resource, L"Close");
|
||
if (ResourceEntry == NULL)
|
||
{
|
||
return; // this should not happen
|
||
}
|
||
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Close request for resource '%1!ws!' Service '%2!ws!' \n",
|
||
ResourceEntry->ResourceName,
|
||
ResourceEntry->Params.ServiceName);
|
||
//
|
||
// Remove from list
|
||
//
|
||
EnterCriticalSection(&IISTableLock);
|
||
|
||
RemoveEntryList( &ResourceEntry->ListEntry );
|
||
g_fIISResourceTable_HadChanged = TRUE;
|
||
|
||
|
||
DestructIISResource(ResourceEntry);
|
||
|
||
if ( g_lOpenRefs > 0 )
|
||
{
|
||
if ( !InterlockedDecrement( &g_lOpenRefs ) )
|
||
{
|
||
CMetaData::Terminate();
|
||
}
|
||
}
|
||
|
||
LeaveCriticalSection(&IISTableLock);
|
||
|
||
//
|
||
// If this was the last resource in the list than stop the polling thread
|
||
//
|
||
if ( IsListEmpty (&IISResourceTable) )
|
||
{
|
||
ClusWorkerTerminate( &g_cwAlivePollingThread );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISClose] Terminated IISAlivePollingThread\n") );
|
||
}
|
||
|
||
} // IISClose
|
||
|
||
|
||
LPIIS_RESOURCE
|
||
GetValidResource(
|
||
IN RESID Resource,
|
||
IN LPWSTR RoutineName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
Validate the resource ID, log any error, return valid resource
|
||
|
||
Arguments:
|
||
Resource - the resource to validate
|
||
|
||
RoutineName - the routine that is requesting the validation
|
||
|
||
Return Value:
|
||
Success - ResourceEntry
|
||
NULL - Error
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD Index;
|
||
LPIIS_RESOURCE ResourceEntry;
|
||
|
||
ResourceEntry = (LPIIS_RESOURCE)Resource;
|
||
|
||
//
|
||
// Check for a valid
|
||
//
|
||
if ( ResourceEntry == NULL )
|
||
{
|
||
(g_IISLogEvent)(
|
||
NULL,
|
||
LOG_ERROR,
|
||
L"[%1!ws!] Resource Entry is NULL for Resource Id = %2!u!\n",
|
||
RoutineName,
|
||
Resource);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Sanity check the resource struct
|
||
//
|
||
|
||
if ( ResourceEntry->Signature != IIS_RESOURCE_SIGNATURE )
|
||
{
|
||
(g_IISLogEvent)(
|
||
ResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"[%1!ws!] IIS Resource index sanity checked failed! Index = %2!u!.\n",
|
||
RoutineName,
|
||
Resource );
|
||
|
||
return NULL;
|
||
}
|
||
|
||
return ResourceEntry;
|
||
|
||
} // END GetValidResource
|
||
|
||
|
||
|
||
PWSTR
|
||
IISGetParameter(
|
||
IN HKEY ClusterKey,
|
||
IN LPCWSTR ValueName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Queries a REG_SZ parameter out of the registry 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 if successful.
|
||
|
||
NULL if unsuccessful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PWSTR Value;
|
||
PWSTR Value2;
|
||
DWORD ValueLength;
|
||
DWORD ValueType;
|
||
DWORD Status;
|
||
|
||
ValueLength = 0;
|
||
|
||
Status = ClusterRegQueryValue(ClusterKey,
|
||
ValueName,
|
||
&ValueType,
|
||
NULL,
|
||
&ValueLength);
|
||
|
||
if ( (Status != ERROR_SUCCESS) &&
|
||
(Status != ERROR_MORE_DATA) )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISGetParameter] Failed to open %S, error %u\n",ValueName,Status) );
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Add on the size of the null terminator.
|
||
//
|
||
ValueLength += sizeof(UNICODE_NULL);
|
||
|
||
Value = (WCHAR*)LocalAlloc(LMEM_FIXED, ValueLength);
|
||
if (Value == NULL)
|
||
{
|
||
return(NULL);
|
||
}
|
||
|
||
Status = ClusterRegQueryValue(ClusterKey,
|
||
ValueName,
|
||
&ValueType,
|
||
(LPBYTE)Value,
|
||
&ValueLength);
|
||
|
||
if (Status != ERROR_SUCCESS)
|
||
{
|
||
LocalFree(Value);
|
||
Value = NULL;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Numeric value are prefixed with '!' to force them to be stored as string,
|
||
// so remove leading '!' if present
|
||
//
|
||
|
||
if ( Value[0] == L'!' )
|
||
{
|
||
Value2 = (WCHAR*)LocalAlloc(LMEM_FIXED, ValueLength);
|
||
if (Value2 == NULL)
|
||
{
|
||
LocalFree( Value );
|
||
return(NULL);
|
||
}
|
||
wcscpy( Value2, Value + 1 );
|
||
LocalFree( Value );
|
||
Value = Value2;
|
||
}
|
||
}
|
||
|
||
|
||
TR( (DEBUG_BUFFER,"[IISGetParameter] Read %S, length %d, value %S\n",ValueName,ValueLength,Value?Value:L"ERROR") );
|
||
|
||
return(Value);
|
||
|
||
} // IISGetParameter
|
||
|
||
|
||
|
||
LPWSTR
|
||
GetResourceParameter(
|
||
IN HRESOURCE hResource,
|
||
IN LPCWSTR ValueName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Opens the parameter key for the resource. Then Queries a REG_SZ parameter
|
||
out of the registry and allocates the necessary storage for it.
|
||
|
||
Arguments:
|
||
|
||
hResource - the resource to query
|
||
|
||
ValueName - Supplies the name of the value.
|
||
|
||
Return Value:
|
||
|
||
A pointer to a buffer containing the parameter if successful.
|
||
|
||
NULL if unsuccessful.
|
||
|
||
--*/
|
||
{
|
||
HKEY hKey = NULL;
|
||
HKEY hParametersKey = NULL;
|
||
DWORD status;
|
||
LPWSTR paramValue = NULL;
|
||
|
||
//
|
||
// Get Resource key
|
||
//
|
||
hKey = GetClusterResourceKey(hResource,KEY_READ);
|
||
if (hKey == NULL)
|
||
{
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Get parameters key
|
||
//
|
||
status = ClusterRegOpenKey(hKey,
|
||
L"Parameters",
|
||
KEY_READ,
|
||
&hParametersKey );
|
||
if (status != ERROR_SUCCESS)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
|
||
paramValue = IISGetParameter(hParametersKey,ValueName);
|
||
|
||
if (paramValue == NULL)
|
||
{
|
||
goto error_exit;
|
||
}
|
||
|
||
error_exit:
|
||
if (hParametersKey != NULL)
|
||
{
|
||
ClusterRegCloseKey(hParametersKey);
|
||
}
|
||
if (hKey != NULL)
|
||
{
|
||
ClusterRegCloseKey(hKey);
|
||
}
|
||
return(paramValue);
|
||
|
||
} // GetResourceParameter
|
||
|
||
|
||
DWORD
|
||
IISReadParameters(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads all the parameters for a resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Entry in the resource table.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
ERROR_RESOURCE_NOT_FOUND - failure
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
|
||
//
|
||
// Read the parameters for the resource.
|
||
//
|
||
status = ResUtilReadProperties( ResourceEntry->ParametersKey,
|
||
IISResourcePrivateProperties,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
ResourceEntry->ResourceHandle,
|
||
g_IISLogEvent );
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
return status;
|
||
}
|
||
|
||
return IISBuildInternalParameters( &ResourceEntry->Params );
|
||
}
|
||
|
||
|
||
DWORD
|
||
IISBuildInternalParameters(
|
||
IN OUT IIS_PARAMS* Params
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build all the parameters for a resource from wolfpack parameters
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Entry in the resource table.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - Success
|
||
|
||
ERROR_RESOURCE_NOT_FOUND - failure
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
INT iServiceType;
|
||
DWORD length;
|
||
|
||
//
|
||
// Make sure we got passed a valid service name
|
||
//
|
||
|
||
for ( iServiceType = 0 ; iServiceType < MAX_SERVICE ; iServiceType++ )
|
||
{
|
||
if ( lstrcmpiW( Params->ServiceName, ActualServiceName[iServiceType] ) == 0 )
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( iServiceType >= MAX_SERVICE )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISBuildInternalParameters] Invalid service name %S", Params->ServiceName) );
|
||
return ERROR_RESOURCE_NOT_FOUND;
|
||
}
|
||
|
||
Params->ServiceType = iServiceType;
|
||
|
||
//
|
||
// Build MetaData path
|
||
//
|
||
|
||
TCHAR achMDPath[80];
|
||
DWORD dwL;
|
||
|
||
dwL = wsprintf( achMDPath, L"/LM/%s/%s", Params->ServiceName, Params->InstanceId );
|
||
|
||
Params->MDPath = (WCHAR*)LocalAlloc( LMEM_FIXED, (dwL+1)*sizeof(WCHAR) );
|
||
if ( Params->MDPath == NULL )
|
||
{
|
||
return ERROR_RESOURCE_NOT_FOUND;
|
||
}
|
||
memcpy( Params->MDPath, achMDPath,(dwL+1)*sizeof(TCHAR) );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISBuildInternalParameters] Built path %S\n", Params->MDPath) );
|
||
|
||
return(ERROR_SUCCESS);
|
||
} // IISReadParameters
|
||
|
||
|
||
VOID
|
||
IISInitializeParams(
|
||
IN OUT IIS_PARAMS* Params
|
||
)
|
||
{
|
||
ZeroMemory( Params, sizeof(IIS_PARAMS) );
|
||
}
|
||
|
||
|
||
VOID
|
||
IISFreeInternalParameters(
|
||
IN IIS_PARAMS* Params
|
||
)
|
||
{
|
||
if ( Params->MDPath )
|
||
{
|
||
LocalFree( Params->MDPath );
|
||
Params->MDPath = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
DWORD
|
||
IISGetRequiredDependencies(
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
|
||
for resources of type IIS server instance.
|
||
|
||
Arguments:
|
||
|
||
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the available space
|
||
pointed to by OutBuffer.
|
||
|
||
BytesReturned - Returns the number of bytes of OutBuffer actually
|
||
filled in by the resource. If OutBuffer is too small, BytesReturned
|
||
contains the total number of bytes for the operation to succeed.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_MORE_DATA - The output buffer is too small to return the data.
|
||
BytesReturned contains the required size.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
typedef struct DEP_DATA
|
||
{
|
||
CLUSPROP_SZ_DECLARE( ipaddrEntry, sizeof(IP_ADDRESS_RESOURCE_NAME) / sizeof(WCHAR) );
|
||
CLUSPROP_SYNTAX endmark;
|
||
} DEP_DATA, *PDEP_DATA;
|
||
PDEP_DATA pdepdata = (PDEP_DATA)OutBuffer;
|
||
DWORD status;
|
||
|
||
*BytesReturned = sizeof(DEP_DATA);
|
||
if ( OutBufferSize < sizeof(DEP_DATA) )
|
||
{
|
||
if ( OutBuffer == NULL )
|
||
{
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISGetRequiredDependencies] buffer too small: %d bytes\n",OutBufferSize) );
|
||
status = ERROR_MORE_DATA;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ZeroMemory( pdepdata, sizeof(DEP_DATA) );
|
||
pdepdata->ipaddrEntry.Syntax.dw = CLUSPROP_SYNTAX_NAME;
|
||
pdepdata->ipaddrEntry.cbLength = sizeof(IP_ADDRESS_RESOURCE_NAME);
|
||
lstrcpyW( pdepdata->ipaddrEntry.sz, IP_ADDRESS_RESOURCE_NAME );
|
||
pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
|
||
return status;
|
||
|
||
} // IISGetRequiredDependencies
|
||
|
||
|
||
|
||
DWORD
|
||
IISResourceControl(
|
||
IN RESID ResourceId,
|
||
IN DWORD ControlCode,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ResourceControl routine for IIS Virtual Root resources.
|
||
|
||
Perform the control request specified by ControlCode on the specified
|
||
resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - Supplies the resource id for the specific resource.
|
||
|
||
ControlCode - Supplies the control code that defines the action
|
||
to be performed.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the available space
|
||
pointed to by OutBuffer.
|
||
|
||
BytesReturned - Returns the number of bytes of OutBuffer actually
|
||
filled in by the resource. If OutBuffer is too small, BytesReturned
|
||
contains the total number of bytes for the operation to succeed.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_FUNCTION - The requested control code is not supported.
|
||
In some cases, this allows the cluster software to perform the work.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
LPIIS_RESOURCE resourceEntry = NULL;
|
||
IIS_PARAMS params;
|
||
|
||
//
|
||
// Get a valid resource
|
||
//
|
||
resourceEntry = GetValidResource( ResourceId, L"ResourceControl");
|
||
if ( resourceEntry == NULL )
|
||
{
|
||
return ERROR_RESOURCE_NOT_FOUND; // this should not happen
|
||
}
|
||
|
||
switch ( ControlCode )
|
||
{
|
||
|
||
case CLUSCTL_RESOURCE_UNKNOWN:
|
||
*BytesReturned = 0;
|
||
status = ERROR_SUCCESS;
|
||
TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_UNKNOWN : status = %d\n",status) );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
|
||
status = IISGetRequiredDependencies(
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned
|
||
);
|
||
TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES : status = %d\n",status) );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
|
||
status = IISGetPrivateResProperties( resourceEntry,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned );
|
||
TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES : status = %d\n",status) );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
|
||
status = IISValidatePrivateResProperties(
|
||
resourceEntry,
|
||
InBuffer,
|
||
InBufferSize,
|
||
¶ms );
|
||
TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES : status = %d\n",status) );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
|
||
status = IISSetPrivateResProperties(
|
||
resourceEntry,
|
||
InBuffer,
|
||
InBufferSize );
|
||
TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES : status = %d\n",status) );
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_DELETE:
|
||
InstanceDisableCluster( resourceEntry->Params.ServiceName, resourceEntry->Params.InstanceId);
|
||
IISReplicateProperties(NULL, &(resourceEntry->Params));
|
||
TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_DELETE : status = %d\n",status) );
|
||
break;
|
||
|
||
default:
|
||
status = ERROR_INVALID_FUNCTION;
|
||
TR( (DEBUG_BUFFER,"[IISResourceControl] default %d: status = %d\n",ControlCode,status) );
|
||
break;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // IISResourceControl
|
||
|
||
|
||
|
||
DWORD
|
||
IISResourceTypeControl(
|
||
IN LPCWSTR ResourceTypeName,
|
||
IN DWORD ControlCode,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
ResourceTypeControl routine for IIS Virtual Root resources.
|
||
|
||
Perform the control request specified by ControlCode.
|
||
|
||
Arguments:
|
||
|
||
ResourceTypeName - Supplies the name of the resource type.
|
||
|
||
ControlCode - Supplies the control code that defines the action
|
||
to be performed.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
OutBuffer - Supplies a pointer to the output buffer to be filled in.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the available space
|
||
pointed to by OutBuffer.
|
||
|
||
BytesReturned - Returns the number of bytes of OutBuffer actually
|
||
filled in by the resource. If OutBuffer is too small, BytesReturned
|
||
contains the total number of bytes for the operation to succeed.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_FUNCTION - The requested control code is not supported.
|
||
In some cases, this allows the cluster software to perform the work.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
|
||
switch ( ControlCode )
|
||
{
|
||
|
||
case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
|
||
*BytesReturned = 0;
|
||
status = ERROR_SUCCESS;
|
||
break;
|
||
|
||
case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
|
||
status = IISGetRequiredDependencies(
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned
|
||
);
|
||
break;
|
||
|
||
default:
|
||
status = ERROR_INVALID_FUNCTION;
|
||
break;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // IISResourceTypeControl
|
||
|
||
|
||
DWORD
|
||
IISGetPrivateResProperties(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry,
|
||
OUT PVOID OutBuffer,
|
||
IN DWORD OutBufferSize,
|
||
OUT LPDWORD BytesReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
|
||
for resources of type IIS.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Supplies the resource entry on which to operate.
|
||
|
||
OutBuffer - Returns the output data.
|
||
|
||
OutBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by OutBuffer.
|
||
|
||
BytesReturned - The number of bytes returned in OutBuffer.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD required;
|
||
|
||
status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
|
||
IISResourcePrivateProperties,
|
||
OutBuffer,
|
||
OutBufferSize,
|
||
BytesReturned,
|
||
&required );
|
||
if ( status == ERROR_MORE_DATA )
|
||
{
|
||
*BytesReturned = required;
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // IISGetPrivateResProperties
|
||
|
||
|
||
DWORD
|
||
IISValidatePrivateResProperties(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize,
|
||
OUT PIIS_PARAMS Params
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
|
||
function for resources of type IIS Virtual Root.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Supplies the resource entry on which to operate.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
Params - Supplies the parameters structure to fill in. Pointers in this
|
||
structure will point to the data in InBuffer.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
IIS_PARAMS params;
|
||
PIIS_PARAMS pParams;
|
||
|
||
//
|
||
// Check if there is input data.
|
||
//
|
||
|
||
if ( (InBuffer == NULL) ||
|
||
(InBufferSize < sizeof(DWORD)) )
|
||
{
|
||
return(ERROR_INVALID_DATA);
|
||
}
|
||
|
||
//
|
||
// Duplicate the resource parameter block.
|
||
//
|
||
|
||
if ( Params == NULL )
|
||
{
|
||
pParams = ¶ms;
|
||
}
|
||
else
|
||
{
|
||
pParams = Params;
|
||
}
|
||
ZeroMemory( pParams, sizeof(params) );
|
||
status = ResUtilDupParameterBlock( (LPBYTE) pParams,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
IISResourcePrivateProperties );
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Parse and validate the properties.
|
||
//
|
||
status = ResUtilVerifyPropertyTable( IISResourcePrivateProperties,
|
||
NULL,
|
||
TRUE,
|
||
InBuffer,
|
||
InBufferSize,
|
||
(LPBYTE) pParams );
|
||
|
||
|
||
//
|
||
// Cleanup our parameter block.
|
||
//
|
||
if ( pParams == ¶ms )
|
||
{
|
||
ResUtilFreeParameterBlock( (LPBYTE) ¶ms,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
IISResourcePrivateProperties );
|
||
}
|
||
|
||
return(status);
|
||
|
||
} // IISValidatePrivateResProperties
|
||
|
||
|
||
|
||
DWORD
|
||
IISSetPrivateResProperties(
|
||
IN OUT LPIIS_RESOURCE ResourceEntry,
|
||
IN PVOID InBuffer,
|
||
IN DWORD InBufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
|
||
for resources of type IIS Virtual Root.
|
||
|
||
Arguments:
|
||
|
||
ResourceEntry - Supplies the resource entry on which to operate.
|
||
|
||
InBuffer - Supplies a pointer to a buffer containing input data.
|
||
|
||
InBufferSize - Supplies the size, in bytes, of the data pointed
|
||
to by InBuffer.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function completed successfully.
|
||
|
||
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
|
||
|
||
Win32 error code - The function failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
DWORD dupstatus = ERROR_SUCCESS;
|
||
IIS_PARAMS params;
|
||
|
||
IISInitializeParams( ¶ms );
|
||
|
||
//
|
||
// Parse the properties so they can be validated together.
|
||
// This routine does individual property validation.
|
||
//
|
||
status = IISValidatePrivateResProperties( ResourceEntry,
|
||
InBuffer,
|
||
InBufferSize,
|
||
¶ms );
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
ResUtilFreeParameterBlock( (LPBYTE) ¶ms,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
IISResourcePrivateProperties );
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Save the original paramters. Use them to unset properties.
|
||
//
|
||
|
||
IIS_PARAMS oldParams;
|
||
|
||
dupstatus = ResUtilDupParameterBlock( (LPBYTE) &oldParams,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
IISResourcePrivateProperties
|
||
);
|
||
|
||
//
|
||
// Save the parameter values.
|
||
//
|
||
|
||
status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
|
||
IISResourcePrivateProperties,
|
||
NULL,
|
||
(LPBYTE) ¶ms,
|
||
InBuffer,
|
||
InBufferSize,
|
||
(LPBYTE) &ResourceEntry->Params );
|
||
|
||
//
|
||
// If the resource is online, return a non-success status.
|
||
//
|
||
|
||
if (status == ERROR_SUCCESS)
|
||
{
|
||
if ( params.ServiceName && params.InstanceId )
|
||
{
|
||
if ( IISBuildInternalParameters( ¶ms ) == ERROR_SUCCESS )
|
||
{
|
||
//
|
||
// Reflect all properties we set to other nodes of the cluster.
|
||
//
|
||
|
||
if (ERROR_SUCCESS == dupstatus)
|
||
{
|
||
InstanceDisableCluster( oldParams.ServiceName, oldParams.InstanceId);
|
||
IISReplicateProperties(¶ms, &oldParams);
|
||
}
|
||
else
|
||
{
|
||
IISReplicateProperties(¶ms, NULL);
|
||
}
|
||
|
||
InstanceEnableCluster( params.ServiceName, params.InstanceId );
|
||
|
||
IISFreeInternalParameters( ¶ms );
|
||
}
|
||
}
|
||
|
||
if ( (ResourceEntry->State == ClusterResourceOnline) ||
|
||
(ResourceEntry->State == ClusterResourceOnlinePending) )
|
||
{
|
||
status = ERROR_RESOURCE_PROPERTIES_STORED;
|
||
}
|
||
else
|
||
{
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
}
|
||
|
||
ResUtilFreeParameterBlock( (LPBYTE) ¶ms,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
IISResourcePrivateProperties );
|
||
|
||
if (ERROR_SUCCESS == dupstatus)
|
||
{
|
||
ResUtilFreeParameterBlock( (LPBYTE) &oldParams,
|
||
(LPBYTE) &ResourceEntry->Params,
|
||
IISResourcePrivateProperties );
|
||
}
|
||
|
||
return status;
|
||
|
||
} // IISSetPrivateResProperties
|
||
|
||
void
|
||
IISReplicateProperties(
|
||
IN IIS_PARAMS* lpNewParams,
|
||
IN IIS_PARAMS* lpOldParams
|
||
)
|
||
{
|
||
//
|
||
// Get Local Computer Name. Do not replicate to local computer
|
||
//
|
||
|
||
WCHAR wszLocalComputerName[MAX_COMPUTERNAME_LENGTH+1] = L"";
|
||
DWORD dwLength = MAX_COMPUTERNAME_LENGTH+1;
|
||
|
||
GetComputerName(wszLocalComputerName, &dwLength);
|
||
|
||
HCLUSTER hClus = OpenCluster(NULL);
|
||
|
||
if (hClus)
|
||
{
|
||
HCLUSENUM hClusEnumNode = ClusterOpenEnum( hClus, CLUSTER_ENUM_NODE);
|
||
|
||
if (hClusEnumNode)
|
||
{
|
||
DWORD dwType, dwIndex = 0;
|
||
WCHAR wszNodeName[MAX_COMPUTERNAME_LENGTH+1] = L"";
|
||
DWORD cbBufferLength = MAX_COMPUTERNAME_LENGTH+1;
|
||
|
||
while ( ERROR_SUCCESS == ClusterEnum( hClusEnumNode,
|
||
dwIndex,
|
||
&dwType,
|
||
wszNodeName,
|
||
&cbBufferLength))
|
||
{
|
||
dwIndex++;
|
||
|
||
//
|
||
// Set these properties on the node (if not local computer)
|
||
//
|
||
|
||
if (wcscmp(wszNodeName, wszLocalComputerName))
|
||
{
|
||
IISSetRemoteNodeProperties(wszNodeName, lpNewParams, lpOldParams);
|
||
}
|
||
|
||
cbBufferLength = MAX_COMPUTERNAME_LENGTH+1;
|
||
}
|
||
|
||
ClusterCloseEnum(hClusEnumNode);
|
||
}
|
||
|
||
CloseCluster(hClus);
|
||
}
|
||
} // IISReplicateProperties
|
||
|
||
void
|
||
IISSetRemoteNodeProperties(
|
||
IN LPWSTR wszNodeName,
|
||
IN IIS_PARAMS* lpNewParams,
|
||
IN IIS_PARAMS* lpOldParams
|
||
)
|
||
{
|
||
IMSAdminBaseW * pcAdmCom = NULL;
|
||
METADATA_HANDLE hmd;
|
||
HRESULT hRes = S_OK;
|
||
COSERVERINFO csiMachine;
|
||
MULTI_QI QI = {&IID_IMSAdminBase, NULL, 0};
|
||
|
||
//
|
||
// Open Metabase path to the remote Node
|
||
//
|
||
|
||
ZeroMemory( &csiMachine, sizeof(COSERVERINFO) );
|
||
csiMachine.pwszName = (LPWSTR)wszNodeName;
|
||
|
||
hRes = CoCreateInstanceEx( GETAdminBaseCLSID(TRUE),
|
||
NULL,
|
||
CLSCTX_SERVER,
|
||
&csiMachine,
|
||
1,
|
||
&QI
|
||
);
|
||
|
||
if ( SUCCEEDED(hRes) && SUCCEEDED(QI.hr))
|
||
{
|
||
WCHAR achMDPath[80];
|
||
METADATA_RECORD mdRecord;
|
||
DWORD dwVal;
|
||
|
||
pcAdmCom = (IMSAdminBaseW *)QI.pItf;
|
||
|
||
if ( lpOldParams && lpOldParams->ServiceName && lpOldParams->InstanceId)
|
||
{
|
||
wcscpy(achMDPath,L"/LM/");
|
||
wcscat(achMDPath,lpOldParams->ServiceName);
|
||
wcscat(achMDPath,L"/");
|
||
wcscat(achMDPath,lpOldParams->InstanceId);
|
||
|
||
dwVal = 0;
|
||
|
||
if( SUCCEEDED( pcAdmCom->OpenKey( METADATA_MASTER_ROOT_HANDLE,
|
||
achMDPath,
|
||
METADATA_PERMISSION_WRITE,
|
||
5000,
|
||
&hmd)) )
|
||
{
|
||
MD_SET_DATA_RECORD ( &mdRecord,
|
||
MD_CLUSTER_ENABLED,
|
||
METADATA_INHERIT,
|
||
IIS_MD_UT_SERVER,
|
||
DWORD_METADATA,
|
||
sizeof(DWORD),
|
||
&dwVal
|
||
);
|
||
|
||
pcAdmCom->SetData( hmd, L"", &mdRecord);
|
||
pcAdmCom->CloseKey( hmd );
|
||
}
|
||
}
|
||
|
||
if ( lpNewParams && lpNewParams->ServiceName && lpNewParams->InstanceId)
|
||
{
|
||
wcscpy(achMDPath,L"/LM/");
|
||
wcscat(achMDPath,lpNewParams->ServiceName);
|
||
wcscat(achMDPath,L"/");
|
||
wcscat(achMDPath,lpNewParams->InstanceId);
|
||
|
||
dwVal = 1;
|
||
|
||
if( SUCCEEDED( pcAdmCom->OpenKey( METADATA_MASTER_ROOT_HANDLE,
|
||
achMDPath,
|
||
METADATA_PERMISSION_WRITE,
|
||
5000,
|
||
&hmd)) )
|
||
{
|
||
MD_SET_DATA_RECORD ( &mdRecord,
|
||
MD_CLUSTER_ENABLED,
|
||
METADATA_INHERIT,
|
||
IIS_MD_UT_SERVER,
|
||
DWORD_METADATA,
|
||
sizeof(DWORD),
|
||
&dwVal
|
||
);
|
||
|
||
pcAdmCom->SetData( hmd, L"", &mdRecord);
|
||
pcAdmCom->CloseKey( hmd );
|
||
}
|
||
}
|
||
|
||
pcAdmCom->Release();
|
||
}
|
||
} // IISSetRemoteNodeProperties
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
IISAlivePollingThread(
|
||
IN PCLUS_WORKER pWorker,
|
||
IN LPVOID lpVoid )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Polls the state of the given resource
|
||
|
||
Arguments:
|
||
|
||
Returns:
|
||
|
||
Win32 error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL bIsAlive = TRUE;
|
||
BOOL bFoundRes = FALSE;
|
||
DWORD dwStatus = ERROR_SUCCESS;
|
||
PLIST_ENTRY pRes = NULL; // temp list entry for looping
|
||
PLIST_ENTRY pListStart = NULL; // temp list head used for looping
|
||
PLIST_ENTRY pEntry = NULL; // list entry used to check the list of resources
|
||
LPIIS_RESOURCE pResourceEntry = NULL; // resource entry that corresponds to the list entry
|
||
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Thread Started \n") );
|
||
|
||
while ( !ClusWorkerCheckTerminate( &g_cwAlivePollingThread ) )
|
||
{
|
||
DWORD dwPort = 0;
|
||
SOCKADDR saServer;
|
||
DWORD dwServiceType = 0;
|
||
LPWSTR szMDPath = NULL;
|
||
BOOL bReadBindingsInfo = FALSE ;
|
||
|
||
//
|
||
// update the time stamp that is used by the isalive/looksalive check to determine this thread is still running
|
||
//
|
||
InterlockedExchange( (LPLONG) &g_dwTickOfLastResourceCheck, GetTickCount() );
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] set g_dwTickOfLastResourceCheck (%d)\n", g_dwTickOfLastResourceCheck) );
|
||
|
||
EnterCriticalSection( &IISTableLock );
|
||
{
|
||
//
|
||
// check that the list is not empty
|
||
//
|
||
if ( IsListEmpty ( &IISResourceTable ) )
|
||
{
|
||
LeaveCriticalSection( &IISTableLock );
|
||
pEntry = NULL;
|
||
|
||
goto done_check;
|
||
}
|
||
|
||
//
|
||
// if we don't have a list element yet get the fisrt element in the list
|
||
//
|
||
if ( !pEntry || g_fIISResourceTable_HadChanged)
|
||
{
|
||
pEntry = IISResourceTable.Flink;
|
||
g_fIISResourceTable_HadChanged = FALSE;
|
||
}
|
||
|
||
//
|
||
// look for an element in the list that is OnLine
|
||
//
|
||
bFoundRes = FALSE ;
|
||
|
||
pListStart = pEntry;
|
||
|
||
do
|
||
{
|
||
if ( &IISResourceTable != pEntry )
|
||
{
|
||
//
|
||
// get the structure that contains this list element
|
||
//
|
||
pResourceEntry = CONTAINING_RECORD( pEntry,
|
||
IIS_RESOURCE,
|
||
ListEntry );
|
||
|
||
if ( pResourceEntry &&
|
||
(ClusterResourceOnline == pResourceEntry->State) )
|
||
{
|
||
//
|
||
// grab the info that we need from this structure so we can release the critical section
|
||
//
|
||
dwPort = pResourceEntry->dwPort;
|
||
dwServiceType = pResourceEntry->Params.ServiceType;
|
||
memcpy( (LPVOID) &saServer, (LPVOID) &pResourceEntry->saServer, sizeof(SOCKADDR) );
|
||
|
||
//
|
||
// allocate memory for the metabase path for this resource
|
||
//
|
||
if ( pResourceEntry->Params.MDPath )
|
||
{
|
||
szMDPath = (LPWSTR) LocalAlloc ( LPTR, (lstrlen(pResourceEntry->Params.MDPath)+1) * sizeof(WCHAR) ) ;
|
||
if ( szMDPath )
|
||
{
|
||
lstrcpy( szMDPath, pResourceEntry->Params.MDPath );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] checking resource (%S/%S), State:%d OnLineState:%d\n", pResourceEntry->Params.ServiceName, pResourceEntry->Params.InstanceId, pResourceEntry->State, ClusterResourceOnline) );
|
||
|
||
bFoundRes = TRUE;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Failed to allocate memory for metadata path\n") );
|
||
}
|
||
}
|
||
|
||
if ( szMDPath ) TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Checking resource Metadata Path:%S\n", szMDPath) );
|
||
}
|
||
else
|
||
{
|
||
if ( pResourceEntry ) TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Not checking resource (%S/%S) because it's not Online, State:%d OnLineState:%d\n", pResourceEntry->Params.ServiceName, pResourceEntry->Params.InstanceId, pResourceEntry->State, ClusterResourceOnline) );
|
||
}
|
||
}
|
||
|
||
//
|
||
// check the next element
|
||
//
|
||
pEntry = pEntry->Flink ;
|
||
}
|
||
while ( pListStart != pEntry );
|
||
|
||
//
|
||
// verify the loop ended because a valid resource was found
|
||
//
|
||
if ( !bFoundRes )
|
||
{
|
||
LeaveCriticalSection( &IISTableLock );
|
||
pEntry = NULL;
|
||
|
||
goto done_check;
|
||
}
|
||
}
|
||
LeaveCriticalSection( &IISTableLock );
|
||
|
||
//
|
||
// if the service status check (isalive/looksalive check) fails then get server bindings and try again
|
||
//
|
||
if ( ERROR_SUCCESS != (dwStatus = VerifyIISService( szMDPath, dwServiceType, dwPort, saServer, g_IISLogEvent )) )
|
||
{
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] VerifyIISService failed , calling GetServerBindings() and retrying \n") );
|
||
|
||
if ( ERROR_SUCCESS == (dwStatus = GetServerBindings( szMDPath, dwServiceType, &saServer, &dwPort )) )
|
||
{
|
||
bReadBindingsInfo = TRUE ;
|
||
dwStatus = VerifyIISService( szMDPath, dwServiceType, dwPort, saServer, g_IISLogEvent );
|
||
}
|
||
}
|
||
|
||
bIsAlive = (dwStatus == ERROR_SUCCESS);
|
||
|
||
if ( szMDPath )
|
||
{
|
||
LocalFree ( szMDPath );
|
||
szMDPath = NULL;
|
||
}
|
||
|
||
EnterCriticalSection( &IISTableLock );
|
||
{
|
||
//
|
||
// check that the list is not empty
|
||
//
|
||
if ( IsListEmpty ( &IISResourceTable ) )
|
||
{
|
||
LeaveCriticalSection( &IISTableLock );
|
||
pEntry = NULL;
|
||
|
||
goto done_check;
|
||
}
|
||
|
||
//
|
||
// check that the element still exists in the list
|
||
//
|
||
bFoundRes = FALSE ;
|
||
|
||
for ( pRes = IISResourceTable.Flink;
|
||
pRes != &IISResourceTable;
|
||
pRes = pRes->Flink )
|
||
{
|
||
if ( pEntry == pRes )
|
||
{
|
||
bFoundRes = TRUE ;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( bFoundRes )
|
||
{
|
||
//
|
||
// get the elemement
|
||
//
|
||
pResourceEntry = CONTAINING_RECORD( pEntry,
|
||
IIS_RESOURCE,
|
||
ListEntry );
|
||
|
||
//
|
||
// update the element's state information (isalive/looksalive)
|
||
//
|
||
InterlockedExchange( (LPLONG)&pResourceEntry->bAlive , bIsAlive );
|
||
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Updating IsAlive/LooksAlive status for resource Metadata Path:%S bAlive:%d State:%d\n", pResourceEntry->Params.MDPath, bIsAlive, pResourceEntry->State) );
|
||
|
||
//
|
||
// update the bindings info if new information was found . these assignments do not need to be sync'ed
|
||
// since the only other thread they are used in is in the online thread . before the resource has been marked online
|
||
// so this code will never be executed at the same time .
|
||
//
|
||
if ( bReadBindingsInfo )
|
||
{
|
||
pResourceEntry->dwPort = dwPort ;
|
||
memcpy( (LPVOID) &pResourceEntry->saServer, (LPVOID) &saServer, sizeof(SOCKADDR) );
|
||
}
|
||
|
||
//
|
||
// print some error messages so users will know when a resource fails
|
||
//
|
||
if ( !pResourceEntry->bAlive )
|
||
{
|
||
if ( g_IISLogEvent )
|
||
{
|
||
//
|
||
// Some type of error
|
||
//
|
||
(g_IISLogEvent)(
|
||
pResourceEntry->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"IsAlive/LooksAlive ERROR getting information for service %1!ws! resource %2!ws!\n",
|
||
pResourceEntry->Params.ServiceName,
|
||
pResourceEntry->ResourceName );
|
||
}
|
||
|
||
if ( g_hEventLog )
|
||
{
|
||
LPCTSTR aErrStr[3];
|
||
WCHAR aErrCode[32];
|
||
|
||
_ultow( dwStatus, aErrCode, 10 );
|
||
|
||
aErrStr[0] = pResourceEntry->Params.ServiceName;
|
||
aErrStr[1] = pResourceEntry->Params.InstanceId;
|
||
aErrStr[2] = aErrCode;
|
||
|
||
ReportEvent( g_hEventLog,
|
||
EVENTLOG_ERROR_TYPE,
|
||
0,
|
||
IISCL_EVENT_CANT_ACCESS_IIS,
|
||
NULL,
|
||
sizeof(aErrStr)/sizeof(LPCTSTR),
|
||
0,
|
||
aErrStr,
|
||
NULL );
|
||
}
|
||
}
|
||
|
||
//
|
||
// move to the next element
|
||
//
|
||
pEntry = pEntry->Flink;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// the resource was not found , probably deleted so pEntry is now invalid
|
||
//
|
||
pEntry = NULL;
|
||
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Failed to find a resource after checking its state\n") );
|
||
}
|
||
|
||
}
|
||
LeaveCriticalSection( &IISTableLock );
|
||
|
||
done_check:
|
||
|
||
Sleep( DELAY_BETWEEN_ISALIVE_CHECKS );
|
||
}
|
||
|
||
TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Thread Exiting \n") );
|
||
|
||
return dwStatus;
|
||
|
||
} // IISAlivePollingThread
|
||
|
||
//***********************************************************
|
||
//
|
||
// Define Function Table
|
||
//
|
||
//***********************************************************
|
||
|
||
// Define entry points
|
||
|
||
|
||
CLRES_V1_FUNCTION_TABLE( IISFunctionTable,
|
||
CLRES_VERSION_V1_00,
|
||
IIS,
|
||
NULL,
|
||
NULL,
|
||
IISResourceControl,
|
||
IISResourceTypeControl );
|