|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
notify.c
Abstract:
Server side support for the notification APIs in the NT Cluster Service
Author:
John Vert (jvert) 26-Mar-1996
Revision History:
--*/ #include "apip.h"
//
// Classification of the item types based on FilterType
//
#define ITEM_TYPE_OBJECT_NAME (CLUSTER_CHANGE_GROUP_STATE | \
CLUSTER_CHANGE_GROUP_ADDED | \ CLUSTER_CHANGE_GROUP_DELETED | \ CLUSTER_CHANGE_GROUP_PROPERTY | \ CLUSTER_CHANGE_NODE_STATE | \ CLUSTER_CHANGE_NODE_DELETED | \ CLUSTER_CHANGE_NODE_ADDED | \ CLUSTER_CHANGE_NODE_PROPERTY | \ CLUSTER_CHANGE_RESOURCE_STATE | \ CLUSTER_CHANGE_RESOURCE_ADDED | \ CLUSTER_CHANGE_RESOURCE_DELETED | \ CLUSTER_CHANGE_RESOURCE_PROPERTY | \ CLUSTER_CHANGE_NETWORK_STATE | \ CLUSTER_CHANGE_NETWORK_ADDED | \ CLUSTER_CHANGE_NETWORK_DELETED | \ CLUSTER_CHANGE_NETWORK_PROPERTY | \ CLUSTER_CHANGE_NETINTERFACE_STATE | \ CLUSTER_CHANGE_NETINTERFACE_ADDED | \ CLUSTER_CHANGE_NETINTERFACE_DELETED | \ CLUSTER_CHANGE_NETINTERFACE_PROPERTY)
#define ITEM_TYPE_OBJECT_ID (CLUSTER_CHANGE_RESOURCE_TYPE_DELETED | \
CLUSTER_CHANGE_RESOURCE_TYPE_ADDED | \ CLUSTER_CHANGE_QUORUM_STATE | \ CLUSTER_CHANGE_CLUSTER_STATE)
#define ITEM_TYPE_REGISTRY (CLUSTER_CHANGE_REGISTRY_NAME | \
CLUSTER_CHANGE_REGISTRY_ATTRIBUTES | \ CLUSTER_CHANGE_REGISTRY_VALUE | \ CLUSTER_CHANGE_REGISTRY_SUBTREE)
#define ITEM_TYPE_NAME (ITEM_TYPE_REGISTRY | \
CLUSTER_CHANGE_HANDLE_CLOSE | \ CLUSTER_CHANGE_CLUSTER_PROPERTY)
//
// Define types local to this module
//
typedef struct _INTEREST { LIST_ENTRY ListEntry; LIST_ENTRY HandleList; PVOID Object; DWORD Filter; DWORD Key; } INTEREST, *PINTEREST;
typedef struct _ITEM { LIST_ENTRY ListEntry; DWORD FilterType; DWORD NotifyKey; union { LPVOID Object; WCHAR KeyName[0]; // For registry notifications
}; } ITEM, *PITEM;
//
// Function prototypes local to this module
//
DWORD ApipAddNotifyInterest( IN PNOTIFY_PORT Notify, IN PAPI_HANDLE ObjectHandle, IN DWORD Filter, IN DWORD NotifyKey, IN DWORD NotifyFilter );
//
// Define static data local to this module
//
LIST_ENTRY NotifyListHead; CRITICAL_SECTION NotifyListLock;
VOID ApiReportRegistryNotify( IN DWORD_PTR Context1, IN DWORD_PTR Context2, IN DWORD CompletionFilter, IN LPCWSTR KeyName ) /*++
Routine Description:
Interface to be called by DM when a registry change triggers a notification.
Arguments:
Context1 - Supplies the first DWORD of Context that was passed to DmNotifyChangeKey. This is the NOTIFY_PORT to be used.
Context2 - Supplies the second DWORD of Context that was passed to DmNotifyChangeKey. This is the NotifyKey to be used.
CompletionFilter - Supplies the type of change that occurred.
KeyName - Supplies the relative name of the key that was changed.
Return Value:
None.
--*/
{ PLIST_ENTRY InterestEntry; PLIST_ENTRY PortEntry; PINTEREST Interest; PITEM Item; PNOTIFY_PORT NotifyPort; DWORD NameLength;
ClRtlLogPrint(LOG_NOISE, "[API] Notification on port %1!8lx!, key %2!8lx! of type %3!d!. KeyName %4!ws!\n", (DWORD)Context1, (DWORD)Context2, CompletionFilter, KeyName);
NameLength = (lstrlenW(KeyName)+1)*sizeof(WCHAR); NotifyPort = (PNOTIFY_PORT)Context1;
//
// Post notification item for this interest.
//
Item = LocalAlloc(LMEM_FIXED, sizeof(ITEM)+NameLength); if (Item != NULL) { Item->FilterType = CompletionFilter; Item->NotifyKey = (DWORD)Context2; CopyMemory(Item->KeyName, KeyName, NameLength);
ClRtlInsertTailQueue(&NotifyPort->Queue, &Item->ListEntry); } else { ClRtlLogPrint(LOG_UNUSUAL, "[API] ApiReportRegistryNotify: Memory alloc failure for registry item, status %1!u!\n", GetLastError()); } }
VOID ApipRundownNotify( IN PAPI_HANDLE Handle ) /*++
Routine Description:
Runs down any notification interests on a particular cluster object. The INTEREST structures will be yanked from their notification lists and freed.
Arguments:
Handle - Supplies the API handle for the object.
Return Value:
None.
--*/
{ PLIST_ENTRY ListEntry; PINTEREST Interest;
if (IsListEmpty(&Handle->NotifyList)) { return; }
EnterCriticalSection(&NotifyListLock); while (!IsListEmpty(&Handle->NotifyList)) { ListEntry = RemoveHeadList(&Handle->NotifyList); Interest = CONTAINING_RECORD(ListEntry, INTEREST, HandleList); CL_ASSERT(Interest->Object == Handle->Cluster);
RemoveEntryList(&Interest->ListEntry); LocalFree(Interest); } LeaveCriticalSection(&NotifyListLock); }
DWORD WINAPI ApipEventHandler( IN CLUSTER_EVENT Event, IN PVOID Context )
/*++
Routine Description:
Processes cluster events and dispatches the notifications to the appropriate notify queues.
Arguments:
Event - Supplies the type of cluster event.
Context - Supplies the event-specific context
Return Value:
ERROR_SUCCESS
--*/
{ DWORD Filter; DWORD NameLength = 0; PLIST_ENTRY PortEntry; PNOTIFY_PORT NotifyPort; PLIST_ENTRY InterestEntry; PINTEREST Interest; PITEM Item;
//
// Translate EP event types into clusapi notification filters
//
switch (Event) { case CLUSTER_EVENT_API_NODE_UP: case CLUSTER_EVENT_NODE_DOWN: case CLUSTER_EVENT_NODE_JOIN: case CLUSTER_EVENT_NODE_CHANGE: Filter = CLUSTER_CHANGE_NODE_STATE; break;
case CLUSTER_EVENT_NODE_ADDED: Filter = CLUSTER_CHANGE_NODE_ADDED; break;
case CLUSTER_EVENT_NODE_PROPERTY_CHANGE: Filter = CLUSTER_CHANGE_NODE_PROPERTY; break;
case CLUSTER_EVENT_NODE_DELETED: Filter = CLUSTER_CHANGE_NODE_DELETED; break;
case CLUSTER_EVENT_RESOURCE_ONLINE: case CLUSTER_EVENT_RESOURCE_OFFLINE: case CLUSTER_EVENT_RESOURCE_FAILED: case CLUSTER_EVENT_RESOURCE_CHANGE: Filter = CLUSTER_CHANGE_RESOURCE_STATE; break;
case CLUSTER_EVENT_RESOURCE_PROPERTY_CHANGE: Filter = CLUSTER_CHANGE_RESOURCE_PROPERTY; break;
case CLUSTER_EVENT_RESOURCE_ADDED: Filter = CLUSTER_CHANGE_RESOURCE_ADDED; break;
case CLUSTER_EVENT_RESOURCE_DELETED: Filter = CLUSTER_CHANGE_RESOURCE_DELETED; break;
case CLUSTER_EVENT_GROUP_ONLINE: case CLUSTER_EVENT_GROUP_OFFLINE: case CLUSTER_EVENT_GROUP_FAILED: case CLUSTER_EVENT_GROUP_CHANGE: Filter = CLUSTER_CHANGE_GROUP_STATE; break;
case CLUSTER_EVENT_GROUP_PROPERTY_CHANGE: Filter = CLUSTER_CHANGE_GROUP_PROPERTY; break;
case CLUSTER_EVENT_GROUP_ADDED: Filter = CLUSTER_CHANGE_GROUP_ADDED; break;
case CLUSTER_EVENT_GROUP_DELETED: Filter = CLUSTER_CHANGE_GROUP_DELETED; break;
case CLUSTER_EVENT_NETWORK_UNAVAILABLE: case CLUSTER_EVENT_NETWORK_DOWN: case CLUSTER_EVENT_NETWORK_PARTITIONED: case CLUSTER_EVENT_NETWORK_UP: Filter = CLUSTER_CHANGE_NETWORK_STATE; break;
case CLUSTER_EVENT_NETWORK_PROPERTY_CHANGE: Filter = CLUSTER_CHANGE_NETWORK_PROPERTY; break;
case CLUSTER_EVENT_NETWORK_ADDED: Filter = CLUSTER_CHANGE_NETWORK_ADDED; break;
case CLUSTER_EVENT_NETWORK_DELETED: Filter = CLUSTER_CHANGE_NETWORK_DELETED; break;
case CLUSTER_EVENT_NETINTERFACE_UNAVAILABLE: case CLUSTER_EVENT_NETINTERFACE_FAILED: case CLUSTER_EVENT_NETINTERFACE_UNREACHABLE: case CLUSTER_EVENT_NETINTERFACE_UP: Filter = CLUSTER_CHANGE_NETINTERFACE_STATE; break;
case CLUSTER_EVENT_NETINTERFACE_PROPERTY_CHANGE: Filter = CLUSTER_CHANGE_NETINTERFACE_PROPERTY; break;
case CLUSTER_EVENT_NETINTERFACE_ADDED: Filter = CLUSTER_CHANGE_NETINTERFACE_ADDED; break;
case CLUSTER_EVENT_NETINTERFACE_DELETED: Filter = CLUSTER_CHANGE_NETINTERFACE_DELETED; break;
case CLUSTER_EVENT_RESTYPE_ADDED: Filter = CLUSTER_CHANGE_RESOURCE_TYPE_ADDED; break;
case CLUSTER_EVENT_RESTYPE_DELETED: Filter = CLUSTER_CHANGE_RESOURCE_TYPE_DELETED; break;
case CLUSTER_EVENT_PROPERTY_CHANGE: Filter = CLUSTER_CHANGE_CLUSTER_PROPERTY; break;
default: //
// No notification for any of the other events yet.
//
return(ERROR_SUCCESS);
}
//
// Run through the outstanding notify sessions and post notify items
// for any matches.
//
EnterCriticalSection(&NotifyListLock); PortEntry = NotifyListHead.Flink; while (PortEntry != &NotifyListHead) { NotifyPort = CONTAINING_RECORD(PortEntry, NOTIFY_PORT, ListEntry); if (NotifyPort->Filter & Filter) {
//
// There are notification interests for this notify type, run
// through the list of notification interests.
//
InterestEntry = NotifyPort->InterestList.Flink; while (InterestEntry != &NotifyPort->InterestList) { Interest = CONTAINING_RECORD(InterestEntry, INTEREST, ListEntry);
//
// Report the notification if the Interest's cluster object is NULL (which
// means that this is a general cluster interest) or if the interest's specific
// object matches the object reporting the notify.
//
if ((Interest->Filter & Filter) && ((Interest->Object == NULL) || (Interest->Object == Context))) { //
// Post notification item for this interest.
//
if (Filter & ITEM_TYPE_NAME) { NameLength = (lstrlenW(Context)+1)*sizeof(WCHAR); Item = LocalAlloc(LMEM_FIXED, sizeof(ITEM)+NameLength); } else { Item = LocalAlloc(LMEM_FIXED, sizeof(ITEM)); } if (Item != NULL) { Item->FilterType = Filter; Item->NotifyKey = Interest->Key;
if (!(Filter & ITEM_TYPE_NAME)) { //
// Reference the object again to ensure that the name does
// not disappear out from under us before we are done with it.
//
Item->Object = Context; OmReferenceObject(Context); } else { CopyMemory(Item->KeyName, Context, NameLength); } ClRtlInsertTailQueue(&NotifyPort->Queue, &Item->ListEntry); } else { ClRtlLogPrint(LOG_UNUSUAL, "[API] ApipEventHandler: Memory alloc failure notification item, status %1!u!\n", GetLastError()); } } InterestEntry = InterestEntry->Flink; } } PortEntry = PortEntry->Flink; }
LeaveCriticalSection(&NotifyListLock);
return(ERROR_SUCCESS); }
HNOTIFY_RPC s_ApiCreateNotify( IN HCLUSTER_RPC hCluster, OUT error_status_t *rpc_error )
/*++
Routine Description:
Creates the server side of a notification port.
Arguments:
IDL_handle - Supplies cluster handle.
dwFilter - Supplies the cluster events of interest.
dwNotifyKey - Supplies a key to be returned on any notifications
rpc_error - Returns any RPC-specific error
Return Value:
An RPC context handle for a notification port.
NULL on failure.
--*/
{ DWORD Status; PNOTIFY_PORT Port = NULL; PAPI_HANDLE Handle = NULL; //assume success
*rpc_error = ERROR_SUCCESS;
if (ApiState != ApiStateOnline) { *rpc_error = ERROR_SHARING_PAUSED; goto FnExit; }
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE)); if (Handle == NULL) { *rpc_error = ERROR_NOT_ENOUGH_MEMORY; goto FnExit; } Port = LocalAlloc(LMEM_FIXED, sizeof(NOTIFY_PORT)); if (Port == NULL) { *rpc_error = ERROR_NOT_ENOUGH_MEMORY; goto FnExit; } InitializeListHead(&Port->InterestList); InitializeListHead(&Port->RegistryList); InitializeCriticalSection(&Port->Lock); Status = ClRtlInitializeQueue(&Port->Queue); if (Status != ERROR_SUCCESS) { *rpc_error = Status; goto FnExit; }
EnterCriticalSection(&NotifyListLock); InsertTailList(&NotifyListHead, &Port->ListEntry); LeaveCriticalSection(&NotifyListLock);
Handle->Type = API_NOTIFY_HANDLE; Handle->Notify = Port; Handle->Flags = 0; InitializeListHead(&Handle->NotifyList); FnExit: if ((*rpc_error) != ERROR_SUCCESS) { if (Port) LocalFree(Port); if (Handle) LocalFree(Handle); return (NULL); } else { return(Handle); } }
error_status_t s_ApiAddNotifyCluster( IN HNOTIFY_RPC hNotify, IN HCLUSTER_RPC hCluster, IN DWORD dwFilter, IN DWORD dwNotifyKey )
/*++
Routine Description:
Adds another set of notification events to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hCluster - Supplies the cluster to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PAPI_HANDLE Handle;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify);
Handle = (PAPI_HANDLE)hCluster; if ((Handle == NULL ) || (Handle->Type != API_CLUSTER_HANDLE)) { return(ERROR_INVALID_HANDLE); } Status = ApipAddNotifyInterest(Port, Handle, dwFilter, dwNotifyKey, 0); if (dwFilter & ITEM_TYPE_REGISTRY) { //
// Add a registry notification for the entire cluster.
//
DmNotifyChangeKey(DmClusterParametersKey, dwFilter & ITEM_TYPE_REGISTRY, (dwFilter & CLUSTER_CHANGE_REGISTRY_SUBTREE) ? TRUE : FALSE, &Port->RegistryList, ApiReportRegistryNotify, (DWORD_PTR)Port, dwNotifyKey); } return(Status);
}
error_status_t s_ApiAddNotifyNode( IN HNOTIFY_RPC hNotify, IN HNODE_RPC hNode, IN DWORD dwFilter, IN DWORD dwNotifyKey, OUT DWORD *dwStateSequence )
/*++
Routine Description:
Adds a node-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hNode - Supplies the node to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this node
dwStateSequence - Returns the current state sequence for the specified object
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PNM_NODE Node;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_NODE(Node, hNode); Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hNode, dwFilter, dwNotifyKey, 0); if (Status == ERROR_SUCCESS) { *dwStateSequence = NmGetNodeState(Node); }
return(Status); }
error_status_t s_ApiAddNotifyGroup( IN HNOTIFY_RPC hNotify, IN HGROUP_RPC hGroup, IN DWORD dwFilter, IN DWORD dwNotifyKey, OUT DWORD *dwStateSequence )
/*++
Routine Description:
Adds a group-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hGroup - Supplies the group to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this group
dwStateSequence - Returns the current state sequence for the specified object
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PFM_GROUP Group;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_GROUP_EXISTS(Group, hGroup); Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hGroup, dwFilter, dwNotifyKey, 0); if (Status == ERROR_SUCCESS) { *dwStateSequence = Group->StateSequence; } return(Status);
}
error_status_t s_ApiAddNotifyNetwork( IN HNOTIFY_RPC hNotify, IN HNETWORK_RPC hNetwork, IN DWORD dwFilter, IN DWORD dwNotifyKey, OUT DWORD *dwStateSequence )
/*++
Routine Description:
Adds a network-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hNetwork - Supplies the network to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this network
dwStateSequence - Returns the current state sequence for the specified object
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PNM_NETWORK Network;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_NETWORK_EXISTS(Network, hNetwork);
Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hNetwork, dwFilter, dwNotifyKey, 0);
if (Status == ERROR_SUCCESS) { *dwStateSequence = NmGetNetworkState( Network ); }
return(Status); }
error_status_t s_ApiAddNotifyNetInterface( IN HNOTIFY_RPC hNotify, IN HNETINTERFACE_RPC hNetInterface, IN DWORD dwFilter, IN DWORD dwNotifyKey, OUT DWORD *dwStateSequence )
/*++
Routine Description:
Adds a network interface-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hNetInterface - Supplies the network interface to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this network
dwStateSequence - Returns the current state sequence for the specified object
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PNM_INTERFACE NetInterface;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_NETINTERFACE_EXISTS(NetInterface, hNetInterface);
Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hNetInterface, dwFilter, dwNotifyKey, 0);
if (Status == ERROR_SUCCESS) { *dwStateSequence = NmGetInterfaceState( NetInterface ); }
return(Status); }
error_status_t s_ApiAddNotifyResource( IN HNOTIFY_RPC hNotify, IN HRES_RPC hResource, IN DWORD dwFilter, IN DWORD dwNotifyKey, OUT DWORD *dwStateSequence )
/*++
Routine Description:
Adds a resource-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hResource - Supplies the resource to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this group
dwStateSequence - Returns the current state sequence for the specified object
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PFM_RESOURCE Resource;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_RESOURCE_EXISTS(Resource, hResource); Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hResource, dwFilter, dwNotifyKey, 0); if (Status == ERROR_SUCCESS) { *dwStateSequence = Resource->StateSequence; } return(Status);
}
error_status_t s_ApiReAddNotifyNode( IN HNOTIFY_RPC hNotify, IN HNODE_RPC hNode, IN DWORD dwFilter, IN DWORD dwNotifyKey, IN DWORD dwStateSequence )
/*++
Routine Description:
Adds a node-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hNode - Supplies the node to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this node
dwStateSequence - Supplies the previous state sequence. If this does not match the current sequence, an immediate notification will be issued.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PNM_NODE Node; DWORD NotifyFilter;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_NODE(Node, hNode);
ClRtlLogPrint(LOG_NOISE, "[API] s_ApiReAddNotifyNode for %1!ws! (%2!lx!) oldstate %3!d! newstate %4!d!\n", OmObjectId(Node), dwFilter, dwStateSequence, NmGetNodeState(Node)); if (NmGetNodeState(Node) != (CLUSTER_NODE_STATE)dwStateSequence) { NotifyFilter = CLUSTER_CHANGE_NODE_STATE & dwFilter; } else { NotifyFilter = 0; } Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hNode, dwFilter, dwNotifyKey, NotifyFilter); return(Status); }
error_status_t s_ApiReAddNotifyGroup( IN HNOTIFY_RPC hNotify, IN HGROUP_RPC hGroup, IN DWORD dwFilter, IN DWORD dwNotifyKey, IN DWORD dwStateSequence )
/*++
Routine Description:
Adds a group-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hGroup - Supplies the group to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this group
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PFM_GROUP Group; DWORD NotifyFilter;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_GROUP_EXISTS(Group, hGroup); ClRtlLogPrint(LOG_NOISE, "[API] s_ApiReAddNotifyGroup for %1!ws! (%2!lx!) oldstate %3!d! newstate %4!d!\n", OmObjectName(Group), dwFilter, dwStateSequence, Group->StateSequence); if (Group->StateSequence != dwStateSequence) { NotifyFilter = CLUSTER_CHANGE_GROUP_STATE & dwFilter; } else { NotifyFilter = 0; } Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hGroup, dwFilter, dwNotifyKey, NotifyFilter); return(Status);
}
error_status_t s_ApiReAddNotifyNetwork( IN HNOTIFY_RPC hNotify, IN HNETWORK_RPC hNetwork, IN DWORD dwFilter, IN DWORD dwNotifyKey, IN DWORD dwStateSequence )
/*++
Routine Description:
Adds a network-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hNetwork - Supplies the network to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this network
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PNM_NETWORK Network; DWORD NotifyFilter = 0; CLUSTER_NETWORK_STATE CurrentState;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_NETWORK_EXISTS(Network, hNetwork);
CurrentState = NmGetNetworkState( Network );
ClRtlLogPrint(LOG_NOISE, "[API] s_ApiReAddNotifyNetwork for %1!ws! (%2!lx!) oldstate %3!d! newstate %4!d!\n", OmObjectName(Network), dwFilter, dwStateSequence, CurrentState);
if ((DWORD)CurrentState != dwStateSequence) { NotifyFilter = CLUSTER_CHANGE_NETWORK_STATE & dwFilter; } else { NotifyFilter = 0; }
Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hNetwork, dwFilter, dwNotifyKey, NotifyFilter); return(Status); }
error_status_t s_ApiReAddNotifyNetInterface( IN HNOTIFY_RPC hNotify, IN HNETINTERFACE_RPC hNetInterface, IN DWORD dwFilter, IN DWORD dwNotifyKey, IN DWORD dwStateSequence )
/*++
Routine Description:
Adds a network interface-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hNetInterface - Supplies the network interface to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this network
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PNM_INTERFACE NetInterface; DWORD NotifyFilter = 0; CLUSTER_NETINTERFACE_STATE CurrentState;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_NETINTERFACE_EXISTS(NetInterface, hNetInterface);
CurrentState = NmGetInterfaceState( NetInterface );
ClRtlLogPrint(LOG_NOISE, "[API] s_ApiReAddNotifyNetInterface for %1!ws! (%2!lx!) oldstate %3!d! newstate %4!d!\n", OmObjectName(NetInterface), dwFilter, dwStateSequence, CurrentState);
if ((DWORD)CurrentState != dwStateSequence) { NotifyFilter = CLUSTER_CHANGE_NETINTERFACE_STATE & dwFilter; } else { NotifyFilter = 0; }
Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hNetInterface, dwFilter, dwNotifyKey, NotifyFilter); return(Status); }
error_status_t s_ApiReAddNotifyResource( IN HNOTIFY_RPC hNotify, IN HRES_RPC hResource, IN DWORD dwFilter, IN DWORD dwNotifyKey, IN DWORD dwStateSequence )
/*++
Routine Description:
Adds a resource-specific notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hResource - Supplies the resource to be added
dwFilter - Supplies the set of notification events to be added.
dwNotifyKey - Supplies the notification key to be returned on any notification events for this group
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; PFM_RESOURCE Resource; DWORD NotifyFilter;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_RESOURCE_EXISTS(Resource, hResource); ClRtlLogPrint(LOG_NOISE, "[API] s_ApiReAddNotifyGroup for %1!ws! (%2!lx!) oldstate %3!d! newstate %4!d!\n", OmObjectName(Resource), dwFilter, dwStateSequence, Resource->StateSequence); if (Resource->StateSequence != dwStateSequence) { NotifyFilter = CLUSTER_CHANGE_RESOURCE_STATE & dwFilter; } else { NotifyFilter = 0; } Status = ApipAddNotifyInterest(Port, (PAPI_HANDLE)hResource, dwFilter, dwNotifyKey, NotifyFilter); return(Status);
}
error_status_t s_ApiAddNotifyKey( IN HNOTIFY_RPC hNotify, IN HKEY_RPC hKey, IN DWORD dwNotifyKey, IN DWORD Filter, IN BOOL WatchSubTree )
/*++
Routine Description:
Adds a registry notification event to an existing cluster notification port
Arguments:
hNotify - Supplies the notification port
hKey - Supplies the key to be added
dwNotifyKey - Supplies the notification key to be returned on any notification events for this group
WatchSubTree - Supplies whether the notification applies to just the specified key or to the keys entire subtree
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ DWORD Status; PNOTIFY_PORT Port; HDMKEY Key;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify); VALIDATE_KEY(Key, hKey); Status = DmNotifyChangeKey(Key, Filter, WatchSubTree, &Port->RegistryList, ApiReportRegistryNotify, (DWORD_PTR)Port, dwNotifyKey); return(Status);
}
void HNOTIFY_RPC_rundown( IN HNOTIFY_RPC hNotify )
/*++
Routine Description:
RPC rundown routine for notification ports.
Arguments:
hNotify - Supplies the notification port to be rundown
Return Value:
None.
--*/
{ s_ApiCloseNotify(&hNotify); }
error_status_t s_ApiUnblockGetNotifyCall( IN HNOTIFY_RPC hNotify )
/*++
Routine Description:
Unblocks the s_ApiGetNotify call.
Arguments:
hNotify - Supplies the notification port to be closed.
Return Value:
None.
--*/
{ PNOTIFY_PORT pPort;
//
// Chittur Subbaraman (chitturs) - 4/19/2000
//
// In order to prevent the client from calling ApiGetNotify
// during or after the context handle is destroyed, we split
// the notification port close into two steps. In the first step,
// we merely unblock the ApiGetNotify call without freeing the
// context handle. That is the purpose of this function.
// In the next step, we free the context handle. The client can now
// perform the notification port close in 2 steps, properly
// synchronizing the freeing of the context handle with the call to
// ApiGetNotify. This avoids an AV in RPC code caused by the
// ApiGetNotify call being made during or soon after the context
// handle is freed.
//
API_ASSERT_INIT();
VALIDATE_NOTIFY( pPort, hNotify );
DELETE_HANDLE( hNotify );
ApipUnblockGetNotifyCall( pPort ); return( ERROR_SUCCESS ); }
DWORD s_ApiCloseNotify( IN OUT HNOTIFY_RPC *phNotify )
/*++
Routine Description:
Closes a cluster notification port and unblocks the s_ApiGetNotify thread, if necessary.
Arguments:
phNotify - Supplies the pointer to the notification port to be closed. Returns NULL
Return Value:
ERROR_SUCCESS.
--*/
{ PNOTIFY_PORT pPort;
API_ASSERT_INIT();
if ( *phNotify == NULL ) return ( ERROR_INVALID_HANDLE ); if ( !IS_HANDLE_DELETED( *phNotify ) ) { //
// If the handle is not already deleted, this means this call is
// coming from a client that does not make the ApiUnblockGetNotify
// call. In such a case, do all the work of unblocking the
// ApiGetNotify thread and freeing the context handle.
//
VALIDATE_NOTIFY( pPort, *phNotify );
ApipUnblockGetNotifyCall( pPort ); } else { pPort = ((PAPI_HANDLE)(*phNotify))->Notify; }
DeleteCriticalSection(&pPort->Lock); LocalFree( pPort );
LocalFree( *phNotify );
*phNotify = NULL;
return( ERROR_SUCCESS ); }
error_status_t s_ApiGetNotify( IN HNOTIFY_RPC hNotify, IN DWORD Timeout, OUT DWORD *dwNotifyKey, OUT DWORD *dwFilter, OUT DWORD *dwStateSequence, OUT LPWSTR *Name )
/*++
Routine Description:
Retrieves a cluster notification event from a notify port
Arguments:
hNotify - Supplies the notification port
Timeout - Supplies the time to wait in ms.
dwNotifyKey - Returns the notification key of the event
dwFilter - Returns the notification type of the event
dwStateSequence - Returns the current state sequence of the object.
Name - Returns the name of the event. This buffer must be freed on the client side with MIDL_user_free
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise
--*/ { PNOTIFY_PORT Port; PLIST_ENTRY ListEntry; PITEM Item; DWORD NameLen; LPCWSTR ObjectName; LPWSTR NullName = L""; DWORD StateSequence = 0;
API_ASSERT_INIT();
VALIDATE_NOTIFY(Port, hNotify);
//
// Make sure that Port is valid.
//
if ( Port == NULL ) { return(ERROR_INVALID_HANDLE); }
//
// Wait for something to arrive in the queue.
// Take the lock to make sure the notify port doesn't
// disappear out from under us.
//
EnterCriticalSection(&Port->Lock); if (IS_HANDLE_DELETED(hNotify)) { ListEntry = NULL; } else { ListEntry = ClRtlRemoveHeadQueue(&Port->Queue); } LeaveCriticalSection(&Port->Lock); if (ListEntry == NULL) { return(ERROR_NO_MORE_ITEMS); }
Item = CONTAINING_RECORD(ListEntry, ITEM, ListEntry); if (Item->FilterType & ITEM_TYPE_OBJECT_NAME) { ObjectName = OmObjectName( Item->Object ); } else if (Item->FilterType & ITEM_TYPE_OBJECT_ID) { ObjectName = OmObjectId( Item->Object ); } else if (Item->FilterType & ITEM_TYPE_NAME) { ObjectName = Item->KeyName; } else { ClRtlLogPrint(LOG_CRITICAL, "[API] s_ApiGetNotify: Unrecognized filter type,0x%1!08lx!\r\n", Item->FilterType); LocalFree(Item); #if DBG
CL_ASSERT(FALSE) #endif
return(ERROR_INVALID_PARAMETER); }
//
// Get the state sequence for those notifications that have
// state sequences.
//
if (Item->FilterType & CLUSTER_CHANGE_GROUP_STATE) { StateSequence = ((PFM_GROUP)(Item->Object))->StateSequence; } else if (Item->FilterType & CLUSTER_CHANGE_RESOURCE_STATE) { StateSequence = ((PFM_RESOURCE)(Item->Object))->StateSequence; } else if (Item->FilterType & CLUSTER_CHANGE_NODE_STATE) { StateSequence = NmGetNodeState((PNM_NODE)(Item->Object)); } if ( ObjectName == NULL ) { ObjectName = NullName; } NameLen = (lstrlenW(ObjectName)+1)*sizeof(WCHAR); *Name = MIDL_user_allocate(NameLen); if (*Name != NULL) { CopyMemory(*Name, ObjectName, NameLen); }
*dwFilter = Item->FilterType; *dwNotifyKey = Item->NotifyKey; *dwStateSequence = StateSequence; if (Item->FilterType & (ITEM_TYPE_OBJECT_NAME | ITEM_TYPE_OBJECT_ID)) { OmDereferenceObject(Item->Object); } LocalFree(Item);
if (*Name == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); } else { return(ERROR_SUCCESS); }
}
DWORD ApipAddNotifyInterest( IN PNOTIFY_PORT Notify, IN PAPI_HANDLE ObjectHandle, IN DWORD Filter, IN DWORD NotifyKey, IN DWORD NotifyFilter )
/*++
Routine Description:
Registers a notification interest on an existing cluster notification port
Arguments:
Notify - Supplies the notification port
ObjectHandle - Supplies a pointer to the object's handle.
Filter - Supplies the set of notification events to be added.
NotifyKey - Supplies the notification key to be returned on any notification events
NotifyNow - Supplies whether a notification should be immediately posted (TRUE).
NotifyFilter - If not zero, indicates that a notification should be immediately posted with the specified filter.
Return Value:
ERROR_SUCCESS if successful
Win32 error code otherwise.
--*/
{ PINTEREST Interest; PITEM Item;
if (Filter == 0) { return(ERROR_SUCCESS); }
Interest = LocalAlloc(LMEM_FIXED, sizeof(INTEREST)); if (Interest == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); } Interest->Object = ObjectHandle->Cluster; Interest->Filter = Filter; Interest->Key = NotifyKey;
EnterCriticalSection(&NotifyListLock); InsertHeadList(&Notify->InterestList, &Interest->ListEntry); InsertHeadList(&ObjectHandle->NotifyList, &Interest->HandleList); Notify->Filter |= Filter; if (NotifyFilter) { //
// Post an immediate notification on this object.
//
//SS: this assert is wrong because you can have a filter
//that is a combination of say CLUSTER_CHANGE_GROUP_STATE+CLUSTER_CHANGE_HANDLE_CLOSE
//and that is perfectly valid
//CL_ASSERT(!(Filter & ITEM_TYPE_NAME));
Item = LocalAlloc(LMEM_FIXED, sizeof(ITEM)); if (Item != NULL) { Item->FilterType = NotifyFilter; Item->NotifyKey = Interest->Key; Item->Object = ObjectHandle->Node; OmReferenceObject(ObjectHandle->Node); ClRtlInsertTailQueue(&Notify->Queue, &Item->ListEntry); } else { ClRtlLogPrint(LOG_UNUSUAL, "[API] ApipAddNotifyInterest: Memory alloc failure for immediate notification item, status %1!u!\n", GetLastError()); }
} LeaveCriticalSection(&NotifyListLock);
return(ERROR_SUCCESS);
}
DWORD ApipUnblockGetNotifyCall( PNOTIFY_PORT pPort )
/*++
Routine Description:
Unblocks the s_ApiGetNotify call.
Arguments:
pPort - Port associated with the session.
Return Value:
ERROR_SUCCESS.
--*/
{ PINTEREST Interest; PLIST_ENTRY ListEntry; LIST_ENTRY RundownList; PITEM Item;
EnterCriticalSection(&NotifyListLock); RemoveEntryList(&pPort->ListEntry);
//
// rundown registry notifications
//
DmRundownList(&pPort->RegistryList);
//
// Abort any waiters on the queue and rundown any
// items that may have already been posted to the
// queue.
//
ClRtlRundownQueue(&pPort->Queue, &RundownList); while (!IsListEmpty(&RundownList)) { ListEntry = RemoveHeadList(&RundownList); Item = CONTAINING_RECORD(ListEntry, ITEM, ListEntry); if (!(Item->FilterType & ITEM_TYPE_NAME)) { OmDereferenceObject(Item->Object); } LocalFree(Item); }
EnterCriticalSection(&pPort->Lock); ClRtlDeleteQueue(&pPort->Queue); LeaveCriticalSection(&pPort->Lock);
//
// rundown list of notify interests and delete each one.
//
while (!IsListEmpty(&pPort->InterestList)) { ListEntry = RemoveHeadList(&pPort->InterestList); Interest = CONTAINING_RECORD(ListEntry, INTEREST, ListEntry); RemoveEntryList(&Interest->HandleList); LocalFree(Interest); }
LeaveCriticalSection(&NotifyListLock);
return(ERROR_SUCCESS); }
|