/**************************************************************************** * * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/callcon2.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) 1996 Intel Corporation. * * $Revision: 1.35 $ * $Date: 03 Mar 1997 09:08:16 $ * $Author: MANDREWS $ * * Deliverable: * * Abstract: * * Notes: * ***************************************************************************/ #ifdef GATEKEEPER #include "precomp.h" #include "apierror.h" #include "incommon.h" #include "callcont.h" #include "q931.h" #include "ccmain.h" #include "confman.h" #include "listman.h" #include "q931man.h" #include "h245man.h" #include "callman.h" #include "userman.h" #include "chanman.h" #include "hangman.h" #include "linkapi.h" #include "h245api.h" #include "ccutils.h" #include "callman2.h" #define HResultLeave(x) return x extern CC_CONFERENCEID InvalidConferenceID; // // Complete CC_xxx Operations // HRESULT ListenReject (CC_HLISTEN hListen, HRESULT Reason) { HRESULT status; PLISTEN pListen; CC_LISTEN_CALLBACK_PARAMS ListenCallbackParams; ASSERT(GKIExists()); status = LockListen(hListen, &pListen); if (status == CC_OK) { ListenCallbackParams.hCall = CC_INVALID_HANDLE; ListenCallbackParams.pCallerAliasNames = NULL; ListenCallbackParams.pCalleeAliasNames = NULL; ListenCallbackParams.pNonStandardData = NULL; ListenCallbackParams.pszDisplay = NULL; ListenCallbackParams.pVendorInfo = NULL; ListenCallbackParams.ConferenceID = InvalidConferenceID; ListenCallbackParams.pCallerAddr = NULL; ListenCallbackParams.pCalleeAddr = NULL; ListenCallbackParams.dwListenToken = pListen->dwListenToken; // 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, Reason, &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) { HQ931LISTEN hQ931Listen = pListen->hQ931Listen; UnlockListen(pListen); status = Q931CancelListen(hQ931Listen); if (LockListen(hListen, &pListen) == CC_OK) { FreeListen(pListen); } } } HResultLeave(status); } // ListenReject() HRESULT PlaceCallConfirm (void *pCallVoid, void *pConferenceVoid) { register PCALL pCall = (PCALL) pCallVoid; HRESULT status; ASSERT(GKIExists()); // Free Alias lists if (pCall->GkiCall.pCalleeAliasNames != NULL) { Q931FreeAliasNames(pCall->GkiCall.pCalleeAliasNames); pCall->GkiCall.pCalleeAliasNames = NULL; } if (pCall->GkiCall.pCalleeExtraAliasNames != NULL) { Q931FreeAliasNames(pCall->GkiCall.pCalleeExtraAliasNames); pCall->GkiCall.pCalleeExtraAliasNames = NULL; } if (pCall->pQ931PeerConnectAddr == NULL) { pCall->pQ931PeerConnectAddr = (PCC_ADDR)MemAlloc(sizeof(CC_ADDR)); if (pCall->pQ931PeerConnectAddr == NULL) return PlaceCallReject(pCallVoid, pConferenceVoid, CC_NO_MEMORY); } pCall->pQ931PeerConnectAddr->nAddrType = CC_IP_BINARY; pCall->pQ931PeerConnectAddr->bMulticast = FALSE; pCall->pQ931PeerConnectAddr->Addr.IP_Binary.wPort = pCall->GkiCall.wPort; pCall->pQ931PeerConnectAddr->Addr.IP_Binary.dwAddr = ntohl(pCall->GkiCall.dwIpAddress); status = PlaceCall(pCall, (PCONFERENCE)pConferenceVoid); if (status != CC_OK) PlaceCallReject(pCallVoid, pConferenceVoid, status); return status; } // PlaceCallConfirm() HRESULT PlaceCallReject (void *pCallVoid, void *pConferenceVoid, HRESULT Reason) { register PCALL pCall = (PCALL) pCallVoid; register PCONFERENCE pConference = (PCONFERENCE) pConferenceVoid; CC_HCONFERENCE hConference; HRESULT status = CC_OK; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams = {0}; CC_HCALL hCall; PCALL pCall2; ASSERT(GKIExists()); ASSERT(pCall != NULL); ASSERT(pConference != NULL); // Free Alias lists if (pCall->GkiCall.pCalleeAliasNames != NULL) { Q931FreeAliasNames(pCall->GkiCall.pCalleeAliasNames); pCall->GkiCall.pCalleeAliasNames = NULL; } if (pCall->GkiCall.pCalleeExtraAliasNames != NULL) { Q931FreeAliasNames(pCall->GkiCall.pCalleeExtraAliasNames); pCall->GkiCall.pCalleeExtraAliasNames = NULL; } // Inform Call Control client of failure ConnectCallbackParams.pNonStandardData = pCall->pPeerNonStandardData; ConnectCallbackParams.pszPeerDisplay = pCall->pszPeerDisplay; ConnectCallbackParams.bRejectReason = 0; ConnectCallbackParams.pTermCapList = pCall->pPeerH245TermCapList; ConnectCallbackParams.pH2250MuxCapability = pCall->pPeerH245H2250MuxCapability; ConnectCallbackParams.pTermCapDescriptors = pCall->pPeerH245TermCapDescriptors; ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr; if (pCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr; ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo; if (pConference->ConferenceMode == MULTIPOINT_MODE) ConnectCallbackParams.bMultipointConference = TRUE; else ConnectCallbackParams.bMultipointConference = FALSE; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pCall->dwUserToken; hConference = pConference->hConference; InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, Reason, &ConnectCallbackParams); if (ValidateConference(hConference) == CC_OK) { // Start up an enqueued call, if one exists for ( ; ; ) { status = RemoveEnqueuedCallFromConference(pConference, &hCall); if ((status != CC_OK) || (hCall == CC_INVALID_HANDLE)) break; status = LockCall(hCall, &pCall2); if (status == CC_OK) { pCall2->CallState = PLACED; status = PlaceCall(pCall2, pConference); UnlockCall(pCall2); if (status == CC_OK) break; } } } HResultLeave(status); } // PlaceCallReject() HRESULT AcceptCallConfirm (void *pCallVoid, void *pConferenceVoid) { CC_HCALL hCall = ((PCALL)pCallVoid)->hCall; CC_HCONFERENCE hConference = ((PCONFERENCE)pConferenceVoid)->hConference; HRESULT status; ASSERT(GKIExists()); status = AcceptCall((PCALL)pCallVoid, (PCONFERENCE)pConferenceVoid); LockConference(hConference, (PPCONFERENCE)&pConferenceVoid); LockCall(hCall, (PPCALL)&pCallVoid); if (status != CC_OK && pCallVoid != NULL && pConferenceVoid != NULL) AcceptCallReject(pCallVoid, pConferenceVoid, status); return status; } // AcceptCallConfirm() HRESULT AcceptCallReject (void *pCallVoid, void *pConferenceVoid, HRESULT Reason) { register PCALL pCall = (PCALL) pCallVoid; register PCONFERENCE pConference = (PCONFERENCE) pConferenceVoid; HRESULT status = CC_OK; CC_CONNECT_CALLBACK_PARAMS ConnectCallbackParams = {0}; ASSERT(GKIExists()); status = Q931RejectCall(pCall->hQ931Call, // Q931 call handle CC_REJECT_GATEKEEPER_RESOURCES, &pCall->ConferenceID, // Conference Identifier NULL, // alternate address pCall->pLocalNonStandardData); ConnectCallbackParams.pNonStandardData = pCall->pPeerNonStandardData; ConnectCallbackParams.pszPeerDisplay = pCall->pszPeerDisplay; ConnectCallbackParams.bRejectReason = 0; ConnectCallbackParams.pTermCapList = pCall->pPeerH245TermCapList; ConnectCallbackParams.pH2250MuxCapability = pCall->pPeerH245H2250MuxCapability; ConnectCallbackParams.pTermCapDescriptors = pCall->pPeerH245TermCapDescriptors; ConnectCallbackParams.pLocalAddr = pCall->pQ931LocalConnectAddr; if (pCall->pQ931DestinationAddr == NULL) ConnectCallbackParams.pPeerAddr = pCall->pQ931PeerConnectAddr; else ConnectCallbackParams.pPeerAddr = pCall->pQ931DestinationAddr; if (pConference->ConferenceMode == MULTIPOINT_MODE) ConnectCallbackParams.bMultipointConference = TRUE; else ConnectCallbackParams.bMultipointConference = FALSE; ConnectCallbackParams.pVendorInfo = pCall->pPeerVendorInfo; ConnectCallbackParams.pConferenceID = &pConference->ConferenceID; ConnectCallbackParams.pMCAddress = pConference->pMultipointControllerAddr; ConnectCallbackParams.pAlternateAddress = NULL; ConnectCallbackParams.dwUserToken = pCall->dwUserToken; InvokeUserConferenceCallback(pConference, CC_CONNECT_INDICATION, Reason, &ConnectCallbackParams); HResultLeave(status); } // AcceptCallReject() #if 0 HRESULT CancelCallConfirm (void *pCallVoid, void *pConferenceVoid) { PCALL pCall = (PCALL) pCallVoid; PCONFERENCE pConference = (PCONFERENCE) pConferenceVoid; HRESULT status; H245_INST_T H245Instance; HQ931CALL hQ931Call; CC_HCONFERENCE hConference; HRESULT SaveStatus; CC_HCALL hCall; ASSERT(GKIExists()); H245Instance = pCall->H245Instance; hQ931Call = pCall->hQ931Call; hConference = pCall->hConference; FreeCall(pCall); if (H245Instance != H245_INVALID_ID) SaveStatus = H245ShutDown(H245Instance); else SaveStatus = H245_ERROR_OK; if (SaveStatus == H245_ERROR_OK) { SaveStatus = Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); // Q931Hangup may legitimately return CS_BAD_PARAM, because the Q.931 call object // may have been deleted at this point if (SaveStatus == CS_BAD_PARAM) SaveStatus = CC_OK; } else Q931Hangup(hQ931Call, CC_REJECT_UNDEFINED_REASON); // Start up an enqueued call, if one exists for ( ; ; ) { 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; } } UnlockConference(pConference); if (SaveStatus != CC_OK) status = SaveStatus; HResultLeave(status); } // CancelCallConfirm() HRESULT CancelCallReject (void *pCallVoid, void *pConferenceVoid) { // I don't care what the Gatekeeper says; I'm shutting down the call! return CancelCallConfirm(pCallVoid, pConferenceVoid); } // CancelCallReject() #endif HRESULT OpenChannelConfirm (CC_HCHANNEL hChannel) { HRESULT status; PCHANNEL pChannel; PCONFERENCE pConference; WORD wNumCalls; PCC_HCALL CallList; HRESULT SaveStatus; unsigned i; PCALL pCall; ASSERT(GKIExists()); status = LockChannelAndConference(hChannel, &pChannel, &pConference); if (status == CC_OK) { // Open a logical channel for each established call status = EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ESTABLISHED_CALL); if (status == CC_OK) { SaveStatus = CC_OK; for (i = 0; i < wNumCalls; ++i) { if (LockCall(CallList[i], &pCall) == CC_OK) { status = H245OpenChannel(pCall->H245Instance, // H245 instance pChannel->hChannel, // dwTransId pChannel->wLocalChannelNumber, pChannel->pTxH245TermCap, // TxMode pChannel->pTxMuxTable, // TxMux H245_INVALID_PORT_NUMBER, // TxPort pChannel->pRxH245TermCap, // RxMode pChannel->pRxMuxTable, // RxMux pChannel->pSeparateStack); if (status == H245_ERROR_OK) (pChannel->wNumOutstandingRequests)++; else SaveStatus = status; UnlockCall(pCall); } } if (CallList != NULL) MemFree(CallList); if (pChannel->wNumOutstandingRequests == 0) { // all open channel requests failed FreeChannel(pChannel); } else { UnlockChannel(pChannel); } if (SaveStatus != CC_OK) status = SaveStatus; } else { FreeChannel(pChannel); } UnlockConference(pConference); } HResultLeave(status); } // OpenChannelConfirm() HRESULT OpenChannelReject (CC_HCHANNEL hChannel, HRESULT Reason) { PCHANNEL pChannel; PCONFERENCE pConference; CC_HCONFERENCE hConference; HRESULT status; CC_TX_CHANNEL_OPEN_CALLBACK_PARAMS Params = {0}; ASSERT(GKIExists()); status = LockChannelAndConference(hChannel, &pChannel, &pConference); if (status == CC_OK) { // Inform Call Control client of failure Params.hChannel = hChannel; Params.pPeerRTPAddr = pChannel->pPeerRTPAddr; Params.pPeerRTCPAddr = pChannel->pPeerRTCPAddr; Params.dwRejectReason = 0; Params.dwUserToken = pChannel->dwUserToken; hConference = pConference->hConference; InvokeUserConferenceCallback(pConference, CC_TX_CHANNEL_OPEN_INDICATION, Reason, &Params); if (ValidateChannel(hChannel) == CC_OK) FreeChannel(pChannel); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); } HResultLeave(status); } // OpenChannelReject() HRESULT AcceptChannelConfirm(CC_HCHANNEL hChannel) { HRESULT status; PCHANNEL pChannel; PCONFERENCE pConference; CC_HCONFERENCE hConference; PCALL pCall; unsigned i; H245_MUX_T H245MuxTable; CC_ACCEPT_CHANNEL_CALLBACK_PARAMS Params; ASSERT(GKIExists()); status = LockChannelAndConference(hChannel, &pChannel, &pConference); if (status != CC_OK) HResultLeave(status); status = LockCall(pChannel->hCall, &pCall); if (status != CC_OK) { UnlockChannel(pChannel); UnlockConference(pConference); HResultLeave(status); } if (pChannel->wNumOutstandingRequests != 0) { PCC_ADDR pRTPAddr = pChannel->pLocalRTPAddr; PCC_ADDR pRTCPAddr = pChannel->pLocalRTCPAddr; if ((pChannel->bMultipointChannel) && (pConference->tsMultipointController == TS_TRUE)) { // Supply the RTP and RTCP addresses in the OpenLogicalChannelAck if (pConference->pSessionTable != NULL) { for (i = 0; i < pConference->pSessionTable->wLength; ++i) { if (pConference->pSessionTable->SessionInfoArray[i].bSessionID == pChannel->bSessionID) { pRTPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTPAddr; pRTCPAddr = pConference->pSessionTable->SessionInfoArray[i].pRTCPAddr; break; } } } } H245MuxTable.Kind = H245_H2250ACK; H245MuxTable.u.H2250ACK.nonStandardList = NULL; if (pRTPAddr != NULL) { if (pRTPAddr->bMulticast) H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_MULTICAST; else H245MuxTable.u.H2250ACK.mediaChannel.type = H245_IP_UNICAST; H245MuxTable.u.H2250ACK.mediaChannel.u.ip.tsapIdentifier = pRTPAddr->Addr.IP_Binary.wPort; HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaChannel.u.ip.network, pRTPAddr->Addr.IP_Binary.dwAddr); H245MuxTable.u.H2250ACK.mediaChannelPresent = TRUE; } else H245MuxTable.u.H2250ACK.mediaChannelPresent = FALSE; if (pRTCPAddr != NULL) { if (pRTCPAddr->bMulticast) H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_MULTICAST; else H245MuxTable.u.H2250ACK.mediaControlChannel.type = H245_IP_UNICAST; H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.tsapIdentifier = pRTCPAddr->Addr.IP_Binary.wPort; HostToH245IPNetwork(H245MuxTable.u.H2250ACK.mediaControlChannel.u.ip.network, pRTCPAddr->Addr.IP_Binary.dwAddr); H245MuxTable.u.H2250ACK.mediaControlChannelPresent = TRUE; } else H245MuxTable.u.H2250ACK.mediaControlChannelPresent = FALSE; H245MuxTable.u.H2250ACK.dynamicRTPPayloadTypePresent = FALSE; H245MuxTable.u.H2250ACK.sessionIDPresent = TRUE; H245MuxTable.u.H2250ACK.sessionID = pChannel->bSessionID; status = H245OpenChannelAccept(pCall->H245Instance, 0, // dwTransId pChannel->wRemoteChannelNumber, // Rx channel &H245MuxTable, 0, // Tx channel NULL, // Tx mux H245_INVALID_PORT_NUMBER,// Port pChannel->pSeparateStack); if (status == CC_OK) pChannel->wNumOutstandingRequests = 0; else --(pChannel->wNumOutstandingRequests); } pChannel->tsAccepted = TS_TRUE; Params.hChannel = hChannel; if (status == CC_OK) UnlockChannel(pChannel); else FreeChannel(pChannel); UnlockCall(pCall); hConference = pConference->hConference; InvokeUserConferenceCallback(pConference, CC_ACCEPT_CHANNEL_INDICATION, status, &Params); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); HResultLeave(status); } // AcceptChannelConfirm(void() HRESULT AcceptChannelReject (CC_HCHANNEL hChannel, HRESULT Reason) { HRESULT status; PCHANNEL pChannel; PCONFERENCE pConference; CC_HCONFERENCE hConference; CC_ACCEPT_CHANNEL_CALLBACK_PARAMS Params; ASSERT(GKIExists()); status = LockChannelAndConference(hChannel, &pChannel, &pConference); if (status == CC_OK) { Params.hChannel = hChannel; FreeChannel(pChannel); hConference = pConference->hConference; InvokeUserConferenceCallback(pConference, CC_ACCEPT_CHANNEL_INDICATION, Reason, &Params); if (ValidateConference(hConference) == CC_OK) UnlockConference(pConference); } HResultLeave(status); } // AcceptChannelReject() // // Handle gratuitous messages from Gatekeeper // // Note: pCall assumed locked when called! HRESULT Disengage(void *pCallVoid) { CC_HCALL hCall = ((PCALL)pCallVoid)->hCall; HRESULT status; UnlockCall((PCALL)pCallVoid); status = ProcessRemoteHangup(hCall, CC_INVALID_HANDLE, CC_REJECT_GATEKEEPER_TERMINATED); HResultLeave(status); } // Disengage() // Note: pCall assumed locked when called! HRESULT BandwidthShrunk(void *pCallVoid, void *pConferenceVoid, unsigned uBandwidthAllocated, long lBandwidthChange) { PCALL pCall = (PCALL) pCallVoid; PCONFERENCE pConference = (PCONFERENCE)pConferenceVoid; CC_BANDWIDTH_CALLBACK_PARAMS Params; ASSERT(GKIExists()); Params.hCall = pCall->hCall; Params.dwBandwidthTotal = uBandwidthAllocated; Params.lBandwidthChange = lBandwidthChange; InvokeUserConferenceCallback(pConference, CC_BANDWIDTH_CHANGED_INDICATION, CC_OK, &Params); HResultLeave(CC_OK); } // BandwidthShrunk() #else // GATEKEEPER static char ch; // Kludge around warning C4206: nonstandard extension used : translation unit is empty #endif // GATEKEEPER