1282 lines
43 KiB
C
1282 lines
43 KiB
C
/****************************************************************************
|
||
*
|
||
* $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);
|
||
}
|
||
|