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 2.15 2007/08/05 22:34:14 hfriederich
28 * Merge from MediaTypeBranch.
31 * - Session ID replaced by OpalMediaType class
32 * - Dynamic session ID assignment in H.323 according to H.245
33 * - Attempt to dynamically handle different media types (audio / video /
34 * / fax / H.224 etc) instead of hardcoded in the core classes.
36 * - Improved propagation of media formats / options between connections
37 * - New media command implementation, uses chain-like propagation
38 * - SDP 'Capabilities' to ease handling of complex SDP parameters
40 * - New SIP Transaction handling, avoiding race conditions
41 * - Re-written H.224 implementation as an example how to add additional
42 * media types without adding code to the base classes
43 * (connection / endpoint / manager etc)
45 * This commit breaks the following code:
46 * - T38Fax implementation.
47 * - Recently added FMTP handling in MediaFormat/Option and SDP.
49 * Revision 2.14 2007/01/18 12:49:22 csoutheren
50 * Add ability to disable T.38 in compile
52 * Revision 2.13 2005/02/21 12:20:08 rjongbloed
53 * Added new "options list" to the OpalMediaFormat class.
55 * Revision 2.12 2004/04/07 08:21:10 rjongbloed
56 * Changes for new RTTI system.
58 * Revision 2.11 2002/11/10 11:33:20 robertj
59 * Updated to OpenH323 v1.10.3
61 * Revision 2.10 2002/09/04 06:01:49 robertj
62 * Updated to OpenH323 v1.9.6
64 * Revision 2.9 2002/07/01 04:56:33 robertj
65 * Updated to OpenH323 v1.9.1
67 * Revision 2.8 2002/03/22 06:57:50 robertj
68 * Updated to OpenH323 version 1.8.2
70 * Revision 2.7 2002/02/11 09:32:13 robertj
71 * Updated to openH323 v1.8.0
73 * Revision 2.6 2002/01/14 06:35:59 robertj
74 * Updated to OpenH323 v1.7.9
76 * Revision 2.5 2001/11/12 05:32:12 robertj
77 * Added OpalTransportAddress::GetIpAddress when don't need port number.
79 * Revision 2.4 2001/10/05 00:22:14 robertj
80 * Updated to PWLib 1.2.0 and OpenH323 1.7.0
82 * Revision 2.3 2001/08/13 05:10:40 robertj
83 * Updates from OpenH323 v1.6.0 release.
85 * Revision 2.2 2001/08/01 05:07:52 robertj
86 * Major changes to H.323 capabilities, uses OpalMediaFormat for base name.
88 * Revision 2.1 2001/08/01 05:05:26 robertj
89 * Major changes to H.323 capabilities, uses OpalMediaFormat for base name.
91 * Revision 2.0 2001/07/27 15:48:25 robertj
92 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
94 * Revision 1.24 2002/08/05 10:03:47 robertj
95 * Cosmetic changes to normalise the usage of pragma interface/implementation.
97 * Revision 1.23 2002/07/02 10:02:32 robertj
98 * Added H323TransportAddress::GetIpAddress() so don't have to provide port
99 * when you don't need it as in GetIpAndPort(),.
101 * Revision 1.22 2002/05/21 06:37:55 robertj
102 * Fixed crash if CreateT38Handler returns NULL.
104 * Revision 1.21 2002/05/15 23:29:31 robertj
105 * Backed out delete of t38 handler, causes race conditions.
107 * Revision 1.20 2002/05/15 01:31:23 robertj
108 * Added missing delete of t38 handler, thanks thsuk@digitalsis.com.
109 * Changed to allow the T.35 information to be adjusted so it will work for
110 * various vendors version of the non-standard capability.
112 * Revision 1.19 2002/05/14 08:41:31 robertj
113 * Fixed incorrect class type check for finding reverse T.38 channel and also
114 * fixed possible race condition on channel close, thanks Vyacheslav Frolov
116 * Revision 1.18 2002/05/10 05:50:02 robertj
117 * Added the max bit rate field to the data channel capability class.
118 * Added session ID to the data logical channel class.
119 * Added capability for old pre-v3 non-standard T.38.
121 * Revision 1.17 2002/04/17 00:49:04 robertj
122 * Fixed problems with T.38 start up, thanks Vyacheslav Frolov.
124 * Revision 1.16 2002/02/13 07:41:45 robertj
125 * Fixed missing setting of transport on second H323Channel, thanks Vyacheslav Frolov
127 * Revision 1.15 2002/02/09 04:39:05 robertj
128 * Changes to allow T.38 logical channels to use single transport which is
129 * now owned by the OpalT38Protocol object instead of H323Channel.
131 * Revision 1.14 2002/01/10 04:08:42 robertj
132 * Fixed missing bit rate in mode request PDU.
134 * Revision 1.13 2002/01/09 00:21:40 robertj
135 * Changes to support outgoing H.245 RequstModeChange.
137 * Revision 1.12 2002/01/01 23:27:50 craigs
138 * Added CleanupOnTermination functions
139 * Thanks to Vyacheslav Frolov
141 * Revision 1.11 2001/12/22 03:21:58 robertj
142 * Added create protocol function to H323Connection.
144 * Revision 1.10 2001/12/22 01:55:06 robertj
145 * Removed vast quatities of redundent code that is done by ancestor class.
147 * Revision 1.9 2001/12/19 09:15:43 craigs
148 * Added changes from Vyacheslav Frolov
150 * Revision 1.8 2001/12/14 08:36:36 robertj
151 * More implementation of T.38, thanks Adam Lazur
153 * Revision 1.7 2001/11/20 03:04:30 robertj
154 * Added ability to reuse t38 channels with same session ID.
156 * Revision 1.6 2001/11/09 05:39:54 craigs
157 * Added initial T.38 support thanks to Adam Lazur
159 * Revision 1.5 2001/09/12 07:48:05 robertj
160 * Fixed various problems with tracing.
162 * Revision 1.4 2001/08/06 03:08:57 robertj
163 * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
165 * Revision 1.3 2001/07/24 02:26:24 robertj
166 * Added UDP, dual TCP and single TCP modes to T.38 capability.
168 * Revision 1.2 2001/07/19 10:48:20 robertj
171 * Revision 1.1 2001/07/17 04:44:32 robertj
172 * Partial implementation of T.120 and T.38 logical channels.
179 #pragma implementation "h323t38.h"
182 #include <opal/buildopts.h>
186 #include <t38/h323t38.h>
188 #include <h323/h323ep.h>
189 #include <h323/h323con.h>
190 #include <h323/transaddr.h>
191 #include <asn/h245.h>
192 #include <t38/t38proto.h>
197 #define FAX_BIT_RATE 144 //14.4k
201 /////////////////////////////////////////////////////////////////////////////
203 H323_T38Capability::H323_T38Capability(TransportMode m
)
204 : H323DataCapability(FAX_BIT_RATE
),
210 PObject::Comparison
H323_T38Capability::Compare(const PObject
& obj
) const
212 Comparison result
= H323DataCapability::Compare(obj
);
213 if (result
!= EqualTo
)
216 PAssert(PIsDescendant(&obj
, H323_T38Capability
), PInvalidCast
);
217 const H323_T38Capability
& other
= (const H323_T38Capability
&)obj
;
219 if (mode
< other
.mode
)
222 if (mode
> other
.mode
)
229 PObject
* H323_T38Capability::Clone() const
231 return new H323_T38Capability(*this);
235 unsigned H323_T38Capability::GetSubType() const
237 return H245_DataApplicationCapability_application::e_t38fax
;
241 PString
H323_T38Capability::GetFormatName() const
243 static const char * const modes
[NumTransportModes
] = {
246 return PString(OPAL_T38
"{") + modes
[mode
] + '}';
250 H323Channel
* H323_T38Capability::CreateChannel(H323Connection
& connection
,
251 H323Channel::Directions direction
,
252 unsigned int sessionID
,
253 const H245_H2250LogicalChannelParameters
* /*params*/) const
255 PTRACE(1, "H323T38\tCreateChannel, sessionID=" << sessionID
<< " direction=" << direction
);
257 return new H323_T38Channel(connection
, *this, direction
, sessionID
, mode
);
261 BOOL
H323_T38Capability::OnSendingPDU(H245_DataApplicationCapability
& pdu
) const
263 PTRACE(3, "H323T38\tOnSendingPDU for capability");
265 pdu
.m_maxBitRate
= FAX_BIT_RATE
;
266 pdu
.m_application
.SetTag(H245_DataApplicationCapability_application::e_t38fax
);
267 H245_DataApplicationCapability_application_t38fax
& fax
= pdu
.m_application
;
268 return OnSendingPDU(fax
.m_t38FaxProtocol
, fax
.m_t38FaxProfile
);
272 BOOL
H323_T38Capability::OnSendingPDU(H245_DataMode
& pdu
) const
274 pdu
.m_bitRate
= FAX_BIT_RATE
;
275 pdu
.m_application
.SetTag(H245_DataMode_application::e_t38fax
);
276 H245_DataMode_application_t38fax
& fax
= pdu
.m_application
;
277 return OnSendingPDU(fax
.m_t38FaxProtocol
, fax
.m_t38FaxProfile
);
281 BOOL
H323_T38Capability::OnSendingPDU(H245_DataProtocolCapability
& proto
,
282 H245_T38FaxProfile
& profile
) const
285 proto
.SetTag(H245_DataProtocolCapability::e_udp
);
286 profile
.m_t38FaxRateManagement
.SetTag(H245_T38FaxRateManagement::e_transferredTCF
); // recommended for UDP
288 profile
.IncludeOptionalField(H245_T38FaxProfile::e_t38FaxUdpOptions
);
289 profile
.m_t38FaxUdpOptions
.IncludeOptionalField(H245_T38FaxUdpOptions::e_t38FaxMaxBuffer
);
290 profile
.m_t38FaxUdpOptions
.m_t38FaxMaxBuffer
= 200;
291 profile
.m_t38FaxUdpOptions
.IncludeOptionalField(H245_T38FaxUdpOptions::e_t38FaxMaxDatagram
);
292 profile
.m_t38FaxUdpOptions
.m_t38FaxMaxDatagram
= 72;
293 profile
.m_t38FaxUdpOptions
.m_t38FaxUdpEC
.SetTag(H245_T38FaxUdpOptions_t38FaxUdpEC::e_t38UDPRedundancy
);
296 proto
.SetTag(H245_DataProtocolCapability::e_tcp
);
297 profile
.m_t38FaxRateManagement
.SetTag(H245_T38FaxRateManagement::e_localTCF
); // recommended for TCP
299 profile
.IncludeOptionalField(H245_T38FaxProfile::e_t38FaxTcpOptions
);
300 profile
.m_t38FaxTcpOptions
.m_t38TCPBidirectionalMode
= mode
== e_SingleTCP
;
307 BOOL
H323_T38Capability::OnReceivedPDU(const H245_DataApplicationCapability
& cap
)
309 PTRACE(3, "H323T38\tOnRecievedPDU for capability");
311 if (cap
.m_application
.GetTag() != H245_DataApplicationCapability_application::e_t38fax
)
314 const H245_DataApplicationCapability_application_t38fax
& fax
= cap
.m_application
;
315 const H245_DataProtocolCapability
& proto
= fax
.m_t38FaxProtocol
;
317 if (proto
.GetTag() == H245_DataProtocolCapability::e_udp
)
320 const H245_T38FaxProfile
& profile
= fax
.m_t38FaxProfile
;
321 if (profile
.m_t38FaxTcpOptions
.m_t38TCPBidirectionalMode
)
331 //////////////////////////////////////////////////////////////
333 static const char T38NonStandardCapabilityName
[] = "T38FaxUDP";
335 H323_T38NonStandardCapability::H323_T38NonStandardCapability(BYTE country
,
338 : H323NonStandardDataCapability(FAX_BIT_RATE
,
339 country
, extension
, manufacturer
,
340 (const BYTE
*)T38NonStandardCapabilityName
,
341 sizeof(T38NonStandardCapabilityName
)-1)
346 PObject
* H323_T38NonStandardCapability::Clone() const
348 return new H323_T38NonStandardCapability(*this);
352 PString
H323_T38NonStandardCapability::GetFormatName() const
354 return PString(OPAL_T38
"{") + T38NonStandardCapabilityName
+ '}';
358 H323Channel
* H323_T38NonStandardCapability::CreateChannel(H323Connection
& connection
,
359 H323Channel::Directions direction
,
360 unsigned int sessionID
,
361 const H245_H2250LogicalChannelParameters
* /*params*/) const
363 PTRACE(1, "H323T38\tCreateChannel, sessionID=" << sessionID
<< " direction=" << direction
);
365 return new H323_T38Channel(connection
, *this, direction
, sessionID
, H323_T38Capability::e_UDP
);
369 //////////////////////////////////////////////////////////////
371 H323_T38Channel::H323_T38Channel(H323Connection
& connection
,
372 const H323Capability
& capability
,
373 H323Channel::Directions dir
,
375 H323_T38Capability::TransportMode mode
)
376 : H323DataChannel(connection
, capability
, dir
, sessionID
)
378 PTRACE(3, "H323T38\tH323 channel created");
380 // Transport will be owned by OpalT38Protocol
381 autoDeleteTransport
= FALSE
;
383 separateReverseChannel
= mode
!= H323_T38Capability::e_SingleTCP
;
384 usesTCP
= mode
!= H323_T38Capability::e_UDP
;
388 H323Channel
* chan
= connection
.FindChannel(capability
.GetMediaFormat().GetMediaType(), dir
== H323Channel::IsTransmitter
);
390 if (PIsDescendant(chan
, H323_T38Channel
)) {
391 PTRACE(3, "H323T38\tConnected to existing T.38 handler");
392 t38handler
= ((H323_T38Channel
*)chan
)->GetHandler();
395 PTRACE(1, "H323T38\tCreateChannel, channel " << *chan
<< " is not H323_T38Channel");
398 if (t38handler
== NULL
) {
399 PTRACE(3, "H323T38\tCreating new T.38 handler");
400 t38handler
= connection
.CreateT38ProtocolHandler();
403 if (t38handler
!= NULL
) {
404 transport
= t38handler
->GetTransport();
406 if (transport
== NULL
&& !usesTCP
&& CreateTransport())
407 t38handler
->SetTransport(transport
, TRUE
);
412 H323_T38Channel::~H323_T38Channel()
416 void H323_T38Channel::Close()
421 PTRACE(3, "H323T38\tCleanUpOnTermination");
423 if (t38handler
!= NULL
)
426 H323DataChannel::Close();
430 BOOL
H323_T38Channel::OnSendingPDU(H245_OpenLogicalChannel
& open
) const
432 if (t38handler
!= NULL
)
433 return H323DataChannel::OnSendingPDU(open
);
435 PTRACE(1, "H323T38\tNo protocol handler, aborting OpenLogicalChannel.");
440 BOOL
H323_T38Channel::OnReceivedPDU(const H245_OpenLogicalChannel
& open
,
441 unsigned & errorCode
)
443 if (t38handler
!= NULL
)
444 return H323DataChannel::OnReceivedPDU(open
, errorCode
);
446 errorCode
= H245_OpenLogicalChannelReject_cause::e_unspecified
;
447 PTRACE(1, "H323T38\tNo protocol handler, refusing OpenLogicalChannel.");
452 void H323_T38Channel::Receive()
454 PTRACE(2, "H323T38\tReceive thread started.");
456 if (t38handler
!= NULL
) {
457 if (listener
!= NULL
) {
458 transport
= listener
->Accept(30000); // 30 second wait for connect back
459 t38handler
->SetTransport(transport
);
462 if (transport
!= NULL
)
463 t38handler
->Answer();
465 PTRACE(1, "H323T38\tNo transport, aborting thread.");
469 PTRACE(1, "H323T38\tNo protocol handler, aborting thread.");
473 connection
.CloseLogicalChannelNumber(number
);
475 PTRACE(2, "H323T38\tReceive thread ended");
479 void H323_T38Channel::Transmit()
484 PTRACE(2, "H323T38\tTransmit thread starting");
486 if (t38handler
!= NULL
)
487 t38handler
->Originate();
489 PTRACE(1, "H323T38\tTransmit no proto handler");
493 connection
.CloseLogicalChannelNumber(number
);
495 PTRACE(2, "H323T38\tTransmit thread terminating");
499 BOOL
H323_T38Channel::CreateTransport()
501 if (transport
!= NULL
)
505 return H323DataChannel::CreateTransport();
507 PIPSocket::Address ip
;
508 if (!connection
.GetControlChannel().GetLocalAddress().GetIpAddress(ip
)) {
509 PTRACE(2, "H323T38\tTrying to use UDP when base transport is not IP");
510 PIPSocket::GetHostAddress(ip
);
513 transport
= new H323TransportUDP(connection
.GetEndPoint(), ip
);
514 PTRACE(3, "H323T38\tCreated transport: " << *transport
);
519 BOOL
H323_T38Channel::CreateListener()
521 if (listener
!= NULL
)
525 return H323DataChannel::CreateListener();
526 PTRACE(3, "H323T38\tCreated listener " << *listener
);
529 return CreateTransport();
532 #endif // OPAL_T38FAX
534 /////////////////////////////////////////////////////////////////////////////