1087 lines
32 KiB
C++
1087 lines
32 KiB
C++
/*++
|
||
|
||
Copyright (c) 1998 - 2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dstq931.cpp
|
||
|
||
Abstract:
|
||
|
||
Methods for processing Q.931 messages to/from destination side
|
||
of a H.323 connection.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "stdafx.h"
|
||
|
||
|
||
DEST_Q931_INFO::~DEST_Q931_INFO (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Constructor for DEST_Q931_INFO class
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
Virtual
|
||
|
||
--*/
|
||
|
||
{
|
||
// release the allocated call reference value
|
||
// 0 is not a valid call ref value
|
||
// Note that the CRV is allocated for both incoming as well as
|
||
// outgoing calls.
|
||
if (m_CallRefVal != 0)
|
||
{
|
||
DeallocCallRefVal(m_CallRefVal);
|
||
}
|
||
}
|
||
|
||
|
||
HRESULT
|
||
DEST_Q931_INFO::AcceptCallback (
|
||
IN DWORD Status,
|
||
IN SOCKET Socket,
|
||
IN SOCKADDR_IN * LocalAddress,
|
||
IN SOCKADDR_IN * RemoteAddress
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Routine invoked when Q.931 connection is asynchronously accepted
|
||
|
||
Arguments:
|
||
Status -- status code of the asynchronous accept operation
|
||
Socket -- handle of the socket on which the accept completed
|
||
LocalAddress - address of the local socket that accepted the connection
|
||
RemoteAddress - address of the remote socket that initiated the connection
|
||
|
||
Return Values:
|
||
Result of processing the accept completion
|
||
|
||
Notes:
|
||
1. Virtual
|
||
2. Currently there are not codepaths that would invoke the
|
||
method. It is only provided because the base class declares
|
||
the function as virtual.
|
||
|
||
--*/
|
||
|
||
{
|
||
DebugF (_T("Q931: AcceptCallback: status %08XH socket %08XH local address %08X:%04X remote address %08X:%04X) called.\n"),
|
||
Status,
|
||
Socket,
|
||
ntohl (LocalAddress -> sin_addr.s_addr),
|
||
ntohs (LocalAddress -> sin_port),
|
||
ntohl (RemoteAddress -> sin_addr.s_addr),
|
||
ntohs (RemoteAddress -> sin_port));
|
||
|
||
// we don't yet have any code that'll result in this method
|
||
// getting called
|
||
_ASSERTE(FALSE);
|
||
// CHECK_TERMINATION;
|
||
|
||
return E_UNEXPECTED;
|
||
}
|
||
|
||
|
||
HRESULT DEST_Q931_INFO::ReceiveCallback (
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Routine invoked when Q.931 receive from the network completes.
|
||
|
||
Arguments:
|
||
pQ931Message -- Q.931 message received from the network
|
||
pH323UserInfo - ASN.1-encoded part of the Q.931 message
|
||
|
||
Return Values:
|
||
Result of processing the received Q.931 message
|
||
|
||
Notes:
|
||
Virtual
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT HResult;
|
||
|
||
// CHECK_TERMINATION;
|
||
|
||
// we must have valid decoded PDUs
|
||
_ASSERTE(NULL != pQ931Message);
|
||
_ASSERTE(NULL != pH323UserInfo);
|
||
|
||
// CODEWORK: Ensure that this message has an ASN part
|
||
// i.e. pH323UserInfo != NULL
|
||
|
||
// if RELEASE COMPLETE PDU
|
||
if (pH323UserInfo != NULL &&
|
||
releaseComplete_chosen ==
|
||
pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
||
{
|
||
|
||
DebugF (_T("Q931: 0x%x callee sent 'Release Complete'.\n"), &GetCallBridge ());
|
||
HResult = HandleReleaseCompletePDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
|
||
return HResult;
|
||
}
|
||
|
||
// handle new PDU from the remote end
|
||
switch(m_Q931DestState)
|
||
{
|
||
case Q931_DEST_STATE_CON_ESTD:
|
||
{
|
||
// processes PDUs when in Q931_DEST_STATE_CON_EST state
|
||
HResult = HandleStateDestConEstd(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
|
||
case Q931_DEST_STATE_CALL_PROC_RCVD:
|
||
{
|
||
// processes PDUs when in Q931_DEST_STATE_CALL_PROC_RCVD state
|
||
HResult = HandleStateDestCallProcRcvd(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
|
||
case Q931_DEST_STATE_ALERTING_RCVD:
|
||
{
|
||
// processes PDUs when in Q931_DEST_STATE_ALERTING_RCVD state
|
||
HResult = HandleStateDestAlertingRcvd(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
|
||
case Q931_DEST_STATE_CONNECT_RCVD:
|
||
{
|
||
// processes PDUs when in Q931_DEST_STATE_CONNECT_RCVD state
|
||
HResult = HandleStateDestConnectRcvd(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
|
||
case Q931_DEST_STATE_INIT:
|
||
case Q931_DEST_STATE_REL_COMP_RCVD:
|
||
default:
|
||
{
|
||
// we cannot be in Q931_DEST_STATE_INIT as we wouldn't have
|
||
// queued an async receive by then
|
||
|
||
// we cannot be in Q931_DEST_STATE_REL_COMP_RCVD as we would
|
||
// not have queue an async receive on transitioning to this state
|
||
|
||
// Commenting out the assert below is fix for #389657
|
||
// _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 previous
|
||
// PDU was dropped
|
||
HResult = QueueReceive();
|
||
if (FAILED(HResult))
|
||
{
|
||
goto shutdown;
|
||
}
|
||
//_ASSERTE(S_FALSE != HResult);
|
||
|
||
return HResult;
|
||
|
||
shutdown:
|
||
|
||
// initiate shutdown
|
||
GetCallBridge().Terminate ();
|
||
|
||
return HResult;
|
||
}
|
||
|
||
|
||
HRESULT
|
||
DEST_Q931_INFO::HandleStateDestConEstd (
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Processes Q.931 PDUs when in Q931_DEST_STATE_CON_ESTD state.
|
||
CALL_PROCEEDING, ALERTING and CONNECT PDUs are handled here.
|
||
Any other PDU is simply passed on to the Q931 source instance
|
||
|
||
Arguments:
|
||
pQ931Message -- Q.931 message received from the network
|
||
pH323UserInfo - ASN.1-encoded part of the Q.931 message
|
||
|
||
Return Values:
|
||
Result of the PDU processing
|
||
|
||
Notes:
|
||
--*/
|
||
{
|
||
HRESULT HResult = E_FAIL;
|
||
|
||
// check PDU type
|
||
switch (pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
||
{
|
||
case callProceeding_chosen : // CALL_PROCEEDING
|
||
|
||
DebugF (_T("Q931: 0x%x callee sent 'Call Proceeding'.\n"), &GetCallBridge ());
|
||
HResult = HandleCallProceedingPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
break;
|
||
|
||
case alerting_chosen : // ALERTING
|
||
|
||
DebugF (_T("Q931: 0x%x callee sent 'Alerting'.\n"), &GetCallBridge ());
|
||
HResult = HandleAlertingPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
break;
|
||
|
||
case connect_chosen : // CONNECT
|
||
|
||
DebugF (_T("Q931: 0x%x callee sent 'Connect'.\n"), &GetCallBridge ());
|
||
HResult = HandleConnectPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
break;
|
||
|
||
default: // everything else
|
||
// pass on the pdu to the Q931 source instance
|
||
DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"),
|
||
&GetCallBridge (),
|
||
pH323UserInfo->h323_uu_pdu.h323_message_body.choice);
|
||
|
||
HResult = GetSourceQ931Info().ProcessDestPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
break;
|
||
};
|
||
|
||
return HResult;
|
||
}
|
||
|
||
|
||
|
||
HRESULT
|
||
DEST_Q931_INFO::HandleCallProceedingPDU (
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Handles CALL PROCEEDING PDU
|
||
|
||
Arguments:
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
|
||
Return Values:
|
||
Result of PDU processing
|
||
|
||
--*/
|
||
{
|
||
HRESULT HResult = E_FAIL;
|
||
|
||
// for fast connect do the following
|
||
// if there is h245 info and no current h245 connection
|
||
// handle it (save it, establish connection etc.)
|
||
// state transition to Q931_DEST_STATE_CONNECT_RCVD
|
||
// else
|
||
// create new timer for ALERTING
|
||
// state transition to Q931_DEST_STATE_CALL_PROC_RCVD
|
||
|
||
HResult = GetSourceQ931Info().ProcessDestPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
|
||
if (FAILED (HResult))
|
||
{
|
||
|
||
return HResult;
|
||
}
|
||
|
||
_ASSERTE(S_OK == HResult);
|
||
|
||
// cancel current timer (there MUST be one)
|
||
// we can only cancel the timer at this point, as we may drop the
|
||
// PDU anytime before this
|
||
//_ASSERTE(NULL != m_TimerHandle);
|
||
TimprocCancelTimer();
|
||
DebugF (_T("Q931: 0x%x cancelled timer.\n"),
|
||
&GetCallBridge ());
|
||
|
||
HResult = CreateTimer(Q931_POST_CALL_PROC_TIMER_VALUE);
|
||
if (FAILED(HResult))
|
||
{
|
||
DebugF (_T("Q931: 0x%x failed to create timer for duration %d milliseconds.('Call Proceeding'). Error - %x.\n"),
|
||
&GetCallBridge (),
|
||
Q931_POST_CALL_PROC_TIMER_VALUE,
|
||
HResult);
|
||
return HResult;
|
||
}
|
||
|
||
DebugF (_T("Q931: 0x%x created timer for duration %d milliseconds.('Call Proceeding').\n"),
|
||
&GetCallBridge (),
|
||
Q931_POST_CALL_PROC_TIMER_VALUE);
|
||
|
||
m_Q931DestState = Q931_DEST_STATE_CALL_PROC_RCVD;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
// handles Alerting PDUs
|
||
HRESULT
|
||
DEST_Q931_INFO::HandleAlertingPDU(
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
{
|
||
HRESULT HResult = E_FAIL;
|
||
|
||
// for fast connect do the following
|
||
// if there is h245 info and no current h245 connection
|
||
// handle it (save it, establish connection etc.)
|
||
// state transition to Q931_DEST_STATE_CONNECT_RCVD
|
||
// else
|
||
// create new timer for CONNECT
|
||
// state transition to Q931_DEST_STATE_ALERTING_RCVD
|
||
|
||
HResult = GetSourceQ931Info().ProcessDestPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
if (FAILED(HResult))
|
||
{
|
||
return HResult;
|
||
}
|
||
|
||
_ASSERTE(S_OK == HResult);
|
||
|
||
// cancel current timer (there MUST be one)
|
||
// we can only cancel the timer at this point, as we may drop the
|
||
// PDU anytime before this
|
||
//_ASSERTE(NULL != m_TimerHandle);
|
||
TimprocCancelTimer();
|
||
DebugF (_T("Q931: 0x%x cancelled timer.\n"),
|
||
&GetCallBridge ());
|
||
|
||
HResult = CreateTimer(Q931_POST_ALERTING_TIMER_VALUE);
|
||
if (FAILED(HResult))
|
||
{
|
||
DebugF (_T("Q931: 0x%x failed to create timer for duration %d milliseconds('Alerting'). Error - %x.\n"),
|
||
&GetCallBridge (),
|
||
Q931_POST_ALERTING_TIMER_VALUE,
|
||
HResult);
|
||
return HResult;
|
||
}
|
||
|
||
DebugF (_T("Q931: 0x%x created timer for duration %d milliseconds ('Alerting').\n"),
|
||
&GetCallBridge (),
|
||
Q931_POST_ALERTING_TIMER_VALUE);
|
||
|
||
m_Q931DestState = Q931_DEST_STATE_ALERTING_RCVD;
|
||
|
||
return HResult;
|
||
}
|
||
|
||
|
||
// handles CONNECT PDUs
|
||
HRESULT
|
||
DEST_Q931_INFO::HandleConnectPDU(
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
{
|
||
Connect_UUIE * Connect;
|
||
HRESULT HResult = E_FAIL;
|
||
SOCKADDR_IN H245CalleeAddress;
|
||
|
||
// it has to 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 cannot have an earlier h245 connection
|
||
_ASSERTE(m_pH323State->GetH245Info().GetSocketInfo().Socket == INVALID_SOCKET);
|
||
|
||
// if the pdu doesn't have h245 info or a non-ip address is sent
|
||
if (!(Connect_UUIE_h245Address_present & Connect -> bit_mask) ||
|
||
!(ipAddress_chosen == Connect -> h245Address.choice)) {
|
||
|
||
// TO DO ** send back a release complete
|
||
// go to shutdown mode
|
||
|
||
DebugF (_T("Q931: 0x%x addressing information missing or bogus, rejecting 'Connect' PDU.\n"), &GetCallBridge());
|
||
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
// convert the destination H.245 transport address to address (dword),
|
||
// port (word)
|
||
|
||
HResult = GetTransportInfo(
|
||
pH323UserInfo->h323_uu_pdu.h323_message_body.u.connect.h245Address,
|
||
H245CalleeAddress);
|
||
|
||
if (HResult != S_OK)
|
||
{
|
||
return HResult;
|
||
}
|
||
|
||
// Pass it on to the source Q931 instance
|
||
HResult = GetSourceQ931Info().ProcessDestPDU (pQ931Message, pH323UserInfo);
|
||
if (HResult != S_OK) {
|
||
return HResult;
|
||
}
|
||
|
||
// save the destination's H.245 address/port
|
||
// when the source responds by connecting to our sent address/port,
|
||
// we'll connect to the destination's sent address/port
|
||
GetDestH245Info().SetCalleeInfo (&H245CalleeAddress);
|
||
|
||
DebugF (_T("H245: 0x%x will make H.245 connection to %08X:%04X.\n"),
|
||
&GetCallBridge (),
|
||
SOCKADDR_IN_PRINTF (&H245CalleeAddress));
|
||
|
||
// cancel current timer (there MUST be one)
|
||
// we can only cancel the timer at this point, as we may drop the
|
||
// PDU anytime before this
|
||
//_ASSERTE(NULL != m_TimerHandle);
|
||
TimprocCancelTimer();
|
||
DebugF (_T("Q931: 0x%x cancelled timer.\n"),
|
||
&GetCallBridge ());
|
||
|
||
// state transition to Q931_DEST_STATE_CONNECT_RCVD
|
||
m_Q931DestState = Q931_DEST_STATE_CONNECT_RCVD;
|
||
|
||
return HResult;
|
||
}
|
||
|
||
|
||
// handles RELEASE_COMPLETE PDUs
|
||
HRESULT
|
||
DEST_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_DEST_STATE_INIT != m_Q931DestState);
|
||
_ASSERTE(Q931_DEST_STATE_REL_COMP_RCVD != m_Q931DestState);
|
||
|
||
// cancel current timer if any
|
||
|
||
// pass on the pdu to the Q931 source instance
|
||
// ignore return error code, if any
|
||
GetSourceQ931Info().ProcessDestPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
|
||
// state transition to Q931_DEST_STATE_REL_COMP_RCVD
|
||
m_Q931DestState = Q931_DEST_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_DEST_STATE_CALL_PROC_RCVD state
|
||
HRESULT
|
||
DEST_Q931_INFO::HandleStateDestCallProcRcvd(
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
{
|
||
// we can handle ALERTING and CONNECT
|
||
// PDUs here. Any other PDU is simply passed on to the
|
||
// Q931 source instance
|
||
|
||
HRESULT HResult;
|
||
switch (pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
||
{
|
||
case alerting_chosen : // ALERTING
|
||
{
|
||
DebugF (_T("Q931: 0x%x callee sent 'Alerting'.\n"), &GetCallBridge ());
|
||
HResult = HandleAlertingPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
|
||
case connect_chosen : // CONNECT
|
||
{
|
||
DebugF (_T("Q931: 0x%x callee sent 'Connect'.\n"), &GetCallBridge ());
|
||
HResult = HandleConnectPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
{
|
||
DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"),
|
||
&GetCallBridge (),
|
||
pH323UserInfo->h323_uu_pdu.h323_message_body.choice);
|
||
// pass on the pdu to the Q931 source instance
|
||
HResult = GetSourceQ931Info().ProcessDestPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
};
|
||
|
||
return HResult;
|
||
}
|
||
|
||
// processes PDUs when in Q931_DEST_STATE_ALERTING_RCVD state
|
||
HRESULT
|
||
DEST_Q931_INFO::HandleStateDestAlertingRcvd(
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
{
|
||
// we can handle CONNECT and RELEASE_COMPLETE
|
||
// PDUs here. Any other PDU is simply passed on to the
|
||
// Q931 source instance
|
||
|
||
HRESULT HResult = E_FAIL;
|
||
switch (pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
||
{
|
||
case connect_chosen : // CONNECT
|
||
{
|
||
DebugF (_T("Q931: 0x%x callee sent 'Connect'.\n"), &GetCallBridge ());
|
||
HResult = HandleConnectPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
{
|
||
// pass on the pdu to the Q931 source instance
|
||
DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"),
|
||
&GetCallBridge (),
|
||
pH323UserInfo->h323_uu_pdu.h323_message_body.choice);
|
||
|
||
HResult = GetSourceQ931Info().ProcessDestPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
}
|
||
break;
|
||
};
|
||
|
||
return HResult;
|
||
}
|
||
|
||
// processes PDUs when in Q931_DEST_STATE_CONNECT_RCVD state
|
||
HRESULT
|
||
DEST_Q931_INFO::HandleStateDestConnectRcvd(
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
{
|
||
// all PDUs are simply passed on to the Q931 source instance
|
||
|
||
HRESULT HResult = E_FAIL;
|
||
|
||
DebugF (_T("Q931: 0x%x callee sent PDU (type %d). Forwarding without processing.\n"),
|
||
&GetCallBridge (),
|
||
pH323UserInfo->h323_uu_pdu.h323_message_body.choice);
|
||
|
||
// pass on the pdu to the Q931 source instance
|
||
HResult = GetSourceQ931Info().ProcessDestPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
|
||
return HResult;
|
||
}
|
||
|
||
HRESULT
|
||
DEST_Q931_INFO::ProcessSourcePDU(
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
{
|
||
// handle PDU from the source Q931 instance
|
||
switch(m_Q931DestState)
|
||
{
|
||
case Q931_DEST_STATE_INIT:
|
||
{
|
||
HRESULT HResult = E_FAIL;
|
||
// we can only handle the SETUP PDU in this state
|
||
// establishes Q931 connection, forwards the SETUP PDU and
|
||
// queues the first async receive on the new socket
|
||
DebugF (_T("Q931: 0x%x caller sent 'Setup'.\n"), &GetCallBridge ());
|
||
|
||
HResult = ProcessSourceSetupPDU(
|
||
pQ931Message,
|
||
pH323UserInfo
|
||
);
|
||
|
||
return HResult;
|
||
}
|
||
|
||
case Q931_DEST_STATE_CON_ESTD:
|
||
case Q931_DEST_STATE_CALL_PROC_RCVD:
|
||
case Q931_DEST_STATE_ALERTING_RCVD:
|
||
case Q931_DEST_STATE_CONNECT_RCVD:
|
||
{
|
||
// pass on the PDU after modifications
|
||
DebugF (_T("Q931: 0x%x caller sent PDU (type %d). Forwarding without processing.\n"),
|
||
&GetCallBridge (),
|
||
pH323UserInfo->h323_uu_pdu.h323_message_body.choice);
|
||
|
||
}
|
||
break;
|
||
|
||
case Q931_DEST_STATE_REL_COMP_RCVD:
|
||
default:
|
||
{
|
||
return E_UNEXPECTED;
|
||
}
|
||
break;
|
||
};
|
||
|
||
// we come here only if we fall through the switch statement
|
||
|
||
// Q931 Header - change CallReferenceValue
|
||
// pQ931Message->CallReferenceValue = GetCallRefVal();
|
||
|
||
// queue async send for the PDU
|
||
HRESULT HResult = E_FAIL;
|
||
HResult = QueueSend(pQ931Message, pH323UserInfo);
|
||
if (FAILED(HResult))
|
||
{
|
||
return HResult;
|
||
}
|
||
|
||
return HResult;
|
||
}
|
||
|
||
HRESULT
|
||
DEST_Q931_INFO::ProcessSourceSetupPDU(
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
{
|
||
Setup_UUIE * Setup;
|
||
HRESULT Result;
|
||
ULONG Error;
|
||
SOCKADDR_IN DestinationAddress = {0};
|
||
DWORD TranslatedDestinationAddress = 0;
|
||
AliasAddress * Alias;
|
||
ANSI_STRING AnsiAlias;
|
||
|
||
ASN1uint32_t OldFastStartBit = 0U;
|
||
ASN1uint32_t OldH245TunnelingBit = 0U;
|
||
ASN1bool_t OldH245TunnelingFlag = FALSE;
|
||
|
||
GetCallBridge ().GetDestinationAddress (&DestinationAddress);
|
||
|
||
_ASSERTE(Q931_DEST_STATE_INIT == m_Q931DestState);
|
||
|
||
// it has to be a Setup PDU
|
||
if (setup_chosen != pH323UserInfo->h323_uu_pdu.h323_message_body.choice)
|
||
{
|
||
DebugF(_T("Q931: 0x%x in Setup PDU UUIE is not a Setup-UUIE, rejecting PDU.\n"), &GetCallBridge ());
|
||
return E_UNEXPECTED;
|
||
}
|
||
|
||
Setup = &pH323UserInfo -> h323_uu_pdu.h323_message_body.u.setup;
|
||
|
||
// Generate the Call Reference Value for both incoming/outgoing calls
|
||
if (!AllocCallRefVal(m_CallRefVal))
|
||
{
|
||
DebugF(_T("Q931: 0x%x failed to allocate call reference value.\n"), &GetCallBridge ());
|
||
return E_UNEXPECTED;
|
||
}
|
||
|
||
// examine the alias from the Setup-UUIE, query the LDAP translation table
|
||
|
||
if (Setup -> bit_mask & destinationAddress_present
|
||
&& Setup -> destinationAddress) {
|
||
CHAR AnsiAliasValue [0x100];
|
||
INT Length;
|
||
|
||
Alias = &Setup -> destinationAddress -> value;
|
||
|
||
switch (Alias -> choice) {
|
||
case h323_ID_chosen:
|
||
// the expected case
|
||
// downgrade to ANSI
|
||
|
||
Length = WideCharToMultiByte (CP_ACP, 0, (LPWSTR)Alias -> u.h323_ID.value,
|
||
Alias -> u.h323_ID.length,
|
||
AnsiAliasValue, 0xFF, NULL, NULL);
|
||
if (!Length) {
|
||
DebugF (_T("Q931: 0x%x failed to convert unicode string. Internal error.\n"), &GetCallBridge ());
|
||
return E_FAIL;
|
||
}
|
||
|
||
AnsiAliasValue [Length] = 0;
|
||
AnsiAlias.Buffer = AnsiAliasValue;
|
||
AnsiAlias.Length = Length * (USHORT)sizeof (CHAR);
|
||
break;
|
||
|
||
case email_ID_chosen:
|
||
AnsiAlias.Buffer = Alias -> u.email_ID;
|
||
AnsiAlias.Length = (USHORT) strlen (Alias -> u.email_ID) * sizeof (CHAR);
|
||
break;
|
||
|
||
case e164_chosen:
|
||
AnsiAlias.Buffer = Alias -> u.e164;
|
||
AnsiAlias.Length = (USHORT) strlen (Alias -> u.e164) * sizeof (CHAR);
|
||
break;
|
||
|
||
default:
|
||
DebugF (_T("Q931: 0x%x bogus alias address type.\n"), &GetCallBridge());
|
||
return E_FAIL;
|
||
}
|
||
|
||
Result = LdapQueryTableByAlias (&AnsiAlias, &TranslatedDestinationAddress);
|
||
|
||
if (Result == S_OK) {
|
||
DebugF (_T("Q931: 0x%x resolved alias (%.*S) to address %08X.\n"),
|
||
&GetCallBridge (),
|
||
ANSI_STRING_PRINTF (&AnsiAlias),
|
||
TranslatedDestinationAddress);
|
||
|
||
// Change the initial destination address to the one read from
|
||
// the LDAP Address Translation Table
|
||
DestinationAddress.sin_addr.s_addr = htonl (TranslatedDestinationAddress);
|
||
|
||
}
|
||
else {
|
||
DebugF (_T("Q931: 0x%x failed to resolve alias (%.*S) in LDAP table.\n"),
|
||
&GetCallBridge (),
|
||
ANSI_STRING_PRINTF (&AnsiAlias));
|
||
}
|
||
}
|
||
else {
|
||
DebugF (_T("Q931: 0x%x destination not specified. Looking in registry for special destination.\n"),
|
||
&GetCallBridge ());
|
||
|
||
Result = LookupDefaultDestination (&TranslatedDestinationAddress);
|
||
if (Result == S_OK) {
|
||
|
||
DestinationAddress.sin_addr.s_addr = htonl (TranslatedDestinationAddress);
|
||
|
||
DebugF (_T("Q931: 0x%x found special destination in registry.\n"),
|
||
&GetCallBridge ());
|
||
}
|
||
else {
|
||
|
||
DebugF (_T("Q931: 0x%x did not find special destination in registry.\n"),
|
||
&GetCallBridge ());
|
||
}
|
||
}
|
||
|
||
DebugF (_T("Q931: 0x%x will use address %08X:%04X as destination.\n"),
|
||
&GetCallBridge (),
|
||
SOCKADDR_IN_PRINTF (&DestinationAddress));
|
||
|
||
Error = GetBestInterfaceAddress (ntohl (DestinationAddress.sin_addr.s_addr), &GetCallBridge ().DestinationInterfaceAddress);
|
||
if (ERROR_SUCCESS != Error) {
|
||
DebugF (_T("Q931: 0x%x failed to determine destination interface address for %08X:%04X.\n"),
|
||
&GetCallBridge (),
|
||
SOCKADDR_IN_PRINTF (&DestinationAddress));
|
||
|
||
return HRESULT_FROM_WIN32 (Error);
|
||
}
|
||
|
||
Result = ConnectToH323Endpoint (&DestinationAddress);
|
||
if (Result != S_OK) {
|
||
DebugF (_T("Q931: 0x%x failed to connect to address %08X:%04X.\n"),
|
||
&GetCallBridge (),
|
||
SOCKADDR_IN_PRINTF (&DestinationAddress));
|
||
return E_FAIL;
|
||
}
|
||
|
||
// If the call succeeds, then the connection to the destination is
|
||
// established. So, the Q.931 PDU can be modified and sent to the
|
||
// destination.
|
||
|
||
// Q931 Header - CallReferenceValue
|
||
// pQ931Message->CallReferenceValue = GetCallRefVal();
|
||
|
||
// H323UserInfo -
|
||
// destCallSignalAddress TransportAddress OPTIONAL
|
||
// sourceCallSignalAddress TransportAddress OPTIONAL
|
||
|
||
// if the destCallSignalAddress is set, replace it with the
|
||
// remote ip v4 address, port
|
||
if (Setup -> bit_mask & Setup_UUIE_destCallSignalAddress_present) {
|
||
FillTransportAddress (
|
||
m_SocketInfo.RemoteAddress,
|
||
Setup -> destCallSignalAddress);
|
||
}
|
||
|
||
// if the sourceCallSignalAddress is set, replace it with
|
||
// own ip v4 address, port
|
||
if (Setup -> bit_mask & sourceCallSignalAddress_present) {
|
||
FillTransportAddress (
|
||
m_SocketInfo.LocalAddress,
|
||
Setup -> sourceCallSignalAddress);
|
||
}
|
||
|
||
// if ANY of the fields in the extension field are set,
|
||
// then make sure that all of the mandatory extension fields
|
||
// are set. this is a workaround for a problem caused by
|
||
// inconsistent ASN.1 files. -- arlied
|
||
|
||
if ((sourceCallSignalAddress_present
|
||
| Setup_UUIE_remoteExtensionAddress_present
|
||
| Setup_UUIE_callIdentifier_present
|
||
| h245SecurityCapability_present
|
||
| Setup_UUIE_tokens_present
|
||
| Setup_UUIE_cryptoTokens_present
|
||
| Setup_UUIE_fastStart_present
|
||
| canOverlapSend_present
|
||
| mediaWaitForConnect_present
|
||
) & Setup -> bit_mask) {
|
||
|
||
// check each mandatory field
|
||
// fill in quasi-bogus values for those that the source did not supply
|
||
|
||
if (!(Setup -> bit_mask & Setup_UUIE_callIdentifier_present)) {
|
||
Debug (_T("Q931: *** warning, source did NOT fill in the mandatory callIdentifier field! using zeroes\n"));
|
||
|
||
ZeroMemory (Setup -> callIdentifier.guid.value, sizeof (GUID));
|
||
Setup -> callIdentifier.guid.length = sizeof (GUID);
|
||
Setup -> bit_mask |= Setup_UUIE_callIdentifier_present;
|
||
}
|
||
|
||
if (!(Setup -> bit_mask & canOverlapSend_present)) {
|
||
Debug (_T("Q931: *** warning, source did NOT fill in the mandatory canOverlapSend field! using value of FALSE\n"));
|
||
|
||
Setup -> canOverlapSend = FALSE;
|
||
Setup -> bit_mask |= canOverlapSend_present;
|
||
}
|
||
|
||
if (!(Setup -> bit_mask & mediaWaitForConnect_present)) {
|
||
Debug (_T("Q931: *** warning, source did NOT fill in the mandatory mediaWaitForConnect field! using value of FALSE\n"));
|
||
|
||
Setup -> mediaWaitForConnect = FALSE;
|
||
Setup -> bit_mask |= mediaWaitForConnect_present;
|
||
}
|
||
|
||
// We don't support FastStart procedures for now
|
||
// Save the information on whether fastStart element was present: it will
|
||
// have to be restored later.
|
||
OldFastStartBit = Setup -> bit_mask & Setup_UUIE_fastStart_present;
|
||
// Now unconditionally turn off FastStart
|
||
Setup -> bit_mask &= ~Setup_UUIE_fastStart_present;
|
||
}
|
||
|
||
// We don't support H.245 Tunneling
|
||
// Save the information on whether this PDU contained H.245 tunneled data: it will
|
||
// have to be restored later.
|
||
OldH245TunnelingBit = pH323UserInfo -> h323_uu_pdu.bit_mask & h245Tunneling_present;
|
||
OldH245TunnelingFlag = pH323UserInfo -> h323_uu_pdu.h245Tunneling;
|
||
// Now unconditionally turn off H.245 tunneling
|
||
pH323UserInfo -> h323_uu_pdu.bit_mask &= ~h245Tunneling_present;
|
||
pH323UserInfo -> h323_uu_pdu.h245Tunneling = FALSE;
|
||
|
||
// queue async send for SETUP PDU
|
||
Result = QueueSend(pQ931Message, pH323UserInfo);
|
||
if (FAILED(Result)) {
|
||
DebugF (_T("Q931: 0x%x failed to queue send.\n"), &GetCallBridge ());
|
||
goto cleanup;
|
||
}
|
||
|
||
// Need to restore information about FastStart and H.245 tunneling so that the
|
||
// Setup PDU is properly deallocated by the ASN.1 module
|
||
Setup -> bit_mask |= OldFastStartBit;
|
||
pH323UserInfo -> h323_uu_pdu.bit_mask |= OldH245TunnelingBit;
|
||
pH323UserInfo -> h323_uu_pdu.h245Tunneling = OldH245TunnelingFlag;
|
||
|
||
// since the socket was created just now, we must
|
||
// queue the first async receive
|
||
Result = QueueReceive();
|
||
if (FAILED(Result)) {
|
||
DebugF (_T("Q931: 0x%x failed to queue receive.\n"), &GetCallBridge());
|
||
goto cleanup;
|
||
}
|
||
|
||
Result = CreateTimer (Q931_POST_SETUP_TIMER_VALUE);
|
||
if (FAILED(Result)) {
|
||
DebugF (_T("Q931: 0x%x failed to create timer for duration %d milliseconds ('Setup'). Error - %x.\n"),
|
||
&GetCallBridge (),
|
||
Q931_POST_SETUP_TIMER_VALUE,
|
||
Result);
|
||
goto cleanup;
|
||
}
|
||
DebugF (_T("Q931: 0x%x created timer for duration %d milliseconds('Setup').\n"),
|
||
&GetCallBridge (),
|
||
Q931_POST_SETUP_TIMER_VALUE);
|
||
|
||
// state transition to Q931_DEST_STATE_CON_ESTD
|
||
m_Q931DestState = Q931_DEST_STATE_CON_ESTD;
|
||
|
||
return Result;
|
||
|
||
cleanup:
|
||
|
||
m_SocketInfo.Clear(TRUE);
|
||
|
||
return Result;
|
||
}
|
||
|
||
#define IPV4_ADDR_MAX_LEN 0x10 // max length of quad-dotted representation of an IP address
|
||
|
||
HRESULT DEST_Q931_INFO::LookupDefaultDestination (
|
||
OUT DWORD * ReturnAddress) // host order
|
||
{
|
||
TCHAR szDefaultLocalDestAddr [IPV4_ADDR_MAX_LEN];
|
||
LONG Result;
|
||
DWORD ValueLength;
|
||
DWORD Type;
|
||
HKEY Key;
|
||
SOCKADDR_IN Address = { 0 };
|
||
|
||
INT AddressLength = sizeof(SOCKADDR_IN);
|
||
|
||
// 1. Open the registry key containing the proxy's parameters
|
||
Result = RegOpenKeyEx (HKEY_LOCAL_MACHINE, H323ICS_SERVICE_PARAMETERS_KEY_PATH,
|
||
0, KEY_READ, &Key);
|
||
|
||
if (Result != ERROR_SUCCESS)
|
||
{
|
||
DebugF(_T("Q931: 0x%x could not open registry parameter key. Error: %d(0x%x)"),
|
||
&GetCallBridge (),
|
||
Result, Result);
|
||
|
||
return Result;
|
||
}
|
||
|
||
// 2. Read the value of the default destination on the local subnet
|
||
ValueLength = sizeof (szDefaultLocalDestAddr);
|
||
Result = RegQueryValueEx (
|
||
Key,
|
||
H323ICS_REG_VAL_DEFAULT_LOCAL_DEST_ADDR,
|
||
0,
|
||
&Type,
|
||
(LPBYTE) szDefaultLocalDestAddr,
|
||
&ValueLength);
|
||
|
||
if (Result != ERROR_SUCCESS || Type != REG_SZ)
|
||
{
|
||
szDefaultLocalDestAddr[0] = '\0';
|
||
|
||
RegCloseKey (Key);
|
||
|
||
return S_FALSE;
|
||
}
|
||
|
||
// 3. Close the registry key for the proxy parameters
|
||
RegCloseKey (Key);
|
||
|
||
// 4. Convert the string with the IP address of the default
|
||
// destination on the local subnet to its binary representation
|
||
Result = WSAStringToAddress(
|
||
szDefaultLocalDestAddr,
|
||
AF_INET,
|
||
NULL,
|
||
(SOCKADDR *) &Address,
|
||
&AddressLength
|
||
);
|
||
|
||
if (Result != ERROR_SUCCESS)
|
||
{
|
||
DebugF (_T("Q931: Bogus address (%S).\n"), szDefaultLocalDestAddr);
|
||
|
||
return Result;
|
||
}
|
||
|
||
// 5. Prepare the return address in host order
|
||
*ReturnAddress = htonl (Address.sin_addr.s_addr);
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
HRESULT DEST_Q931_INFO::ConnectToH323Endpoint(
|
||
IN SOCKADDR_IN * DestinationAddress)
|
||
{
|
||
INT Status;
|
||
|
||
// Connect to the destination specifed by the client (for outbound calls)
|
||
// or to the selected destination on the local subnet (for inbound calls)
|
||
Status = m_SocketInfo.Connect (DestinationAddress);
|
||
|
||
if (Status == 0)
|
||
{
|
||
DebugF (_T ("Q931: 0x%x successfully connected to %08X:%04X.\n"),
|
||
&GetCallBridge (),
|
||
SOCKADDR_IN_PRINTF (DestinationAddress));
|
||
|
||
return S_OK;
|
||
}
|
||
else
|
||
{
|
||
DebugErrorF (Status, _T("Q931: 0x%x failed to connect to %08X:%04X.\n"),
|
||
&GetCallBridge (),
|
||
SOCKADDR_IN_PRINTF (DestinationAddress));
|
||
|
||
return HRESULT_FROM_WIN32 (Status);
|
||
}
|
||
}
|