1528 lines
36 KiB
C
1528 lines
36 KiB
C
/*++
|
||
|
||
Copyright (c) 1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dummyiis.c
|
||
|
||
Abstract:
|
||
|
||
This file was adapted from \nt\private\cluster\resdll\dummy\dummy.c. It
|
||
implements an NT Cluster resource DLL for the IIS Virtual Root resource type.
|
||
This resource does nothing except read the value "Parameters\Failed" from the
|
||
resource definition in the registry on each poll to determine whether or not the resource
|
||
has failed.
|
||
|
||
The DLL is to be installed during UPGRADE from NT 4.0. It will become obsolete
|
||
with the availability of a IIS Virtual Root resource DLL that works with IIS 5.
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 5-Dec-1995
|
||
|
||
Revision History:
|
||
|
||
C. Brent Thomas (a-brentt) 29-May-1998
|
||
|
||
Adapted for IIS Virtual Root reaource type.
|
||
|
||
--*/
|
||
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
#include "clusapi.h"
|
||
#include "resapi.h"
|
||
|
||
//
|
||
// Local Types.
|
||
//
|
||
|
||
typedef enum TimerType {
|
||
TimerNotUsed,
|
||
TimerErrorPending,
|
||
TimerOnlinePending,
|
||
TimerOfflinePending
|
||
};
|
||
|
||
typedef struct {
|
||
DWORD Flags;
|
||
CLUSTER_RESOURCE_STATE State;
|
||
HANDLE SignalEvent;
|
||
HANDLE TimerThreadWakeup;
|
||
HANDLE ThreadHandle;
|
||
HKEY ParametersKey;
|
||
RESID ResourceId;
|
||
DWORD TimerType;
|
||
RESOURCE_HANDLE ResourceHandle;
|
||
DWORD PendTime;
|
||
} DUMMY_RESOURCE, *PDUMMY_RESOURCE;
|
||
// 10 dwords ( 0x28 offset )
|
||
|
||
//
|
||
// Constants
|
||
//
|
||
#define DUMMY_RESOURCE_BLOCK_SIZE 4
|
||
|
||
#define DUMMY_FLAG_VALID 0x00000001
|
||
#define DUMMY_FLAG_ASYNC 0x00000002 // Asynchronous failure mode
|
||
#define DUMMY_FLAG_PENDING 0x00000004 // Pending mode on shutdown
|
||
|
||
#define DUMMY_PARAMETER_FAILED L"Failed"
|
||
#define DUMMY_PARAMETER_ASYNC L"Asynchronous"
|
||
#define DUMMY_PARAMETER_PENDING L"Pending"
|
||
#define DUMMY_PARAMETER_OPENSFAIL L"OpensFail"
|
||
#define DUMMY_PARAMETER_PENDTIME L"PendTime"
|
||
|
||
#define DUMMY_PRINT printf
|
||
|
||
//
|
||
// Macros
|
||
//
|
||
#define AsyncMode(Resource) (Resource->Flags & DUMMY_FLAG_ASYNC)
|
||
#define PendingMode(Resource) (Resource->Flags & DUMMY_FLAG_PENDING)
|
||
|
||
#define EnterAsyncMode(Resource) (Resource->Flags |= DUMMY_FLAG_ASYNC)
|
||
|
||
#define DummyAcquireResourceLock() \
|
||
{ \
|
||
DWORD status; \
|
||
status = WaitForSingleObject(DummyResourceSemaphore, INFINITE); \
|
||
}
|
||
|
||
#define DummyReleaseResourceLock() \
|
||
{ \
|
||
ReleaseSemaphore(DummyResourceSemaphore, 1, NULL); \
|
||
}
|
||
|
||
|
||
//
|
||
// Local Variables
|
||
//
|
||
PDUMMY_RESOURCE DummyResourceList = NULL;
|
||
DWORD DummyResourceListSize = DUMMY_RESOURCE_BLOCK_SIZE;
|
||
HANDLE DummyResourceSemaphore = NULL;
|
||
PLOG_EVENT_ROUTINE LogEvent;
|
||
PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus;
|
||
|
||
extern CLRES_FUNCTION_TABLE DumbFunctionTable;
|
||
|
||
|
||
//
|
||
// Local utility functions
|
||
//
|
||
|
||
|
||
DWORD
|
||
DummyInit(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates and initializes global system resources for the Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A Win32 error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
|
||
|
||
DummyResourceSemaphore = CreateSemaphore(NULL, 0, 1 , NULL);
|
||
|
||
if (DummyResourceSemaphore == NULL) {
|
||
status = GetLastError();
|
||
DUMMY_PRINT(
|
||
"DUMMY: unable to create resource mutex, error %u\n",
|
||
status
|
||
);
|
||
return(status);
|
||
}
|
||
|
||
if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
|
||
ReleaseSemaphore( DummyResourceSemaphore, 1, NULL );
|
||
}
|
||
|
||
DummyResourceList = LocalAlloc(
|
||
LMEM_FIXED,
|
||
DummyResourceListSize * sizeof(DUMMY_RESOURCE)
|
||
);
|
||
|
||
if (DummyResourceList == NULL) {
|
||
DUMMY_PRINT("DUMMY: unable to allocate resource list\n");
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
CloseHandle(DummyResourceSemaphore);
|
||
DummyResourceSemaphore = NULL;
|
||
return(status);
|
||
}
|
||
|
||
ZeroMemory(
|
||
DummyResourceList,
|
||
DummyResourceListSize * sizeof(DUMMY_RESOURCE)
|
||
);
|
||
|
||
return(NO_ERROR);
|
||
|
||
} // DummyInit
|
||
|
||
|
||
|
||
VOID
|
||
DummyCleanup(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deallocates any system resources in use by the Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (DummyResourceList != NULL) {
|
||
LocalFree(DummyResourceList);
|
||
DummyResourceList = NULL;
|
||
}
|
||
|
||
if (DummyResourceSemaphore != NULL) {
|
||
CloseHandle(DummyResourceSemaphore);
|
||
DummyResourceSemaphore = NULL;
|
||
}
|
||
|
||
return;
|
||
|
||
} // DummyCleanup
|
||
|
||
|
||
|
||
PDUMMY_RESOURCE
|
||
DummyAllocateResource(
|
||
OUT RESID *ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates a resource structure from the free pool.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - Filled in with the RESID for the allocated resource
|
||
on return.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the allocated resource, or NULL on error.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDUMMY_RESOURCE resource = NULL;
|
||
PDUMMY_RESOURCE newList;
|
||
DWORD i;
|
||
DWORD newSize = DummyResourceListSize +
|
||
DUMMY_RESOURCE_BLOCK_SIZE;
|
||
|
||
for (i=1; i < DummyResourceListSize; i++) {
|
||
if (!(DummyResourceList[i].Flags & DUMMY_FLAG_VALID)) {
|
||
resource = DummyResourceList + i;
|
||
*ResourceId = (RESID)ULongToPtr( i );
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (resource == NULL) {
|
||
newList = LocalReAlloc(
|
||
DummyResourceList,
|
||
newSize * sizeof(DUMMY_RESOURCE),
|
||
LMEM_MOVEABLE
|
||
);
|
||
|
||
if (newList == NULL) {
|
||
return(NULL);
|
||
}
|
||
|
||
DummyResourceList = newList;
|
||
resource = DummyResourceList + DummyResourceListSize;
|
||
*ResourceId = (RESID) ULongToPtr( DummyResourceListSize );
|
||
DummyResourceListSize = newSize;
|
||
ZeroMemory(resource, DUMMY_RESOURCE_BLOCK_SIZE * sizeof(DUMMY_RESOURCE));
|
||
}
|
||
|
||
ZeroMemory(resource, sizeof(DUMMY_RESOURCE));
|
||
|
||
resource->Flags = DUMMY_FLAG_VALID;
|
||
|
||
return(resource);
|
||
|
||
} // DummyAllocateResource
|
||
|
||
|
||
|
||
VOID
|
||
DummyFreeResource(
|
||
IN PDUMMY_RESOURCE Resource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns a resource structure to the free pool.
|
||
|
||
Arguments:
|
||
|
||
Resource - A pointer to the resource structure to free.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
Resource->Flags = 0;
|
||
|
||
return;
|
||
|
||
} // DummyFreeResource
|
||
|
||
|
||
|
||
PDUMMY_RESOURCE
|
||
DummyFindResource(
|
||
IN RESID ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Locates the Dummy resource structure identified by a RESID.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - The RESID of the resource to locate.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the resource strucuture, or NULL on error.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD index = PtrToUlong(ResourceId);
|
||
PDUMMY_RESOURCE resource = NULL;
|
||
|
||
|
||
if (index < DummyResourceListSize) {
|
||
|
||
if (DummyResourceList[index].Flags & DUMMY_FLAG_VALID) {
|
||
resource = DummyResourceList + index;
|
||
}
|
||
}
|
||
|
||
return(resource);
|
||
|
||
} // DummyFindResource
|
||
|
||
|
||
|
||
DWORD
|
||
DummyTimerThread(
|
||
IN LPVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Starts a timer thread to wait and signal failures
|
||
|
||
Arguments:
|
||
|
||
Context - A pointer to the DummyResource block for this resource.
|
||
|
||
Returns:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Win32 error code on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDUMMY_RESOURCE resource = (PDUMMY_RESOURCE)Context;
|
||
RESOURCE_STATUS resourceStatus;
|
||
SYSTEMTIME time;
|
||
DWORD delay;
|
||
DWORD status;
|
||
|
||
(LogEvent)(
|
||
NULL,
|
||
LOG_INFORMATION,
|
||
L"TimerThread Entry\n");
|
||
|
||
//
|
||
// If we are not running in async failure mode, or
|
||
// pending mode then exit now.
|
||
//
|
||
|
||
if ( !AsyncMode(resource) && !PendingMode(resource) ) {
|
||
return(ERROR_SUCCESS);
|
||
}
|
||
|
||
more_pending:
|
||
|
||
ResUtilInitializeResourceStatus( &resourceStatus );
|
||
|
||
//
|
||
// Otherwise, get system time for random delay.
|
||
//
|
||
if (resource->PendTime == 0) {
|
||
GetSystemTime(&time);
|
||
|
||
delay = (time.wMilliseconds + time.wSecond) * 6;
|
||
} else {
|
||
delay = resource->PendTime * 1000;
|
||
}
|
||
|
||
|
||
// Use longer delays for errors
|
||
if ( resource->TimerType == TimerErrorPending ) {
|
||
delay = delay*10;
|
||
}
|
||
|
||
//
|
||
// This routine is either handling an Offline Pending or an error timeout.
|
||
//
|
||
|
||
switch ( resource->TimerType ) {
|
||
|
||
case TimerOnlinePending:
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Will complete online in approximately %1!u! seconds\n",
|
||
(delay+500)/1000);
|
||
|
||
resourceStatus.ResourceState = ClusterResourceOnline;
|
||
resourceStatus.WaitHint = 0;
|
||
resourceStatus.CheckPoint = 1;
|
||
|
||
status = WaitForSingleObject( resource->TimerThreadWakeup, delay );
|
||
|
||
//
|
||
// Either the terminate routine was called, or we timed out.
|
||
// If we timed out, then indicate that we've completed.
|
||
//
|
||
|
||
if ( status == WAIT_TIMEOUT ) {
|
||
GetSystemTime(&time);
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Online resource state transition complete at %1!02d!:%2!02d!:%3!02d!.%4!03d!\n",
|
||
time.wHour,
|
||
time.wMinute,
|
||
time.wSecond,
|
||
time.wMilliseconds);
|
||
|
||
resource->State = ClusterResourceOnline;
|
||
(SetResourceStatus)(resource->ResourceHandle,
|
||
&resourceStatus);
|
||
if ( AsyncMode( resource ) ) {
|
||
resource->TimerType = TimerErrorPending;
|
||
goto more_pending;
|
||
}
|
||
} else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Online pending terminated\n");
|
||
if ( resource->State == ClusterResourceOffline ) {
|
||
resource->TimerType = TimerOfflinePending;
|
||
goto more_pending;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TimerOfflinePending:
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Will complete offline in approximately %1!u! seconds\n",
|
||
(delay+500)/1000);
|
||
|
||
resourceStatus.ResourceState = ClusterResourceOffline;
|
||
resourceStatus.WaitHint = 0;
|
||
resourceStatus.CheckPoint = 1;
|
||
|
||
status = WaitForSingleObject( resource->TimerThreadWakeup, delay );
|
||
|
||
//
|
||
// Either the terminate routine was called, or we timed out.
|
||
// If we timed out, then indicate that we've completed.
|
||
//
|
||
|
||
if ( status == WAIT_TIMEOUT ) {
|
||
GetSystemTime(&time);
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Offline resource state transition complete at %1!02d!:%2!02d!:%3!02d!.%4!03d!\n",
|
||
time.wHour,
|
||
time.wMinute,
|
||
time.wSecond,
|
||
time.wMilliseconds);
|
||
|
||
resource->State = ClusterResourceOffline;
|
||
(SetResourceStatus)(resource->ResourceHandle,
|
||
&resourceStatus);
|
||
} else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Offline pending terminated\n");
|
||
}
|
||
break;
|
||
|
||
case TimerErrorPending:
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Will fail in approximately %1!u! seconds\n",
|
||
(delay+500)/1000);
|
||
|
||
if ( !ResetEvent( resource->SignalEvent ) ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to reset the signal event\n");
|
||
resource->ThreadHandle = NULL;
|
||
return(ERROR_GEN_FAILURE);
|
||
}
|
||
|
||
status = WaitForSingleObject( resource->TimerThreadWakeup, delay );
|
||
|
||
//
|
||
// Either the terminate routine was called, or we timed out.
|
||
// If we timed out, then signal the waiting event.
|
||
//
|
||
|
||
if ( status == WAIT_TIMEOUT ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Failed randomly\n");
|
||
resource->TimerType = TimerNotUsed;
|
||
SetEvent( resource->SignalEvent );
|
||
} else {
|
||
if ( resource->State == ClusterResourceOfflinePending ) {
|
||
resource->TimerType = TimerOfflinePending;
|
||
goto more_pending;
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"DummyTimer internal error, timer %1!u!\n",
|
||
resource->TimerType);
|
||
break;
|
||
|
||
}
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"TimerThread Exit\n");
|
||
|
||
|
||
resource->TimerType = TimerNotUsed;
|
||
resource->ThreadHandle = NULL;
|
||
return(ERROR_SUCCESS);
|
||
|
||
} // DummyTimerThread
|
||
|
||
|
||
|
||
//
|
||
// Public Functions
|
||
//
|
||
|
||
BOOL
|
||
WINAPI
|
||
DummyDllEntryPoint(
|
||
IN HINSTANCE DllHandle,
|
||
IN DWORD Reason,
|
||
IN LPVOID Reserved
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialization & cleanup routine for Dummy resource DLL.
|
||
|
||
Arguments:
|
||
|
||
DllHandle - Handle to the DLL.
|
||
|
||
Reason - The reason this routine is being invoked.
|
||
|
||
Return Value:
|
||
|
||
On PROCESS_ATTACH: TRUE if the DLL initialized successfully
|
||
FALSE if it did not.
|
||
|
||
The return value from all other calls is ignored.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
|
||
|
||
switch(Reason) {
|
||
|
||
case DLL_PROCESS_ATTACH:
|
||
status = DummyInit();
|
||
|
||
if (status != NO_ERROR) {
|
||
SetLastError(status);
|
||
return(FALSE);
|
||
}
|
||
|
||
break;
|
||
|
||
case DLL_PROCESS_DETACH:
|
||
DummyCleanup();
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return(TRUE);
|
||
|
||
} // DummyDllEntryPoint
|
||
|
||
|
||
|
||
//
|
||
// Define the resource Name
|
||
//
|
||
#define IIS_RESOURCE_NAME L"IIS Virtual Root"
|
||
|
||
DWORD
|
||
WINAPI
|
||
Startup(
|
||
IN LPCWSTR ResourceType,
|
||
IN DWORD MinVersionSupported,
|
||
IN DWORD MaxVersionSupported,
|
||
IN PSET_RESOURCE_STATUS_ROUTINE pSetResourceStatus,
|
||
IN PLOG_EVENT_ROUTINE pLogEvent,
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
if ( lstrcmpiW( ResourceType, IIS_RESOURCE_NAME ) != 0 )
|
||
{
|
||
return (ERROR_UNKNOWN_REVISION);
|
||
}
|
||
|
||
LogEvent = pLogEvent;
|
||
SetResourceStatus = pSetResourceStatus;
|
||
|
||
if ( (MinVersionSupported <= CLRES_VERSION_V1_00) &&
|
||
(MaxVersionSupported >= CLRES_VERSION_V1_00) )
|
||
{
|
||
*FunctionTable = &DumbFunctionTable;
|
||
return (ERROR_SUCCESS);
|
||
}
|
||
|
||
return (ERROR_REVISION_MISMATCH);
|
||
|
||
} // Startup
|
||
|
||
|
||
|
||
RESID
|
||
WINAPI
|
||
DumbOpen(
|
||
IN LPCWSTR ResourceName,
|
||
IN HKEY ResourceKey,
|
||
IN RESOURCE_HANDLE ResourceHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Open (initialize) routine for Dummy resource
|
||
|
||
Arguments:
|
||
|
||
ResourceName - supplies the resource name
|
||
|
||
ResourceKey - supplies a handle to the resource's cluster registry key
|
||
|
||
ResourceHandle - the resource handle to be supplied with SetResourceStatus
|
||
is called.
|
||
|
||
SetResourceStatus - a routine to call to update status for the resource.
|
||
|
||
LogEvent - a routine to call to log an event for this resource.
|
||
|
||
Return Value:
|
||
|
||
RESID of created resource
|
||
NULL on failure
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
HKEY parametersKey = NULL;
|
||
PDUMMY_RESOURCE resource = NULL;
|
||
RESID resourceId = 0;
|
||
DWORD asyncMode = FALSE;
|
||
DWORD valueSize;
|
||
DWORD valueType;
|
||
DWORD pendingMode = FALSE;
|
||
DWORD opensFail = FALSE;
|
||
DWORD pendingTime = 0;
|
||
|
||
status = ClusterRegOpenKey(ResourceKey,
|
||
L"Parameters",
|
||
KEY_READ,
|
||
¶metersKey);
|
||
|
||
if (status != NO_ERROR) {
|
||
(LogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to open parameters key, status %1!u!\n",
|
||
status);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Find out if we should just fail the open request.
|
||
//
|
||
valueSize = sizeof(opensFail);
|
||
status = ClusterRegQueryValue(parametersKey,
|
||
DUMMY_PARAMETER_OPENSFAIL,
|
||
&valueType,
|
||
(PBYTE)&opensFail,
|
||
&valueSize);
|
||
if ( status != NO_ERROR ) {
|
||
opensFail = FALSE;
|
||
}
|
||
|
||
if ( opensFail ) {
|
||
ClusterRegCloseKey(parametersKey);
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// Find out whether we should run in async failure mode.
|
||
//
|
||
|
||
valueSize = sizeof(asyncMode);
|
||
status = ClusterRegQueryValue(parametersKey,
|
||
DUMMY_PARAMETER_ASYNC,
|
||
&valueType,
|
||
(PBYTE)&asyncMode,
|
||
&valueSize);
|
||
|
||
if (status != NO_ERROR) {
|
||
asyncMode = FALSE;
|
||
}
|
||
|
||
//
|
||
// Find out whether we should return Pending on shutdown.
|
||
//
|
||
|
||
valueSize = sizeof(pendingMode);
|
||
status = ClusterRegQueryValue(parametersKey,
|
||
DUMMY_PARAMETER_PENDING,
|
||
&valueType,
|
||
(PBYTE)&pendingMode,
|
||
&valueSize);
|
||
|
||
if (status != NO_ERROR) {
|
||
pendingMode = FALSE;
|
||
} else {
|
||
//
|
||
// See if there is a defined time period
|
||
//
|
||
valueSize = sizeof(pendingTime);
|
||
status = ClusterRegQueryValue(parametersKey,
|
||
DUMMY_PARAMETER_PENDTIME,
|
||
&valueType,
|
||
(PBYTE)&pendingTime,
|
||
&valueSize);
|
||
}
|
||
|
||
//
|
||
// Now go allocate a resource structure.
|
||
//
|
||
|
||
DummyAcquireResourceLock();
|
||
|
||
resource = DummyAllocateResource(&resourceId);
|
||
|
||
if (resource == NULL) {
|
||
(LogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Unable to allocate resource structure\n");
|
||
DummyReleaseResourceLock();
|
||
ClusterRegCloseKey(parametersKey);
|
||
return(0);
|
||
}
|
||
|
||
resource->State = ClusterResourceOffline;
|
||
resource->ParametersKey = parametersKey;
|
||
resource->ResourceId = resourceId;
|
||
|
||
//
|
||
// Copy stuff for returning pending status.
|
||
//
|
||
|
||
resource->ResourceHandle = ResourceHandle;
|
||
|
||
DummyReleaseResourceLock();
|
||
|
||
//
|
||
// Create a TimerThreadWakeup event if needed.
|
||
//
|
||
|
||
if ( pendingMode || asyncMode ) {
|
||
resource->TimerThreadWakeup = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||
|
||
if ( resource->TimerThreadWakeup == NULL ) {
|
||
DummyFreeResource( resource );
|
||
(LogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to create timer thread wakeup event\n");
|
||
ClusterRegCloseKey(parametersKey);
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
if ( pendingMode ) {
|
||
resource->Flags |= DUMMY_FLAG_PENDING;
|
||
resource->PendTime = pendingTime;
|
||
}
|
||
|
||
if ( asyncMode ) {
|
||
EnterAsyncMode( resource );
|
||
|
||
resource->SignalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||
|
||
if ( resource->SignalEvent == NULL ) {
|
||
DummyFreeResource( resource );
|
||
(LogEvent)(
|
||
ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to create a timer event\n");
|
||
ClusterRegCloseKey(parametersKey);
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
return(resourceId);
|
||
|
||
} // DumbOpen
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DumbOnline(
|
||
IN RESID ResourceId,
|
||
IN OUT PHANDLE EventHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Online routine for Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDUMMY_RESOURCE resource;
|
||
DWORD status = ERROR_SUCCESS;
|
||
DWORD threadId;
|
||
SYSTEMTIME time;
|
||
|
||
(LogEvent)(
|
||
NULL,
|
||
LOG_INFORMATION,
|
||
L"Online Entry\n");
|
||
|
||
DummyAcquireResourceLock();
|
||
|
||
resource = DummyFindResource(ResourceId);
|
||
|
||
if (resource == NULL) {
|
||
status = ERROR_RESOURCE_NOT_FOUND;
|
||
DUMMY_PRINT("DUMMY Online: resource %u not found.\n", PtrToUlong(ResourceId));
|
||
} else {
|
||
if ( resource->TimerType != TimerNotUsed ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Timer still running!\n");
|
||
DummyReleaseResourceLock();
|
||
return(ERROR_GEN_FAILURE);
|
||
}
|
||
if ( PendingMode( resource ) ) {
|
||
if ( !resource->ThreadHandle ) {
|
||
resource->TimerType = TimerOnlinePending;
|
||
resource->ThreadHandle = CreateThread(
|
||
NULL,
|
||
0,
|
||
DummyTimerThread,
|
||
resource,
|
||
0,
|
||
&threadId
|
||
);
|
||
if ( resource->ThreadHandle == NULL ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to start timer thread.\n");
|
||
resource->TimerType = TimerNotUsed;
|
||
status = ERROR_GEN_FAILURE;
|
||
} else {
|
||
CloseHandle( resource->ThreadHandle );
|
||
}
|
||
status = ERROR_IO_PENDING;
|
||
}
|
||
if ( AsyncMode(resource) && (status != ERROR_GEN_FAILURE) ) {
|
||
*EventHandle = resource->SignalEvent;
|
||
}
|
||
} else if ( AsyncMode( resource ) ) {
|
||
if ( !ResetEvent( resource->TimerThreadWakeup ) ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to reset timer wakeup event\n");
|
||
status = ERROR_GEN_FAILURE;
|
||
} else if ( !resource->ThreadHandle ) {
|
||
resource->ThreadHandle = CreateThread(
|
||
NULL,
|
||
0,
|
||
DummyTimerThread,
|
||
resource,
|
||
0,
|
||
&threadId
|
||
);
|
||
|
||
if ( resource->ThreadHandle == NULL ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to start timer thread.\n");
|
||
status = ERROR_GEN_FAILURE;
|
||
} else {
|
||
CloseHandle(resource->ThreadHandle);
|
||
}
|
||
resource->TimerType = TimerErrorPending;
|
||
}
|
||
//
|
||
// If we are successful, then return our signal event.
|
||
//
|
||
if ( status == ERROR_SUCCESS ) {
|
||
*EventHandle = resource->SignalEvent;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( status == ERROR_SUCCESS ) {
|
||
resource->State = ClusterResourceOnline;
|
||
GetSystemTime(&time);
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Online at %1!02d!:%2!02d!:%3!02d!.%4!03d!\n",
|
||
time.wHour,
|
||
time.wMinute,
|
||
time.wSecond,
|
||
time.wMilliseconds);
|
||
} else if ( status == ERROR_IO_PENDING ) {
|
||
resource->State = ClusterResourceOnlinePending;
|
||
}
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Online Exit\n");
|
||
|
||
|
||
DummyReleaseResourceLock();
|
||
|
||
return(status);
|
||
|
||
} // DumbOnline
|
||
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
DumbTerminate(
|
||
IN RESID ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Terminate routine for Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - supplies resource id to be terminated
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDUMMY_RESOURCE resource;
|
||
|
||
(LogEvent)(
|
||
NULL,
|
||
LOG_INFORMATION,
|
||
L"Terminate Entry\n");
|
||
|
||
DummyAcquireResourceLock();
|
||
|
||
resource = DummyFindResource(ResourceId);
|
||
|
||
if (resource == NULL) {
|
||
DUMMY_PRINT("DUMMY Terminate: resource %u not found\n", PtrToUlong(ResourceId));
|
||
}
|
||
else {
|
||
resource->State = ClusterResourceFailed;
|
||
if ( resource->TimerType != TimerNotUsed ) {
|
||
SetEvent( resource->TimerThreadWakeup );
|
||
}
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Terminated\n");
|
||
}
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Terminate Exit\n");
|
||
|
||
resource->ThreadHandle = NULL;
|
||
DummyReleaseResourceLock();
|
||
|
||
return;
|
||
|
||
} // DumbTerminate
|
||
|
||
|
||
|
||
DWORD
|
||
WINAPI
|
||
DumbOffline(
|
||
IN RESID ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Offline routine for Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - supplies the resource it to be taken offline
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - always successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status = ERROR_SUCCESS;
|
||
DWORD threadId;
|
||
PDUMMY_RESOURCE resource;
|
||
|
||
(LogEvent)(
|
||
NULL,
|
||
LOG_INFORMATION,
|
||
L"Offline Entry\n");
|
||
|
||
DumbTerminate(ResourceId);
|
||
|
||
//
|
||
// Now check if we are to return pending...
|
||
//
|
||
|
||
DummyAcquireResourceLock();
|
||
|
||
resource = DummyFindResource(ResourceId);
|
||
|
||
if (resource == NULL) {
|
||
DUMMY_PRINT("DUMMY Offline: resource %u not found\n", PtrToUlong(ResourceId));
|
||
} else {
|
||
resource->State = ClusterResourceOfflinePending;
|
||
if ( resource->TimerType != TimerNotUsed ) {
|
||
DummyReleaseResourceLock();
|
||
return(ERROR_IO_PENDING);
|
||
}
|
||
resource->State = ClusterResourceOffline;
|
||
if ( PendingMode(resource) ) {
|
||
//CL_ASSERT( resource->ThreadHandle == NULL );
|
||
if ( !ResetEvent( resource->TimerThreadWakeup ) ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to reset pending wakeup event\n");
|
||
status = ERROR_GEN_FAILURE;
|
||
} else if ( !resource->ThreadHandle ) {
|
||
resource->ThreadHandle = CreateThread(
|
||
NULL,
|
||
0,
|
||
DummyTimerThread,
|
||
resource,
|
||
0,
|
||
&threadId
|
||
);
|
||
|
||
if ( resource->ThreadHandle == NULL ) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_ERROR,
|
||
L"Failed to start pending timer thread.\n");
|
||
status = GetLastError();
|
||
} else {
|
||
CloseHandle( resource->ThreadHandle );
|
||
resource->TimerType = TimerOfflinePending;
|
||
status = ERROR_IO_PENDING;
|
||
resource->State = ClusterResourceOfflinePending;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Offline Exit\n");
|
||
|
||
DummyReleaseResourceLock();
|
||
|
||
return(status);
|
||
|
||
} // DumbOffline
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
DumbIsAlive(
|
||
IN RESID ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
IsAlive routine for Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - supplies the resource id to be polled.
|
||
|
||
Return Value:
|
||
|
||
TRUE - Resource is alive and well
|
||
|
||
FALSE - Resource is toast.
|
||
|
||
--*/
|
||
|
||
{
|
||
SYSTEMTIME Time;
|
||
PDUMMY_RESOURCE resource;
|
||
BOOLEAN returnValue = FALSE;
|
||
DWORD failed = FALSE;
|
||
DWORD status;
|
||
DWORD ValueType;
|
||
DWORD ValueSize;
|
||
|
||
DummyAcquireResourceLock();
|
||
|
||
resource = DummyFindResource(ResourceId);
|
||
|
||
if (resource == NULL) {
|
||
DUMMY_PRINT("DUMMY IsAlive: resource %u not found.\n", PtrToUlong(ResourceId));
|
||
DummyReleaseResourceLock();
|
||
return(FALSE);
|
||
}
|
||
|
||
GetSystemTime(&Time);
|
||
|
||
ValueSize = sizeof(failed);
|
||
status = ClusterRegQueryValue(resource->ParametersKey,
|
||
DUMMY_PARAMETER_FAILED,
|
||
&ValueType,
|
||
(PBYTE)&failed,
|
||
&ValueSize);
|
||
|
||
if (status != NO_ERROR) {
|
||
if (resource->State == ClusterResourceFailed) {
|
||
failed = TRUE;
|
||
}
|
||
}
|
||
|
||
if (resource->State == ClusterResourceFailed) {
|
||
if (!failed) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Recovered at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
resource->State = ClusterResourceOnline;
|
||
}
|
||
else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Is Dead at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
}
|
||
}
|
||
else if (resource->State == ClusterResourceOnline) {
|
||
if (failed) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Failed at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
resource->State = ClusterResourceFailed;
|
||
}
|
||
else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Is Alive at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
}
|
||
}
|
||
else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Resource state %1!u! during IsAlive poll at %2!2d!:%3!02d!:%4!02d!.%5!03d! !!!!\n",
|
||
resource->State,
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
}
|
||
|
||
returnValue = (resource->State == ClusterResourceOnline) ? TRUE : FALSE;
|
||
|
||
DummyReleaseResourceLock();
|
||
|
||
return(returnValue);
|
||
|
||
} // DumbIsAlive
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
DumbLooksAlive(
|
||
IN RESID ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
LooksAlive routine for Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
SYSTEMTIME Time;
|
||
PDUMMY_RESOURCE resource;
|
||
BOOLEAN returnValue = FALSE;
|
||
DWORD failed = FALSE;
|
||
DWORD status;
|
||
DWORD ValueType;
|
||
DWORD ValueSize;
|
||
|
||
|
||
DummyAcquireResourceLock();
|
||
|
||
resource = DummyFindResource(ResourceId);
|
||
|
||
if (resource == NULL) {
|
||
DUMMY_PRINT("DUMMY LooksAlive: resource %u not found.\n", PtrToUlong(ResourceId));
|
||
DummyReleaseResourceLock();
|
||
return(FALSE);
|
||
}
|
||
|
||
GetSystemTime(&Time);
|
||
|
||
ValueSize = sizeof(failed);
|
||
status = ClusterRegQueryValue(resource->ParametersKey,
|
||
DUMMY_PARAMETER_FAILED,
|
||
&ValueType,
|
||
(PBYTE)&failed,
|
||
&ValueSize);
|
||
|
||
if (status != NO_ERROR) {
|
||
if (resource->State == ClusterResourceFailed) {
|
||
failed = TRUE;
|
||
}
|
||
}
|
||
|
||
if (resource->State == ClusterResourceFailed) {
|
||
if (!failed) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Recovered at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
resource->State = ClusterResourceOnline;
|
||
}
|
||
else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Looks Dead at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
}
|
||
}
|
||
else if (resource->State == ClusterResourceOnline) {
|
||
if (failed) {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Failed at %1!2d!:%2!02d!:%3!02d!.%4!03d! !!!!\n",
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
resource->State = ClusterResourceFailed;
|
||
}
|
||
else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Looks Alive at %1!2d!:%2!02d!:%3!02d!.%4!03d!\n",
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
}
|
||
}
|
||
else {
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Resource state %1!u! during LooksAlive poll at %2!2d!:%3!02d!:%4!02d!.%5!03d! !!!!\n",
|
||
resource->State,
|
||
Time.wHour,
|
||
Time.wMinute,
|
||
Time.wSecond,
|
||
Time.wMilliseconds);
|
||
}
|
||
|
||
returnValue = (resource->State == ClusterResourceOnline) ? TRUE : FALSE;
|
||
|
||
DummyReleaseResourceLock();
|
||
|
||
return(returnValue);
|
||
|
||
} // DumbLooksAlive
|
||
|
||
|
||
|
||
VOID
|
||
WINAPI
|
||
DumbClose(
|
||
IN RESID ResourceId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Close routine for Dummy resource.
|
||
|
||
Arguments:
|
||
|
||
ResourceId - supplies resource id to be closed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDUMMY_RESOURCE resource;
|
||
PLIST_ENTRY entry;
|
||
|
||
|
||
DummyAcquireResourceLock();
|
||
|
||
resource = DummyFindResource(ResourceId);
|
||
|
||
if (resource == NULL) {
|
||
DUMMY_PRINT("DUMMY: Close, resource %u not found\n", PtrToUlong(ResourceId));
|
||
}
|
||
else {
|
||
if ( resource->TimerThreadWakeup != NULL ) {
|
||
CloseHandle( resource->TimerThreadWakeup );
|
||
}
|
||
if ( resource->SignalEvent != NULL ) {
|
||
CloseHandle( resource->SignalEvent );
|
||
}
|
||
ClusterRegCloseKey(resource->ParametersKey);
|
||
DummyFreeResource(resource);
|
||
}
|
||
|
||
DummyReleaseResourceLock();
|
||
|
||
(LogEvent)(
|
||
resource->ResourceHandle,
|
||
LOG_INFORMATION,
|
||
L"Closed.\n");
|
||
|
||
return;
|
||
|
||
} // DumbClose
|
||
|
||
//
|
||
// Define Function Table
|
||
//
|
||
|
||
CLRES_V1_FUNCTION_TABLE( DumbFunctionTable,
|
||
CLRES_VERSION_V1_00,
|
||
Dumb,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL );
|
||
|
||
|