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

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. clusapip.h
  5. Abstract:
  6. Private header file for cluster api
  7. Author:
  8. John Vert (jvert) 15-Jan-1996
  9. Revision History:
  10. --*/
  11. #include "nt.h"
  12. #include "ntrtl.h"
  13. #include "nturtl.h"
  14. #include "windows.h"
  15. #include "cluster.h"
  16. #include "api_rpc.h"
  17. //
  18. // Define CLUSTER structure. There is one cluster structure created
  19. // for each OpenCluster API call. An HCLUSTER is really a pointer to
  20. // this structure.
  21. //
  22. #define CLUS_SIGNATURE 'SULC'
  23. typedef struct _RECONNECT_CANDIDATE {
  24. BOOL IsUp;
  25. BOOL IsCurrent;
  26. LPWSTR Name;
  27. } RECONNECT_CANDIDATE, *PRECONNECT_CANDIDATE;
  28. typedef struct _CLUSTER {
  29. DWORD Signature;
  30. DWORD ReferenceCount;
  31. DWORD FreedRpcHandleListLen;
  32. LPWSTR ClusterName;
  33. LPWSTR NodeName; // node name we are connected to
  34. DWORD Flags;
  35. RPC_BINDING_HANDLE RpcBinding;
  36. HCLUSTER_RPC hCluster;
  37. LIST_ENTRY KeyList; // open cluster registry keys
  38. LIST_ENTRY ResourceList; // open resource handles
  39. LIST_ENTRY GroupList; // open group handles
  40. LIST_ENTRY NodeList; // open node handles
  41. LIST_ENTRY NetworkList; // open network handles
  42. LIST_ENTRY NetInterfaceList; // open net interface handles
  43. LIST_ENTRY NotifyList; // outstanding notification event filters
  44. LIST_ENTRY SessionList; // open notification sessions.
  45. unsigned long AuthnLevel; // Level of authentication to be performed on remote procedure calls
  46. HANDLE NotifyThread;
  47. CRITICAL_SECTION Lock;
  48. DWORD Generation;
  49. DWORD ReconnectCount;
  50. PRECONNECT_CANDIDATE Reconnect;
  51. LIST_ENTRY FreedBindingList;
  52. LIST_ENTRY FreedContextList;
  53. } CLUSTER, *PCLUSTER;
  54. // [GorN] Jan/13/1999
  55. // This is a temporary fix for the race between the users
  56. // of binding and context handles and reconnectThread
  57. //
  58. // The code assumes that RPC_BINDING_HANDLE == ContextHandle == void*
  59. typedef struct _CTX_HANDLE {
  60. LIST_ENTRY HandleList;
  61. void * RpcHandle; // assumption RPC_BINDING_HANDLE == ContextHandle == void*
  62. ULONGLONG TimeStamp;
  63. } CTX_HANDLE, *PCTX_HANDLE;
  64. RPC_STATUS
  65. FreeRpcBindingOrContext(
  66. IN PCLUSTER Cluster,
  67. IN void ** RpcHandle,
  68. IN BOOL IsBinding);
  69. #define MyRpcBindingFree(Cluster, Binding) \
  70. FreeRpcBindingOrContext(Cluster, Binding, TRUE)
  71. #define MyRpcSmDestroyClientContext(Cluster, Context) \
  72. FreeRpcBindingOrContext(Cluster, Context, FALSE)
  73. VOID
  74. FreeObsoleteRpcHandlesEx(
  75. IN PCLUSTER Cluster,
  76. IN BOOL Cleanup,
  77. IN BOOL IsBinding
  78. );
  79. #define FreeObsoleteRpcHandles(Cluster, Cleanup) { \
  80. FreeObsoleteRpcHandlesEx(Cluster, Cleanup, TRUE); \
  81. FreeObsoleteRpcHandlesEx(Cluster, Cleanup, FALSE); \
  82. }
  83. //
  84. // Define CLUSTER.Flags
  85. //
  86. #define CLUS_DELETED 1
  87. #define CLUS_DEAD 2
  88. #define CLUS_LOCALCONNECT 4
  89. //
  90. // Cluster helper macros
  91. //
  92. #define GET_CLUSTER(hCluster) (PCLUSTER)((((PCLUSTER)(hCluster))->Flags & CLUS_DELETED) ? NULL : hCluster)
  93. #define IS_CLUSTER_FREE(c) ((c->Flags & CLUS_DELETED) && \
  94. (IsListEmpty(&(c)->KeyList)) && \
  95. (IsListEmpty(&(c)->GroupList)) && \
  96. (IsListEmpty(&(c)->NodeList)) && \
  97. (IsListEmpty(&(c)->ResourceList)) && \
  98. (IsListEmpty(&(c)->NetworkList)) && \
  99. (IsListEmpty(&(c)->NetInterfaceList)))
  100. //
  101. // Cluster structure cleanup routine.
  102. //
  103. VOID
  104. CleanupCluster(
  105. IN PCLUSTER Cluster
  106. );
  107. VOID
  108. RundownNotifyEvents(
  109. IN PLIST_ENTRY ListHead,
  110. IN LPCWSTR Name
  111. );
  112. //
  113. // Define CRESOURCE structure. There is one resource structure created
  114. // for each OpenResource/CreateResource API call. An HRESOURCE is really
  115. // a pointer to this structure. These are chained onto the CLUSTER that
  116. // they were opened relative to.
  117. //
  118. typedef struct _CRESOURCE {
  119. LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.ResourceList
  120. LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
  121. PCLUSTER Cluster; // Parent cluster
  122. LPWSTR Name;
  123. HRES_RPC hResource; // RPC handle
  124. } CRESOURCE, *PCRESOURCE;
  125. //
  126. // Define CGROUP structure. There is one group structure created
  127. // for each OpenGroup/CreateGroup API call. An HGROUP is really
  128. // a pointer to this structure. These are chained onto the CLUSTER that
  129. // they were opened relative to.
  130. //
  131. typedef struct _CGROUP {
  132. LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.Group
  133. LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
  134. PCLUSTER Cluster; // Parent cluster
  135. LPWSTR Name;
  136. HRES_RPC hGroup; // RPC handle
  137. } CGROUP, *PCGROUP;
  138. //
  139. // Define CNODE structure. There is one node structure created
  140. // for each OpenClusterNode call. An HNODE is really a pointer
  141. // to this structure. These are chained onto the CLUSTER that they
  142. // were opened relative to.
  143. //
  144. typedef struct _CNODE {
  145. LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.NodeList
  146. LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
  147. PCLUSTER Cluster; // Parent cluster
  148. LPWSTR Name;
  149. HNODE_RPC hNode; // RPC handle
  150. } CNODE, *PCNODE;
  151. //
  152. // Define CNETWORK structure. There is one network structure created
  153. // for each OpenNetwork API call. An HNETWORK is really a pointer to
  154. // this structure. These are chained onto the CLUSTER that they were
  155. // opened relative to.
  156. //
  157. typedef struct _CNETWORK {
  158. LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.NetworkList
  159. LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
  160. PCLUSTER Cluster; // Parent cluster
  161. LPWSTR Name;
  162. HNETWORK_RPC hNetwork; // RPC handle
  163. } CNETWORK, *PCNETWORK;
  164. //
  165. // Define CNETINTERFACE structure. There is one network interface structure
  166. // created for each OpenNetInterface API call. An HNETINTERFACE is really a
  167. // pointer to this structure. These are chained onto the CLUSTER that they
  168. // were opened relative to.
  169. //
  170. typedef struct _CNETINTERFACE {
  171. LIST_ENTRY ListEntry; // Links for chaining onto CLUSTER.NetInterfaceList
  172. LIST_ENTRY NotifyList; // Links for tracking outstanding notifies.
  173. PCLUSTER Cluster; // Parent cluster
  174. LPWSTR Name;
  175. HNETINTERFACE_RPC hNetInterface; // RPC handle
  176. } CNETINTERFACE, *PCNETINTERFACE;
  177. //
  178. // Define cluster registry key handle structure.
  179. //
  180. // These are kept around in a tree to track all outstanding
  181. // registry handles. This allows the handles to be re-opened
  182. // transparently in the event that the cluster node we are
  183. // communicating with crashes.
  184. //
  185. typedef struct _CKEY {
  186. LIST_ENTRY ParentList;
  187. LIST_ENTRY ChildList;
  188. LIST_ENTRY NotifyList;
  189. struct _CKEY *Parent;
  190. PCLUSTER Cluster;
  191. LPWSTR RelativeName;
  192. HKEY_RPC RemoteKey;
  193. REGSAM SamDesired;
  194. } CKEY, *PCKEY;
  195. //
  196. // Define CNOTIFY structure. There is one CNOTIFY structure for each
  197. // notification port. A notification port contains zero or more notify
  198. // sessions. Each session is an RPC connection to a different cluster.
  199. // Each session contains one or more notify events. Each event represents
  200. // a a registered notification on a cluster object. Events are linked onto
  201. // both the session structure and the cluster object structure. Events are
  202. // removed from a notification session when the cluster object handle is
  203. // closed, or the cluster notify port itself is closed. When the last event
  204. // in a session is removed, the session is cleaned up. This closes the RPC
  205. // connection.
  206. //
  207. typedef struct _CNOTIFY {
  208. LIST_ENTRY SessionList;
  209. CRITICAL_SECTION Lock;
  210. CL_QUEUE Queue;
  211. CL_HASH NotifyKeyHash;
  212. LIST_ENTRY OrphanedEventList; // CNOTIFY_EVENTs whose object has been closed
  213. // We cannot get rid of these as there may still
  214. // be some packets referencing the CNOTIFY_EVENT
  215. // structure in either the server or client-side
  216. // queues.
  217. } CNOTIFY, *PCNOTIFY;
  218. typedef struct _CNOTIFY_SESSION {
  219. LIST_ENTRY ListEntry; // Linkage onto CNOTIFY.SessionList
  220. LIST_ENTRY ClusterList; // Linkage onto CLUSTER.SessionList
  221. LIST_ENTRY EventList; // List of CNOTIFY_EVENTs on this session
  222. PCLUSTER Cluster;
  223. HNOTIFY_RPC hNotify;
  224. HANDLE NotifyThread;
  225. PCNOTIFY ParentNotify;
  226. BOOL Destroyed; // Set by DestroySession so NotifyThread doesn't
  227. // try and reconnect
  228. } CNOTIFY_SESSION, *PCNOTIFY_SESSION;
  229. typedef struct _CNOTIFY_EVENT {
  230. LIST_ENTRY ListEntry; // Linkage onto CNOTIFY_SESSION.EventList
  231. LIST_ENTRY ObjectList; // Linkage onto cluster object's list.
  232. PCNOTIFY_SESSION Session;
  233. DWORD dwFilter;
  234. DWORD_PTR dwNotifyKey;
  235. DWORD StateSequence;
  236. DWORD EventId;
  237. PVOID Object;
  238. } CNOTIFY_EVENT, *PCNOTIFY_EVENT;
  239. typedef struct _CNOTIFY_PACKET {
  240. LIST_ENTRY ListEntry;
  241. DWORD Status;
  242. DWORD KeyId;
  243. DWORD Filter;
  244. DWORD StateSequence;
  245. LPWSTR Name;
  246. } CNOTIFY_PACKET, *PCNOTIFY_PACKET;
  247. DWORD
  248. RegisterNotifyEvent(
  249. IN PCNOTIFY_SESSION Session,
  250. IN PCNOTIFY_EVENT Event,
  251. OUT OPTIONAL PLIST_ENTRY *pNotifyList
  252. );
  253. DWORD
  254. ReRegisterNotifyEvent(
  255. IN PCNOTIFY_SESSION Session,
  256. IN PCNOTIFY_EVENT Event,
  257. OUT OPTIONAL PLIST_ENTRY *pNotifyList
  258. );
  259. //
  260. // Wrappers for RPC functions. These are equivalent to the raw RPC interface, except
  261. // that they filter out connection errors and perform transparent reconnects.
  262. //
  263. DWORD
  264. ReconnectCluster(
  265. IN PCLUSTER Cluster,
  266. IN DWORD Error,
  267. IN DWORD Generation
  268. );
  269. DWORD
  270. GetReconnectCandidates(
  271. IN PCLUSTER Cluster
  272. );
  273. VOID
  274. FreeReconnectCandidates(
  275. IN PCLUSTER Cluster
  276. );
  277. #define WRAP(_outstatus_, _fn_,_clus_) \
  278. { \
  279. DWORD _err_; \
  280. DWORD _generation_; \
  281. \
  282. while (TRUE) { \
  283. if ((_clus_)->Flags & CLUS_DEAD) { \
  284. TIME_PRINT(("Failing "#_fn_ " due to dead cluster\n")); \
  285. _err_ = RPC_S_SERVER_UNAVAILABLE; \
  286. break; \
  287. } \
  288. FreeObsoleteRpcHandles(_clus_, FALSE); \
  289. _generation_ = (_clus_)->Generation; \
  290. TIME_PRINT(("Calling " #_fn_ "\n")); \
  291. _err_ = _fn_; \
  292. if (_err_ != ERROR_SUCCESS) { \
  293. _err_ = ReconnectCluster(_clus_, \
  294. _err_, \
  295. _generation_); \
  296. if (_err_ == ERROR_SUCCESS) { \
  297. continue; \
  298. } \
  299. } \
  300. break; \
  301. } \
  302. _outstatus_ = _err_; \
  303. }
  304. //
  305. // This variation of WRAP only attempts to reconnect if _condition_ == TRUE.
  306. // This is useful for threads such as the NotifyThread that can have their
  307. // context handle closed out from under them by another thread.
  308. //
  309. #define WRAP_CHECK(_outstatus_, _fn_,_clus_,_condition_) \
  310. { \
  311. DWORD _err_; \
  312. DWORD _generation_; \
  313. \
  314. while (TRUE) { \
  315. if ((_clus_)->Flags & CLUS_DEAD) { \
  316. TIME_PRINT(("Failing "#_fn_ " due to dead cluster\n")); \
  317. _err_ = RPC_S_SERVER_UNAVAILABLE; \
  318. break; \
  319. } \
  320. FreeObsoleteRpcHandles(_clus_, FALSE); \
  321. _generation_ = (_clus_)->Generation; \
  322. TIME_PRINT(("Calling " #_fn_ "\n")); \
  323. _err_ = _fn_; \
  324. if ((_err_ != ERROR_SUCCESS) && (_condition_)) { \
  325. _err_ = ReconnectCluster(_clus_, \
  326. _err_, \
  327. _generation_); \
  328. if (_err_ == ERROR_SUCCESS) { \
  329. continue; \
  330. } \
  331. } \
  332. break; \
  333. } \
  334. _outstatus_ = _err_; \
  335. }
  336. #define WRAP_NULL(_outvar_, _fn_, _reterr_, _clus_) \
  337. { \
  338. DWORD _err_; \
  339. DWORD _generation_; \
  340. \
  341. while (TRUE) { \
  342. if ((_clus_)->Flags & CLUS_DEAD) { \
  343. TIME_PRINT(("Failing "#_fn_ " due to dead cluster\n")); \
  344. *(_reterr_) = RPC_S_SERVER_UNAVAILABLE; \
  345. _outvar_ = NULL; \
  346. break; \
  347. } \
  348. FreeObsoleteRpcHandles(_clus_, FALSE); \
  349. _generation_ = (_clus_)->Generation; \
  350. _outvar_ = _fn_; \
  351. if ((_outvar_ == NULL) || \
  352. (*(_reterr_) != ERROR_SUCCESS)) { \
  353. *(_reterr_) = ReconnectCluster(_clus_, \
  354. *(_reterr_), \
  355. _generation_); \
  356. if (*(_reterr_) == ERROR_SUCCESS) { \
  357. continue; \
  358. } \
  359. } \
  360. break; \
  361. } \
  362. }
  363. //
  364. // A version of lstrcpynW that doesn't bother doing try/except so it doesn't
  365. // quietly succeed if somebody passes in NULL.
  366. //
  367. VOID
  368. APIENTRY
  369. MylstrcpynW(
  370. LPWSTR lpString1,
  371. LPCWSTR lpString2,
  372. DWORD iMaxLength
  373. );
  374. //
  375. // Increase the reference count on a cluster handle.
  376. //
  377. DWORD
  378. WINAPI
  379. AddRefToClusterHandle(
  380. IN HCLUSTER hCluster
  381. );
  382. #define _API_PRINT 0
  383. #if _API_PRINT
  384. ULONG
  385. _cdecl
  386. DbgPrint(
  387. PCH Format,
  388. ...
  389. );
  390. #define ApiPrint(_x_) { \
  391. if (IsDebuggerPresent()) { \
  392. DbgPrint _x_ ; \
  393. } \
  394. }
  395. //
  396. // Timing macro
  397. //
  398. #define TIME_PRINT(_x_) { \
  399. DWORD msec; \
  400. \
  401. msec = GetTickCount(); \
  402. ApiPrint(("%d.%03d:%02x: ", \
  403. msec/1000, \
  404. msec % 1000, \
  405. GetCurrentThreadId())); \
  406. ApiPrint(_x_); \
  407. }
  408. #else
  409. #define ApiPrint(_x_)
  410. #define TIME_PRINT(_x_)
  411. #endif