Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / h323t38.cxx
blobfedb5a8f818d5171b8f67c9f1f39a4e9ba448ec2
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 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
111 * Fixed bandwidth
113 * Revision 1.1 2001/07/17 04:44:32 robertj
114 * Partial implementation of T.120 and T.38 logical channels.
118 #include <ptlib.h>
120 #ifdef __GNUC__
121 #pragma implementation "h323t38.h"
122 #endif
124 #include "h323t38.h"
126 #include "h323con.h"
127 #include "h245.h"
128 #include "t38proto.h"
129 #include "t38.h"
130 #include "h323ep.h"
133 #define new PNEW
135 #define FAX_BIT_RATE 144 //14.4k
139 /////////////////////////////////////////////////////////////////////////////
141 H323_T38Capability::H323_T38Capability(TransportMode m)
142 : H323DataCapability(FAX_BIT_RATE),
143 mode(m)
148 PObject::Comparison H323_T38Capability::Compare(const PObject & obj) const
150 if (!PIsDescendant(&obj, H323_T38Capability))
151 return LessThan;
153 Comparison result = H323DataCapability::Compare(obj);
154 if (result != EqualTo)
155 return result;
157 PAssert(PIsDescendant(&obj, H323_T38Capability), PInvalidCast);
158 const H323_T38Capability & other = (const H323_T38Capability &)obj;
160 if (mode < other.mode)
161 return LessThan;
163 if (mode > other.mode)
164 return GreaterThan;
166 return EqualTo;
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] = {
185 "UDP", "TCP2", "TCP"
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
225 if (mode == e_UDP) {
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);
236 else {
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;
244 return TRUE;
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)
253 return FALSE;
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)
259 mode = e_UDP;
260 else {
261 const H245_T38FaxProfile & profile = fax.m_t38FaxProfile;
262 if (profile.m_t38FaxTcpOptions.m_t38TCPBidirectionalMode)
263 mode = e_SingleTCP;
264 else
265 mode = e_DualTCP;
268 return TRUE;
272 //////////////////////////////////////////////////////////////
274 static const char T38NonStandardCapabilityName[] = "T38FaxUDP";
276 H323_T38NonStandardCapability::H323_T38NonStandardCapability(BYTE country,
277 BYTE extension,
278 WORD manufacturer)
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,
315 unsigned sessionID,
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;
327 t38handler = NULL;
329 H323Channel * chan = connection.FindChannel(sessionID, dir == H323Channel::IsTransmitter);
330 if (chan != NULL) {
331 if (PIsDescendant(chan, H323_T38Channel)) {
332 PTRACE(3, "H323T38\tConnected to existing T.38 handler");
333 t38handler = ((H323_T38Channel *)chan)->GetHandler();
335 else
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()
360 if (terminating)
361 return;
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.");
378 return FALSE;
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.");
390 return FALSE;
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();
406 else {
407 PTRACE(1, "H323T38\tNo transport, aborting thread.");
410 else {
411 PTRACE(1, "H323T38\tNo protocol handler, aborting thread.");
414 if (!terminating)
415 connection.CloseLogicalChannelNumber(number);
417 PTRACE(2, "H323T38\tReceive thread ended");
421 void H323_T38Channel::Transmit()
423 if (terminating)
424 return;
426 PTRACE(2, "H323T38\tTransmit thread starting");
428 if (t38handler != NULL)
429 t38handler->Originate();
430 else {
431 PTRACE(1, "H323T38\tTransmit no proto handler");
434 if (!terminating)
435 connection.CloseLogicalChannelNumber(number);
437 PTRACE(2, "H323T38\tTransmit thread terminating");
441 BOOL H323_T38Channel::CreateTransport()
443 if (transport != NULL)
444 return TRUE;
446 if (usesTCP)
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);
457 return TRUE;
461 BOOL H323_T38Channel::CreateListener()
463 if (listener != NULL)
464 return TRUE;
466 if (usesTCP) {
467 return H323DataChannel::CreateListener();
468 PTRACE(3, "H323T38\tCreated listener " << *listener);
471 return CreateTransport();
475 /////////////////////////////////////////////////////////////////////////////