You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1719 lines
43 KiB
1719 lines
43 KiB
/*++
|
|
|
|
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);
|
|
}
|