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.
 
 
 
 
 
 

1477 lines
44 KiB

#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_MCSNC);
/*
* privchnl.cpp
*
* Copyright (c) 1993 - 1995 by DataBeam Corporation, Lexington, KY
*
* Abstract:
* This is the implementation file for the PrivateChannel class. It
* contains the code that distinguishes this class from that of its parent,
* Channel.
*
* This class maintains an authorized user list, and includes the code
* necessary to use that list. No user will be allowed to join or send
* data on a private channel unless they are either the channel manager
* or an admitted user.
*
* Private Instance Variables:
* m_uidChannelManager
* This is the User ID of the user that convened the private channel.
* Only this user is allowed to manipulate the authorized user list.
* When a private channel becomes invalid (as the result of a channel
* disband request or indication), this value will be set to 0.
* m_AuthorizedUserList
* This is a collection containing the user IDs of those users that
* have been admitted to the private channel by the channel manager.
* Other than the manager, these are the only users that are allowed
* to join or send data on the channel. When a private channel becomes
* invalid (as the result of a channel disband request or indication),
* this list will be cleared.
* m_fDisbandRequestPending
* This is a boolean flag that gets set when a disband request is
* forwarded upward to the top provider. This prevents this channel
* from issuing a disband indication to the channel manager when it
* comes back down the tree from the top provider.
*
* Private Member Functions:
* ValidateUserID
* This member function is called to verify that a specified user ID
* corresponds to a valid user in the sub-tree of the local provider.
* BuildAttachmentLists
* This member function is called to build two lists of attachments
* from a master user ID list. The first list contains all local
* attachments whose user ID is in the specified list. The second
* list contains all remote attachments whose user ID is in the
* specified list. These lists are used to issue various indications
* to specified users without sending any to the same attachment.
* BuildUserIDList
* This member function is called to build a list of users that lie
* in the direction of a specified attachment. These lists are
* sent along with PDUs that require them.
*
* Caveats:
* None.
*
* Author:
* James P. Galvin, Jr.
*/
/*
* External Interfaces
*/
#include "privchnl.h"
/*
* PrivateChannel ()
*
* Public
*
* Functional Description:
* This is the primary constructor for PrivateChannel objects. It creates
* an object with all instance variable initialized, but with no
* attachments (i.e. no users are joined to the channel automatically).
*
* Note that most instance variable initialization is done by invoking the
* equivalent constructor in the base class.
*
* Upon successful completion, a channel convene confirm is automatically
* issued to the channel manager, if the channel manager is in the sub-tree
* of this provider. Note that if the channel manager is NOT in this
* sub-tree, then this private channel object was probably created as the
* result of a channel admit indication, and no channel convene confirm
* will be issued.
*/
PrivateChannel::PrivateChannel (
ChannelID channel_id,
UserID channel_manager,
PDomain local_provider,
PConnection top_provider,
CChannelList2 *channel_list,
CAttachmentList *attachment_list)
:
Channel(channel_id, local_provider, top_provider, channel_list, attachment_list),
m_AuthorizedUserList(),
m_uidChannelManager(channel_manager),
m_fDisbandRequestPending(FALSE)
{
/*
* Check to see if the channel manager lies in the sub-tree of this
* provider. If so, then this object was created as the result of a
* channel convene request or confirm, and it is necessary to issue the
* confirm toward that user. If not, then this object was created as the
* result of a channel admit indication, and it is not necessary to send
* the channel convene confirm.
*/
if (ValidateUserID(m_uidChannelManager))
{
PChannel lpChannel;
/*
* Determine which attachment leads to the channel manager by asking
* the channel object corresponding to it. Then issue the confirm
* to that attachment.
*/
if (NULL != (lpChannel = m_pChannelList2->Find(m_uidChannelManager)))
{
CAttachment *pAtt = lpChannel->GetAttachment();
if (pAtt)
{
pAtt->ChannelConveneConfirm(RESULT_SUCCESSFUL,
m_uidChannelManager, channel_id);
}
else
{
ERROR_OUT(("PrivateChannel::PrivateChannel: null attachment"));
}
}
}
}
/*
* PrivateChannel ()
*
* Public
*
* Functional Description:
* This is a secondary constructor that is only used during merge
* operations. The intent of this constructor is to create an equivalent
* object without issuing any of the confirms.
*
* Note that the additional constructor allows for the creator to specify
* that there is an attachment already joined to the channel upon creation.
*/
PrivateChannel::PrivateChannel (
ChannelID channel_id,
UserID channel_manager,
PDomain local_provider,
PConnection top_provider,
CChannelList2 *channel_list,
CAttachmentList *attachment_list,
CUidList *admitted_list,
PConnection pConn)
:
Channel(channel_id, local_provider, top_provider, channel_list, attachment_list, pConn),
m_AuthorizedUserList(),
m_uidChannelManager(channel_manager),
m_fDisbandRequestPending(FALSE)
{
UserID uid;
/*
* Copy the initial contents of the admitted list into the authorized
* user list.
*/
admitted_list->Reset();
while (NULL != (uid = admitted_list->Iterate()))
{
m_AuthorizedUserList.Append(uid);
}
}
/*
* ~PrivateChannel ()
*
* Public
*
* Functional Description:
* This destructor walks through the admitted list, sending expel
* indications to any admitted users that are locally attached. If the
* channel manager is locally attached, and this channel is being deleted
* a reason other than a previous disband request, then a disband
* indication will be sent to the channel manager.
*/
PrivateChannel::~PrivateChannel ()
{
CAttachmentList local_attachment_list;
CAttachmentList remote_attachment_list;
CAttachment *pAtt;
CUidList user_id_list;
/*
* Assemble lists of the attachments that lead to authorized users in
* the sub-tree of this provider.
*/
BuildAttachmentLists (&m_AuthorizedUserList, &local_attachment_list,
&remote_attachment_list);
/*
* For each local attachment, issue a channel expel indication letting the
* user know that the channel is no longer valid.
*/
local_attachment_list.Reset();
while (NULL != (pAtt = local_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of the users
* that lie in the direction of that attachment.
*/
BuildUserIDList(&m_AuthorizedUserList, pAtt, &user_id_list);
/*
* Send the indication.
*/
pAtt->ChannelExpelIndication(Channel_ID, &user_id_list);
}
/*
* If the channel manager is a locally attached user, then send it a
* ChannelDisbandIndication informing it that the channel is no longer
* valid.
*/
if ((m_fDisbandRequestPending == FALSE) && ValidateUserID(m_uidChannelManager))
{
PChannel lpChannel;
if (NULL != (lpChannel = m_pChannelList2->Find(m_uidChannelManager)))
{
CAttachment *pAtt = lpChannel->GetAttachment();
if (m_pAttachmentList->Find(pAtt) && pAtt->IsUserAttachment())
{
PUser pUser = (PUser) pAtt;
pUser->ChannelDisbandIndication(Channel_ID);
}
}
}
/*
* Clear the lists associated with this object. Note that this also
* prevents the base class destructor from issuing ChannelLeaveIndications
* to any local attachments in the joined attachment list (which would be
* inappropriate).
*/
m_AuthorizedUserList.Clear();
m_JoinedAttachmentList.Clear();
}
/*
* Channel_Type GetChannelType ()
*
* Public
*
* Functional Description:
* Objects of this class are always private channels, so simply return
* PRIVATE_CHANNEL.
*/
Channel_Type PrivateChannel::GetChannelType ()
{
return (PRIVATE_CHANNEL);
}
/*
* BOOL IsValid ()
*
* Public
*
* Functional Description:
* By convention, if the m_uidChannelManager is in the sub-tree of this
* provider OR if there are any users in the authorized user list, then
* the private channel is valid. Otherwise it is not, and can be deleted
* by the domain object.
*/
BOOL PrivateChannel::IsValid ()
{
UserID uid;
CUidList deletion_list;
/*
* Loop through the authorized user list making a list of those entries
* that are no longer valid.
*/
m_AuthorizedUserList.Reset();
while (NULL != (uid = m_AuthorizedUserList.Iterate()))
{
if (ValidateUserID(uid) == FALSE)
deletion_list.Append(uid);
}
/*
* Loop through the deletion list created above, deleting those user IDs
* that are no longer valid.
*/
deletion_list.Reset();
while (NULL != (uid = deletion_list.Iterate()))
{
m_AuthorizedUserList.Remove(uid);
}
/*
* If this is the Top Provider, then the channel manager should ALWAYS be
* in the sub-tree. If it is not, then this indicates that the channel
* manager has detached (willingly or otherwise). When this happens it
* is necessary to simulate a channel disband request (only if there are
* other admitted users who need to receive a channel expel indication).
*/
if ((m_pConnToTopProvider == NULL) &&
(ValidateUserID(m_uidChannelManager) == FALSE) &&
(m_AuthorizedUserList.IsEmpty() == FALSE))
{
TRACE_OUT (("PrivateChannel::IsValid: "
"simulating ChannelDisbandRequest"));
ChannelDisbandRequest(NULL, m_uidChannelManager, Channel_ID);
}
/*
* Check to see if the channel manager is in the sub-tree of this provider
* or if the authorized user list is not empty. If either is TRUE, then
* then the channel is still valid.
*/
return (ValidateUserID(m_uidChannelManager) || (m_AuthorizedUserList.IsEmpty() == FALSE));
}
/*
* CAttachment *GetAttachment ()
*
* Public
*
* Functional Description:
* Return a pointer to the attachment leading to the channel manager.
*/
CAttachment *PrivateChannel::GetAttachment(void)
{
if (ValidateUserID(m_uidChannelManager))
{
PChannel lpChannel;
if (NULL != (lpChannel = m_pChannelList2->Find(m_uidChannelManager)))
{
return lpChannel->GetAttachment();
}
}
return NULL;
}
/*
* Void IssueMergeRequest ()
*
* Public
*
* Functional Description:
* Issue a merge request for the information contained in this
* PrivateChannel object.
*/
Void PrivateChannel::IssueMergeRequest ()
{
ChannelAttributes channel_attributes;
CChannelAttributesList merge_channel_list;
CChannelIDList purge_channel_list;
if (m_pConnToTopProvider != NULL)
{
/*
* Fill in the fields of the channel attributes structure so that it
* accurately describes this channel. Then put the structure into the
* merge channel list.
*/
channel_attributes.channel_type = PRIVATE_CHANNEL;
if (m_JoinedAttachmentList.IsEmpty() )
channel_attributes.u.private_channel_attributes.joined = FALSE;
else
channel_attributes.u.private_channel_attributes.joined = TRUE;
channel_attributes.u.private_channel_attributes.channel_id = Channel_ID;
channel_attributes.u.private_channel_attributes.channel_manager = m_uidChannelManager;
channel_attributes.u.private_channel_attributes.admitted_list = &m_AuthorizedUserList;
merge_channel_list.Append(&channel_attributes);
/*
* Send the merge request to the indicated provider.
*/
m_pConnToTopProvider->MergeChannelsRequest(&merge_channel_list, &purge_channel_list);
}
}
/*
* Void ChannelJoinRequest ()
*
* Public
*
* Functional Description:
* This function overrides the base class implementation. The main
* difference is that this implementation only allows a user to join
* the private channel if it is either the channel manager or in the
* authorized user list.
*/
Void PrivateChannel::ChannelJoinRequest (
CAttachment *pOrigAtt,
UserID uidInitiator,
ChannelID channel_id)
{
/*
* See if the requesting user is either the channel manager or in the
* authorized user list.
*/
if ((uidInitiator == m_uidChannelManager) || m_AuthorizedUserList.Find(uidInitiator))
{
/*
* See if anyone is currently joined to the channel in this sub-tree
*/
if (m_JoinedAttachmentList.IsEmpty())
{
/*
* If this is the Top Provider, then this request can be handled
* locally.
*/
if (IsTopProvider())
{
/*
* There is no one in this sub-tree joined to the channel. It
* will therefore be necessary to add the originator to the
* attachment list.
*/
TRACE_OUT (("PrivateChannel::ChannelJoinRequest: "
"user %04X joining private channel = %04X",
(UINT) uidInitiator, (UINT) Channel_ID));
m_JoinedAttachmentList.Append(pOrigAtt);
/*
* Send a ChannelJoinConfirm downward to the originator.
*/
pOrigAtt->ChannelJoinConfirm(RESULT_SUCCESSFUL, uidInitiator, channel_id, Channel_ID);
}
else
{
/*
* This is not the Top Provider. Forward the join request
* upward to the Top Provider.
*/
TRACE_OUT (("PrivateChannel::ChannelJoinRequest: "
"forwarding join request to Top Provider"));
m_pConnToTopProvider->ChannelJoinRequest(uidInitiator, Channel_ID);
}
}
/*
* There is at least one attachment joined to the channel, which means
* that we do not have to forward the join request upward (even if
* this is not the Top Provider). Now check to see if the requesting
* originator is already joined to the channel.
*/
else if (m_JoinedAttachmentList.Find(pOrigAtt) == FALSE)
{
/*
* The originator is not yet joined to the channel, so add it to
* the channel.
*/
TRACE_OUT (("PrivateChannel::ChannelJoinRequest: "
"user %04X joining private channel = %04X",
(UINT) uidInitiator, (UINT) Channel_ID));
m_JoinedAttachmentList.Append(pOrigAtt);
/*
* Send a ChannelJoinConfirm downward to the originator.
*/
pOrigAtt->ChannelJoinConfirm(RESULT_SUCCESSFUL, uidInitiator, channel_id, Channel_ID);
}
else
{
/*
* The originator is already joined to the channel. Go ahead and
* issue a successful channel join confirm.
*/
WARNING_OUT (("PrivateChannel::ChannelJoinRequest: "
"already joined to channel"));
pOrigAtt->ChannelJoinConfirm(RESULT_SUCCESSFUL, uidInitiator, channel_id, Channel_ID);
}
}
else
{
/*
* Someone is trying to join a private channel that they are not
* admitted to. Reject the request without further processing.
*/
WARNING_OUT (("PrivateChannel::ChannelJoinRequest: "
"rejecting attempt to join private channel"));
pOrigAtt->ChannelJoinConfirm(RESULT_NOT_ADMITTED, uidInitiator, channel_id, 0);
}
}
/*
* Void ChannelDisbandRequest ()
*
* Public
*
* Functional Description:
* This MCS command is initially sent by a user that wishes to disband a
* private channel that it previously created. If the requesting user is
* the private channel manager, then the request will be processed. If
* this is not the Top Provider, the request will be forwarded upward.
*/
Void PrivateChannel::ChannelDisbandRequest (
CAttachment *,
UserID uidInitiator,
ChannelID)
{
CUidList user_id_list;
/*
* Check to see if the requesting user is the channel manager. Only
* process the request if it is.
*/
if (uidInitiator == m_uidChannelManager)
{
/*
* See if this is the Top Provider. If it is, then the request can
* be processed locally. Otherwise, pass the request upward toward
* the Top Provider.
*/
if (IsTopProvider())
{
CAttachmentList local_attachment_list;
CAttachmentList remote_attachment_list;
CAttachment *pAtt;
TRACE_OUT (("PrivateChannel::ChannelDisbandRequest: "
"disbanding channel = %04X", Channel_ID));
/*
* Go construct lists of the current unique local and remote
* attachments. These lists will be used to transmit the proper
* channel expel and channel disband indications.
*/
BuildAttachmentLists (&m_AuthorizedUserList, &local_attachment_list,
&remote_attachment_list);
/*
* It is also necessary to send the disband indication to the
* channel manager, if it is valid and in the sub-tree of this
* provider. Determine what attachment leads to the channel
* manager, and make sure that attachment is in the remote
* attachment list, if valid.
*/
if (ValidateUserID(m_uidChannelManager))
{
PChannel lpChannel;
if (NULL != (lpChannel = m_pChannelList2->Find(m_uidChannelManager)))
{
pAtt = lpChannel->GetAttachment();
if (m_pAttachmentList->Find(pAtt) && pAtt->IsConnAttachment())
{
if (remote_attachment_list.Find(pAtt) == FALSE)
{
remote_attachment_list.Append(pAtt);
}
}
}
else
{
ERROR_OUT(("PrivateChannel::ChannelDisbandRequest: can't locate channel"));
}
}
/*
* Loop through the local attachment list sending channel expel
* indications to each attachment contained therein.
*/
local_attachment_list.Reset();
while (NULL != (pAtt = local_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&m_AuthorizedUserList, pAtt, &user_id_list);
/*
* Send the expel indication to the locally attached user.
*/
pAtt->ChannelExpelIndication(Channel_ID, &user_id_list);
}
/*
* Loop through the remote attachment list sending channel disband
* indications to each attachment contained therein.
*/
remote_attachment_list.Reset();
while (NULL != (pAtt = remote_attachment_list.Iterate()))
{
/*
* Send the disband indication to the remotely attached
* provider.
*/
pAtt->ChannelDisbandIndication(Channel_ID);
}
/*
* Set m_uidChannelManager to 0 and clear the authorized user list as
* an indicator that this private channel object is no longer
* valid, and cannot be used. The next time the domain object
* calls IsValid, it will return FALSE allowing the domain object
* to delete this object.
*/
m_uidChannelManager = 0;
m_AuthorizedUserList.Clear();
}
else
{
/*
* Set a flag indicating that a disband request has been sent
* upward. This flag will be used to prevent a disband indication
* from being sent to the channel manager as it flows back down
* the domain tree.
*/
m_fDisbandRequestPending = TRUE;
/*
* This is not the Top Provider, so forward the request toward
* the Top Provider. This will result in a channel disband
* indication at a future time.
*/
TRACE_OUT (("PrivateChannel::ChannelDisbandRequest: "
"forwarding request to Top Provider"));
m_pConnToTopProvider->ChannelDisbandRequest(uidInitiator, Channel_ID);
}
}
else
{
/*
* Someone is trying to disband a private channel that they are not
* the channel manager for. Ignore the request.
*/
WARNING_OUT (("PrivateChannel::ChannelDisbandRequest: "
"ignoring request from non-channel manager"));
}
}
/*
* Void ChannelDisbandIndication ()
*
* Public
*
* Functional Description:
* This MCS command is initially sent by the Top Provider when it decides
* to delete a private channel from the domain. It travels downward to
* all attachments and connections that contain an admitted user or the
* channel manager in their sub-tree.
*/
Void PrivateChannel::ChannelDisbandIndication (
ChannelID)
{
CAttachmentList local_attachment_list;
CAttachmentList remote_attachment_list;
CAttachment *pAtt;
CUidList user_id_list;
TRACE_OUT (("PrivateChannel::ChannelDisbandIndication: "
"disbanding channel = %04X", Channel_ID));
/*
* Build the lists of unique local and remote attachments. These lists
* will be used to issue the appropriate indications.
*/
BuildAttachmentLists (&m_AuthorizedUserList, &local_attachment_list,
&remote_attachment_list);
/*
* It is also necessary to send the disband indication to the channel
* manager, if it is valid and in the sub-tree of this provider.
* Determine what attachment leads to the channel manager, and make sure
* that attachment is in the remote attachment list, if valid.
*/
if (ValidateUserID(m_uidChannelManager))
{
PChannel lpChannel;
if (NULL != (lpChannel = m_pChannelList2->Find(m_uidChannelManager)))
{
pAtt = lpChannel->GetAttachment();
if ((m_fDisbandRequestPending == FALSE) ||
(m_pAttachmentList->Find(pAtt) && pAtt->IsConnAttachment()))
{
if (remote_attachment_list.Find(pAtt) == FALSE)
{
remote_attachment_list.Append(pAtt);
}
}
}
else
{
ERROR_OUT(("PrivateChannel::ChannelDisbandIndication: can't locate channel"));
}
}
/*
* Loop through the local attachment list sending channel expel indications
* to each attachment contained therein.
*/
local_attachment_list.Reset();
while (NULL != (pAtt = local_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&m_AuthorizedUserList, pAtt, &user_id_list);
/*
* Send the expel indication to the locally attached user.
*/
pAtt->ChannelExpelIndication(Channel_ID, &user_id_list);
}
/*
* Loop through the remote attachment list sending channel disband
* indications to each attachment contained therein.
*/
remote_attachment_list.Reset();
while (NULL != (pAtt = remote_attachment_list.Iterate()))
{
/*
* Send the disband indication to the remotely attached provider.
*/
pAtt->ChannelDisbandIndication(Channel_ID);
}
/*
* Set m_uidChannelManager to 0 and clear the authorized user list as an
* indicator that this private channel object is no longer valid, and
* cannot be used. The next time the domain object calls IsValid, it will
* return FALSE allowing the domain object to delete this object.
*/
m_uidChannelManager = 0;
m_AuthorizedUserList.Clear();
}
/*
* Void ChannelAdmitRequest ()
*
* Public
*
* Functional Description:
* This MCS command is initially sent by the manager of a private channel
* when it wishes to expand the authorized user list of that channel. If
* this is the Top Provider, then the request can be handled locally.
* Otherwise, it must be forwarded upward to the Top Provider.
*/
Void PrivateChannel::ChannelAdmitRequest (
CAttachment *,
UserID uidInitiator,
ChannelID,
CUidList *user_id_list)
{
UserID uid;
CUidList admitted_id_list;
CUidList user_id_subset;
/*
* Check to see if the requesting user is the channel manager. Only
* process the request if it is.
*/
if (uidInitiator == m_uidChannelManager)
{
/*
* See if this is the Top Provider. If it is, then the request can
* be processed locally. Otherwise, pass the request upward toward
* the Top Provider.
*/
if (IsTopProvider())
{
CAttachmentList local_attachment_list;
CAttachmentList remote_attachment_list;
CAttachment *pAtt;
TRACE_OUT (("PrivateChannel::ChannelAdmitRequest: "
"admitting users to channel = %04X", Channel_ID));
/*
* Iterate through the list of users to be admitted, adding all
* valid users to the local authorized user list.
*/
user_id_list->Reset();
while (NULL != (uid = user_id_list->Iterate()))
{
/*
* Make sure that the user ID corresponds to a valid user in
* the domain.
*/
if (ValidateUserID(uid))
{
/*
* If the user is not already in the authorized user list,
* then add it.
*/
if (m_AuthorizedUserList.Find(uid) == FALSE)
{
m_AuthorizedUserList.Append(uid);
admitted_id_list.Append(uid);
}
}
}
/*
* Build lists of unique attachments which can then be used to
* issue the appropriate admit indications. This prevents the
* transmission of an admit indication to the same attachment more
* than once.
*/
BuildAttachmentLists (&admitted_id_list, &local_attachment_list,
&remote_attachment_list);
/*
* Iterate through the local attachment list issuing an admit
* indication to each attachment contained therein.
*/
local_attachment_list.Reset();
while (NULL != (pAtt = local_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&admitted_id_list, pAtt, &user_id_subset);
/*
* Send the admit indication to the named attachment.
*/
pAtt->ChannelAdmitIndication(uidInitiator, Channel_ID, &user_id_subset);
}
/*
* Iterate through the remote attachment list issuing an admit
* indication to each attachment contained therein.
*/
remote_attachment_list.Reset();
while (NULL != (pAtt = remote_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&admitted_id_list, pAtt, &user_id_subset);
/*
* Send the admit indication to the named attachment.
*/
pAtt->ChannelAdmitIndication(uidInitiator, Channel_ID, &user_id_subset);
}
}
else
{
/*
* This is not the Top Provider, so forward the request toward
* the Top Provider. This will result in a channel admit
* indication at a future time.
*/
TRACE_OUT (("PrivateChannel::ChannelAdmitRequest: "
"forwarding request to Top Provider"));
m_pConnToTopProvider->ChannelAdmitRequest(uidInitiator, Channel_ID, user_id_list);
}
}
else
{
/*
* Someone is trying to admit users to a private channel that they are
* not the channel manager for. Ignore the request.
*/
WARNING_OUT (("PrivateChannel::ChannelAdmitRequest: "
"ignoring request from non-channel manager"));
}
}
/*
* Void ChannelAdmitIndication ()
*
* Public
*
* Functional Description:
* This MCS command is initially sent by the Top Provider when it receives
* a channel admit indication from the manager of a private channel. This
* indication is broadcast downward to all providers that contain an
* admitted user somewhere in their sub-tree. A side-effect of this
* indication is that a private channel will be created in the information
* base if one does not already exist.
*/
Void PrivateChannel::ChannelAdmitIndication (
PConnection,
UserID uidInitiator,
ChannelID,
CUidList *user_id_list)
{
UserID uid;
CUidList admitted_id_list;
CAttachmentList local_attachment_list;
CAttachmentList remote_attachment_list;
CAttachment *pAtt;
CUidList user_id_subset;
TRACE_OUT (("PrivateChannel::ChannelAdmitIndication: "
"admitting users to channel = %04X", (UINT) Channel_ID));
/*
* Iterate through the list of users to be admitted, adding all
* valid users to the local authorized user list.
*/
user_id_list->Reset();
while (NULL != (uid = user_id_list->Iterate()))
{
/*
* Make sure that the user ID corresponds to a valid user in
* the domain.
*/
if (ValidateUserID(uid))
{
/*
* If the user is not already in the authorized user list,
* then add it.
*/
if (m_AuthorizedUserList.Find(uid) == FALSE)
{
m_AuthorizedUserList.Append(uid);
admitted_id_list.Append(uid);
}
}
}
/*
* Build lists of unique attachments which can then be used to
* issue the appropriate admit indications. This prevents the
* transmission of an admit indication to the same attachment more
* than once.
*/
BuildAttachmentLists (&admitted_id_list, &local_attachment_list,
&remote_attachment_list);
/*
* Iterate through the local attachment list issuing an admit
* indication to each attachment contained therein.
*/
local_attachment_list.Reset();
while (NULL != (pAtt = local_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&admitted_id_list, pAtt, &user_id_subset);
/*
* Send the admit indication to the named attachment.
*/
pAtt->ChannelAdmitIndication(uidInitiator, Channel_ID, &user_id_subset);
}
/*
* Iterate through the remote attachment list issuing an admit
* indication to each attachment contained therein.
*/
remote_attachment_list.Reset();
while (NULL != (pAtt = remote_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&admitted_id_list, pAtt, &user_id_subset);
/*
* Send the admit indication to the named attachment.
*/
pAtt->ChannelAdmitIndication(uidInitiator, Channel_ID, &user_id_subset);
}
}
/*
* Void ChannelExpelRequest ()
*
* Public
*
* Functional Description:
* This MCS command is initially sent by the manager of a private channel
* when it wishes to shrink the authorized user list of that channel. If
* the channel is in the local information base, the request is sent to it.
* Otherwise, the request is ignored.
*/
Void PrivateChannel::ChannelExpelRequest (
CAttachment *,
UserID uidInitiator,
ChannelID,
CUidList *user_id_list)
{
UserID uid;
CUidList expelled_id_list;
CUidList user_id_subset;
/*
* Check to see if the requesting user is the channel manager. Only
* process the request if it is.
*/
if (uidInitiator == m_uidChannelManager)
{
/*
* See if this is the Top Provider. If it is, then the request can
* be processed locally. Otherwise, pass the request upward toward
* the Top Provider.
*/
if (m_pConnToTopProvider == NULL)
{
CAttachmentList local_attachment_list;
CAttachmentList remote_attachment_list;
CAttachment *pAtt;
TRACE_OUT (("PrivateChannel::ChannelExpelRequest: "
"expelling users from channel = %04X", Channel_ID));
/*
* Iterate through the list of users to be expelled, removing all
* valid users from the local authorized user list.
*/
user_id_list->Reset();
while (NULL != (uid = user_id_list->Iterate()))
{
/*
* If the user is in the authorized user list, then remove it.
*/
if (m_AuthorizedUserList.Find(uid))
{
m_AuthorizedUserList.Remove(uid);
expelled_id_list.Append(uid);
}
}
/*
* Build lists of unique attachments which can then be used to
* issue the appropriate expel indications. This prevents the
* transmission of an expel indication to the same attachment more
* than once.
*/
BuildAttachmentLists (&expelled_id_list, &local_attachment_list,
&remote_attachment_list);
/*
* Iterate through the local attachment list issuing an expel
* indication to each attachment contained therein.
*/
local_attachment_list.Reset();
while (NULL != (pAtt = local_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&expelled_id_list, pAtt, &user_id_subset);
/*
* Send the expel indication to the named attachment.
*/
pAtt->ChannelExpelIndication(Channel_ID, &user_id_subset);
/*
* Since this is a locally attached user, it is necessary to
* simulate a channel leave request from the user, indicating
* the fact that it can no longer use the channel.
*/
ChannelLeaveRequest(pAtt, (CChannelIDList *) &user_id_subset);
}
/*
* Iterate through the remote attachment list issuing an expel
* indication to each attachment contained therein.
*/
remote_attachment_list.Reset();
while (NULL != (pAtt = remote_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&expelled_id_list, pAtt, &user_id_subset);
/*
* Send the expel indication to the named attachment.
*/
pAtt->ChannelExpelIndication(Channel_ID, &user_id_subset);
}
}
else
{
/*
* This is not the Top Provider, so forward the request toward
* the Top Provider. This will result in a channel expel
* indication at a future time.
*/
TRACE_OUT (("PrivateChannel::ChannelExpelRequest: "
"forwarding request to Top Provider"));
m_pConnToTopProvider->ChannelExpelRequest(uidInitiator, Channel_ID, user_id_list);
}
}
else
{
/*
* Someone is trying to admit users to a private channel that they are
* not the channel manager for. Ignore the request.
*/
WARNING_OUT (("PrivateChannel::ChannelExpelRequest: "
"ignoring request from non-channel manager"));
}
}
/*
* Void ChannelExpelIndication ()
*
* Public
*
* Functional Description:
* This MCS command is initially sent by the Top Provider when it receives
* a request from the manager of a private channel to reduce the
* authorized user list. It travels downward to all attachments and
* connections that contain an admitted user or the channel manager in
* their sub-tree.
*/
Void PrivateChannel::ChannelExpelIndication (
PConnection,
ChannelID,
CUidList *user_id_list)
{
UserID uid;
CUidList expelled_id_list;
CAttachmentList local_attachment_list;
CAttachmentList remote_attachment_list;
CAttachment *pAtt;
CUidList user_id_subset;
TRACE_OUT (("PrivateChannel::ChannelExpelIndication: "
"expelling users from channel = %04X", Channel_ID));
/*
* Iterate through the list of users to be expelled, removing all
* valid users from the local authorized user list.
*/
user_id_list->Reset();
while (NULL != (uid = user_id_list->Iterate()))
{
/*
* If the user is in the authorized user list, then remove it.
*/
if (m_AuthorizedUserList.Find(uid))
{
m_AuthorizedUserList.Remove(uid);
expelled_id_list.Append(uid);
}
}
/*
* Build lists of unique attachments which can then be used to
* issue the appropriate expel indications. This prevents the
* transmission of an expel indication to the same attachment more
* than once.
*/
BuildAttachmentLists (&expelled_id_list, &local_attachment_list,
&remote_attachment_list);
/*
* Iterate through the local attachment list issuing an expel
* indication to each attachment contained therein.
*/
local_attachment_list.Reset();
while (NULL != (pAtt = local_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&expelled_id_list, pAtt, &user_id_subset);
/*
* Send the expel indication to the named attachment.
*/
pAtt->ChannelExpelIndication(Channel_ID, &user_id_subset);
/*
* Since this is a locally attached user, it is necessary to
* simulate a channel leave request from the user, indicating
* the fact that it can no longer use the channel.
*/
ChannelLeaveRequest(pAtt, (CChannelIDList *) &user_id_subset);
}
/*
* Iterate through the remote attachment list issuing an expel
* indication to each attachment contained therein.
*/
remote_attachment_list.Reset();
while (NULL != (pAtt = remote_attachment_list.Iterate()))
{
/*
* Get the next attachment from the list and build a list of
* the users that lie in the direction of that attachment.
*/
BuildUserIDList(&expelled_id_list, pAtt, &user_id_subset);
/*
* Send the expel indication to the named attachment.
*/
pAtt->ChannelExpelIndication(Channel_ID, &user_id_subset);
}
}
/*
* Void SendDataRequest ()
*
* Public
*
* Functional Description:
* This MCS command is initially sent by a user that wishes to send data
* to other users who are joined to a specified channel. This routine
* is executed in the case that it is a private channel. It verifies
* that the user is authorized to use the channel before allowing the data
* to be sent.
*/
Void PrivateChannel::SendDataRequest (
CAttachment *pOrigAtt,
UINT type,
PDataPacket data_packet)
{
UserID uidInitiator;
uidInitiator = data_packet->GetInitiator();
if ((uidInitiator == m_uidChannelManager) || m_AuthorizedUserList.Find(uidInitiator))
{
/*
* The channel usage is authorized, so forward the request to the
* base class implementation for processing.
*/
Channel::SendDataRequest(pOrigAtt, type, data_packet);
}
else
{
/*
* Someone is trying to send data on a private channel that they are
* not authorized to use. Ignore the request.
*/
WARNING_OUT (("PrivateChannel::SendDataRequest: "
"ignoring request from non-authorized user"));
}
}
/*
* BOOL ValidateUserID ()
*
* Private
*
* Functional Description:
* This function is called whenever another member function of this class
* wants to check and see if a specified user is still valid in the
* domain channel list.
*
* Formal Parameters:
* user_id (i)
* This is the ID of the user being checked out.
*
* Return Value:
* TRUE if the user is valid. FALSE otherwise.
*
* Side Effects:
* None.
*/
BOOL PrivateChannel::ValidateUserID (
UserID user_id)
{
PChannel channel;
/*
* First check to see if the user ID is in the channel list at all. This
* prevents an attempt to read an invalid entry from the dictionary.
*/
if (NULL != (channel = m_pChannelList2->Find(user_id)))
{
/*
* We know that the ID is in the dictionary, but we don't know for sure
* whether or not it is a user ID channel. So check this. If it is a
* user channel, then set the valid flag to TRUE.
*/
if (channel->GetChannelType () == USER_CHANNEL)
return TRUE;
}
return FALSE;
}
/*
* Void BuildAttachmentLists ()
*
* Private
*
* Functional Description:
* This function is called upon to build a list of unique attachments that
* lead to the users in the specified list. It builds two attachment
* lists. The first has an entry for each unique local attachment. The
* second for each remote attachment. The key to each list is the
* attachment.
*
* Formal Parameters:
* user_id_list (i)
* This is the list of users for which the list is to be built.
* local_attachment_list (i)
* This is the dictionary that is to contain the list of unique
* local attachments.
* remote_attachment_list (i)
* This is the dictionary that is to contain the list of unique
* remote attachments.
*
* Return Value:
* None.
*
* Side Effects:
* None.
*/
Void PrivateChannel::BuildAttachmentLists (
CUidList *user_id_list,
CAttachmentList *local_attachment_list,
CAttachmentList *remote_attachment_list)
{
UserID uid;
/*
* Loop through the passed in user ID list building a dictionary of local
* attachments (those leading to locally attached users) and a dictionary
* of remote attachments (those leading to remotely connected providers).
* These dictionaries will be used by this provider to issue various
* indications downward, without sending multiple indications to the same
* attachment.
*/
user_id_list->Reset();
while (NULL != (uid = user_id_list->Iterate()))
{
/*
* Check to see if the user ID refers to a valid user in the sub-tree
* of this provider.
*/
if (ValidateUserID(uid))
{
PChannel lpChannel;
/*
* Determine which attachment leads to the user in question.
*/
if (NULL != (lpChannel = m_pChannelList2->Find(uid)))
{
CAttachment *pAtt = lpChannel->GetAttachment();
/*
* This module builds separate lists for those users that are
* attached locally and those attached remotely.
*/
if (m_pAttachmentList->Find(pAtt))
{
if (pAtt->IsUserAttachment())
{
/*
* This attachment is a local one (meaning that it leads to a
* locally attached user, rather than another MCS provider).
* Check to see if this attachment has already been put into
* the dictionary while processing a previous user ID.
*/
if (local_attachment_list->Find(pAtt) == FALSE)
local_attachment_list->Append(pAtt);
}
else
{
/*
* This attachment is a remote one (meaning that it leads to
* another MCS provider, rather than a locally attached user).
* Check to see if this attachment has already been put into
* the dictionary while processing a previous user ID.
*/
if (remote_attachment_list->Find(pAtt) == FALSE)
remote_attachment_list->Append(pAtt);
}
}
else
{
ERROR_OUT(("PrivateChannel::BuildAttachmentLists: can't find this attachment=0x%p", pAtt));
}
}
else
{
ERROR_OUT(("PrivateChannel::BuildAttachmentLists: can't locate channel"));
}
}
else
{
/*
* This user ID does not correspond to a valid user in the sub-tree
* of this provider. Therefore, discard the ID.
*/
ERROR_OUT (("PrivateChannel::BuildAttachmentLists: "
"ERROR - user ID not valid"));
}
}
}
/*
* Void BuildUserIDList ()
*
* Private
*
* Functional Description:
* This function is called upon to build a list of all users in the
* specified list that are in the direction of the specified attachment.
*
* Formal Parameters:
* user_id_list (i)
* This is the list of users for which the list is to be built.
* attachment (i)
* This is the attachment that the caller wishes to have a list of
* user IDs for.
* user_id_subset (o)
* This is the subset of the passed in user IDs that are in the
* direction of the specified attachment.
*
* Return Value:
* None.
*
* Side Effects:
* None.
*/
Void PrivateChannel::BuildUserIDList (
CUidList *user_id_list,
CAttachment *pAtt,
CUidList *user_id_subset)
{
UserID uid;
/*
* Clear out the subset list, so that we start fresh.
*/
user_id_subset->Clear();
/*
* Loop through the specified user list, checking to see which users
* lie in the direction of the specified attachment.
*/
user_id_list->Reset();
while (NULL != (uid = user_id_list->Iterate()))
{
/*
* Check to see if the user ID refers to a valid user in the sub-tree
* of this provider.
*/
if (ValidateUserID(uid))
{
PChannel lpChannel;
/*
* Check to see if this user is the direction of the specified
* attachment. If it is, then put it into the user ID subset that
* we are building.
*/
if (NULL != (lpChannel = m_pChannelList2->Find(uid)))
{
if (lpChannel->GetAttachment () == pAtt)
user_id_subset->Append(uid);
}
else
{
ERROR_OUT(("PrivateChannel::BuildUserIDList: can't locate channel"));
}
}
else
{
/*
* This user ID does not correspond to a valid user in the sub-tree
* of this provider. Therefore, discard the ID.
*/
ERROR_OUT (("PrivateChannel::BuildUserIDList: "
"ERROR - user ID not valid"));
}
}
}