windows-nt/Source/XPSP1/NT/net/rras/ip/nath323/srcq931.cpp
2020-09-26 16:20:57 +08:00

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;
}