windows-nt/Source/XPSP1/NT/net/tapi/skywalker/h323/tsp/rascall.cpp
2020-09-26 16:20:57 +08:00

832 lines
22 KiB
C++

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
rascall.cpp
Abstract:
The RAS call functionality (ARQ/DRQ/ACF/DCF/IRR/ARJ/DRJ)
Author:
Nikhil Bobde (NikhilB)
Revision History:
--*/
#include "globals.h"
#include "q931obj.h"
#include "line.h"
#include "q931pdu.h"
#include "ras.h"
//!!always called from a lock
BOOL
CH323Call::SendARQ(
IN long seqNumber
)
{
RasMessage rasMessage;
AdmissionRequest * ARQ;
EXPIRE_CONTEXT * pExpireContext;
PH323_ALIASNAMES pAliasList;
PAdmissionRequest_destinationInfo destInfo = NULL;
H323DBG(( DEBUG_LEVEL_TRACE, "SendARQ entered:%p.",this ));
//if not registered with the GK then return failure
if (!RasIsRegistered())
return FALSE;
pExpireContext = new EXPIRE_CONTEXT;
if( pExpireContext == NULL )
{
return FALSE;
}
ZeroMemory( &rasMessage, sizeof RasMessage );
rasMessage.choice = admissionRequest_chosen;
ARQ = &rasMessage.u.admissionRequest;
// get sequence number
if( seqNumber != NOT_RESEND_SEQ_NUM )
{
ARQ -> requestSeqNum = (WORD)seqNumber;
}
else
{
m_wARQSeqNum = RasAllocSequenceNumber();
ARQ -> requestSeqNum = m_wARQSeqNum;
}
ARQ -> callType.choice = pointToPoint_chosen;
// endpointIdentifier
RasGetEndpointID (&ARQ -> endpointIdentifier);
// srcInfo: pass on the registered aliases
pAliasList = RASGetRegisteredAliasList();
ARQ -> srcInfo = (PAdmissionRequest_srcInfo)
SetMsgAddressAlias( pAliasList );
if( ARQ -> srcInfo == NULL )
{
delete pExpireContext;
return FALSE;
}
// destInfo
if( (m_dwOrigin==LINECALLORIGIN_OUTBOUND) && m_pCalleeAliasNames &&
(m_pCalleeAliasNames -> wCount) )
{
ARQ -> destinationInfo = (PAdmissionRequest_destinationInfo)
SetMsgAddressAlias( m_pCalleeAliasNames );
if( ARQ -> destinationInfo != NULL )
{
ARQ -> bit_mask |= AdmissionRequest_destinationInfo_present;
}
}
else if( (m_dwOrigin==LINECALLORIGIN_INBOUND) && m_pCallerAliasNames
&& (m_pCallerAliasNames -> wCount) )
{
ARQ -> destinationInfo = (PAdmissionRequest_destinationInfo)
SetMsgAddressAlias( m_pCallerAliasNames );
//H323DBG(( DEBUG_LEVEL_ERROR, "Caller alias count:%d : %p", m_pCallerAliasNames->wCount, this ));
if( ARQ -> destinationInfo )
{
ARQ -> bit_mask |= AdmissionRequest_destinationInfo_present;
}
}
for( destInfo = ARQ -> destinationInfo; destInfo; destInfo=destInfo->next )
{
H323DBG(( DEBUG_LEVEL_TRACE, "the alias:%s.", destInfo->value.u.e164 ));
}
ARQ -> bandWidth = 0;
ARQ -> callReferenceValue = m_wCallReference;
// no destExtraCallInfo
// no srcCallSignalAddress
// no nonStandardData
// no callServices
CopyConferenceID (&ARQ -> conferenceID, &m_ConferenceID);
ARQ -> activeMC = FALSE;
ARQ -> answerCall = ( m_dwOrigin == LINECALLORIGIN_INBOUND );
ARQ -> canMapAlias = TRUE;
CopyMemory( (PVOID)&ARQ -> callIdentifier.guid.value,
(PVOID)&m_callIdentifier, sizeof(GUID) );
ARQ -> callIdentifier.guid.length = sizeof (GUID);
ARQ -> bit_mask |= AdmissionRequest_callIdentifier_present;
// no srcAlternatives
// no destAlternatives
// no gatekeeperIdentifier
// no tokens
// no cryptoTokens
// no integrityCheckValue
// no transportQOS
ARQ -> willSupplyUUIEs = FALSE;
if( m_hARQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue, m_hARQTimer, NULL );
m_hARQTimer = NULL;
}
pExpireContext -> DriverCallHandle = m_hdCall;
pExpireContext -> seqNumber = ARQ -> requestSeqNum;
if( !CreateTimerQueueTimer(
&m_hARQTimer,
H323TimerQueue,
CH323Call::ARQExpiredCallback,
(PVOID)pExpireContext,
ARQ_EXPIRE_TIME, 0,
WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ))
{
goto cleanup;
}
if( RasEncodeSendMessage (&rasMessage) != S_OK )
{
goto cleanup;
}
if( ARQ -> bit_mask & AdmissionRequest_destinationInfo_present )
{
FreeAddressAliases( (PSetup_UUIE_destinationAddress)
ARQ -> destinationInfo );
}
FreeAddressAliases( (PSetup_UUIE_destinationAddress)ARQ -> srcInfo );
m_dwRASCallState = RASCALL_STATE_ARQSENT;
m_dwARQRetryCount++;
_ASSERTE( m_pARQExpireContext == NULL );
m_pARQExpireContext = pExpireContext;
H323DBG(( DEBUG_LEVEL_TRACE, "SendARQ exited:%p.",this ));
return TRUE;
cleanup:
if( m_hARQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue,
m_hARQTimer, NULL );
m_hARQTimer = NULL;
m_dwARQRetryCount = 0;
}
if( ARQ -> bit_mask & AdmissionRequest_destinationInfo_present )
{
FreeAddressAliases( (PSetup_UUIE_destinationAddress)
ARQ -> destinationInfo );
}
if( pExpireContext != NULL )
{
delete pExpireContext;
}
FreeAddressAliases( (PSetup_UUIE_destinationAddress)ARQ -> srcInfo );
return FALSE;
}
//!!always called from a lock
BOOL
CH323Call::SendDRQ(
IN USHORT usDisengageReason,
IN long seqNumber,
IN BOOL fResendOnExpire
)
{
RasMessage rasMessage;
DisengageRequest * DRQ;
EXPIRE_CONTEXT * pExpireContext;
H323DBG(( DEBUG_LEVEL_TRACE, "SendDRQ entered:%p.",this ));
ZeroMemory( &rasMessage, sizeof(rasMessage) );
rasMessage.choice = disengageRequest_chosen;
DRQ = &rasMessage.u.disengageRequest;
//if not registered with the GK then return failure
if (!RasIsRegistered())
{
return FALSE;
}
if( fResendOnExpire == TRUE )
{
pExpireContext = new EXPIRE_CONTEXT;
if( pExpireContext == NULL )
{
return FALSE;
}
}
// get sequence number
if( seqNumber != NOT_RESEND_SEQ_NUM )
{
DRQ -> requestSeqNum = (WORD)seqNumber;
}
else
{
m_wDRQSeqNum = RasAllocSequenceNumber();
DRQ -> requestSeqNum = m_wDRQSeqNum;
}
DRQ -> callReferenceValue = m_wCallReference;
DRQ -> disengageReason.choice = usDisengageReason;
// endpoint identifier
RasGetEndpointID (&DRQ -> endpointIdentifier);
// conferenceID
CopyConferenceID (&DRQ -> conferenceID, &m_ConferenceID);
// callIdentifier
CopyConferenceID (&DRQ -> callIdentifier.guid, &m_callIdentifier);
DRQ -> bit_mask |= DisengageRequest_callIdentifier_present;
if( RasEncodeSendMessage( &rasMessage ) != S_OK )
{
delete pExpireContext;
return FALSE;
}
if( m_hDRQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue, m_hDRQTimer, NULL );
m_hDRQTimer = NULL;
}
if( fResendOnExpire == TRUE )
{
pExpireContext -> DriverCallHandle = m_hdCall;
pExpireContext -> seqNumber = DRQ -> requestSeqNum;
if( !CreateTimerQueueTimer(
&m_hDRQTimer,
H323TimerQueue,
CH323Call::DRQExpiredCallback,
(PVOID)pExpireContext,
ARQ_EXPIRE_TIME, 0,
WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ))
{
delete pExpireContext;
return FALSE;
}
_ASSERTE( m_pDRQExpireContext == NULL );
m_pDRQExpireContext = pExpireContext;
}
m_dwRASCallState = RASCALL_STATE_DRQSENT;
m_dwDRQRetryCount++;
H323DBG(( DEBUG_LEVEL_TRACE, "SendDRQ exited:%p.",this ));
return TRUE;
}
//!!always called from a lock
void
CH323Call::OnDisengageRequest(
IN DisengageRequest * DRQ
)
{
GUID RequestConferenceID;
H323DBG(( DEBUG_LEVEL_TRACE, "OnDisengageRequest entered:%p.",this ));
if( (m_dwRASCallState == RASCALL_STATE_UNREGISTERED) ||
(m_dwRASCallState == RASCALL_STATE_ARJRECVD) )
{
return;
}
CopyConferenceID (&RequestConferenceID, &DRQ -> conferenceID);
if (!IsEqualGUID (m_ConferenceID, RequestConferenceID))
{
H323DBG ((DEBUG_LEVEL_ERROR, "DisengageRequest conference ID does not match this call, ignoring..."));
return;
}
if (SendDCF (DRQ -> requestSeqNum))
{
m_dwRASCallState = RASCALL_STATE_UNREGISTERED;
CloseCall( 0 );
}
H323DBG(( DEBUG_LEVEL_TRACE, "OnDisengageRequest exited:%p.",this ));
}
//!!always called in a lock
BOOL
CH323Call::SendDCF(
IN WORD seqNumber
)
{
RasMessage rasMessage;
DisengageConfirm * DCF;
H323DBG(( DEBUG_LEVEL_TRACE, "SendDCF entered:%p.",this ));
ZeroMemory( &rasMessage, sizeof(rasMessage) );
rasMessage.choice = disengageConfirm_chosen;
DCF = &rasMessage.u.disengageConfirm;
//if not registered with the GK then return failure
if (!RasIsRegistered())
{
return FALSE;
}
DCF -> requestSeqNum = seqNumber;
if (RasEncodeSendMessage (&rasMessage) != S_OK)
{
return FALSE;
}
H323DBG(( DEBUG_LEVEL_TRACE, "SendDCF exited:%p.",this ));
return TRUE;
}
//!!always called from a lock
void
CH323Call::OnDisengageReject(
IN DisengageReject* DRJ
)
{
H323DBG(( DEBUG_LEVEL_TRACE, "OnDisengageReject entered:%p.",this ));
if( DRJ -> requestSeqNum != m_wDRQSeqNum )
{
return;
}
if( m_dwRASCallState != RASCALL_STATE_DRQSENT )
{
return;
}
if( DRJ->rejectReason.choice == requestToDropOther_chosen )
{
//
H323DBG(( DEBUG_LEVEL_ERROR, "!!something is wrong in the way DRQ is encoded.",this ));
}
else //if( DRJ->rejectReason.choice == DisengageRejectReason_notRegistered_chosen )
{
//the call has been unregistered but is still around, so dsrop it
m_dwRASCallState = RASCALL_STATE_UNREGISTERED;
//CloseCall( 0 );
}
H323DBG(( DEBUG_LEVEL_TRACE, "OnDisengageReject exited:%p.",this ));
}
void
CH323Call::OnRequestInProgress(
IN RequestInProgress* RIP
)
{
H323DBG(( DEBUG_LEVEL_TRACE, "OnRequestInProgress entered:%p.",this ));
EXPIRE_CONTEXT * pExpireContext;
if( RIP -> requestSeqNum != m_wARQSeqNum )
{
return;
}
if( m_dwRASCallState != RASCALL_STATE_ARQSENT )
{
return;
}
//if delay is more than 30 seconds ignore it
if( (RIP->delay > 0) && (RIP->delay > 30000) )
{
return;
}
pExpireContext = new EXPIRE_CONTEXT;
if( pExpireContext == NULL )
{
return;
}
//restart the timer
if( m_hARQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue, m_hARQTimer, NULL );
m_hARQTimer = NULL;
}
pExpireContext -> DriverCallHandle = m_hdCall;
pExpireContext -> seqNumber = m_wARQSeqNum;
if( !CreateTimerQueueTimer(
&m_hARQTimer,
H323TimerQueue,
CH323Call::ARQExpiredCallback,
(PVOID)pExpireContext,
(DWORD)RIP->delay, 0,
WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE ))
{
//close the call
CloseCall( 0 );
}
H323DBG(( DEBUG_LEVEL_TRACE, "OnRequestInProgress exited:%p.",this ));
}
//!!always called from a lock
void
CH323Call::OnDisengageConfirm(
IN DisengageConfirm* DCF
)
{
H323DBG(( DEBUG_LEVEL_TRACE, "OnDisengageConfirm entered:%p.",this ));
if( DCF -> requestSeqNum != m_wDRQSeqNum )
{
return;
}
if( m_dwRASCallState == RASCALL_STATE_DRQSENT )
{
if( m_hDRQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue, m_hDRQTimer,
NULL );
m_hDRQTimer = NULL;
}
//nikhil:if this is a replacement call/diverted call then this may lead
//to inconsistent behaviour
m_dwRASCallState = RASCALL_STATE_UNREGISTERED;
//CloseCall( 0 );
}
H323DBG(( DEBUG_LEVEL_TRACE, "OnDisengageConfirm exited:%p.",this ));
}
//!!always called from a lock
void
CH323Call::OnAdmissionConfirm(
IN AdmissionConfirm * ACF
)
{
PH323_CALL pCall = NULL;
H323DBG(( DEBUG_LEVEL_TRACE, "OnAdmissionConfirm entered:%p.",this ));
_ASSERTE( m_dwRASCallState != RASCALL_STATE_IDLE );
if( ACF -> requestSeqNum != m_wARQSeqNum )
{
return;
}
if( m_hARQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue, m_hARQTimer,
NULL );
m_hARQTimer = NULL;
m_dwARQRetryCount = 0;
}
if( m_dwRASCallState == RASCALL_STATE_ARQSENT )
{
m_dwRASCallState = RASCALL_STATE_REGISTERED;
if( m_dwOrigin == LINECALLORIGIN_OUTBOUND )
{
if( (ACF ->destCallSignalAddress.choice != ipAddress_chosen) ||
(ACF->destCallSignalAddress.u.ipAddress.ip.length != 4) )
{
DropCall( LINEDISCONNECTMODE_BADADDRESS );
return;
}
// save converted address
m_CalleeAddr.nAddrType = H323_IP_BINARY;
m_CalleeAddr.Addr.IP_Binary.dwAddr =
ntohl(*(DWORD*)(ACF->destCallSignalAddress.u.ipAddress.ip.value) );
m_CalleeAddr.Addr.IP_Binary.wPort =
ACF->destCallSignalAddress.u.ipAddress.port;
m_CalleeAddr.bMulticast =
IN_MULTICAST(m_CalleeAddr.Addr.IP_Binary.dwAddr);
//Replaces the first alias in the callee list (the dialableAddress
//passed in TSPI_lineMakecall ). The GK looks at the first alias
//only. Its assumed that only the first alias is mapped by the GK.
if( (ACF -> bit_mask & AdmissionConfirm_destinationInfo_present) &&
ACF->destinationInfo )
{
MapAliasItem( m_pCalleeAliasNames,
&(ACF->destinationInfo->value) );
}
if( !PlaceCall() )
{
DropCall( LINEDISCONNECTMODE_UNREACHABLE );
}
}
else
{
if( (m_dwCallType & CALLTYPE_TRANSFEREDDEST) && m_hdRelatedCall )
{
MSPMessageData* pMSPMessageData = new MSPMessageData;
if( pMSPMessageData == NULL )
{
CloseCall( 0 );
return;
}
pMSPMessageData->hdCall = m_hdRelatedCall;
pMSPMessageData->messageType = SP_MSG_PrepareToAnswer;
pMSPMessageData->pbEncodedBuf = m_prepareToAnswerMsgData.pbBuffer;
pMSPMessageData->wLength = (WORD)m_prepareToAnswerMsgData.dwLength;
pMSPMessageData->hReplacementCall = m_hdCall;
m_prepareToAnswerMsgData.pbBuffer = NULL;
QueueUserWorkItem( SendMSPMessageOnRelatedCall,
pMSPMessageData, WT_EXECUTEDEFAULT );
}
else
{
// signal incoming call
_ASSERTE(!m_htCall);
PostLineEvent (
LINE_NEWCALL,
(DWORD_PTR)m_hdCall,
(DWORD_PTR)&m_htCall, 0);
_ASSERTE( m_htCall );
if( m_htCall == NULL )
{
H323DBG(( DEBUG_LEVEL_ERROR, "tapi call handle NULL!!" ));
CloseCall( 0 );
return;
}
if( IsListEmpty(&m_IncomingU2U) == FALSE )
{
// signal incoming
PostLineEvent (
LINE_CALLINFO,
(DWORD_PTR)LINECALLINFOSTATE_USERUSERINFO,
0, 0);
}
ChangeCallState( LINECALLSTATE_OFFERING, 0 );
// send the new call message to the unspecified MSP
SendMSPMessage( SP_MSG_PrepareToAnswer,
m_prepareToAnswerMsgData.pbBuffer,
m_prepareToAnswerMsgData.dwLength, NULL );
}
if( m_prepareToAnswerMsgData.pbBuffer )
delete m_prepareToAnswerMsgData.pbBuffer;
ZeroMemory( (PVOID)&m_prepareToAnswerMsgData, sizeof(BUFFERDESCR) );
}
}
else if( m_dwRASCallState == RASCALL_STATE_ARQEXPIRED )
{
SendDRQ( forcedDrop_chosen, NOT_RESEND_SEQ_NUM, TRUE );
}
H323DBG(( DEBUG_LEVEL_TRACE, "OnAdmissionConfirm exited:%p.",this ));
}
//!!always called from a lock
void
CH323Call::OnAdmissionReject(
IN AdmissionReject * ARJ
)
{
H323DBG(( DEBUG_LEVEL_TRACE, "OnAdmissionReject entered:%p.",this ));
if( ARJ -> requestSeqNum != m_wARQSeqNum )
{
return;
}
m_dwRASCallState = RASCALL_STATE_ARJRECVD;
//If a forward consult call then enable the forwarding anyway.
if( (m_dwCallType & CALLTYPE_FORWARDCONSULT )&&
(m_dwOrigin == LINECALLORIGIN_OUTBOUND ) )
{
//Success of forwarding
EnableCallForwarding();
}
//drop the call. shutdown the call and rlease the call.
CloseCall( LINEDISCONNECTMODE_BADADDRESS );
H323DBG(( DEBUG_LEVEL_TRACE, "OnAdmissionReject exited:%p.",this ));
}
HRESULT
CH323Call::GetCallInfo (
OUT GUID * ReturnCallID,
OUT GUID * ReturnConferenceID )
{
//verify call state
if( m_dwCallState == LINECALLSTATE_DISCONNECTED )
{
return E_FAIL;
}
*ReturnCallID = m_callIdentifier;
*ReturnConferenceID = m_ConferenceID;
return S_OK;
}
void
NTAPI CH323Call::DRQExpiredCallback(
IN PVOID ContextParameter, // pExpireContext
IN BOOLEAN TimerFired // not used
)
{
EXPIRE_CONTEXT * pExpireContext;
HDRVCALL DriverCall;
PH323_CALL pCall;
_ASSERTE(ContextParameter);
pExpireContext = (EXPIRE_CONTEXT *) ContextParameter;
_ASSERTE( pExpireContext == m_pDRQExpireContext );
__try
{
DriverCall = (HDRVCALL) pExpireContext -> DriverCallHandle;
pCall = g_pH323Line -> FindH323CallAndLock (DriverCall);
if (pCall)
{
pCall -> DRQExpired (pExpireContext -> seqNumber);
delete pExpireContext;
pCall -> Unlock();
}
else
{
H323DBG ((DEBUG_LEVEL_ERROR, "warning: DRQExpiredCallback failed to locate call object"));
}
}
__except( 1 )
{
// The call has already been deleted and hence the pExpireContext
// buffer is also deleted.
return;
}
}
void
NTAPI CH323Call::ARQExpiredCallback(
IN PVOID ContextParameter, // pExpireContext
IN BOOLEAN TimerFired) // not used
{
EXPIRE_CONTEXT * pExpireContext;
HDRVCALL DriverCall;
PH323_CALL pCall;
_ASSERTE(ContextParameter);
pExpireContext = (EXPIRE_CONTEXT *) ContextParameter;
_ASSERTE( pExpireContext == m_pARQExpireContext );
__try
{
DriverCall = (HDRVCALL) pExpireContext -> DriverCallHandle;
pCall = g_pH323Line -> FindH323CallAndLock (DriverCall);
if (pCall)
{
pCall -> ARQExpired (pExpireContext -> seqNumber);
delete pExpireContext;
pCall -> Unlock();
}
else
{
H323DBG ((DEBUG_LEVEL_ERROR, "warning: ARQExpiredCallback failed to locate call object"));
}
}
__except( 1 )
{
// The call has already been deleted and hence the pExpireContext
// buffer is also deleted.
return;
}
}
//!!always called from a lock
void CH323Call::ARQExpired (
IN WORD seqNumber)
{
H323DBG(( DEBUG_LEVEL_TRACE, "ARQExpired entered:%p.",this ));
m_pARQExpireContext = NULL;
if( m_hARQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue, m_hARQTimer, NULL );
m_hARQTimer = NULL;
}
if( m_dwRASCallState == RASCALL_STATE_ARQSENT )
{
if( m_dwARQRetryCount < ARQ_RETRY_MAX )
{
if( !SendARQ( (long)seqNumber ) )
{
// drop call using disconnect mode
DropCall(0);
}
}
else
{
m_dwRASCallState = RASCALL_STATE_ARQEXPIRED;
//Not able to register, shutdown the RAS client object
CloseCall( 0 );
}
}
H323DBG(( DEBUG_LEVEL_TRACE, "ARQExpired exited:%p.",this ));
}
//!!always called from a lock
void
CH323Call::DRQExpired(
IN WORD seqNumber
)
{
H323DBG(( DEBUG_LEVEL_TRACE, "DRQExpired entered:%p.", this ));
m_pDRQExpireContext = NULL;
if( m_hDRQTimer != NULL )
{
DeleteTimerQueueTimer( H323TimerQueue, m_hDRQTimer, NULL );
m_hDRQTimer = NULL;
}
if( m_dwRASCallState == RASCALL_STATE_DRQSENT )
{
if( m_dwDRQRetryCount < DRQ_RETRY_MAX )
{
if( !SendDRQ( forcedDrop_chosen, (long)seqNumber, TRUE ) )
{
// drop call using disconnect mode
DropCall(0);
}
}
else
{
m_dwRASCallState = RASCALL_STATE_DRQEXPIRED;
//Not able to register, shutdown the RAS client object
CloseCall( 0 );
}
}
H323DBG(( DEBUG_LEVEL_TRACE, "DRQExpired exited:%p.",this ));
}