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