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

/* (C) 1997-1999 Microsoft Corp.
*
* file : MCSCore.c
* author : Erik Mavrinac
*
* description: MCS core manipulation code for actions that are common
* between inbound PDU handling and API calls from upper components.
*/
#include "PreComp.h"
#pragma hdrstop
#include <MCSImpl.h>
// Gets a new dynamic channel number, but does not add it to channel list.
// Returns 0 if none available.
ChannelID GetNewDynamicChannel(Domain *pDomain)
{
if (SListGetEntries(&pDomain->ChannelList) >=
pDomain->DomParams.MaxChannels)
return 0;
pDomain->NextAvailDynChannel++;
ASSERT(pDomain->NextAvailDynChannel <= 65535);
return (pDomain->NextAvailDynChannel - 1);
}
/*
* Common detach-user request code applicable to both net PDU requests and
* local requests.
* bDisconnect is FALSE if this is a normal detach where local attachments
* are notified, nonzero if this a disconnection situation and the
* attachment needs to be sent a detach-user indication with its own UserID.
*/
MCSError DetachUser(
Domain *pDomain,
UserHandle hUser,
MCSReason Reason,
BOOLEAN bDisconnect)
{
POUTBUF pOutBuf;
BOOLEAN bChannelRemoved;
NTSTATUS Status;
MCSError MCSErr;
MCSChannel *pMCSChannel;
UserAttachment *pUA, *pCurUA;
DetachUserIndication DUin;
pUA = (UserAttachment *)hUser;
TraceOut3(pDomain->pContext, "DetachUser() entry, pDomain=%X, hUser=%X, "
"UserID=%X", pDomain, hUser, pUA->UserID);
// Remove the user from all joined channels.
SListResetIteration(&pUA->JoinedChannelList);
while (SListIterate(&pUA->JoinedChannelList, (UINT_PTR *)&pMCSChannel,
&pMCSChannel)) {
MCSErr = ChannelLeave(hUser, pMCSChannel, &bChannelRemoved);
ASSERT(MCSErr == MCS_NO_ERROR);
}
// Remove the requested hUser from the user attachments list.
TraceOut(pDomain->pContext, "DetachUser(): Removing hUser from main list");
SListRemove(&pDomain->UserAttachmentList, (UINT_PTR)hUser, &pUA);
if (pUA != NULL) {
// Common callback information.
DUin.UserID = pUA->UserID;
DUin.Reason = Reason;
}
else {
ErrOut(pDomain->pContext, "DetachUser: hUser is not a valid "
"user attachment");
return MCS_NO_SUCH_USER;
}
if (bDisconnect) {
// Send detach-user callback to user with its own ID.
DUin.bSelf = TRUE;
(pUA->Callback)(hUser, MCS_DETACH_USER_INDICATION, &DUin,
pUA->UserDefined);
}
else if (!bDisconnect && SListGetEntries(&pDomain->UserAttachmentList)) {
DUin.bSelf = FALSE;
// Iterate the remaining local attachments and send the indication.
// It is the caller's responsibility to inform downlevel connections
// of the detachment.
SListResetIteration(&pDomain->UserAttachmentList);
while (SListIterate(&pDomain->UserAttachmentList, (UINT_PTR *)&hUser,
&pCurUA)) {
if (pCurUA->bLocal)
(pCurUA->Callback)(hUser, MCS_DETACH_USER_INDICATION, &DUin,
pCurUA->UserDefined);
}
// Reset again to keep callers from failing to iterate.
SListResetIteration(&pDomain->UserAttachmentList);
}
// Remove UserID from channel list. It may no longer be there if the
// user had joined the channel and the channel was purged above.
TraceOut(pDomain->pContext, "DetachUser(): Removing UserID from main "
"channel list");
SListRemove(&pDomain->ChannelList, pUA->UserID, &pMCSChannel);
if (pMCSChannel) {
// Consistency check -- the code above should have caught the channel
// and destroyed it if the user had joined. Otherwise the channel
// should be empty.
ASSERT(SListGetEntries(&pMCSChannel->UserList) == 0);
SListDestroy(&pMCSChannel->UserList);
if (pMCSChannel->bPreallocated)
pMCSChannel->bInUse = FALSE;
else
ExFreePool(pMCSChannel);
}
// Destruct and deallocate pUA.
SListDestroy(&pUA->JoinedChannelList);
if (pUA->bPreallocated)
pUA->bInUse = FALSE;
else
ExFreePool(pUA);
return MCS_NO_ERROR;
}
MCSError ChannelLeave(
UserHandle hUser,
ChannelHandle hChannel,
BOOLEAN *pbChannelRemoved)
{
UserAttachment *pUA, *pUA_Channel;
MCSChannel *pMCSChannel_UA, *pMCSChannel_Main;
*pbChannelRemoved = FALSE;
pUA = (UserAttachment *)hUser;
pMCSChannel_Main = (MCSChannel *)hChannel;
if (NULL == pMCSChannel_Main) {
return MCS_NO_SUCH_CHANNEL;
}
// Remove the channel from the UA joined-channel list.
TraceOut1(pUA->pDomain->pContext, "ChannelLeave(): Removing hChannel %X "
"from main channel list", hChannel);
SListRemove(&pUA->JoinedChannelList, (UINT_PTR)pMCSChannel_Main,
&pMCSChannel_UA);
ASSERT(pMCSChannel_UA == pMCSChannel_Main); // Consistency check.
// Remove the hUser from the channel user list.
TraceOut1(pUA->pDomain->pContext, "ChannelLeave(): Removing hUser %X "
"from channel joined user list", hUser);
SListRemove(&pMCSChannel_Main->UserList, (UINT_PTR)pUA, &pUA_Channel);
ASSERT(pUA == pUA_Channel); // Consistency check.
// Remove the channel from the main list if there are no more users joined.
if (!SListGetEntries(&pMCSChannel_Main->UserList)) {
TraceOut(pUA->pDomain->pContext, "ChannelLeave(): Removing channel "
"from main channel list");
SListRemove(&pUA->pDomain->ChannelList, pMCSChannel_Main->ID,
&pMCSChannel_Main);
ASSERT(pMCSChannel_Main != NULL);
if (pMCSChannel_Main == NULL) {
return MCS_NO_SUCH_CHANNEL;
}
if (pMCSChannel_Main->bPreallocated)
pMCSChannel_Main->bInUse = FALSE;
else
ExFreePool(pMCSChannel_Main);
*pbChannelRemoved = TRUE;
}
if (!pUA->pDomain->bTopProvider) {
// MCS FUTURE: Local lists are updated, forward the request to the
// top provider. No confirm will be issued.
}
return MCS_NO_ERROR;
}
/*
* Disconnect provider. Called on receipt of a disconnect-provider ultimatum
* PDU, or when the connection is lost. bLocal is TRUE if this call is
* for a local node controller call or lost connection, FALSE if for a
* received PDU.
*/
NTSTATUS DisconnectProvider(Domain *pDomain, BOOLEAN bLocal, MCSReason Reason)
{
NTSTATUS Status;
UserHandle hUser;
UserAttachment *pUA;
pDomain->State = State_Disconnected;
TraceOut1(pDomain->pContext, "DisconnectProvider(): pDomain=%X", pDomain);
// Search through the attached users list, launch detach-user indications.
// For bLocal == FALSE, we do a regular-style detach for each nonlocal user.
// Otherwise, we send a detach-user indication to each local user
// attachment containing the attachment's own user ID, indicating that
// it was forced out of the domain.
// Multiple iterations: DetachUser also iterates UserAttachmentList, but
// takes care to reset the iteration again after it is done. Since
// removing a list entry resets the iteration, this is exactly what we
// want.
SListResetIteration(&pDomain->UserAttachmentList);
while (SListIterate(&pDomain->UserAttachmentList, (UINT_PTR *)&hUser,
&pUA)) {
if (bLocal && pUA->bLocal)
Status = DetachUser(pDomain, hUser, Reason, TRUE);
else if (!bLocal && !pUA->bLocal)
Status = DetachUser(pDomain, hUser, Reason, FALSE);
}
// We do not do any notification to either the local node controller or
// sending across the net -- the caller is responsible for doing the
// right thing.
return STATUS_SUCCESS;
}
/*
* Handles sending an OutBuf to the TD, including updating perf counters.
* NOTE: This code is inlined into the critical MCSSendDataRequest() path
* in MCSKAPI.c. Any changes here need to be reflected there.
*/
NTSTATUS SendOutBuf(Domain *pDomain, POUTBUF pOutBuf)
{
SD_RAWWRITE SdWrite;
ASSERT(pOutBuf->ByteCount > 0);
if (!pDomain->bCanSendData) {
WarnOut1(pDomain->pContext, "%s: SendOutBuf(): Ignoring a send because "
"ICA stack not connected",
pDomain->StackClass == Stack_Primary ? "Primary" :
(pDomain->StackClass == Stack_Shadow ? "Shadow" :
"PassThru"));
IcaBufferFree(pDomain->pContext, pOutBuf);
return STATUS_SUCCESS;
}
// Fill out the raw write data.
SdWrite.pBuffer = NULL;
SdWrite.ByteCount = 0;
SdWrite.pOutBuf = pOutBuf;
// Increment protocol counters.
pDomain->pStat->Output.WdFrames++;
pDomain->pStat->Output.WdBytes += pOutBuf->ByteCount;
// Send data to next driver in stack.
return IcaCallNextDriver(pDomain->pContext, SD$RAWWRITE, &SdWrite);
}