4 * H.323 T.38 logical channel establishment
8 * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.27 2004/08/24 14:23:11 csoutheren
28 * Fixed problem with plugin codecs using capability compare functions
30 * Revision 1.26 2004/05/04 03:33:33 csoutheren
31 * Added guards against comparing certain kinds of Capabilities
33 * Revision 1.25 2004/04/03 08:28:07 csoutheren
34 * Remove pseudo-RTTI and replaced with real RTTI
36 * Revision 1.24 2002/08/05 10:03:47 robertj
37 * Cosmetic changes to normalise the usage of pragma interface/implementation.
39 * Revision 1.23 2002/07/02 10:02:32 robertj
40 * Added H323TransportAddress::GetIpAddress() so don't have to provide port
41 * when you don't need it as in GetIpAndPort(),.
43 * Revision 1.22 2002/05/21 06:37:55 robertj
44 * Fixed crash if CreateT38Handler returns NULL.
46 * Revision 1.21 2002/05/15 23:29:31 robertj
47 * Backed out delete of t38 handler, causes race conditions.
49 * Revision 1.20 2002/05/15 01:31:23 robertj
50 * Added missing delete of t38 handler, thanks thsuk@digitalsis.com.
51 * Changed to allow the T.35 information to be adjusted so it will work for
52 * various vendors version of the non-standard capability.
54 * Revision 1.19 2002/05/14 08:41:31 robertj
55 * Fixed incorrect class type check for finding reverse T.38 channel and also
56 * fixed possible race condition on channel close, thanks Vyacheslav Frolov
58 * Revision 1.18 2002/05/10 05:50:02 robertj
59 * Added the max bit rate field to the data channel capability class.
60 * Added session ID to the data logical channel class.
61 * Added capability for old pre-v3 non-standard T.38.
63 * Revision 1.17 2002/04/17 00:49:04 robertj
64 * Fixed problems with T.38 start up, thanks Vyacheslav Frolov.
66 * Revision 1.16 2002/02/13 07:41:45 robertj
67 * Fixed missing setting of transport on second H323Channel, thanks Vyacheslav Frolov
69 * Revision 1.15 2002/02/09 04:39:05 robertj
70 * Changes to allow T.38 logical channels to use single transport which is
71 * now owned by the OpalT38Protocol object instead of H323Channel.
73 * Revision 1.14 2002/01/10 04:08:42 robertj
74 * Fixed missing bit rate in mode request PDU.
76 * Revision 1.13 2002/01/09 00:21:40 robertj
77 * Changes to support outgoing H.245 RequstModeChange.
79 * Revision 1.12 2002/01/01 23:27:50 craigs
80 * Added CleanupOnTermination functions
81 * Thanks to Vyacheslav Frolov
83 * Revision 1.11 2001/12/22 03:21:58 robertj
84 * Added create protocol function to H323Connection.
86 * Revision 1.10 2001/12/22 01:55:06 robertj
87 * Removed vast quatities of redundent code that is done by ancestor class.
89 * Revision 1.9 2001/12/19 09:15:43 craigs
90 * Added changes from Vyacheslav Frolov
92 * Revision 1.8 2001/12/14 08:36:36 robertj
93 * More implementation of T.38, thanks Adam Lazur
95 * Revision 1.7 2001/11/20 03:04:30 robertj
96 * Added ability to reuse t38 channels with same session ID.
98 * Revision 1.6 2001/11/09 05:39:54 craigs
99 * Added initial T.38 support thanks to Adam Lazur
101 * Revision 1.5 2001/09/12 07:48:05 robertj
102 * Fixed various problems with tracing.
104 * Revision 1.4 2001/08/06 03:08:57 robertj
105 * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
107 * Revision 1.3 2001/07/24 02:26:24 robertj
108 * Added UDP, dual TCP and single TCP modes to T.38 capability.
110 * Revision 1.2 2001/07/19 10:48:20 robertj
113 * Revision 1.1 2001/07/17 04:44:32 robertj
114 * Partial implementation of T.120 and T.38 logical channels.
121 #pragma implementation "h323t38.h"
128 #include "t38proto.h"
135 #define FAX_BIT_RATE 144 //14.4k
139 /////////////////////////////////////////////////////////////////////////////
141 H323_T38Capability::H323_T38Capability(TransportMode m
)
142 : H323DataCapability(FAX_BIT_RATE
),
148 PObject::Comparison
H323_T38Capability::Compare(const PObject
& obj
) const
150 if (!PIsDescendant(&obj
, H323_T38Capability
))
153 Comparison result
= H323DataCapability::Compare(obj
);
154 if (result
!= EqualTo
)
157 PAssert(PIsDescendant(&obj
, H323_T38Capability
), PInvalidCast
);
158 const H323_T38Capability
& other
= (const H323_T38Capability
&)obj
;
160 if (mode
< other
.mode
)
163 if (mode
> other
.mode
)
170 PObject
* H323_T38Capability::Clone() const
172 return new H323_T38Capability(*this);
176 unsigned H323_T38Capability::GetSubType() const
178 return H245_DataApplicationCapability_application::e_t38fax
;
182 PString
H323_T38Capability::GetFormatName() const
184 static const char * const modes
[NumTransportModes
] = {
187 return PString("T.38-") + modes
[mode
];
191 H323Channel
* H323_T38Capability::CreateChannel(H323Connection
& connection
,
192 H323Channel::Directions direction
,
193 unsigned int sessionID
,
194 const H245_H2250LogicalChannelParameters
* /*params*/) const
196 PTRACE(1, "H323T38\tCreateChannel, sessionID=" << sessionID
<< " direction=" << direction
);
198 return new H323_T38Channel(connection
, *this, direction
, sessionID
, mode
);
202 BOOL
H323_T38Capability::OnSendingPDU(H245_DataApplicationCapability
& pdu
) const
204 PTRACE(3, "H323T38\tOnSendingPDU for capability");
206 pdu
.m_maxBitRate
= FAX_BIT_RATE
;
207 pdu
.m_application
.SetTag(H245_DataApplicationCapability_application::e_t38fax
);
208 H245_DataApplicationCapability_application_t38fax
& fax
= pdu
.m_application
;
209 return OnSendingPDU(fax
.m_t38FaxProtocol
, fax
.m_t38FaxProfile
);
213 BOOL
H323_T38Capability::OnSendingPDU(H245_DataMode
& pdu
) const
215 pdu
.m_bitRate
= FAX_BIT_RATE
;
216 pdu
.m_application
.SetTag(H245_DataMode_application::e_t38fax
);
217 H245_DataMode_application_t38fax
& fax
= pdu
.m_application
;
218 return OnSendingPDU(fax
.m_t38FaxProtocol
, fax
.m_t38FaxProfile
);
222 BOOL
H323_T38Capability::OnSendingPDU(H245_DataProtocolCapability
& proto
,
223 H245_T38FaxProfile
& profile
) const
226 proto
.SetTag(H245_DataProtocolCapability::e_udp
);
227 profile
.m_t38FaxRateManagement
.SetTag(H245_T38FaxRateManagement::e_transferredTCF
); // recommended for UDP
229 profile
.IncludeOptionalField(H245_T38FaxProfile::e_t38FaxUdpOptions
);
230 profile
.m_t38FaxUdpOptions
.IncludeOptionalField(H245_T38FaxUdpOptions::e_t38FaxMaxBuffer
);
231 profile
.m_t38FaxUdpOptions
.m_t38FaxMaxBuffer
= 200;
232 profile
.m_t38FaxUdpOptions
.IncludeOptionalField(H245_T38FaxUdpOptions::e_t38FaxMaxDatagram
);
233 profile
.m_t38FaxUdpOptions
.m_t38FaxMaxDatagram
= 72;
234 profile
.m_t38FaxUdpOptions
.m_t38FaxUdpEC
.SetTag(H245_T38FaxUdpOptions_t38FaxUdpEC::e_t38UDPRedundancy
);
237 proto
.SetTag(H245_DataProtocolCapability::e_tcp
);
238 profile
.m_t38FaxRateManagement
.SetTag(H245_T38FaxRateManagement::e_localTCF
); // recommended for TCP
240 profile
.IncludeOptionalField(H245_T38FaxProfile::e_t38FaxTcpOptions
);
241 profile
.m_t38FaxTcpOptions
.m_t38TCPBidirectionalMode
= mode
== e_SingleTCP
;
248 BOOL
H323_T38Capability::OnReceivedPDU(const H245_DataApplicationCapability
& cap
)
250 PTRACE(3, "H323T38\tOnRecievedPDU for capability");
252 if (cap
.m_application
.GetTag() != H245_DataApplicationCapability_application::e_t38fax
)
255 const H245_DataApplicationCapability_application_t38fax
& fax
= cap
.m_application
;
256 const H245_DataProtocolCapability
& proto
= fax
.m_t38FaxProtocol
;
258 if (proto
.GetTag() == H245_DataProtocolCapability::e_udp
)
261 const H245_T38FaxProfile
& profile
= fax
.m_t38FaxProfile
;
262 if (profile
.m_t38FaxTcpOptions
.m_t38TCPBidirectionalMode
)
272 //////////////////////////////////////////////////////////////
274 static const char T38NonStandardCapabilityName
[] = "T38FaxUDP";
276 H323_T38NonStandardCapability::H323_T38NonStandardCapability(BYTE country
,
279 : H323NonStandardDataCapability(FAX_BIT_RATE
,
280 country
, extension
, manufacturer
,
281 (const BYTE
*)T38NonStandardCapabilityName
,
282 (PINDEX
)sizeof(T38NonStandardCapabilityName
)-1)
287 PObject
* H323_T38NonStandardCapability::Clone() const
289 return new H323_T38NonStandardCapability(*this);
293 class PString
H323_T38NonStandardCapability::GetFormatName() const
295 return T38NonStandardCapabilityName
;
299 H323Channel
* H323_T38NonStandardCapability::CreateChannel(H323Connection
& connection
,
300 H323Channel::Directions direction
,
301 unsigned int sessionID
,
302 const H245_H2250LogicalChannelParameters
* /*params*/) const
304 PTRACE(1, "H323T38\tCreateChannel, sessionID=" << sessionID
<< " direction=" << direction
);
306 return new H323_T38Channel(connection
, *this, direction
, sessionID
, H323_T38Capability::e_UDP
);
310 //////////////////////////////////////////////////////////////
312 H323_T38Channel::H323_T38Channel(H323Connection
& connection
,
313 const H323Capability
& capability
,
314 H323Channel::Directions dir
,
316 H323_T38Capability::TransportMode mode
)
317 : H323DataChannel(connection
, capability
, dir
, sessionID
)
319 PTRACE(3, "H323T38\tH323 channel created");
321 // Transport will be owned by OpalT38Protocol
322 autoDeleteTransport
= FALSE
;
324 separateReverseChannel
= mode
!= H323_T38Capability::e_SingleTCP
;
325 usesTCP
= mode
!= H323_T38Capability::e_UDP
;
329 H323Channel
* chan
= connection
.FindChannel(sessionID
, dir
== H323Channel::IsTransmitter
);
331 if (PIsDescendant(chan
, H323_T38Channel
)) {
332 PTRACE(3, "H323T38\tConnected to existing T.38 handler");
333 t38handler
= ((H323_T38Channel
*)chan
)->GetHandler();
336 PTRACE(1, "H323T38\tCreateChannel, channel " << *chan
<< " is not H323_T38Channel");
339 if (t38handler
== NULL
) {
340 PTRACE(3, "H323T38\tCreating new T.38 handler");
341 t38handler
= connection
.CreateT38ProtocolHandler();
344 if (t38handler
!= NULL
) {
345 transport
= t38handler
->GetTransport();
347 if (transport
== NULL
&& !usesTCP
&& CreateTransport())
348 t38handler
->SetTransport(transport
, TRUE
);
353 H323_T38Channel::~H323_T38Channel()
358 void H323_T38Channel::CleanUpOnTermination()
363 PTRACE(3, "H323T38\tCleanUpOnTermination");
365 if (t38handler
!= NULL
)
366 t38handler
->CleanUpOnTermination();
368 H323DataChannel::CleanUpOnTermination();
372 BOOL
H323_T38Channel::OnSendingPDU(H245_OpenLogicalChannel
& open
) const
374 if (t38handler
!= NULL
)
375 return H323DataChannel::OnSendingPDU(open
);
377 PTRACE(1, "H323T38\tNo protocol handler, aborting OpenLogicalChannel.");
382 BOOL
H323_T38Channel::OnReceivedPDU(const H245_OpenLogicalChannel
& open
,
383 unsigned & errorCode
)
385 if (t38handler
!= NULL
)
386 return H323DataChannel::OnReceivedPDU(open
, errorCode
);
388 errorCode
= H245_OpenLogicalChannelReject_cause::e_unspecified
;
389 PTRACE(1, "H323T38\tNo protocol handler, refusing OpenLogicalChannel.");
394 void H323_T38Channel::Receive()
396 PTRACE(2, "H323T38\tReceive thread started.");
398 if (t38handler
!= NULL
) {
399 if (listener
!= NULL
) {
400 transport
= listener
->Accept(30000); // 30 second wait for connect back
401 t38handler
->SetTransport(transport
);
404 if (transport
!= NULL
)
405 t38handler
->Answer();
407 PTRACE(1, "H323T38\tNo transport, aborting thread.");
411 PTRACE(1, "H323T38\tNo protocol handler, aborting thread.");
415 connection
.CloseLogicalChannelNumber(number
);
417 PTRACE(2, "H323T38\tReceive thread ended");
421 void H323_T38Channel::Transmit()
426 PTRACE(2, "H323T38\tTransmit thread starting");
428 if (t38handler
!= NULL
)
429 t38handler
->Originate();
431 PTRACE(1, "H323T38\tTransmit no proto handler");
435 connection
.CloseLogicalChannelNumber(number
);
437 PTRACE(2, "H323T38\tTransmit thread terminating");
441 BOOL
H323_T38Channel::CreateTransport()
443 if (transport
!= NULL
)
447 return H323DataChannel::CreateTransport();
449 PIPSocket::Address ip
;
450 if (!connection
.GetControlChannel().GetLocalAddress().GetIpAddress(ip
)) {
451 PTRACE(2, "H323T38\tTrying to use UDP when base transport is not IP");
452 PIPSocket::GetHostAddress(ip
);
455 transport
= new H323TransportUDP(connection
.GetEndPoint(), ip
);
456 PTRACE(3, "H323T38\tCreated transport: " << *transport
);
461 BOOL
H323_T38Channel::CreateListener()
463 if (listener
!= NULL
)
467 return H323DataChannel::CreateListener();
468 PTRACE(3, "H323T38\tCreated listener " << *listener
);
471 return CreateTransport();
475 /////////////////////////////////////////////////////////////////////////////