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