You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
996 lines
23 KiB
996 lines
23 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
|
|
// Yes, it is ugly and bad practice but this is a QFE
|
|
// for details look up bug# WinSE 31054, 691666 (read both 35928 and 33546).
|
|
Sleep( 500 );
|
|
|
|
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 (
|