#include "precomp.h" DEBUG_FILEZONE(ZONE_T120_GCCNC); /* * mcsuser.cpp * * Copyright (c) 1995 by DataBeam Corporation, Lexington, KY * * Abstract: * This is the implemntation file for the MCSUser class. It implements * functions responsible for encoding out bound indirect conference * join request and response PDUs, and also Send user ID Requests. All * these PDUs are encapsulated in user data field of MCSSendDataRequest. * Also this file implements functions that are responsible for decoding * incoming indications and confirm PDUs which are encapsulated in the * user data field of MCSSendDataIndication. Functions responsible for * joining different channels are also implemented in this module. * * SEE THE INTERFACE FILE FOR A MORE DETAILED DESCRIPTION OF THIS CLASS. * * Private Instance Variables * m_pMCSSap * This is the MCS User handle handed back from the MCS Attache User * Request. * m_nidMyself * The is the MCS User ID returned in the Attach User Confirm. This * is also refered to as the Node ID with in GCC. * m_nidTopProvider * This holds the MCS User ID (or Node ID) for the top Provider. * m_nidParent * This holds the MCS User ID (or Node ID) for this nodes parent node. * m_fEjectionPending * This flag indicates if an ejection of this node is pending. * m_eEjectReason * This variable holds the reason for ejection until the eject * indication can be delivered after all child nodes have disconnected. * m_pOwnerConf * Pointer to the object that will receive all the owner callbacks * from the user object (typically the conference object). * m_ChannelJoinedFlags * A structure of flags used to keep up with creation state machine. * Basically, it keeps up with which channels have been joined and * which ones have not. * m_ChildUidConnHdlList2 * Keeps mapping of child Node IDs to child logical connection * handles. * m_OutgoingPDUQueue * This is a rogue wave list used to queue up all outgoing PDUs. * m_ConfJoinResponseList2 * This rogue wave list holds information needed to send back in a join * response after the local node controller responds. * m_EjectedNodeAlarmList2 * This list holds alarm objects for all the nodes that have been * ejected and are directly connected to this node. The alarm is * used to disconnect any misbehaving nodes that do not disconnect * after the EJECTED_NODE_TIMER_DURATION. * m_EjectedNodeList * This list keeps up with nodes that have been ejected but are NOT * directly connected to this node. We save these nodes so that * a correct reason for disconnecting (user ejected) can be issued * when the detch user indication comes in. * * Author: * blp */ #include "mcsuser.h" #include "mcsdllif.h" #include "ogcccode.h" #include "conf.h" #include "translat.h" #include "gcontrol.h" // Static Channel and Token ID definitions used by the MCS user object. #define BROADCAST_CHANNEL_ID 1 #define CONVENER_CHANNEL_ID 2 #define CONDUCTOR_TOKEN_ID 1 // Time given to allow an ejected node to disconnect before it is disconnected #define EJECTED_NODE_TIMER_DURATION 10000 // Duration in milliseconds extern MCSDLLInterface *g_pMCSIntf; /* * This is a global variable that has a pointer to the one GCC coder that * is instantiated by the GCC Controller. Most objects know in advance * whether they need to use the MCS or the GCC coder, so, they do not need * this pointer in their constructors. */ extern CGCCCoder *g_GCCCoder; /* * MCSUser () * * Public Function Description * This is the MCSUser object constructor. It is responsible for * initializing all the instance variables used by this class. The * constructor is responsible for establishing the user attachment to * the MCS domain defined by the conference ID. It also kicks off the * process of joining all the appropriate channels. */ MCSUser:: MCSUser(CConf *pConf, GCCNodeID nidTopProvider, GCCNodeID nidParent, PGCCError return_value) : CRefCount(MAKE_STAMP_ID('M','U','s','r')), m_ChildUidConnHdlList2(), m_EjectedNodeAlarmList2(), m_EjectedNodeList(), m_pConf(pConf), m_nidTopProvider(nidTopProvider), m_nidParent(nidParent), m_nidMyself(NULL), m_fEjectionPending(FALSE) { MCSError mcs_rc; GCCConfID nConfID = pConf->GetConfID(); // No channels are joined initially m_ChannelJoinedFlags.user_channel_joined = FALSE; m_ChannelJoinedFlags.broadcast_channel_joined = FALSE; m_ChannelJoinedFlags.convener_channel_joined = FALSE; m_ChannelJoinedFlags.channel_join_error = FALSE; mcs_rc = g_pMCSIntf->AttachUserRequest(&nConfID, &m_pMCSSap, this); if (MCS_NO_ERROR != mcs_rc) { WARNING_OUT(("MCSUser::MCSUser: Failure in attach user req, ")); *return_value = GCC_FAILURE_ATTACHING_TO_MCS; } else { *return_value = GCC_NO_ERROR; } } /* * ~MCSUser () * * Public Function Description * This is the user destructor. It takes care of leaving channels * joined by the user object. Also it detaches the user attachment * with MCS by issuing a detach user request. */ MCSUser::~MCSUser(void) { // Clean up the Ejected Node Alarm List PAlarm lpAlarm; while (NULL != (lpAlarm = m_EjectedNodeAlarmList2.Get())) { delete lpAlarm; } if(m_ChannelJoinedFlags.user_channel_joined) { g_pMCSIntf->ChannelLeaveRequest(m_nidMyself, m_pMCSSap); } if(m_ChannelJoinedFlags.broadcast_channel_joined) { g_pMCSIntf->ChannelLeaveRequest(BROADCAST_CHANNEL_ID, m_pMCSSap); } if(m_ChannelJoinedFlags.convener_channel_joined) { g_pMCSIntf->ChannelLeaveRequest(CONVENER_CHANNEL_ID, m_pMCSSap); } // Empty the queue of all PDUs SEND_DATA_REQ_INFO *pReqInfo; m_OutgoingPDUQueue.Reset(); while (NULL != (pReqInfo = m_OutgoingPDUQueue.Iterate())) { pReqInfo->packet->Unlock(); delete pReqInfo; } g_pMCSIntf->DetachUserRequest(m_pMCSSap, this); } /* * UINT ProcessAttachUserConfirm () * * Private Function Description * This function is called when the user object gets an attach user * confirm from MCS in response to an attach user request made by the * user object in it's constructor. The function checks the result * indicated in the confirm. If the result is a successful attachment, then * different channels depending upon the type of the provider, are joined. * Also this function reports failures in attach user (as indicated by * result in attach user confirm) and channel joins, to the conference * through an owner callback. * * Formal Parameters: * result - (i) Result of the attach user request. * user_id - (i) This nodes user or Node ID if successful result. * * Return Value * MCS_NO_ERROR - No error is always returned. * * Side Effects * None. * * Caveats * None. */ UINT MCSUser::ProcessAttachUserConfirm(Result result, UserID user_id) { UINT rc; if (result == RESULT_SUCCESSFUL) { m_nidMyself = user_id; /* ** After the attach confirm is received we go ahead and join the ** appropriate channel based on the conf node type. If this ** node is the yop provider we also set up the top provider user id, ** otherwise this gets set up in the constructor. */ switch (m_pConf->GetConfNodeType()) { case TOP_PROVIDER_NODE: m_nidTopProvider = m_nidMyself; rc = JoinUserAndBroadCastChannels(); break; case JOINED_CONVENER_NODE: case CONVENER_NODE: rc = JoinUserAndBroadCastChannels(); if(rc == MCS_NO_ERROR) { rc = JoinConvenerChannel(); } break; case TOP_PROVIDER_AND_CONVENER_NODE: m_nidTopProvider = m_nidMyself; rc = JoinUserAndBroadCastChannels(); if(rc == MCS_NO_ERROR) { rc = JoinConvenerChannel(); } break; case JOINED_NODE: case INVITED_NODE: rc = JoinUserAndBroadCastChannels(); break; default: ERROR_OUT(("User::ProcessAttachUserConfirm: Bad Node Type, %u", (UINT) m_pConf->GetConfNodeType())); break; } if (rc != MCS_NO_ERROR) { /* * ChannelJoinRequestFailed at some level in MCS * So this message tells the conferenceabout this * failure. Conference will delete the user object * as a result of this */ m_pConf->ProcessUserCreateConfirm(USER_CHANNEL_JOIN_FAILURE, m_nidMyself); } } else { /* * Attach user request failed as indicated by the result field in the * confirm message, because of any of the following causes: * congested, domain disconnected, no such domain, too many channels, * too many users, unspecified failure. In this case the user object * just sends the conference a GCC_USER_ATTACH_FAILURE ( to be defined * in command target.h) , which causes * the conference object to delete the user attachment. * UserCreateConfirm message is not corresponding exectly to a single * primitive. */ WARNING_OUT(("MCSUser::ProcessAttachUserConfirm: ATTACH FAILED")); m_pConf->ProcessUserCreateConfirm(USER_ATTACH_FAILURE, m_nidMyself); } return (MCS_NO_ERROR); } /* * MCSError JoinUserAndBroadCastChannels() * * Private Function Description * This function is called by user object when it gets a successful * attach user confrim, to join user id and broadcast channels. * If the channel join requests fail, it returns the appropriate MCS * Error. * * Formal Parameters: * None. * * Return Value * See return values for mcs channel jon request. * * Side Effects * None. * * Caveats * None. */ MCSError MCSUser::JoinUserAndBroadCastChannels() { MCSError rc; rc = g_pMCSIntf->ChannelJoinRequest(m_nidMyself, m_pMCSSap); if(rc == MCS_NO_ERROR) { rc = g_pMCSIntf->ChannelJoinRequest(BROADCAST_CHANNEL_ID, m_pMCSSap); } return (rc); } /* * MCSError JoinUserAndBroadCastChannels() * * Private Function Description * This function is called by user object of a convener gcc provider * when it gets a successful attach user confrim, to join convener * channel. If the channel join requests fail, it returns the appropriate * MCS Error. * * Formal Parameters: * None. * * Return Value * See return values for mcs channel jon request. * * Side Effects * None. * * Caveats * None. */ MCSError MCSUser::JoinConvenerChannel() { return g_pMCSIntf->ChannelJoinRequest(CONVENER_CHANNEL_ID, m_pMCSSap); } /* * UINT ProcessChannelJoinConfirm() * * Private Function Description * This function is called when the user object gets an channel join * confirm from MCS in response to channel join requests made by the * user object. If a channel is joined successfully as indicated by * the result in the confirm, a channel joined flag corresponding to * that channel id is set. This flag indicates as to which channels a * user object is joined at any given time. Also after setting this * flag the functions checks to see if all tke required channels based * on the type of gcc provider, are joined. If all required channels are * joined the conference object is informaed about it via an owner call- * back (USER_CREATE_CONFIRM). * * Formal Parameters: * result - (i) Result of the channel join request. * channel_id - (i) Channel ID that this confirm pertains to. * * Return Value * MCS_NO_ERROR is always returned. * * Side Effects * None. * * Caveats * None. */ UINT MCSUser::ProcessChannelJoinConfirm(Result result, ChannelID channel_id) { if (m_ChannelJoinedFlags.channel_join_error == FALSE) { if (result == RESULT_SUCCESSFUL) { if( channel_id == m_nidMyself) { m_ChannelJoinedFlags.user_channel_joined = TRUE; } else { switch (channel_id) { case CONVENER_CHANNEL_ID: m_ChannelJoinedFlags.convener_channel_joined = TRUE; break; case BROADCAST_CHANNEL_ID: m_ChannelJoinedFlags.broadcast_channel_joined = TRUE; break; } } /* ** If all the channels are joined we inform the owner object that ** the user object was successfully created. */ if (AreAllChannelsJoined()) { m_pConf->ProcessUserCreateConfirm(USER_RESULT_SUCCESSFUL, m_nidMyself); } } else { WARNING_OUT(("MCSUser::ProcessChannelJoinConfirm: Error joining channel, result=%u", (UINT) result)); m_ChannelJoinedFlags.channel_join_error = TRUE ; m_pConf->ProcessUserCreateConfirm(USER_CHANNEL_JOIN_FAILURE, m_nidMyself); } } return (MCS_NO_ERROR); } /* * BOOL AreAllChannelsJoined() * * Public Function Description * This function is called to check if all tke required channels based * on the type of gcc provider, are joined. It returns true if all * required channels are joined and false otherwise. This function uses * different channel joined flags to check which channels the given user * object is joined to. * * Formal Parameters: * None. * * Return Value * TRUE - If all channels are joined. * FALSE - If all the channels are not joined. * * Side Effects * None. * * Caveats * None. */ BOOL MCSUser::AreAllChannelsJoined(void) { BOOL rc = FALSE; switch (m_pConf->GetConfNodeType()) { case TOP_PROVIDER_NODE: if ((m_ChannelJoinedFlags.user_channel_joined) && (m_ChannelJoinedFlags.broadcast_channel_joined)) { rc = TRUE; } break; case JOINED_CONVENER_NODE: case CONVENER_NODE: if ((m_ChannelJoinedFlags.convener_channel_joined) && (m_ChannelJoinedFlags.user_channel_joined) && (m_ChannelJoinedFlags.broadcast_channel_joined)) { rc = TRUE; } break; case TOP_PROVIDER_AND_CONVENER_NODE: if ((m_ChannelJoinedFlags.convener_channel_joined) && (m_ChannelJoinedFlags.user_channel_joined) && (m_ChannelJoinedFlags.broadcast_channel_joined)) { rc = TRUE; } break; case JOINED_NODE: case INVITED_NODE: if( (m_ChannelJoinedFlags.user_channel_joined) && (m_ChannelJoinedFlags.broadcast_channel_joined)) { rc = TRUE; } break; } return rc; } /* * void SendUserIDRequest() * * Public Function Description: * This request originates from the conference object. Conference object * sends the sequence number obtained in the conference create confirm * or conference join confirm to the parent GCC provider on the parent * gcc provider's UserId channel. The pdu is encoded here and is * queued to be sent during the next heartbeat. */ void MCSUser::SendUserIDRequest(TagNumber tag_number) { PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; /* ** Fill in the UserIDIndication pdu structure to be passed in the ** constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = USER_ID_INDICATION_CHOSEN; gcc_pdu.u.indication.u.user_id_indication.tag = tag_number; /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidParent, TOP_PRIORITY, FALSE); } else { ResourceFailureHandler(); } } /* * GCCError ConferenceJoinRequest() * * Public Function Description: * This call is made by the conference object of the intermediate node * to forward the conference join request over to the top provider. This * function encodes the conference join request pdu and queues it to be * sent in the next heartbeat. * * Caveats * The connection handle is used here for a TAG and should be passed back * to the owner object when the join response comes in. */ GCCError MCSUser::ConferenceJoinRequest( CPassword *convener_password, CPassword *password_challenge, LPWSTR pwszCallerID, CUserDataListContainer *user_data_list, ConnectionHandle connection_handle) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = CONFERENCE_JOIN_REQUEST_CHOSEN; gcc_pdu.u.request.u.conference_join_request.tag = (TagNumber)connection_handle; gcc_pdu.u.request.u.conference_join_request.bit_mask = TAG_PRESENT; // Insert the convener password into the ASN.1 structure if (convener_password != NULL) { rc = convener_password->GetPasswordSelectorPDU( &gcc_pdu.u.request.u.conference_join_request.cjrq_convener_password); if (rc == GCC_NO_ERROR) { gcc_pdu.u.request.u.conference_join_request.bit_mask |= CJRQ_CONVENER_PASSWORD_PRESENT; } } // Insert the password challenge into the ASN.1 structure if (( password_challenge != NULL ) && (rc == GCC_NO_ERROR)) { rc = password_challenge->GetPasswordChallengeResponsePDU ( &gcc_pdu.u.request.u.conference_join_request. cjrq_password); if (rc == GCC_NO_ERROR) { gcc_pdu.u.request.u.conference_join_request.bit_mask |= CJRQ_PASSWORD_PRESENT; } } // Insert the caller identifier into the ASN.1 structure UINT cchCallerID = ::My_strlenW(pwszCallerID); if ((cchCallerID != 0 ) && (rc == GCC_NO_ERROR)) { gcc_pdu.u.request.u.conference_join_request.cjrq_caller_id.value = pwszCallerID; gcc_pdu.u.request.u.conference_join_request.cjrq_caller_id.length = cchCallerID; gcc_pdu.u.request.u.conference_join_request.bit_mask |= CJRQ_CALLER_ID_PRESENT; } // Insert the user data into the ASN.1 structure if (( user_data_list != NULL ) && (rc == GCC_NO_ERROR)) { rc = user_data_list->GetUserDataPDU ( &gcc_pdu.u.request.u.conference_join_request.cjrq_user_data); if (rc == GCC_NO_ERROR) { gcc_pdu.u.request.u.conference_join_request.bit_mask |= CJRQ_USER_DATA_PRESENT; } } if (rc == GCC_NO_ERROR) { DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, TOP_PRIORITY, FALSE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } // Cleanup after any errors if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } return rc; } /* * GCCError SendConferenceLockRequest() * * Public Function Description: * This function is invoked by the owner object to send a conference lock * request PDU to the top provider. */ GCCError MCSUser::SendConferenceLockRequest() { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = CONFERENCE_LOCK_REQUEST_CHOSEN; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConferenceLockResponse() * * Public Function Description: * This function is invoked by the owner object to send a conference lock * response PDU to the requesting node. */ GCCError MCSUser::SendConferenceLockResponse ( UserID source_node, GCCResult result) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = CONFERENCE_LOCK_RESPONSE_CHOSEN; gcc_pdu.u.response.u.conference_lock_response.result = ::TranslateGCCResultToLockResult(result); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, source_node, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConferenceUnlockRequest() * * Public Function Description: * This function is invoked by the owner object to send a conference unlock * request PDU to the top provider. */ GCCError MCSUser::SendConferenceUnlockRequest () { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = CONFERENCE_UNLOCK_REQUEST_CHOSEN; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConferenceUnlockResponse() * * Public Function Description: * This function is invoked by the owner object to send a conference unlock * response PDU to the requesting node. */ GCCError MCSUser::SendConferenceUnlockResponse ( UserID source_node, GCCResult result) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = CONFERENCE_UNLOCK_RESPONSE_CHOSEN; gcc_pdu.u.response.u.conference_unlock_response.result = ::TranslateGCCResultToUnlockResult(result); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, source_node, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConferenceLockIndication() * * Public Function Description: * This function is invoked by the owner object of the top provider * to send a conference lock indication PDU to one or all other nodes * that are registered in the conference. */ GCCError MCSUser::SendConferenceLockIndication( BOOL uniform_send, UserID source_node) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_LOCK_INDICATION_CHOSEN; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue( packet, uniform_send ? BROADCAST_CHANNEL_ID : source_node, HIGH_PRIORITY, uniform_send); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConferenceUnlockIndication() * * Public Function Description: * This function is invoked by the owner object of the top provider * to send a conference unlock indication PDU to one or all other nodes * that are registered in the conference. */ GCCError MCSUser::SendConferenceUnlockIndication( BOOL uniform_send, UserID source_node) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_UNLOCK_INDICATION_CHOSEN; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue( packet, uniform_send ? BROADCAST_CHANNEL_ID : source_node, HIGH_PRIORITY, uniform_send); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /******************************* Registry Calls ******************************/ /* * void RegistryRegisterChannelRequest() * * Public Function Description: * This routine is used when an APE wishes to register a channel in * the application registry. */ void MCSUser::RegistryRegisterChannelRequest( CRegKeyContainer *registry_key_data, ChannelID channel_id, EntityID entity_id) { GCCError error_value; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = REGISTRY_REGISTER_CHANNEL_REQUEST_CHOSEN; error_value = registry_key_data->GetRegistryKeyDataPDU( &gcc_pdu.u.request.u. registry_register_channel_request.key); if (error_value == GCC_NO_ERROR) { gcc_pdu.u.request.u.registry_register_channel_request.channel_id = channel_id; gcc_pdu.u.request.u.registry_register_channel_request.entity_id = entity_id; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { ERROR_OUT(("MCSUser::RegistryRegisterChannelRequest: Error creating packet")); error_value = GCC_ALLOCATION_FAILURE; delete packet; } registry_key_data->FreeRegistryKeyDataPDU(); } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * MCSUser::RegistryAssignTokenRequest() * * Public Function Description: * This routine is used when an APE wishes to register a token in * the application registry. Note that there is no token ID included in * this request. The token ID is allocated at the top provider. */ void MCSUser::RegistryAssignTokenRequest ( CRegKeyContainer *registry_key_data, EntityID entity_id) { GCCError error_value; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = REGISTRY_ASSIGN_TOKEN_REQUEST_CHOSEN; error_value = registry_key_data->GetRegistryKeyDataPDU( &gcc_pdu.u.request.u. registry_assign_token_request.registry_key); if (error_value == GCC_NO_ERROR) { gcc_pdu.u.request.u.registry_assign_token_request.entity_id = entity_id; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; } registry_key_data->FreeRegistryKeyDataPDU(); } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void RegistrySetParameterRequest() * * Public Function Description: * This routine is used when an APE wishes to register a parameter in * the application registry. Note that parameter to be registered is * included in this request. */ void MCSUser::RegistrySetParameterRequest ( CRegKeyContainer *registry_key_data, LPOSTR parameter_value, GCCModificationRights modification_rights, EntityID entity_id) { GCCError error_value; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = REGISTRY_SET_PARAMETER_REQUEST_CHOSEN; gcc_pdu.u.request.u.registry_set_parameter_request.bit_mask = 0; error_value = registry_key_data->GetRegistryKeyDataPDU( &gcc_pdu.u.request.u. registry_set_parameter_request.key); if (error_value == GCC_NO_ERROR) { if (parameter_value != NULL) { gcc_pdu.u.request.u.registry_set_parameter_request. registry_set_parameter.length = parameter_value->length; memcpy (gcc_pdu.u.request.u.registry_set_parameter_request. registry_set_parameter.value, parameter_value->value, parameter_value->length); } else { gcc_pdu.u.request.u.registry_set_parameter_request. registry_set_parameter.length = 0; } gcc_pdu.u.request.u.registry_set_parameter_request.entity_id = entity_id; // Set up the modification rights here if it exists if (modification_rights != GCC_NO_MODIFICATION_RIGHTS_SPECIFIED) { gcc_pdu.u.request.u.registry_set_parameter_request.bit_mask |= PARAMETER_MODIFY_RIGHTS_PRESENT; gcc_pdu.u.request.u.registry_set_parameter_request. parameter_modify_rights = (RegistryModificationRights)modification_rights; } DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; } registry_key_data->FreeRegistryKeyDataPDU(); } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void RegistryRetrieveEntryRequest() * * Public Function Description: * This routine is used when an APE wishes to retrieve an registry item * from the registry. */ void MCSUser::RegistryRetrieveEntryRequest ( CRegKeyContainer *registry_key_data, EntityID entity_id) { GCCError error_value; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = REGISTRY_RETRIEVE_ENTRY_REQUEST_CHOSEN; error_value = registry_key_data->GetRegistryKeyDataPDU( &gcc_pdu.u.request.u. registry_retrieve_entry_request.key); if (error_value == GCC_NO_ERROR) { gcc_pdu.u.request.u.registry_retrieve_entry_request.entity_id = entity_id; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; } registry_key_data->FreeRegistryKeyDataPDU(); } else error_value = GCC_ALLOCATION_FAILURE; if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void RegistryDeleteEntryRequest() * * Public Function Description: * This routine is used when an APE wishes to delete a registry item * from the registry. */ void MCSUser::RegistryDeleteEntryRequest ( CRegKeyContainer *registry_key_data, EntityID entity_id) { GCCError error_value; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = REGISTRY_DELETE_ENTRY_REQUEST_CHOSEN; error_value = registry_key_data->GetRegistryKeyDataPDU( &gcc_pdu.u.request.u. registry_delete_entry_request.key); if (error_value == GCC_NO_ERROR) { gcc_pdu.u.request.u.registry_delete_entry_request.entity_id = entity_id; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; } registry_key_data->FreeRegistryKeyDataPDU(); } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void RegistryMonitorRequest() * * Public Function Description: * This routine is used when an APE wishes to monitor a registry item * in the registry. */ void MCSUser::RegistryMonitorRequest ( CRegKeyContainer *registry_key_data, EntityID entity_id) { GCCError error_value; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = REGISTRY_MONITOR_ENTRY_REQUEST_CHOSEN; error_value = registry_key_data->GetRegistryKeyDataPDU( &gcc_pdu.u.request.u. registry_monitor_entry_request.key); if (error_value == GCC_NO_ERROR) { gcc_pdu.u.request.u.registry_monitor_entry_request.entity_id= entity_id; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; } registry_key_data->FreeRegistryKeyDataPDU(); } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void RegistryAllocateHandleRequest() * * Public Function Description: * This routine is used when an APE wishes to allocate a number of * handles from the application registry. */ void MCSUser::RegistryAllocateHandleRequest( UINT number_of_handles, EntityID entity_id ) { GCCError error_value = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = REGISTRY_ALLOCATE_HANDLE_REQUEST_CHOSEN; gcc_pdu.u.request.u.registry_allocate_handle_request.number_of_handles = (USHORT) number_of_handles; gcc_pdu.u.request.u.registry_allocate_handle_request.entity_id= entity_id; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void RegistryAllocateHandleResponse() * * Public Function Description: * This routine is used by the Top Provider to respond to an allocate * handle request from an APE at a remote node. The allocated handles * are passed back here. */ void MCSUser::RegistryAllocateHandleResponse ( UINT number_of_handles, UINT registry_handle, EntityID requester_entity_id, UserID requester_node_id, GCCResult result) { GCCError error_value = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = REGISTRY_ALLOCATE_HANDLE_RESPONSE_CHOSEN; gcc_pdu.u.response.u.registry_allocate_handle_response.number_of_handles = (USHORT) number_of_handles; gcc_pdu.u.response.u.registry_allocate_handle_response.entity_id = requester_entity_id; gcc_pdu.u.response.u.registry_allocate_handle_response.first_handle = (Handle) registry_handle; if (result == GCC_RESULT_SUCCESSFUL) { gcc_pdu.u.response.u.registry_allocate_handle_response.result = RARS_RESULT_SUCCESS; } else { gcc_pdu.u.response.u.registry_allocate_handle_response.result = NO_HANDLES_AVAILABLE; } DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, requester_node_id, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); error_value = GCC_ALLOCATION_FAILURE; delete packet; } } /* * void RegistryResponse() * * Public Function Description: * This routine is used to respond to all the registry request except * allocate handle. It formulates the response PDU and queues it for * delivery. */ void MCSUser::RegistryResponse ( RegistryResponsePrimitiveType primitive_type, UserID requester_owner_id, EntityID requester_entity_id, CRegKeyContainer *registry_key_data, CRegItem *registry_item_data, GCCModificationRights modification_rights, UserID entry_owner_id, EntityID entry_entity_id, GCCResult result) { GCCError error_value; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; DebugEntry(MCSUser::RegistryResponse); /* ** Encode the conference join response PDU, along with the sequence ** number. */ gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = REGISTRY_RESPONSE_CHOSEN; gcc_pdu.u.response.u.registry_response.bit_mask = 0; error_value = registry_key_data->GetRegistryKeyDataPDU(&gcc_pdu.u.response.u.registry_response.key); if (error_value == GCC_NO_ERROR) { if (registry_item_data != NULL) { registry_item_data->GetRegistryItemDataPDU(&gcc_pdu.u.response.u.registry_response.item); } else { gcc_pdu.u.response.u.registry_response.item.choice = VACANT_CHOSEN; } TRACE_OUT(("MCSUser: RegistryResponse: item_type=%d", (UINT) gcc_pdu.u.response.u.registry_response.item.choice)); // Set up the entry owner if (entry_owner_id != 0) { gcc_pdu.u.response.u.registry_response.owner.choice = OWNED_CHOSEN; gcc_pdu.u.response.u.registry_response.owner.u.owned.node_id = entry_owner_id; gcc_pdu.u.response.u.registry_response.owner.u.owned.entity_id = entry_entity_id; } else { gcc_pdu.u.response.u.registry_response.owner.choice = NOT_OWNED_CHOSEN; } // Set up the requesters entity ID gcc_pdu.u.response.u.registry_response.entity_id = requester_entity_id; // Set up the primitive type gcc_pdu.u.response.u.registry_response.primitive_type = primitive_type; gcc_pdu.u.response.u.registry_response.result = ::TranslateGCCResultToRegistryResp(result); if (modification_rights != GCC_NO_MODIFICATION_RIGHTS_SPECIFIED) { gcc_pdu.u.response.u.registry_response.bit_mask |= RESPONSE_MODIFY_RIGHTS_PRESENT; gcc_pdu.u.response.u.registry_response.response_modify_rights = (RegistryModificationRights)modification_rights; } DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, requester_owner_id, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); error_value = GCC_ALLOCATION_FAILURE; delete packet; } } DebugExitVOID(MCSUser::RegistryResponse); } /* * void RegistryMonitorEntryIndication() * * Public Function Description: * This routine is used by the top provider to issue a monitor * indication anytime a registry entry that is being monitored changes. */ void MCSUser::RegistryMonitorEntryIndication ( CRegKeyContainer *registry_key_data, CRegItem *registry_item_data, UserID entry_owner_id, EntityID entry_entity_id, GCCModificationRights modification_rights) { GCCError error_value; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; /* ** Encode the conference join response PDU, along with the sequence ** number. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = REGISTRY_MONITOR_ENTRY_INDICATION_CHOSEN; gcc_pdu.u.indication.u.registry_monitor_entry_indication.bit_mask = 0; error_value = registry_key_data->GetRegistryKeyDataPDU( &gcc_pdu.u.indication.u. registry_monitor_entry_indication.key); if (error_value == GCC_NO_ERROR) { registry_item_data->GetRegistryItemDataPDU(&gcc_pdu.u.indication.u.registry_monitor_entry_indication.item); // Set up the entry owner if (entry_owner_id != 0) { gcc_pdu.u.indication.u.registry_monitor_entry_indication.owner.choice = OWNED_CHOSEN; gcc_pdu.u.indication.u.registry_monitor_entry_indication.owner.u.owned.node_id = entry_owner_id; gcc_pdu.u.indication.u.registry_monitor_entry_indication.owner.u.owned.entity_id = entry_entity_id; } else { gcc_pdu.u.indication.u.registry_monitor_entry_indication.owner.choice = NOT_OWNED_CHOSEN; } if (modification_rights != GCC_NO_MODIFICATION_RIGHTS_SPECIFIED) { gcc_pdu.u.indication.u.registry_monitor_entry_indication.bit_mask |= RESPONSE_MODIFY_RIGHTS_PRESENT; gcc_pdu.u.indication.u.registry_monitor_entry_indication.entry_modify_rights = (RegistryModificationRights)modification_rights; } DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; } } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /************************************************************************/ /* * GCCError AppInvokeIndication() * * Public Function Description: * This routine is used to send an application invoke indication to * every node in the conference. */ GCCError MCSUser::AppInvokeIndication( CInvokeSpecifierListContainer *invoke_specifier_list, GCCSimpleNodeList *pNodeList) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; PSetOfDestinationNodes new_destination_node; PSetOfDestinationNodes old_destination_node = NULL; PSetOfDestinationNodes pDstNodesToFree = NULL; UINT i; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = APPLICATION_INVOKE_INDICATION_CHOSEN; gcc_pdu.u.indication.u.application_invoke_indication.bit_mask = 0; gcc_pdu.u.indication.u.application_invoke_indication.destination_nodes = NULL; gcc_pdu.u.indication.u.application_invoke_indication.application_protocol_entity_list = NULL; // First, set up the destination node list if (pNodeList->cNodes != 0) { gcc_pdu.u.indication.u.application_invoke_indication.bit_mask |= DESTINATION_NODES_PRESENT; for (i = 0; i < pNodeList->cNodes; i++) { DBG_SAVE_FILE_LINE new_destination_node = new SetOfDestinationNodes; if (new_destination_node != NULL) { if (gcc_pdu.u.indication.u.application_invoke_indication. destination_nodes == NULL) { gcc_pdu.u.indication.u.application_invoke_indication. destination_nodes = new_destination_node; pDstNodesToFree = new_destination_node; } else { old_destination_node->next = new_destination_node; } old_destination_node = new_destination_node; new_destination_node->next = NULL; new_destination_node->value = pNodeList->aNodeIDs[i]; } else { rc = GCC_ALLOCATION_FAILURE; break; } } } if (rc == GCC_NO_ERROR) { rc = invoke_specifier_list->GetApplicationInvokeSpecifierListPDU( &gcc_pdu.u.indication.u.application_invoke_indication. application_protocol_entity_list); } if (rc == GCC_NO_ERROR) { DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } if (NULL != pDstNodesToFree) { PSetOfDestinationNodes p; while (NULL != (p = pDstNodesToFree)) { pDstNodesToFree = pDstNodesToFree->next; delete p; } } if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } return rc; } /* * GCCError TextMessageIndication() * * Public Function Description: * This routine is used to send a text message to either a specific node * or to every node in the conference. */ GCCError MCSUser::TextMessageIndication ( LPWSTR pwszTextMsg, UserID destination_node ) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; LPWSTR pwszMsg; // Encode the PDU that will be forwarded to the top provider. gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = TEXT_MESSAGE_INDICATION_CHOSEN; if (NULL != (pwszMsg = ::My_strdupW(pwszTextMsg))) { gcc_pdu.u.indication.u.text_message_indication.message.length = ::lstrlenW(pwszMsg); gcc_pdu.u.indication.u.text_message_indication.message.value = pwszMsg; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPVOID)&gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue( packet, (destination_node == 0) ? BROADCAST_CHANNEL_ID : destination_node, HIGH_PRIORITY, FALSE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } delete pwszMsg; } else { rc = GCC_ALLOCATION_FAILURE; } if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } return rc; } /* * GCCError ConferenceAssistanceIndication() * * Public Function Description: * This routine is used to send a conference assistance indication to * every node in the conference. */ GCCError MCSUser::ConferenceAssistanceIndication ( UINT number_of_user_data_members, PGCCUserData * user_data_list) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; CUserDataListContainer *user_data_record; DebugEntry(MCSUser::ConferenceAssistanceIndication); // Encode the PDU gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_ASSISTANCE_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_assistance_indication.bit_mask = 0; // Construct the user data list container if ((number_of_user_data_members != 0) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE user_data_record = new CUserDataListContainer(number_of_user_data_members, user_data_list, &rc); if (user_data_record == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { user_data_record = NULL; } if ((user_data_record != NULL) && (rc == GCC_NO_ERROR)) { rc = user_data_record->GetUserDataPDU( &gcc_pdu.u.indication.u.conference_assistance_indication. cain_user_data); gcc_pdu.u.indication.u.conference_assistance_indication.bit_mask |= CAIN_USER_DATA_PRESENT; } if (rc == GCC_NO_ERROR) { DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } // Clean up containers if (user_data_record != NULL) { user_data_record->Release(); } return (rc); } /* * GCCError ConferenceTransferRequest() * * Public Function Description: * This routine is used to send a conference transfer request to the * top provider in the conference. */ GCCError MCSUser::ConferenceTransferRequest ( PGCCConferenceName destination_conference_name, GCCNumericString destination_conference_modifier, CNetAddrListContainer *destination_address_list, UINT number_of_destination_nodes, PUserID destination_node_list, CPassword *password) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; UINT string_length; PSetOfTransferringNodesRq new_set_of_nodes; PSetOfTransferringNodesRq old_set_of_nodes; UINT i; DebugEntry(MCSUser::ConferenceTransferRequest); // Encode the PDU gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = CONFERENCE_TRANSFER_REQUEST_CHOSEN; gcc_pdu.u.request.u.conference_transfer_request.bit_mask = 0; // First get the conference name (either numeric or text). if (destination_conference_name->numeric_string != NULL) { gcc_pdu.u.request.u.conference_transfer_request.conference_name.choice = NAME_SELECTOR_NUMERIC_CHOSEN; lstrcpy (gcc_pdu.u.request.u.conference_transfer_request. conference_name.u.name_selector_numeric, (LPSTR)destination_conference_name->numeric_string); } else { // Use a unicode string to determine the length gcc_pdu.u.request.u.conference_transfer_request.conference_name.choice = NAME_SELECTOR_TEXT_CHOSEN; string_length = ::My_strlenW(destination_conference_name->text_string); gcc_pdu.u.request.u.conference_transfer_request. conference_name.u.name_selector_text.length = string_length; gcc_pdu.u.request.u.conference_transfer_request. conference_name.u.name_selector_text.value = destination_conference_name->text_string; } // Next get the conference name modifier if it exists if (destination_conference_modifier != NULL) { gcc_pdu.u.request.u.conference_transfer_request.bit_mask |= CTRQ_CONFERENCE_MODIFIER_PRESENT; lstrcpy (gcc_pdu.u.request.u.conference_transfer_request. ctrq_conference_modifier, (LPSTR)destination_conference_modifier); } // Get the network address list if it exist if (destination_address_list != NULL) { gcc_pdu.u.request.u.conference_transfer_request.bit_mask |= CTRQ_NETWORK_ADDRESS_PRESENT; rc = destination_address_list->GetNetworkAddressListPDU ( &gcc_pdu.u.request.u.conference_transfer_request. ctrq_net_address); } // Get the destination node list if it exists if ((number_of_destination_nodes != 0) && (rc == GCC_NO_ERROR)) { gcc_pdu.u.request.u.conference_transfer_request.bit_mask |= CTRQ_TRANSFERRING_NODES_PRESENT; old_set_of_nodes = NULL; gcc_pdu.u.request.u.conference_transfer_request. ctrq_transferring_nodes = NULL; for (i = 0; i < number_of_destination_nodes; i++) { DBG_SAVE_FILE_LINE new_set_of_nodes = new SetOfTransferringNodesRq; if (new_set_of_nodes == NULL) { rc = GCC_ALLOCATION_FAILURE; break; } else new_set_of_nodes->next = NULL; if (old_set_of_nodes == NULL) { gcc_pdu.u.request.u.conference_transfer_request. ctrq_transferring_nodes = new_set_of_nodes; } else old_set_of_nodes->next = new_set_of_nodes; old_set_of_nodes = new_set_of_nodes; new_set_of_nodes->value = destination_node_list[i]; } } // Get the password if it exists if ((password != NULL) && (rc == GCC_NO_ERROR)) { gcc_pdu.u.request.u.conference_transfer_request.bit_mask |= CTRQ_PASSWORD_PRESENT; rc = password->GetPasswordSelectorPDU ( &gcc_pdu.u.request.u.conference_transfer_request.ctrq_password); } // Encode the PDU if (rc == GCC_NO_ERROR) { DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } // Clean up the node list if it was created if (gcc_pdu.u.request.u.conference_transfer_request.bit_mask & CTRQ_TRANSFERRING_NODES_PRESENT) { old_set_of_nodes = gcc_pdu.u.request.u.conference_transfer_request. ctrq_transferring_nodes; while (old_set_of_nodes != NULL) { new_set_of_nodes = old_set_of_nodes->next; delete old_set_of_nodes; old_set_of_nodes = new_set_of_nodes; } } return rc; } /* * GCCError ConferenceTransferIndication() * * Public Function Description: * This routine is used by the top provider to send out the transfer * indication to every node in the conference. It is each nodes * responsiblity to search the destination node list to see if * it should transfer. */ GCCError MCSUser::ConferenceTransferIndication ( PGCCConferenceName destination_conference_name, GCCNumericString destination_conference_modifier, CNetAddrListContainer *destination_address_list, UINT number_of_destination_nodes, PUserID destination_node_list, CPassword *password) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; UINT string_length; PSetOfTransferringNodesIn new_set_of_nodes; PSetOfTransferringNodesIn old_set_of_nodes; UINT i; DebugEntry(MCSUser::ConferenceTransferIndication); // Encode the PDU gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_TRANSFER_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_transfer_indication.bit_mask = 0; // First get the conference name (either numeric or text). if (destination_conference_name->numeric_string != NULL) { gcc_pdu.u.indication.u.conference_transfer_indication. conference_name.choice = NAME_SELECTOR_NUMERIC_CHOSEN; lstrcpy (gcc_pdu.u.indication.u.conference_transfer_indication. conference_name.u.name_selector_numeric, (LPSTR)destination_conference_name->numeric_string); } else { // Use a unicode string to determine the length gcc_pdu.u.indication.u.conference_transfer_indication. conference_name.choice = NAME_SELECTOR_TEXT_CHOSEN; string_length = ::My_strlenW(destination_conference_name->text_string); gcc_pdu.u.indication.u.conference_transfer_indication. conference_name.u.name_selector_text.length = string_length; gcc_pdu.u.indication.u.conference_transfer_indication. conference_name.u.name_selector_text.value = destination_conference_name->text_string; } // Next get the conference name modifier if it exists if (destination_conference_modifier != NULL) { gcc_pdu.u.indication.u.conference_transfer_indication.bit_mask |= CTIN_CONFERENCE_MODIFIER_PRESENT; lstrcpy (gcc_pdu.u.indication.u.conference_transfer_indication. ctin_conference_modifier, (LPSTR)destination_conference_modifier); } // Get the network address list if it exist if (destination_address_list != NULL) { gcc_pdu.u.indication.u.conference_transfer_indication.bit_mask |= CTIN_NETWORK_ADDRESS_PRESENT; rc = destination_address_list->GetNetworkAddressListPDU ( &gcc_pdu.u.indication.u.conference_transfer_indication. ctin_net_address); } // Get the destination node list if it exists if ((number_of_destination_nodes != 0) && (rc == GCC_NO_ERROR)) { gcc_pdu.u.indication.u.conference_transfer_indication.bit_mask |= CTIN_TRANSFERRING_NODES_PRESENT; old_set_of_nodes = NULL; gcc_pdu.u.indication.u.conference_transfer_indication. ctin_transferring_nodes = NULL; for (i = 0; i < number_of_destination_nodes; i++) { DBG_SAVE_FILE_LINE new_set_of_nodes = new SetOfTransferringNodesIn; if (new_set_of_nodes == NULL) { rc = GCC_ALLOCATION_FAILURE; break; } else new_set_of_nodes->next = NULL; if (old_set_of_nodes == NULL) { gcc_pdu.u.indication.u.conference_transfer_indication. ctin_transferring_nodes = new_set_of_nodes; } else old_set_of_nodes->next = new_set_of_nodes; old_set_of_nodes = new_set_of_nodes; new_set_of_nodes->value = destination_node_list[i]; } } // Get the password if it exists if ((password != NULL) && (rc == GCC_NO_ERROR)) { gcc_pdu.u.indication.u.conference_transfer_indication.bit_mask |= CTIN_PASSWORD_PRESENT; rc = password->GetPasswordSelectorPDU ( &gcc_pdu.u.indication.u.conference_transfer_indication. ctin_password); } // Encode the PDU if (rc == GCC_NO_ERROR) { DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } // Clean up the node list if it was created if (gcc_pdu.u.indication.u.conference_transfer_indication.bit_mask & CTIN_TRANSFERRING_NODES_PRESENT) { old_set_of_nodes = gcc_pdu.u.indication.u. conference_transfer_indication.ctin_transferring_nodes; while (old_set_of_nodes != NULL) { new_set_of_nodes = old_set_of_nodes->next; delete old_set_of_nodes; old_set_of_nodes = new_set_of_nodes; } } DebugExitINT(MCSUser::ConferenceTransferIndication, rc); return rc; } /* * GCCError ConferenceTransferResponse() * * Public Function Description: * This routine is used by the top provider to send back a response to * the node that made a transfer request. The info specified in the * request is included in the response to match request to response. */ GCCError MCSUser::ConferenceTransferResponse ( UserID requesting_node_id, PGCCConferenceName destination_conference_name, GCCNumericString destination_conference_modifier, UINT number_of_destination_nodes, PUserID destination_node_list, GCCResult result) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; UINT string_length; PSetOfTransferringNodesRs new_set_of_nodes; PSetOfTransferringNodesRs old_set_of_nodes; UINT i; DebugEntry(MCSUser::ConferenceTransferResponse); // Encode the PDU gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = CONFERENCE_TRANSFER_RESPONSE_CHOSEN; gcc_pdu.u.response.u.conference_transfer_response.bit_mask = 0; // First get the conference name (either numeric or text). if (destination_conference_name->numeric_string != NULL) { gcc_pdu.u.response.u.conference_transfer_response. conference_name.choice = NAME_SELECTOR_NUMERIC_CHOSEN; ::lstrcpyA(gcc_pdu.u.response.u.conference_transfer_response. conference_name.u.name_selector_numeric, (LPSTR)destination_conference_name->numeric_string); } else { // Use a unicode string to determine the length gcc_pdu.u.response.u.conference_transfer_response. conference_name.choice = NAME_SELECTOR_TEXT_CHOSEN; string_length = ::My_strlenW(destination_conference_name->text_string); gcc_pdu.u.response.u.conference_transfer_response. conference_name.u.name_selector_text.length = string_length; gcc_pdu.u.response.u.conference_transfer_response. conference_name.u.name_selector_text.value = destination_conference_name->text_string; } // Next get the conference name modifier if it exists if (destination_conference_modifier != NULL) { gcc_pdu.u.response.u.conference_transfer_response.bit_mask |= CTRS_CONFERENCE_MODIFIER_PRESENT; ::lstrcpyA(gcc_pdu.u.response.u.conference_transfer_response. ctrs_conference_modifier, (LPSTR)destination_conference_modifier); } // Get the destination node list if it exists if ((number_of_destination_nodes != 0) && (rc == GCC_NO_ERROR)) { gcc_pdu.u.response.u.conference_transfer_response.bit_mask |= CTRS_TRANSFERRING_NODES_PRESENT; old_set_of_nodes = NULL; gcc_pdu.u.response.u.conference_transfer_response. ctrs_transferring_nodes = NULL; for (i = 0; i < number_of_destination_nodes; i++) { DBG_SAVE_FILE_LINE new_set_of_nodes = new SetOfTransferringNodesRs; if (new_set_of_nodes == NULL) { rc = GCC_ALLOCATION_FAILURE; break; } else new_set_of_nodes->next = NULL; if (old_set_of_nodes == NULL) { gcc_pdu.u.response.u.conference_transfer_response. ctrs_transferring_nodes = new_set_of_nodes; } else old_set_of_nodes->next = new_set_of_nodes; old_set_of_nodes = new_set_of_nodes; new_set_of_nodes->value = destination_node_list[i]; } } // Set up the result if (result == GCC_RESULT_SUCCESSFUL) { gcc_pdu.u.response.u.conference_transfer_response.result = CTRANS_RESULT_SUCCESS; } else { gcc_pdu.u.response.u.conference_transfer_response.result = CTRANS_RESULT_INVALID_REQUESTER; } // Encode the PDU if (rc == GCC_NO_ERROR) { DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, requesting_node_id, HIGH_PRIORITY, FALSE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } // Clean up the node list if it was created if (gcc_pdu.u.response.u.conference_transfer_response.bit_mask & CTRS_TRANSFERRING_NODES_PRESENT) { old_set_of_nodes = gcc_pdu.u.response.u. conference_transfer_response.ctrs_transferring_nodes; while (old_set_of_nodes != NULL) { new_set_of_nodes = old_set_of_nodes->next; delete old_set_of_nodes; old_set_of_nodes = new_set_of_nodes; } } DebugExitINT(MCSUser::ConferenceTransferResponse, rc); return rc; } /* * GCCError ConferenceAddRequest() * * Public Function Description: * This routine is used to send a conference add request to the appropriate * node. This call can be made by the requesting node or by the top * provider to pass the add request on to the adding node. */ GCCError MCSUser::ConferenceAddRequest ( TagNumber conference_add_tag, UserID requesting_node, UserID adding_node, UserID target_node, CNetAddrListContainer *network_address_container, CUserDataListContainer *user_data_container) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; DebugEntry(MCSUser::ConferenceAddRequest); // Encode the PDU gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = CONFERENCE_ADD_REQUEST_CHOSEN; gcc_pdu.u.request.u.conference_add_request.bit_mask = 0; // Get the network address list if it exist if (network_address_container != NULL) { // Set up the network address portion of the pdu rc = network_address_container->GetNetworkAddressListPDU ( &gcc_pdu.u.request.u.conference_add_request. add_request_net_address); // Set up the user data container if ((rc == GCC_NO_ERROR) && (user_data_container != NULL)) { rc = user_data_container->GetUserDataPDU ( &gcc_pdu.u.request.u.conference_add_request.carq_user_data); if (rc == GCC_NO_ERROR) { gcc_pdu.u.request.u.conference_add_request.bit_mask |= CARQ_USER_DATA_PRESENT; } } // Encode the PDU if (rc == GCC_NO_ERROR) { // specify the requesting node gcc_pdu.u.request.u.conference_add_request.requesting_node = requesting_node; if (adding_node != 0) { gcc_pdu.u.request.u.conference_add_request.bit_mask |= ADDING_MCU_PRESENT; gcc_pdu.u.request.u.conference_add_request.adding_mcu = adding_node; } gcc_pdu.u.request.u.conference_add_request.tag = conference_add_tag; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, target_node, HIGH_PRIORITY, FALSE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } } else { rc = GCC_BAD_NETWORK_ADDRESS; } DebugExitINT(MCSUser::ConferenceAddRequest, rc); return rc; } /* * GCCError ConferenceAddResponse() * * Public Function Description: * This routine is used to send a conference add request to the appropriate * node. This call can be made by the requesting node or by the top * provider to pass the add request on to the adding node. */ GCCError MCSUser::ConferenceAddResponse( TagNumber add_request_tag, UserID requesting_node, CUserDataListContainer *user_data_container, GCCResult result) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; DebugEntry(MCSUser::ConferenceAddResponse); // Encode the PDU gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = CONFERENCE_ADD_RESPONSE_CHOSEN; gcc_pdu.u.response.u.conference_add_response.bit_mask = 0; // Set up the user data container if ((rc == GCC_NO_ERROR) && (user_data_container != NULL)) { rc = user_data_container->GetUserDataPDU ( &gcc_pdu.u.response.u.conference_add_response.cars_user_data); if (rc == GCC_NO_ERROR) { gcc_pdu.u.response.u.conference_add_response.bit_mask |= CARS_USER_DATA_PRESENT; } } // Encode the PDU if (rc == GCC_NO_ERROR) { gcc_pdu.u.response.u.conference_add_response.tag = add_request_tag; gcc_pdu.u.response.u.conference_add_response.result = ::TranslateGCCResultToAddResult(result); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, requesting_node, HIGH_PRIORITY, FALSE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } DebugExitINT(MCSUser::ConferenceAddResponse, rc); return rc; } /************************* Conductorship Calls ***********************/ /* * GCCError ConductorTokenGrab() * * Public Function Description: * This routine makes the MCS calls to grab the conductor token. */ GCCError MCSUser::ConductorTokenGrab() { MCSError mcs_error; mcs_error = g_pMCSIntf->TokenGrabRequest(m_pMCSSap, CONDUCTOR_TOKEN_ID); return (g_pMCSIntf->TranslateMCSIFErrorToGCCError (mcs_error)); } /* * GCCError ConductorTokenRelease() * * Public Function Description: * This routine makes the MCS calls to release the conductor token. */ GCCError MCSUser::ConductorTokenRelease() { MCSError mcs_error; mcs_error = g_pMCSIntf->TokenReleaseRequest(m_pMCSSap, CONDUCTOR_TOKEN_ID); return (g_pMCSIntf->TranslateMCSIFErrorToGCCError (mcs_error)); } /* * GCCError ConductorTokenPlease() * * Public Function Description: * This routine makes the MCS calls to request the conductor token from * the current conductor. */ GCCError MCSUser::ConductorTokenPlease() { MCSError mcs_error; mcs_error = g_pMCSIntf->TokenPleaseRequest(m_pMCSSap, CONDUCTOR_TOKEN_ID); return (g_pMCSIntf->TranslateMCSIFErrorToGCCError (mcs_error)); } /* * GCCError ConductorTokenGive () * * Public Function Description: * This routine makes the MCS calls to give the conductor token to the * specified node. */ GCCError MCSUser::ConductorTokenGive(UserID recipient_user_id) { MCSError mcs_error; mcs_error = g_pMCSIntf->TokenGiveRequest(m_pMCSSap, CONDUCTOR_TOKEN_ID, recipient_user_id); return (g_pMCSIntf->TranslateMCSIFErrorToGCCError (mcs_error)); } /* * GCCError ConductorTokenGiveResponse () * * Public Function Description: * This routine makes the MCS calls to respond to a conductor give * request. */ GCCError MCSUser::ConductorTokenGiveResponse(Result result) { MCSError mcs_error; mcs_error = g_pMCSIntf->TokenGiveResponse(m_pMCSSap, CONDUCTOR_TOKEN_ID, result); return g_pMCSIntf->TranslateMCSIFErrorToGCCError(mcs_error); } /* * GCCError ConductorTokenTest () * * Public Function Description: * This routine is used to test the current state of the conductor token * (is it grabbed or not). */ GCCError MCSUser::ConductorTokenTest() { MCSError mcs_error; mcs_error = g_pMCSIntf->TokenTestRequest(m_pMCSSap, CONDUCTOR_TOKEN_ID); return g_pMCSIntf->TranslateMCSIFErrorToGCCError(mcs_error); } /* * GCCError SendConductorAssignIndication() * * Public Function Description: * This routine sends a conductor assign indication to all the * nodes in the conference. */ GCCError MCSUser::SendConductorAssignIndication( UserID conductor_user_id) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; /* ** Fill in the ConductorAssignIndication pdu structure to be passed in the ** constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONDUCTOR_ASSIGN_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conductor_assign_indication.user_id = conductor_user_id; /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, TOP_PRIORITY, TRUE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConductorReleaseIndication() * * Public Function Description: * This routine sends a conductor release indication to all the * nodes in the conference. */ GCCError MCSUser::SendConductorReleaseIndication() { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; /* ** Fill in the ConductorAssignIndication pdu structure to be passed in the ** constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONDUCTOR_RELEASE_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conductor_release_indication.placeholder = 0; /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, TOP_PRIORITY, TRUE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConductorPermitAsk () * * Public Function Description: * This routine sends a conductor permission ask request directly to the * conductor node. */ GCCError MCSUser::SendConductorPermitAsk ( BOOL grant_permission) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; /* ** Fill in the ConductorPermissionAskIndication pdu structure to be passed ** in the constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONDUCTOR_PERMISSION_ASK_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conductor_permission_ask_indication. permission_is_granted = (ASN1bool_t)grant_permission; /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError SendConductorPermitGrant () * * Public Function Description: * This routine sends a conductor permission grant indication to every * node in the conference. Usually issued when permissions change. */ GCCError MCSUser::SendConductorPermitGrant ( UINT number_granted, PUserID granted_node_list, UINT number_waiting, PUserID waiting_node_list) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; PPermissionList permission_list; PPermissionList previous_permission_list; PWaitingList waiting_list; PWaitingList previous_waiting_list; UINT i; /* ** Fill in the ConductorPermissionAskIndication pdu structure to be passed ** in the constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONDUCTOR_PERMISSION_GRANT_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conductor_permission_grant_indication.bit_mask = 0; // First fill in the granted node permission list gcc_pdu.u.indication.u. conductor_permission_grant_indication.permission_list = NULL; previous_permission_list = NULL; for (i = 0; i < number_granted; i++) { DBG_SAVE_FILE_LINE permission_list = new PermissionList; if (permission_list == NULL) { rc = GCC_ALLOCATION_FAILURE; break; } if (previous_permission_list == NULL) { gcc_pdu.u.indication.u.conductor_permission_grant_indication. permission_list = permission_list; } else previous_permission_list->next = permission_list; previous_permission_list = permission_list; permission_list->value = granted_node_list[i]; permission_list->next = NULL; } // If waiting list exists fill it in if ((number_waiting != 0) && (rc == GCC_NO_ERROR)) { gcc_pdu.u.indication.u.conductor_permission_grant_indication.bit_mask = WAITING_LIST_PRESENT; gcc_pdu.u.indication.u. conductor_permission_grant_indication.waiting_list = NULL; previous_waiting_list = NULL; for (i = 0; i < number_waiting; i++) { DBG_SAVE_FILE_LINE waiting_list = new WaitingList; if (waiting_list == NULL) { rc = GCC_ALLOCATION_FAILURE; break; } if (previous_waiting_list == NULL) { gcc_pdu.u.indication.u.conductor_permission_grant_indication. waiting_list = waiting_list; } else previous_waiting_list->next = waiting_list; previous_waiting_list = waiting_list; waiting_list->value = waiting_node_list[i]; waiting_list->next = NULL; } } /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, TOP_PRIORITY, TRUE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /**********************************************************************/ /***************** Miscelaneous calls ******************************/ /* * GCCError TimeRemainingRequest() * * Public Function Description: * This routine sends out an indication to every node in the * conference informing how much time is remaining in the conference. */ GCCError MCSUser::TimeRemainingRequest ( UINT time_remaining, UserID node_id) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; /* ** Fill in the TimeRemainingRequest pdu structure to be passed in the ** constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_TIME_REMAINING_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_time_remaining_indication.bit_mask = 0; gcc_pdu.u.indication.u.conference_time_remaining_indication.time_remaining = time_remaining; if (node_id != 0) { gcc_pdu.u.indication.u.conference_time_remaining_indication.bit_mask |= TIME_REMAINING_NODE_ID_PRESENT; gcc_pdu.u.indication.u.conference_time_remaining_indication. time_remaining_node_id = node_id; } /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError TimeInquireRequest() * * Public Function Description: * This routine sends out a request for a time remaing update. */ GCCError MCSUser::TimeInquireRequest ( BOOL time_is_conference_wide) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; /* ** Fill in the TimeInquireRequest pdu structure to be passed in the ** constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_TIME_INQUIRE_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_time_inquire_indication. time_is_node_specific = (ASN1bool_t)time_is_conference_wide; /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, CONVENER_CHANNEL_ID, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * GCCError ConferenceExtendIndication() * * Public Function Description: * This routine sends out an indication informing conference participants * of an extension. */ GCCError MCSUser::ConferenceExtendIndication ( UINT extension_time, BOOL time_is_conference_wide) { GCCError rc = GCC_NO_ERROR; PPacket packet; GCCPDU gcc_pdu; PacketError packet_error; /* ** Fill in the ConfernceExtendIndication pdu structure to be passed in the ** constructor of the packet class. */ gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_TIME_EXTEND_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_time_extend_indication. time_to_extend = extension_time; gcc_pdu.u.indication.u.conference_time_extend_indication. time_is_node_specific = (ASN1bool_t)time_is_conference_wide; /* ** Create a packet object */ DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, // pdu_type TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, CONVENER_CHANNEL_ID, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * void ConferenceJoinResponse() * * Functional Description: * This function is called by the conference object of the * top provider when it wants to send the join response back to the gcc * provider that made the join request, through the directly connected * intermediate node. This function does the encoding of the join response * PDU and also adds the sequence number sent in the request. */ void MCSUser::ConferenceJoinResponse( UserID receiver_id, BOOL password_is_in_the_clear, BOOL conference_locked, BOOL conference_listed, GCCTerminationMethod termination_method, CPassword *password_challenge, CUserDataListContainer *user_data_list, GCCResult result) { GCCError rc = GCC_NO_ERROR; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; TagNumber lTagNum; if (0 == (lTagNum = m_ConfJoinResponseList2.Find(receiver_id))) { WARNING_OUT(("MCSUser::ConferenceJoinResponse: Unexpected Join Response")); return; } /* ** Encode the conference join response PDU, along with the sequence ** number. */ gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = CONFERENCE_JOIN_RESPONSE_CHOSEN; gcc_pdu.u.response.u.conference_join_response.bit_mask = 0; /* ** Get the sequence number of the outstanding response from the ** list of seq # vs userID using the userID passed from above. */ gcc_pdu.u.response.u.conference_join_response.tag = lTagNum; // Remove this entry from the list. m_ConfJoinResponseList2.Remove(receiver_id); // Get password challenge PDU if ((password_challenge != NULL) && (rc == GCC_NO_ERROR)) { rc = password_challenge->GetPasswordChallengeResponsePDU ( &gcc_pdu.u.response.u.conference_join_response.cjrs_password); if (rc == GCC_NO_ERROR) { gcc_pdu.u.response.u.conference_join_response.bit_mask |= CJRS_PASSWORD_PRESENT; } } // Get user data list PDU if ((user_data_list != NULL) && (rc == GCC_NO_ERROR)) { rc = user_data_list->GetUserDataPDU ( &gcc_pdu.u.response.u.conference_join_response.cjrs_user_data); if (rc == GCC_NO_ERROR) { gcc_pdu.u.response.u.conference_join_response.bit_mask |= CJRS_USER_DATA_PRESENT; } } if (rc == GCC_NO_ERROR) { gcc_pdu.u.response.u.conference_join_response. top_node_id = m_nidTopProvider; gcc_pdu.u.response.u.conference_join_response. clear_password_required = (ASN1bool_t)password_is_in_the_clear; gcc_pdu.u.response.u.conference_join_response. conference_is_locked = (ASN1bool_t)conference_locked; gcc_pdu.u.response.u.conference_join_response. conference_is_listed = (ASN1bool_t)conference_listed; gcc_pdu.u.response.u.conference_join_response.termination_method = (TerminationMethod)termination_method; gcc_pdu.u.response.u.conference_join_response.result = ::TranslateGCCResultToJoinResult(result); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, receiver_id, TOP_PRIORITY, FALSE); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void ConferenceTerminateRequest() * * Functional Description: * This routine is used by a node subordinate to the top provider to * request that the conference by terminated. */ void MCSUser::ConferenceTerminateRequest( GCCReason reason) { GCCError error_value = GCC_NO_ERROR; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = CONFERENCE_TERMINATE_REQUEST_CHOSEN; gcc_pdu.u.request.u.conference_terminate_request.reason = ::TranslateGCCReasonToTerminateRqReason(reason); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, m_nidTopProvider, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); error_value = GCC_ALLOCATION_FAILURE; delete packet; } } /* * void ConferenceTerminateResponse () * * Functional Description: * This routine is used by the top provider to respond to a terminate * request issued by a subordinate node. The result indicates if the * requesting node had the correct privileges. */ void MCSUser::ConferenceTerminateResponse ( UserID requester_id, GCCResult result) { GCCError error_value = GCC_NO_ERROR; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = CONFERENCE_TERMINATE_RESPONSE_CHOSEN; gcc_pdu.u.response.u.conference_terminate_response.result = ::TranslateGCCResultToTerminateResult(result); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, requester_id, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); error_value = GCC_ALLOCATION_FAILURE; delete packet; } } /* * GCCError ConferenceTerminateIndication() * * Functional Description: * This routine is used by the top provider to send out a terminate * indication to every node in the conference. */ void MCSUser::ConferenceTerminateIndication ( GCCReason reason) { GCCError error_value = GCC_NO_ERROR; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_TERMINATE_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_terminate_indication.reason = ::TranslateGCCReasonToTerminateInReason(reason); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } else { ResourceFailureHandler(); error_value = GCC_ALLOCATION_FAILURE; delete packet; } } /* * void EjectNodeFromConference() * * Functional Description: * This routine is used when attempting to eject a node from the * conference. */ GCCError MCSUser::EjectNodeFromConference ( UserID ejected_node_id, GCCReason reason) { GCCError rc = GCC_NO_ERROR; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; ChannelID channel_id; BOOL uniform_send; Priority priority; PAlarm alarm; if (ejected_node_id == m_nidMyself) { /* ** If the ejected node is this node we can immediately initiate the ** ejection. There is no need to request this through the Top ** Provider. */ rc = InitiateEjectionFromConference (reason); } else { /* ** If the ejected node is a child node to this node we can directly ** eject it. Otherwise the request is forwarded to the Top Provider. */ if (m_ChildUidConnHdlList2.Find(ejected_node_id) || (m_nidTopProvider == m_nidMyself)) { gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_EJECT_USER_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_eject_user_indication. node_to_eject = ejected_node_id; gcc_pdu.u.indication.u.conference_eject_user_indication.reason = ::TranslateGCCReasonToEjectInd(reason); uniform_send = TRUE; channel_id = BROADCAST_CHANNEL_ID; // If this is the top provider send the data at TOP priority if (m_nidTopProvider == m_nidMyself) priority = TOP_PRIORITY; else priority = HIGH_PRIORITY; /* ** Set up ejection alarm to automatically eject any misbehaving ** nodes. Note that we only do this if we are directly connected ** to the node to be ejected. */ if (m_ChildUidConnHdlList2.Find(ejected_node_id)) { DBG_SAVE_FILE_LINE alarm = new Alarm (EJECTED_NODE_TIMER_DURATION); if (alarm != NULL) { /* ** Here we save the alarm in a list of ejected nodes. This ** alarm is used to cleanup any misbehaving node. */ m_EjectedNodeAlarmList2.Append(ejected_node_id, alarm); } else { rc = GCC_ALLOCATION_FAILURE; } } } else { gcc_pdu.choice = REQUEST_CHOSEN; gcc_pdu.u.request.choice = CONFERENCE_EJECT_USER_REQUEST_CHOSEN; gcc_pdu.u.request.u.conference_eject_user_request.node_to_eject = ejected_node_id; // The only valid reason is user initiated which is zero gcc_pdu.u.request.u.conference_eject_user_request.reason = CERQ_REASON_USER_INITIATED; uniform_send = FALSE; channel_id = m_nidTopProvider; priority = TOP_PRIORITY; } if (rc == GCC_NO_ERROR) { DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, channel_id, priority, uniform_send); } else { rc = GCC_ALLOCATION_FAILURE; delete packet; } } } if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } return rc; } /* * void SendEjectNodeResponse() * * Functional Description: * This routine is used by the top provider to respond to an eject * user request. */ GCCError MCSUser::SendEjectNodeResponse ( UserID requester_id, UserID node_to_eject, GCCResult result) { GCCError rc = GCC_NO_ERROR; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; gcc_pdu.choice = RESPONSE_CHOSEN; gcc_pdu.u.response.choice = CONFERENCE_EJECT_USER_RESPONSE_CHOSEN; gcc_pdu.u.response.u.conference_eject_user_response.node_to_eject = node_to_eject; gcc_pdu.u.response.u.conference_eject_user_response.result = ::TranslateGCCResultToEjectResult(result); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, requester_id, HIGH_PRIORITY, FALSE); } else { ResourceFailureHandler(); rc = GCC_ALLOCATION_FAILURE; delete packet; } return rc; } /* * void RosterUpdateIndication() * * Functional Description: * This routine is used to forward a roster update indication either * upward to the parent node or downward as a full refresh to all nodes * in the conference. */ void MCSUser::RosterUpdateIndication(PGCCPDU gcc_pdu, BOOL send_update_upward) { PPacket packet; PacketError packet_error; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { if (send_update_upward) { AddToMCSMessageQueue(packet, m_nidParent, HIGH_PRIORITY, FALSE); } else { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); } } else { ResourceFailureHandler(); delete packet; } } /* * void AddToMCSMessageQueue() * * Private Function Description: * This function adds the out bound messages to a queue which is * flushed in the next heartbeat when controller call FlushMessageQueue. * In case memory allocation for messages holding the out bound inform- * ation fails an owner call back is sent to conference object to * indicate insufficient memory. * * Formal Parameters: * packet - (i) Pointer to packet to queue up. * send_data_request_info - (i) Structure containing all the info * necessary to deliver the packet. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: AddToMCSMessageQueue ( PPacket packet, ChannelID channel_id, Priority priority, BOOL uniform_send ) { SEND_DATA_REQ_INFO *pReqInfo; DBG_SAVE_FILE_LINE pReqInfo = new SEND_DATA_REQ_INFO; if (pReqInfo != NULL) { pReqInfo->packet = packet; pReqInfo->channel_id = channel_id; pReqInfo->priority = priority; pReqInfo->uniform_send = uniform_send; /* ** This forces the packet to be encoded. This must happen here so ** that any memory used by the decoded portion of the packet can ** be freed after returning. */ // packet->Lock(); m_OutgoingPDUQueue.Append(pReqInfo); if (m_OutgoingPDUQueue.GetCount() == 1) { if (FlushOutgoingPDU()) { // Inform the MCS interface that there are PDUs queued g_pGCCController->SetEventToFlushOutgoingPDU(); } } else { // Inform the MCS interface that there are PDUs queued g_pGCCController->SetEventToFlushOutgoingPDU(); } } else { ResourceFailureHandler(); /* ** This just sets a flag in the packet object that allows packet ** to commit suicide if lock count on encoded and decoded data is ** zero. This will occur once the packet is sent on to MCS. */ packet->Unlock(); } } /* * BOOL FlushOutgoingPDU() * * Public Function Description: * This function is called by the owner object in every heartbeat. This * function iterates throught the list of pending out bound messages * and sends them down to MCS. Also after a successful send it frees * any resources tied up with the outbound messages. If however a message * can not be sent in this heartbeat, as indicated by MCS, then it * inserts the message back onto the message queue and returns. * * Return value: * TRUE, if there remain un-processed msgs in the MCS message queue * FALSE, if all the msgs in the MCS msg queue were processed. */ void MCSUser:: CheckEjectedNodeAlarms ( void ) { /* ** We first check the eject user list to make sure that no alarms have ** expired on any of the ejected nodes. */ if (m_EjectedNodeAlarmList2.IsEmpty() == FALSE) { PAlarm lpAlarm; UserID uid; // We copy the list so that we can remove entries in the iterator while (NULL != (lpAlarm = m_EjectedNodeAlarmList2.Get(&uid))) { // Has the alarm expired for this node? if (lpAlarm->IsExpired()) { ConnectionHandle hConn; /* ** Tell the owner object to disconnect the misbehaving node ** that exists at the connection handle accessed through ** the m_ChildUidConnHdlList2. */ if (NULL != (hConn = m_ChildUidConnHdlList2.Find(uid))) { // // This must generate a disconnect provider for eject node to // work properly. // g_pMCSIntf->DisconnectProviderRequest(hConn); // // Since this node will not get a disconnect indication when it // issues a DisconnectProviderRequest we go ahead and call it // from here. // m_pConf->DisconnectProviderIndication(hConn); } } // Delete the alarm delete lpAlarm; } } } BOOL MCSUser:: FlushOutgoingPDU ( void ) { DWORD mcs_message_count; DWORD count; UINT rc; SEND_DATA_REQ_INFO *pReqInfo; mcs_message_count = m_OutgoingPDUQueue.GetCount(); for (count = 0; (count < mcs_message_count) && (m_OutgoingPDUQueue.IsEmpty() == FALSE); count++) { /* ** Get the next message from the queue. */ pReqInfo = m_OutgoingPDUQueue.Get(); /* * If MCS takes the request without an error, free information * structure and unlock the encoded information in the packet. * Unlocking the packet before deleting the infomration structure * ensures that packet object is deleted and not left dangling. * This is true because here only one lock is performed. * If there is an error in the send data request, it means mcs can not * take any more requests, therefore insert the information * structure back in the queue and break out of this loop. */ if (pReqInfo->uniform_send) { rc = g_pMCSIntf->UniformSendDataRequest( pReqInfo->channel_id, m_pMCSSap, pReqInfo->priority, (LPBYTE) pReqInfo->packet->GetEncodedData(), pReqInfo->packet->GetEncodedDataLength()); } else { rc = g_pMCSIntf->SendDataRequest( pReqInfo->channel_id, m_pMCSSap, pReqInfo->priority, (LPBYTE) pReqInfo->packet->GetEncodedData(), pReqInfo->packet->GetEncodedDataLength()); } if (rc == MCS_NO_ERROR) { pReqInfo->packet->Unlock(); delete pReqInfo; } else { TRACE_OUT(("MCSUser::FlushMessageQueue: Could not send queued packet data in this heartbeat")); m_OutgoingPDUQueue.Prepend(pReqInfo); break; // breaking out of the for loop } } return (! (m_OutgoingPDUQueue.IsEmpty() && m_EjectedNodeAlarmList2.IsEmpty())); } /* * MCSUser::SetChildUserID() * * Public Function Description: * This function is called by the conference object to pass on the user id * of the child node to the user object. The user object inserts this * user id into a user id list of it's children which it maintains. */ void MCSUser::SetChildUserIDAndConnection ( UserID child_user_id, ConnectionHandle child_connection_handle) { TRACE_OUT(("MCSUser::SetChildUserID: Adding Child userid=0x%04x to the list", (UINT) child_user_id)); TRACE_OUT(("MCSUser::SetChildUserID: Adding Child Connection=%d to the list", (UINT) child_connection_handle)); m_ChildUidConnHdlList2.Append(child_user_id, child_connection_handle); } /* * GCCError InitiateEjectionFromConference() * * Private Function Description: * This internal routine kicks of the process of ejecting this node * from the conference. This includes ejecting all the nodes below * this node and waiting for their disconnect indications to come back * in. * * Formal Parameters: * reason - (i) Reason for ejection. * * Return Value * GCC_NO_ERROR - No error occured. * GCC_ALLOCATION_FAILURE - A resource error occured. * * Side Effects * None. * * Caveats * None. */ GCCError MCSUser::InitiateEjectionFromConference (GCCReason reason) { GCCError error_value = GCC_NO_ERROR; GCCPDU gcc_pdu; PPacket packet; PacketError packet_error; PAlarm alarm = NULL; m_fEjectionPending = TRUE; m_eEjectReason = reason; if (m_ChildUidConnHdlList2.IsEmpty() == FALSE) { UserID uid; gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = CONFERENCE_EJECT_USER_INDICATION_CHOSEN; gcc_pdu.u.indication.u.conference_eject_user_indication.reason = ::TranslateGCCReasonToEjectInd( GCC_REASON_HIGHER_NODE_EJECTED); m_ChildUidConnHdlList2.Reset(); while (m_ChildUidConnHdlList2.Iterate(&uid)) { // Get the Node to eject from the list of child nodes gcc_pdu.u.indication.u.conference_eject_user_indication.node_to_eject = uid; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, &gcc_pdu, GCC_PDU, TRUE, &packet_error); if ((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { AddToMCSMessageQueue(packet, BROADCAST_CHANNEL_ID, HIGH_PRIORITY, TRUE); DBG_SAVE_FILE_LINE alarm = new Alarm (EJECTED_NODE_TIMER_DURATION); if (alarm != NULL) { /* ** Here we save the alarm in a list of ejected ** nodes. This alarm is used to cleanup any ** misbehaving node. */ m_EjectedNodeAlarmList2.Append(uid, alarm); } else { error_value = GCC_ALLOCATION_FAILURE; break; } } else { error_value = GCC_ALLOCATION_FAILURE; delete packet; break; } } } else { m_pConf->ProcessEjectUserIndication(m_eEjectReason); } return (error_value); } /* * UINT ProcessSendDataIndication() * * Private Function Description: * This function is called when the user object gets send data indications * from below. It finds out the message type and decodes the pdu in the * user data field of send data indications. Based on the type of decoded * pdu it take the necessary actions. * * Formal Parameters: * send_data_info - (i) Send data structure to process. * * Return Value * MCS_NO_ERROR is always returned from this routine. * * Side Effects * None. * * Caveats * None. */ UINT MCSUser::ProcessSendDataIndication(PSendData send_data_info) { PPacket packet; PacketError packet_error; PGCCPDU gcc_pdu; GCCError error_value = GCC_NO_ERROR; UserID initiator; DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPBYTE)send_data_info->user_data.value, send_data_info->user_data.length, GCC_PDU, TRUE, &packet_error); if(packet != NULL && packet_error == PACKET_NO_ERROR) { initiator = send_data_info->initiator; gcc_pdu = (PGCCPDU)packet->GetDecodedData(); switch(gcc_pdu->choice) { case INDICATION_CHOSEN: // Data PDU switch(gcc_pdu->u.indication.choice) { case USER_ID_INDICATION_CHOSEN: { /* * Sequence number and User Id sent by the child * node after a successful conference create or * join. */ m_pConf->ProcessUserIDIndication( gcc_pdu->u.indication.u.user_id_indication.tag, initiator); } break; case ROSTER_UPDATE_INDICATION_CHOSEN: if(send_data_info->channel_id == m_nidMyself) { // // We only process the roster update if the conference is // established. // if (m_pConf->IsConfEstablished()) { m_pConf->ProcessRosterUpdatePDU(gcc_pdu, initiator); } } break; case CONFERENCE_TIME_INQUIRE_INDICATION_CHOSEN: g_pControlSap->ConfTimeInquireIndication( m_pConf->GetConfID(), gcc_pdu->u.indication.u.conference_time_inquire_indication.time_is_node_specific, initiator); break; case CONFERENCE_TIME_EXTEND_INDICATION_CHOSEN: #ifdef JASPER ProcessConferenceExtendIndicationPDU( &gcc_pdu->u.indication.u. conference_time_extend_indication, initiator); #endif // JASPER break; case APPLICATION_INVOKE_INDICATION_CHOSEN: ProcessApplicationInvokeIndication( &gcc_pdu->u.indication.u. application_invoke_indication, initiator); break; case TEXT_MESSAGE_INDICATION_CHOSEN: #ifdef JASPER if (ProcessTextMessageIndication( &gcc_pdu->u.indication.u. text_message_indication, initiator) != GCC_NO_ERROR) { error_value = GCC_ALLOCATION_FAILURE; } #endif // JASPER break; case CONFERENCE_LOCK_INDICATION_CHOSEN: m_pConf->ProcessConferenceLockIndication(initiator); break; case CONFERENCE_UNLOCK_INDICATION_CHOSEN: m_pConf->ProcessConferenceUnlockIndication(initiator); break; default: ERROR_OUT(("User::ProcessSendDataIndication Unsupported PDU")); break; } // switch(gcc_pdu->u.indication.choice) break; case REQUEST_CHOSEN: // Connection(control) PDU switch(gcc_pdu->u.request.choice) { case CONFERENCE_JOIN_REQUEST_CHOSEN: ProcessConferenceJoinRequestPDU( &gcc_pdu->u.request.u.conference_join_request, send_data_info); break; case CONFERENCE_TERMINATE_REQUEST_CHOSEN: ProcessConferenceTerminateRequestPDU( &gcc_pdu->u.request.u. conference_terminate_request, send_data_info); break; case CONFERENCE_EJECT_USER_REQUEST_CHOSEN: ProcessConferenceEjectUserRequestPDU( &gcc_pdu->u.request.u. conference_eject_user_request, send_data_info); break; case REGISTRY_ALLOCATE_HANDLE_REQUEST_CHOSEN: ProcessRegistryAllocateHandleRequestPDU( &gcc_pdu->u.request.u. registry_allocate_handle_request, send_data_info); break; case CONFERENCE_LOCK_REQUEST_CHOSEN: m_pConf->ProcessConferenceLockRequest(initiator); break; case CONFERENCE_UNLOCK_REQUEST_CHOSEN: m_pConf->ProcessConferenceUnlockRequest(initiator); break; case CONFERENCE_TRANSFER_REQUEST_CHOSEN: ProcessTransferRequestPDU( &gcc_pdu->u.request.u.conference_transfer_request, send_data_info); break; case CONFERENCE_ADD_REQUEST_CHOSEN: ProcessAddRequestPDU ( &gcc_pdu->u.request.u.conference_add_request, send_data_info); break; case REGISTRY_REGISTER_CHANNEL_REQUEST_CHOSEN: case REGISTRY_ASSIGN_TOKEN_REQUEST_CHOSEN: case REGISTRY_SET_PARAMETER_REQUEST_CHOSEN: case REGISTRY_DELETE_ENTRY_REQUEST_CHOSEN: case REGISTRY_RETRIEVE_ENTRY_REQUEST_CHOSEN: case REGISTRY_MONITOR_ENTRY_REQUEST_CHOSEN: ProcessRegistryRequestPDU( gcc_pdu, send_data_info); break; default: ERROR_OUT(("User::ProcessSendDataIndication this pdu choice is not supported")); break; } // switch(gcc_pdu->u.request.choice) break; case RESPONSE_CHOSEN: // Connection(control) PDU switch(gcc_pdu->u.response.choice) { case CONFERENCE_JOIN_RESPONSE_CHOSEN: /* This comes from top provider to the intermediate * gcc provider which has to pass it on to the node * that made a join request. */ ProcessConferenceJoinResponsePDU( &gcc_pdu->u.response.u. conference_join_response); break; case CONFERENCE_TERMINATE_RESPONSE_CHOSEN: ProcessConferenceTerminateResponsePDU( &gcc_pdu->u.response.u. conference_terminate_response); break; case CONFERENCE_EJECT_USER_RESPONSE_CHOSEN: ProcessConferenceEjectUserResponsePDU( &gcc_pdu->u.response.u. conference_eject_user_response); break; case REGISTRY_RESPONSE_CHOSEN: ProcessRegistryResponsePDU( &gcc_pdu->u.response.u.registry_response); break; case REGISTRY_ALLOCATE_HANDLE_RESPONSE_CHOSEN: ProcessRegistryAllocateHandleResponsePDU( &gcc_pdu->u.response.u. registry_allocate_handle_response); break; case CONFERENCE_LOCK_RESPONSE_CHOSEN: #ifdef JASPER { GCCResult result; result = ::TranslateLockResultToGCCResult(gcc_pdu->u.response.u.conference_lock_response.result); g_pControlSap->ConfLockConfirm(result, m_pConf->GetConfID()); } #endif // JASPER break; case CONFERENCE_UNLOCK_RESPONSE_CHOSEN: #ifdef JASPER { GCCResult result; result = ::TranslateUnlockResultToGCCResult(gcc_pdu->u.response.u.conference_unlock_response.result); g_pControlSap->ConfUnlockConfirm(result, m_pConf->GetConfID()); } #endif // JASPER break; case CONFERENCE_TRANSFER_RESPONSE_CHOSEN: #ifdef JASPER ProcessTransferResponsePDU( &gcc_pdu->u.response.u.conference_transfer_response); #endif // JASPER break; case CONFERENCE_ADD_RESPONSE_CHOSEN: ProcessAddResponsePDU( &gcc_pdu->u.response.u.conference_add_response); break; case FUNCTION_NOT_SUPPORTED_RESPONSE_CHOSEN: ProcessFunctionNotSupported ( (UINT) gcc_pdu->u.response.u.function_not_supported_response.request.choice); break; // other cases to be added as we go along. default: ERROR_OUT(("User::ProcessSendDataIndication this pdu choice is not supported")); break; } // switch(gcc_pdu->u.response.choice) break; default: ERROR_OUT(("User::ProcessSendDataIndication this pdu type")); break; } // switch(gcc_pdu->choice) packet->Unlock(); } else { delete packet; error_value = GCC_ALLOCATION_FAILURE; } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } return(MCS_NO_ERROR); } /* * void ProcessConferenceJoinRequestPDU () * * Private Function Description: * This PDU comes from below (intermediate directly connected node) to the * top gcc provider. Pull out the tag number and user id from the * pdu and store in a list. * * Formal Parameters: * join_request - (i) Join request PDU structure to process. * send_data_info - (i) Send data structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessConferenceJoinRequestPDU( PConferenceJoinRequest join_request, PSendData send_data_info) { GCCError rc = GCC_NO_ERROR; UserJoinRequestInfo join_request_info; /* ** Build all the containers to be used in the join request info structure. */ // Build the convener password container if ((join_request->bit_mask & CJRQ_CONVENER_PASSWORD_PRESENT) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE join_request_info.convener_password = new CPassword( &join_request->cjrq_convener_password, &rc); if (join_request_info.convener_password == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { join_request_info.convener_password = NULL; } // Build the password challenge container if ((join_request->bit_mask & CJRQ_PASSWORD_PRESENT) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE join_request_info.password_challenge = new CPassword( &join_request->cjrq_password, &rc); if (join_request_info.password_challenge == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { join_request_info.password_challenge = NULL; } // Build the caller identifier container if ((join_request->bit_mask & CJRQ_CALLER_ID_PRESENT) && (rc == GCC_NO_ERROR)) { if (NULL == (join_request_info.pwszCallerID = ::My_strdupW2( join_request->cjrq_caller_id.length, join_request->cjrq_caller_id.value))) { rc = GCC_ALLOCATION_FAILURE; } } else { join_request_info.pwszCallerID = NULL; } // Build the password challenge container if ((join_request->bit_mask & CJRQ_USER_DATA_PRESENT) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE join_request_info.user_data_list = new CUserDataListContainer(join_request->cjrq_user_data, &rc); if (join_request_info.user_data_list == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { join_request_info.user_data_list = NULL; } if (rc == GCC_NO_ERROR) { m_ConfJoinResponseList2.Append(send_data_info->initiator, join_request->tag); join_request_info.sender_id = send_data_info->initiator; g_pControlSap->ForwardedConfJoinIndication( join_request_info.sender_id, m_pConf->GetConfID(), join_request_info.convener_password, join_request_info.password_challenge, join_request_info.pwszCallerID, join_request_info.user_data_list); } // Free up the containers allocated above if (join_request_info.convener_password != NULL) { join_request_info.convener_password->Release(); } if (join_request_info.password_challenge != NULL) { join_request_info.password_challenge->Release(); } delete join_request_info.pwszCallerID; if (join_request_info.user_data_list != NULL) { join_request_info.user_data_list->Release(); } if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void ProcessConferenceJoinResponsePDU () * * Private Function Description: * This comes from top provider to the intermediate gcc provider which has * to pass it on to the node that made a join request. * * Formal Parameters: * join_response - (i) Join response PDU structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessConferenceJoinResponsePDU( PConferenceJoinResponse join_response) { GCCError rc = GCC_NO_ERROR; UserJoinResponseInfo join_response_info; // Store the password data in the join response info structure if ((join_response->bit_mask & CJRS_PASSWORD_PRESENT) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE join_response_info.password_challenge = new CPassword( &join_response->cjrs_password, &rc); if (join_response_info.password_challenge == NULL) { rc = GCC_NO_ERROR; } } else { join_response_info.password_challenge = NULL; } // Store the user data in the join response info structure if ((join_response->bit_mask & CJRS_USER_DATA_PRESENT) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE join_response_info.user_data_list = new CUserDataListContainer(join_response->cjrs_user_data, &rc); if (join_response_info.user_data_list == NULL) { rc = GCC_NO_ERROR; } } else { join_response_info.user_data_list = NULL; } if (rc == GCC_NO_ERROR) { join_response_info.connection_handle = (ConnectionHandle)join_response->tag; join_response_info.result = ::TranslateJoinResultToGCCResult(join_response->result); m_pConf->ProcessConfJoinResponse(&join_response_info); } // Free up the containers allocated above if (join_response_info.password_challenge != NULL) join_response_info.password_challenge->Release(); if (join_response_info.user_data_list != NULL) join_response_info.user_data_list->Release(); // Cleanup after any allocation failures. if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } /* * void ProcessConferenceTerminateRequestPDU() * * Private Function Description: * This routine is responsible for processing an incoming Conference * Terminate Request PDU. * * Formal Parameters: * terminate_request - (i) Terminate request PDU structure to process. * send_data_info - (i) Send data structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: ProcessConferenceTerminateRequestPDU ( PConferenceTerminateRequest terminate_request, PSendData send_data_info ) { m_pConf->ProcessTerminateRequest( send_data_info->initiator, ::TranslateTerminateRqReasonToGCCReason(terminate_request->reason)); } /* * void ProcessConferenceEjectUserRequestPDU() * * Private Function Description: * This routine is responsible for processing an incoming Conference * eject user request PDU. * * Formal Parameters: * eject_user_request - (i) Eject user request PDU structure to process. * send_data_info - (i) Send data structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessConferenceEjectUserRequestPDU( PConferenceEjectUserRequest eject_user_request, PSendData send_data_info) { UserEjectNodeRequestInfo eject_node_request; eject_node_request.requester_id = send_data_info->initiator; eject_node_request.node_to_eject = eject_user_request->node_to_eject; eject_node_request.reason = GCC_REASON_NODE_EJECTED; m_pConf->ProcessEjectUserRequest(&eject_node_request); } /* * void ProcessConferenceTerminateResponsePDU() * * Private Function Description: * This routine is responsible for processing an incoming Conference * terminate response PDU. * * Formal Parameters: * terminate_response - (i) Terminate response PDU structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessConferenceTerminateResponsePDU( PConferenceTerminateResponse terminate_response) { GCCResult result = ::TranslateTerminateResultToGCCResult(terminate_response->result); // // If the terminate was successful, go ahead and set the // conference to not established. // if (result == GCC_RESULT_SUCCESSFUL) { m_pConf->ConfIsOver(); } g_pControlSap->ConfTerminateConfirm(m_pConf->GetConfID(), result); } /* * void ProcessConferenceEjectUserResponsePDU() * * Private Function Description: * This routine is responsible for processing an incoming Conference * Eject User response PDU. * * Formal Parameters: * eject_user_response - (i) Eject user response PDU structure to * process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessConferenceEjectUserResponsePDU( PConferenceEjectUserResponse eject_user_response) { UserEjectNodeResponseInfo eject_node_response; eject_node_response.node_to_eject = eject_user_response->node_to_eject; eject_node_response.result = ::TranslateEjectResultToGCCResult( eject_user_response->result); m_pConf->ProcessEjectUserResponse(&eject_node_response); } /* * void ProcessRegistryRequest() * * Private Function Description: * This routine is responsible for processing an incoming Registry * request PDU. * * Formal Parameters: * gcc_pdu - (i) This is the PDU structure to process. * send_data_info - (i) Send data structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: ProcessRegistryRequestPDU ( PGCCPDU gcc_pdu, PSendData send_data_info ) { CRegistry *pAppReg = m_pConf->GetRegistry(); if (NULL != pAppReg) { GCCError rc = GCC_ALLOCATION_FAILURE; CRegKeyContainer *pRegKey = NULL; switch (gcc_pdu->u.request.choice) { case REGISTRY_REGISTER_CHANNEL_REQUEST_CHOSEN: DBG_SAVE_FILE_LINE pRegKey = new CRegKeyContainer( &gcc_pdu->u.request.u.registry_register_channel_request.key, &rc); if ((pRegKey != NULL) && (rc == GCC_NO_ERROR)) { pAppReg->ProcessRegisterChannelPDU( pRegKey, gcc_pdu->u.request.u.registry_register_channel_request.channel_id, send_data_info->initiator, // Requester node id gcc_pdu->u.request.u.registry_register_channel_request.entity_id); } else { // rc = GCC_ALLOCATION_FAILURE; } break; case REGISTRY_ASSIGN_TOKEN_REQUEST_CHOSEN: DBG_SAVE_FILE_LINE pRegKey = new CRegKeyContainer( &gcc_pdu->u.request.u.registry_assign_token_request.registry_key, &rc); if ((pRegKey != NULL) && (rc == GCC_NO_ERROR)) { pAppReg->ProcessAssignTokenPDU( pRegKey, send_data_info->initiator, // Requester node id gcc_pdu->u.request.u.registry_assign_token_request.entity_id); } else { // rc = GCC_ALLOCATION_FAILURE; } break; case REGISTRY_SET_PARAMETER_REQUEST_CHOSEN: DBG_SAVE_FILE_LINE pRegKey = new CRegKeyContainer( &gcc_pdu->u.request.u.registry_set_parameter_request.key, &rc); if ((pRegKey != NULL) && (rc == GCC_NO_ERROR)) { OSTR oszParamValue; LPOSTR poszParamValue; GCCModificationRights eRights; if (gcc_pdu->u.request.u.registry_set_parameter_request. registry_set_parameter.length != 0) { poszParamValue = &oszParamValue; oszParamValue.length = gcc_pdu->u.request.u.registry_set_parameter_request. registry_set_parameter.length; oszParamValue.value = gcc_pdu->u.request.u.registry_set_parameter_request. registry_set_parameter.value; } else { poszParamValue = NULL; } if (gcc_pdu->u.request.u.registry_set_parameter_request. bit_mask & PARAMETER_MODIFY_RIGHTS_PRESENT) { eRights = (GCCModificationRights)gcc_pdu->u.request.u. registry_set_parameter_request.parameter_modify_rights; } else { eRights = GCC_NO_MODIFICATION_RIGHTS_SPECIFIED; } pAppReg->ProcessSetParameterPDU( pRegKey, poszParamValue, eRights, send_data_info->initiator, // Requester node id gcc_pdu->u.request.u.registry_set_parameter_request.entity_id); } else { // rc = GCC_ALLOCATION_FAILURE; } break; case REGISTRY_RETRIEVE_ENTRY_REQUEST_CHOSEN: DBG_SAVE_FILE_LINE pRegKey = new CRegKeyContainer( &gcc_pdu->u.request.u.registry_retrieve_entry_request.key, &rc); if ((pRegKey != NULL) && (rc == GCC_NO_ERROR)) { pAppReg->ProcessRetrieveEntryPDU( pRegKey, send_data_info->initiator, // Requester node id gcc_pdu->u.request.u.registry_retrieve_entry_request.entity_id); } else { // rc = GCC_ALLOCATION_FAILURE; } break; case REGISTRY_DELETE_ENTRY_REQUEST_CHOSEN: DBG_SAVE_FILE_LINE pRegKey = new CRegKeyContainer( &gcc_pdu->u.request.u.registry_delete_entry_request.key, &rc); if ((pRegKey != NULL) && (rc == GCC_NO_ERROR)) { pAppReg->ProcessDeleteEntryPDU ( pRegKey, send_data_info->initiator, // Requester node id gcc_pdu->u.request.u.registry_delete_entry_request.entity_id); } else { // rc = GCC_ALLOCATION_FAILURE; } break; case REGISTRY_MONITOR_ENTRY_REQUEST_CHOSEN: DBG_SAVE_FILE_LINE pRegKey = new CRegKeyContainer( &gcc_pdu->u.request.u.registry_monitor_entry_request.key, &rc); if ((pRegKey != NULL) && (rc == GCC_NO_ERROR)) { pAppReg->ProcessMonitorEntryPDU( pRegKey, send_data_info->initiator, // Requester node id gcc_pdu->u.request.u.registry_monitor_entry_request.entity_id); } else { // rc = GCC_ALLOCATION_FAILURE; } break; } if (NULL != pRegKey) { pRegKey->Release(); } // Handle resource errors if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } // if pAppReg != NULL } /* * void ProcessRegistryAllocateHandleRequestPDU() * * Private Function Description: * This routine is responsible for processing an incoming Allocate * Handle request PDU. * * Formal Parameters: * allocate_handle_request - (i) This is the PDU structure to process. * send_data_info - (i) Send data structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: ProcessRegistryAllocateHandleRequestPDU ( PRegistryAllocateHandleRequest allocate_handle_request, PSendData send_data_info ) { CRegistry *pAppReg = m_pConf->GetRegistry(); if (NULL != pAppReg) { pAppReg->ProcessAllocateHandleRequestPDU( allocate_handle_request->number_of_handles, allocate_handle_request->entity_id, send_data_info->initiator); } } /* * void ProcessRegistryResponsePDU() * * Private Function Description: * This routine is responsible for processing an incoming Registry * Response PDU. * * Formal Parameters: * registry_response - (i) This is the PDU structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: ProcessRegistryResponsePDU ( PRegistryResponse registry_response ) { CRegistry *pAppReg = m_pConf->GetRegistry(); if (NULL != pAppReg) { GCCError rc; UserRegistryResponseInfo urri; ::ZeroMemory(&urri, sizeof(urri)); // urri.registry_key = NULL; // urri.registry_item = NULL; DBG_SAVE_FILE_LINE urri.registry_key = new CRegKeyContainer(®istry_response->key, &rc); if ((urri.registry_key != NULL) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE urri.registry_item = new CRegItem(®istry_response->item, &rc); if ((urri.registry_item != NULL) && (rc == GCC_NO_ERROR)) { // Set up the original requester entity id urri.requester_entity_id = registry_response->entity_id; // Set up the primitive type being responded to urri.primitive_type = registry_response->primitive_type; // Set up the owner related variables if (registry_response->owner.choice == OWNED_CHOSEN) { urri.owner_node_id = registry_response->owner.u.owned.node_id; urri.owner_entity_id = registry_response->owner.u.owned.entity_id; } else { // urri.owner_node_id = 0; // urri.owner_entity_id = 0; } // Set up the modification rights if (registry_response->bit_mask & RESPONSE_MODIFY_RIGHTS_PRESENT) { urri.modification_rights = (GCCModificationRights)registry_response->response_modify_rights; } else { urri.modification_rights = GCC_NO_MODIFICATION_RIGHTS_SPECIFIED; } // Translate the result to a GCC result urri.result = ::TranslateRegistryRespToGCCResult(registry_response->result); pAppReg->ProcessRegistryResponsePDU( urri.primitive_type, urri.registry_key, urri.registry_item, urri.modification_rights, urri.requester_entity_id, urri.owner_node_id, urri.owner_entity_id, urri.result); } else { rc = GCC_ALLOCATION_FAILURE; } } else { rc = GCC_ALLOCATION_FAILURE; } if (NULL != urri.registry_key) { urri.registry_key->Release(); } if (NULL != urri.registry_item) { urri.registry_item->Release(); } // Handle any resource errors if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } // if pAppReg != NULL } /* * void ProcessAllocateHandleResponsePDU() * * Private Function Description: * This routine is responsible for processing an incoming Allocate * Handle Response PDU. * * Formal Parameters: * allocate_handle_response- (i) This is the PDU structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: ProcessRegistryAllocateHandleResponsePDU ( PRegistryAllocateHandleResponse allocate_handle_response ) { CRegistry *pAppReg = m_pConf->GetRegistry(); if (NULL != pAppReg) { pAppReg->ProcessAllocateHandleResponsePDU( allocate_handle_response->number_of_handles, allocate_handle_response->first_handle, allocate_handle_response->entity_id, (allocate_handle_response->result == RARS_RESULT_SUCCESS) ? GCC_RESULT_SUCCESSFUL : GCC_RESULT_NO_HANDLES_AVAILABLE); } } /* * void ProcessTransferRequestPDU() * * Private Function Description: * This routine is responsible for processing an incoming Transfer * request PDU. * * Formal Parameters: * transfer_request - (i) This is the PDU structure to process. * send_data_info - (i) Send data structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: ProcessTransferRequestPDU ( PConferenceTransferRequest transfer_request, PSendData send_data_info ) { GCCError rc = GCC_NO_ERROR; TransferInfo transfer_info; PSetOfTransferringNodesRq set_of_nodes; LPBYTE sub_node_list_memory = NULL; Int i; // Make sure that this node is the top provider if (GetMyNodeID() != GetTopNodeID()) return; ::ZeroMemory(&transfer_info, sizeof(transfer_info)); // First set up the conference name if (transfer_request->conference_name.choice == NAME_SELECTOR_NUMERIC_CHOSEN) { transfer_info.destination_conference_name.numeric_string = (LPSTR) transfer_request->conference_name.u.name_selector_numeric; // transfer_info.destination_conference_name.text_string = NULL; } else { // transfer_info.destination_conference_name.numeric_string = NULL; if (NULL == (transfer_info.destination_conference_name.text_string = ::My_strdupW2( transfer_request->conference_name.u.name_selector_text.length, transfer_request->conference_name.u.name_selector_text.value))) { rc = GCC_ALLOCATION_FAILURE; } } // Next set up the conference name modifier if (transfer_request->bit_mask & CTRQ_CONFERENCE_MODIFIER_PRESENT) { transfer_info.destination_conference_modifier = (LPSTR) transfer_request->ctrq_conference_modifier; } else { // transfer_info.destination_conference_modifier = NULL; } // Next set up the network address if (transfer_request->bit_mask & CTRQ_NETWORK_ADDRESS_PRESENT) { DBG_SAVE_FILE_LINE transfer_info.destination_address_list = new CNetAddrListContainer( transfer_request->ctrq_net_address, &rc); if (transfer_info.destination_address_list == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { // transfer_info.destination_address_list = NULL; } // Set up the transferring nodes list if (transfer_request->bit_mask & CTRQ_TRANSFERRING_NODES_PRESENT) { // First determine the number of nodes. set_of_nodes = transfer_request->ctrq_transferring_nodes; // transfer_info.number_of_destination_nodes = 0; while (set_of_nodes != NULL) { transfer_info.number_of_destination_nodes++; set_of_nodes = set_of_nodes->next; } // Next allocate the memory required to hold the sub nodes DBG_SAVE_FILE_LINE sub_node_list_memory = new BYTE[sizeof(UserID) * transfer_info.number_of_destination_nodes]; // Now fill in the permission list if (sub_node_list_memory != NULL) { transfer_info.destination_node_list = (PUserID) sub_node_list_memory; set_of_nodes = transfer_request->ctrq_transferring_nodes; for (i = 0; i < transfer_info.number_of_destination_nodes; i++) { transfer_info.destination_node_list[i] = set_of_nodes->value; set_of_nodes = set_of_nodes->next; } } else { ERROR_OUT(("MCSUser: ProcessTransferRequestPDU: Memory Manager Alloc Failure")); rc = GCC_ALLOCATION_FAILURE; } } else { // transfer_info.number_of_destination_nodes = 0; // transfer_info.destination_node_list = NULL; } // Set up the password if (transfer_request->bit_mask & CTRQ_PASSWORD_PRESENT) { DBG_SAVE_FILE_LINE transfer_info.password = new CPassword(&transfer_request->ctrq_password, &rc); if (transfer_info.password == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { // transfer_info.password = NULL; } // Save the sender ID transfer_info.requesting_node_id = send_data_info->initiator; if (rc == GCC_NO_ERROR) { m_pConf->ProcessConferenceTransferRequest( transfer_info.requesting_node_id, &transfer_info.destination_conference_name, transfer_info.destination_conference_modifier, transfer_info.destination_address_list, transfer_info.number_of_destination_nodes, transfer_info.destination_node_list, transfer_info.password); } else { ERROR_OUT(("MCSUser::ProcessTransferRequestPDU: Allocation Failure")); if (GCC_ALLOCATION_FAILURE == rc) { ResourceFailureHandler(); } } // Now cleanup any allocated memory if (transfer_info.destination_address_list != NULL) { transfer_info.destination_address_list->Release(); } delete [] sub_node_list_memory; if (transfer_info.password != NULL) { transfer_info.password->Release(); } } /* * void ProcessAddRequestPDU () * * Private Function Description: * This routine is responsible for processing an incoming Conference Add * request PDU. * * Formal Parameters: * conference_add_request - (i) This is the PDU structure to process. * send_data_info - (i) Send data structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessAddRequestPDU ( PConferenceAddRequest conference_add_request, PSendData send_data_info) { GCCError rc = GCC_NO_ERROR; AddRequestInfo add_request_info; /* ** Ignore this request if this node is NOT the Top Provider and the request ** did not come from the Top Provider. */ if (m_nidTopProvider != m_nidMyself) { if (m_nidTopProvider != send_data_info->initiator) return; } ::ZeroMemory(&add_request_info, sizeof(add_request_info)); DBG_SAVE_FILE_LINE add_request_info.network_address_list = new CNetAddrListContainer( conference_add_request->add_request_net_address, &rc); if (add_request_info.network_address_list == NULL) { rc = GCC_ALLOCATION_FAILURE; } if ((rc == GCC_NO_ERROR) && (conference_add_request->bit_mask & CARQ_USER_DATA_PRESENT)) { DBG_SAVE_FILE_LINE add_request_info.user_data_list = new CUserDataListContainer(conference_add_request->carq_user_data, &rc); if (add_request_info.user_data_list == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { // add_request_info.user_data_list = NULL; } if (rc == GCC_NO_ERROR) { add_request_info.adding_node = (conference_add_request->bit_mask & ADDING_MCU_PRESENT) ? conference_add_request->adding_mcu : 0; add_request_info.requesting_node = conference_add_request->requesting_node; add_request_info.add_request_tag = (TagNumber)conference_add_request->tag; m_pConf->ProcessConferenceAddRequest( add_request_info.network_address_list, add_request_info.user_data_list, add_request_info.adding_node, add_request_info.add_request_tag, add_request_info.requesting_node); } else { ERROR_OUT(("MCSUser::ProcessAddRequestPDU: Allocation Failure")); if (GCC_ALLOCATION_FAILURE == rc) { ResourceFailureHandler(); } } if (add_request_info.network_address_list != NULL) { add_request_info.network_address_list->Release(); } if (add_request_info.user_data_list != NULL) { add_request_info.user_data_list->Release(); } } /* * void ProcessTransferResponsePDU() * * Private Function Description: * This routine is responsible for processing an incoming Conference * Transfer response PDU. * * Formal Parameters: * transfer_response - (i) This is the PDU structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ #ifdef JASPER void MCSUser::ProcessTransferResponsePDU ( PConferenceTransferResponse transfer_response) { GCCError rc = GCC_NO_ERROR; TransferInfo transfer_info; PSetOfTransferringNodesRs set_of_nodes; LPBYTE sub_node_list_memory = NULL; Int i; ::ZeroMemory(&transfer_info, sizeof(transfer_info)); // First set up the conference name if (transfer_response->conference_name.choice == NAME_SELECTOR_NUMERIC_CHOSEN) { transfer_info.destination_conference_name.numeric_string = (LPSTR) transfer_response->conference_name.u.name_selector_numeric; // transfer_info.destination_conference_name.text_string = NULL; } else { // transfer_info.destination_conference_name.numeric_string = NULL; if (NULL == (transfer_info.destination_conference_name.text_string = ::My_strdupW2( transfer_response->conference_name.u.name_selector_text.length, transfer_response->conference_name.u.name_selector_text.value))) { rc = GCC_ALLOCATION_FAILURE; } } // Next set up the conference name modifier if (transfer_response->bit_mask & CTRS_CONFERENCE_MODIFIER_PRESENT) { transfer_info.destination_conference_modifier = (LPSTR) transfer_response->ctrs_conference_modifier; } else { // transfer_info.destination_conference_modifier = NULL; } // Set up the transferring nodes list if (transfer_response->bit_mask & CTRS_TRANSFERRING_NODES_PRESENT) { // First determine the number of nodes. set_of_nodes = transfer_response->ctrs_transferring_nodes; // transfer_info.number_of_destination_nodes = 0; while (set_of_nodes != NULL) { transfer_info.number_of_destination_nodes++; set_of_nodes = set_of_nodes->next; } // Next allocate the memory required to hold the sub nodes DBG_SAVE_FILE_LINE sub_node_list_memory = new BYTE[sizeof(UserID) * transfer_info.number_of_destination_nodes]; // Now fill in the permission list if (sub_node_list_memory != NULL) { transfer_info.destination_node_list = (PUserID) sub_node_list_memory; set_of_nodes = transfer_response->ctrs_transferring_nodes; for (i = 0; i < transfer_info.number_of_destination_nodes; i++) { transfer_info.destination_node_list[i] = set_of_nodes->value; set_of_nodes = set_of_nodes->next; } } else { ERROR_OUT(("MCSUser: ProcessTransferResponsePDU: Memory Manager Alloc Failure")); rc = GCC_ALLOCATION_FAILURE; } } else { // transfer_info.number_of_destination_nodes = 0; // transfer_info.destination_node_list = NULL; } // Save the result transfer_info.result = (transfer_response->result == CTRANS_RESULT_SUCCESS) ? GCC_RESULT_SUCCESSFUL : GCC_RESULT_INVALID_REQUESTER; if (rc == GCC_NO_ERROR) { g_pControlSap->ConfTransferConfirm( m_pConf->GetConfID(), &transfer_info.destination_conference_name, transfer_info.destination_conference_modifier, transfer_info.number_of_destination_nodes, transfer_info.destination_node_list, transfer_info.result); } else { ERROR_OUT(("MCSUser::ProcessTransferResponsePDU: Allocation Failure")); if (GCC_ALLOCATION_FAILURE == rc) { ResourceFailureHandler(); } } // Now cleanup any allocated memory delete sub_node_list_memory; } #endif // JASPER /* * void ProcessAddResponsePDU () * * Private Function Description: * This routine is responsible for processing an incoming Conference * Add response PDU. * * Formal Parameters: * conference_add_response - (i) This is the PDU structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessAddResponsePDU ( PConferenceAddResponse conference_add_response) { GCCError error_value = GCC_NO_ERROR; AddResponseInfo add_response_info; if (conference_add_response->bit_mask & CARS_USER_DATA_PRESENT) { DBG_SAVE_FILE_LINE add_response_info.user_data_list = new CUserDataListContainer(conference_add_response->cars_user_data, &error_value); if (add_response_info.user_data_list == NULL) { error_value = GCC_ALLOCATION_FAILURE; } } else { add_response_info.user_data_list = NULL; } if (error_value == GCC_NO_ERROR) { add_response_info.add_request_tag = (TagNumber)conference_add_response->tag; add_response_info.result = ::TranslateAddResultToGCCResult(conference_add_response->result); m_pConf->ProcessConfAddResponse(&add_response_info); } else { ERROR_OUT(("MCSUser::ProcessAddResponsePDU: Allocation Failure")); if (GCC_ALLOCATION_FAILURE == error_value) { ResourceFailureHandler(); } } if (add_response_info.user_data_list != NULL) { add_response_info.user_data_list->Release(); } } /* * void ProcessFunctionNotSupported () * * Private Function Description: * This routine is responsible for processing responses for request that * are not supported at the node that the request was directed toward. * * Formal Parameters: * request_choice - (i) This is the request that is not supported. * * Return Value * None. * * Side Effects * None. * * Caveats * The existance of this routine does not mean that this provider does * not support it. It only means that the node which received the * request does not support it. */ void MCSUser:: ProcessFunctionNotSupported ( UINT request_choice ) { switch (request_choice) { case CONFERENCE_LOCK_REQUEST_CHOSEN: #ifdef JASPER g_pControlSap->ConfLockConfirm(GCC_RESULT_LOCKED_NOT_SUPPORTED, m_pConf->GetConfID()); #endif // JASPER break; case CONFERENCE_UNLOCK_REQUEST_CHOSEN: #ifdef JASPER g_pControlSap->ConfUnlockConfirm(GCC_RESULT_UNLOCK_NOT_SUPPORTED, m_pConf->GetConfID()); #endif // JASPER break; default: ERROR_OUT(("MCSUser: ProcessFunctionNotSupported: " "Error: Illegal request is unsupported")); break; } } /* * UINT ProcessUniformSendDataIndication () * * Private Function Description: * This function is called when the user object gets send data indications * from below. It finds out the message type and decodes the pdu in the * user data field of send data indications. Based on the type of decoded * pdu it take the necessary actions. * This routine is responsible for processing responses for request that * are not supported at the node that the request was directed toward. * * Formal Parameters: * send_data_info - (i) This is the MCS data structure to process. * * Return Value * MCS_NO_ERROR is always returned. * * Side Effects * None. * * Caveats * None. */ UINT MCSUser::ProcessUniformSendDataIndication( PSendData send_data_info) { PPacket packet; PacketError packet_error; PGCCPDU gcc_pdu; GCCError error_value = GCC_NO_ERROR; UserID initiator; TRACE_OUT(("User: UniformSendDataInd: length = %d", send_data_info->user_data.length)); DBG_SAVE_FILE_LINE packet = new Packet((PPacketCoder) g_GCCCoder, PACKED_ENCODING_RULES, (LPBYTE)send_data_info->user_data.value, send_data_info->user_data.length, GCC_PDU, TRUE, &packet_error); if((packet != NULL) && (packet_error == PACKET_NO_ERROR)) { initiator = send_data_info->initiator; gcc_pdu = (PGCCPDU)packet->GetDecodedData(); switch (gcc_pdu->choice) { case INDICATION_CHOSEN: // Data PDU switch(gcc_pdu->u.indication.choice) { case CONFERENCE_TERMINATE_INDICATION_CHOSEN: /* ** Note that we allow the top provider to process ** this message so that it can set up its own ** node for termination in a generic way. */ ProcessConferenceTerminateIndicationPDU ( &gcc_pdu->u.indication.u. conference_terminate_indication, initiator); break; case CONFERENCE_EJECT_USER_INDICATION_CHOSEN: /* ** Do not decode a packet that was sent uniformly ** from this node. */ if (initiator != m_nidMyself) { ProcessConferenceEjectUserIndicationPDU ( &gcc_pdu->u.indication.u. conference_eject_user_indication, initiator); } break; case ROSTER_UPDATE_INDICATION_CHOSEN: /* ** Do not decode a packet that was sent uniformly ** from this node. */ if ((initiator != m_nidMyself) && (send_data_info->channel_id == BROADCAST_CHANNEL_ID)) { // // We only process the roster update if the conference is // established. // if (m_pConf->IsConfEstablished()) { m_pConf->ProcessRosterUpdatePDU(gcc_pdu, initiator); } } break; case CONFERENCE_LOCK_INDICATION_CHOSEN: m_pConf->ProcessConferenceLockIndication(initiator); break; case CONFERENCE_UNLOCK_INDICATION_CHOSEN: m_pConf->ProcessConferenceUnlockIndication(initiator); break; case CONDUCTOR_ASSIGN_INDICATION_CHOSEN: m_pConf->ProcessConductorAssignIndication( gcc_pdu->u.indication.u.conductor_assign_indication.user_id, initiator); break; case CONDUCTOR_RELEASE_INDICATION_CHOSEN: if (initiator != m_nidMyself) { m_pConf->ProcessConductorReleaseIndication(initiator); } break; case CONDUCTOR_PERMISSION_ASK_INDICATION_CHOSEN: #ifdef JASPER /* ** Do not decode a packet that was sent uniformly ** from this node. */ if (initiator != m_nidMyself) { PermitAskIndicationInfo indication_info; indication_info.sender_id = initiator; indication_info.permission_is_granted = gcc_pdu->u.indication.u. conductor_permission_ask_indication. permission_is_granted; m_pConf->ProcessConductorPermitAskIndication(&indication_info); } #endif // JASPER break; case CONDUCTOR_PERMISSION_GRANT_INDICATION_CHOSEN: ProcessPermissionGrantIndication( &(gcc_pdu->u.indication.u. conductor_permission_grant_indication), initiator); break; case CONFERENCE_TIME_REMAINING_INDICATION_CHOSEN: #ifdef JASPER ProcessTimeRemainingIndicationPDU ( &gcc_pdu->u.indication.u. conference_time_remaining_indication, initiator); #endif // JASPER break; case APPLICATION_INVOKE_INDICATION_CHOSEN: ProcessApplicationInvokeIndication( &gcc_pdu->u.indication.u. application_invoke_indication, initiator); break; case TEXT_MESSAGE_INDICATION_CHOSEN: #ifdef JASPER if (ProcessTextMessageIndication( &gcc_pdu->u.indication.u. text_message_indication, initiator) != GCC_NO_ERROR) { error_value = GCC_ALLOCATION_FAILURE; } #endif // JASPER break; case CONFERENCE_ASSISTANCE_INDICATION_CHOSEN: #ifdef JASPER ProcessConferenceAssistanceIndicationPDU( &gcc_pdu->u.indication.u. conference_assistance_indication, initiator); #endif // JASPER break; case REGISTRY_MONITOR_ENTRY_INDICATION_CHOSEN: /* ** Do not decode this packet if it was sent ** uniformly from this node. */ if (initiator != m_nidMyself) { ProcessRegistryMonitorIndicationPDU ( &gcc_pdu->u.indication.u. registry_monitor_entry_indication, initiator); } break; case CONFERENCE_TRANSFER_INDICATION_CHOSEN: #ifdef JASPER /* ** Do not decode this packet if it was not sent ** from the top provider. */ if (initiator == m_nidTopProvider) { ProcessTransferIndicationPDU ( &gcc_pdu->u.indication.u. conference_transfer_indication); } #endif // JASPER break; default: ERROR_OUT(("MCSUser::ProcessSendDataIndication" "Unsupported PDU")); break; } // switch(gcc_pdu->u.indication.choice) break; default: ERROR_OUT(("MCSUser::ProcessUniformSendDataIndication. wrong pdu type ")); break; } packet->Unlock(); } else { delete packet; error_value = GCC_ALLOCATION_FAILURE; } if (error_value == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } return (MCS_NO_ERROR); } /* * void ProcessTransferIndicationPDU () * * Private Function Description: * This routine is responsible for processing an incoming Conference * Transfer indication PDU. * * Formal Parameters: * transfer_indication - (i) This is the PDU structure to process. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ #ifdef JASPER void MCSUser:: ProcessTransferIndicationPDU ( PConferenceTransferIndication transfer_indication ) { GCCError rc = GCC_NO_ERROR; TransferInfo transfer_info; PSetOfTransferringNodesIn set_of_nodes; LPBYTE sub_node_list_memory = NULL; Int i; BOOL process_pdu = FALSE; ::ZeroMemory(&transfer_info, sizeof(transfer_info)); /* ** If there is a transferring node list we must determine if this node ** is in the list. If it isn't then the request is ignored. */ if (transfer_indication->bit_mask & CTIN_TRANSFERRING_NODES_PRESENT) { set_of_nodes = transfer_indication->ctin_transferring_nodes; while (set_of_nodes != NULL) { if (set_of_nodes->value == GetMyNodeID()) { process_pdu = TRUE; break; } set_of_nodes = set_of_nodes->next; } if (process_pdu == FALSE) { return; } } // First set up the conference name if (transfer_indication->conference_name.choice == NAME_SELECTOR_NUMERIC_CHOSEN) { transfer_info.destination_conference_name.numeric_string = (LPSTR) transfer_indication->conference_name.u.name_selector_numeric; // transfer_info.destination_conference_name.text_string = NULL; } else { // transfer_info.destination_conference_name.numeric_string = NULL; if (NULL == (transfer_info.destination_conference_name.text_string = ::My_strdupW2( transfer_indication->conference_name.u.name_selector_text.length, transfer_indication->conference_name.u.name_selector_text.value))) { rc = GCC_ALLOCATION_FAILURE; } } // Next set up the conference name modifier if (transfer_indication->bit_mask & CTIN_CONFERENCE_MODIFIER_PRESENT) { transfer_info.destination_conference_modifier = (LPSTR) transfer_indication->ctin_conference_modifier; } else { // transfer_info.destination_conference_modifier = NULL; } // Next set up the network address if (transfer_indication->bit_mask & CTIN_NETWORK_ADDRESS_PRESENT) { DBG_SAVE_FILE_LINE transfer_info.destination_address_list = new CNetAddrListContainer( transfer_indication->ctin_net_address, &rc); if (transfer_info.destination_address_list == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { // transfer_info.destination_address_list = NULL; } // Set up the transferring nodes list if (transfer_indication->bit_mask & CTIN_TRANSFERRING_NODES_PRESENT) { // First determine the number of nodes. set_of_nodes = transfer_indication->ctin_transferring_nodes; // transfer_info.number_of_destination_nodes = 0; while (set_of_nodes != NULL) { transfer_info.number_of_destination_nodes++; set_of_nodes = set_of_nodes->next; } // Next allocate the memory required to hold the sub nodes DBG_SAVE_FILE_LINE sub_node_list_memory = new BYTE[sizeof(UserID) * transfer_info.number_of_destination_nodes]; // Now fill in the permission list if (sub_node_list_memory != NULL) { transfer_info.destination_node_list = (PUserID) sub_node_list_memory; set_of_nodes = transfer_indication->ctin_transferring_nodes; for (i = 0; i < transfer_info.number_of_destination_nodes; i++) { transfer_info.destination_node_list[i] = set_of_nodes->value; set_of_nodes = set_of_nodes->next; } } else { ERROR_OUT(("MCSUser: ProcessTransferIndicationPDU: Memory Manager Alloc Failure")); rc = GCC_ALLOCATION_FAILURE; } } else { // transfer_info.number_of_destination_nodes = 0; // transfer_info.destination_node_list = NULL; } // Set up the password if (transfer_indication->bit_mask & CTIN_PASSWORD_PRESENT) { DBG_SAVE_FILE_LINE transfer_info.password = new CPassword(&transfer_indication->ctin_password, &rc); if (transfer_info.password == NULL) { rc = GCC_ALLOCATION_FAILURE; } } else { // transfer_info.password = NULL; } if (rc == GCC_NO_ERROR) { g_pControlSap->ConfTransferIndication( m_pConf->GetConfID(), &transfer_info.destination_conference_name, transfer_info.destination_conference_modifier, transfer_info.destination_address_list, transfer_info.password); } else { ERROR_OUT(("MCSUser::ProcessTransferIndicationPDU: Allocation Failure")); if (GCC_ALLOCATION_FAILURE == rc) { ResourceFailureHandler(); } } // Now cleanup any allocated memory if (NULL != transfer_info.destination_address_list) { transfer_info.destination_address_list->Release(); } delete sub_node_list_memory; if (NULL != transfer_info.password) { transfer_info.password->Release(); } } #endif // JASPER /* * void ProcessConferenceTerminateIndicationPDU() * * Private Function Description: * This routine is responsible for processing an incoming Conference * Terminate indication PDU. * * Formal Parameters: * terminate_indication - (i) This is the PDU structure to process. * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessConferenceTerminateIndicationPDU ( PConferenceTerminateIndication terminate_indication, UserID sender_id) { if (sender_id == m_nidTopProvider) { m_pConf->ProcessTerminateIndication( ::TranslateTerminateInReasonToGCCReason(terminate_indication->reason)); } } /* * void ProcessTimeRemainingIndicationPDU () * * Private Function Description: * This routine is responsible for processing an incoming Conference * Time remaining indication PDU. * * Formal Parameters: * time_remaining_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ #ifdef JASPER void MCSUser:: ProcessTimeRemainingIndicationPDU ( PConferenceTimeRemainingIndication time_remaining_indication, UserID sender_id ) { g_pControlSap->ConfTimeRemainingIndication( m_pConf->GetConfID(), sender_id, (time_remaining_indication->bit_mask & TIME_REMAINING_NODE_ID_PRESENT) ? time_remaining_indication->time_remaining_node_id : 0, time_remaining_indication->time_remaining); } #endif // JASPER /* * void ProcessConferenceAssistanceIndicationPDU () * * Private Function Description: * This routine is responsible for processing an incoming Conference * assistance indication PDU. * * Formal Parameters: * conf_assistance_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ #ifdef JASPER void MCSUser:: ProcessConferenceAssistanceIndicationPDU ( PConferenceAssistanceIndication conf_assistance_indication, UserID sender_id ) { GCCError rc = GCC_NO_ERROR; CUserDataListContainer *user_data_list = NULL; DebugEntry(MCSUser::ProcessConferenceAssistanceIndication); // Unpack the user data list if it exists if (conf_assistance_indication->bit_mask & CAIN_USER_DATA_PRESENT) { DBG_SAVE_FILE_LINE user_data_list = new CUserDataListContainer(conf_assistance_indication->cain_user_data, &rc); if (user_data_list == NULL) { rc = GCC_ALLOCATION_FAILURE; } } if (rc == GCC_NO_ERROR) { g_pControlSap->ConfAssistanceIndication( m_pConf->GetConfID(), user_data_list, sender_id); } else { ERROR_OUT(("MCSUser::ProcessConferenceAssistanceIndication: can't create CUserDataListContainer")); if (GCC_ALLOCATION_FAILURE == rc) { ResourceFailureHandler(); } } } #endif // JASPER /* * void ProcessConferenceExtendIndicationPDU() * * Private Function Description: * This routine is responsible for processing an incoming Conference * extend indication PDU. * * Formal Parameters: * conf_time_extend_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ #ifdef JASPER void MCSUser:: ProcessConferenceExtendIndicationPDU ( PConferenceTimeExtendIndication conf_time_extend_indication, UserID sender_id ) { g_pControlSap->ConfExtendIndication( m_pConf->GetConfID(), conf_time_extend_indication->time_to_extend, conf_time_extend_indication->time_is_node_specific, sender_id); } #endif // JASPER /* * void ProcessConferenceEjectUserIndicationPDU () * * Private Function Description: * This routine is responsible for processing an incoming Conference * eject user indication PDU. * * Formal Parameters: * eject_user_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessConferenceEjectUserIndicationPDU ( PConferenceEjectUserIndication eject_user_indication, UserID sender_id) { GCCError error_value = GCC_NO_ERROR; PAlarm alarm = NULL; // First check to make sure that this is the node being ejected if (eject_user_indication->node_to_eject == m_nidMyself) { /* ** Next make sure the ejection came from either the Top Provider or ** the Parent Node. */ if ((sender_id == m_nidParent) || (sender_id == m_nidTopProvider)) { TRACE_OUT(("MCSUser:ProcessEjectUserIndication: This node is ejected")); error_value = InitiateEjectionFromConference ( ::TranslateEjectIndReasonToGCCReason( eject_user_indication->reason)); } else { ERROR_OUT(("MCSUser: ProcessEjectUserIndication: Received eject from illegal node")); } } else { TRACE_OUT(("MCSUser: ProcessEjectUserIndication: Received eject for node other than mine")); /* ** If this node is a directly connected child node we insert an ** alarm in the list m_EjectedNodeAlarmList2 to disconnect it if ** it misbehaves and does not disconnect itself. Otherwise, we save ** the ejected user id in the m_EjectedNodeList to inform the local ** node of the correct reason for disconnecting (user ejected) when the ** detch user indication comes in. */ if (m_ChildUidConnHdlList2.Find(eject_user_indication->node_to_eject)) { DBG_SAVE_FILE_LINE alarm = new Alarm (EJECTED_NODE_TIMER_DURATION); if (alarm != NULL) { m_EjectedNodeAlarmList2.Append(eject_user_indication->node_to_eject, alarm); } else error_value = GCC_ALLOCATION_FAILURE; } else { /* ** Here we save the alarm in a list of ejected nodes. This ** alarm is used to cleanup any misbehaving node. Note that ** if the ejected node is not a child of this node then no ** alarm is set up to monitor the ejection. */ m_EjectedNodeList.Append(eject_user_indication->node_to_eject); } } if (error_value == GCC_ALLOCATION_FAILURE) { ERROR_OUT(("MCSUser::ProcessEjectUserIndication: Allocation Failure")); ResourceFailureHandler(); } } /* * void ProcessPermissionGrantIndication () * * Private Function Description: * This routine is responsible for processing an incoming Permission * grant indication PDU. * * Formal Parameters: * permission_grant_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessPermissionGrantIndication( PConductorPermissionGrantIndication permission_grant_indication, UserID sender_id) { GCCError error_value = GCC_NO_ERROR; UserPermissionGrantIndicationInfo grant_indication_info; PPermissionList permission_list; LPBYTE permission_list_memory = NULL; PWaitingList waiting_list; LPBYTE waiting_list_memory = NULL; UINT i; // First count the number of entries in the permission list grant_indication_info.number_granted = 0; permission_list = permission_grant_indication->permission_list; while (permission_list != NULL) { permission_list = permission_list->next; grant_indication_info.number_granted++; } TRACE_OUT(("MCSUser: ProcessPermissionGrantIndication: number_granted=%d", (UINT) grant_indication_info.number_granted)); // If a list exist allocate memory for it and copy it over. if (grant_indication_info.number_granted != 0) { // allocating space to hold permission list. DBG_SAVE_FILE_LINE permission_list_memory = new BYTE[sizeof(UserID) * grant_indication_info.number_granted]; // Now fill in the permission list if (permission_list_memory != NULL) { grant_indication_info.granted_node_list = (PUserID) permission_list_memory; permission_list = permission_grant_indication->permission_list; for (i = 0; i < grant_indication_info.number_granted; i++) { grant_indication_info.granted_node_list[i] = permission_list->value; permission_list = permission_list->next; } } else { ERROR_OUT(("MCSUser: ProcessPermissionGrantIndication: Memory Manager Alloc Failure")); error_value = GCC_ALLOCATION_FAILURE; } } else { grant_indication_info.granted_node_list = NULL; } // Now extract the waiting list information if any exist if ((error_value == GCC_NO_ERROR) && (permission_grant_indication->bit_mask & WAITING_LIST_PRESENT)) { // First count the number of entries in the waiting list grant_indication_info.number_waiting = 0; waiting_list = permission_grant_indication->waiting_list; while (waiting_list != NULL) { waiting_list = waiting_list->next; grant_indication_info.number_waiting++; } TRACE_OUT(("MCSUser: ProcessPermissionGrantIndication: number_waiting=%d", (UINT) grant_indication_info.number_waiting)); // allocating space to hold waiting list. DBG_SAVE_FILE_LINE waiting_list_memory = new BYTE[sizeof(UserID) * grant_indication_info.number_waiting]; // Now fill in the permission list if (waiting_list_memory != NULL) { grant_indication_info.waiting_node_list = (PUserID) waiting_list_memory; waiting_list = permission_grant_indication->waiting_list; for (i = 0; i < grant_indication_info.number_waiting; i++) { grant_indication_info.waiting_node_list[i] = waiting_list->value; waiting_list = waiting_list->next; } } else { error_value = GCC_ALLOCATION_FAILURE; } } else { grant_indication_info.number_waiting = 0; grant_indication_info.waiting_node_list = NULL; } /* ** If there were no memory errors, send the indication back to the ** owner object. */ if (error_value == GCC_NO_ERROR) { m_pConf->ProcessConductorPermitGrantInd(&grant_indication_info, sender_id); } else { ERROR_OUT(("MCSUser::ProcessPermissionGrantIndication: Alloc Failed")); if (GCC_ALLOCATION_FAILURE == error_value) { ResourceFailureHandler(); } } // Free up any memory used in this call delete [] permission_list_memory; delete [] waiting_list_memory; } /* * MCSUser::GetUserIDFromConnection() * * Public Function Description: * This function returns the Node ID associated with the specified * connection handle. It returns zero if the connection handle is * not a child connection of this node. */ UserID MCSUser::GetUserIDFromConnection(ConnectionHandle connection_handle) { ConnectionHandle hConn; UserID uid; m_ChildUidConnHdlList2.Reset(); while (NULL != (hConn = m_ChildUidConnHdlList2.Iterate(&uid))) { if (hConn == connection_handle) { return uid; } } return 0; } /* * MCSUser::UserDisconnectIndication() * * Public Function Description: * This function informs the user object when a Node disconnects from * the conference. This gives the user object a chance to clean up * its internal information base. */ void MCSUser::UserDisconnectIndication(UserID disconnected_user) { PAlarm lpAlarm; /* ** If this node has a pending ejection we will go ahead and remove the ** ejected node from the list. Once all child nodes have disconnected ** we will inform the owner object of the ejection. */ if (m_fEjectionPending) { // Delete the Alarm if it exists if (NULL != (lpAlarm = m_EjectedNodeAlarmList2.Remove(disconnected_user))) { delete lpAlarm; /* ** Here we must check to see if there are anymore active alarms ** in the list. If so we wait until that node disconnects before ** informing the owner object that this node has been ejected. ** Otherwise, we complete the ejection process. */ if (m_EjectedNodeAlarmList2.IsEmpty()) { m_pConf->ProcessEjectUserIndication(m_eEjectReason); } } } // If we are the top provider, just clean the eject alarm list. else if (TOP_PROVIDER_AND_CONVENER_NODE == m_pConf->GetConfNodeType() && NULL != (lpAlarm = m_EjectedNodeAlarmList2.Remove(disconnected_user))) { delete lpAlarm; } /* ** Here we remove the entry from the list of child connections if ** it is included in this list. */ m_ChildUidConnHdlList2.Remove(disconnected_user); } /* * void ProcessApplicationInvokeIndication () * * Private Function Description: * This routine is responsible for processing an incoming Invoke * indication PDU. * * Formal Parameters: * invoke_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser::ProcessApplicationInvokeIndication( PApplicationInvokeIndication invoke_indication, UserID sender_id) { GCCError error_value = GCC_NO_ERROR; BOOL process_pdu = FALSE; CInvokeSpecifierListContainer *invoke_list; PSetOfDestinationNodes set_of_destination_nodes; if (invoke_indication->bit_mask & DESTINATION_NODES_PRESENT) { set_of_destination_nodes = invoke_indication->destination_nodes; while (set_of_destination_nodes != NULL) { if (set_of_destination_nodes->value == m_nidMyself) { process_pdu = TRUE; break; } else { set_of_destination_nodes = set_of_destination_nodes->next; } } } else { process_pdu = TRUE; } if (process_pdu) { TRACE_OUT(("MCSUser: ProcessApplicationInvokeIndication: Process PDU")); DBG_SAVE_FILE_LINE invoke_list = new CInvokeSpecifierListContainer( invoke_indication->application_protocol_entity_list, &error_value); if ((invoke_list != NULL) && (error_value == GCC_NO_ERROR)) { m_pConf->ProcessAppInvokeIndication(invoke_list, sender_id); invoke_list->Release(); } else if (invoke_list == NULL) { error_value = GCC_ALLOCATION_FAILURE; } else { invoke_list->Release(); } if (error_value == GCC_ALLOCATION_FAILURE) { ERROR_OUT(("MCSUser::ProcessApplicationInvokeIndication: Allocation Failure")); ResourceFailureHandler(); } } else { WARNING_OUT(("MCSUser:ProcessApplicationInvokeIndication: Don't Process PDU")); } } /* * GCCError ProcessTextMessageIndication () * * Private Function Description: * This routine is responsible for processing an incoming Text * message indication PDU. * * Formal Parameters: * text_message_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * GCC_NO_ERROR - No error occured. * GCC_ALLOCATION_FAILURE - A resource error occured. * * Side Effects * None. * * Caveats * None. */ #ifdef JASPER GCCError MCSUser::ProcessTextMessageIndication( PTextMessageIndication text_message_indication, UserID sender_id) { LPWSTR gcc_unicode_string; GCCError rc; if (NULL != (gcc_unicode_string = ::My_strdupW2( text_message_indication->message.length, text_message_indication->message.value))) { rc = g_pControlSap->TextMessageIndication( m_pConf->GetConfID(), gcc_unicode_string, sender_id); } else { rc = GCC_ALLOCATION_FAILURE; } return rc; } #endif // JASPER /* * void ProcessRegistryMonitorIndication () * * Private Function Description: * This routine is responsible for processing an incoming Registry * monitor indication PDU. * * Formal Parameters: * monitor_indication - (i) This is the PDU structure to process * sender_id - (i) Node ID of node that sent this PDU. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void MCSUser:: ProcessRegistryMonitorIndicationPDU ( PRegistryMonitorEntryIndication monitor_indication, UserID sender_id ) { if (sender_id == m_nidTopProvider) { CRegistry *pAppReg = m_pConf->GetRegistry(); if (NULL != pAppReg) { GCCError rc; UserRegistryMonitorInfo urmi; ::ZeroMemory(&urmi, sizeof(urmi)); // urmi.registry_key = NULL; // urmi.registry_item = NULL; DBG_SAVE_FILE_LINE urmi.registry_key = new CRegKeyContainer(&monitor_indication->key, &rc); if ((urmi.registry_key != NULL) && (rc == GCC_NO_ERROR)) { DBG_SAVE_FILE_LINE urmi.registry_item = new CRegItem(&monitor_indication->item, &rc); if ((urmi.registry_item != NULL) && (rc == GCC_NO_ERROR)) { // Set up the owner related variables if (monitor_indication->owner.choice == OWNED_CHOSEN) { urmi.owner_node_id = monitor_indication->owner.u.owned.node_id; urmi.owner_entity_id = monitor_indication->owner.u.owned.entity_id; } else { // urmi.owner_node_id = 0; // urmi.owner_entity_id = 0; } // Set up the modification rights if (monitor_indication->bit_mask & RESPONSE_MODIFY_RIGHTS_PRESENT) { urmi.modification_rights = (GCCModificationRights)monitor_indication->entry_modify_rights; } else { urmi.modification_rights = GCC_NO_MODIFICATION_RIGHTS_SPECIFIED; } pAppReg->ProcessMonitorIndicationPDU( urmi.registry_key, urmi.registry_item, urmi.modification_rights, urmi.owner_node_id, urmi.owner_entity_id); } else { rc = GCC_ALLOCATION_FAILURE; } } else { rc = GCC_ALLOCATION_FAILURE; } if (NULL != urmi.registry_key) { urmi.registry_key->Release(); } if (NULL != urmi.registry_item) { urmi.registry_item->Release(); } // Handle any resource errors if (rc == GCC_ALLOCATION_FAILURE) { ResourceFailureHandler(); } } else { WARNING_OUT(("MCSUser:ProcessRegistryMonitorIndication: invalid app registry")); } } else { WARNING_OUT(("MCSUser:ProcessRegistryMonitorIndication:" "Monitor Indication received from NON Top Provider")); } } /* * UINT ProcessDetachUserIndication() * * Private Function Description: * This function is called when the user object gets detach user * indications from nodes in it's subtree or it's parent node. * Depending upon the reason of the indication it sends to the * conference object the appropriate owner callback. * If the reason contained in the indication is UserInitiated or * provider initiated a DETACH USER INDICATION is sent to the con- * ference. The MCS reason is converted to GCC reason. If MCS * reason in indication is neither user initiated nor provider initiated * then the above owner callback carries a GCC reason ERROR_TERMINATION * else it carries a GCC reason USER_INITIATED. * If the detach user indication reveals the user id of the sendar as * the parent user id of this node a CONFERENCE_TERMINATE_INDICATION * is sent to the conference object. * * Formal Parameters: * mcs_reason - (i) MCS reason for being detached. * sender_id - (i) User ID of user being detached. * * Return Value * MCS_NO_ERROR is always returned fro this routine. * * Side Effects * None. * * Caveats * None. */ UINT MCSUser::ProcessDetachUserIndication( Reason mcs_reason, UserID detached_user) { GCCReason gcc_reason; if (detached_user == m_nidParent) { WARNING_OUT(("MCSUser: Fatal Error: Parent User Detached")); m_pConf->ProcessTerminateIndication(GCC_REASON_PARENT_DISCONNECTED); } else { TRACE_OUT(("MCSUser: User Detached: uid=0x%04x", (UINT) detached_user)); /* ** First, we check to see if the detching node was ejected. ** If not, translate the mcs reason to a gcc reason. */ if (m_EjectedNodeList.Find(detached_user)) { gcc_reason = GCC_REASON_NODE_EJECTED; // Remove this entry from the ejected node list. m_EjectedNodeList.Remove(detached_user); } else if (m_EjectedNodeAlarmList2.Find(detached_user)) { // Here we wait for the disconnect before removing the entry. gcc_reason = GCC_REASON_NODE_EJECTED; } else if ((mcs_reason == REASON_USER_REQUESTED) || (mcs_reason == REASON_PROVIDER_INITIATED)) { gcc_reason = GCC_REASON_USER_INITIATED; } else { gcc_reason = GCC_REASON_ERROR_TERMINATION; } m_pConf->ProcessDetachUserIndication(detached_user, gcc_reason); } return (MCS_NO_ERROR); } void MCSUser:: ProcessTokenGrabConfirm ( TokenID tidConductor, Result result ) { if (tidConductor == CONDUCTOR_TOKEN_ID) { m_pConf->ProcessConductorGrabConfirm(::TranslateMCSResultToGCCResult(result)); } else { ERROR_OUT(("MCSUser:Assertion Failure: Non Conductor Grab Confirm")); } } void MCSUser:: ProcessTokenGiveIndication ( TokenID tidConductor, UserID uidRecipient ) { if (tidConductor == CONDUCTOR_TOKEN_ID) { m_pConf->ProcessConductorGiveIndication(uidRecipient); } else { ERROR_OUT(("MCSUser:Assertion Failure: Non Conductor Please Ind")); } } void MCSUser:: ProcessTokenGiveConfirm ( TokenID tidConductor, Result result ) { if (tidConductor == CONDUCTOR_TOKEN_ID) { m_pConf->ProcessConductorGiveConfirm(::TranslateMCSResultToGCCResult(result)); } else { ERROR_OUT(("MCSUser:Assertion Failure: Non Conductor Grab Confirm")); } } #ifdef JASPER void MCSUser:: ProcessTokenPleaseIndication ( TokenID tidConductor, UserID uidRequester ) { if (tidConductor == CONDUCTOR_TOKEN_ID) { if (m_pConf->IsConfConductible()) { // Inform the control SAP. g_pControlSap->ConductorPleaseIndication( m_pConf->GetConfID(), uidRequester); } } else { ERROR_OUT(("MCSUser:Assertion Failure: Non Conductor Please Ind")); } } #endif // JASPER #ifdef JASPER void MCSUser:: ProcessTokenReleaseConfirm ( TokenID tidConductor, Result result ) { if (tidConductor == CONDUCTOR_TOKEN_ID) { g_pControlSap->ConductorReleaseConfirm(::TranslateMCSResultToGCCResult(result), m_pConf->GetConfID()); } else { ERROR_OUT(("MCSUser:Assertion Failure: Non Conductor Release Cfrm")); } } #endif // JASPER void MCSUser:: ProcessTokenTestConfirm ( TokenID tidConductor, TokenStatus eStatus ) { if (tidConductor == CONDUCTOR_TOKEN_ID) { m_pConf->ProcessConductorTestConfirm((eStatus == TOKEN_NOT_IN_USE) ? GCC_RESULT_NOT_IN_CONDUCTED_MODE : GCC_RESULT_SUCCESSFUL); } else { ERROR_OUT(("MCSUser:Assertion Failure: Non Conductor Release Cfrm")); } } void MCSUser::ResourceFailureHandler(void) { ERROR_OUT(("MCSUser::ResourceFailureHandler: terminating the conference")); m_pConf->InitiateTermination(GCC_REASON_ERROR_LOW_RESOURCES, 0); }