home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.muug.mb.ca
/
2014.06.ftp.muug.mb.ca.tar
/
ftp.muug.mb.ca
/
pub
/
openh323.tar.gz
/
openh323.tar
/
openh323
/
src
/
h323neg.cxx
< prev
next >
Wrap
Text File
|
2003-01-29
|
49KB
|
1,666 lines
/*
* h323neg.cxx
*
* H.323 PDU definitions
*
* Open H323 Library
*
* Copyright (c) 1998-2000 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Open H323 Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions of this code were written with the assisance of funding from
* Vovida Networks, Inc. http://www.vovida.com.
*
* Contributor(s): ______________________________________.
*
* $Log: h323neg.cxx,v $
* Revision 1.69 2003/01/30 01:38:19 robertj
* Fixed some trace log errors
*
* Revision 1.68 2002/11/05 05:33:56 robertj
* Fixed problem where if capability is rejected by OnReceivedCapabilitySet()
* it still thinks it has received them.
*
* Revision 1.67 2002/08/05 10:03:47 robertj
* Cosmetic changes to normalise the usage of pragma interface/implementation.
*
* Revision 1.66 2002/06/27 07:11:55 robertj
* Fixed GNU warning
*
* Revision 1.65 2002/06/26 08:51:19 robertj
* Fixed deadlock if logical channel is closed via H.245 at exactly same
* time as being closed locally due to a channel I/O error.
*
* Revision 1.64 2002/05/03 03:08:40 robertj
* Added replacementFor field in OLC when resolving conflicting channels.
*
* Revision 1.63 2002/01/10 04:38:29 robertj
* Fixed problem with having incorrect constraint if getting array from caller on
* setting up a requestMode.
*
* Revision 1.62 2002/01/10 04:02:08 robertj
* Fixed correct filling of modeRequest structure.
*
* Revision 1.61 2002/01/09 00:21:40 robertj
* Changes to support outgoing H.245 RequstModeChange.
*
* Revision 1.60 2002/01/08 01:26:32 robertj
* Removed PTRACE in FindChannelsBySession as it can get called a LOT.
*
* Revision 1.59 2002/01/01 23:24:04 craigs
* Removed reference to myPTRACE
*
* Revision 1.58 2002/01/01 23:20:22 craigs
* Added HandleAck and StartRequest implementations for T.38
* thanks to Vyacheslav Frolov
*
* Revision 1.57 2001/12/22 03:10:17 robertj
* Changed OnRequstModeChange to return ack, then actually do the change.
*
* Revision 1.56 2001/12/22 01:46:33 robertj
* Fixed bug in RequestMode negotiation, failure to set sequence number.
*
* Revision 1.55 2001/12/14 08:36:36 robertj
* More implementation of T.38, thanks Adam Lazur
*
* Revision 1.54 2001/11/11 23:07:52 robertj
* Some clean ups after T.38 commit, thanks Adam Lazur
*
* Revision 1.53 2001/11/09 05:39:54 craigs
* Added initial T.38 support thanks to Adam Lazur
*
* Revision 1.52 2001/09/13 04:18:57 robertj
* Added support for "reopen" function when closing logical channel.
*
* Revision 1.51 2001/08/06 03:08:56 robertj
* Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
*
* Revision 1.50 2001/05/30 23:34:54 robertj
* Added functions to send TCS=0 for transmitter side pause.
*
* Revision 1.49 2001/05/09 02:34:37 robertj
* Fixed problem with being able to start two MSD's at the same time.
* Fixed possible race condition in code to prevent two TCS's happening
* at the same time.
*
* Revision 1.48 2001/04/26 02:01:53 robertj
* Added workaround for more strange Cisco behaviour, stops sending RTP
* data if you try and do a H.245 RoundTripDelay request!!
*
* Revision 1.47 2001/03/16 07:11:39 robertj
* Added logical channel open function version without locking.
*
* Revision 1.46 2001/03/14 03:20:27 robertj
* Fixed possible nested mutex deadlock in logical channel negotiator.
*
* Revision 1.45 2001/03/06 04:44:47 robertj
* Fixed problem where could send capability set twice. This should not be
* a problem except when talking to another broken stack, eg Cisco routers.
*
* Revision 1.44 2001/02/09 05:13:56 craigs
* Added pragma implementation to (hopefully) reduce the executable image size
* under Linux
*
* Revision 1.43 2001/01/04 07:46:22 robertj
* Added special test for broken NetMeeting in restablishing logical channels
* when have to close one due to device conflict (asymetric codecs).
*
* Revision 1.42 2001/01/02 08:03:28 robertj
* Changed MSD determination number comparision to be clearly as per spec.
*
* Revision 1.41 2000/10/16 09:46:37 robertj
* Fixed problem with opening codec before capability fields updated from
* OLC PDU, caused problems in G.711 tweaked psuedo-packet size.
*
* Revision 1.40 2000/09/22 01:35:50 robertj
* Added support for handling LID's that only do symmetric codecs.
*
* Revision 1.39 2000/09/12 01:01:17 robertj
* Fixed protocol issue, should send CloseLogicalChannel PDU's on accepting RequestClose.
*
* Revision 1.38 2000/08/31 10:49:38 robertj
* Fixed unix deadlock when non-fastStart but with H245 tunneling.
*
* Revision 1.37 2000/08/21 12:37:14 robertj
* Fixed race condition if close call just as slow start media channels are opening, part 2.
*
* Revision 1.36 2000/08/21 02:50:28 robertj
* Fixed race condition if close call just as slow start media channels are opening.
*
* Revision 1.35 2000/07/14 09:00:48 robertj
* Fixed race condition in closing connection and explicit close logical channel.
*
* Revision 1.34 2000/07/11 19:31:28 robertj
* Fixed possible deadlock under unix when trying to restart running TCS.
*
* Revision 1.33 2000/07/10 16:04:01 robertj
* Added TCS=0 support.
* Fixed bug where negotiations hang if not fast start and tunnelled but remot does not tunnel.
*
* Revision 1.32 2000/07/09 14:57:54 robertj
* Fixed bug where don't accept TCS if supplied sequence number is zero.
*
* Revision 1.31 2000/07/04 13:00:36 craigs
* Fixed problem with selecting large and small video sizes
*
* Revision 1.30 2000/07/04 04:15:41 robertj
* Fixed capability check of "combinations" for fast start cases.
*
* Revision 1.29 2000/07/03 00:38:40 robertj
* Fixed deadlock caused by nested mutex waits in negotiated channel closing.
*
* Revision 1.28 2000/06/27 03:46:52 robertj
* Fixed another possible race condition on logical channel closure.
*
* Revision 1.27 2000/06/03 03:16:39 robertj
* Fixed using the wrong capability table (should be connections) for some operations.
*
* Revision 1.26 2000/05/23 11:32:37 robertj
* Rewrite of capability table to combine 2 structures into one and move functionality into that class
* allowing some normalisation of usage across several applications.
* Changed H323Connection so gets a copy of capabilities instead of using endponts, allows adjustments
* to be done depending on the remote client application.
*
* Revision 1.25 2000/05/22 07:32:51 craigs
* Fixed problem with ohphone silence detection hanging
*
* Revision 1.24 2000/05/16 08:13:42 robertj
* Added function to find channel by session ID, supporting H323Connection::FindChannel() with mutex.
*
* Revision 1.23 2000/05/11 04:19:45 robertj
* Fixed typo
*
* Revision 1.22 2000/05/11 04:16:35 robertj
* Fixed missing timeout (and typo!) in bidirectional open logical channel.
*
* Revision 1.21 2000/05/08 05:06:27 robertj
* Fixed bug in H.245 close logical channel timeout, thanks XuPeili.
*
* Revision 1.20 2000/05/05 04:35:10 robertj
* Changed where the system timer is sampled to minimise overhead in round trip delay calculation.
*
* Revision 1.19 2000/05/02 04:32:27 robertj
* Fixed copyright notice comment.
*
* Revision 1.18 2000/04/24 23:47:01 robertj
* Fixed bug in master/slave negotiator for if have "in sync" random number generators, thanks Shawn Sincoski.
*
* Revision 1.17 2000/04/10 17:50:28 robertj
* Fixed yet another race condition needing mutex in logical channels management class.
*
* Revision 1.16 2000/04/05 03:17:31 robertj
* Added more RTP statistics gathering and H.245 round trip delay calculation.
*
* Revision 1.15 2000/03/29 02:14:46 robertj
* Changed TerminationReason to CallEndReason to use correct telephony nomenclature.
* Added CallEndReason for capability exchange failure.
*
* Revision 1.14 2000/03/25 02:19:50 robertj
* Fixed missing mutex call in some logical channels structure access.
*
* Revision 1.13 2000/02/17 12:07:43 robertj
* Used ne wPWLib random number generator after finding major problem in MSVC rand().
*
* Revision 1.12 1999/11/26 01:25:01 craigs
* Removed deadlock when remote endpoint requests unsupported channel type
*
* Revision 1.11 1999/11/19 09:07:27 robertj
* Fixed bug allocating incorrect channel number to fast start transmit channel.
*
* Revision 1.10 1999/11/06 11:00:18 robertj
* Fixed race condition in explicit channel close and connection close.
*
* Revision 1.9 1999/11/06 05:37:45 robertj
* Complete rewrite of termination of connection to avoid numerous race conditions.
*
* Revision 1.8 1999/10/30 12:34:47 robertj
* Added information callback for closed logical channel on H323EndPoint.
*
* Revision 1.7 1999/10/24 04:45:14 robertj
* Removed requirement that must be sending capability set to receive capability set.
*
* Revision 1.6 1999/09/21 14:10:41 robertj
* Fixed incorrect PTRACING test and removed uneeded include of videoio.h
*
* Revision 1.5 1999/09/15 01:26:27 robertj
* Changed capability set call backs to have more specific class as parameter.
*
* Revision 1.4 1999/09/14 14:26:17 robertj
* Added more debug tracing.
*
* Revision 1.3 1999/09/08 04:05:49 robertj
* Added support for video capabilities & codec, still needs the actual codec itself!
*
* Revision 1.2 1999/08/31 12:34:19 robertj
* Added gatekeeper support.
*
* Revision 1.1 1999/08/25 05:08:14 robertj
* File fission (critical mass reached).
*
*/
#include <ptlib.h>
#ifdef __GNUC__
#pragma implementation "h323neg.h"
#endif
#include "h323neg.h"
#include "h323ep.h"
#include <ptclib/random.h>
#define new PNEW
///////////////////////////////////////////////////////////////////////////////
H245Negotiator::H245Negotiator(H323EndPoint & end, H323Connection & conn)
: endpoint(end),
connection(conn)
{
replyTimer.SetNotifier(PCREATE_NOTIFIER(HandleTimeout));
}
void H245Negotiator::HandleTimeout(PTimer &, INT)
{
}
/////////////////////////////////////////////////////////////////////////////
H245NegMasterSlaveDetermination::H245NegMasterSlaveDetermination(H323EndPoint & end,
H323Connection & conn)
: H245Negotiator(end, conn)
{
retryCount = 1;
state = e_Idle;
status = e_Indeterminate;
}
BOOL H245NegMasterSlaveDetermination::Start(BOOL renegotiate)
{
PWaitAndSignal wait(mutex);
if (state != e_Idle) {
PTRACE(3, "H245\tMasterSlaveDetermination already in progress");
return TRUE;
}
if (!renegotiate && IsDetermined())
return TRUE;
retryCount = 1;
return Restart();
}
BOOL H245NegMasterSlaveDetermination::Restart()
{
PTRACE(3, "H245\tSending MasterSlaveDetermination");
// Begin the Master/Slave determination procedure
determinationNumber = PRandom::Number()%16777216;
replyTimer = endpoint.GetMasterSlaveDeterminationTimeout();
state = e_Outgoing;
H323ControlPDU pdu;
pdu.BuildMasterSlaveDetermination(endpoint.GetTerminalType(), determinationNumber);
return connection.WriteControlPDU(pdu);
}
void H245NegMasterSlaveDetermination::Stop()
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tStopping MasterSlaveDetermination: state=" << state);
if (state == e_Idle)
return;
replyTimer.Stop();
state = e_Idle;
}
BOOL H245NegMasterSlaveDetermination::HandleIncoming(const H245_MasterSlaveDetermination & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived MasterSlaveDetermination: state=" << state);
if (state == e_Incoming) {
replyTimer.Stop();
state = e_Idle;
return connection.OnControlProtocolError(H323Connection::e_MasterSlaveDetermination,
"Duplicate MasterSlaveDetermination");
}
replyTimer = endpoint.GetMasterSlaveDeterminationTimeout();
// Determine the master and slave
MasterSlaveStatus newStatus;
if (pdu.m_terminalType < (unsigned)endpoint.GetTerminalType())
newStatus = e_DeterminedMaster;
else if (pdu.m_terminalType > (unsigned)endpoint.GetTerminalType())
newStatus = e_DeterminedSlave;
else {
DWORD moduloDiff = (pdu.m_statusDeterminationNumber - determinationNumber)&0xffffff;
if (moduloDiff == 0 || moduloDiff == 0x800000)
newStatus = e_Indeterminate;
else if (moduloDiff < 0x800000)
newStatus = e_DeterminedMaster;
else
newStatus = e_DeterminedSlave;
}
H323ControlPDU reply;
if (newStatus != e_Indeterminate) {
PTRACE(2, "H245\tMasterSlaveDetermination: local is "
<< (newStatus == e_DeterminedMaster ? "master" : "slave"));
reply.BuildMasterSlaveDeterminationAck(newStatus == e_DeterminedMaster);
state = e_Incoming;
status = newStatus;
}
else if (state == e_Outgoing) {
retryCount++;
if (retryCount < endpoint.GetMasterSlaveDeterminationRetries())
return Restart(); // Try again
replyTimer.Stop();
state = e_Idle;
return connection.OnControlProtocolError(H323Connection::e_MasterSlaveDetermination,
"Retries exceeded");
}
else {
reply.BuildMasterSlaveDeterminationReject(H245_MasterSlaveDeterminationReject_cause::e_identicalNumbers);
}
return connection.WriteControlPDU(reply);
}
BOOL H245NegMasterSlaveDetermination::HandleAck(const H245_MasterSlaveDeterminationAck & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived MasterSlaveDeterminationAck: state=" << state);
if (state == e_Idle)
return TRUE;
replyTimer = endpoint.GetMasterSlaveDeterminationTimeout();
MasterSlaveStatus newStatus;
if (pdu.m_decision.GetTag() == H245_MasterSlaveDeterminationAck_decision::e_master)
newStatus = e_DeterminedMaster;
else
newStatus = e_DeterminedSlave;
H323ControlPDU reply;
if (state == e_Outgoing) {
status = newStatus;
PTRACE(2, "H245\tMasterSlaveDetermination: remote is "
<< (newStatus == e_DeterminedSlave ? "master" : "slave"));
reply.BuildMasterSlaveDeterminationAck(newStatus == e_DeterminedMaster);
if (!connection.WriteControlPDU(reply))
return FALSE;
}
replyTimer.Stop();
state = e_Idle;
if (status != newStatus)
return connection.OnControlProtocolError(H323Connection::e_MasterSlaveDetermination,
"Master/Slave mismatch");
return TRUE;
}
BOOL H245NegMasterSlaveDetermination::HandleReject(const H245_MasterSlaveDeterminationReject & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived MasterSlaveDeterminationReject: state=" << state);
switch (state) {
case e_Idle :
return TRUE;
case e_Outgoing :
if (pdu.m_cause.GetTag() == H245_MasterSlaveDeterminationReject_cause::e_identicalNumbers) {
retryCount++;
if (retryCount < endpoint.GetMasterSlaveDeterminationRetries())
return Restart();
}
default :
break;
}
replyTimer.Stop();
state = e_Idle;
return connection.OnControlProtocolError(H323Connection::e_MasterSlaveDetermination,
"Retries exceeded");
}
BOOL H245NegMasterSlaveDetermination::HandleRelease(const H245_MasterSlaveDeterminationRelease & /*pdu*/)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived MasterSlaveDeterminationRelease: state=" << state);
if (state == e_Idle)
return TRUE;
replyTimer.Stop();
state = e_Idle;
return connection.OnControlProtocolError(H323Connection::e_MasterSlaveDetermination,
"Aborted");
}
void H245NegMasterSlaveDetermination::HandleTimeout(PTimer &, INT)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tTimeout on MasterSlaveDetermination: state=" << state);
if (state == e_Outgoing) {
H323ControlPDU reply;
reply.Build(H245_IndicationMessage::e_masterSlaveDeterminationRelease);
connection.WriteControlPDU(reply);
}
state = e_Idle;
connection.OnControlProtocolError(H323Connection::e_MasterSlaveDetermination,
"Timeout");
}
#if PTRACING
const char * const H245NegMasterSlaveDetermination::StateNames[] = {
"Idle", "Outgoing", "Incoming"
};
const char * const H245NegMasterSlaveDetermination::StatusNames[] = {
"Indeterminate", "DeterminedMaster", "DeterminedSlave"
};
#endif
/////////////////////////////////////////////////////////////////////////////
H245NegTerminalCapabilitySet::H245NegTerminalCapabilitySet(H323EndPoint & end,
H323Connection & conn)
: H245Negotiator(end, conn)
{
inSequenceNumber = UINT_MAX;
outSequenceNumber = 0;
state = e_Idle;
receivedCapabilites = FALSE;
}
BOOL H245NegTerminalCapabilitySet::Start(BOOL renegotiate, BOOL empty)
{
PWaitAndSignal wait(mutex);
if (state == e_InProgress) {
PTRACE(3, "H245\tTerminalCapabilitySet already in progress: outSeq=" << outSequenceNumber);
return TRUE;
}
if (!renegotiate && state == e_Sent) {
PTRACE(3, "H245\tTerminalCapabilitySet already sent.");
return TRUE;
}
// Begin the capability exchange procedure
outSequenceNumber = (outSequenceNumber+1)%256;
replyTimer = endpoint.GetCapabilityExchangeTimeout();
state = e_InProgress;
PTRACE(3, "H245\tSending TerminalCapabilitySet: outSeq=" << outSequenceNumber);
H323ControlPDU pdu;
connection.OnSendCapabilitySet(pdu.BuildTerminalCapabilitySet(connection, outSequenceNumber, empty));
return connection.WriteControlPDU(pdu);
}
void H245NegTerminalCapabilitySet::Stop()
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tStopping TerminalCapabilitySet: state=" << state);
if (state == e_Idle)
return;
replyTimer.Stop();
state = e_Idle;
receivedCapabilites = FALSE;
}
BOOL H245NegTerminalCapabilitySet::HandleIncoming(const H245_TerminalCapabilitySet & pdu)
{
mutex.Wait();
PTRACE(3, "H245\tReceived TerminalCapabilitySet:"
" state=" << state <<
" pduSeq=" << pdu.m_sequenceNumber <<
" inSeq=" << inSequenceNumber);
if (pdu.m_sequenceNumber == inSequenceNumber) {
mutex.Signal();
PTRACE(3, "H245\tIgnoring TerminalCapabilitySet, already received sequence number");
return TRUE; // Already had this one
}
inSequenceNumber = pdu.m_sequenceNumber;
mutex.Signal();
H323Capabilities remoteCapabilities(connection, pdu);
const H245_MultiplexCapability * muxCap = NULL;
if (pdu.HasOptionalField(H245_TerminalCapabilitySet::e_multiplexCapability))
muxCap = &pdu.m_multiplexCapability;
H323ControlPDU reject;
if (connection.OnReceivedCapabilitySet(remoteCapabilities, muxCap,
reject.BuildTerminalCapabilitySetReject(inSequenceNumber,
H245_TerminalCapabilitySetReject_cause::e_unspecified))) {
receivedCapabilites = TRUE;
H323ControlPDU ack;
ack.BuildTerminalCapabilitySetAck(inSequenceNumber);
return connection.WriteControlPDU(ack);
}
connection.WriteControlPDU(reject);
connection.ClearCall(H323Connection::EndedByCapabilityExchange);
return TRUE;
}
BOOL H245NegTerminalCapabilitySet::HandleAck(const H245_TerminalCapabilitySetAck & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived TerminalCapabilitySetAck:"
" state=" << state <<
" pduSeq=" << pdu.m_sequenceNumber <<
" outSeq=" << (unsigned)outSequenceNumber);
if (state != e_InProgress)
return TRUE;
if (pdu.m_sequenceNumber != outSequenceNumber)
return TRUE;
replyTimer.Stop();
state = e_Sent;
PTRACE(2, "H245\tTerminalCapabilitySet Sent.");
return TRUE;
}
BOOL H245NegTerminalCapabilitySet::HandleReject(const H245_TerminalCapabilitySetReject & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived TerminalCapabilitySetReject:"
" state=" << state <<
" pduSeq=" << pdu.m_sequenceNumber <<
" outSeq=" << (unsigned)outSequenceNumber);
if (state != e_InProgress)
return TRUE;
if (pdu.m_sequenceNumber != outSequenceNumber)
return TRUE;
state = e_Idle;
replyTimer.Stop();
return connection.OnControlProtocolError(H323Connection::e_CapabilityExchange,
"Rejected");
}
BOOL H245NegTerminalCapabilitySet::HandleRelease(const H245_TerminalCapabilitySetRelease & /*pdu*/)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived TerminalCapabilityRelease: state=" << state);
receivedCapabilites = FALSE;
return connection.OnControlProtocolError(H323Connection::e_CapabilityExchange,
"Aborted");
}
void H245NegTerminalCapabilitySet::HandleTimeout(PTimer &, INT)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tTimeout on TerminalCapabilitySet: state=" << state);
H323ControlPDU reply;
reply.Build(H245_IndicationMessage::e_terminalCapabilitySetRelease);
connection.WriteControlPDU(reply);
connection.OnControlProtocolError(H323Connection::e_CapabilityExchange, "Timeout");
}
#if PTRACING
const char * const H245NegTerminalCapabilitySet::StateNames[] = {
"Idle", "InProgress", "Sent"
};
#endif
/////////////////////////////////////////////////////////////////////////////
H245NegLogicalChannel::H245NegLogicalChannel(H323EndPoint & end,
H323Connection & conn,
const H323ChannelNumber & chanNum)
: H245Negotiator(end, conn),
channelNumber(chanNum)
{
channel = NULL;
state = e_Released;
}
H245NegLogicalChannel::H245NegLogicalChannel(H323EndPoint & end,
H323Connection & conn,
H323Channel & chan)
: H245Negotiator(end, conn),
channelNumber(chan.GetNumber())
{
channel = &chan;
state = e_Established;
}
H245NegLogicalChannel::~H245NegLogicalChannel()
{
replyTimer.Stop();
PThread::Yield(); // Do this to avoid possible race condition with timer
mutex.Wait();
delete channel;
mutex.Signal();
}
BOOL H245NegLogicalChannel::Open(const H323Capability & capability,
unsigned sessionID,
unsigned replacementFor)
{
PWaitAndSignal wait(mutex);
return OpenWhileLocked(capability, sessionID, replacementFor);
}
BOOL H245NegLogicalChannel::OpenWhileLocked(const H323Capability & capability,
unsigned sessionID,
unsigned replacementFor)
{
if (state != e_Released && state != e_AwaitingRelease) {
PTRACE(3, "H245\tOpen of channel currently in negotiations: " << channelNumber);
return FALSE;
}
PTRACE(3, "H245\tOpening channel: " << channelNumber);
if (channel != NULL) {
channel->CleanUpOnTermination();
delete channel;
channel = NULL;
}
state = e_AwaitingEstablishment;
H323ControlPDU pdu;
H245_OpenLogicalChannel & open = pdu.BuildOpenLogicalChannel(channelNumber);
if (!capability.OnSendingPDU(open.m_forwardLogicalChannelParameters.m_dataType)) {
PTRACE(3, "H245\tOpening channel: " << channelNumber
<< ", capability.OnSendingPDU() failed");
return FALSE;
}
channel = capability.CreateChannel(connection, H323Channel::IsTransmitter, sessionID, NULL);
if (channel == NULL) {
PTRACE(3, "H245\tOpening channel: " << channelNumber
<< ", capability.CreateChannel() failed");
return FALSE;
}
channel->SetNumber(channelNumber);
if (!channel->OnSendingPDU(open)) {
PTRACE(3, "H245\tOpening channel: " << channelNumber
<< ", channel->OnSendingPDU() failed");
return FALSE;
}
if (replacementFor > 0) {
if (open.HasOptionalField(H245_OpenLogicalChannel::e_reverseLogicalChannelParameters)) {
open.m_reverseLogicalChannelParameters.IncludeOptionalField(H245_OpenLogicalChannel_reverseLogicalChannelParameters::e_replacementFor);
open.m_reverseLogicalChannelParameters.m_replacementFor = replacementFor;
}
else {
open.m_forwardLogicalChannelParameters.IncludeOptionalField(H245_OpenLogicalChannel_forwardLogicalChannelParameters::e_replacementFor);
open.m_forwardLogicalChannelParameters.m_replacementFor = replacementFor;
}
}
if (!channel->Open())
return FALSE;
if (!channel->SetInitialBandwidth()) {
PTRACE(3, "H245\tOpening channel: " << channelNumber << ", Insufficient bandwidth");
return FALSE;
}
replyTimer = endpoint.GetLogicalChannelTimeout();
return connection.WriteControlPDU(pdu);
}
BOOL H245NegLogicalChannel::Close()
{
PWaitAndSignal wait(mutex);
return CloseWhileLocked();
}
BOOL H245NegLogicalChannel::CloseWhileLocked()
{
PTRACE(3, "H245\tClosing channel: " << channelNumber << ", state=" << state);
if (state != e_AwaitingEstablishment && state != e_Established)
return TRUE;
replyTimer = endpoint.GetLogicalChannelTimeout();
H323ControlPDU reply;
if (channelNumber.IsFromRemote()) {
reply.BuildRequestChannelClose(channelNumber, H245_RequestChannelClose_reason::e_normal);
state = e_AwaitingResponse;
}
else {
reply.BuildCloseLogicalChannel(channelNumber);
state = e_AwaitingRelease;
}
return connection.WriteControlPDU(reply);
}
BOOL H245NegLogicalChannel::HandleOpen(const H245_OpenLogicalChannel & pdu)
{
PTRACE(3, "H245\tReceived open channel: " << channelNumber << ", state=" << state);
if (channel != NULL) {
channel->CleanUpOnTermination();
delete channel;
channel = NULL;
}
state = e_AwaitingEstablishment;
H323ControlPDU reply;
H245_OpenLogicalChannelAck & ack = reply.BuildOpenLogicalChannelAck(channelNumber);
BOOL ok = FALSE;
unsigned cause = H245_OpenLogicalChannelReject_cause::e_unspecified;
if (connection.OnOpenLogicalChannel(pdu, ack, cause))
channel = connection.CreateLogicalChannel(pdu, FALSE, cause);
if (channel != NULL) {
channel->SetNumber(channelNumber);
channel->OnSendOpenAck(pdu, ack);
if (channel->GetDirection() == H323Channel::IsBidirectional) {
state = e_AwaitingConfirmation;
replyTimer = endpoint.GetLogicalChannelTimeout(); // T103
ok = TRUE;
}
else {
ok = channel->Start();
if (!ok) {
// The correct protocol thing to do is reject the channel if we are
// the master. However NetMeeting will not then reopen a channel, so
// we act like we are a slave and close our end instead.
if (connection.IsH245Master() &&
connection.GetRemoteApplication().Find("NetMeeting") == P_MAX_INDEX)
cause = H245_OpenLogicalChannelReject_cause::e_masterSlaveConflict;
else {
connection.OnConflictingLogicalChannel(*channel);
ok = channel->Start();
}
}
if (ok)
state = e_Established;
}
}
if (ok)
mutex.Signal();
else {
reply.BuildOpenLogicalChannelReject(channelNumber, cause);
Release();
}
return connection.WriteControlPDU(reply);
}
BOOL H245NegLogicalChannel::HandleOpenAck(const H245_OpenLogicalChannelAck & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived open channel ack: " << channelNumber << ", state=" << state);
switch (state) {
case e_Released :
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Ack unknown channel");
case e_AwaitingEstablishment :
state = e_Established;
replyTimer.Stop();
if (!channel->OnReceivedAckPDU(pdu))
return CloseWhileLocked();
if (channel->GetDirection() == H323Channel::IsBidirectional) {
H323ControlPDU reply;
reply.BuildOpenLogicalChannelConfirm(channelNumber);
if (!connection.WriteControlPDU(reply))
return FALSE;
}
// Channel was already opened when OLC sent, if have error here it is
// somthing other than an asymmetric codec conflict, so close it down.
if (!channel->Start())
return CloseWhileLocked();
default :
break;
}
return TRUE;
}
BOOL H245NegLogicalChannel::HandleOpenConfirm(const H245_OpenLogicalChannelConfirm & /*pdu*/)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived open channel confirm: " << channelNumber << ", state=" << state);
switch (state) {
case e_Released :
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Confirm unknown channel");
case e_AwaitingEstablishment :
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Confirm established channel");
case e_AwaitingConfirmation :
replyTimer.Stop();
state = e_Established;
// Channel was already opened when OLC sent, if have error here it is
// somthing other than an asymmetric codec conflict, so close it down.
if (!channel->Start())
return CloseWhileLocked();
default :
break;
}
return TRUE;
}
BOOL H245NegLogicalChannel::HandleReject(const H245_OpenLogicalChannelReject & pdu)
{
mutex.Wait();
PTRACE(3, "H245\tReceived open channel reject: " << channelNumber << ", state=" << state);
switch (state) {
case e_Released :
mutex.Signal();
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Reject unknown channel");
case e_Established :
Release();
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Reject established channel");
case e_AwaitingEstablishment :
// Master rejected our attempt to open, so try something else.
if (pdu.m_cause.GetTag() == H245_OpenLogicalChannelReject_cause::e_masterSlaveConflict)
connection.OnConflictingLogicalChannel(*channel);
// Do next case
case e_AwaitingRelease :
Release();
break;
default :
mutex.Signal();
break;
}
return TRUE;
}
BOOL H245NegLogicalChannel::HandleClose(const H245_CloseLogicalChannel & /*pdu*/)
{
mutex.Wait();
PTRACE(3, "H245\tReceived close channel: " << channelNumber << ", state=" << state);
//if (pdu.m_source.GetTag() == H245_CloseLogicalChannel_source::e_user)
H323ControlPDU reply;
reply.BuildCloseLogicalChannelAck(channelNumber);
Release();
return connection.WriteControlPDU(reply);
}
BOOL H245NegLogicalChannel::HandleCloseAck(const H245_CloseLogicalChannelAck & /*pdu*/)
{
mutex.Wait();
PTRACE(3, "H245\tReceived close channel ack: " << channelNumber << ", state=" << state);
switch (state) {
case e_Established :
Release();
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Close ack open channel");
case e_AwaitingRelease :
Release();
break;
default :
mutex.Signal();
break;
}
return TRUE;
}
BOOL H245NegLogicalChannel::HandleRequestClose(const H245_RequestChannelClose & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived request close channel: " << channelNumber << ", state=" << state);
if (state != e_Established)
return TRUE; // Already closed
H323ControlPDU reply;
if (connection.OnClosingLogicalChannel(*channel)) {
reply.BuildRequestChannelCloseAck(channelNumber);
if (!connection.WriteControlPDU(reply))
return FALSE;
// Do normal Close procedure
replyTimer = endpoint.GetLogicalChannelTimeout();
reply.BuildCloseLogicalChannel(channelNumber);
state = e_AwaitingRelease;
if (pdu.m_reason.GetTag() == H245_RequestChannelClose_reason::e_reopen) {
PTRACE(2, "H245\tReopening channel: " << channelNumber);
connection.OpenLogicalChannel(channel->GetCapability(),
channel->GetSessionID(),
channel->GetDirection());
}
}
else
reply.BuildRequestChannelCloseReject(channelNumber);
return connection.WriteControlPDU(reply);
}
BOOL H245NegLogicalChannel::HandleRequestCloseAck(const H245_RequestChannelCloseAck & /*pdu*/)
{
mutex.Wait();
PTRACE(3, "H245\tReceived request close ack channel: " << channelNumber << ", state=" << state);
if (state == e_AwaitingResponse)
Release(); // Other end says close OK, so do so.
else
mutex.Signal();
return TRUE;
}
BOOL H245NegLogicalChannel::HandleRequestCloseReject(const H245_RequestChannelCloseReject & /*pdu*/)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived request close reject channel: " << channelNumber << ", state=" << state);
// Other end refused close, so go back to still having channel open
if (state == e_AwaitingResponse)
state = e_Established;
return TRUE;
}
BOOL H245NegLogicalChannel::HandleRequestCloseRelease(const H245_RequestChannelCloseRelease & /*pdu*/)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tReceived request close release channel: " << channelNumber << ", state=" << state);
// Other end refused close, so go back to still having channel open
state = e_Established;
return TRUE;
}
void H245NegLogicalChannel::HandleTimeout(PTimer &, INT)
{
mutex.Wait();
PTRACE(3, "H245\tTimeout on open channel: " << channelNumber << ", state=" << state);
H323ControlPDU reply;
switch (state) {
case e_AwaitingEstablishment :
reply.BuildCloseLogicalChannel(channelNumber);
connection.WriteControlPDU(reply);
break;
case e_AwaitingResponse :
reply.BuildRequestChannelCloseRelease(channelNumber);
connection.WriteControlPDU(reply);
break;
case e_Released :
mutex.Signal();
return;
default :
break;
}
Release();
connection.OnControlProtocolError(H323Connection::e_LogicalChannel, "Timeout");
}
void H245NegLogicalChannel::Release()
{
state = e_Released;
H323Channel * chan = channel;
channel = NULL;
mutex.Signal();
replyTimer.Stop();
if (chan != NULL) {
chan->CleanUpOnTermination();
delete chan;
}
}
H323Channel * H245NegLogicalChannel::GetChannel()
{
return channel;
}
#if PTRACING
const char * const H245NegLogicalChannel::StateNames[] = {
"Released",
"AwaitingEstablishment",
"Established",
"AwaitingRelease",
"AwatingConfirmation",
"AwaitingResponse"
};
#endif
/////////////////////////////////////////////////////////////////////////////
H245NegLogicalChannels::H245NegLogicalChannels(H323EndPoint & end,
H323Connection & conn)
: H245Negotiator(end, conn),
lastChannelNumber(100, FALSE)
{
}
void H245NegLogicalChannels::Add(H323Channel & channel)
{
mutex.Wait();
channels.SetAt(channel.GetNumber(), new H245NegLogicalChannel(endpoint, connection, channel));
mutex.Signal();
}
BOOL H245NegLogicalChannels::Open(const H323Capability & capability,
unsigned sessionID,
unsigned replacementFor)
{
mutex.Wait();
lastChannelNumber++;
H245NegLogicalChannel * negChan = new H245NegLogicalChannel(endpoint, connection, lastChannelNumber);
channels.SetAt(lastChannelNumber, negChan);
mutex.Signal();
return negChan->Open(capability, sessionID, replacementFor);
}
BOOL H245NegLogicalChannels::Close(unsigned channelNumber, BOOL fromRemote)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(channelNumber, fromRemote);
if (chan != NULL)
return chan->Close();
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Close unknown");
}
BOOL H245NegLogicalChannels::HandleOpen(const H245_OpenLogicalChannel & pdu)
{
H323ChannelNumber chanNum(pdu.m_forwardLogicalChannelNumber, TRUE);
H245NegLogicalChannel * chan;
mutex.Wait();
if (channels.Contains(chanNum))
chan = &channels[chanNum];
else {
chan = new H245NegLogicalChannel(endpoint, connection, chanNum);
channels.SetAt(chanNum, chan);
}
chan->mutex.Wait();
mutex.Signal();
return chan->HandleOpen(pdu);
}
BOOL H245NegLogicalChannels::HandleOpenAck(const H245_OpenLogicalChannelAck & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, FALSE);
if (chan != NULL)
return chan->HandleOpenAck(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Ack unknown");
}
BOOL H245NegLogicalChannels::HandleOpenConfirm(const H245_OpenLogicalChannelConfirm & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, TRUE);
if (chan != NULL)
return chan->HandleOpenConfirm(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Confirm unknown");
}
BOOL H245NegLogicalChannels::HandleReject(const H245_OpenLogicalChannelReject & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, FALSE);
if (chan != NULL)
return chan->HandleReject(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Reject unknown");
}
BOOL H245NegLogicalChannels::HandleClose(const H245_CloseLogicalChannel & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, TRUE);
if (chan != NULL)
return chan->HandleClose(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Close unknown");
}
BOOL H245NegLogicalChannels::HandleCloseAck(const H245_CloseLogicalChannelAck & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, FALSE);
if (chan != NULL)
return chan->HandleCloseAck(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Close Ack unknown");
}
BOOL H245NegLogicalChannels::HandleRequestClose(const H245_RequestChannelClose & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, FALSE);
if (chan != NULL)
return chan->HandleRequestClose(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Request Close unknown");
}
BOOL H245NegLogicalChannels::HandleRequestCloseAck(const H245_RequestChannelCloseAck & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, TRUE);
if (chan != NULL)
return chan->HandleRequestCloseAck(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Request Close Ack unknown");
}
BOOL H245NegLogicalChannels::HandleRequestCloseReject(const H245_RequestChannelCloseReject & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, TRUE);
if (chan != NULL)
return chan->HandleRequestCloseReject(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Request Close Reject unknown");
}
BOOL H245NegLogicalChannels::HandleRequestCloseRelease(const H245_RequestChannelCloseRelease & pdu)
{
H245NegLogicalChannel * chan = FindNegLogicalChannel(pdu.m_forwardLogicalChannelNumber, FALSE);
if (chan != NULL)
return chan->HandleRequestCloseRelease(pdu);
return connection.OnControlProtocolError(H323Connection::e_LogicalChannel,
"Request Close Release unknown");
}
H323ChannelNumber H245NegLogicalChannels::GetNextChannelNumber()
{
PWaitAndSignal wait(mutex);
lastChannelNumber++;
return lastChannelNumber;
}
H323Channel * H245NegLogicalChannels::GetChannelAt(PINDEX i)
{
mutex.Wait();
H323Channel * chan = channels.GetDataAt(i).GetChannel();
mutex.Signal();
return chan;
}
H323Channel * H245NegLogicalChannels::FindChannel(unsigned channelNumber,
BOOL fromRemote)
{
PWaitAndSignal wait(mutex);
H323ChannelNumber chanNum(channelNumber, fromRemote);
if (channels.Contains(chanNum))
return channels[chanNum].GetChannel();
return NULL;
}
H245NegLogicalChannel & H245NegLogicalChannels::GetNegLogicalChannelAt(PINDEX i)
{
PWaitAndSignal wait(mutex);
return channels.GetDataAt(i);
}
H245NegLogicalChannel * H245NegLogicalChannels::FindNegLogicalChannel(unsigned channelNumber,
BOOL fromRemote)
{
H323ChannelNumber chanNum(channelNumber, fromRemote);
mutex.Wait();
H245NegLogicalChannel * channel = channels.GetAt(chanNum);
mutex.Signal();
return channel;
}
H323Channel * H245NegLogicalChannels::FindChannelBySession(unsigned rtpSessionId,
BOOL fromRemote)
{
PWaitAndSignal wait(mutex);
PINDEX i;
H323Channel::Directions desiredDirection = fromRemote ? H323Channel::IsReceiver : H323Channel::IsTransmitter;
for (i = 0; i < GetSize(); i++) {
H323Channel * channel = channels.GetDataAt(i).GetChannel();
if (channel != NULL && channel->GetSessionID() == rtpSessionId &&
channel->GetDirection() == desiredDirection)
return channel;
}
return NULL;
}
void H245NegLogicalChannels::RemoveAll()
{
PWaitAndSignal wait(mutex);
for (PINDEX i = 0; i < channels.GetSize(); i++) {
H245NegLogicalChannel & neg = channels.GetDataAt(i);
neg.mutex.Wait();
H323Channel * channel = neg.GetChannel();
if (channel != NULL)
channel->CleanUpOnTermination();
neg.mutex.Signal();
}
channels.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
H245NegRequestMode::H245NegRequestMode(H323EndPoint & end, H323Connection & conn)
: H245Negotiator(end, conn)
{
awaitingResponse = FALSE;
inSequenceNumber = UINT_MAX;
outSequenceNumber = 0;
}
BOOL H245NegRequestMode::StartRequest(const PString & newModes)
{
PStringArray modes = newModes.Lines();
if (modes.IsEmpty())
return FALSE;
H245_ArrayOf_ModeDescription descriptions;
PINDEX modeCount = 0;
const H323Capabilities & localCapabilities = connection.GetLocalCapabilities();
for (PINDEX i = 0; i < modes.GetSize(); i++) {
H245_ModeDescription description;
PINDEX count = 0;
PStringArray caps = modes[i].Tokenise('\t');
for (PINDEX j = 0; j < caps.GetSize(); j++) {
H323Capability * capability = localCapabilities.FindCapability(caps[j]);
if (capability != NULL) {
description.SetSize(count+1);
capability->OnSendingPDU(description[count]);
count++;
}
}
if (count > 0) {
descriptions.SetSize(modeCount+1);
descriptions[modeCount] = description;
modeCount++;
}
}
if (modeCount == 0)
return FALSE;
return StartRequest(descriptions);
}
BOOL H245NegRequestMode::StartRequest(const H245_ArrayOf_ModeDescription & newModes)
{
PTRACE(1, "H245\tStarted request mode: outSeq=" << outSequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
if (awaitingResponse)
return FALSE;
// Initiate a mode request
outSequenceNumber = (outSequenceNumber+1)%256;
replyTimer = endpoint.GetRequestModeTimeout();
awaitingResponse = TRUE;
H323ControlPDU pdu;
H245_RequestMode & requestMode = pdu.BuildRequestMode(outSequenceNumber);
requestMode.m_requestedModes = newModes;
requestMode.m_requestedModes.SetConstraints(PASN_Object::FixedConstraint, 1, 256);
return connection.WriteControlPDU(pdu);
}
BOOL H245NegRequestMode::HandleRequest(const H245_RequestMode & pdu)
{
inSequenceNumber = pdu.m_sequenceNumber;
PTRACE(3, "H245\tReceived request mode: inSeq=" << inSequenceNumber);
H323ControlPDU reply_ack;
H245_RequestModeAck & ack = reply_ack.BuildRequestModeAck(inSequenceNumber,
H245_RequestModeAck_response::e_willTransmitMostPreferredMode);
H323ControlPDU reply_reject;
H245_RequestModeReject & reject = reply_reject.BuildRequestModeReject(inSequenceNumber,
H245_RequestModeReject_cause::e_modeUnavailable);
PINDEX selectedMode = 0;
if (!connection.OnRequestModeChange(pdu, ack, reject, selectedMode))
return connection.WriteControlPDU(reply_reject);
if (selectedMode != 0)
ack.m_response.SetTag(H245_RequestModeAck_response::e_willTransmitLessPreferredMode);
if (!connection.WriteControlPDU(reply_ack))
return FALSE;
connection.OnModeChanged(pdu.m_requestedModes[selectedMode]);
return TRUE;
}
BOOL H245NegRequestMode::HandleAck(const H245_RequestModeAck & pdu)
{
PTRACE(3, "H245\tReceived ack on request mode: outSeq=" << outSequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
if (awaitingResponse && pdu.m_sequenceNumber == outSequenceNumber) {
awaitingResponse = FALSE;
replyTimer.Stop();
connection.OnAcceptModeChange(pdu);
}
return TRUE;
}
BOOL H245NegRequestMode::HandleReject(const H245_RequestModeReject & pdu)
{
PTRACE(3, "H245\tReceived reject on request mode: outSeq=" << outSequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
if (awaitingResponse && pdu.m_sequenceNumber == outSequenceNumber) {
awaitingResponse = FALSE;
replyTimer.Stop();
connection.OnRefusedModeChange(&pdu);
}
return TRUE;
}
BOOL H245NegRequestMode::HandleRelease(const H245_RequestModeRelease & /*pdu*/)
{
PTRACE(3, "H245\tReceived release on request mode: inSeq=" << inSequenceNumber);
return TRUE;
}
void H245NegRequestMode::HandleTimeout(PTimer &, INT)
{
PTRACE(3, "H245\tTimeout on request mode: outSeq=" << outSequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
if (awaitingResponse) {
awaitingResponse = FALSE;
H323ControlPDU pdu;
pdu.Build(H245_IndicationMessage::e_requestModeRelease);
connection.WriteControlPDU(pdu);
connection.OnRefusedModeChange(NULL);
}
connection.OnControlProtocolError(H323Connection::e_ModeRequest, "Timeout");
}
/////////////////////////////////////////////////////////////////////////////
H245NegRoundTripDelay::H245NegRoundTripDelay(H323EndPoint & end, H323Connection & conn)
: H245Negotiator(end, conn)
{
awaitingResponse = FALSE;
sequenceNumber = 0;
// Temporary (ie quick) fix for strange Cisco behaviour. If keep trying to
// do this it stops sending RTP audio data!!
retryCount = 1;
}
BOOL H245NegRoundTripDelay::StartRequest()
{
PWaitAndSignal wait(mutex);
replyTimer = endpoint.GetRoundTripDelayTimeout();
sequenceNumber = (sequenceNumber + 1)%256;
awaitingResponse = TRUE;
PTRACE(3, "H245\tStarted round trip delay: seq=" << sequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
H323ControlPDU pdu;
pdu.BuildRoundTripDelayRequest(sequenceNumber);
if (!connection.WriteControlPDU(pdu))
return FALSE;
tripStartTime = PTimer::Tick();
return TRUE;
}
BOOL H245NegRoundTripDelay::HandleRequest(const H245_RoundTripDelayRequest & pdu)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tStarted round trip delay: seq=" << sequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
H323ControlPDU reply;
reply.BuildRoundTripDelayResponse(pdu.m_sequenceNumber);
return connection.WriteControlPDU(reply);
}
BOOL H245NegRoundTripDelay::HandleResponse(const H245_RoundTripDelayResponse & pdu)
{
PWaitAndSignal wait(mutex);
PTimeInterval tripEndTime = PTimer::Tick();
PTRACE(3, "H245\tHandling round trip delay: seq=" << sequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
if (awaitingResponse && pdu.m_sequenceNumber == sequenceNumber) {
replyTimer.Stop();
awaitingResponse = FALSE;
roundTripTime = tripEndTime - tripStartTime;
retryCount = 3;
}
return TRUE;
}
void H245NegRoundTripDelay::HandleTimeout(PTimer &, INT)
{
PWaitAndSignal wait(mutex);
PTRACE(3, "H245\tTimeout on round trip delay: seq=" << sequenceNumber
<< (awaitingResponse ? " awaitingResponse" : " idle"));
if (awaitingResponse && retryCount > 0)
retryCount--;
awaitingResponse = FALSE;
connection.OnControlProtocolError(H323Connection::e_RoundTripDelay, "Timeout");
}
/////////////////////////////////////////////////////////////////////////////