|
|
#include "precomp.h"
DEBUG_FILEZONE(ZONE_T120_GCCNC); /*
* conf.cpp * * Copyright (c) 1995 by DataBeam Corporation, Lexington, KY * * Abstract: * This is the imlementation file for the CConf Class. The * conference class is the heart of GCC. It maintains all the * information basses for a single conference including conference and * application rosters as well as registry information. It also * routes, encodes and decodes various PDU's and primitives supported * by GCC. * * FOR A MORE DETAILED EXPLANATION OF THIS CLASS SEE THE INTERFACE FILE. * * Portable: * Yes * * Private Instance Variables * m_JoinRespNamePresentConnHdlList2 * This list keeps up with outstanding joins at an intermediate node. * Enrolled_App_List * This list keeps up with all the enrolled applications. * m_ConnHandleList * This list keeps up with all the child node connection handles. * m_ConnHdlTagNumberList2 * This list keeps up with all the outstanding user ID Tag numbers. * m_EjectedNodeConfirmList * This list keeps up with all the nodes that have been ejected but * have yet to disconnect. Used to disconnect any misbehaving apps. * m_pMcsUserObject * Holds a pointer to the MCSUser object owned by this conference. * m_pszConfNumericName * Holds the numeric conference name. * m_pwszConfTextName * Holds a pointer to a unicode string object that contains the text * conference name. NULL if empty. * m_pszConfModifier * Holds a pointer to the conference modifier. NULL if empty. * m_pszRemoteModifier * Holds a pointer to the remote modifier. Only used in Join Confirms. * m_nConfID * Holds the conference ID associated with this conference object. * m_fConfLocked * Flag that indicates if the conference is locked. * m_fConfListed * Flag that indicates if the conference is listed. * m_fConfConductible * Flag that indicates if the conference is conductible. * m_fClearPassword * Flag that indicates if password in the clear is used. * m_nConvenerNodeID * Holds the MCS user ID of the convener. Zero if convener has left. * m_eTerminationMethod * Holds the enumeration that defines the termination method. * m_pDomainParameters * Holds the domain parameters that are returned in a number * of confirms. * m_nUserIDTagNumber * The tag number that must be included when sending this nodes user ID * back to a connected node. * m_nConvenerUserIDTagNumber * Used to uniquely mark the convener when it is rejoining a * conference. * m_nParentIDTagNumber * Used to uniquely mark the parent user ID for an invited node. * m_eNodeType * Holds the enumerated Node Type for this particular node. * m_hParentConnection * Holds the parent logical connection handle. * m_hConvenerConnection * Holds the convener connection handle. * m_fConfIsEstablished * Flag which is set to TRUE when the confernce is completely * established and ready for enrolls and announces. * m_fConfDisconnectPending * Flag which is set to TRUE when a disconnect has been issued but * the conference is waiting for subordinate nodes to disconnect. * m_fConfTerminatePending * Flag which is set to TRUE when a terminate has been issued but * the conference is waiting for subordinate nodes to disconnect. * m_eConfTerminateReason * Maintains the terminate reason for delivery in the indication. * m_pConfTerminateAlarm * Alarm that is used to force automatic termination when * subordinate nodes will not disconnect. * m_pConfStartupAlarm * Alarm used to hold back the flush of the first roster update * indication until all the APEs that wish to enroll have had time * to enroll. * m_pConductorPrivilegeList * Holds a pointer to the conductor privilege list object. * m_pConductModePrivilegeList * Holds a pointer to the conducted mode privilege list object. * m_pNonConductModePrivilegeList * Holds a pointer to the non-conducted mode privilege list object. * m_pwszConfDescription * Holds a pointer to a unicode string which holds the conference * description. * m_pNetworkAddressList * Holds a pointer to an object that contains all the local network * addresses. * m_pUserDataList * Holds a pointer to a user data object needed to deliver an * asynchronus confirm message. * m_nConfAddRequestTagNumber * This instance variable is used to generate the add request tag that * is returned in an add response. * m_nConfAddResponseTag * This instance variable is used to generate a response tag that is * passed in an add indication and returned in an add response. * m_AddRequestList * List that keeps up with all the outstanding add request tags. * m_AddResponseList * List that keeps up with all the outstanding add response tags. * m_pConfRosterMgr * Pointer to the Conference Roster manager. * m_AppRosterMgrList * List which holds pointers to all ofthe Application Roster managers. * m_pAppRegistry * Pointer to the Application Registry object used by this conference. * m_InviteRequestList * List which keeps up with the info associated with all of the * outstanding invite request. Used for cleanup when the invited * node never responds. * m_nConductorNodeID * The MCS user ID associated with the conducting node. Zero if the * conference is not in conducted mode. * m_nPendingConductorNodeID * Used to keep up with the new conductor node ID when conductorship * is being passed from one node to another. * m_fConductorGrantedPermission * Flag which when TRUE specifies that this node has conductor granted * permission. * m_ConductorTestList * List that is used to keep up with all the command targets that have * issued conductor inquire request. * m_fConductorGiveResponsePending * Flag that states if this node is waiting on a conductor give * response. * m_fConductorAssignRequestPending * Flag that states if this node is waiting to here back from an * assign request. * APE_Enitity_ID * This is a counter used to generate application enityt ids. * * Caveats: * Note that the conference object is now split into two seperate files * to prevent text segment problems. This file contains the constructors * and all the entry points for the Owner Object. * * Author: * blp */
#include "conf.h"
#include "gcontrol.h"
#include "translat.h"
#include "ogcccode.h"
#ifdef _DEBUG
#define STARTUP_TIMER_DURATION 10000 // Ten second startup time
#else
#define STARTUP_TIMER_DURATION 2000 // Two second startup time
#endif
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;
/*
* CConf::CConf () * * Public Function Description * When pConfSpecParams != NULL * This is the conference constructor. It is responsible for * initializing all the instance variables used by this class. * It also creates the MCS domain based on the conference id. * Fatal errors are returned from this constructor in the * return value. Note that this constructor is used when the * Conference specification parameters such as termination * method or known in advance of conference creation. This is * the case for a CONVENOR node and a TOP PROVIDER. It is not * used for joining nodes. * * When pConfSpecParams == NULL * This is the conference constructor. It is responsible for * initializing all the instance variables used by this class. * It also creates the MCS domain based on the conference id. * Fatal errors are returned from this constructor in the * return value. Note that this constructor is used by nodes that * do not know the Conference specification parameters such as * termination method in advance of conference creation. This is * the case for joining nodes. */ CConf:: CConf ( PGCCConferenceName pConfName, GCCNumericString pszConfModifier, GCCConfID nConfID, CONF_SPEC_PARAMS *pConfSpecParams, UINT cNetworkAddresses, PGCCNetworkAddress *pLocalNetworkAddress, PGCCError pRetCode ) : CRefCount(MAKE_STAMP_ID('C','o','n','f')), m_RegisteredAppSapList(DESIRED_MAX_APP_SAP_ITEMS), m_EnrolledApeEidList2(DESIRED_MAX_APP_SAP_ITEMS), m_ConnHdlTagNumberList2(DESIRED_MAX_CONN_HANDLES), m_JoinRespNamePresentConnHdlList2(CLIST_DEFAULT_MAX_ITEMS), m_InviteRequestList(CLIST_DEFAULT_MAX_ITEMS), m_ConnHandleList(DESIRED_MAX_CONN_HANDLES), m_EjectedNodeConfirmList(CLIST_DEFAULT_MAX_ITEMS), m_AddRequestList(CLIST_DEFAULT_MAX_ITEMS), m_AddResponseList(CLIST_DEFAULT_MAX_ITEMS), m_NodeVersionList2(CLIST_DEFAULT_MAX_ITEMS), m_cEnrollRequests(0), m_fFirstAppRosterSent(FALSE), m_nConfID(nConfID), m_pMcsUserObject(NULL), m_pDomainParameters(NULL), m_pUserDataList(NULL), m_pszRemoteModifier(NULL), m_pConfRosterMgr(NULL), m_pAppRegistry(NULL), m_nConductorNodeID(0), m_nPendingConductorNodeID(0), m_fConductorGrantedPermission(FALSE), m_fConductorGiveResponsePending(FALSE), m_fConductorAssignRequestPending(FALSE), m_hParentConnection(0), m_hConvenerConnection(0), m_pConfTerminateAlarm(NULL), m_nUserIDTagNumber(0), m_nConfAddRequestTagNumber(0), m_nConfAddResponseTag(0), m_nConvenerNodeID(0), m_nConvenerUserIDTagNumber(0), m_nAPEEntityID(0), m_pwszConfTextName(NULL), m_pszConfModifier(NULL), m_pConductorPrivilegeList(NULL), m_pConductModePrivilegeList(NULL), m_pNonConductModePrivilegeList(NULL), m_pwszConfDescription(NULL), m_pNetworkAddressList(NULL), /* This variable transitions to TRUE when the conference has completely
** stabilized. Once it is set to TRUE applications may enroll with the ** conference. */ m_fConfIsEstablished(FALSE), /* This variable is transitioned to TRUE if the node that is
** disconnected is connected to child nodes. */ m_fConfDisconnectPending(FALSE), /* This variable is transitioned to TRUE if a valid Terminate request
** is processed. */ m_fConfTerminatePending(FALSE), /* This variable is set to TRUE if InitiateTermination is called once */ m_fTerminationInitiated(FALSE), m_fSecure(FALSE), m_fWBEnrolled(FALSE), m_fFTEnrolled(FALSE), m_fChatEnrolled(FALSE) { GCCError rc = GCC_ALLOCATION_FAILURE;
DebugEntry(CConf::CConf);
// Conference Specification
if (NULL != pConfSpecParams) { m_fClearPassword = pConfSpecParams->fClearPassword; m_fConfLocked = pConfSpecParams->fConfLocked; m_fConfListed = pConfSpecParams->fConfListed; m_fConfConductible = pConfSpecParams->fConfConductable; m_eTerminationMethod = pConfSpecParams->eTerminationMethod; }
// m_pConfStartupAlarm = NULL;
DBG_SAVE_FILE_LINE m_pConfStartupAlarm = new Alarm(STARTUP_TIMER_DURATION); if (NULL == m_pConfStartupAlarm) { ERROR_OUT(("CConf::CConf: Error allocating startup alarm")); goto MyExit; }
// Save the numeric conference name.
if (NULL != pConfName->numeric_string) { if (NULL == (m_pszConfNumericName = ::My_strdupA(pConfName->numeric_string))) { ERROR_OUT(("CConf::CConf: Error allocating conf numeric name")); goto MyExit; } TRACE_OUT(("CConf::CConf: m_strConfNumericName = %s", m_pszConfNumericName)); } else { m_pszConfNumericName = NULL; if (NULL != pConfSpecParams) { //
// LONCHANC: It is an error for top-provider.
//
ERROR_OUT(("CConf::CConf: Error: Numeric Name not present")); rc = GCC_INVALID_CONFERENCE_NAME; goto MyExit; } //
// LONCHANC: It is not an error for joining node.
//
}
// Save the text conference name if one exists
if (NULL != pConfName->text_string) { if (NULL == (m_pwszConfTextName = ::My_strdupW(pConfName->text_string))) { ERROR_OUT(("CConf::CConf: Error allocating unicode string")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; } }
// Save the conference modifier if one exists
if (NULL != pszConfModifier) { if (NULL == (m_pszConfModifier = ::My_strdupA(pszConfModifier))) { ERROR_OUT(("CConf::CConf: Error allocating conf modifier")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; } else { TRACE_OUT(("CConf::CConf: Conference_Modifier = %s", m_pszConfModifier)); } }
// Set up the privilege list as needed
if (NULL != pConfSpecParams) { if (NULL != pConfSpecParams->pConductPrivilege) { DBG_SAVE_FILE_LINE m_pConductorPrivilegeList = new PrivilegeListData(pConfSpecParams->pConductPrivilege); if (NULL == m_pConductorPrivilegeList) { ERROR_OUT(("CConf::CConf: Error allocating conductor privilege list")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; } } if (NULL != pConfSpecParams->pConductModePrivilege) { DBG_SAVE_FILE_LINE m_pConductModePrivilegeList = new PrivilegeListData(pConfSpecParams->pConductModePrivilege); if (NULL == m_pConductModePrivilegeList) { ERROR_OUT(("CConf::CConf: Error allocating conduct mode privilege list")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; } }
if (NULL != pConfSpecParams->pNonConductPrivilege) { DBG_SAVE_FILE_LINE m_pNonConductModePrivilegeList = new PrivilegeListData(pConfSpecParams->pNonConductPrivilege); if (NULL == m_pNonConductModePrivilegeList) { ERROR_OUT(("CConf::CConf: Error allocating non-conduct mode privilege list")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; } }
if (NULL != pConfSpecParams->pwszConfDescriptor) { if (NULL == (m_pwszConfDescription = ::My_strdupW(pConfSpecParams->pwszConfDescriptor))) { ERROR_OUT(("CConf::CConf: Error allocating conf descriptor")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; } } }
// Save the network address(es)
if (0 != cNetworkAddresses) { DBG_SAVE_FILE_LINE m_pNetworkAddressList = new CNetAddrListContainer(cNetworkAddresses, pLocalNetworkAddress, &rc); if (NULL == m_pNetworkAddressList || GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::CConf: Error allocating network address list")); rc = GCC_ALLOCATION_FAILURE; // rc could be a different value
goto MyExit; } }
ASSERT(GCC_ALLOCATION_FAILURE == rc);
/*
** Create the Domain based on the conference name that was ** passed in. */ if (MCS_NO_ERROR != g_pMCSIntf->CreateDomain(&m_nConfID)) { ERROR_OUT(("CConf::CConf: Error creating domain")); rc = GCC_FAILURE_CREATING_DOMAIN; goto MyExit; }
rc = GCC_NO_ERROR;
MyExit:
*pRetCode = rc;
DebugExitINT(CConf::CConf, rc); }
/*
* CConf::~CConf () * * Public Function Description * This is the conference destructor. It is responsible for * deleting the User Attachment and freeing up any outstanding * resources used by the conference class. It also calls * MCS Disconnect Provider to disconnect fron all its connections * including both parent and child connections. In addition, it * unregisters its command target from the controller and application * SAPs and deletes the MCS domain it is associated with. * * Caveats * none */ CConf:: ~CConf ( void ) { ConnectionHandle nConnHdl; //CAppRosterMgr *lpAppRosterMgr;
ENROLLED_APE_INFO *lpEnrAPEInfo; //CAppSap *pAppSap;
DebugEntry(CConf::~CConf);
// Delete the terminate alarm if it exists
delete m_pConfTerminateAlarm;
// Delete the startup alarm if it exists
delete m_pConfStartupAlarm;
// Delete Conference Roster Managers
if (NULL != m_pConfRosterMgr) { m_pConfRosterMgr->Release(); }
// Delete Application Roster Managers
m_AppRosterMgrList.DeleteList();
// Delete the application registry
if (NULL != m_pAppRegistry) { m_pAppRegistry->Release(); }
// Delete the text conference name if it exist
delete m_pszConfNumericName; delete m_pwszConfTextName;
// Delete the conference modifier if it exist
delete m_pszConfModifier;
// Delete the remote modifier if it exist
delete m_pszRemoteModifier;
/*
** The privilege list are not directly deleted here instead Free is called ** to prevent the list from being deleted in the case where it has been ** locked outside the conference object. */
// Delete all the privilege list (Free is needed incase the list
delete m_pConductorPrivilegeList; delete m_pConductModePrivilegeList; delete m_pNonConductModePrivilegeList;
// Delete the conference descriptor
delete m_pwszConfDescription;
// Delete the network address list
if (NULL != m_pNetworkAddressList) { m_pNetworkAddressList->Release(); }
if (NULL != m_pUserDataList) { m_pUserDataList->Release(); }
// Delete the Domain Parameters if they exist
delete m_pDomainParameters;
// Delete the User Attachment object if they exist
if (NULL != m_pMcsUserObject) { m_pMcsUserObject->Release(); }
// Disconnect from the MCS parent connection
if (m_hParentConnection != NULL) { g_pMCSIntf->DisconnectProviderRequest(m_hParentConnection); }
// Disconnect from all MCS child connections
m_ConnHandleList.Reset(); while (0 != (nConnHdl = m_ConnHandleList.Iterate())) { g_pMCSIntf->DisconnectProviderRequest(nConnHdl); }
// Delete the MCS domain
g_pMCSIntf->DeleteDomain(&m_nConfID);
// Cleanup up the m_EnrolledApeEidList2
m_EnrolledApeEidList2.Reset(); while (NULL != (lpEnrAPEInfo = m_EnrolledApeEidList2.Iterate())) { if (NULL != lpEnrAPEInfo->session_key) { lpEnrAPEInfo->session_key->Release(); } delete lpEnrAPEInfo; }
DebugExitVOID(CConf::~CConf); }
/*
** Non-CommandTarget Calls. Initiated from the Owner Object. Note that ** all calls received from the owner object are preceeded by GCC. */
/*
* CConf::ConfCreateRequest() * * Public Function Description * This routine is called from the owner object when a * ConferenceCreateRequest primitive needs to be processed. * If the calling address equals the called address then an * empty conference is created at this node (this node will * then be both the convenor and the top provider). * * Caveats * All errors should be handled directly by the calling application. * This includes deletion of the conference object. */ GCCError CConf:: ConfCreateRequest ( TransportAddress calling_address, TransportAddress called_address, BOOL fSecure, CPassword *convener_password, CPassword *password, LPWSTR pwszCallerID, PDomainParameters domain_parameters, CUserDataListContainer *user_data_list, PConnectionHandle connection_handle ) { GCCError rc = GCC_ALLOCATION_FAILURE; ConnectGCCPDU connect_pdu; LPBYTE encoded_pdu; UINT encoded_pdu_length; MCSError mcs_error;
DebugEntry(CConf::ConfCreateRequest);
/*
** First make a copy of the new domain parameters if they exists. These ** will be copied over when the connect provider confirm comes in. */ if (NULL != domain_parameters) { DBG_SAVE_FILE_LINE m_pDomainParameters = new DomainParameters; if (NULL == m_pDomainParameters) { ERROR_OUT(("CConf::ConfCreateRequest: can't create DomainParameters")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; }
// structure-wide shallow copy
*m_pDomainParameters = *domain_parameters; }
/*
** If the called address equals NULL this node will be both the Top ** Provider and the Convener. In this case there is no need to send out the ** ConfCreateRq PDU. Instead we go ahead and create the User Object. If the ** conference is created with someone else, wait until the response is ** returned before creating the User Object. */ if (NULL != called_address) { // Set up the node type
m_eNodeType = CONVENER_NODE;
/*
** Create the ConferenceCreateRequest PDU here. */ connect_pdu.choice = CONFERENCE_CREATE_REQUEST_CHOSEN; connect_pdu.u.conference_create_request.bit_mask = 0;
// Encode the conference name
connect_pdu.u.conference_create_request.conference_name.bit_mask = 0; // Encode the numeric portion of the name
::lstrcpyA(connect_pdu.u.conference_create_request.conference_name.numeric, m_pszConfNumericName);
// Encode the text portion of the conference name if it exists
if (NULL != m_pwszConfTextName) { connect_pdu.u.conference_create_request.conference_name.bit_mask |= CONFERENCE_NAME_TEXT_PRESENT; connect_pdu.u.conference_create_request.conference_name.conference_name_text.value = m_pwszConfTextName; connect_pdu.u.conference_create_request.conference_name.conference_name_text.length = ::lstrlenW(m_pwszConfTextName); }
// Encode the convener password if one exists.
if (NULL != convener_password) { rc = convener_password->GetPasswordPDU( &connect_pdu.u.conference_create_request.ccrq_convener_password); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfCreateRequest: can't get convenor password, rc=%d", rc)); goto MyExit; }
connect_pdu.u.conference_create_request.bit_mask |= CCRQ_CONVENER_PASSWORD_PRESENT; }
// Encode the convener password if one exists.
if (NULL != password) { rc = password->GetPasswordPDU( &connect_pdu.u.conference_create_request.ccrq_password); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfCreateRequest: can't get password, rc=%d", rc)); goto MyExit; }
connect_pdu.u.conference_create_request.bit_mask |= CCRQ_PASSWORD_PRESENT; }
// Encode the privilege list
if (NULL != m_pConductorPrivilegeList) { rc = m_pConductorPrivilegeList->GetPrivilegeListPDU( &connect_pdu.u.conference_create_request.ccrq_conductor_privs); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfCreateRequest: can't get conductor's privileges, rc=%d", rc)); goto MyExit; }
connect_pdu.u.conference_create_request.bit_mask |= CCRQ_CONDUCTOR_PRIVS_PRESENT; } if (NULL != m_pConductModePrivilegeList) { rc = m_pConductModePrivilegeList->GetPrivilegeListPDU( &connect_pdu.u.conference_create_request.ccrq_conducted_privs); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfCreateRequest: can't get conduct mode privileges, rc=%d", rc)); goto MyExit; }
connect_pdu.u.conference_create_request.bit_mask |= CCRQ_CONDUCTED_PRIVS_PRESENT; } if (NULL != m_pNonConductModePrivilegeList) { rc = m_pNonConductModePrivilegeList->GetPrivilegeListPDU( &connect_pdu.u.conference_create_request.ccrq_non_conducted_privs); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfCreateRequest: can't get non-conduct mode privileges, rc=%d", rc)); goto MyExit; }
connect_pdu.u.conference_create_request.bit_mask |= CCRQ_NON_CONDUCTED_PRIVS_PRESENT; } // Encode the conference descriptor
if (NULL != m_pwszConfDescription) { connect_pdu.u.conference_create_request.bit_mask |= CCRQ_DESCRIPTION_PRESENT;
connect_pdu.u.conference_create_request.ccrq_description.length = ::lstrlenW(m_pwszConfDescription);
connect_pdu.u.conference_create_request.ccrq_description.value = m_pwszConfDescription; }
// Encode the caller identifier if on exists.
if (NULL != pwszCallerID) { connect_pdu.u.conference_create_request.bit_mask |= CCRQ_CALLER_ID_PRESENT; connect_pdu.u.conference_create_request.ccrq_caller_id.length = ::lstrlenW(pwszCallerID); connect_pdu.u.conference_create_request.ccrq_caller_id.value = pwszCallerID; } // Encode the user data if any exists
if (NULL != user_data_list) { rc = user_data_list->GetUserDataPDU( &connect_pdu.u.conference_create_request.ccrq_user_data); if (GCC_NO_ERROR != NULL) { ERROR_OUT(("CConf::ConfCreateRequest: can't get user data, rc=%d", rc)); goto MyExit; }
connect_pdu.u.conference_create_request.bit_mask |= CCRQ_USER_DATA_PRESENT; }
connect_pdu.u.conference_create_request.conference_is_locked = (ASN1bool_t)m_fConfLocked; connect_pdu.u.conference_create_request.conference_is_listed = (ASN1bool_t)m_fConfListed; connect_pdu.u.conference_create_request.conference_is_conductible = (ASN1bool_t)m_fConfConductible; connect_pdu.u.conference_create_request.termination_method = (TerminationMethod)m_eTerminationMethod;
if (! g_GCCCoder->Encode((LPVOID) &connect_pdu, CONNECT_GCC_PDU, PACKED_ENCODING_RULES, &encoded_pdu, &encoded_pdu_length)) { ERROR_OUT(("CConf::ConfCreateRequest: can't encode")); rc = GCC_ALLOCATION_FAILURE; goto MyExit; }
mcs_error = g_pMCSIntf->ConnectProviderRequest ( &m_nConfID, // calling domain selector
&m_nConfID, // called domain selector
calling_address, called_address, fSecure, TRUE, // Upward connection
encoded_pdu, encoded_pdu_length, &m_hParentConnection, m_pDomainParameters, this);
g_GCCCoder->FreeEncoded(encoded_pdu); *connection_handle = m_hParentConnection;
if (MCS_NO_ERROR != mcs_error) { ERROR_OUT(("CConf::ConfCreateRequest: ConnectProviderRequest call failed, rc=%d", mcs_error));
/*
** DataBeam's current implementation of MCS returns ** MCS_INVALID_PARAMETER when something other than ** the transport prefix is wrong with the specified ** transport address. */ rc = (mcs_error == MCS_INVALID_PARAMETER) ? GCC_INVALID_TRANSPORT_ADDRESS : g_pMCSIntf->TranslateMCSIFErrorToGCCError(mcs_error); goto MyExit; } // Free the privilege list packed into structures for encoding
if (connect_pdu.u.conference_create_request.bit_mask & CCRQ_CONDUCTOR_PRIVS_PRESENT) { m_pConductorPrivilegeList->FreePrivilegeListPDU( connect_pdu.u.conference_create_request.ccrq_conductor_privs); }
if (connect_pdu.u.conference_create_request.bit_mask & CCRQ_CONDUCTED_PRIVS_PRESENT) { m_pConductModePrivilegeList->FreePrivilegeListPDU( connect_pdu.u.conference_create_request.ccrq_conducted_privs); }
if (connect_pdu.u.conference_create_request.bit_mask & CCRQ_NON_CONDUCTED_PRIVS_PRESENT) { m_pNonConductModePrivilegeList->FreePrivilegeListPDU( connect_pdu.u.conference_create_request.ccrq_non_conducted_privs); } } else { *connection_handle = NULL; m_eNodeType = TOP_PROVIDER_AND_CONVENER_NODE; DBG_SAVE_FILE_LINE m_pMcsUserObject = new MCSUser(this, 0, 0, &rc); if (NULL == m_pMcsUserObject || GCC_NO_ERROR != rc) { ERROR_OUT(("CConf: ConfCreateRequest: can't create mcs user object, rc=%d", rc)); if (NULL != m_pMcsUserObject) { m_pMcsUserObject->Release(); m_pMcsUserObject = NULL; } else { rc = GCC_ALLOCATION_FAILURE; // rc may be a different value
} goto MyExit; } }
m_fSecure = fSecure;
rc = GCC_NO_ERROR;
MyExit:
if (GCC_NO_ERROR != rc) { if (NULL != domain_parameters) { delete m_pDomainParameters; m_pDomainParameters = NULL; } }
DebugExitINT(CConf::ConferenceCreateRequest, rc); return rc; }
/*
* CConf::ConfCreateResponse () * * Public Function Description * This routine is called from the owner object when a * ConferenceCreateResponse primitive needs to be processed. * Note that this should only be called when the result of * the response is success. Only the top provider receives the * conference create response. * * Caveats * All errors should be handled directly by the calling application. * This includes deletion of the conference object and notification * to the node controller that the conference was abnormally * terminated. */ GCCError CConf:: ConfCreateResponse ( ConnectionHandle connection_handle, PDomainParameters domain_parameters, CUserDataListContainer *user_data_list ) { GCCError rc = GCC_ALLOCATION_FAILURE;
DebugEntry(CConf::ConfCreateResponse);
// Conference Create Responses can only be received at the top provider
m_eNodeType = TOP_PROVIDER_NODE;
/*
** First make a copy of the new domain parameters if they exists. We do ** this here so that they can be passed in when we perform the Connect ** Provider Response. */ if (domain_parameters != NULL) { DBG_SAVE_FILE_LINE m_pDomainParameters = new DomainParameters; if (NULL == m_pDomainParameters) { ERROR_OUT(("CConf::ConfCreateResponse: can't create domain parameters")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; }
// structure-wide shallow copy
*m_pDomainParameters = *domain_parameters; }
// Store the child connection in the list of connection handles
ASSERT(0 != connection_handle); m_ConnHandleList.Append(connection_handle);
/*
** The convener connection handle is stored seperately so that ** the Connect Provider response can be sent on the right ** connection. This may be overkill but I was a little concerned ** about pulling this out of the list even though this should be ** the only entry in the list when it's time to send the response. */ m_hConvenerConnection = connection_handle; if (user_data_list != NULL) { /*
** Since we must wait until the user attachment is fully ** established before we send the response we must save the user ** data list in a temporary container. */ m_pUserDataList = user_data_list; // Lock the user data in memory
m_pUserDataList->LockUserDataList(); }
/*
** Now create the user attachment object and wait for the confirm ** which occurs after all the proper channels are joined. The ** user object will determine the top provider ID. When the user ** create confirm is received the response PDU will be sent out ** in the Connect Provider Response. */ DBG_SAVE_FILE_LINE m_pMcsUserObject = new MCSUser(this, 0, 0, &rc); if (NULL == m_pMcsUserObject || GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfCreateResponse: can't create mcs user object, rc=%d", rc)); if (NULL != m_pMcsUserObject) { m_pMcsUserObject->Release(); m_pMcsUserObject = NULL; } else { rc = GCC_ALLOCATION_FAILURE; // rc may be a different value
} goto MyExit; }
rc = GCC_NO_ERROR;
MyExit:
if (GCC_NO_ERROR != rc) { if (NULL != domain_parameters) { delete m_pDomainParameters; m_pDomainParameters = NULL; } }
DebugExitINT(CConf::ConferenceCreateResponse, rc); return rc; }
/*
* CConf::ConfJoinRequest() * * Public Function Description * This routine is called from the owner object when a * ConferenceJoinRequest primitive received from the node controller needs * to be processed. This routine sends a JoinRequest PDU to its parent * node through an MCS Connect Provider Request. * * Caveats * All errors should be handled directly by the calling application. * This includes deletion of the conference object. */ GCCError CConf:: ConfJoinRequest ( GCCNumericString called_node_modifier, CPassword *convener_password, CPassword *password_challenge, LPWSTR pwszCallerID, TransportAddress calling_address, TransportAddress called_address, BOOL fSecure, PDomainParameters domain_parameters, CUserDataListContainer *user_data_list, PConnectionHandle connection_handle ) { GCCError rc = GCC_ALLOCATION_FAILURE; LPBYTE encoded_pdu; UINT encoded_pdu_length; MCSError mcs_error; ConnectGCCPDU connect_pdu;
DebugEntry(CConf::ConfJoinRequest);
ASSERT(FALSE == m_fSecure); m_fSecure = fSecure;
/*
** First make a copy of the new domain parameters if they exists. These ** will be copied over when the connect provider confirm comes in. */ if (domain_parameters != NULL) { DBG_SAVE_FILE_LINE m_pDomainParameters = new DomainParameters; if (NULL == m_pDomainParameters) { ERROR_OUT(("CConf::ConfJoinRequest: can't create domain parameters")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; }
*m_pDomainParameters = *domain_parameters; }
m_eNodeType = (NULL == convener_password) ? // Node type must be joined when receiving this request
JOINED_NODE : // Node type must be joined convener when receiving this request
JOINED_CONVENER_NODE; // Create the ConferenceJoinRequest PDU here.
connect_pdu.choice = CONNECT_JOIN_REQUEST_CHOSEN;
connect_pdu.u.connect_join_request.bit_mask = CONFERENCE_NAME_PRESENT;
if (NULL != m_pszConfNumericName && '\0' != *m_pszConfNumericName) { // Send the numeric portion of the conference name
connect_pdu.u.connect_join_request.conference_name.choice = NAME_SELECTOR_NUMERIC_CHOSEN;
::lstrcpyA(connect_pdu.u.connect_join_request.conference_name.u.name_selector_numeric, m_pszConfNumericName); } else { // Send the text portion of the conference name
connect_pdu.u.connect_join_request.conference_name.choice = NAME_SELECTOR_TEXT_CHOSEN;
connect_pdu.u.connect_join_request.conference_name.u.name_selector_text.length = ::lstrlenW(m_pwszConfTextName); connect_pdu.u.connect_join_request.conference_name.u.name_selector_text.value = m_pwszConfTextName; } // Fill in the remote node modifier if one exists
if (NULL != called_node_modifier) { // Save the remote modifier so that it can be returned in the confirm
if (NULL == (m_pszRemoteModifier = ::My_strdupA(called_node_modifier))) { ERROR_OUT(("CConf::ConfJoinRequest: can't create remote modifier")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; }
connect_pdu.u.connect_join_request.bit_mask |= CJRQ_CONFERENCE_MODIFIER_PRESENT; ::lstrcpyA(connect_pdu.u.connect_join_request.cjrq_conference_modifier, (LPCSTR) called_node_modifier); } // Fill in the convener password selector.
if (NULL != convener_password) { rc = convener_password->GetPasswordSelectorPDU( &connect_pdu.u.connect_join_request.cjrq_convener_password); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinRequest: can't get password selector, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_request.bit_mask |= CJRQ_CONVENER_PASSWORD_PRESENT; }
// Fill in the password challenge
if (NULL != password_challenge) { rc = password_challenge->GetPasswordChallengeResponsePDU( &connect_pdu.u.connect_join_request.cjrq_password); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinRequest: can't get password challenge response, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_request.bit_mask |=CJRQ_PASSWORD_PRESENT; }
// Fill in the caller identifier if one exists
if (NULL != pwszCallerID) { connect_pdu.u.connect_join_request.bit_mask |= CJRQ_CALLER_ID_PRESENT; connect_pdu.u.connect_join_request.cjrq_caller_id.value = pwszCallerID; connect_pdu.u.connect_join_request.cjrq_caller_id.length = ::lstrlenW(pwszCallerID); }
// Fill in the user data if it exists
if (NULL != user_data_list) { rc = user_data_list->GetUserDataPDU( &connect_pdu.u.connect_join_request.cjrq_user_data); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinRequest: can't get user data, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_request.bit_mask |= CJRQ_USER_DATA_PRESENT; }
if (! g_GCCCoder->Encode((LPVOID) &connect_pdu, CONNECT_GCC_PDU, PACKED_ENCODING_RULES, &encoded_pdu, &encoded_pdu_length)) { ERROR_OUT(("CConf::ConfJoinRequest: can't encode")); rc = GCC_ALLOCATION_FAILURE; goto MyExit; }
/*
** Note that the TransportStrings are casted twice here. It ** must be done this way to satisfy the compiler. Sorry about ** not adhearing to coding standards. */ mcs_error = g_pMCSIntf->ConnectProviderRequest( &m_nConfID, // calling domain selector
&m_nConfID, // called domain selector
calling_address, called_address, m_fSecure, TRUE, // Upward connection
encoded_pdu, encoded_pdu_length, &m_hParentConnection, m_pDomainParameters, this);
g_GCCCoder->FreeEncoded(encoded_pdu);
*connection_handle = m_hParentConnection;
if (MCS_NO_ERROR != mcs_error) { ERROR_OUT(("CConf::ConfJoinRequest: can't connect provider request, rc=%d", mcs_error)); /*
** DataBeam's current implementation of MCS returns ** MCS_INVALID_PARAMETER when something other than ** the transport prefix is wrong with the specified ** transport address. */ rc = (mcs_error == MCS_INVALID_PARAMETER) ? GCC_INVALID_TRANSPORT_ADDRESS : g_pMCSIntf->TranslateMCSIFErrorToGCCError(mcs_error); goto MyExit; }
rc = GCC_NO_ERROR;
MyExit:
if (GCC_NO_ERROR != rc) { if (NULL != domain_parameters) { delete m_pDomainParameters; m_pDomainParameters = NULL; }
if (NULL != called_node_modifier) { delete m_pszRemoteModifier; m_pszRemoteModifier = NULL; } }
DebugExitINT(CConf:ConferenceJoinRequest, rc); return rc; }
/*
* CConf::ForwardConfJoinRequest () * * Public Function Description * This routine is called from the owner object when a conference join * request is received for a conference that is at a node that is not the * Top Provider. This routine forwards the request on up to the Top * Provider. * * Caveats * This routine should never be called if this node is the Top Provider. */ GCCError CConf:: ForwardConfJoinRequest ( CPassword *convener_password, CPassword *password_challange, LPWSTR pwszCallerID, CUserDataListContainer *user_data_list, BOOL numeric_name_present, ConnectionHandle connection_handle ) { GCCError rc;
DebugEntry(CConf::ForwardConfJoinRequest);
/*
** If the node is the top provider we will go ahead and send the ** join indication to the node controller, otherwise we will pass ** the request on up to the top provider. */ if (IsConfTopProvider()) { WARNING_OUT(("CConf::GCCConferenceJoinIndication: not top provider")); rc = GCC_INVALID_CONFERENCE; goto MyExit; }
/*
** The connection handle is used as the tag which is sent in the request ** and returned in the response. Note that it is the user objects ** responsiblity to resolve any type conflicts with the tag. */ if (NULL == m_pMcsUserObject) { ERROR_OUT(("CConf::GCCConferenceJoinIndication: invalid mcs user object")); rc = GCC_INVALID_CONFERENCE; goto MyExit; }
/*
** This list holds information about the conference name alias that ** must be returned in the join response. When the reponse comes ** back from the top provider, the information can be obtained from ** this list. */ m_JoinRespNamePresentConnHdlList2.Append(connection_handle, numeric_name_present ? TRUE_PTR : FALSE_PTR);
// The user object is responsible for encoding this PDU
rc = m_pMcsUserObject->ConferenceJoinRequest(convener_password, password_challange, pwszCallerID, user_data_list, connection_handle); MyExit:
DebugExitINT(CConf::ForwardConfJoinRequest, rc); return rc; }
/*
* CConf::ConfJoinIndResponse() * * Public Function Description * This routine is called from the owner object when a * ConferenceJoinResponse primitive is received from the node controller. * It is also called when a ConferenceJoinResponse is received from the * Top Provider. * * Caveats * If the GCC_DOMAIN_PARAMETERS_UNACCEPTABLE error is returned from this * routine, MCS will automatically reject the connection sending a * result to the other side stating the the Domain Parameters were * unacceptable. */ GCCError CConf:: ConfJoinIndResponse ( ConnectionHandle connection_handle, CPassword *password_challenge, CUserDataListContainer *user_data_list, BOOL numeric_name_present, BOOL convener_is_joining, GCCResult result ) { GCCError rc = GCC_NO_ERROR; MCSError mcs_error; LPBYTE encoded_pdu; UINT encoded_pdu_length; ConnectGCCPDU connect_pdu; Result mcs_result;
DebugEntry(CConf::ConfJoinIndResponse);
// Set up the MCS result for the connect provider response.
mcs_result = (result == GCC_RESULT_SUCCESSFUL) ? RESULT_SUCCESSFUL : RESULT_USER_REJECTED;
// Encode the PDU
connect_pdu.choice = CONNECT_JOIN_RESPONSE_CHOSEN; connect_pdu.u.connect_join_response.bit_mask = CJRS_NODE_ID_PRESENT;
if (result == GCC_RESULT_SUCCESSFUL) { // Check to see if it is necessary to send the conference name alias
if (numeric_name_present && (m_pwszConfTextName != NULL)) { connect_pdu.u.connect_join_response.bit_mask |= CONFERENCE_NAME_ALIAS_PRESENT;
connect_pdu.u.connect_join_response.conference_name_alias.choice = NAME_SELECTOR_TEXT_CHOSEN;
connect_pdu.u.connect_join_response.conference_name_alias.u.name_selector_text.value = m_pwszConfTextName;
connect_pdu.u.connect_join_response.conference_name_alias.u.name_selector_text.length = ::lstrlenW(m_pwszConfTextName); } else if (! numeric_name_present) { connect_pdu.u.connect_join_response.bit_mask |= CONFERENCE_NAME_ALIAS_PRESENT;
connect_pdu.u.connect_join_response.conference_name_alias.choice = NAME_SELECTOR_NUMERIC_CHOSEN;
lstrcpy (connect_pdu.u.connect_join_response.conference_name_alias.u.name_selector_numeric, m_pszConfNumericName); }
// Get the conductor privilege list
if (NULL != m_pConductorPrivilegeList) { rc = m_pConductorPrivilegeList->GetPrivilegeListPDU( &connect_pdu.u.connect_join_response.cjrs_conductor_privs); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinIndResponse: can't get privilege, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_response.bit_mask |= CJRS_CONDUCTOR_PRIVS_PRESENT; } // Get the conducted mode privilege list
if (NULL != m_pConductModePrivilegeList) { rc = m_pConductModePrivilegeList->GetPrivilegeListPDU( &connect_pdu.u.connect_join_response.cjrs_conducted_privs); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinIndResponse: can't get conduct mode privilege, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_response.bit_mask |= CJRS_CONDUCTED_PRIVS_PRESENT; } // Get the non conducted mode privilege list
if (NULL != m_pNonConductModePrivilegeList) { rc = m_pNonConductModePrivilegeList->GetPrivilegeListPDU( &connect_pdu.u.connect_join_response.cjrs_non_conducted_privs); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinIndResponse: can't get non-conduct mode privilege, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_response.bit_mask |= CJRS_NON_CONDUCTED_PRIVS_PRESENT; } // Get the conference description
if (NULL != m_pwszConfDescription) { connect_pdu.u.connect_join_response.cjrs_description.length = ::lstrlenW(m_pwszConfDescription); connect_pdu.u.connect_join_response.cjrs_description.value = m_pwszConfDescription; connect_pdu.u.connect_join_response.bit_mask |= CJRS_DESCRIPTION_PRESENT; } } // Get the password challenge
if (NULL != password_challenge) { rc = password_challenge->GetPasswordChallengeResponsePDU ( &connect_pdu.u.connect_join_response.cjrs_password); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinIndResponse: can't get password challenge response, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_response.bit_mask |= CJRS_PASSWORD_PRESENT; }
// Get the user data list
if (NULL != user_data_list) { rc = user_data_list->GetUserDataPDU(&connect_pdu.u.connect_join_response.cjrs_user_data); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfJoinIndResponse: can't get user data, rc=%d", rc)); goto MyExit; }
connect_pdu.u.connect_join_response.bit_mask |= CJRS_USER_DATA_PRESENT; }
connect_pdu.u.connect_join_response.tag = GetNewUserIDTag ();
/*
** if this is the convener rejoining the conference, we save ** the user id tag so that we can record the convener id when it ** is returned in the user id indication. */ if (convener_is_joining && ((m_eNodeType == TOP_PROVIDER_NODE) || (m_eNodeType == TOP_PROVIDER_AND_CONVENER_NODE))) { m_nConvenerUserIDTagNumber = connect_pdu.u.connect_join_response.tag; }
connect_pdu.u.connect_join_response.cjrs_node_id = m_pMcsUserObject->GetMyNodeID(); connect_pdu.u.connect_join_response.top_node_id = m_pMcsUserObject->GetTopNodeID(); connect_pdu.u.connect_join_response.clear_password_required = (ASN1bool_t)m_fClearPassword; connect_pdu.u.connect_join_response.conference_is_locked = (ASN1bool_t)m_fConfLocked; connect_pdu.u.connect_join_response.conference_is_listed = (ASN1bool_t)m_fConfListed; connect_pdu.u.connect_join_response.conference_is_conductible = (ASN1bool_t)m_fConfConductible; connect_pdu.u.connect_join_response.termination_method = (TerminationMethod)m_eTerminationMethod; connect_pdu.u.connect_join_response.result = ::TranslateGCCResultToJoinResult(result);
if (! g_GCCCoder->Encode((LPVOID) &connect_pdu, CONNECT_GCC_PDU, PACKED_ENCODING_RULES, &encoded_pdu, &encoded_pdu_length)) { ERROR_OUT(("CConf::ConfJoinIndResponse: can't encode")); rc = GCC_ALLOCATION_FAILURE; goto MyExit; }
mcs_error = g_pMCSIntf->ConnectProviderResponse( connection_handle, &m_nConfID, m_pDomainParameters, mcs_result, encoded_pdu, encoded_pdu_length);
g_GCCCoder->FreeEncoded(encoded_pdu);
if ((mcs_error == MCS_NO_ERROR) && (result == GCC_RESULT_SUCCESSFUL)) { /*
** Add the connection handle to our list of ** connection handles. */ ASSERT(0 != connection_handle); m_ConnHandleList.Append(connection_handle);
/*
** Add the user's tag number to the list of outstanding ** user ids along with its associated connection. */ m_ConnHdlTagNumberList2.Append(connect_pdu.u.connect_join_response.tag, connection_handle); } else { WARNING_OUT(("CConf::ConfJoinIndResponse: ConnectProviderResponse failed, mcs_error=%d, result=%d", mcs_error, result)); rc = g_pMCSIntf->TranslateMCSIFErrorToGCCError(mcs_error); goto MyExit; }
// Free up any memory allocated by the conatiners to build the PDU structs
if (connect_pdu.u.connect_join_response.bit_mask & CJRS_CONDUCTOR_PRIVS_PRESENT) { m_pConductorPrivilegeList->FreePrivilegeListPDU( connect_pdu.u.connect_join_response.cjrs_conductor_privs); }
if (connect_pdu.u.connect_join_response.bit_mask & CJRS_CONDUCTED_PRIVS_PRESENT) { m_pConductModePrivilegeList->FreePrivilegeListPDU( connect_pdu.u.connect_join_response.cjrs_conducted_privs); }
if (connect_pdu.u.connect_join_response.bit_mask & CJRS_NON_CONDUCTED_PRIVS_PRESENT) { m_pNonConductModePrivilegeList->FreePrivilegeListPDU( connect_pdu.u.connect_join_response.cjrs_non_conducted_privs); }
ASSERT(GCC_NO_ERROR == rc);
MyExit:
if (GCC_NO_ERROR != rc) { g_pGCCController->FailConfJoinIndResponse(m_nConfID, connection_handle); }
g_pGCCController->RemoveConfJoinInfo(connection_handle);
DebugExitINT(CConf::ConfJoinIndResponse, rc); return rc; }
/*
* CConf::ConfInviteResponse() * * Public Function Description * This routine is called from the owner object when a * ConferenceInviteResponse primitive needs to be processed. */ GCCError CConf:: ConfInviteResponse ( UserID parent_user_id, UserID top_user_id, TagNumber tag_number, ConnectionHandle connection_handle, BOOL fSecure, PDomainParameters domain_parameters, CUserDataListContainer *user_data_list ) { GCCError rc = GCC_ALLOCATION_FAILURE; LPBYTE encoded_pdu; UINT encoded_pdu_length; MCSError mcs_error; ConnectGCCPDU connect_pdu;
DebugEntry(CConf::ConfInviteResponse);
ASSERT(FALSE == m_fSecure); m_fSecure = fSecure;
// First make a copy of the new domain parameters if they exists
if (domain_parameters != NULL) { DBG_SAVE_FILE_LINE m_pDomainParameters = new DomainParameters; if (NULL == m_pDomainParameters) { ERROR_OUT(("CConf::ConfInviteResponse: can't create domain parameters")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; }
// structure-wide shallow copy
*m_pDomainParameters = *domain_parameters; }
m_eNodeType = INVITED_NODE;
m_nParentIDTagNumber = tag_number; m_hParentConnection = connection_handle;
/*
** First we must send the invite response back to the requester. ** If we've gotten this far it will always be a positive response. */
// Create the ConferenceInviteRequest PDU here.
connect_pdu.choice = CONFERENCE_INVITE_RESPONSE_CHOSEN; connect_pdu.u.conference_invite_response.bit_mask = 0;
if (user_data_list != NULL) { rc = user_data_list->GetUserDataPDU( &connect_pdu.u.conference_invite_response.cirs_user_data); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfInviteResponse: can't get user data, rc=%d", rc)); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; }
connect_pdu.u.conference_invite_response.bit_mask |= CIRS_USER_DATA_PRESENT; }
connect_pdu.u.conference_invite_response.result = ::TranslateGCCResultToInviteResult(GCC_RESULT_SUCCESSFUL); if (! g_GCCCoder->Encode((LPVOID) &connect_pdu, CONNECT_GCC_PDU, PACKED_ENCODING_RULES, &encoded_pdu, &encoded_pdu_length)) { ERROR_OUT(("CConf::ConfInviteResponse: can't encode")); rc = GCC_ALLOCATION_FAILURE; goto MyExit; }
/*
** Note that the TransportStrings are casted twice here. It ** must be done this way to satisfy the compiler. Sorry about ** not adhearing to coding standards. */ mcs_error = g_pMCSIntf->ConnectProviderResponse ( connection_handle, &m_nConfID, m_pDomainParameters, RESULT_SUCCESSFUL, encoded_pdu, encoded_pdu_length);
g_GCCCoder->FreeEncoded(encoded_pdu);
if (MCS_NO_ERROR != mcs_error) { WARNING_OUT(("CConf::ConfInviteResponse: ConnectProviderRequest failed: rc=%d", mcs_error)); rc = g_pMCSIntf->TranslateMCSIFErrorToGCCError(mcs_error); goto MyExit; }
/*
** Now create the user attachment object and wait for the ** confirm which occurs after all the proper channels are ** joined. The user object will determine the top provider ID. ** When the user create confirm is received the response PDU ** will be sent out in the Connect Provider Response. */ DBG_SAVE_FILE_LINE m_pMcsUserObject = new MCSUser(this, top_user_id, parent_user_id, &rc); if (NULL == m_pMcsUserObject || GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::ConfInviteResponse: Creation of User Attachment failed, rc=%d", rc)); if (NULL != m_pMcsUserObject) { m_pMcsUserObject->Release(); m_pMcsUserObject = NULL; } else { rc = GCC_ALLOCATION_FAILURE; } goto MyExit; }
rc = GCC_NO_ERROR;
MyExit:
if (GCC_NO_ERROR != rc) { if (NULL != domain_parameters) { delete m_pDomainParameters; m_pDomainParameters = NULL; } }
DebugExitINT(CConf::ConfInviteResponse, rc); return rc; }
/*
* CConf::RegisterAppSap() * * Public Function Description * This routine is called from the owner object whenever an application * SAP becomes a candidate for Enrollment. This will happen whenever * Applications SAPs exists at the same time a conference becomes * established. It will also be called whenever a conference exists * and a new application SAP is created. */ GCCError CConf:: RegisterAppSap ( CAppSap *pAppSap ) { GCCError rc; GCCConferenceName conference_name; GCCNumericString conference_modifier;
DebugEntry(CConf::RegisterAppSap);
if (m_fConfIsEstablished) { /*
** We first check to see if the application is already registered. ** If so, we do not add it to the list of registered applications ** again. */ if (NULL == m_RegisteredAppSapList.Find(pAppSap)) { // Add the application sap pointer to the registered sap list.
pAppSap->AddRef(); m_RegisteredAppSapList.Append(pAppSap);
/*
** Get the conference name and modifier to send back in the ** permission to enroll indication. */ GetConferenceNameAndModifier(&conference_name, &conference_modifier);
// Inform the application that it can now enroll.
pAppSap->PermissionToEnrollIndication(m_nConfID, TRUE); }
rc = GCC_NO_ERROR; } else { ERROR_OUT(("CConf::RegisterAppSap: CConf not established")); rc = GCC_CONFERENCE_NOT_ESTABLISHED; }
DebugExitINT(CConf::RegisterAppSap, rc); return rc; }
/*
* CConf::UnRegisterAppSap () * * Public Function Description * This routine is called from the owner object whenever an application * SAP becomes unavailable due to whatever reason. This routine is * responsible for unenrolling any APEs from any rosters that it might have * used this SAP to enroll with. */ GCCError CConf:: UnRegisterAppSap ( CAppSap *pAppSap ) { GCCError rc = GCC_NO_ERROR; GCCConferenceName conference_name; GCCNumericString conference_modifier;
DebugEntry(CConf::UnRegisterAppSap);
/*
** We first check to see if the application is already registered. ** If so, we do not add it to the list of registered applications ** again. */ if (! m_RegisteredAppSapList.Find(pAppSap)) { TRACE_OUT(("CConf::UnRegisterAppSap: app not registered")); rc = GCC_APPLICATION_NOT_REGISTERED; goto MyExit; }
/*
** Get the conference name and modifier to send back in the ** permission to enroll indication. */ GetConferenceNameAndModifier(&conference_name, &conference_modifier);
// Inform the application that it can no longer enroll.
pAppSap->PermissionToEnrollIndication(m_nConfID, FALSE);
/*
** We unenroll the appropriate APE. Note that we will only send roster updates ** if the conference is established. */ RemoveSAPFromAPEList(pAppSap);
#if 0 // LONCHANC: UnRegisterAppSap should not affect the roster.
// Only UnenrollApp will affect the app roster.
if (m_fConfIsEstablished) { /*
** Here we flush any PDU data or messages that might have gotten ** queued up when this SAP we was being unenrolled. ** An error here is considered FATAL in that the conference ** information base at this node is now corrupted therefore we ** terminate the conference. */ rc = AsynchFlushRosterData(); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::UnRegisterAppSap: can't flush roster data, rc=%d", rc)); //
// Do not need to initiate termination because we are
// either already in termination procedure or
// the application is going away.
//
#if 0
InitiateTermination((rc == GCC_ALLOCATION_FAILURE) ? GCC_REASON_ERROR_LOW_RESOURCES : GCC_REASON_ERROR_TERMINATION, 0); #endif // 0
goto MyExit; } } #endif // 0
// Remove the application sap from list of registered SAPs
if (m_RegisteredAppSapList.Remove(pAppSap)) { //
// Only when this app sap is still in the list, we then can
// release it. It is possible that this app sap has been
// unregistered by the app due to permission-to-enroll-ind
// we just sent earlier.
//
pAppSap->Release(); }
ASSERT(GCC_NO_ERROR == rc);
MyExit:
DebugExitINT(CConf::UnRegisterAppSap, rc); return rc; }
/*
* CConf::AppEnrollRequest() * * Public Function Description * This routine is called from the owner object when an * Application is requesting to enroll with this conference. * * Caveats * Enroll confirms are performed by the application roster manager so * anyplace where the application roster manager isn't informed of the * enroll we must perform the enroll confirm here in this routine. */ GCCError CConf:: AppEnrollRequest ( CAppSap *pAppSap, GCCEnrollRequest *pReq, GCCRequestTag nReqTag ) { GCCError rc = GCC_NO_ERROR; CAppRosterMgr *pAppRosterMgr; CAppRosterMgr *pNewAppRosterMgr = NULL; // a must
EntityID eid, new_eid = GCC_INVALID_EID; // a must
GCCNodeID nid; GCCAppEnrollConfirm aec;
DebugEntry(CConf::AppEnrollRequest);
TRACE_OUT_EX(ZONE_T120_APP_ROSTER, ("CConf::AppEnrollRequest: " "enrolled?=%u\r\n", (UINT) pReq->fEnroll));
// If the conference is not established return an error.
if (! m_fConfIsEstablished) { WARNING_OUT(("CConf::AppEnrollRequest: CConf not established")); rc = GCC_CONFERENCE_NOT_ESTABLISHED; goto MyExit; }
if (! m_RegisteredAppSapList.Find(pAppSap)) { WARNING_OUT(("CConf::AppEnrollRequest: app not registered")); rc = GCC_APPLICATION_NOT_REGISTERED; goto MyExit; }
if (pReq->fEnroll) { m_cEnrollRequests++; } else { m_cEnrollRequests--; }
TRACE_OUT_EX(ZONE_T120_APP_ROSTER, ("CConf::AppEnrollRequest: cEnroll=%d\r\n", m_cEnrollRequests));
if (m_cEnrollRequests < 0) { //
// LONCHANC: It seems to me that the upper layer does unenroll without
// enroll first. it happens when someone calls me.
// We should change this later and have a way to know whether the app
// already enrolled or not.
//
m_cEnrollRequests = 0; }
// get the node id
nid = m_pMcsUserObject->GetMyNodeID();
/*
** Is the application enrolling or unenrolling? Here we set up the ** application roster and APE information if enrolling. */ if (pReq->fEnroll) // Appplication is enrolling
{ TRACE_OUT(("CConf::AppEnrollRequest: Application is Enrolling"));
/*
** First determine if this APE has already enrolled with this ** conference. If it hasn't we must generate a new EntityID for ** this APE. */ rc = GetEntityIDFromAPEList(pAppSap, pReq->pSessionKey, &eid); if (rc == GCC_APP_NOT_ENROLLED) { rc = GenerateEntityIDForAPEList(pAppSap, pReq->pSessionKey, &new_eid); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::AppEnrollRequest: can't generate entity id, rc=%d", rc)); goto MyExit; }
eid = new_eid; m_pAppRegistry->EnrollAPE(eid, pAppSap); }
/*
** This takes care of setting up the application roster manager ** if none exists or it will call the appropriate manager with ** the enroll. */ pAppRosterMgr = GetAppRosterManager(pReq->pSessionKey); if (pAppRosterMgr == NULL) { DBG_SAVE_FILE_LINE pNewAppRosterMgr = new CAppRosterMgr( pReq->pSessionKey, NULL, m_nConfID, m_pMcsUserObject, this, &rc); if (NULL == pNewAppRosterMgr || GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::AppEnrollRequest: can't create app roster mgr, rc=%d", rc)); rc = GCC_ALLOCATION_FAILURE; goto MyExit; }
pAppRosterMgr = pNewAppRosterMgr; }
/*
** Doing the enroll here ensures that an empty roster ** manager will not get put in to the roster manager ** list if the Enroll Fails. */ rc = pAppRosterMgr->EnrollRequest(pReq, eid, nid, pAppSap); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::AppEnrollRequest: EnrollRequest failed, rc=%d", rc)); goto MyExit; }
/*
** If this is a new roster manager we will append it to ** the list of roster managers here if no errors occcured. */ if (pNewAppRosterMgr != NULL) { m_AppRosterMgrList.Append(pNewAppRosterMgr); }
/*
** Here we inform the newly enrolled application of the ** conductor status if the conference is conductible. */ if (m_fConfConductible) { if (m_nConductorNodeID != 0) { pAppSap->ConductorAssignIndication(m_nConductorNodeID, m_nConfID); } else { pAppSap->ConductorReleaseIndication(m_nConfID); } } } else // Appplication is unenrolling
{ TRACE_OUT(("CConf::AppEnrollRequest: Application is UnEnrolling"));
if (pReq->pSessionKey != NULL) { rc = GetEntityIDFromAPEList(pAppSap, pReq->pSessionKey, &eid); if (rc != GCC_NO_ERROR) { WARNING_OUT(("CConf::AppEnrollRequest: app not enrolled")); goto MyExit; }
pAppRosterMgr = GetAppRosterManager(pReq->pSessionKey); if (NULL == pAppRosterMgr) { WARNING_OUT(("CConf::AppEnrollRequest: app not enrolled")); rc = GCC_APP_NOT_ENROLLED; goto MyExit; }
/*
** UnEnroll this APE from the specified session. ** Note that the application roster manager will send ** the enroll confirm. */ pAppRosterMgr->UnEnrollRequest(pReq->pSessionKey, eid);
// UnEnroll this APE from the registry
m_pAppRegistry->UnEnrollAPE(eid);
/*
** Since this APE is no longer enrolled remove it from ** the list of APEs. */ DeleteEnrolledAPE(eid); } else { TRACE_OUT(("CConf::AppEnrollRequest: null session key")); /*
** Since a null session key was passed in we will go ahead ** and unenroll all the APEs associated with this sap. */ RemoveSAPFromAPEList(pAppSap); } }
/*
** Here we take care of sending the enroll confirm to the application ** SAP that enrolled. We also flush any roster PDUs and messages that ** might have been queued up during the enrollment process above. Note ** that we only send a successful enroll confirm if no errors occured. */
ASSERT(GCC_NO_ERROR == rc);
/*
** First we sent the enroll confirm. It is important to send this ** before the flush so that the node ID and entity ID will be ** received by a top provider node before the roster is delivered ** with the applications record in it. This makes it easier on the ** developer when trying to determine if the enrolled record is in ** the roster when the roster report is received. */ aec.nConfID = m_nConfID; aec.sidMyself = pReq->pSessionKey->session_id; aec.eidMyself = eid; aec.nidMyself = nid; aec.nResult = GCC_RESULT_SUCCESSFUL; aec.nReqTag = nReqTag; pAppSap->AppEnrollConfirm(&aec);
/*
** Now we flush all the application roster managers of any PDU data ** that might have been queued up during enrollment. This also ** gives the roster managers a chance to deliver roster update if ** necessary. Note that we build and deliver the high level ** portion of the PDU here. Since only application roster stuff will be ** sent in this pdu we must set the pointer to the conference ** information to NULL so that the encoder wont try to encode it. ** An error here is considered FATAL in that the conference information ** base at this node is now corrupted therefore we terminate the ** conference. Note that we only do the flush here if the start up ** alarm has expired. */ rc = AsynchFlushRosterData(); if (rc != GCC_NO_ERROR) { ERROR_OUT(("CConf::AppEnrollRequest: can't flush roster data, rc=%d", rc));
InitiateTermination((rc == GCC_ALLOCATION_FAILURE) ? GCC_REASON_ERROR_LOW_RESOURCES : GCC_REASON_ERROR_TERMINATION, 0); goto MyExit; }
ASSERT(GCC_NO_ERROR == rc);
MyExit:
if (GCC_NO_ERROR != rc && pReq->fEnroll) { if (NULL != pNewAppRosterMgr) { pNewAppRosterMgr->Release(); }
if (new_eid != GCC_INVALID_EID) { // UnEnroll this APE from the registry
m_pAppRegistry->UnEnrollAPE(new_eid); DeleteEnrolledAPE(new_eid); } }
DebugExitINT(CConf::AppEnrollRequest, rc); return rc; }
/*
* CConf::DisconnectProviderIndication () * * Public Function Description * This routine is called from the owner object when a * Disconnect Provider is received from the MCS interface. * Since the owner object has no way of knowing which connections * are associated with which conferences it may be possible to * receive a disconnect provider for a connection that is not in * the conferences list. */ GCCError CConf:: DisconnectProviderIndication ( ConnectionHandle connection_handle ) { GCCError rc = GCC_NO_ERROR; GCCNodeID nidDisconnected;
DebugEntry(CConf::DisconnectProviderIndication);
TRACE_OUT(("CConf::DisconnectProviderIndication: connection_handle = %d", connection_handle));
// reject any pending join ind response
ConnectionHandle hConn; while (NULL != m_JoinRespNamePresentConnHdlList2.Get(&hConn)) { if (NULL != g_pGCCController) { g_pGCCController->FailConfJoinIndResponse(0, hConn); } }
// First check for the parent connection going down.
if (m_hParentConnection == connection_handle) { TRACE_OUT(("CConf::DisconnectProviderIndication: Connection == PARENT"));
/*
** If the Parent Connection is broken the conference must be ** terminated since this node no longer has access to the top ** gcc provider. */ m_hParentConnection = NULL; InitiateTermination ( GCC_REASON_PARENT_DISCONNECTED, 0); } else { /*
** Now check to see if this connection is associated with an ejected ** node. */ nidDisconnected = m_pMcsUserObject->GetUserIDFromConnection(connection_handle); if (m_EjectedNodeConfirmList.Remove(nidDisconnected)) { #ifdef JASPER
g_pControlSap->ConfEjectUserConfirm(m_nConfID, nidDisconnected, GCC_RESULT_SUCCESSFUL); #endif // JASPER
}
// If this is the convener set its node id back to 0
if (m_nConvenerNodeID == nidDisconnected) m_nConvenerNodeID = 0;
// Inform the User Attachment object that another user disconnected
m_pMcsUserObject->UserDisconnectIndication (nidDisconnected);
ASSERT(0 != connection_handle); if (m_ConnHandleList.Remove(connection_handle)) { TRACE_OUT(("CConf::DisconnectProviderIndication: Connection = CHILD"));
/*
** If there is a disconnect pending we must send the disconnect ** confirm here and terminate the conference. Note that in this ** case, the m_fConfIsEstablished variable was set to FALSE ** when the Disconnect Request was issued (therefore a terminate ** indication will not be sent). */ if (m_ConnHandleList.IsEmpty() && m_fConfDisconnectPending) { TRACE_OUT(("CConf::DisconnectProviderIndication: conf disconnect confirm")); /*
** First inform the control SAP that this node has successfuly ** disconnected. */ g_pControlSap->ConfDisconnectConfirm(m_nConfID, GCC_RESULT_SUCCESSFUL);
// Tell the owner object to terminate this conference
InitiateTermination(GCC_REASON_NORMAL_TERMINATION, m_pMcsUserObject->GetMyNodeID()); } else if (m_ConnHandleList.IsEmpty() && m_fConfTerminatePending) { TRACE_OUT(("CConf::DisconnectProviderIndication: Terminate Request is Completed"));
InitiateTermination(m_eConfTerminateReason, m_pMcsUserObject->GetMyNodeID()); } else if (m_ConnHandleList.IsEmpty() && ((m_eNodeType == TOP_PROVIDER_NODE) || (m_eNodeType == TOP_PROVIDER_AND_CONVENER_NODE)) && (m_eTerminationMethod == GCC_AUTOMATIC_TERMINATION_METHOD)) { /*
** If nothing is left in our connection list and we are the Top ** Provider and automatic termination is enabled then terminate ** the conference. */ TRACE_OUT(("CConf::DisconnectProviderIndication: AUTOMATIC_TERMINATION"));
InitiateTermination( GCC_REASON_NORMAL_TERMINATION, 0); } } else { rc = GCC_INVALID_PARAMETER; } }
DebugExitINT(CConf::DisconnectProviderIndication, rc); return rc; }
/*
* void ConfRosterInquireRequest() * * Public Function Description * This function is used to obtain a conference roster. The conference * roster is delivered to the requesting command target in a Conference * Roster inquire confirm. */ GCCError CConf:: ConfRosterInquireRequest ( CBaseSap *pSap, GCCAppSapMsgEx **ppMsgEx ) { GCCError rc = GCC_NO_ERROR; CConfRoster *conference_roster; LPWSTR pwszConfDescription = NULL; GCCConferenceName conference_name; GCCNumericString conference_modifier;
DebugEntry(CConf::ConfRosterInquireRequest);
if (m_fConfIsEstablished) { /*
** We use the actual conference roster here to build the roster ** inquire confirm message. Note that the SAP should NOT free this ** roster. */ conference_roster = m_pConfRosterMgr->GetConferenceRosterPointer(); if (conference_roster != NULL) { GetConferenceNameAndModifier(&conference_name, &conference_modifier); if (m_pwszConfDescription != NULL) { pwszConfDescription= m_pwszConfDescription; }
pSap->ConfRosterInquireConfirm(m_nConfID, &conference_name, conference_modifier, pwszConfDescription, conference_roster, GCC_RESULT_SUCCESSFUL, ppMsgEx); } else { ERROR_OUT(("CConf::ConfRosterInquireRequest: conf roster does not exist")); rc = GCC_ALLOCATION_FAILURE; } } else { ERROR_OUT(("CConf::ConfRosterInquireRequest: conference not established")); rc = GCC_CONFERENCE_NOT_ESTABLISHED; }
DebugExitINT(CConf:ConfRosterInquireRequest, rc); return rc; }
/*
* CConf::AppRosterInquireRequest() * * Public Function Description * This function is used to obtain a list of application rosters. This * list is delivered to the requesting SAP through an Application Roster * inquire confirm message. */ GCCError CConf:: AppRosterInquireRequest ( PGCCSessionKey session_key, CAppRosterMsg **ppAppRosterMsgOut ) { GCCError rc; BOOL roster_manager_found = FALSE; CAppRosterMsg *roster_message = NULL; CAppRosterMgr *lpAppRosterMgr;
DebugEntry(CConf::AppRosterInquireRequest);
if (m_AppRosterMgrList.IsEmpty()) { WARNING_OUT(("CConf::AppRosterInquireRequest: app roster mgr is empty")); rc = GCC_NO_SUCH_APPLICATION; goto MyExit; }
// First allocate the application roster message
DBG_SAVE_FILE_LINE roster_message = new CAppRosterMsg(); if (NULL == roster_message) { ERROR_OUT(("CConf::AppRosterInquireRequest: can't create app roster msg")); rc = GCC_ALLOCATION_FAILURE; goto MyExit; }
rc = GCC_NO_ERROR;
m_AppRosterMgrList.Reset(); if (session_key != NULL) { while (NULL != (lpAppRosterMgr = m_AppRosterMgrList.Iterate())) { roster_manager_found = lpAppRosterMgr->IsThisYourSessionKey (session_key); if (roster_manager_found) { rc = lpAppRosterMgr->ApplicationRosterInquire(session_key, roster_message); break; } } } else { while (NULL != (lpAppRosterMgr = m_AppRosterMgrList.Iterate())) { rc = lpAppRosterMgr->ApplicationRosterInquire (NULL, roster_message); if (rc != GCC_NO_ERROR) break; } }
MyExit:
if (GCC_NO_ERROR == rc) { *ppAppRosterMsgOut = roster_message; // do not call roster_message->Release() because the sap will call it as needed
} else { if (NULL != roster_message) { roster_message->Release(); } }
DebugExitINT(CConf::AppRosterInquireRequest, rc); return rc; }
/*
* CConf::FlushOutgoingPDU() * * Public Function Description * This is the heartbeat for the conference object. The conference * is responsible for giving the User Attachment object its * heartbeat. * Return value: * TRUE, if there remain un-processed msgs in the CConf message queue * FALSE, if all the msgs in the conference msg queue were processed. */ BOOL CConf:: FlushOutgoingPDU ( void ) { //GCCError error_value;
BOOL fFlushMoreData = FALSE;
if (m_fConfTerminatePending && m_pConfTerminateAlarm != NULL) { if (m_pConfTerminateAlarm->IsExpired()) { delete m_pConfTerminateAlarm; m_pConfTerminateAlarm = NULL; InitiateTermination(m_eConfTerminateReason, m_pMcsUserObject->GetTopNodeID()); } else { fFlushMoreData = TRUE; } }
if (m_pMcsUserObject != NULL) { m_pMcsUserObject->CheckEjectedNodeAlarms(); fFlushMoreData |= m_pMcsUserObject->FlushOutgoingPDU(); }
return fFlushMoreData; }
/*
* BOOL IsConfEstablished () * * Public Function Description * The conference is established when it is ready to be enrolled * with. No application permission to enrolls should be sent until * this routine returns TRUE. */
/*
* BOOL IsConfTopProvider () * * Public Function Description * Function informs whether this node is the Top Provider of the * conference. */
/*
* GCCNodeID GetTopProvider () * * Public Function Description * Function returns the GCCNodeID of the Top Provider of the conference. */
/*
* BOOL DoesConvenerExists () * * Public Function Description * This function informs whether or not the convener is still joined to * this conference. */
/*
* LPSTR GetNumericConfName() * * Public Function Description * Returns a pointer to the numeric portion of the conference name. Used * for comparisons. */
/*
* LPWSTR GetTextConfName() * * Public Function Description * Returns a pointer to the text portion of the conference name. Used for * comparisons. */
/*
* LPSTR GetConfModifier() * * Public Function Description * Returns a pointer to the conference name modifier. */
/*
* LPWSTR GetConfDescription() * * Public Function Description * Returns a pointer to the conference description. */
/*
* CNetAddrListContainer *GetNetworkAddressList() * * Public Function Description * Returns a pointer to the network address list. */
/*
* GCCConfID GetConfID() * * Public Function Description * Returns the conference ID. */
/*
* BOOL IsConfListed() * * Public Function Description * Returns the listed flag. */
/*
* BOOL IsConfPasswordInTheClear() * * Public Function Description * Returns the password protected flag. */
/*
* BOOL IsConfLocked() * * Public Function Description * Returns the locked flag. */
/*
** These routines operate on the m_EnrolledApeEidList2. */
/*
* CConf::GetEntityIDFromAPEList () * * Private Function Description * This routine determines what the entity id is for the specified APE * (note that an APE is defined by its SAP handle and the session key * of the session it is enrolled in). If there is no entity ID associated * with this APE an error is returned. * * Formal Parameters: * hSap - (i) SAP handle associated with the entity ID being * searched for. * session_key - (i) Session key associated with the entity ID being * searched for. * entity_id - (o) The found entity ID is returned here (or zero if * none is found). * * Return Value * GCC_NO_ERROR - No error occured. * GCC_ALLOCATION_FAILURE - A resource error occured allocating session * key data. * GCC_APP_NOT_ENROLLED - Entity ID was not found. * * Side Effects * None. * * Caveats * None. */ GCCError CConf:: GetEntityIDFromAPEList ( CAppSap *pAppSap, PGCCSessionKey session_key, GCCEntityID *pEid ) { GCCError rc = GCC_ALLOCATION_FAILURE; CSessKeyContainer *pSessKey;
*pEid = GCC_INVALID_EID;
DBG_SAVE_FILE_LINE pSessKey = new CSessKeyContainer(session_key, &rc); if (pSessKey != NULL && rc == GCC_NO_ERROR) { GCCEntityID eid; ENROLLED_APE_INFO *lpEnrAPEInfo;
m_EnrolledApeEidList2.Reset(); while (NULL != (lpEnrAPEInfo = m_EnrolledApeEidList2.Iterate(&eid))) { if (pAppSap == lpEnrAPEInfo->pAppSap && *pSessKey == *lpEnrAPEInfo->session_key) { *pEid = eid; break; } }
if (*pEid == GCC_INVALID_EID) { TRACE_OUT(("CConf::GetEntityIDFromAPEList: App NOT Enrolled")); rc = GCC_APP_NOT_ENROLLED; } }
// Free up the temporary session key.
if (NULL != pSessKey) { pSessKey->Release(); }
return rc; }
/*
* CConf::GenerateEntityIDForAPEList () * * Private Function Description * This function is responsible for generating a unqiue entity ID for * the specified APE. * * Formal Parameters: * hSap - (i) SAP handle associated with the entity ID being * generated. * session_key - (i) Session key associated with the entity ID being * generated. * entity_id - (o) The generated entity ID is returned here. * * Return Value * GCC_NO_ERROR - No error occured. * GCC_ALLOCATION_FAILURE - A resource error occured. * * Side Effects * None. * * Caveats * None. */ GCCError CConf:: GenerateEntityIDForAPEList ( CAppSap *pAppSap, PGCCSessionKey session_key, GCCEntityID *pEid ) { GCCError rc = GCC_ALLOCATION_FAILURE; CSessKeyContainer *pSessKey = NULL; // a must
EntityID eidOriginal; ENROLLED_APE_INFO *enrolled_ape_info = NULL; // a must
/*
** First find an entity id that has not been used. If all of the IDs ** are in use we return an allocation failure. */ *pEid = GCC_INVALID_EID; eidOriginal = m_nAPEEntityID; while (TRUE) { if (++m_nAPEEntityID != GCC_INVALID_EID) { if (NULL == m_EnrolledApeEidList2.Find(m_nAPEEntityID)) { // the new entity ID does not exist. job is done.
*pEid = m_nAPEEntityID; break; }
if (m_nAPEEntityID == eidOriginal) { ERROR_OUT(("CConf::GenerateEntityIDForAPEList: use up all entity IDs")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; } } }
ASSERT(GCC_INVALID_EID != *pEid);
/*
** Now if no errors occured we will create the enrolled APE info structure ** that will be stored in the enrolled APE list. */ //
// LONCHANC: We should avoid this memory allocation. ENROLLED_APE_INFO has only 2 dwords!
//
DBG_SAVE_FILE_LINE enrolled_ape_info = new ENROLLED_APE_INFO; if (NULL == enrolled_ape_info) { ERROR_OUT(("CConf::GenerateEntityIDForAPEList: can't create ENROLLED_APE_INFO")); ASSERT(GCC_ALLOCATION_FAILURE == rc); goto MyExit; }
enrolled_ape_info->pAppSap = pAppSap;
DBG_SAVE_FILE_LINE pSessKey = new CSessKeyContainer(session_key, &rc); if (pSessKey != NULL && rc == GCC_NO_ERROR) { enrolled_ape_info->session_key = pSessKey; m_EnrolledApeEidList2.Append(*pEid, enrolled_ape_info); }
MyExit:
if (GCC_NO_ERROR != rc) { delete enrolled_ape_info; if (NULL != pSessKey) { pSessKey->Release(); } }
return rc; }
/*
* CConf::RemoveSAPFromAPEList () * * Private Function Description * This routine takes care of removing all the references to a single * sap from the m_EnrolledApeEidList2. It is also responsible for unenrolling * all of these APEs from the appropriate Application SAPs. * * Formal Parameters: * hSap - (i) SAP handle to remove and unenroll. * * Return Value * None. * * Side Effects * None. * * Caveats * None. */ void CConf:: RemoveSAPFromAPEList ( CAppSap *pAppSap ) { GCCEntityID eid; ENROLLED_APE_INFO *lpEnrAPEInfo;
/*
** We make a temporary copy of the list here so that we can remove ** members from it while we are iterating on it. */ while (NULL != (lpEnrAPEInfo = GetEnrolledAPEbySap(pAppSap, &eid))) { CAppRosterMgr *lpAppRosterMgr; /*
** Here we remove the entities associated with this application ** from any application rosters it is enrolled in. */ m_AppRosterMgrList.Reset(); while (NULL != (lpAppRosterMgr = m_AppRosterMgrList.Iterate())) { TRACE_OUT(("CConf::RemoveSAPFromAPEList: remove entity = %d", (int) eid)); lpAppRosterMgr->RemoveEntityReference(eid); }
/*
** We must remove any references to this SAP from the ** registry so that any outstanding request by this SAP ** will not be processed. */ m_pAppRegistry->UnEnrollAPE(eid);
/*
** Since this APE is no longer enrolled remove it from ** the list of APEs. */ DeleteEnrolledAPE(eid); } }
/*
* CConf::DoesSAPHaveEnrolledAPE () * * Private Function Description * This routine is responsible for determining if there is a single * (or multiple) APEs enrolled through the specified SAP handle. * * Formal Parameters: * sap_handle - (i) SAP handle of SAP being checked. * * Return Value * TRUE - If SAP does have an enrolled APE. * FALSE - If SAP does not have an enrolled APE. * * Side Effects * None. * * Caveats * None. */
ENROLLED_APE_INFO *CConf:: GetEnrolledAPEbySap ( CAppSap *pAppSap, GCCEntityID *pEid ) { ENROLLED_APE_INFO *pEnrAPEInfo; GCCEntityID eid;
m_EnrolledApeEidList2.Reset(); while (NULL != (pEnrAPEInfo = m_EnrolledApeEidList2.Iterate(&eid))) { if (pAppSap == pEnrAPEInfo->pAppSap) { if (NULL != pEid) { *pEid = eid; } return pEnrAPEInfo; } } return NULL; }
void CConf:: DeleteEnrolledAPE ( EntityID nEntityID ) { ENROLLED_APE_INFO *lpEnrAPEInfo;
if (NULL != (lpEnrAPEInfo = m_EnrolledApeEidList2.Remove(nEntityID))) { if (NULL != lpEnrAPEInfo->session_key) { lpEnrAPEInfo->session_key->Release(); } delete lpEnrAPEInfo; } }
/*
* GCCError FlushRosterData() * * Private Function Description * This routine flushes all the application roster managers of any PDU data * that might be queued up. This also gives the roster managers a chance * to deliver roster update if necessary. Note that we build and deliver * the high level portion of the PDU here. Since only application roster * stuff will be sent in this pdu we must set the pointer to the conference * information to NULL so that the encoder wont try to encode it. */ GCCError CConf:: AsynchFlushRosterData ( void ) { if (NULL != g_pControlSap) { AddRef(); ::PostMessage(g_pControlSap->GetHwnd(), CONF_FLUSH_ROSTER_DATA, 0, (LPARAM) this); }
return GCC_NO_ERROR; }
void CConf:: WndMsgHandler ( UINT uMsg ) { if (CONF_FLUSH_ROSTER_DATA == uMsg) { FlushRosterData();
//
// We AddRef while posting the message.
//
Release(); } else { ERROR_OUT(("WndMsgHandler: invalid msg=%u", uMsg)); } }
GCCError CConf:: FlushRosterData ( void ) { GCCError rc = GCC_NO_ERROR;
DebugEntry(CConf::FlushRosterData);
if (m_fConfIsEstablished) { GCCPDU gcc_pdu; CAppRosterMgrList RosterMgrDeleteList; CAppRosterMgr *lpAppRosterMgr;
gcc_pdu.choice = INDICATION_CHOSEN; gcc_pdu.u.indication.choice = ROSTER_UPDATE_INDICATION_CHOSEN; gcc_pdu.u.indication.u.roster_update_indication.refresh_is_full = FALSE; gcc_pdu.u.indication.u.roster_update_indication.application_information= NULL;
// First get any CConf Roster PDU data that exists.
rc = m_pConfRosterMgr->FlushRosterUpdateIndication( &gcc_pdu.u.indication.u.roster_update_indication.node_information); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::FlushRosterData: can't flush conf roster update, rc=%d", rc)); goto MyExit; }
if (IsReadyToSendAppRosterUpdate()) { PSetOfApplicationInformation *ppSetOfAppInfo; PSetOfApplicationInformation pNextSetOfInfo;
// Set up the pointer to the first application information.
ppSetOfAppInfo = &gcc_pdu.u.indication.u.roster_update_indication.application_information;
/*
** Here we iterate through all the application roster managers ** giving each a chance to append their roster updates to the ** roster update PDU and to deliver any necessary roster update ** messages. */ m_AppRosterMgrList.Reset(); while (NULL != (lpAppRosterMgr = m_AppRosterMgrList.Iterate())) { pNextSetOfInfo = lpAppRosterMgr->FlushRosterUpdateIndication(ppSetOfAppInfo, &rc); if (GCC_NO_ERROR != rc) { ERROR_OUT(("CConf::FlushRosterData: can't flush app roster update, rc=%d", rc)); goto MyExit; }
if (NULL != pNextSetOfInfo) { ppSetOfAppInfo = &pNextSetOfInfo->next; }
/*
** Here we add the application roster manager to the list of ** managers to delete. They we be deleted and removed from the ** roster manager list below after the PDU is delivered. */ if (lpAppRosterMgr->IsEmpty()) { m_AppRosterMgrList.Remove(lpAppRosterMgr); RosterMgrDeleteList.Append(lpAppRosterMgr); } } } // if ready-to-send-app-roster-update
else { TRACE_OUT(("CConf::FlushRosterData: not ready to send app roster update")); TRACE_OUT(("cApps=%u, m_cEnrollRequests=%u", m_RegisteredAppSapList.GetCount(), m_cEnrollRequests)); }
/*
** Here, if there are no errors and there is actual application ** information, we go ahead and send out the roster update. */ if (NULL != gcc_pdu.u.indication.u.roster_update_indication. application_information || NODE_NO_CHANGE_CHOSEN != gcc_pdu.u.indication.u.roster_update_indication. node_information.node_record_list.choice) { TRACE_OUT(("CConf::FlushRosterData: sending roster update indication to mcs")); m_pMcsUserObject->RosterUpdateIndication( &gcc_pdu, IsConfTopProvider() ? FALSE : TRUE); }
/*
** Here we cleanup any empty roster managers. Note that we must do this ** after delivering the PDU to avoid deleting a roster manager before ** using data associated with it (data obtained in the flush). */ RosterMgrDeleteList.DeleteList(); } // if m_fConfIsEstablished
ASSERT(GCC_NO_ERROR == rc);
MyExit:
DebugExitINT(CConf::FlushRosterData, rc); return rc; }
#define MIN_REGISTERED_APPS 2
BOOL CConf:: IsReadyToSendAppRosterUpdate ( void ) { if (m_fFirstAppRosterSent) { TRACE_OUT_EX(ZONE_T120_APP_ROSTER, ("CConf::IsReadyToSendAppRosterUpdate: " "YES <first one sent>\r\n")); return TRUE; }
BOOL fRet = TRUE;
if (NULL != m_pConfStartupAlarm && m_pConfStartupAlarm->IsExpired()) { TRACE_OUT_EX(ZONE_T120_APP_ROSTER, ("CConf::IsReadyToSendAppRosterUpdate: " "YES <alarm expired>\r\n")); // fRet = TRUE;
} else { UINT cApps = m_RegisteredAppSapList.GetCount(); if (cApps >= MIN_REGISTERED_APPS && (int) cApps <= m_cEnrollRequests) { TRACE_OUT_EX(ZONE_T120_APP_ROSTER, ("CConf::IsReadyToSendAppRosterUpdate: " "YES <cApp=%u, cEnroll=%d>\r\n", cApps, m_cEnrollRequests)); // fRet = TRUE;
} else { TRACE_OUT_EX(ZONE_T120_APP_ROSTER, ("CConf::IsReadyToSendAppRosterUpdate: " "NO <cApp=%u, cEnroll=%d>\r\n", cApps, m_cEnrollRequests)); fRet = FALSE; } }
if (fRet) { m_fFirstAppRosterSent = TRUE; delete m_pConfStartupAlarm; m_pConfStartupAlarm = NULL; }
return fRet; }
// look for this node ID in the roster's record set.
BOOL CConf:: IsThisNodeParticipant ( GCCNodeID nid ) { return ((NULL != m_pConfRosterMgr) ? m_pConfRosterMgr->IsThisNodeParticipant(nid) : FALSE); }
void CConfList:: DeleteList ( void ) { CConf *pConf; while (NULL != (pConf = Get())) { pConf->Release(); } }
void CConfList2:: DeleteList ( void ) { CConf *pConf; while (NULL != (pConf = Get())) { pConf->Release(); } }
|