993 lines
22 KiB
C++
993 lines
22 KiB
C++
/*++
|
||
|
||
Copyright (c) 1998 - 2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
cbridge.cpp
|
||
|
||
Abstract:
|
||
|
||
Contains the CALL_BRIDGE-related common definitions
|
||
(not specific to Q931 or H245).
|
||
The call bridge calls the event manager for async winsock
|
||
operations and the event manager calls the overlapped
|
||
processor with the results.
|
||
|
||
Revision History:
|
||
1. created
|
||
Byrisetty Rajeev (rajeevb) 12-Jun-1998
|
||
2. q931.cpp and h245.cpp were created with functions in this
|
||
file on 21-Aug-1998. This was done to reduce file sizes and
|
||
remote unnecessary tapi, rend, atl dependencies.
|
||
|
||
--*/
|
||
|
||
/* TO DO -
|
||
4. Need fn on Q931_INFO and H245_INFO to simplify modify a PDU from the opposite
|
||
instance and forward it to its remote end.
|
||
6. Clearly define when and where we should return if in shutdown mode
|
||
7. Need to use the oss library free methods to free the pdu structs
|
||
9. Must receive be queued (always) after state transition? Does it matter?
|
||
10. Should try to recover from error situations, but should initiate clean
|
||
up in case of unrecoverable situations.
|
||
11. Need to isolate recoverable error situations.
|
||
12. Use a table to handle PDUs in a given state - look at the destination
|
||
instance's (q931) methods for the same.
|
||
|
||
DONE -
|
||
1. Should the state transition be fired immediately or after the actions have been taken
|
||
Ans: Should be done after the actions as, in case of error, if the state transition is still
|
||
fired, the actions will never be retried. So failure should either be handled by resetting
|
||
the member variables or by always using temporary variables and copying the results into
|
||
member variables after state transition.
|
||
5. IMPORTANT: Need to send the RELEASE COMPLETE PDU before initiating termination
|
||
Ans: We first pass on the PDU to the other instance and then perform state
|
||
transitions as well as initiate termination.
|
||
8. Call reference value should be 1-3 bytes, its a WORD currently in both
|
||
the q931pdu.h file as well as the cbridge class
|
||
Ans: The h225 spec defines the call ref field to be 2 bytes (WORD).
|
||
|
||
NOT DONE -
|
||
2. Should we try to consolidate all actions taken in response to an event in a single fn
|
||
instead of spreading it around in the src and dest instances? Can this be done via
|
||
inline fns instead (to maintain some encapsulation)
|
||
3. Should we handle timer events in the same fns as the PDU events?
|
||
*/
|
||
|
||
#include "stdafx.h"
|
||
|
||
|
||
// CALL_BRIDGE --------------------------------------------------------------------------
|
||
|
||
|
||
HRESULT CALL_BRIDGE::Initialize (
|
||
IN SOCKET Socket,
|
||
IN SOCKADDR_IN * LocalAddress,
|
||
IN SOCKADDR_IN * RemoteAddress,
|
||
IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Initializes an instance of CALL_BRIDGE
|
||
|
||
Arguments:
|
||
Socket - Socket on which connection was accepted
|
||
LocalAddress - Address of the local side of the session
|
||
RemoteAddress - Address of the remote side of the session
|
||
RedirectInformation - Information about the redirect (obtained from NAT)
|
||
|
||
Return Values:
|
||
Passes through return value of another method
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT Result;
|
||
|
||
Lock();
|
||
|
||
Result = InitializeLocked (
|
||
Socket,
|
||
LocalAddress,
|
||
RemoteAddress,
|
||
RedirectInformation);
|
||
|
||
Unlock();
|
||
|
||
return Result;
|
||
} // CALL_BRIDGE::Initialize
|
||
|
||
|
||
HRESULT CALL_BRIDGE::InitializeLocked (
|
||
IN SOCKET Socket,
|
||
IN SOCKADDR_IN * LocalAddress,
|
||
IN SOCKADDR_IN * RemoteAddress,
|
||
IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Initializes an instance of CALL_BRIDGE
|
||
|
||
Arguments:
|
||
Socket - Socket on which connection was accepted
|
||
LocalAddress - Address of the local side of the session
|
||
RemoteAddress - Address of the remote side of the session
|
||
RedirectInformation - Information about the redirect (obtained from NAT)
|
||
|
||
Return Values:
|
||
S_OK if successful
|
||
E_UNEXPECTED if the instance has already been initialized
|
||
|
||
Otherwise, passes through status code returned by other
|
||
functions/methods
|
||
|
||
Notes:
|
||
To be called for a locked instance
|
||
|
||
--*/
|
||
|
||
{
|
||
HRESULT Result;
|
||
ULONG Error;
|
||
|
||
assert (Socket != INVALID_SOCKET);
|
||
assert (LocalAddress);
|
||
assert (RemoteAddress);
|
||
|
||
if (State != STATE_NONE) {
|
||
DebugF(_T("Q931: 0x%x has already been initialized, cannot do so again.\n"), this);
|
||
return E_UNEXPECTED;
|
||
}
|
||
|
||
DebugF (_T ("Q931: 0x%x connection accepted on adapter %d.\n"), this, RedirectInformation -> AdapterIndex);
|
||
|
||
SourceInterfaceAddress = H323MapAdapterToAddress (RedirectInformation -> AdapterIndex);
|
||
|
||
if (INADDR_NONE == SourceInterfaceAddress) {
|
||
|
||
DebugF (_T ("Q931: 0x%x failed to get source interface address (via H323MapAdapterToAddress).\n"), this);
|
||
|
||
return E_FAIL;
|
||
|
||
}
|
||
|
||
// Address of the best interface to the destination will be determined when alias in Q.931 Setup PDU is
|
||
// mapped to the real destination address.
|
||
|
||
DebugF (_T("Q931: 0x%x arrived on interface %08X.\n"), this, SourceInterfaceAddress);
|
||
|
||
Result = EventMgrBindIoHandle (Socket);
|
||
if (Result != S_OK) {
|
||
DebugErrorF (Result, _T("Q931: 0x%x failed to bind I/O handle to completion port\n"), this);
|
||
return Result;
|
||
}
|
||
|
||
DebugF (_T("Q931: 0x%x bound I/O handle to socket %x.\n"), this, Socket);
|
||
|
||
// init source call state
|
||
m_SourceH323State.Init (*this);
|
||
|
||
Result = m_SourceH323State.GetSourceQ931Info().SetIncomingSocket(
|
||
Socket,
|
||
const_cast <SOCKADDR_IN *> (LocalAddress),
|
||
const_cast <SOCKADDR_IN *> (RemoteAddress));
|
||
|
||
// init dest call state
|
||
Result = m_DestH323State.Init (*this);
|
||
if (Result != S_OK) {
|
||
return Result;
|
||
}
|
||
|
||
State = STATE_CONNECTED;
|
||
|
||
return Result;
|
||
} // CALL_BRIDGE::InitializeLocked
|
||
|
||
|
||
void
|
||
CALL_BRIDGE::Terminate (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Terminates the instance
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
1. To be called for a locked instance only.
|
||
2. Not to be called when Q.931 Release Complete PDU is received
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
switch (State) {
|
||
case STATE_NONE:
|
||
DebugF (_T("Q931: 0x%x terminates. STATE_NONE --> TERMINATED\n"), this);
|
||
|
||
State = STATE_TERMINATED;
|
||
|
||
CallBridgeList.RemoveCallBridge (this);
|
||
|
||
break;
|
||
|
||
case STATE_TERMINATED:
|
||
DebugF (_T("Q931: 0x%x terminates. TERMINATED --> TERMINATED\n"), this);
|
||
|
||
// no transition
|
||
break;
|
||
|
||
case STATE_CONNECTED:
|
||
DebugF (_T("Q931: 0x%x terminates. STATE_CONN --> TERMINATED\n"), this);
|
||
|
||
// call is currently active
|
||
// begin the process of tearing down call state
|
||
State = STATE_TERMINATED;
|
||
|
||
m_SourceH323State.GetQ931Info().SendReleaseCompletePdu();
|
||
m_DestH323State.GetQ931Info().SendReleaseCompletePdu();
|
||
|
||
// cancel all timers, ignore error code
|
||
CancelAllTimers ();
|
||
|
||
// close each socket
|
||
m_SourceH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
|
||
m_DestH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
|
||
|
||
CallBridgeList.RemoveCallBridge (this);
|
||
|
||
break;
|
||
|
||
default:
|
||
assert (FALSE);
|
||
break;
|
||
}
|
||
} // CALL_BRIDGE::Terminate
|
||
|
||
|
||
void
|
||
CALL_BRIDGE::TerminateExternal (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Terminates the instance
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
Not to be called when Q.931 Release Complete PDU is received
|
||
|
||
--*/
|
||
{
|
||
Lock();
|
||
|
||
Terminate ();
|
||
|
||
Unlock();
|
||
} // CALL_BRIDGE::TerminateExternal
|
||
|
||
|
||
BOOL
|
||
CALL_BRIDGE::IsConnectionThrough (
|
||
IN DWORD InterfaceAddress // host order
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Determines whether the connection goes through the
|
||
interface specified
|
||
|
||
Arguments:
|
||
InterfaceAddress - address of the interface for which
|
||
the determination is to be made.
|
||
|
||
Return Values:
|
||
TRUE - if the connection being proxied goes through the
|
||
interface specified
|
||
|
||
FALSE - if the connection being proxied does not go through the
|
||
interface specified
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOL IsThrough;
|
||
|
||
IsThrough = (InterfaceAddress == SourceInterfaceAddress) ||
|
||
(InterfaceAddress == DestinationInterfaceAddress);
|
||
|
||
return IsThrough;
|
||
|
||
} // CALL_BRIDGE::IsConnectionThrough
|
||
|
||
|
||
void
|
||
CALL_BRIDGE::OnInterfaceShutdown (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Performs necessary actions when a network interface
|
||
through which the connection being proxied goes down.
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Value:
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
Lock ();
|
||
|
||
switch (State) {
|
||
case STATE_NONE:
|
||
DebugF (_T("Q931: 0x%x terminates (interface goes down). STATE_NONE --> TERMINATED\n"), this);
|
||
|
||
State = STATE_TERMINATED;
|
||
|
||
CallBridgeList.RemoveCallBridge (this);
|
||
|
||
break;
|
||
|
||
case STATE_TERMINATED:
|
||
DebugF (_T("Q931: 0x%x terminates (interface goes down). TERMINATED --> TERMINATED\n"), this);
|
||
|
||
// no transition
|
||
break;
|
||
|
||
case STATE_CONNECTED:
|
||
DebugF (_T("Q931: 0x%x terminates (interface goes down). STATE_CONN --> TERMINATED\n"), this);
|
||
|
||
// call is currently active
|
||
// begin the process of tearing down call state
|
||
State = STATE_TERMINATED;
|
||
|
||
m_SourceH323State.GetH245Info().SendEndSessionCommand ();
|
||
m_DestH323State.GetH245Info().SendEndSessionCommand ();
|
||
|
||
m_SourceH323State.GetQ931Info().SendReleaseCompletePdu();
|
||
m_DestH323State.GetQ931Info().SendReleaseCompletePdu();
|
||
|
||
// cancel all timers, ignore error code
|
||
CancelAllTimers ();
|
||
|
||
CallBridgeList.RemoveCallBridge (this);
|
||
|
||
break;
|
||
|
||
default:
|
||
assert (FALSE);
|
||
break;
|
||
}
|
||
|
||
Unlock ();
|
||
|
||
} // CALL_BRIDGE::OnInterfaceShutdown
|
||
|
||
|
||
void
|
||
CALL_BRIDGE::TerminateCallOnReleaseComplete (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Terminate the instance when Q.931 Release Complete PDU is received
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
if (State != STATE_TERMINATED)
|
||
{
|
||
State = STATE_TERMINATED;
|
||
|
||
CancelAllTimers ();
|
||
|
||
// CODEWORK: When we are in a terminating state we need not process
|
||
// any more PDUs. We can just drop them.
|
||
|
||
// CODEWORK: When the proxy is originating the call shutdown (because
|
||
// of an error or timeout, it should send ReleaseComplete PDUs and
|
||
// endSessionCommand PDUs to either side. Do we need to send
|
||
// closeLC PDUs also ?
|
||
|
||
// We probably need a state called RELEASE_COMPLETE_SENT and after
|
||
// this any more errors means we just mercilessly shut down everything.
|
||
|
||
// close H245 sockets, if any as they may have outstanding
|
||
// async receive/send requests pending
|
||
// NOTE: the source H245 info may be listening for incoming connections
|
||
// in which case we just close the listen socket
|
||
m_SourceH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
|
||
m_DestH323State.GetH245Info().GetSocketInfo().Clear(TRUE);
|
||
|
||
CallBridgeList.RemoveCallBridge (this);
|
||
}
|
||
} // CALL_BRIDGE::TerminateCallOnReleaseComplete
|
||
|
||
|
||
DWORD
|
||
CALL_BRIDGE::GetSourceInterfaceAddress (
|
||
void
|
||
) const
|
||
/*++
|
||
|
||
Routine Description:
|
||
Accessor method
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
Address of the interface on which the connection was
|
||
accepted
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
return SourceInterfaceAddress;
|
||
} // CALL_BRIDGE::GetSourceInterfaceAddress
|
||
|
||
|
||
VOID
|
||
CALL_BRIDGE::GetSourceAddress (
|
||
OUT SOCKADDR_IN* ReturnSourceAddress
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Accessor method
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values (by reference):
|
||
Address of the remote party that initiated the call
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
_ASSERTE(ReturnSourceAddress);
|
||
|
||
ReturnSourceAddress->sin_family = SourceAddress.sin_family;
|
||
ReturnSourceAddress->sin_addr.s_addr = SourceAddress.sin_addr.s_addr;
|
||
ReturnSourceAddress->sin_port = SourceAddress.sin_port;
|
||
}
|
||
|
||
|
||
void CALL_BRIDGE::GetDestinationAddress (
|
||
OUT SOCKADDR_IN * ReturnDestinationAddress
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Accessor method
|
||
|
||
Arguments:
|
||
ReturnDestinationAddress (out) - Destination address of
|
||
the session this instance proxies
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
assert (ReturnDestinationAddress);
|
||
|
||
*ReturnDestinationAddress = DestinationAddress;
|
||
}
|
||
|
||
|
||
CALL_BRIDGE::CALL_BRIDGE (
|
||
NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
|
||
)
|
||
:
|
||
LIFETIME_CONTROLLER (
|
||
&Q931SyncCounter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Constructor for CALL_BRIDGE class
|
||
|
||
Arguments:
|
||
RedirectInformation - original source/destination before
|
||
the NAT redirect was satisfied
|
||
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
Passes pointer to associated global sync counter to the base class
|
||
|
||
--*/
|
||
|
||
{
|
||
SourceInterfaceAddress = 0;
|
||
DestinationInterfaceAddress = 0;
|
||
|
||
State = STATE_NONE;
|
||
|
||
DestinationAddress.sin_family = AF_INET;
|
||
DestinationAddress.sin_addr.s_addr = RedirectInformation -> DestinationAddress;
|
||
DestinationAddress.sin_port = RedirectInformation -> DestinationPort;
|
||
|
||
SourceAddress.sin_family = AF_INET;
|
||
SourceAddress.sin_addr.s_addr = RedirectInformation -> SourceAddress;
|
||
SourceAddress.sin_port = RedirectInformation -> SourcePort;
|
||
|
||
DebugF (_T("Q931: 0x%x created.\n"), this);
|
||
|
||
} // CALL_BRIDGE::CALL_BRIDGE
|
||
|
||
|
||
CALL_BRIDGE::~CALL_BRIDGE (
|
||
void)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Destructor for CALL_BRIDGE class
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
DebugF (_T("Q931: 0x%x destroyed.\n"), this);
|
||
|
||
} // CALL_BRIDGE::~CALL_BRIDGE
|
||
|
||
|
||
|
||
void
|
||
Q931_INFO::IncrementLifetimeCounter (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Increments reference counter to the parent
|
||
CALL_BRIDGE on its own behalf
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
GetCallBridge().AddRef();
|
||
} // Q931_INFO::IncrementLifetimeCounter
|
||
|
||
|
||
void
|
||
Q931_INFO::DecrementLifetimeCounter (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Decrements reference counter to the parent
|
||
CALL_BRIDGE on its own behalf
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
GetCallBridge().Release ();
|
||
} // Q931_INFO::DecrementLifetimeCounter
|
||
|
||
|
||
|
||
HRESULT
|
||
Q931_INFO::SendCallback (
|
||
IN HRESULT CallbackResult
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Handle completion of the send operation
|
||
|
||
Arguments:
|
||
CallbackResult -- status of the async operation invoked
|
||
|
||
Return Values:
|
||
S_OK if the parent call-bridge was already terminated;
|
||
passes back the value of CallbackResult otherwise
|
||
|
||
Notes:
|
||
Virtual
|
||
|
||
--*/
|
||
|
||
{
|
||
CALL_BRIDGE *pCallBridge = &GetCallBridge();
|
||
HRESULT Result = S_OK;
|
||
|
||
pCallBridge->Lock();
|
||
|
||
if (!pCallBridge -> IsTerminated ()) {
|
||
|
||
if (FAILED(CallbackResult))
|
||
{
|
||
pCallBridge->Terminate ();
|
||
|
||
_ASSERTE(pCallBridge->IsTerminated());
|
||
|
||
Result = CallbackResult;
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
// This is here to take care of closing the socket
|
||
// when callbridge sends ReleaseComplete PDU during
|
||
// termination path.
|
||
GetSocketInfo ().Clear (TRUE);
|
||
}
|
||
|
||
pCallBridge->Unlock();
|
||
|
||
return Result;
|
||
} // Q931_INFO::SendCallback
|
||
|
||
|
||
|
||
HRESULT
|
||
Q931_INFO::ReceiveCallback(
|
||
IN HRESULT CallbackResult,
|
||
IN BYTE *Buffer,
|
||
IN DWORD BufferLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Handles completion of a receive operation
|
||
|
||
Arguments:
|
||
CallbackResult -- status of the async operation
|
||
Buffer --
|
||
BufferLength --
|
||
|
||
Return Values:
|
||
Result of decoding of the received data, if the receive was successful
|
||
Otherwise just returns the status code passed.
|
||
|
||
|
||
Notes:
|
||
1. Virtual
|
||
2. This function is responsible for freeing Buffer
|
||
|
||
--*/
|
||
|
||
{
|
||
Q931_MESSAGE *pQ931msg = NULL;
|
||
H323_UserInformation *pDecodedH323UserInfo = NULL;
|
||
CALL_BRIDGE *pCallBridge = &GetCallBridge();
|
||
|
||
pCallBridge->Lock();
|
||
|
||
if (!pCallBridge -> IsTerminated ()) {
|
||
|
||
if (SUCCEEDED(CallbackResult))
|
||
{
|
||
CallbackResult = DecodeQ931PDU(Buffer, BufferLength,
|
||
&pQ931msg, &pDecodedH323UserInfo);
|
||
|
||
if (SUCCEEDED(CallbackResult))
|
||
{
|
||
// Process the PDU
|
||
ReceiveCallback(pQ931msg, pDecodedH323UserInfo);
|
||
FreeQ931PDU(pQ931msg, pDecodedH323UserInfo);
|
||
}
|
||
else
|
||
{
|
||
// An error occured. Terminate the CALL_BRIDGE
|
||
EM_FREE (Buffer);
|
||
DebugF( _T("Q931: 0x%x terminating on receive callback. Error=0x%x."),
|
||
pCallBridge,
|
||
CallbackResult);
|
||
|
||
pCallBridge->Terminate ();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// An error occured. Terminate the CALL_BRIDGE
|
||
EM_FREE (Buffer);
|
||
DebugF( _T("Q931: 0x%x terminating on receive callback. Error=0x%x."),
|
||
pCallBridge,
|
||
CallbackResult);
|
||
pCallBridge->Terminate ();
|
||
}
|
||
|
||
} else {
|
||
|
||
EM_FREE (Buffer);
|
||
}
|
||
|
||
pCallBridge->Unlock();
|
||
|
||
return CallbackResult;
|
||
} // Q931_INFO::ReceiveCallback
|
||
|
||
|
||
/*++
|
||
--*/
|
||
|
||
|
||
HRESULT
|
||
Q931_INFO::QueueSend (
|
||
IN Q931_MESSAGE *pQ931Message,
|
||
IN H323_UserInformation *pH323UserInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Encodes the Q.931 PDU into a buffer and sends it
|
||
on the socket. Once the send completes the buffer is freed
|
||
|
||
Arguments:
|
||
pQ931Message --
|
||
pH323UserInfo --
|
||
|
||
Return Values:
|
||
|
||
Notes:
|
||
This function does NOT free the Q.931 PDU.
|
||
--*/
|
||
|
||
{
|
||
BYTE *pBuf = NULL;
|
||
DWORD BufLen = 0;
|
||
|
||
// This should be the only place where CRVs are replaced.
|
||
// replace the CRV for all calls (incoming and outgoing)
|
||
pQ931Message->CallReferenceValue = m_CallRefVal;
|
||
|
||
// This function also encodes the TPKT header into the buffer.
|
||
HRESULT HResult = EncodeQ931PDU(
|
||
pQ931Message,
|
||
pH323UserInfo, // decoded ASN.1 part - could be NULL
|
||
&pBuf,
|
||
&BufLen
|
||
);
|
||
|
||
if (FAILED(HResult))
|
||
{
|
||
DebugF( _T("Q931: 0x%x EncodeQ931PDU() failed. Error=0x%x\n"),
|
||
&GetCallBridge (),
|
||
HResult);
|
||
return HResult;
|
||
}
|
||
|
||
// call the event manager to make the async send call
|
||
// the event mgr will free the buffer.
|
||
|
||
HResult = EventMgrIssueSend (m_SocketInfo.Socket, *this, pBuf, BufLen);
|
||
|
||
if (FAILED(HResult))
|
||
{
|
||
DebugF(_T("Q931: 0x%x EventMgrIssueSend failed: Error=0x%x\n"),
|
||
&GetCallBridge (),
|
||
HResult);
|
||
}
|
||
|
||
return HResult;
|
||
} // Q931_INFO::QueueSend
|
||
|
||
|
||
|
||
HRESULT
|
||
Q931_INFO::QueueReceive (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Issues an asynchronous receive
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
Passes through the result of calling another function
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
// call the event manager to make the async receive call
|
||
HRESULT HResult;
|
||
|
||
HResult = EventMgrIssueRecv (m_SocketInfo.Socket, *this);
|
||
|
||
if (FAILED(HResult))
|
||
{
|
||
DebugF (_T("Q931: 0x%x Async Receive call failed.\n"), &GetCallBridge ());
|
||
}
|
||
|
||
return HResult;
|
||
} // Q931_INFO::QueueReceive
|
||
|
||
|
||
HRESULT
|
||
Q931_INFO::SendReleaseCompletePdu (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Encodes and sends Q.931 Release Complete PDU
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
Passes through the result of calling another function
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
Q931_MESSAGE ReleaseCompletePdu;
|
||
H323_UserInformation ReleaseCompleteH323UserInfo;
|
||
HRESULT HResult;
|
||
|
||
HResult = Q931EncodeReleaseCompleteMessage(
|
||
m_CallRefVal,
|
||
&ReleaseCompletePdu,
|
||
&ReleaseCompleteH323UserInfo
|
||
);
|
||
if (FAILED(HResult))
|
||
{
|
||
DebugF(_T("Q931: 0x%x cCould not create Release Complete PDU.\n"), &GetCallBridge ());
|
||
return HResult;
|
||
}
|
||
|
||
HResult = QueueSend(
|
||
&ReleaseCompletePdu,
|
||
&ReleaseCompleteH323UserInfo
|
||
);
|
||
if (FAILED(HResult))
|
||
{
|
||
DebugF(_T("Q931: 0x%x failed to send ReleaseComplete PDU. Error=0x%x\n"),
|
||
&GetCallBridge (),
|
||
HResult);
|
||
}
|
||
|
||
return HResult;
|
||
} // Q931_INFO::SendReleaseCompletePdu
|
||
|
||
|
||
HRESULT
|
||
Q931_INFO::CreateTimer (
|
||
IN DWORD TimeoutValue
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Creates a Q.931 timer
|
||
|
||
Arguments:
|
||
TimeoutValue - self-explanatory
|
||
|
||
Return Values:
|
||
S_OK if timer was created successfully
|
||
Otherwise, passes back error code from another method
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
{
|
||
DWORD RetCode;
|
||
|
||
RetCode = TimprocCreateTimer(TimeoutValue);
|
||
|
||
return HRESULT_FROM_WIN32(RetCode);
|
||
} // Q931_INFO::CreateTimer
|
||
|
||
|
||
void
|
||
Q931_INFO::TimerCallback (
|
||
void
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Called when Q.931 timer expires
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Values:
|
||
None
|
||
|
||
Notes:
|
||
Virtual
|
||
|
||
--*/
|
||
|
||
{
|
||
// We keep a copy of the CALL_BRIDGE to be able to unlock it.
|
||
// DeleteAndRemoveSelf() will delete the LOGICAL_CHANNEL and
|
||
// so we can not access the CALL_BRIDGE through the member variable
|
||
// after the CALL_BRIDGE is deleted.
|
||
CALL_BRIDGE *pCallBridge = &GetCallBridge();
|
||
|
||
pCallBridge->Lock();
|
||
|
||
// Clear the timer - Note that Termninate () will try to
|
||
// cancel all the timers in this CALL_BRIDGE
|
||
TimprocCancelTimer();
|
||
|
||
DebugF (_T("Q931: 0x%x cancelled timer.\n"),
|
||
&GetCallBridge ());
|
||
|
||
// Don't do anything if the CALL_BRIDGE is already terminated.
|
||
if (!pCallBridge->IsTerminated())
|
||
{
|
||
// initiate shutdown
|
||
pCallBridge->Terminate ();
|
||
|
||
_ASSERTE(pCallBridge->IsTerminated());
|
||
}
|
||
|
||
pCallBridge -> Unlock ();
|
||
|
||
pCallBridge -> Release ();
|
||
} // Q931_INFO::TimerCallback (
|