Fixed DevStudio 2005 build.
[opal.git] / src / t38 / h323t38.cxx
blob1ed01806d88037e6e4cf1f19be0898f7143695b9
1 /*
2 * h323t38.cxx
4 * H.323 T.38 logical channel establishment
6 * Open H323 Library
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
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 2.15 2007/08/05 22:34:14 hfriederich
28 * Merge from MediaTypeBranch.
30 * New features:
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.
35 * (not completed yet)
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
39 * (like FMTP)
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
169 * Fixed bandwidth
171 * Revision 1.1 2001/07/17 04:44:32 robertj
172 * Partial implementation of T.120 and T.38 logical channels.
176 #include <ptlib.h>
178 #ifdef __GNUC__
179 #pragma implementation "h323t38.h"
180 #endif
182 #include <opal/buildopts.h>
184 #if OPAL_T38FAX
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>
195 #define new PNEW
197 #define FAX_BIT_RATE 144 //14.4k
201 /////////////////////////////////////////////////////////////////////////////
203 H323_T38Capability::H323_T38Capability(TransportMode m)
204 : H323DataCapability(FAX_BIT_RATE),
205 mode(m)
210 PObject::Comparison H323_T38Capability::Compare(const PObject & obj) const
212 Comparison result = H323DataCapability::Compare(obj);
213 if (result != EqualTo)
214 return result;
216 PAssert(PIsDescendant(&obj, H323_T38Capability), PInvalidCast);
217 const H323_T38Capability & other = (const H323_T38Capability &)obj;
219 if (mode < other.mode)
220 return LessThan;
222 if (mode > other.mode)
223 return GreaterThan;
225 return EqualTo;
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] = {
244 "UDP", "TCP2", "TCP"
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
284 if (mode == e_UDP) {
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);
295 else {
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;
303 return TRUE;
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)
312 return FALSE;
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)
318 mode = e_UDP;
319 else {
320 const H245_T38FaxProfile & profile = fax.m_t38FaxProfile;
321 if (profile.m_t38FaxTcpOptions.m_t38TCPBidirectionalMode)
322 mode = e_SingleTCP;
323 else
324 mode = e_DualTCP;
327 return TRUE;
331 //////////////////////////////////////////////////////////////
333 static const char T38NonStandardCapabilityName[] = "T38FaxUDP";
335 H323_T38NonStandardCapability::H323_T38NonStandardCapability(BYTE country,
336 BYTE extension,
337 WORD manufacturer)
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,
374 unsigned sessionID,
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;
386 t38handler = NULL;
388 H323Channel * chan = connection.FindChannel(capability.GetMediaFormat().GetMediaType(), dir == H323Channel::IsTransmitter);
389 if (chan != NULL) {
390 if (PIsDescendant(chan, H323_T38Channel)) {
391 PTRACE(3, "H323T38\tConnected to existing T.38 handler");
392 t38handler = ((H323_T38Channel *)chan)->GetHandler();
394 else
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()
418 if (terminating)
419 return;
421 PTRACE(3, "H323T38\tCleanUpOnTermination");
423 if (t38handler != NULL)
424 t38handler->Close();
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.");
436 return FALSE;
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.");
448 return FALSE;
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();
464 else {
465 PTRACE(1, "H323T38\tNo transport, aborting thread.");
468 else {
469 PTRACE(1, "H323T38\tNo protocol handler, aborting thread.");
472 if (!terminating)
473 connection.CloseLogicalChannelNumber(number);
475 PTRACE(2, "H323T38\tReceive thread ended");
479 void H323_T38Channel::Transmit()
481 if (terminating)
482 return;
484 PTRACE(2, "H323T38\tTransmit thread starting");
486 if (t38handler != NULL)
487 t38handler->Originate();
488 else {
489 PTRACE(1, "H323T38\tTransmit no proto handler");
492 if (!terminating)
493 connection.CloseLogicalChannelNumber(number);
495 PTRACE(2, "H323T38\tTransmit thread terminating");
499 BOOL H323_T38Channel::CreateTransport()
501 if (transport != NULL)
502 return TRUE;
504 if (usesTCP)
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);
515 return TRUE;
519 BOOL H323_T38Channel::CreateListener()
521 if (listener != NULL)
522 return TRUE;
524 if (usesTCP) {
525 return H323DataChannel::CreateListener();
526 PTRACE(3, "H323T38\tCreated listener " << *listener);
529 return CreateTransport();
532 #endif // OPAL_T38FAX
534 /////////////////////////////////////////////////////////////////////////////