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