/**************************************************************************** * * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/q931man.c_v $ * * INTEL Corporation Prorietary Information * * This listing is supplied under the terms of a license agreement * with INTEL Corporation and may not be copied nor disclosed except * in accordance with the terms of that agreement. * * Copyright (c) 1993-1994 Intel Corporation. * * $Revision: 1.138 $ * $Date: 04 Mar 1997 09:43:22 $ * $Author: MANDREWS $ * * Deliverable: * * Abstract: * * * Notes: * ***************************************************************************/ #include "precomp.h" #include "apierror.h" #include "incommon.h" #include "callcont.h" #include "q931.h" #include "ccmain.h" #include "listman.h" #include "q931man.h" #include "userman.h" #include "callman.h" #include "confman.h" #include "h245man.h" #include "linkapi.h" #include "ccutils.h" extern CALL_CONTROL_STATE CallControlState; extern THREADCOUNT ThreadCount; extern CC_CONFERENCEID InvalidConferenceID; HRESULT InitQ931Manager() { return CC_OK; } HRESULT DeInitQ931Manager() { return CC_OK; } DWORD _GenerateListenCallback( PLISTEN pListen, HQ931CALL hQ931Call, PCSS_CALL_INCOMING pCallIncomingData) { HRESULT status; CC_HLISTEN hListen; CC_LISTEN_CALLBACK_PARAMS ListenCallbackParams; PCALL pCall; CC_HCALL hCall; ASSERT(pListen != NULL); ASSERT(pCallIncomingData != NULL); hListen = pListen->hListen; status = AllocAndLockCall( &hCall, // pointer to call handle CC_INVALID_HANDLE, // conference handle hQ931Call, // Q931 call handle CC_INVALID_HANDLE, // Q931 call handle for third party invitor pCallIncomingData->pCalleeAliasList, pCallIncomingData->pCallerAliasList, NULL, // pPeerExtraAliasNames NULL, // pPeerExtension NULL, // local non-standard data pCallIncomingData->pNonStandardData, // remote non-standard data NULL, // local display value pCallIncomingData->pszDisplay, // remote display value pCallIncomingData->pSourceEndpointType->pVendorInfo,// remote vendor info pCallIncomingData->pLocalAddr, // local address pCallIncomingData->pCallerAddr, // connect address NULL, // destination address pCallIncomingData->pSourceAddr, // source call signal address CALLEE, // call direction pCallIncomingData->bCallerIsMC, 0, // user token; user will specify in AcceptRejectCall INCOMING, // initial call state &pCallIncomingData->CallIdentifier, // H225 CallIdentifier &pCallIncomingData->ConferenceID, // conference ID &pCall); // pointer to call object if (status != CC_OK) { UnlockListen(pListen); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } // Map from Q.931 goals to Call Control goals switch (pCallIncomingData->wGoal) { case CSG_JOIN: ListenCallbackParams.wGoal = CC_GOAL_JOIN; break; case CSG_CREATE: ListenCallbackParams.wGoal = CC_GOAL_CREATE; break; case CSG_INVITE: ListenCallbackParams.wGoal = CC_GOAL_INVITE; break; } ListenCallbackParams.hCall = hCall; ListenCallbackParams.pCallerAliasNames = pCallIncomingData->pCallerAliasList; ListenCallbackParams.pCalleeAliasNames = pCallIncomingData->pCalleeAliasList; ListenCallbackParams.pNonStandardData = pCallIncomingData->pNonStandardData; ListenCallbackParams.pszDisplay = pCallIncomingData->pszDisplay; ListenCallbackParams.pVendorInfo = pCallIncomingData->pSourceEndpointType->pVendorInfo; ListenCallbackParams.ConferenceID = pCallIncomingData->ConferenceID; ListenCallbackParams.pCallerAddr = pCallIncomingData->pCallerAddr; ListenCallbackParams.pCalleeAddr = pCallIncomingData->pLocalAddr; ListenCallbackParams.dwListenToken = pListen->dwListenToken; UnlockCall(pCall); // Invoke the user callback -- the listen object is locked during the callback, // but the associated call object is unlocked (to prevent deadlock if // CC_AcceptCall() or CC_RejectCall() is called during the callback from a // different thread, and the callback thread blocks pending completion of // CC_AcceptCall() or CC_RejectCall()) InvokeUserListenCallback(pListen, CC_OK, &ListenCallbackParams); // Need to validate the listen handle; the associated object may have been // deleted during the user callback by this thread if (ValidateListen(hListen) == CC_OK) UnlockListen(pListen); status = LockCall(hCall, &pCall); if ((status == CC_OK) && (pCall->CallState == INCOMING)) { UnlockCall(pCall); return 0; // cause a ringing condition to occur } else { // call object has been deleted, or exists in a non-incoming state if (status == CC_OK) // call object exists in a non-incoming state; AcceptRejectCall // may have been invoked from the user callback UnlockCall(pCall); // return 1; // don't cause a ringing condition to occur } // // We should never reach this point // ASSERT(0); return 1; } DWORD _Q931CallIncoming( HQ931CALL hQ931Call, CC_HLISTEN hListen, PCSS_CALL_INCOMING pCallIncomingData) { HRESULT status; PLISTEN pListen; PCONFERENCE pConference; PCALL pCall; CC_HCALL hCall; ASSERT(hListen != CC_INVALID_HANDLE); ASSERT(pCallIncomingData != NULL); ASSERT(!EqualConferenceIDs(&pCallIncomingData->ConferenceID, &InvalidConferenceID)); if ((pCallIncomingData->wGoal != CSG_CREATE) && (pCallIncomingData->wGoal != CSG_JOIN) && (pCallIncomingData->wGoal != CSG_INVITE)) { Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } status = LockListen(hListen, &pListen); if (status != CC_OK) { // the listen was presumably cancelled by the user, // but we haven't informed Call Setup yet Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } // Look for wConferenceID in conference list status = LockConferenceID(&pCallIncomingData->ConferenceID, &pConference); if (status == CC_OK) { // We found a matching conference ID if ((pConference->bDeferredDelete) && ((pConference->bAutoAccept == FALSE) || ((pConference->tsMultipointController == TS_TRUE) && (pCallIncomingData->bCallerIsMC == TRUE)))) { UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } else { if (pConference->tsMultipointController == TS_TRUE) { if ((pCallIncomingData->pCalleeDestAddr == NULL) || ((pCallIncomingData->pCalleeDestAddr != NULL) && (EqualAddrs(pCallIncomingData->pLocalAddr, pCallIncomingData->pCalleeDestAddr)))) { switch (pCallIncomingData->wGoal) { case CSG_CREATE: UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; case CSG_JOIN: if ((pConference->bDeferredDelete) && (pConference->bAutoAccept == TRUE)) { // Auto accept status = AllocAndLockCall( &hCall, // pointer to call handle pConference->hConference, // conference handle hQ931Call, // Q931 call handle CC_INVALID_HANDLE, // Q931 call handle for third party invitor pCallIncomingData->pCalleeAliasList, pCallIncomingData->pCallerAliasList, NULL, // pPeerExtraAliasNames NULL, // pPeerExtension NULL, // local non-standard data pCallIncomingData->pNonStandardData, // remote non-standard data NULL, // local display value pCallIncomingData->pszDisplay, // remote display value pCallIncomingData->pSourceEndpointType->pVendorInfo,// remote vendor info pCallIncomingData->pLocalAddr, // local address pCallIncomingData->pCallerAddr, // connect address NULL, // destination address pCallIncomingData->pSourceAddr, // source call signal address CALLEE, // call type pCallIncomingData->bCallerIsMC, 0, // user token; user will specify in AcceptRejectCall INCOMING, // initial call state &pCallIncomingData->CallIdentifier, // h225 CallIdentifier &pCallIncomingData->ConferenceID, // conference ID &pCall); // pointer to call object if (status != CC_OK) { UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } AcceptCall(pCall, pConference); return 1; // Don't send back a RINGING indication } else { UnlockConference(pConference); return _GenerateListenCallback(pListen, hQ931Call, pCallIncomingData); } case CSG_INVITE: UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_IN_CONF, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } // switch (wGoal) } else { // connect addr != destination addr switch (pCallIncomingData->wGoal) { case CSG_CREATE: case CSG_JOIN: UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; case CSG_INVITE: // 3rd party invite if (pCallIncomingData->bCallerIsMC == TRUE) { UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } status = AllocAndLockCall( &hCall, // pointer to call handle pConference->hConference, // conference handle CC_INVALID_HANDLE, // Q931 call handle hQ931Call, // Q931 call handle for third party invitor pCallIncomingData->pCallerAliasList, // local alias names pCallIncomingData->pCalleeAliasList, // remote alias names NULL, // pPeerExtraAliasNames NULL, // pPeerExtension pCallIncomingData->pNonStandardData, // local non-standard data NULL, // remote non-standard data pCallIncomingData->pszDisplay, // local display value NULL, // remote display value NULL, // remote vendor info NULL, // local address pCallIncomingData->pCalleeDestAddr, // connect address pCallIncomingData->pCalleeDestAddr, // destination address pCallIncomingData->pSourceAddr, // source call signal address THIRD_PARTY_INTERMEDIARY, // call type TRUE, // caller (this endpoint) is MC 0, // user token; user will specify in AcceptRejectCall PLACED, // initial call state &pCallIncomingData->CallIdentifier, // h225 CallIdentifier &pCallIncomingData->ConferenceID, // conference ID &pCall); // pointer to call object if (status != CC_OK) { UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } PlaceCall(pCall, pConference); UnlockCall(pCall); UnlockConference(pConference); return 1; // Don't send back a RINGING indication } // switch (wGoal) } } else { // pConference->tsMultipointController != TS_TRUE if ((pCallIncomingData->pCalleeDestAddr == NULL) || ((pCallIncomingData->pCalleeDestAddr != NULL) && (EqualAddrs(pCallIncomingData->pLocalAddr, pCallIncomingData->pCalleeDestAddr)))) { switch (pCallIncomingData->wGoal) { case CSG_CREATE: UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; case CSG_JOIN: case CSG_INVITE: UnlockConference(pConference); return _GenerateListenCallback(pListen, hQ931Call, pCallIncomingData); } // switch (wGoal) } else { // connect addr != destination addr UnlockListen(pListen); UnlockConference(pConference); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } // connect addr != destination addr } // pConference->tsMultipointController != TS_TRUE } // Matching conference ID } else if (status == CC_BAD_PARAM) { // This is OK; it simply means that we did not find a matching conference ID if (((pCallIncomingData->pCalleeDestAddr != NULL) && (EqualAddrs(pCallIncomingData->pLocalAddr, pCallIncomingData->pCalleeDestAddr))) || (pCallIncomingData->pCalleeDestAddr == NULL)) { return _GenerateListenCallback(pListen, hQ931Call, pCallIncomingData); } else { // connect addr != destination addr UnlockListen(pListen); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } } else { // fatal error in LockConference UnlockListen(pListen); Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason &pCallIncomingData->ConferenceID, NULL, // alternate address NULL); // non-standard data return 1; } // We should never reach this point ASSERT(0); return 1; } DWORD _Q931CallRemoteHangup( HQ931CALL hQ931Call, CC_HLISTEN hListen, CC_HCALL hCall) { CC_LISTEN_CALLBACK_PARAMS ListenCallbackParams; PCALL pCall; PLISTEN pListen; if (hCall == CC_INVALID_HANDLE) { // Either we've already informed the user of the hangup, // or the user has not yet accepted or rejected the incoming // call request ASSERT(hListen != CC_INVALID_HANDLE); if (LockQ931Call(hCall, hQ931Call, &pCall) != CC_OK) return 0; hCall = pCall->hCall; if (pCall->hConference != CC_INVALID_HANDLE) { UnlockCall(pCall); // XXX -- need bHangupReason ProcessRemoteHangup(hCall, hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING); return 0; } if (LockListen(hListen, &pListen) != CC_OK) { FreeCall(pCall); return 0; } MarkCallForDeletion(pCall); ListenCallbackParams.hCall = pCall->hCall; ListenCallbackParams.pCallerAliasNames = pCall->pPeerAliasNames; ListenCallbackParams.pCalleeAliasNames = pCall->pLocalAliasNames; ListenCallbackParams.pNonStandardData = pCall->pPeerNonStandardData; ListenCallbackParams.pszDisplay = pCall->pszPeerDisplay; ListenCallbackParams.pVendorInfo = pCall->pPeerVendorInfo; ListenCallbackParams.wGoal = CC_GOAL_CREATE; // igonred in this callback ListenCallbackParams.ConferenceID = pCall->ConferenceID; ListenCallbackParams.pCallerAddr = pCall->pQ931PeerConnectAddr; ListenCallbackParams.pCalleeAddr = pCall->pQ931LocalConnectAddr; ListenCallbackParams.dwListenToken = pListen->dwListenToken; InvokeUserListenCallback(pListen, CC_PEER_CANCEL, &ListenCallbackParams); // Need to validate the listen and call handles; the associated objects may // have been deleted during the user callback by this thread if (ValidateListen(hListen) == CC_OK) UnlockListen(pListen); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); } else // XXX -- need bHangupReason ProcessRemoteHangup(hCall, hQ931Call, CC_REJECT_NORMAL_CALL_CLEARING); return 0; } DWORD _Q931CallRejected( HQ931CALL hQ931Call, CC_HCALL hCall, PCSS_CALL_REJECTED pCallRejectedData) { PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HRESULT status; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams; HQ931CALL hQ931CallInvitor; CC_ENDPOINTTYPE SourceEndpointType; CALLTYPE CallType; CC_CONFERENCEID ConferenceID; CC_ADDR SourceAddr; WORD wNumCalls; WORD wQ931Goal; WORD wQ931CallType; status = LockCall(hCall, &pCall); if (status != CC_OK) return 0; CallType = pCall->CallType; ConferenceID = pCall->ConferenceID; if ((pCall->hQ931Call != hQ931Call) || ((pCall->CallState != PLACED) && (pCall->CallState != RINGING))) { // The peer must be in a bad state; we don't expect to receive this message now UnlockCall(pCall); return 0; } if (CallType == THIRD_PARTY_INTERMEDIARY) { hQ931CallInvitor = pCall->hQ931CallInvitor; FreeCall(pCall); if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, pCallRejectedData->bRejectReason, &ConferenceID, NULL, // alternate address NULL); // non-standard data return 0; } if (pCall->hConference == CC_INVALID_HANDLE) { // Call is not attached to a conference FreeCall(pCall); return 0; } UnlockCall(pCall); status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) return 0; ConnectCallbackParams.pNonStandardData = pCallRejectedData->pNonStandardData; ConnectCallbackParams.pszPeerDisplay = NULL; ConnectCallbackParams.bRejectReason = pCallRejectedData->bRejectReason; ConnectCallbackParams.pTermCapList = NULL; ConnectCallbackParams.pH2250MuxCapability = NULL; ConnectCallbackParams.pTermCapDescriptors = NULL; ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr; if (pCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr; ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo; if (pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_MC) { ConnectCallbackParams.bMultipointConference = TRUE; wQ931Goal = CSG_JOIN; wQ931CallType = CC_CALLTYPE_N_N; } else { // Goal and CallType need to be changed for multipoint support. ConnectCallbackParams.bMultipointConference = FALSE; wQ931Goal = CSG_CREATE; wQ931CallType = CC_CALLTYPE_PT_PT; } ConnectCallbackParams.pConferenceID = &pCallRejectedData->ConferenceID; if (pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_MC) ConnectCallbackParams.pMCAddress = pCallRejectedData->pAlternateAddr; else ConnectCallbackParams.pMCAddress = NULL; ConnectCallbackParams.pAlternateAddress = pCallRejectedData->pAlternateAddr; ConnectCallbackParams.dwUserToken = pCall->dwUserToken; // save a copy of the conference handle; we'll need it to validate // the conference object after returning from the user callback hConference = pConference->hConference; if (((pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_MC) || (pCallRejectedData->bRejectReason == CC_REJECT_CALL_FORWARDED) || (pCallRejectedData->bRejectReason == CC_REJECT_ROUTE_TO_GATEKEEPER)) && (EqualConferenceIDs(&pCallRejectedData->ConferenceID, &pCall->ConferenceID)) && (pCallRejectedData->pAlternateAddr != NULL)) { // XXX - In order to be H.323 compliant here, we need to re-permission this call // through the gatekeeper because: // 1. The rerouted call may be going to another gatekeeper zone. // 2. The alternate address may be NULL, and we may have to resolve the // alternate alias name list through the gatekeeper SourceEndpointType.pVendorInfo = pConference->pVendorInfo; SourceEndpointType.bIsTerminal = TRUE; SourceEndpointType.bIsGateway = FALSE; // Cause our local Q.931 connect address to be placed in the // Q.931 setup-UUIE sourceAddress field SourceAddr.nAddrType = CC_IP_BINARY; SourceAddr.bMulticast = FALSE; SourceAddr.Addr.IP_Binary.dwAddr = 0; SourceAddr.Addr.IP_Binary.wPort = 0; status = Q931PlaceCall(&pCall->hQ931Call, // Q931 call handle pCall->pszLocalDisplay, pCall->pLocalAliasNames, pCall->pPeerAliasNames, pCall->pPeerExtraAliasNames, // pExtraAliasList pCall->pPeerExtension, // pExtensionAliasItem pCall->pLocalNonStandardData,// non-standard data &SourceEndpointType, NULL, // pszCalledPartyNumber pCallRejectedData->pAlternateAddr, // connect address pCall->pQ931DestinationAddr, // destination address NULL, // source address FALSE, // bIsMC &pCall->ConferenceID, // conference ID wQ931Goal, // goal wQ931CallType, // call type hCall, // user token (Q931_CALLBACK)Q931Callback, // callback #ifdef GATEKEEPER pCall->GkiCall.usCRV, // CRV &pCall->CallIdentifier); // H.225 CallIdentifier #else 0, // CRV &pCall->CallIdentifier); // H.225 CallIdentifier #endif GATEKEEPER if (status != CS_OK) { MarkCallForDeletion(pCall); InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, status, &ConnectCallbackParams); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) != CC_OK) return 0; for ( ; ; ) { // Start up an enqueued call, if one exists status = RemoveEnqueuedCallFromConference(pConference, &hCall); if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE)) break; status = LockCall(hCall, &pCall); if (status == CC_OK) { pCall->CallState = PLACED; status = PlaceCall(pCall, pConference); UnlockCall(pCall); if (status == CC_OK) break; } } return 0; } UnlockCall(pCall); UnlockConference(pConference); return 0; } MarkCallForDeletion(pCall); if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) { InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_PEER_REJECT, &ConnectCallbackParams); } if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); // Need to validate conference handle; the associated object may // have been deleted during the user callback in this thread if (ValidateConference(hConference) != CC_OK) return 0; for ( ; ; ) { // Start up an enqueued call, if one exists status = RemoveEnqueuedCallFromConference(pConference, &hCall); if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE)) break; status = LockCall(hCall, &pCall); if (status == CC_OK) { pCall->CallState = PLACED; status = PlaceCall(pCall, pConference); UnlockCall(pCall); if (status == CC_OK) break; } } EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS); if (wNumCalls == 0) { if (pConference->bDeferredDelete) { ASSERT(pConference->LocalEndpointAttached == DETACHED); FreeConference(pConference); } else { if ((pConference->ConferenceMode != MULTIPOINT_MODE) || (pConference->tsMultipointController != TS_TRUE)) ReInitializeConference(pConference); UnlockConference(pConference); } } else { UnlockConference(pConference); } return 0; } DWORD _Q931CallAccepted( HQ931CALL hQ931Call, CC_HCALL hCall, PCSS_CALL_ACCEPTED pCallAcceptedData) { HRESULT status; PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams; BYTE bTerminalType; BOOL bMultipointConference; CALLTYPE CallType; HQ931CALL hQ931CallInvitor; H245_INST_T H245Instance; DWORD dwLinkLayerPhysicalId; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) return 0; CallType = pCall->CallType; hConference = pConference->hConference; hQ931Call = pCall->hQ931Call; hQ931CallInvitor = pCall->hQ931CallInvitor; ASSERT((pCall->hQ931Call == hQ931Call) || (pCall->hQ931CallInvitor == hQ931Call)); if ((pConference->ConferenceMode == POINT_TO_POINT_MODE) || (pConference->ConferenceMode == MULTIPOINT_MODE)) bMultipointConference = TRUE; else bMultipointConference = FALSE; // Initialize ConnectCallbackParams ConnectCallbackParams.pNonStandardData = pCallAcceptedData->pNonStandardData; ConnectCallbackParams.pszPeerDisplay = pCallAcceptedData->pszDisplay; ConnectCallbackParams.bRejectReason = CC_REJECT_UNDEFINED_REASON; // field ignored ConnectCallbackParams.pTermCapList = NULL; ConnectCallbackParams.pH2250MuxCapability = NULL; ConnectCallbackParams.pTermCapDescriptors = NULL; ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr; ConnectCallbackParams.pPeerAddr = pCallAcceptedData->pCalleeAddr; ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo; ConnectCallbackParams.bMultipointConference = bMultipointConference; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pCall->dwUserToken; if (pCallAcceptedData->pCalleeAddr) { // Set pCall->pQ931DestinationAddr to the destination address that we got from Q931. // Note that we may not current have a destination address (if the client didn't // specify one), or we may currently have a destination address in domain name format // which we need to change to binary format if (pCall->pQ931DestinationAddr == NULL) pCall->pQ931DestinationAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pCall->pQ931DestinationAddr != NULL) *pCall->pQ931DestinationAddr = *pCallAcceptedData->pCalleeAddr; } if ((!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) && (!EqualConferenceIDs(&pConference->ConferenceID, &pCallAcceptedData->ConferenceID))) { MarkCallForDeletion(pCall); if (CallType == THIRD_PARTY_INTERMEDIARY) { if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCallAcceptedData->ConferenceID, NULL, // alternate address pCallAcceptedData->pNonStandardData); } else { if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_INTERNAL_ERROR, &ConnectCallbackParams); } if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); return 0; } pConference->ConferenceID = pCallAcceptedData->ConferenceID; pCall->ConferenceID = pCallAcceptedData->ConferenceID; // Copy the newly-supplied peer address into the call object. // This is preferable if the original peer address was in IP dot // or domain name format if (CallType != THIRD_PARTY_INVITOR) { if (pCallAcceptedData->pCalleeAddr != NULL) { if (pCall->pQ931DestinationAddr == NULL) pCall->pQ931DestinationAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pCall->pQ931DestinationAddr != NULL) *pCall->pQ931DestinationAddr = *pCallAcceptedData->pCalleeAddr; } if (pCallAcceptedData->pLocalAddr != NULL) { if (pCall->pQ931LocalConnectAddr == NULL) pCall->pQ931LocalConnectAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pCall->pQ931LocalConnectAddr != NULL) *pCall->pQ931LocalConnectAddr = *pCallAcceptedData->pLocalAddr; } } ASSERT(pCall->pPeerNonStandardData == NULL); CopyNonStandardData(&pCall->pPeerNonStandardData, pCallAcceptedData->pNonStandardData); ASSERT(pCall->pszPeerDisplay == NULL); CopyDisplay(&pCall->pszPeerDisplay, pCallAcceptedData->pszDisplay); ASSERT(pCall->pPeerVendorInfo == NULL); CopyVendorInfo(&pCall->pPeerVendorInfo, pCallAcceptedData->pDestinationEndpointType->pVendorInfo); if (CallType == THIRD_PARTY_INVITOR) { pCall->CallState = CALL_COMPLETE; ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr; MarkCallForDeletion(pCall); InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_OK, &ConnectCallbackParams); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return 0; } pCall->CallState = TERMCAP; status = MakeH245PhysicalID(&pCall->dwH245PhysicalID); if (status != CC_OK) { MarkCallForDeletion(pCall); if (CallType == THIRD_PARTY_INTERMEDIARY) { if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCallAcceptedData->ConferenceID, NULL, // alternate address pCallAcceptedData->pNonStandardData); } else { if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, status, &ConnectCallbackParams); } Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return 0; } //MULTITHREAD //Use a tmp ID so we don't clobber the chosen H245Id. // H245Id=> // <= linkLayerId dwLinkLayerPhysicalId = INVALID_PHYS_ID; SetTerminalType(pConference->tsMultipointController, &bTerminalType); pCall->H245Instance = H245Init(H245_CONF_H323, pCall->dwH245PhysicalID, &dwLinkLayerPhysicalId, hCall, (H245_CONF_IND_CALLBACK_T)H245Callback, bTerminalType); if (pCall->H245Instance == H245_INVALID_ID) { MarkCallForDeletion(pCall); if (CallType == THIRD_PARTY_INTERMEDIARY) { if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCallAcceptedData->ConferenceID, NULL, // alternate address pCallAcceptedData->pNonStandardData); } else { if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_INTERNAL_ERROR, &ConnectCallbackParams); } Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return 0; } H245Instance = pCall->H245Instance; // XXX -- need to define connect callback routine // Send in the Id we got back from H245Init. status = linkLayerConnect(dwLinkLayerPhysicalId, pCallAcceptedData->pH245Addr, NULL); if (status != NOERROR) { MarkCallForDeletion(pCall); if (CallType == THIRD_PARTY_INTERMEDIARY) { if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCallAcceptedData->ConferenceID, NULL, // alternate address pCallAcceptedData->pNonStandardData); } else { if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, status, &ConnectCallbackParams); } H245ShutDown(H245Instance); Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return 0; } pCall->bLinkEstablished = TRUE; status = SendTermCaps(pCall, pConference); if (status != CC_OK) { MarkCallForDeletion(pCall); if (CallType == THIRD_PARTY_INTERMEDIARY) { if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCallAcceptedData->ConferenceID, NULL, // alternate address pCallAcceptedData->pNonStandardData); } else { if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, CC_NO_MEMORY, &ConnectCallbackParams); } H245ShutDown(H245Instance); Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return 0; } pCall->OutgoingTermCapState = AWAITING_ACK; if (pCall->MasterSlaveState == MASTER_SLAVE_NOT_STARTED) { status = H245InitMasterSlave(pCall->H245Instance, pCall->H245Instance); // returned as dwTransId in the callback if (status != H245_ERROR_OK) { MarkCallForDeletion(pCall); if (CallType == THIRD_PARTY_INTERMEDIARY) { if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNDEFINED_REASON, &pCallAcceptedData->ConferenceID, NULL, // alternate address pCallAcceptedData->pNonStandardData); } else { if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, status, &ConnectCallbackParams); } H245ShutDown(H245Instance); Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); return 0; } pCall->MasterSlaveState = MASTER_SLAVE_IN_PROGRESS; } UnlockConference(pConference); UnlockCall(pCall); return 0; } DWORD _Q931CallRinging( HQ931CALL hQ931Call, CC_HCALL hCall) { PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HRESULT status; CC_RINGING_CALLBACK_PARAMS RingingCallbackParams; CC_CONFERENCEID ConferenceID; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) { Q931RejectCall(hQ931Call, // Q931 call handle CC_REJECT_UNDEFINED_REASON, // reject reason NULL, // conference ID NULL, // alternate address NULL); // non-standard data return 0; } ConferenceID = pCall->ConferenceID; if ((pCall->hQ931Call != hQ931Call) || (pCall->CallState != PLACED)) { // The peer must be in a bad state; we don't expect to receive this message now UnlockCall(pCall); return 0; } pCall->CallState = RINGING; if (pCall->CallType == THIRD_PARTY_INTERMEDIARY) { // Send "ringing" indication to pCall->hQ931CallInvitor Q931Ringing(pCall->hQ931CallInvitor, NULL); // pCRV UnlockConference(pConference); UnlockCall(pCall); return 0; } RingingCallbackParams.pNonStandardData = NULL; RingingCallbackParams.dwUserToken = pCall->dwUserToken; // save a copy of the conference handle; we'll need it to validate // the conference object after returning from the user callback hConference = pConference->hConference; InvokeUserConferenceCallback(pConference, CC_RINGING_INDICATION, CC_OK, &RingingCallbackParams); // Need to validate conference and call handles; the associated objects may // have been deleted during the user callback in this thread if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); if (ValidateCall(hCall) == CC_OK) UnlockCall(pCall); return 0; } DWORD _Q931CallFailed( HQ931CALL hQ931Call, CC_HCALL hCall, PCSS_CALL_FAILED pCallFailedData) { PCALL pCall; CC_HCONFERENCE hConference; PCONFERENCE pConference; HQ931CALL hQ931CallInvitor; HRESULT status; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams; CALLTYPE CallType; CC_CONFERENCEID ConferenceID; WORD wNumCalls; status = LockCallAndConference(hCall, &pCall, &pConference); if (status != CC_OK) return 0; CallType = pCall->CallType; ConferenceID = pCall->ConferenceID; if (pCall->hQ931Call != hQ931Call) { UnlockConference(pConference); UnlockCall(pCall); return 0; } if (CallType == THIRD_PARTY_INTERMEDIARY) { hQ931CallInvitor = pCall->hQ931CallInvitor; FreeCall(pCall); UnlockConference(pConference); if (hQ931CallInvitor != CC_INVALID_HANDLE) Q931RejectCall(hQ931CallInvitor, CC_REJECT_UNREACHABLE_DESTINATION, &ConferenceID, NULL, // alternate address NULL); // non-standard data return 0; } ConnectCallbackParams.pNonStandardData = NULL; ConnectCallbackParams.pszPeerDisplay = NULL; ConnectCallbackParams.bRejectReason = CC_REJECT_UNREACHABLE_DESTINATION; ConnectCallbackParams.pTermCapList = NULL; ConnectCallbackParams.pH2250MuxCapability = NULL; ConnectCallbackParams.pTermCapDescriptors = NULL; ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr; if (pCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr; ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo; ConnectCallbackParams.bMultipointConference = FALSE; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = NULL; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pCall->dwUserToken; // save a copy of the conference handle; we'll need it to validate // the conference object after returning from the user callback hConference = pConference->hConference; MarkCallForDeletion(pCall); if ((CallType == CALLER) || (CallType == THIRD_PARTY_INVITOR) || ((CallType == CALLEE) && (pConference->LocalEndpointAttached == NEVER_ATTACHED))) { InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, pCallFailedData->error, &ConnectCallbackParams); } if (ValidateCallMarkedForDeletion(hCall) == CC_OK) FreeCall(pCall); // Need to validate conference handle; the associated object may // have been deleted during the user callback in this thread if (ValidateConference(hConference) != CC_OK) return 0; for ( ; ; ) { // Start up an enqueued call, if one exists status = RemoveEnqueuedCallFromConference(pConference, &hCall); if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE)) break; status = LockCall(hCall, &pCall); if (status == CC_OK) { pCall->CallState = PLACED; status = PlaceCall(pCall, pConference); UnlockCall(pCall); if (status == CC_OK) break; } } EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS); if (wNumCalls == 0) { if (pConference->bDeferredDelete) { ASSERT(pConference->LocalEndpointAttached == DETACHED); FreeConference(pConference); } else { if ((pConference->ConferenceMode != MULTIPOINT_MODE) || (pConference->tsMultipointController != TS_TRUE)) ReInitializeConference(pConference); UnlockConference(pConference); } } else { UnlockConference(pConference); } return 0; } DWORD _Q931CallConnectionClosed( HQ931CALL hQ931Call, CC_HCALL hCall) { return 0; } DWORD Q931Callback( BYTE bEvent, HQ931CALL hQ931Call, DWORD_PTR dwListenToken, DWORD_PTR dwUserToken, void * pEventData) { DWORD dwStatus; EnterCallControl(); if (CallControlState != OPERATIONAL_STATE) DWLeaveCallControl(0); switch (bEvent) { case Q931_CALL_INCOMING: dwStatus = _Q931CallIncoming(hQ931Call, (CC_HLISTEN)dwListenToken, (PCSS_CALL_INCOMING)pEventData); break; case Q931_CALL_REMOTE_HANGUP: dwStatus = _Q931CallRemoteHangup(hQ931Call, (CC_HLISTEN)dwListenToken, (CC_HCALL)dwUserToken); break; case Q931_CALL_REJECTED: dwStatus = _Q931CallRejected(hQ931Call, (CC_HCALL)dwUserToken, (PCSS_CALL_REJECTED)pEventData); break; case Q931_CALL_ACCEPTED: dwStatus = _Q931CallAccepted(hQ931Call, (CC_HCALL)dwUserToken, (PCSS_CALL_ACCEPTED)pEventData); break; case Q931_CALL_RINGING: dwStatus = _Q931CallRinging(hQ931Call, (CC_HCALL)dwUserToken); break; case Q931_CALL_FAILED: dwStatus = _Q931CallFailed(hQ931Call, (CC_HCALL)dwUserToken, (PCSS_CALL_FAILED)pEventData); break; case Q931_CALL_CONNECTION_CLOSED: dwStatus = _Q931CallConnectionClosed(hQ931Call, (CC_HCALL)dwUserToken); break; default: ASSERT(0); dwStatus = 0; break; } DWLeaveCallControl(dwStatus); }