Leaked source code of windows server 2003
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.

267 lines
9.1 KiB

  1. /* (C) 1997-1999 Microsoft Corp.
  2. *
  3. * file : MCSCore.c
  4. * author : Erik Mavrinac
  5. *
  6. * description: MCS core manipulation code for actions that are common
  7. * between inbound PDU handling and API calls from upper components.
  8. */
  9. #include "PreComp.h"
  10. #pragma hdrstop
  11. #include <MCSImpl.h>
  12. // Gets a new dynamic channel number, but does not add it to channel list.
  13. // Returns 0 if none available.
  14. ChannelID GetNewDynamicChannel(Domain *pDomain)
  15. {
  16. if (SListGetEntries(&pDomain->ChannelList) >=
  17. pDomain->DomParams.MaxChannels)
  18. return 0;
  19. pDomain->NextAvailDynChannel++;
  20. ASSERT(pDomain->NextAvailDynChannel <= 65535);
  21. return (pDomain->NextAvailDynChannel - 1);
  22. }
  23. /*
  24. * Common detach-user request code applicable to both net PDU requests and
  25. * local requests.
  26. * bDisconnect is FALSE if this is a normal detach where local attachments
  27. * are notified, nonzero if this a disconnection situation and the
  28. * attachment needs to be sent a detach-user indication with its own UserID.
  29. */
  30. MCSError DetachUser(
  31. Domain *pDomain,
  32. UserHandle hUser,
  33. MCSReason Reason,
  34. BOOLEAN bDisconnect)
  35. {
  36. POUTBUF pOutBuf;
  37. BOOLEAN bChannelRemoved;
  38. NTSTATUS Status;
  39. MCSError MCSErr;
  40. MCSChannel *pMCSChannel;
  41. UserAttachment *pUA, *pCurUA;
  42. DetachUserIndication DUin;
  43. pUA = (UserAttachment *)hUser;
  44. TraceOut3(pDomain->pContext, "DetachUser() entry, pDomain=%X, hUser=%X, "
  45. "UserID=%X", pDomain, hUser, pUA->UserID);
  46. // Remove the user from all joined channels.
  47. SListResetIteration(&pUA->JoinedChannelList);
  48. while (SListIterate(&pUA->JoinedChannelList, (UINT_PTR *)&pMCSChannel,
  49. &pMCSChannel)) {
  50. MCSErr = ChannelLeave(hUser, pMCSChannel, &bChannelRemoved);
  51. ASSERT(MCSErr == MCS_NO_ERROR);
  52. }
  53. // Remove the requested hUser from the user attachments list.
  54. TraceOut(pDomain->pContext, "DetachUser(): Removing hUser from main list");
  55. SListRemove(&pDomain->UserAttachmentList, (UINT_PTR)hUser, &pUA);
  56. if (pUA != NULL) {
  57. // Common callback information.
  58. DUin.UserID = pUA->UserID;
  59. DUin.Reason = Reason;
  60. }
  61. else {
  62. ErrOut(pDomain->pContext, "DetachUser: hUser is not a valid "
  63. "user attachment");
  64. return MCS_NO_SUCH_USER;
  65. }
  66. if (bDisconnect) {
  67. // Send detach-user callback to user with its own ID.
  68. DUin.bSelf = TRUE;
  69. (pUA->Callback)(hUser, MCS_DETACH_USER_INDICATION, &DUin,
  70. pUA->UserDefined);
  71. }
  72. else if (!bDisconnect && SListGetEntries(&pDomain->UserAttachmentList)) {
  73. DUin.bSelf = FALSE;
  74. // Iterate the remaining local attachments and send the indication.
  75. // It is the caller's responsibility to inform downlevel connections
  76. // of the detachment.
  77. SListResetIteration(&pDomain->UserAttachmentList);
  78. while (SListIterate(&pDomain->UserAttachmentList, (UINT_PTR *)&hUser,
  79. &pCurUA)) {
  80. if (pCurUA->bLocal)
  81. (pCurUA->Callback)(hUser, MCS_DETACH_USER_INDICATION, &DUin,
  82. pCurUA->UserDefined);
  83. }
  84. // Reset again to keep callers from failing to iterate.
  85. SListResetIteration(&pDomain->UserAttachmentList);
  86. }
  87. // Remove UserID from channel list. It may no longer be there if the
  88. // user had joined the channel and the channel was purged above.
  89. TraceOut(pDomain->pContext, "DetachUser(): Removing UserID from main "
  90. "channel list");
  91. SListRemove(&pDomain->ChannelList, pUA->UserID, &pMCSChannel);
  92. if (pMCSChannel) {
  93. // Consistency check -- the code above should have caught the channel
  94. // and destroyed it if the user had joined. Otherwise the channel
  95. // should be empty.
  96. ASSERT(SListGetEntries(&pMCSChannel->UserList) == 0);
  97. SListDestroy(&pMCSChannel->UserList);
  98. if (pMCSChannel->bPreallocated)
  99. pMCSChannel->bInUse = FALSE;
  100. else
  101. ExFreePool(pMCSChannel);
  102. }
  103. // Destruct and deallocate pUA.
  104. SListDestroy(&pUA->JoinedChannelList);
  105. if (pUA->bPreallocated)
  106. pUA->bInUse = FALSE;
  107. else
  108. ExFreePool(pUA);
  109. return MCS_NO_ERROR;
  110. }
  111. MCSError ChannelLeave(
  112. UserHandle hUser,
  113. ChannelHandle hChannel,
  114. BOOLEAN *pbChannelRemoved)
  115. {
  116. UserAttachment *pUA, *pUA_Channel;
  117. MCSChannel *pMCSChannel_UA, *pMCSChannel_Main;
  118. *pbChannelRemoved = FALSE;
  119. pUA = (UserAttachment *)hUser;
  120. pMCSChannel_Main = (MCSChannel *)hChannel;
  121. if (NULL == pMCSChannel_Main) {
  122. return MCS_NO_SUCH_CHANNEL;
  123. }
  124. // Remove the channel from the UA joined-channel list.
  125. TraceOut1(pUA->pDomain->pContext, "ChannelLeave(): Removing hChannel %X "
  126. "from main channel list", hChannel);
  127. SListRemove(&pUA->JoinedChannelList, (UINT_PTR)pMCSChannel_Main,
  128. &pMCSChannel_UA);
  129. ASSERT(pMCSChannel_UA == pMCSChannel_Main); // Consistency check.
  130. // Remove the hUser from the channel user list.
  131. TraceOut1(pUA->pDomain->pContext, "ChannelLeave(): Removing hUser %X "
  132. "from channel joined user list", hUser);
  133. SListRemove(&pMCSChannel_Main->UserList, (UINT_PTR)pUA, &pUA_Channel);
  134. ASSERT(pUA == pUA_Channel); // Consistency check.
  135. // Remove the channel from the main list if there are no more users joined.
  136. if (!SListGetEntries(&pMCSChannel_Main->UserList)) {
  137. TraceOut(pUA->pDomain->pContext, "ChannelLeave(): Removing channel "
  138. "from main channel list");
  139. SListRemove(&pUA->pDomain->ChannelList, pMCSChannel_Main->ID,
  140. &pMCSChannel_Main);
  141. ASSERT(pMCSChannel_Main != NULL);
  142. if (pMCSChannel_Main == NULL) {
  143. return MCS_NO_SUCH_CHANNEL;
  144. }
  145. if (pMCSChannel_Main->bPreallocated)
  146. pMCSChannel_Main->bInUse = FALSE;
  147. else
  148. ExFreePool(pMCSChannel_Main);
  149. *pbChannelRemoved = TRUE;
  150. }
  151. if (!pUA->pDomain->bTopProvider) {
  152. // MCS FUTURE: Local lists are updated, forward the request to the
  153. // top provider. No confirm will be issued.
  154. }
  155. return MCS_NO_ERROR;
  156. }
  157. /*
  158. * Disconnect provider. Called on receipt of a disconnect-provider ultimatum
  159. * PDU, or when the connection is lost. bLocal is TRUE if this call is
  160. * for a local node controller call or lost connection, FALSE if for a
  161. * received PDU.
  162. */
  163. NTSTATUS DisconnectProvider(Domain *pDomain, BOOLEAN bLocal, MCSReason Reason)
  164. {
  165. NTSTATUS Status;
  166. UserHandle hUser;
  167. UserAttachment *pUA;
  168. pDomain->State = State_Disconnected;
  169. TraceOut1(pDomain->pContext, "DisconnectProvider(): pDomain=%X", pDomain);
  170. // Search through the attached users list, launch detach-user indications.
  171. // For bLocal == FALSE, we do a regular-style detach for each nonlocal user.
  172. // Otherwise, we send a detach-user indication to each local user
  173. // attachment containing the attachment's own user ID, indicating that
  174. // it was forced out of the domain.
  175. // Multiple iterations: DetachUser also iterates UserAttachmentList, but
  176. // takes care to reset the iteration again after it is done. Since
  177. // removing a list entry resets the iteration, this is exactly what we
  178. // want.
  179. SListResetIteration(&pDomain->UserAttachmentList);
  180. while (SListIterate(&pDomain->UserAttachmentList, (UINT_PTR *)&hUser,
  181. &pUA)) {
  182. if (bLocal && pUA->bLocal)
  183. Status = DetachUser(pDomain, hUser, Reason, TRUE);
  184. else if (!bLocal && !pUA->bLocal)
  185. Status = DetachUser(pDomain, hUser, Reason, FALSE);
  186. }
  187. // We do not do any notification to either the local node controller or
  188. // sending across the net -- the caller is responsible for doing the
  189. // right thing.
  190. return STATUS_SUCCESS;
  191. }
  192. /*
  193. * Handles sending an OutBuf to the TD, including updating perf counters.
  194. * NOTE: This code is inlined into the critical MCSSendDataRequest() path
  195. * in MCSKAPI.c. Any changes here need to be reflected there.
  196. */
  197. NTSTATUS SendOutBuf(Domain *pDomain, POUTBUF pOutBuf)
  198. {
  199. SD_RAWWRITE SdWrite;
  200. ASSERT(pOutBuf->ByteCount > 0);
  201. if (!pDomain->bCanSendData) {
  202. WarnOut1(pDomain->pContext, "%s: SendOutBuf(): Ignoring a send because "
  203. "ICA stack not connected",
  204. pDomain->StackClass == Stack_Primary ? "Primary" :
  205. (pDomain->StackClass == Stack_Shadow ? "Shadow" :
  206. "PassThru"));
  207. IcaBufferFree(pDomain->pContext, pOutBuf);
  208. return STATUS_SUCCESS;
  209. }
  210. // Fill out the raw write data.
  211. SdWrite.pBuffer = NULL;
  212. SdWrite.ByteCount = 0;
  213. SdWrite.pOutBuf = pOutBuf;
  214. // Increment protocol counters.
  215. pDomain->pStat->Output.WdFrames++;
  216. pDomain->pStat->Output.WdBytes += pOutBuf->ByteCount;
  217. // Send data to next driver in stack.
  218. return IcaCallNextDriver(pDomain->pContext, SD$RAWWRITE, &SdWrite);
  219. }