336 lines
9.4 KiB
C++
336 lines
9.4 KiB
C++
#include "stdafx.h"
|
|
#include "cbridge.h"
|
|
|
|
// SOURCE_Q931_INFO methods
|
|
|
|
/* virtual */
|
|
SOURCE_Q931_INFO::~SOURCE_Q931_INFO(
|
|
)
|
|
{
|
|
}
|
|
|
|
|
|
// this should never get called, but needs to be supported
|
|
// as the base class implementation is pure virtual
|
|
// virtual
|
|
HRESULT SOURCE_Q931_INFO::AcceptCallback (
|
|
IN DWORD Status,
|
|
IN SOCKET Socket,
|
|
IN SOCKADDR_IN * LocalAddress,
|
|
IN SOCKADDR_IN * RemoteAddress)
|
|
{
|
|
// we should never receive an accept call back for the
|
|
// Q931 source instance
|
|
_ASSERTE(FALSE);
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
// This function is called by the event manager.
|
|
// The caller will free the PDU. This function may modify
|
|
// some of the fields of the PDU.
|
|
|
|
// this is called when an async receive operation completes
|
|
// virtual
|
|
HRESULT SOURCE_Q931_INFO::ReceiveCallback (
|
|
IN Q931_MESSAGE *pQ931Message,
|
|
IN H323_UserInformation *pH323UserInfo
|
|
)
|
|
{
|
|
HRESULT HResult;
|
|
|
|
// we must have valid decoded PDUs
|
|
_ASSERTE(NULL != pQ931Message);
|
|
|
|
// The ASN.1 part is not present in the case of some PDUs
|
|
//_ASSERTE(NULL != pH323UserInfo);
|
|
|
|
// if RELEASE COMPLETE PDU
|
|
if (pH323UserInfo != NULL &&
|
|
releaseComplete_chosen ==
|
|
pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
|
{
|
|
DebugF (_T("Q931: 0x%x caller sent 'Release Complete'.\n"), &GetCallBridge ());
|
|
HResult = HandleReleaseCompletePDU(
|
|
pQ931Message,
|
|
pH323UserInfo
|
|
);
|
|
|
|
return HResult;
|
|
}
|
|
|
|
// check current state and handle the incoming PDU
|
|
switch(m_Q931SourceState)
|
|
{
|
|
case Q931_SOURCE_STATE_CON_ESTD:
|
|
{
|
|
// processes PDUs when in Q931_SOURCE_STATE_CON_ESTD state
|
|
HResult = HandleStateSrcConEstd(
|
|
pQ931Message,
|
|
pH323UserInfo
|
|
);
|
|
}
|
|
break;
|
|
|
|
case Q931_SOURCE_STATE_SETUP_RCVD:
|
|
{
|
|
// Pass on the PDU to the Q931 destination instance which
|
|
// passes it on after due modifications
|
|
HResult = GetDestQ931Info().ProcessSourcePDU(
|
|
pQ931Message,
|
|
pH323UserInfo
|
|
);
|
|
}
|
|
break;
|
|
|
|
case Q931_SOURCE_STATE_INIT:
|
|
case Q931_SOURCE_STATE_REL_COMP_RCVD:
|
|
default:
|
|
{
|
|
// we can't be in Q931_SOURCE_STATE_INIT as we wouldn't have
|
|
// queued an async receive by then
|
|
|
|
// we can't be in Q931_SOURCE_STATE_REL_COMP_RCVD as we not have
|
|
// queued this receive
|
|
|
|
// I.K. 0819999 _ASSERTE(FALSE);
|
|
HResult = E_UNEXPECTED;
|
|
}
|
|
break;
|
|
};
|
|
|
|
// if there is an error
|
|
if (FAILED(HResult))
|
|
{
|
|
goto shutdown;
|
|
}
|
|
|
|
// we must queue an async receive irrespective of whether
|
|
// the PDU was dropped (IPTEL_E_INVALID_PDU == HResult)
|
|
// queue an async receive
|
|
HResult = QueueReceive();
|
|
if (FAILED(HResult))
|
|
{
|
|
goto shutdown;
|
|
}
|
|
|
|
return HResult;
|
|
|
|
shutdown:
|
|
|
|
// initiate shutdown
|
|
GetCallBridge().Terminate ();
|
|
|
|
return HResult;
|
|
}
|
|
|
|
|
|
// handles RELEASE_COMPLETE PDUs
|
|
HRESULT
|
|
SOURCE_Q931_INFO::HandleReleaseCompletePDU(
|
|
IN Q931_MESSAGE *pQ931Message,
|
|
IN H323_UserInformation *pH323UserInfo
|
|
)
|
|
{
|
|
// it must be a release complete PDU
|
|
_ASSERTE(releaseComplete_chosen == \
|
|
pH323UserInfo->h323_uu_pdu.h323_message_body.choice);
|
|
|
|
// we can handle a RELEASE COMPLETE PDU in any state except the following
|
|
_ASSERTE(Q931_SOURCE_STATE_INIT != m_Q931SourceState);
|
|
_ASSERTE(Q931_SOURCE_STATE_REL_COMP_RCVD != m_Q931SourceState);
|
|
|
|
// pass on the pdu to the Q931 source instance
|
|
// ignore return error code, if any
|
|
GetDestQ931Info().ProcessSourcePDU(
|
|
pQ931Message,
|
|
pH323UserInfo
|
|
);
|
|
|
|
// state transition to Q931_SOURCE_STATE_REL_COMP_RCVD
|
|
m_Q931SourceState = Q931_SOURCE_STATE_REL_COMP_RCVD;
|
|
|
|
// initiate shutdown - this cancels the timers, but doesn't close
|
|
// the sockets. the sockets are closed when the send callback is made
|
|
GetCallBridge().TerminateCallOnReleaseComplete();
|
|
|
|
GetSocketInfo ().Clear (TRUE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// processes PDUs when in Q931_SOURCE_STATE_CON_EST state
|
|
HRESULT
|
|
SOURCE_Q931_INFO::HandleStateSrcConEstd(
|
|
IN Q931_MESSAGE *pQ931Message,
|
|
IN H323_UserInformation *pH323UserInfo
|
|
)
|
|
{
|
|
if (!pH323UserInfo) {
|
|
DebugF(_T("SOURCE_Q931_INFO::HandleStateSrcConEstd: no UUIE data! ignoring message.\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// we can only handle a setup PDU in this state
|
|
// all other PDUs are THROWN AWAY (as we don't know
|
|
// whom to pass it to)
|
|
|
|
if (setup_chosen != pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
|
{
|
|
DebugF(
|
|
_T("SOURCE_Q931_INFO::HandleStateSrcConEstd: received a pdu other than Setup before receiving a Setup, pdu cannot be processed\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// save the caller's call reference value now as we may reuse the
|
|
// PDU structure in ProcessSourcePDU
|
|
// The Setup PDU is sent by the originator and so the call reference flag
|
|
// should not be set.
|
|
// -XXX- this should not be an assert!!!! FIX THIS! -- arlied
|
|
_ASSERTE(!(pQ931Message->CallReferenceValue & CALL_REF_FLAG));
|
|
m_CallRefVal = pQ931Message->CallReferenceValue | CALL_REF_FLAG;
|
|
|
|
// pass on the setup pdu to the Q931 destination instance
|
|
HRESULT HResult = GetDestQ931Info().ProcessSourcePDU(
|
|
pQ931Message,
|
|
pH323UserInfo
|
|
);
|
|
|
|
if (FAILED (HResult))
|
|
{
|
|
return HResult;
|
|
}
|
|
|
|
// state transition to Q931_SOURCE_STATE_SETUP_RCVD
|
|
m_Q931SourceState = Q931_SOURCE_STATE_SETUP_RCVD;
|
|
|
|
|
|
// try to create a CALL PROCEEDING PDU
|
|
// if we fail, don't try to recover
|
|
// Q.931 requires that gateways in the call path must identify
|
|
// themselves to the callee
|
|
Q931_MESSAGE CallProcQ931Message;
|
|
H323_UserInformation CallProcH323UserInfo;
|
|
HResult = Q931EncodeCallProceedingMessage(
|
|
m_CallRefVal,
|
|
&CallProcQ931Message,
|
|
&CallProcH323UserInfo
|
|
);
|
|
|
|
// try to send a CALL PROCEEDING PDU to the caller
|
|
// if we fail, don't try to recover
|
|
|
|
HResult = QueueSend(
|
|
&CallProcQ931Message,
|
|
&CallProcH323UserInfo);
|
|
|
|
return HResult;
|
|
}
|
|
|
|
|
|
// TimerValue contains the timer value in seconds, for a timer event
|
|
// to be created when a queued send completes
|
|
HRESULT
|
|
SOURCE_Q931_INFO::ProcessDestPDU(
|
|
IN Q931_MESSAGE *pQ931Message,
|
|
IN H323_UserInformation *pH323UserInfo
|
|
)
|
|
{
|
|
HRESULT HResult = E_FAIL;
|
|
|
|
// handle PDU from the source Q931 instance
|
|
switch(m_Q931SourceState)
|
|
{
|
|
case Q931_SOURCE_STATE_SETUP_RCVD:
|
|
{
|
|
if (connect_chosen ==
|
|
pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
|
{
|
|
DebugF (_T("Q931: 0x%x forwarding 'Connect' to caller.\n"), &GetCallBridge ());
|
|
HResult = ProcessConnectPDU(
|
|
pQ931Message,
|
|
pH323UserInfo
|
|
);
|
|
if (FAILED(HResult))
|
|
{
|
|
DebugF(_T("SOURCE_Q931_INFO::ProcessDestPDU: ProcessConnectPDU failed, returning %x\n"),
|
|
HResult);
|
|
return HResult;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Q931_SOURCE_STATE_INIT:
|
|
case Q931_SOURCE_STATE_CON_ESTD:
|
|
case Q931_SOURCE_STATE_REL_COMP_RCVD:
|
|
default:
|
|
{
|
|
DebugF( _T("SOURCE_Q931_INFO::ProcessDestPDU: bogus state, returning E_UNEXPECTED\n"));
|
|
return E_UNEXPECTED;
|
|
}
|
|
break;
|
|
};
|
|
|
|
// Q931 Header - CallReferenceValue
|
|
// pQ931Message->CallReferenceValue = GetCallRefVal();
|
|
|
|
// queue async send for the PDU
|
|
HResult = QueueSend(pQ931Message, pH323UserInfo);
|
|
if (HResult != S_OK) {
|
|
DebugF( _T("SOURCE_Q931_INFO::ProcessDestPDU: failed to queue sendreturning %x\n"), HResult);
|
|
return HResult;
|
|
}
|
|
|
|
return HResult;
|
|
}
|
|
|
|
|
|
// NOTE: CRV modification is handled in ProcessDestPDU
|
|
HRESULT
|
|
SOURCE_Q931_INFO::ProcessConnectPDU(
|
|
IN Q931_MESSAGE *pQ931Message,
|
|
IN H323_UserInformation *pH323UserInfo
|
|
)
|
|
{
|
|
Connect_UUIE * Connect;
|
|
HRESULT Result;
|
|
SOCKADDR_IN H245ListenAddress;
|
|
|
|
// it must be a CONNECT PDU
|
|
_ASSERTE(connect_chosen == pH323UserInfo->h323_uu_pdu.h323_message_body.choice);
|
|
|
|
Connect = &pH323UserInfo -> h323_uu_pdu.h323_message_body.u.connect;
|
|
|
|
// we must have already checked to see if an h245 transport
|
|
// address was specified by the callee in the dest instance
|
|
_ASSERTE(Connect_UUIE_h245Address_present & Connect -> bit_mask);
|
|
_ASSERTE(ipAddress_chosen & Connect -> h245Address.choice);
|
|
|
|
// queue an overlapped accept, get ready to accept an incoming
|
|
// connection on the local address/port
|
|
|
|
H245ListenAddress.sin_addr.s_addr = htonl (GetCallBridge (). GetSourceInterfaceAddress ());
|
|
H245ListenAddress.sin_port = htons (0);
|
|
|
|
Result = GetSourceH245Info().ListenForCaller (&H245ListenAddress);
|
|
if (FAILED (Result))
|
|
{
|
|
DebugF (_T("H245: 0x%x failed to listen for caller.\n"), &GetCallBridge ());
|
|
|
|
return Result;
|
|
}
|
|
//_ASSERTE(S_FALSE != HResult);
|
|
|
|
// replace the h245 address/port in the connect PDU
|
|
FillTransportAddress (H245ListenAddress, Connect -> h245Address);
|
|
|
|
DebugF (_T("H245: 0x%x listens for H.245 connection from caller on %08X:%04X.\n"),
|
|
&GetCallBridge (),
|
|
SOCKADDR_IN_PRINTF (&H245ListenAddress));
|
|
|
|
return S_OK;
|
|
}
|