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

471 lines
16 KiB

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
clusapip.h
Abstract:
Private header file for cluster api
Author:
John Vert (jvert) 15-Jan-1996
Revision History:
--*/
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "windows.h"
#include "cluster.h"
#include "api_rpc.h"
//
// Define CLUSTER structure. There is one cluster structure created
// for each OpenCluster API call. An HCLUSTER is really a pointer to
// this structure.
//
#define CLUS_SIGNATURE 'SULC'
typedef struct _RECONNECT_CANDIDATE {
BOOL IsUp;
BOOL IsCurrent;
LPWSTR Name;
} RECONNECT_CANDIDATE, *PRECONNECT_CANDIDATE;
typedef struct _CLUSTER {
DWORD Signature;
DWORD ReferenceCount;
DWORD FreedRpcHandleListLen;
LPWSTR ClusterName;
LPWSTR NodeName; // node name we are connected to
DWORD Flags;
RPC_BINDING_HANDLE RpcBinding;
HCLUSTER_RPC hCluster;
LIST_ENTRY KeyList; // open cluster registry keys
LIST_ENTRY ResourceList; // open resource handles
LIST_ENTRY GroupList; // open group handles
LIST_ENTRY NodeList; // open node handles
LIST_ENTRY NetworkList; // open network handles
LIST_ENTRY NetInterfaceList; // open net interface handles
LIST_ENTRY NotifyList; // outstanding notification event filters
LIST_ENTRY SessionList; // open notification sessions.
unsigned long AuthnLevel; // Level of authentication to be performed on remote procedure calls
HANDLE NotifyThread;
CRITICAL_SECTION Lock;
DWORD Generation;
DWORD ReconnectCount;
PRECONNECT_CANDIDATE Reconnect;
LIST_ENTRY FreedBindingList;
LIST_ENTRY FreedContextList;
} CLUSTER, *PCLUSTER;
// [GorN] Jan/13/1999
// This is a temporary fix for the race between the users
// of binding and context handles and reconnectThread
//
// The code assumes that RPC_BINDING_HANDLE == ContextHandle == void*
typedef struct _CTX_HANDLE {
LIST_ENTRY HandleList;
void * RpcHandle; // assumption RPC_BINDING_HANDLE == ContextHandle == void*
ULONGLONG TimeStamp;
} CTX_HANDLE, *PCTX_HANDLE;
RPC_STATUS
FreeRpcBindingOrContext(
IN PCLUSTER Cluster,
IN void ** RpcHandle,
IN BOOL IsBinding);
#define MyRpcBindingFree(Cluster, Binding) \
FreeRpcBindingOrContext(Cluster, Binding, TRUE)
#define MyRpcSmDestroyClientContext(Cluster, Context) \
FreeRpcBindingOrContext(Cluster, Context, FALSE)
VOID
FreeObsoleteRpcHandlesEx(
IN PCLUSTER Cluster,
IN BOOL Cleanup,
IN BOOL IsBinding
);
#define FreeObsoleteRpcHandles(Cluster, Cleanup) { \
FreeObsoleteRpcHandlesEx(Cluster, Cleanup, TRUE); \
FreeObsoleteRpcHandlesEx(Cluster, Cleanup, FALSE); \
}
//
// Define CLUSTER.Flags
//
#define CLUS_DELETED 1
#define CLUS_DEAD 2
#define CLUS_LOCALCONNECT 4
//
// Cluster helper macros
//
#define GET_CLUSTER(hCluster) (PCLUSTER)((((PCLUSTER)(hCluster))->Flags & CLUS_DELETED) ? NULL : hCluster)
#define IS_CLUSTER_FREE(c) ((c->Flags & CLUS_DELETED) && \
(IsListEmpty(&(c)->KeyList)) && \
(IsListEmpty(&(c)->GroupList)) && \
(IsListEmpty(&(c)->NodeList)) && \
(IsListEmpty(&(c)->ResourceList)) && \
(IsListEmpty(&(c)->NetworkList)) && \
(IsListEmpty(&(c)->NetInterfaceList)))
//
// Cluster structure cleanup routine.
//
VOID
CleanupCluster(
IN PCLUSTER Cluster
);
VOID
RundownNotifyEvents(
IN PLIST_ENTRY ListHead,
IN LPCWSTR Name
);
//
// Define CRESOURCE structure. There is one resource structure created
// for each OpenResource/CreateResource API call. An HRESOURCE is really
// a pointer to this structure. These are chained onto the CLUSTER that
// they were opened relative to.
//
typedef struct _CRESOURCE {
LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.ResourceList
LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
PCLUSTER Cluster; // Parent cluster
LPWSTR Name;
HRES_RPC hResource; // RPC handle
} CRESOURCE, *PCRESOURCE;
//
// Define CGROUP structure. There is one group structure created
// for each OpenGroup/CreateGroup API call. An HGROUP is really
// a pointer to this structure. These are chained onto the CLUSTER that
// they were opened relative to.
//
typedef struct _CGROUP {
LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.Group
LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
PCLUSTER Cluster; // Parent cluster
LPWSTR Name;
HRES_RPC hGroup; // RPC handle
} CGROUP, *PCGROUP;
//
// Define CNODE structure. There is one node structure created
// for each OpenClusterNode call. An HNODE is really a pointer
// to this structure. These are chained onto the CLUSTER that they
// were opened relative to.
//
typedef struct _CNODE {
LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.NodeList
LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
PCLUSTER Cluster; // Parent cluster
LPWSTR Name;
HNODE_RPC hNode; // RPC handle
} CNODE, *PCNODE;
//
// Define CNETWORK structure. There is one network structure created
// for each OpenNetwork API call. An HNETWORK is really a pointer to
// this structure. These are chained onto the CLUSTER that they were
// opened relative to.
//
typedef struct _CNETWORK {
LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.NetworkList
LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
PCLUSTER Cluster; // Parent cluster
LPWSTR Name;
HNETWORK_RPC hNetwork; // RPC handle
} CNETWORK, *PCNETWORK;
//
// Define CNETINTERFACE structure. There is one network interface structure
// created for each OpenNetInterface API call. An HNETINTERFACE is really a
// pointer to this structure. These are chained onto the CLUSTER that they
// were opened relative to.
//
typedef struct _CNETINTERFACE {
LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.NetInterfaceList
LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
PCLUSTER Cluster; // Parent cluster
LPWSTR Name;
HNETINTERFACE_RPC hNetInterface; // RPC handle
} CNETINTERFACE, *PCNETINTERFACE;
//
// Define cluster registry key handle structure.
//
// These are kept around in a tree to track all outstanding
// registry handles. This allows the handles to be re-opened
// transparently in the event that the cluster node we are
// communicating with crashes.
//
typedef struct _CKEY {
LIST_ENTRY ParentList;
LIST_ENTRY ChildList;
LIST_ENTRY NotifyList;
struct _CKEY *Parent;
PCLUSTER Cluster;
LPWSTR RelativeName;
HKEY_RPC RemoteKey;
REGSAM SamDesired;
} CKEY, *PCKEY;
//
// Define CNOTIFY structure. There is one CNOTIFY structure for each
// notification port. A notification port contains zero or more notify
// sessions. Each session is an RPC connection to a different cluster.
// Each session contains one or more notify events. Each event represents
// a a registered notification on a cluster object. Events are linked onto
// both the session structure and the cluster object structure. Events are
// removed from a notification session when the cluster object handle is
// closed, or the cluster notify port itself is closed. When the last event
// in a session is removed, the session is cleaned up. This closes the RPC
// connection.
//
typedef struct _CNOTIFY {
LIST_ENTRY SessionList;
CRITICAL_SECTION Lock;
CL_QUEUE Queue;
CL_HASH NotifyKeyHash;
LIST_ENTRY OrphanedEventList; // CNOTIFY_EVENTs whose object has been closed
// We cannot get rid of these as there may still
// be some packets referencing the CNOTIFY_EVENT
// structure in either the server or client-side
// queues.
} CNOTIFY, *PCNOTIFY;
typedef struct _CNOTIFY_SESSION {
LIST_ENTRY ListEntry; // Linkage onto CNOTIFY.SessionList
LIST_ENTRY ClusterList; // Linkage onto CLUSTER.SessionList
LIST_ENTRY EventList; // List of CNOTIFY_EVENTs on this session
PCLUSTER Cluster;
HNOTIFY_RPC hNotify;
HANDLE NotifyThread;
PCNOTIFY ParentNotify;
BOOL Destroyed; // Set by DestroySession so NotifyThread doesn't
// try and reconnect
} CNOTIFY_SESSION, *PCNOTIFY_SESSION;
typedef struct _CNOTIFY_EVENT {
LIST_ENTRY ListEntry; // Linkage onto CNOTIFY_SESSION.EventList
LIST_ENTRY ObjectList; // Linkage onto cluster object's list.
PCNOTIFY_SESSION Session;
DWORD dwFilter;
DWORD_PTR dwNotifyKey;
DWORD StateSequence;
DWORD EventId;
PVOID Object;
} CNOTIFY_EVENT, *PCNOTIFY_EVENT;
typedef struct _CNOTIFY_PACKET {
LIST_ENTRY ListEntry;
DWORD Status;
DWORD KeyId;
DWORD Filter;
DWORD StateSequence;
LPWSTR Name;
} CNOTIFY_PACKET, *PCNOTIFY_PACKET;
DWORD
RegisterNotifyEvent(
IN PCNOTIFY_SESSION Session,
IN PCNOTIFY_EVENT Event,
OUT OPTIONAL PLIST_ENTRY *pNotifyList
);
DWORD
ReRegisterNotifyEvent(
IN PCNOTIFY_SESSION Session,
IN PCNOTIFY_EVENT Event,
OUT OPTIONAL PLIST_ENTRY *pNotifyList
);
//
// Wrappers for RPC functions. These are equivalent to the raw RPC interface, except
// that they filter out connection errors and perform transparent reconnects.
//
DWORD
ReconnectCluster(
IN PCLUSTER Cluster,
IN DWORD Error,
IN DWORD Generation
);
DWORD
GetReconnectCandidates(
IN PCLUSTER Cluster
);
VOID
FreeReconnectCandidates(
IN PCLUSTER Cluster
);
#define WRAP(_outstatus_, _fn_,_clus_) \
{ \
DWORD _err_; \
DWORD _generation_; \
\
while (TRUE) { \
if ((_clus_)->Flags & CLUS_DEAD) { \
TIME_PRINT(("Failing "#_fn_ " due to dead cluster\n")); \
_err_ = RPC_S_SERVER_UNAVAILABLE; \
break; \
} \
FreeObsoleteRpcHandles(_clus_, FALSE); \
_generation_ = (_clus_)->Generation; \
TIME_PRINT(("Calling " #_fn_ "\n")); \
_err_ = _fn_; \
if (_err_ != ERROR_SUCCESS) { \
_err_ = ReconnectCluster(_clus_, \
_err_, \
_generation_); \
if (_err_ == ERROR_SUCCESS) { \
continue; \
} \
} \
break; \
} \
_outstatus_ = _err_; \
}
//
// This variation of WRAP only attempts to reconnect if _condition_ == TRUE.
// This is useful for threads such as the NotifyThread that can have their
// context handle closed out from under them by another thread.
//
#define WRAP_CHECK(_outstatus_, _fn_,_clus_,_condition_) \
{ \
DWORD _err_; \
DWORD _generation_; \
\
while (TRUE) { \
if ((_clus_)->Flags & CLUS_DEAD) { \
TIME_PRINT(("Failing "#_fn_ " due to dead cluster\n")); \
_err_ = RPC_S_SERVER_UNAVAILABLE; \
break; \
} \
FreeObsoleteRpcHandles(_clus_, FALSE); \
_generation_ = (_clus_)->Generation; \
TIME_PRINT(("Calling " #_fn_ "\n")); \
_err_ = _fn_; \
if ((_err_ != ERROR_SUCCESS) && (_condition_)) { \
_err_ = ReconnectCluster(_clus_, \
_err_, \
_generation_); \
if (_err_ == ERROR_SUCCESS) { \
continue; \
} \
} \
break; \
} \
_outstatus_ = _err_; \
}
#define WRAP_NULL(_outvar_, _fn_, _reterr_, _clus_) \
{ \
DWORD _err_; \
DWORD _generation_; \
\
while (TRUE) { \
if ((_clus_)->Flags & CLUS_DEAD) { \
TIME_PRINT(("Failing "#_fn_ " due to dead cluster\n")); \
*(_reterr_) = RPC_S_SERVER_UNAVAILABLE; \
_outvar_ = NULL; \
break; \
} \
FreeObsoleteRpcHandles(_clus_, FALSE); \
_generation_ = (_clus_)->Generation; \
_outvar_ = _fn_; \
if ((_outvar_ == NULL) || \
(*(_reterr_) != ERROR_SUCCESS)) { \
*(_reterr_) = ReconnectCluster(_clus_, \
*(_reterr_), \
_generation_); \
if (*(_reterr_) == ERROR_SUCCESS) { \
continue; \
} \
} \
break; \
} \
}
//
// A version of lstrcpynW that doesn't bother doing try/except so it doesn't
// quietly succeed if somebody passes in NULL.
//
VOID
APIENTRY
MylstrcpynW(
LPWSTR lpString1,
LPCWSTR lpString2,
DWORD iMaxLength
);
//
// Increase the reference count on a cluster handle.
//
DWORD
WINAPI
AddRefToClusterHandle(
IN HCLUSTER hCluster
);
#define _API_PRINT 0
#if _API_PRINT
ULONG
_cdecl
DbgPrint(
PCH Format,
...
);
#define ApiPrint(_x_) { \
if (IsDebuggerPresent()) { \
DbgPrint _x_ ; \
} \
}
//
// Timing macro
//
#define TIME_PRINT(_x_) { \
DWORD msec; \
\
msec = GetTickCount(); \
ApiPrint(("%d.%03d:%02x: ", \
msec/1000, \
msec % 1000, \
GetCurrentThreadId())); \
ApiPrint(_x_); \
}
#else
#define ApiPrint(_x_)
#define TIME_PRINT(_x_)
#endif