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

1087 lines
32 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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