mirror of https://github.com/tongzx/nt5src
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.
2109 lines
53 KiB
2109 lines
53 KiB
#include "precomp.h"
|
|
#include "fsdiag.h"
|
|
DEBUG_FILEZONE(ZONE_T120_MCSNC);
|
|
/*
|
|
* token.cpp
|
|
*
|
|
* Copyright (c) 1993 - 1995 by DataBeam Corporation, Lexington, KY
|
|
*
|
|
* Abstract:
|
|
* This is the implementation file for the Token class. It contains all
|
|
* code necessary to implement tokens as defined in the MCS specification.
|
|
*
|
|
* Whenever a user allocates a token (by grabbing or inhibiting it), one
|
|
* of these objects is created (if domain parameters allow it). This
|
|
* object then handles all requests related to that token ID. It also
|
|
* issues confirms back to the originators of those requests.
|
|
*
|
|
* This class includes code to maintain a list of user IDs that
|
|
* correspond to the current "owners" of the token. A user is said to
|
|
* own a token if it has it grabbed or inhibited. This code implements
|
|
* the rules concerning who can grab or inhibit tokens at any given
|
|
* time (which is affected by current state).
|
|
*
|
|
* This class also contains the code that allows a current grabber of
|
|
* the token to give it away to another user in the domain.
|
|
*
|
|
* This class also includes code to merge itself upward during a domain
|
|
* merge operation.
|
|
*
|
|
* Private Instance Variables:
|
|
* Token_ID
|
|
* This is the token ID for the token that this object represents.
|
|
* m_pDomain
|
|
* This is a pointer to the local provider (the domain that owns this
|
|
* token). This field is used when a command is issued on behalf of
|
|
* this provider.
|
|
* m_pConnToTopProvider
|
|
* This is the top provider of the current domain.
|
|
* m_pChannelList2
|
|
* This is the channel list that is maintained by the domain. It is
|
|
* used by this class to perform validation of user IDs.
|
|
* m_pAttachmentList
|
|
* This is the attachment list that is maintained by the domain. It is
|
|
* used by this class to determine what users are locally attached,
|
|
* when it becomes necessary to send certain indications.
|
|
* Token_State
|
|
* This contains the current state of the token, which will be one of
|
|
* the following: available; grabbed; inhibited; giving; or given.
|
|
* m_uidGrabber
|
|
* This is the user that current has the token grabbed. This variable
|
|
* is only valid in the grabbed and giving states.
|
|
* m_InhibitorList
|
|
* This is a list of users that have the token inhibited. This
|
|
* list is only valid when the token is in the inhibited state.
|
|
* m_uidRecipient
|
|
* This is the user to whom the token is being given. This variable
|
|
* is only valid in the giving or given states.
|
|
*
|
|
* Private Member Functions:
|
|
* ValidateUserID
|
|
* This function is used to verify that a specified user is valid in
|
|
* the sub-tree of the local provider.
|
|
* GetUserAttachment
|
|
* This function is used to determine which attachment leads to a
|
|
* particular attachment.
|
|
* IssueTokenReleaseIndication
|
|
* This function is used to issue a token release indication to a
|
|
* specified user. It first checks to see if the user is locally
|
|
* attached, and if so, it sends the indication.
|
|
* BuildAttachmentList
|
|
* This function is used to build a list of unique attachments to
|
|
* send please indications to.
|
|
*
|
|
* Caveats:
|
|
* None.
|
|
*
|
|
* Author:
|
|
* James P. Galvin, Jr.
|
|
*/
|
|
|
|
/*
|
|
* External Interfaces
|
|
*/
|
|
|
|
#include "token.h"
|
|
|
|
|
|
/*
|
|
* Token ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is the constructor for the token class. It does nothing more than
|
|
* set the initial states of instance variables.
|
|
*/
|
|
Token::Token (
|
|
TokenID token_id,
|
|
PDomain local_provider,
|
|
PConnection top_provider,
|
|
CChannelList2 *channel_list,
|
|
CAttachmentList *attachment_list)
|
|
:
|
|
m_InhibitorList(),
|
|
Token_ID(token_id),
|
|
m_pDomain(local_provider),
|
|
m_pConnToTopProvider(top_provider),
|
|
m_pChannelList2(channel_list),
|
|
m_pAttachmentList(attachment_list),
|
|
Token_State(TOKEN_AVAILABLE)
|
|
{
|
|
/*
|
|
* Save all parameters in their associated instance variables for later
|
|
* use.
|
|
*/
|
|
|
|
/*
|
|
* Mark the token as available for use.
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* Token ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is an alternate constructor for the token class. It is used when
|
|
* creating a token during a merge operation. It accepts a current state
|
|
* as well as a list of current owners as parameters.
|
|
*/
|
|
Token::Token (
|
|
TokenID token_id,
|
|
PDomain local_provider,
|
|
PConnection top_provider,
|
|
CChannelList2 *channel_list,
|
|
CAttachmentList *attachment_list,
|
|
TokenState token_state,
|
|
UserID grabber,
|
|
CUidList *inhibitor_list,
|
|
UserID recipient)
|
|
:
|
|
m_InhibitorList(),
|
|
Token_ID(token_id),
|
|
m_pDomain(local_provider),
|
|
m_pConnToTopProvider(top_provider),
|
|
m_pChannelList2(channel_list),
|
|
m_pAttachmentList(attachment_list),
|
|
Token_State(token_state)
|
|
{
|
|
UserID uid;
|
|
|
|
/*
|
|
* Save all parameters in their associated instance variables for later
|
|
* use.
|
|
*/
|
|
|
|
/*
|
|
* Indicate the current state of the token (as passed in).
|
|
*/
|
|
|
|
/*
|
|
* Depending on token state, copy the pertinent information into local
|
|
* instance variables.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
m_uidGrabber = grabber;
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
{
|
|
/*
|
|
* Add all user IDs in the inhibitor list to the local
|
|
* inhibitor list.
|
|
*/
|
|
inhibitor_list->Reset();
|
|
while (NULL != (uid = inhibitor_list->Iterate()))
|
|
{
|
|
m_InhibitorList.Append(uid);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
m_uidGrabber = grabber;
|
|
m_uidRecipient = recipient;
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
m_uidRecipient = recipient;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ~Token ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This is the token destructor. It iterates through its current owner
|
|
* list, issuing TokenReleaseIndications to any owners that correspond
|
|
* to locally attached users.
|
|
*/
|
|
Token::~Token ()
|
|
{
|
|
/*
|
|
* Depending on the current state of the token, release resources and
|
|
* issue release indications to all owners.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* Send a release indication to the grabber, if it is locally
|
|
* attached.
|
|
*/
|
|
IssueTokenReleaseIndication (m_uidGrabber);
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
{
|
|
UserID uid;
|
|
/*
|
|
* Iterate through the current inhibitor list, to make sure
|
|
* that everyone is properly informed of the demise of this
|
|
* token.
|
|
*/
|
|
m_InhibitorList.Reset();
|
|
while (NULL != (uid = m_InhibitorList.Iterate()))
|
|
{
|
|
IssueTokenReleaseIndication(uid);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* Send a release indication to the grabber, if it is locally
|
|
* attached.
|
|
*/
|
|
IssueTokenReleaseIndication (m_uidGrabber);
|
|
|
|
/*
|
|
* Send a release indication to the recipient, if it is locally
|
|
* attached. Note that this will not be sent in the case where
|
|
* the grabber and the recipient are one and the same. This
|
|
* prevents the sending of two release indications to the same
|
|
* user for the same token.
|
|
*/
|
|
if (m_uidGrabber != m_uidRecipient)
|
|
IssueTokenReleaseIndication (m_uidRecipient);
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* Send a release indication to the recipient, if it is locally
|
|
* attached.
|
|
*/
|
|
IssueTokenReleaseIndication (m_uidRecipient);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* BOOL IsValid ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function checks the validity of each of its owners. It then
|
|
* returns TRUE if there are any valid owners left. FALSE otherwise.
|
|
*/
|
|
BOOL Token::IsValid ()
|
|
{
|
|
BOOL valid;
|
|
|
|
/*
|
|
* We must check for the validity of this token. How this is checked for
|
|
* is a function of token state. So switch on the state.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* When a token is grabbed, the grabber must be in the sub-tree
|
|
* of the current provider. If this is not true, then mark the
|
|
* token as available (which will cause it to be deleted).
|
|
*/
|
|
if (ValidateUserID (m_uidGrabber) == FALSE)
|
|
Token_State = TOKEN_AVAILABLE;
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
{
|
|
UserID uid;
|
|
CUidList deletion_list;
|
|
/*
|
|
* Iterate through the current inhibitor list of this token,
|
|
* checking to make sure that each user is still valid. Each
|
|
* one that is not will be put into a deletion list (it is
|
|
* invalid to remove items from a list while using an iterator
|
|
* on the list).
|
|
*/
|
|
m_InhibitorList.Reset();
|
|
while (NULL != (uid = m_InhibitorList.Iterate()))
|
|
{
|
|
if (ValidateUserID(uid) == FALSE)
|
|
deletion_list.Append(uid);
|
|
}
|
|
|
|
/*
|
|
* Iterate through the deletion list that was built above,
|
|
* removing each contained user from the token's inhibitor
|
|
* list. These correspond to users that have detached from the
|
|
* domain for one reason or another.
|
|
*/
|
|
deletion_list.Reset();
|
|
while (NULL != (uid = deletion_list.Iterate()))
|
|
{
|
|
m_InhibitorList.Remove(uid);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check to see if there are any inhibitors left. If not, then
|
|
* we must change the state of the token to available (which will
|
|
* cause it to be deleted).
|
|
*/
|
|
if (m_InhibitorList.IsEmpty())
|
|
Token_State = TOKEN_AVAILABLE;
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* When a token is in the giving state, the recipient must be in
|
|
* the sub-tree of the current provider. If it is not, then the
|
|
* token MUST change state. The state it changes to depends on
|
|
* whether or not the grabber is in the sub-tree of the current
|
|
* provider.
|
|
*/
|
|
if (ValidateUserID (m_uidRecipient) == FALSE)
|
|
{
|
|
/*
|
|
* The recipient of the token is gone. Check to see if the
|
|
* grabber is in the sub-tree of this provider.
|
|
*/
|
|
if (ValidateUserID (m_uidGrabber) == FALSE)
|
|
{
|
|
/*
|
|
* The grabber is not in the sub-tree of this provider,
|
|
* meaning that the token is no longer valid.
|
|
*/
|
|
Token_State = TOKEN_AVAILABLE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The grabber is in the sub-tree of this provider, so the
|
|
* token state will transition back to grabbed.
|
|
*/
|
|
Token_State = TOKEN_GRABBED;
|
|
|
|
/*
|
|
* If this is the top provider, it is necessary to issue a
|
|
* give confirm to the grabber telling it that the give
|
|
* failed.
|
|
*/
|
|
if (m_pConnToTopProvider == NULL)
|
|
{
|
|
/*
|
|
* Find out what attachment leads to the current
|
|
* grabber of the token, and issue the appropriate
|
|
* token give confirm.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(m_uidGrabber);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenGiveConfirm(RESULT_NO_SUCH_USER, m_uidGrabber, Token_ID,
|
|
TOKEN_SELF_GRABBED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* When a token is in the given state, the recipient must be in
|
|
* the sub-tree of the current provider. If it is not, then the
|
|
* token is no longer valid, and should transition to the
|
|
* available state.
|
|
*/
|
|
if (ValidateUserID (m_uidRecipient) == FALSE)
|
|
Token_State = TOKEN_AVAILABLE;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Check to see if the token is still in use. If it is marked as
|
|
* available, then it is not, and we will return FALSE.
|
|
*/
|
|
if (Token_State != TOKEN_AVAILABLE)
|
|
valid = TRUE;
|
|
else
|
|
valid = FALSE;
|
|
|
|
return (valid);
|
|
}
|
|
|
|
/*
|
|
* Void IssueMergeRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function tells the token object to pack its state into a merge
|
|
* request and send it to the specified provider.
|
|
*/
|
|
Void Token::IssueMergeRequest ()
|
|
{
|
|
TokenAttributes merge_token;
|
|
CTokenAttributesList merge_token_list;
|
|
CTokenIDList purge_token_list;
|
|
|
|
if (m_pConnToTopProvider != NULL)
|
|
{
|
|
/*
|
|
* Check the state to make sure that the token really is in use. If
|
|
* the state is set to available, then do not issue a merge request.
|
|
*/
|
|
if (Token_State != TOKEN_AVAILABLE)
|
|
{
|
|
/*
|
|
* Fill in a token attributes structure to represent the state of
|
|
* this token. Then put it into the merge token list in
|
|
* preparation for issuing the merge request.
|
|
*/
|
|
merge_token.token_state = Token_State;
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_GRABBED:
|
|
merge_token.u.grabbed_token_attributes.token_id = Token_ID;
|
|
merge_token.u.grabbed_token_attributes.grabber = m_uidGrabber;
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
merge_token.u.inhibited_token_attributes.token_id =
|
|
Token_ID;
|
|
merge_token.u.inhibited_token_attributes.inhibitors =
|
|
&m_InhibitorList;
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
merge_token.u.giving_token_attributes.token_id = Token_ID;
|
|
merge_token.u.giving_token_attributes.grabber = m_uidGrabber;
|
|
merge_token.u.giving_token_attributes.recipient = m_uidRecipient;
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
merge_token.u.given_token_attributes.token_id = Token_ID;
|
|
merge_token.u.given_token_attributes.recipient = m_uidRecipient;
|
|
break;
|
|
}
|
|
merge_token_list.Append(&merge_token);
|
|
|
|
/*
|
|
* Send the resulting merge request to the indicated provider.
|
|
*/
|
|
m_pConnToTopProvider->MergeTokensRequest(&merge_token_list, &purge_token_list);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Report that the token is not in use, but do NOT send a merge
|
|
* request.
|
|
*/
|
|
TRACE_OUT(("Token::IssueMergeRequest: token not in use"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenGrabRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called when a user tries to grab a token. The request
|
|
* will either succeed or fail depending on the current state of the token.
|
|
* Either way, a confirm will be sent to the user originating the request.
|
|
*/
|
|
Void Token::TokenGrabRequest (
|
|
CAttachment *pOrigAtt,
|
|
UserID uidInitiator,
|
|
TokenID)
|
|
{
|
|
Result result;
|
|
TokenStatus token_status;
|
|
|
|
/*
|
|
* Check to see if this provider is the Top Provider. If so, then process
|
|
* this request here. Otherwise, forward the request upward.
|
|
*/
|
|
if (IsTopProvider())
|
|
{
|
|
/*
|
|
* Determine what state we are, which greatly affects how we process
|
|
* the request.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
/*
|
|
* Since the token is available, the request automatically
|
|
* succeeds. Change the state to grabbed, and mark the
|
|
* initiator as the grabber.
|
|
*/
|
|
Token_State = TOKEN_GRABBED;
|
|
m_uidGrabber = uidInitiator;
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_SELF_GRABBED;
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* If the token is already grabbed, then we must fail the
|
|
* request. However, we need to determine if the token is
|
|
* grabbed by the same user who is currently requesting it, or
|
|
* another user.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
if (uidInitiator == m_uidGrabber)
|
|
token_status = TOKEN_SELF_GRABBED;
|
|
else
|
|
token_status = TOKEN_OTHER_GRABBED;
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
/*
|
|
* If the token is inhibited, this request can still succeed if
|
|
* the only inhibitor is the user that is attempting to grab
|
|
* the token. Check to see if this is the case.
|
|
*/
|
|
if (m_InhibitorList.Find(uidInitiator))
|
|
{
|
|
if (m_InhibitorList.GetCount() == 1)
|
|
{
|
|
/*
|
|
* The user attempting to grab the token is the only
|
|
* inhibitor, so convert the state to grabbed.
|
|
*/
|
|
Token_State = TOKEN_GRABBED;
|
|
m_uidGrabber = uidInitiator;
|
|
m_InhibitorList.Clear();
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_SELF_GRABBED;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The token is inhibited by at least one other user,
|
|
* so the grab request must fail.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
token_status = TOKEN_SELF_INHIBITED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The token is not inhibited by the requestor, so it must
|
|
* be inhibited by someone else.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
token_status = TOKEN_OTHER_INHIBITED;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* If the token is in the process of being given from one to
|
|
* another, then a grab request must fail. All we need to
|
|
* figure out is the proper token status to report.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else if (uidInitiator == m_uidGrabber)
|
|
token_status = TOKEN_SELF_GIVING;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* If the token is in the process of being given from one to
|
|
* another, then a grab request must fail. All we need to
|
|
* figure out is the proper token status to report.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Issue the token grab confirm to the initiating user.
|
|
*/
|
|
pOrigAtt->TokenGrabConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Forward this request upward towards the Top Provider.
|
|
*/
|
|
TRACE_OUT(("Token::TokenGrabRequest: forwarding request to Top Provider"));
|
|
m_pConnToTopProvider->TokenGrabRequest(uidInitiator, Token_ID);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenGrabConfirm ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called as a part of sending a response to a user for
|
|
* a previous request. It tells the user the result of the request.
|
|
*/
|
|
Void Token::TokenGrabConfirm (
|
|
Result result,
|
|
UserID uidInitiator,
|
|
TokenID,
|
|
TokenStatus token_status)
|
|
{
|
|
/*
|
|
* Make sure that the initiator ID is valid, since we must forward this
|
|
* confirm in the direction of that user. If it is not valid, ignore
|
|
* this confirm.
|
|
*/
|
|
if (ValidateUserID(uidInitiator))
|
|
{
|
|
/*
|
|
* Check to see if this request was successful.
|
|
*/
|
|
if (result == RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
* Force this token to conform to the results of this confirm.
|
|
*/
|
|
Token_State = TOKEN_GRABBED;
|
|
m_uidGrabber = uidInitiator;
|
|
m_InhibitorList.Clear();
|
|
}
|
|
|
|
/*
|
|
* Determine what attachment leads to the initiator, and forward the
|
|
* confirm in that direction.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(uidInitiator);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenGrabConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The initiator is not in the sub-tree of this provider. So ignore
|
|
* this confirm.
|
|
*/
|
|
ERROR_OUT(("Token::TokenGrabConfirm: invalid initiator ID"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenInhibitRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called when a user tries to inhibit a token. The
|
|
* request will either succeed or fail depending on the current state of
|
|
* the token. Either way, a confirm will be sent to the user originating
|
|
* the request.
|
|
*/
|
|
Void Token::TokenInhibitRequest (
|
|
CAttachment *pOrigAtt,
|
|
UserID uidInitiator,
|
|
TokenID)
|
|
{
|
|
Result result;
|
|
TokenStatus token_status;
|
|
|
|
/*
|
|
* Check to see if this is the Top Provider.
|
|
*/
|
|
if (IsTopProvider())
|
|
{
|
|
/*
|
|
* Determine what state we are, which greatly affects how we process
|
|
* the request.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
/*
|
|
* Since the token is available, the request automatically
|
|
* succeeds. Set the token state to inhibited, and add the
|
|
* initiator to the list of inhibitors.
|
|
*/
|
|
Token_State = TOKEN_INHIBITED;
|
|
m_InhibitorList.Append(uidInitiator);
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_SELF_INHIBITED;
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* If the token is grabbed, this request can still succeed if
|
|
* the grabber is the user that is attempting to inhibit the
|
|
* token. Check to see if this is the case.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
{
|
|
/*
|
|
* The current grabber is attempting to convert the state
|
|
* of the token to inhibited. This is valid, so set the
|
|
* state appropriately.
|
|
*/
|
|
Token_State = TOKEN_INHIBITED;
|
|
m_InhibitorList.Append(uidInitiator);
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_SELF_INHIBITED;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The token is grabbed by someone else, so the inhibit
|
|
* request must fail.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
token_status = TOKEN_OTHER_GRABBED;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
/*
|
|
* The token is already inhibited, but this is okay. Add this
|
|
* user to the list of inhibitors (if it is not already there).
|
|
*/
|
|
if (m_InhibitorList.Find(uidInitiator) == FALSE)
|
|
m_InhibitorList.Append(uidInitiator);
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_SELF_INHIBITED;
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* If the token is in the process of being given from one to
|
|
* another, then an inhibit request must fail. All we need to
|
|
* figure out is the proper token status to report.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else if (uidInitiator == m_uidGrabber)
|
|
token_status = TOKEN_SELF_GIVING;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* If the token is in the process of being given from one to
|
|
* another, then an inhibit request must fail. All we need to
|
|
* figure out is the proper token status to report.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_AVAILABLE;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If the originator is NULL, then this inhibit request is happening as
|
|
* part of a merge operation, in which case we do NOT want to send a
|
|
* token inhibit confirm. Otherwise we do send one.
|
|
*/
|
|
if (pOrigAtt != NULL)
|
|
{
|
|
pOrigAtt->TokenInhibitConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Forward the request toward the top provider.
|
|
*/
|
|
TRACE_OUT(("Token::TokenInhibitRequest: forwarding request to Top Provider"));
|
|
m_pConnToTopProvider->TokenInhibitRequest(uidInitiator, Token_ID);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenInhibitConfirm ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called as a part of sending a response to a user for
|
|
* a previous request. It tells the user the result of the request.
|
|
*/
|
|
Void Token::TokenInhibitConfirm (
|
|
Result result,
|
|
UserID uidInitiator,
|
|
TokenID,
|
|
TokenStatus token_status)
|
|
{
|
|
/*
|
|
* Make sure that the initiator ID is valid, since we must forward this
|
|
* confirm in the direction of that user. If it is not valid, ignore
|
|
* this confirm.
|
|
*/
|
|
if (ValidateUserID (uidInitiator) )
|
|
{
|
|
/*
|
|
* Check to see if this request was successful.
|
|
*/
|
|
if (result == RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
* Force this token to conform to the results of this confirm.
|
|
*/
|
|
Token_State = TOKEN_INHIBITED;
|
|
if (m_InhibitorList.Find(uidInitiator) == FALSE)
|
|
m_InhibitorList.Append(uidInitiator);
|
|
}
|
|
|
|
/*
|
|
* Determine what attachment leads to the initiator, and issue the
|
|
* token confirm in that direction.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(uidInitiator);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenInhibitConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The initiator is not in the sub-tree of this provider. So ignore
|
|
* this confirm.
|
|
*/
|
|
ERROR_OUT(("Token::TokenInhibitConfirm: invalid initiator ID"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenGiveRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called when one user asks to give a token to another
|
|
* user.
|
|
*/
|
|
Void Token::TokenGiveRequest (
|
|
CAttachment *pOrigAtt,
|
|
PTokenGiveRecord pTokenGiveRec)
|
|
{
|
|
Result result;
|
|
TokenStatus token_status;
|
|
|
|
/*
|
|
* Check to see if this provider is the Top Provider. If so, then process
|
|
* this request here. Otherwise, forward the request upward.
|
|
*/
|
|
if (m_pConnToTopProvider == NULL)
|
|
{
|
|
UserID uidInitiator = pTokenGiveRec->uidInitiator;
|
|
UserID receiver_id = pTokenGiveRec->receiver_id;
|
|
/*
|
|
* Determine what state we are, which greatly affects how we process
|
|
* the request.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
/*
|
|
* The token is not in use, and therefore cannot be given by
|
|
* anyone to anyone. So fail this request.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
token_status = TOKEN_NOT_IN_USE;
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* Check to see if the requestor really is the grabber of this
|
|
* token.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
{
|
|
/*
|
|
* Check to see if the intended recipient is a valid user
|
|
* in the domain.
|
|
*/
|
|
if (ValidateUserID (receiver_id) )
|
|
{
|
|
/*
|
|
* Everything checks out. Set the result to success
|
|
* to disable transmission of the give confirm below.
|
|
* Change the state of the token to giving, and
|
|
* save the ID of the intended recipient. Then issue
|
|
* the give indication toward the recipient.
|
|
*/
|
|
result = RESULT_SUCCESSFUL;
|
|
Token_State = TOKEN_GIVING;
|
|
m_uidRecipient = receiver_id;
|
|
|
|
CAttachment *pAtt = GetUserAttachment(receiver_id);
|
|
ASSERT (Token_ID == pTokenGiveRec->token_id);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenGiveIndication(pTokenGiveRec);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The recipient does not exist in the domain, so
|
|
* fail the request.
|
|
*/
|
|
result = RESULT_NO_SUCH_USER;
|
|
token_status = TOKEN_SELF_GRABBED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The requestor does not own the token, so the request
|
|
* must fail.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
token_status = TOKEN_OTHER_GRABBED;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
/*
|
|
* Inhibited tokens cannot be given by anyone to anyone. So
|
|
* fail this request with the proper status.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
if (m_InhibitorList.Find(uidInitiator) )
|
|
token_status = TOKEN_SELF_INHIBITED;
|
|
else
|
|
token_status = TOKEN_OTHER_INHIBITED;
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* This token is already in the process of being given. So
|
|
* this request must fail.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else if (uidInitiator == m_uidGrabber)
|
|
token_status = TOKEN_SELF_GIVING;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* This token is already in the process of being given. So
|
|
* this request must fail.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If necessary, issue a token give confirm to the initiating user.
|
|
*/
|
|
if (result != RESULT_SUCCESSFUL)
|
|
{
|
|
pOrigAtt->TokenGiveConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Forward this request upward towards the Top Provider.
|
|
*/
|
|
TRACE_OUT(("Token::TokenGiveRequest: forwarding request to Top Provider"));
|
|
ASSERT (Token_ID == pTokenGiveRec->token_id);
|
|
m_pConnToTopProvider->TokenGiveRequest(pTokenGiveRec);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenGiveIndication ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called in order to deliver a message to a user that
|
|
* another user is trying to give them a token.
|
|
*/
|
|
Void Token::TokenGiveIndication (
|
|
PTokenGiveRecord pTokenGiveRec)
|
|
{
|
|
UserID receiver_id;
|
|
|
|
receiver_id = pTokenGiveRec->receiver_id;
|
|
/*
|
|
* Make sure that the receiver ID is valid, since we must forward this
|
|
* indication in the direction of that user. If it is not valid, ignore
|
|
* this indication.
|
|
*/
|
|
if (ValidateUserID (receiver_id) )
|
|
{
|
|
/*
|
|
* Force this token to conform to the state implied by this indication.
|
|
*/
|
|
Token_State = TOKEN_GIVING;
|
|
m_uidGrabber = pTokenGiveRec->uidInitiator;
|
|
m_InhibitorList.Clear();
|
|
m_uidRecipient = receiver_id;
|
|
|
|
/*
|
|
* Determine what attachment leads to the recipient, and forward the
|
|
* indication in that direction.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(receiver_id);
|
|
ASSERT (Token_ID == pTokenGiveRec->token_id);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenGiveIndication(pTokenGiveRec);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The recipient is not in the sub-tree of this provider. So ignore
|
|
* this indication.
|
|
*/
|
|
ERROR_OUT(("Token::TokenGiveIndication: invalid receiver ID"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenGiveResponse ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called when a potential recipient decides whether or
|
|
* not to accept an offered token.
|
|
*/
|
|
Void Token::TokenGiveResponse (
|
|
Result result,
|
|
UserID receiver_id,
|
|
TokenID)
|
|
{
|
|
UserID uidInitiator;
|
|
TokenStatus token_status;
|
|
|
|
/*
|
|
* Process the response according to the current state of this token.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
case TOKEN_GRABBED:
|
|
case TOKEN_INHIBITED:
|
|
/*
|
|
* The token is not in the process of being given to anyone, so
|
|
* this response must be ignored.
|
|
*/
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* The token is being given to someone. Check to see if this is
|
|
* the proper recipient. If not, don't do anything.
|
|
*/
|
|
if (receiver_id == m_uidRecipient)
|
|
{
|
|
/*
|
|
* Save the ID of the initiator, for use in issuing a give
|
|
* confirm (if necessary).
|
|
*/
|
|
uidInitiator = m_uidGrabber;
|
|
|
|
/*
|
|
* Check to see if the token was accepted. A result of
|
|
* anything but successful would indicate that it was not.
|
|
*/
|
|
if (result == RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
* The token was accepted by the intended recipient.
|
|
* Change the state of the token to being grabbed by the
|
|
* receiver.
|
|
*/
|
|
Token_State = TOKEN_GRABBED;
|
|
m_uidGrabber = receiver_id;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The token was not accepted. It must either revert to
|
|
* being grabbed by the donor, or deleted, depending on
|
|
* whether or not the donor is in the sub-tree of this
|
|
* provider.
|
|
*/
|
|
if (ValidateUserID(uidInitiator))
|
|
{
|
|
/*
|
|
* The donor is in the sub-tree of this provider, so
|
|
* change the state of the token back to grabbed.
|
|
*/
|
|
Token_State = TOKEN_GRABBED;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The donor is not in the sub-tree of this provider,
|
|
* so the token will be marked as available (which
|
|
* will cause it to be deleted).
|
|
*/
|
|
Token_State = TOKEN_AVAILABLE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check to see if this is the Top Provider.
|
|
*/
|
|
if (m_pConnToTopProvider == NULL)
|
|
{
|
|
/*
|
|
* If the donor is still a valid user in the domain, a
|
|
* token give confirm must be issued in its direction.
|
|
*/
|
|
if (ValidateUserID(uidInitiator))
|
|
{
|
|
/*
|
|
* Determine which attachment leads to the donor, and
|
|
* issue the token give confirm.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
token_status = TOKEN_SELF_GRABBED;
|
|
else
|
|
token_status = TOKEN_OTHER_GRABBED;
|
|
|
|
CAttachment *pAtt = GetUserAttachment(uidInitiator);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenGiveConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If this is not the Top Provider, then the valid give
|
|
* response must be forwarded to the Top Provider.
|
|
*/
|
|
m_pConnToTopProvider->TokenGiveResponse(result, receiver_id, Token_ID);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* The token is being given to someone. Check to see if this is
|
|
* the proper recipient. If not, don't do anything.
|
|
*/
|
|
if (receiver_id == m_uidRecipient)
|
|
{
|
|
/*
|
|
* Check to see if the token was accepted. A result of
|
|
* anything but successful would indicate that it was not.
|
|
*/
|
|
if (result == RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
* The token was accepted by the intended recipient.
|
|
* Change the state of the token to being grabbed by the
|
|
* receiver.
|
|
*/
|
|
Token_State = TOKEN_GRABBED;
|
|
m_uidGrabber = receiver_id;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The token was not accepted. Since the donor has
|
|
* already relinquished control of the token, the token
|
|
* will marked as available (which will cause it to be
|
|
* deleted).
|
|
*/
|
|
Token_State = TOKEN_AVAILABLE;
|
|
}
|
|
|
|
/*
|
|
* Check to see if this is the Top Provider.
|
|
*/
|
|
if (m_pConnToTopProvider != NULL)
|
|
{
|
|
/*
|
|
* If this is not the Top Provider, then the valid give
|
|
* response must be forwarded to the Top Provider.
|
|
*/
|
|
m_pConnToTopProvider->TokenGiveResponse(result, receiver_id, Token_ID);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenGiveConfirm ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called as a potential giver of a token is told whether
|
|
* or not the token was successfully given to the intended recipient.
|
|
*/
|
|
Void Token::TokenGiveConfirm (
|
|
Result result,
|
|
UserID uidInitiator,
|
|
TokenID,
|
|
TokenStatus token_status)
|
|
{
|
|
/*
|
|
* Make sure that the initiator ID is valid, since we must forward this
|
|
* confirm in the direction of that user. If it is not valid, ignore
|
|
* this confirm.
|
|
*/
|
|
if (ValidateUserID(uidInitiator))
|
|
{
|
|
/*
|
|
* The token should be in the grabbed state, or else this confirm
|
|
* was generated in error.
|
|
*/
|
|
if (Token_State == TOKEN_GRABBED)
|
|
{
|
|
/*
|
|
* Check to see if this request was successful.
|
|
*/
|
|
if (result == RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
* If this token is marked as being owned by the initiator of
|
|
* the give, but the status indicates that the token is now
|
|
* owned by someone else (as a result of the successful give),
|
|
* then release the token.*
|
|
*/
|
|
if ((uidInitiator == m_uidGrabber) &&
|
|
(token_status == TOKEN_OTHER_GRABBED))
|
|
Token_State = TOKEN_AVAILABLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The token is in an invalid state. Report the error, but do
|
|
* not change the state of the token.
|
|
*/
|
|
ERROR_OUT(("Token::TokenGiveConfirm: invalid token state"));
|
|
}
|
|
|
|
/*
|
|
* Determine what attachment leads to the initiator, and forward the
|
|
* confirm in that direction.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(uidInitiator);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenGiveConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The initiator is not in the sub-tree of this provider. So ignore
|
|
* this confirm.
|
|
*/
|
|
ERROR_OUT(("Token::TokenGiveConfirm: invalid initiator ID"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenPleaseRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called when a user wishes to ask all current owners
|
|
* of a token to relinquish their ownership.
|
|
*/
|
|
Void Token::TokenPleaseRequest (
|
|
UserID uidInitiator,
|
|
TokenID)
|
|
{
|
|
CUidList please_indication_list;
|
|
|
|
/*
|
|
* Check to see if this is the Top Provider.
|
|
*/
|
|
if (IsTopProvider())
|
|
{
|
|
CAttachmentList attachment_list;
|
|
CAttachment *pAtt;
|
|
/*
|
|
* Determine the state of the token, to determine who to send the
|
|
* please indication to. Each state will place the appropriate user
|
|
* IDs in the please indication list.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* Put the grabber into the list.
|
|
*/
|
|
please_indication_list.Append(m_uidGrabber);
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
{
|
|
UserID uid;
|
|
/*
|
|
* Put all current inhibitors into the list.
|
|
*/
|
|
m_InhibitorList.Reset();
|
|
while (NULL != (uid = m_InhibitorList.Iterate()))
|
|
{
|
|
please_indication_list.Append(uid);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* Put the grabber into the list. And if the recipient is
|
|
* different from the grabber, put it in as well. Remember
|
|
* that it is valid for someone to give a token to themselves.
|
|
*/
|
|
please_indication_list.Append(m_uidGrabber);
|
|
if (m_uidGrabber != m_uidRecipient)
|
|
please_indication_list.Append(m_uidRecipient);
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* Put the recipient into the list.
|
|
*/
|
|
please_indication_list.Append(m_uidRecipient);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Build lists of unique attachments that lead to the users in the
|
|
* please indication list (built above).
|
|
*/
|
|
BuildAttachmentList (&please_indication_list, &attachment_list);
|
|
|
|
/*
|
|
* Iterate through the newly created attachment list, issuing token
|
|
* please indications to all attachments contained therein.
|
|
*/
|
|
attachment_list.Reset();
|
|
while (NULL != (pAtt = attachment_list.Iterate()))
|
|
{
|
|
pAtt->TokenPleaseIndication(uidInitiator, Token_ID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Forward the request toward the top provider.
|
|
*/
|
|
TRACE_OUT(("Token::TokenPleaseRequest: forwarding request to Top Provider"));
|
|
m_pConnToTopProvider->TokenPleaseRequest(uidInitiator, Token_ID);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenPleaseIndication ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called in order to deliver a message to all current
|
|
* owners of a token that someone else wishes to own the token.
|
|
*/
|
|
Void Token::TokenPleaseIndication (
|
|
UserID uidInitiator,
|
|
TokenID)
|
|
{
|
|
CUidList please_indication_list;
|
|
CAttachmentList attachment_list;
|
|
CAttachment *pAtt;
|
|
|
|
/*
|
|
* Determine the state of the token, to determine who to forward the
|
|
* please indication to. Each state will place the appropriate user
|
|
* IDs in the please indication list.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* Put the grabber into the list.
|
|
*/
|
|
please_indication_list.Append(m_uidGrabber);
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
{
|
|
UserID uid;
|
|
/*
|
|
* Put all current inhibitors into the list.
|
|
*/
|
|
m_InhibitorList.Reset();
|
|
while (NULL != (uid = m_InhibitorList.Iterate()))
|
|
{
|
|
please_indication_list.Append(uid);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* Put the grabber into the list. And if the recipient is
|
|
* different from the grabber, put it in as well. Remember
|
|
* that it is valid for someone to give a token to themselves.
|
|
*/
|
|
please_indication_list.Append(m_uidGrabber);
|
|
if (m_uidGrabber != m_uidRecipient)
|
|
please_indication_list.Append(m_uidRecipient);
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* Put the recipient into the list.
|
|
*/
|
|
please_indication_list.Append(m_uidRecipient);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Build lists of unique attachments that lead to the users in the
|
|
* please indication list (built above).
|
|
*/
|
|
BuildAttachmentList (&please_indication_list, &attachment_list);
|
|
|
|
/*
|
|
* Iterate through the newly created attachment list, issuing token
|
|
* please indications to all attachments contained therein.
|
|
*/
|
|
attachment_list.Reset();
|
|
while (NULL != (pAtt = attachment_list.Iterate()))
|
|
{
|
|
pAtt->TokenPleaseIndication(uidInitiator, Token_ID);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenReleaseRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called when a user wished to release a token. If the
|
|
* requesting user really is an owner of the token, the request will
|
|
* succeed. Otherwise it will fail. Either way, an appropriate token
|
|
* release confirm will be issued.
|
|
*/
|
|
Void Token::TokenReleaseRequest (
|
|
CAttachment *pAtt,
|
|
UserID uidInitiator,
|
|
TokenID)
|
|
{
|
|
Result result;
|
|
TokenStatus token_status;
|
|
|
|
/*
|
|
* Check to see if this is the Top Provider.
|
|
*/
|
|
if (IsTopProvider())
|
|
{
|
|
/*
|
|
* Determine the current state of the token before proceeding.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
/*
|
|
* If the token is available, then the requestor cannot be an
|
|
* owner. This means that the request must fail.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
token_status = TOKEN_NOT_IN_USE;
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* The token is in the grabbed state. See if the requesting
|
|
* user is the one who has it grabbed.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
{
|
|
/*
|
|
* The current grabber of the token wishes to release it.
|
|
* Set the state back to available, and send the
|
|
* appropriate token release confirm.
|
|
*/
|
|
Token_State = TOKEN_AVAILABLE;
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_NOT_IN_USE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Someone is trying to release someone elses token. This
|
|
* request must fail. Send the appropriate token release
|
|
* confirm.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
token_status = TOKEN_OTHER_GRABBED;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
/*
|
|
* The token is in the inhibited state. See if the requesting
|
|
* user is one of the inhibitors.
|
|
*/
|
|
if (m_InhibitorList.Remove(uidInitiator))
|
|
{
|
|
/*
|
|
* The user is an inhibitor. Remove the user from the
|
|
* list. Then check to see if this has resulted in an
|
|
* "ownerless" token.
|
|
*/
|
|
if (m_InhibitorList.IsEmpty())
|
|
{
|
|
/*
|
|
* The token has no other inhibitors. Return the token
|
|
* to the available state, and issue the appropriate
|
|
* token release confirm.
|
|
*/
|
|
Token_State = TOKEN_AVAILABLE;
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_NOT_IN_USE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* There are still other inhibitors of the token.
|
|
* Simply issue the appropriate token release confirm.
|
|
*/
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_OTHER_INHIBITED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The user attempting to release the token is not one of
|
|
* the inhibitors. Therefore the request must fail. Issue
|
|
* the appropriate token release indication.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
token_status = TOKEN_OTHER_INHIBITED;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* See if the requestor is the current owner of the token.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
{
|
|
/*
|
|
* The token must transition to the given state. This
|
|
* state indicates that if the recipient rejects the offer
|
|
* or detaches, the token will be freed instead of
|
|
* returning to the grabbed state. Issue the appropriate
|
|
* release confirm.
|
|
*/
|
|
Token_State = TOKEN_GIVEN;
|
|
|
|
result = RESULT_SUCCESSFUL;
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If the requestor is not the current owner, then this
|
|
* request must fail. We first need to determine the
|
|
* proper token status, and then issue the confirm.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* When the token is in the given state, there is no true
|
|
* owner (only a pending owner). This request must therefore
|
|
* fail. We first need to determine the proper token status,
|
|
* and then issue the confirm.
|
|
*/
|
|
result = RESULT_TOKEN_NOT_POSSESSED;
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Issue the token release confirm to the initiator.
|
|
*/
|
|
pAtt->TokenReleaseConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Forward the request toward the top provider.
|
|
*/
|
|
TRACE_OUT(("Token::TokenReleaseRequest: forwarding request to Top Provider"));
|
|
m_pConnToTopProvider->TokenReleaseRequest(uidInitiator, Token_ID);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenReleaseConfirm ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called as a part of sending a response to a user for
|
|
* a previous request. It tells the user the result of the request.
|
|
*/
|
|
Void Token::TokenReleaseConfirm (
|
|
Result result,
|
|
UserID uidInitiator,
|
|
TokenID,
|
|
TokenStatus token_status)
|
|
{
|
|
/*
|
|
* Make sure that the initiator ID is valid, since we must forward this
|
|
* confirm in the direction of that user. If it is not valid, ignore
|
|
* this confirm.
|
|
*/
|
|
if (ValidateUserID (uidInitiator) )
|
|
{
|
|
/*
|
|
* Check to see if this request was successful.
|
|
*/
|
|
if (result == RESULT_SUCCESSFUL)
|
|
{
|
|
/*
|
|
* Process the confirm according to current state.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* If the grabber has released the token, then is becomes
|
|
* available.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
Token_State = TOKEN_AVAILABLE;
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
/*
|
|
* If an inhibitor releases the token, then remove it from
|
|
* the list. If there are no more entries in the list,
|
|
* then the token becomes available.
|
|
*/
|
|
if (m_InhibitorList.Remove(uidInitiator))
|
|
{
|
|
if (m_InhibitorList.IsEmpty())
|
|
Token_State = TOKEN_AVAILABLE;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* If the grabber releases the token, then it transitions
|
|
* to an intermediate state. This state indicates that
|
|
* if the recipient rejects the token, it will be freed
|
|
* instead of returning to the grabbed state.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
Token_State = TOKEN_GIVEN;
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Determine what attachment leads to the initiator, and forward the
|
|
* confirm in that direction.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(uidInitiator);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenReleaseConfirm(result, uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The initiator is not in the sub-tree of this provider. So ignore
|
|
* this confirm.
|
|
*/
|
|
ERROR_OUT(("Token::TokenReleaseConfirm: invalid initiator ID"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenTestRequest ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called when a user wishes to test the current state
|
|
* of a token. The only action is to issue a token test confirm containing
|
|
* the state information.
|
|
*/
|
|
Void Token::TokenTestRequest (
|
|
CAttachment *pAtt,
|
|
UserID uidInitiator,
|
|
TokenID)
|
|
{
|
|
TokenStatus token_status;
|
|
|
|
/*
|
|
* Check to see if this is the Top Provider.
|
|
*/
|
|
if (m_pConnToTopProvider == NULL)
|
|
{
|
|
/*
|
|
* Determine the state of the token before proceeding.
|
|
*/
|
|
switch (Token_State)
|
|
{
|
|
case TOKEN_AVAILABLE:
|
|
/*
|
|
* The token is not in use.
|
|
*/
|
|
token_status = TOKEN_NOT_IN_USE;
|
|
break;
|
|
|
|
case TOKEN_GRABBED:
|
|
/*
|
|
* The token is grabbed. See if the originating user is the
|
|
* grabber. If so, return the state as self grabbed. If not,
|
|
* return the state as other grabbed.
|
|
*/
|
|
if (uidInitiator == m_uidGrabber)
|
|
token_status = TOKEN_SELF_GRABBED;
|
|
else
|
|
token_status = TOKEN_OTHER_GRABBED;
|
|
break;
|
|
|
|
case TOKEN_INHIBITED:
|
|
/*
|
|
* The token is inhibited. See if the originating user is one
|
|
* of the inhibitors. If so, return the state as self
|
|
* inhibited. If not, return the state as other inhibited.
|
|
*/
|
|
if (m_InhibitorList.Find(uidInitiator))
|
|
token_status = TOKEN_SELF_INHIBITED;
|
|
else
|
|
token_status = TOKEN_OTHER_INHIBITED;
|
|
break;
|
|
|
|
case TOKEN_GIVING:
|
|
/*
|
|
* The token is being given from one user to another. See if
|
|
* the requestor is one of the users involved.
|
|
*/
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else if (uidInitiator == m_uidGrabber)
|
|
token_status = TOKEN_SELF_GIVING;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
|
|
case TOKEN_GIVEN:
|
|
/*
|
|
* The token has been given from one user to another. See if
|
|
* the requestor is the receiver.
|
|
*/
|
|
if (uidInitiator == m_uidRecipient)
|
|
token_status = TOKEN_SELF_RECIPIENT;
|
|
else
|
|
token_status = TOKEN_OTHER_GIVING;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Issue the test confirm with the appropriate status information.
|
|
*/
|
|
pAtt->TokenTestConfirm(uidInitiator, Token_ID, token_status);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Forward the request toward the top provider.
|
|
*/
|
|
TRACE_OUT(("Token::TokenTestRequest: forwarding request to Top Provider"));
|
|
m_pConnToTopProvider->TokenTestRequest(uidInitiator, Token_ID);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void TokenTestConfirm ()
|
|
*
|
|
* Public
|
|
*
|
|
* Functional Description:
|
|
* This function is called as a part of sending a response to a user for
|
|
* a previous request. It tells the user the result of the request.
|
|
*/
|
|
Void Token::TokenTestConfirm (
|
|
UserID uidInitiator,
|
|
TokenID,
|
|
TokenStatus token_status)
|
|
{
|
|
/*
|
|
* Make sure that the initiator ID is valid, since we must forward this
|
|
* confirm in the direction of that user. If it is not valid, ignore
|
|
* this confirm.
|
|
*/
|
|
if (ValidateUserID(uidInitiator))
|
|
{
|
|
/*
|
|
* Determine what attachment leads to the initiator, and forward the
|
|
* confirm in that direction.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(uidInitiator);
|
|
if (pAtt)
|
|
{
|
|
pAtt->TokenTestConfirm(uidInitiator, Token_ID, token_status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The initiator is not in the sub-tree of this provider. So ignore
|
|
* this confirm.
|
|
*/
|
|
ERROR_OUT(("Token::TokenReleaseConfirm: invalid initiator ID"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* BOOL ValidateUserID ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function is used to verify the existence of the specified user
|
|
* in the sub-tree of this provider.
|
|
*
|
|
* Formal Parameters:
|
|
* user_id (i)
|
|
* This is the ID of the user the caller wishes to validate.
|
|
*
|
|
* Return Value:
|
|
* TRUE if the user is valid. FALSE otherwise.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*/
|
|
BOOL Token::ValidateUserID (
|
|
UserID user_id)
|
|
{
|
|
/*
|
|
* Initialize the return value to FALSE, indicating that if any of the
|
|
* following checks fail, the ID does NOT refer to a valid user ID.
|
|
*/
|
|
BOOL valid=FALSE;
|
|
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)
|
|
valid = TRUE;
|
|
}
|
|
|
|
return (valid);
|
|
}
|
|
|
|
/*
|
|
* PCommandTarget GetUserAttachment ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function returns the attachment which leads to the specified
|
|
* user.
|
|
*
|
|
* Formal Parameters:
|
|
* user_id (i)
|
|
* This is the ID of the user the caller wishes to find the attachment
|
|
* for.
|
|
*
|
|
* Return Value:
|
|
* A pointer to the attachment that leads to the user.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*/
|
|
CAttachment *Token::GetUserAttachment (
|
|
UserID user_id)
|
|
{
|
|
PChannel lpChannel;
|
|
/*
|
|
* Read and return a pointer to the attachment that leads to the
|
|
* specified user. Note that this routine does NOT check to see if the
|
|
* user is in the channel list. It assumes that the user is known to
|
|
* be valid BEFORE this routine is called.
|
|
*/
|
|
return ((NULL != (lpChannel = m_pChannelList2->Find(user_id))) ?
|
|
lpChannel->GetAttachment() :
|
|
NULL);
|
|
}
|
|
|
|
/*
|
|
* Void IssueTokenReleaseIndication ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function is used to issue a token release indication to a
|
|
* particular user. It first check to make sure that the user id valid,
|
|
* and that it is a local user.
|
|
*
|
|
* Formal Parameters:
|
|
* user_id (i)
|
|
* This is the ID of the user the caller wishes to send a token
|
|
* release indication to.
|
|
*
|
|
* Return Value:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*/
|
|
Void Token::IssueTokenReleaseIndication (
|
|
UserID user_id)
|
|
{
|
|
/*
|
|
* Make sure that the specified user exists in the sub-tree of this
|
|
* provider.
|
|
*/
|
|
if (ValidateUserID (user_id) )
|
|
{
|
|
/*
|
|
* Determine which attachment leads to the grabber.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(user_id);
|
|
|
|
/*
|
|
* Is this attachment a local one? If so, then issue a token
|
|
* release indication to let the user know that the token has
|
|
* been taken away.
|
|
*/
|
|
if (m_pAttachmentList->Find(pAtt) && pAtt->IsUserAttachment())
|
|
{
|
|
PUser pUser = (PUser) pAtt;
|
|
pUser->TokenReleaseIndication(REASON_TOKEN_PURGED, Token_ID);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Void BuildAttachmentList ()
|
|
*
|
|
* Private
|
|
*
|
|
* Functional Description:
|
|
* This function builds a list of unique attachments out of the list of
|
|
* user IDs that is poassed in. This is done to insure that no given
|
|
* attachment receives more than one indication, even when there are more
|
|
* than one user in the same direction.
|
|
*
|
|
* Formal Parameters:
|
|
* user_id_list (i)
|
|
* This is a list of user IDs that the caller wishes to send a token
|
|
* please indication to.
|
|
* attachment_list (i)
|
|
* This is the list that all unique attachments will be added to.
|
|
*
|
|
* Return Value:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*/
|
|
Void Token::BuildAttachmentList (
|
|
CUidList *user_id_list,
|
|
CAttachmentList *attachment_list)
|
|
{
|
|
UserID uid;
|
|
|
|
/*
|
|
* Loop through the passed in user ID list building a list of unique
|
|
* attachments. This will be used to send indications downward without
|
|
* sending one twice over 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))
|
|
{
|
|
/*
|
|
* Determine which attachment leads to the user in question. Then
|
|
* check to see if it is already in the attachment list. If not,
|
|
* then put it there.
|
|
*/
|
|
CAttachment *pAtt = GetUserAttachment(uid);
|
|
if (attachment_list->Find(pAtt) == FALSE)
|
|
attachment_list->Append(pAtt);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* This user ID does not correspond to a valid user in the sub-tree
|
|
* of this provider. Therefore, discard the ID.
|
|
*/
|
|
ERROR_OUT(("Token::BuildAttachmentList: user ID not valid"));
|
|
}
|
|
}
|
|
}
|
|
|