windows-nt/Source/XPSP1/NT/enduser/netmeeting/av/callcont/q931man.c
2020-09-26 16:20:57 +08:00

1282 lines
43 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
*
* $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);
}