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 / h323t38.cxx < prev    next >
C/C++ Source or Header  |  2002-08-05  |  14KB  |  464 lines

  1. /*
  2.  * h323t38.cxx
  3.  *
  4.  * H.323 T.38 logical channel establishment
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
  9.  *
  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/
  14.  *
  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.
  19.  *
  20.  * The Original Code is Open H323 Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Contributor(s): ______________________________________.
  25.  *
  26.  * $Log: h323t38.cxx,v $
  27.  * Revision 1.24  2002/08/05 10:03:47  robertj
  28.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  29.  *
  30.  * Revision 1.23  2002/07/02 10:02:32  robertj
  31.  * Added H323TransportAddress::GetIpAddress() so don't have to provide port
  32.  *   when you don't need it as in GetIpAndPort(),.
  33.  *
  34.  * Revision 1.22  2002/05/21 06:37:55  robertj
  35.  * Fixed crash if CreateT38Handler returns NULL.
  36.  *
  37.  * Revision 1.21  2002/05/15 23:29:31  robertj
  38.  * Backed out delete of t38 handler, causes race conditions.
  39.  *
  40.  * Revision 1.20  2002/05/15 01:31:23  robertj
  41.  * Added missing delete of t38 handler, thanks thsuk@digitalsis.com.
  42.  * Changed to allow the T.35 information to be adjusted so it will work for
  43.  *    various vendors version of the non-standard capability.
  44.  *
  45.  * Revision 1.19  2002/05/14 08:41:31  robertj
  46.  * Fixed incorrect class type check for finding reverse T.38 channel and also
  47.  *   fixed possible race condition on channel close, thanks Vyacheslav Frolov
  48.  *
  49.  * Revision 1.18  2002/05/10 05:50:02  robertj
  50.  * Added the max bit rate field to the data channel capability class.
  51.  * Added session ID to the data logical channel class.
  52.  * Added capability for old pre-v3 non-standard T.38.
  53.  *
  54.  * Revision 1.17  2002/04/17 00:49:04  robertj
  55.  * Fixed problems with T.38 start up, thanks Vyacheslav Frolov.
  56.  *
  57.  * Revision 1.16  2002/02/13 07:41:45  robertj
  58.  * Fixed missing setting of transport on second H323Channel, thanks Vyacheslav Frolov
  59.  *
  60.  * Revision 1.15  2002/02/09 04:39:05  robertj
  61.  * Changes to allow T.38 logical channels to use single transport which is
  62.  *   now owned by the OpalT38Protocol object instead of H323Channel.
  63.  *
  64.  * Revision 1.14  2002/01/10 04:08:42  robertj
  65.  * Fixed missing bit rate in mode request PDU.
  66.  *
  67.  * Revision 1.13  2002/01/09 00:21:40  robertj
  68.  * Changes to support outgoing H.245 RequstModeChange.
  69.  *
  70.  * Revision 1.12  2002/01/01 23:27:50  craigs
  71.  * Added CleanupOnTermination functions
  72.  * Thanks to Vyacheslav Frolov
  73.  *
  74.  * Revision 1.11  2001/12/22 03:21:58  robertj
  75.  * Added create protocol function to H323Connection.
  76.  *
  77.  * Revision 1.10  2001/12/22 01:55:06  robertj
  78.  * Removed vast quatities of redundent code that is done by ancestor class.
  79.  *
  80.  * Revision 1.9  2001/12/19 09:15:43  craigs
  81.  * Added changes from Vyacheslav Frolov
  82.  *
  83.  * Revision 1.8  2001/12/14 08:36:36  robertj
  84.  * More implementation of T.38, thanks Adam Lazur
  85.  *
  86.  * Revision 1.7  2001/11/20 03:04:30  robertj
  87.  * Added ability to reuse t38 channels with same session ID.
  88.  *
  89.  * Revision 1.6  2001/11/09 05:39:54  craigs
  90.  * Added initial T.38 support thanks to Adam Lazur
  91.  *
  92.  * Revision 1.5  2001/09/12 07:48:05  robertj
  93.  * Fixed various problems with tracing.
  94.  *
  95.  * Revision 1.4  2001/08/06 03:08:57  robertj
  96.  * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
  97.  *
  98.  * Revision 1.3  2001/07/24 02:26:24  robertj
  99.  * Added UDP, dual TCP and single TCP modes to T.38 capability.
  100.  *
  101.  * Revision 1.2  2001/07/19 10:48:20  robertj
  102.  * Fixed bandwidth
  103.  *
  104.  * Revision 1.1  2001/07/17 04:44:32  robertj
  105.  * Partial implementation of T.120 and T.38 logical channels.
  106.  *
  107.  */
  108.  
  109. #include <ptlib.h>
  110.  
  111. #ifdef __GNUC__
  112. #pragma implementation "h323t38.h"
  113. #endif
  114.  
  115. #include "h323t38.h"
  116.  
  117. #include "h323con.h"
  118. #include "h245.h"
  119. #include "t38proto.h"
  120. #include "t38.h"
  121. #include "h323ep.h"
  122.  
  123.  
  124. #define new PNEW
  125.  
  126. #define FAX_BIT_RATE 144  //14.4k
  127.  
  128.  
  129.  
  130. /////////////////////////////////////////////////////////////////////////////
  131.  
  132. H323_T38Capability::H323_T38Capability(TransportMode m)
  133.   : H323DataCapability(FAX_BIT_RATE),
  134.     mode(m)
  135. {
  136. }
  137.  
  138.  
  139. PObject::Comparison H323_T38Capability::Compare(const PObject & obj) const
  140. {
  141.   Comparison result = H323DataCapability::Compare(obj);
  142.   if (result != EqualTo)
  143.     return result;
  144.  
  145.   PAssert(obj.IsDescendant(H323_T38Capability::Class()), PInvalidCast);
  146.   const H323_T38Capability & other = (const H323_T38Capability &)obj;
  147.  
  148.   if (mode < other.mode)
  149.     return LessThan;
  150.  
  151.   if (mode > other.mode)
  152.     return GreaterThan;
  153.  
  154.   return EqualTo;
  155. }
  156.  
  157.  
  158. PObject * H323_T38Capability::Clone() const
  159. {
  160.   return new H323_T38Capability(*this);
  161. }
  162.  
  163.  
  164. unsigned H323_T38Capability::GetSubType() const
  165. {
  166.   return H245_DataApplicationCapability_application::e_t38fax;
  167. }
  168.  
  169.  
  170. PString H323_T38Capability::GetFormatName() const
  171. {
  172.   static const char * const modes[NumTransportModes] = {
  173.     "UDP", "TCP2", "TCP"
  174.   };
  175.   return PString("T.38-") + modes[mode];
  176. }
  177.  
  178.  
  179. H323Channel * H323_T38Capability::CreateChannel(H323Connection & connection,
  180.                                                 H323Channel::Directions direction,
  181.                                                 unsigned int sessionID,
  182.                              const H245_H2250LogicalChannelParameters * /*params*/) const
  183. {
  184.   PTRACE(1, "H323T38\tCreateChannel, sessionID=" << sessionID << " direction=" << direction);
  185.  
  186.   return new H323_T38Channel(connection, *this, direction, sessionID, mode);
  187. }
  188.  
  189.  
  190. BOOL H323_T38Capability::OnSendingPDU(H245_DataApplicationCapability & pdu) const
  191. {
  192.   PTRACE(3, "H323T38\tOnSendingPDU for capability");
  193.  
  194.   pdu.m_maxBitRate = FAX_BIT_RATE;
  195.   pdu.m_application.SetTag(H245_DataApplicationCapability_application::e_t38fax);
  196.   H245_DataApplicationCapability_application_t38fax & fax = pdu.m_application;
  197.   return OnSendingPDU(fax.m_t38FaxProtocol, fax.m_t38FaxProfile);
  198. }
  199.  
  200.  
  201. BOOL H323_T38Capability::OnSendingPDU(H245_DataMode & pdu) const
  202. {
  203.   pdu.m_bitRate = FAX_BIT_RATE;
  204.   pdu.m_application.SetTag(H245_DataMode_application::e_t38fax);
  205.   H245_DataMode_application_t38fax & fax = pdu.m_application;
  206.   return OnSendingPDU(fax.m_t38FaxProtocol, fax.m_t38FaxProfile);
  207. }
  208.  
  209.  
  210. BOOL H323_T38Capability::OnSendingPDU(H245_DataProtocolCapability & proto,
  211.                                       H245_T38FaxProfile & profile) const
  212. {
  213.   if (mode == e_UDP) {
  214.     proto.SetTag(H245_DataProtocolCapability::e_udp);
  215.     profile.m_t38FaxRateManagement.SetTag(H245_T38FaxRateManagement::e_transferredTCF); // recommended for UDP
  216.  
  217.     profile.IncludeOptionalField(H245_T38FaxProfile::e_t38FaxUdpOptions);
  218.     profile.m_t38FaxUdpOptions.IncludeOptionalField(H245_T38FaxUdpOptions::e_t38FaxMaxBuffer);
  219.     profile.m_t38FaxUdpOptions.m_t38FaxMaxBuffer = 200;
  220.     profile.m_t38FaxUdpOptions.IncludeOptionalField(H245_T38FaxUdpOptions::e_t38FaxMaxDatagram);
  221.     profile.m_t38FaxUdpOptions.m_t38FaxMaxDatagram = 72;
  222.     profile.m_t38FaxUdpOptions.m_t38FaxUdpEC.SetTag(H245_T38FaxUdpOptions_t38FaxUdpEC::e_t38UDPRedundancy);
  223.   }
  224.   else {
  225.     proto.SetTag(H245_DataProtocolCapability::e_tcp);
  226.     profile.m_t38FaxRateManagement.SetTag(H245_T38FaxRateManagement::e_localTCF); // recommended for TCP
  227.  
  228.     profile.IncludeOptionalField(H245_T38FaxProfile::e_t38FaxTcpOptions);
  229.     profile.m_t38FaxTcpOptions.m_t38TCPBidirectionalMode = mode == e_SingleTCP;
  230.   }
  231.  
  232.   return TRUE;
  233. }
  234.  
  235.  
  236. BOOL H323_T38Capability::OnReceivedPDU(const H245_DataApplicationCapability & cap)
  237. {
  238.   PTRACE(3, "H323T38\tOnRecievedPDU for capability");
  239.  
  240.   if (cap.m_application.GetTag() != H245_DataApplicationCapability_application::e_t38fax)
  241.     return FALSE;
  242.  
  243.   const H245_DataApplicationCapability_application_t38fax & fax = cap.m_application;
  244.   const H245_DataProtocolCapability & proto = fax.m_t38FaxProtocol;
  245.  
  246.   if (proto.GetTag() == H245_DataProtocolCapability::e_udp)
  247.     mode = e_UDP;
  248.   else {
  249.     const H245_T38FaxProfile & profile = fax.m_t38FaxProfile;
  250.     if (profile.m_t38FaxTcpOptions.m_t38TCPBidirectionalMode)
  251.       mode = e_SingleTCP;
  252.     else
  253.       mode = e_DualTCP;
  254.   }
  255.  
  256.   return TRUE;
  257. }
  258.  
  259.  
  260. //////////////////////////////////////////////////////////////
  261.  
  262. static const char T38NonStandardCapabilityName[] = "T38FaxUDP";
  263.  
  264. H323_T38NonStandardCapability::H323_T38NonStandardCapability(BYTE country,
  265.                                                              BYTE extension,
  266.                                                              WORD manufacturer)
  267.   : H323NonStandardDataCapability(FAX_BIT_RATE,
  268.                                   country, extension, manufacturer,
  269.                                   (const BYTE *)T38NonStandardCapabilityName,
  270.                                   sizeof(T38NonStandardCapabilityName)-1)
  271. {
  272. }
  273.  
  274.  
  275. PObject * H323_T38NonStandardCapability::Clone() const
  276. {
  277.   return new H323_T38NonStandardCapability(*this);
  278. }
  279.  
  280.  
  281. class PString H323_T38NonStandardCapability::GetFormatName() const
  282. {
  283.   return T38NonStandardCapabilityName;
  284. }
  285.  
  286.  
  287. H323Channel * H323_T38NonStandardCapability::CreateChannel(H323Connection & connection,
  288.                                                 H323Channel::Directions direction,
  289.                                                 unsigned int sessionID,
  290.                              const H245_H2250LogicalChannelParameters * /*params*/) const
  291. {
  292.   PTRACE(1, "H323T38\tCreateChannel, sessionID=" << sessionID << " direction=" << direction);
  293.  
  294.   return new H323_T38Channel(connection, *this, direction, sessionID, H323_T38Capability::e_UDP);
  295. }
  296.  
  297.  
  298. //////////////////////////////////////////////////////////////
  299.  
  300. H323_T38Channel::H323_T38Channel(H323Connection & connection,
  301.                                  const H323Capability & capability,
  302.                                  H323Channel::Directions dir,
  303.                                  unsigned sessionID,
  304.                                  H323_T38Capability::TransportMode mode)
  305.   : H323DataChannel(connection, capability, dir, sessionID)
  306. {
  307.   PTRACE(3, "H323T38\tH323 channel created");
  308.  
  309.   // Transport will be owned by OpalT38Protocol
  310.   autoDeleteTransport = FALSE;
  311.  
  312.   separateReverseChannel = mode != H323_T38Capability::e_SingleTCP;
  313.   usesTCP = mode != H323_T38Capability::e_UDP;
  314.  
  315.   t38handler = NULL;
  316.  
  317.   H323Channel * chan = connection.FindChannel(sessionID, dir == H323Channel::IsTransmitter);
  318.   if (chan != NULL) {
  319.     if (chan->IsDescendant(H323_T38Channel::Class())) {
  320.       PTRACE(3, "H323T38\tConnected to existing T.38 handler");
  321.       t38handler = ((H323_T38Channel *)chan)->GetHandler();
  322.     }
  323.     else
  324.       PTRACE(1, "H323T38\tCreateChannel, channel " << *chan << " is not H323_T38Channel");
  325.   }
  326.  
  327.   if (t38handler == NULL) {
  328.     PTRACE(3, "H323T38\tCreating new T.38 handler");
  329.     t38handler = connection.CreateT38ProtocolHandler();
  330.   }
  331.  
  332.   if (t38handler != NULL) {
  333.     transport = t38handler->GetTransport();
  334.  
  335.     if (transport == NULL && !usesTCP && CreateTransport())
  336.       t38handler->SetTransport(transport, TRUE);
  337.   }
  338. }
  339.  
  340.  
  341. H323_T38Channel::~H323_T38Channel()
  342. {
  343. }
  344.  
  345.  
  346. void H323_T38Channel::CleanUpOnTermination()
  347. {
  348.   if (terminating)
  349.     return;
  350.  
  351.   PTRACE(3, "H323T38\tCleanUpOnTermination");
  352.     
  353.   if (t38handler != NULL) 
  354.     t38handler->CleanUpOnTermination();
  355.  
  356.   H323DataChannel::CleanUpOnTermination();
  357. }
  358.  
  359.  
  360. BOOL H323_T38Channel::OnSendingPDU(H245_OpenLogicalChannel & open) const
  361. {
  362.   if (t38handler != NULL)
  363.     return H323DataChannel::OnSendingPDU(open);
  364.  
  365.   PTRACE(1, "H323T38\tNo protocol handler, aborting OpenLogicalChannel.");
  366.   return FALSE;
  367. }
  368.  
  369.  
  370. BOOL H323_T38Channel::OnReceivedPDU(const H245_OpenLogicalChannel & open,
  371.                                     unsigned & errorCode)
  372. {
  373.   if (t38handler != NULL)
  374.     return H323DataChannel::OnReceivedPDU(open, errorCode);
  375.  
  376.   errorCode = H245_OpenLogicalChannelReject_cause::e_unspecified;
  377.   PTRACE(1, "H323T38\tNo protocol handler, refusing OpenLogicalChannel.");
  378.   return FALSE;
  379. }
  380.  
  381.  
  382. void H323_T38Channel::Receive()
  383. {
  384.   PTRACE(2, "H323T38\tReceive thread started.");
  385.  
  386.   if (t38handler != NULL) {
  387.     if (listener != NULL) {
  388.       transport = listener->Accept(30000);  // 30 second wait for connect back
  389.       t38handler->SetTransport(transport);
  390.     }
  391.  
  392.     if (transport != NULL)
  393.       t38handler->Answer();
  394.     else {
  395.       PTRACE(1, "H323T38\tNo transport, aborting thread.");
  396.     }
  397.   }
  398.   else {
  399.     PTRACE(1, "H323T38\tNo protocol handler, aborting thread.");
  400.   }
  401.  
  402.   if (!terminating)
  403.     connection.CloseLogicalChannelNumber(number);
  404.  
  405.   PTRACE(2, "H323T38\tReceive thread ended");
  406. }
  407.  
  408.  
  409. void H323_T38Channel::Transmit()
  410. {
  411.   if (terminating)
  412.     return;
  413.  
  414.   PTRACE(2, "H323T38\tTransmit thread starting");
  415.  
  416.   if (t38handler != NULL)
  417.     t38handler->Originate();
  418.   else {
  419.     PTRACE(1, "H323T38\tTransmit no proto handler");
  420.   }
  421.  
  422.   if (!terminating)
  423.     connection.CloseLogicalChannelNumber(number);
  424.  
  425.   PTRACE(2, "H323T38\tTransmit thread terminating");
  426. }
  427.  
  428.  
  429. BOOL H323_T38Channel::CreateTransport()
  430. {
  431.   if (transport != NULL)
  432.     return TRUE;
  433.  
  434.   if (usesTCP)
  435.     return H323DataChannel::CreateTransport();
  436.  
  437.   PIPSocket::Address ip;
  438.   if (!connection.GetControlChannel().GetLocalAddress().GetIpAddress(ip)) {
  439.     PTRACE(2, "H323T38\tTrying to use UDP when base transport is not IP");
  440.     PIPSocket::GetHostAddress(ip);
  441.   }
  442.  
  443.   transport = new H323TransportUDP(connection.GetEndPoint(), ip);
  444.   PTRACE(3, "H323T38\tCreated transport: " << *transport);
  445.   return TRUE;
  446. }
  447.  
  448.  
  449. BOOL H323_T38Channel::CreateListener()
  450. {
  451.   if (listener != NULL)
  452.     return TRUE;
  453.  
  454.   if (usesTCP) {
  455.     return H323DataChannel::CreateListener();
  456.     PTRACE(3, "H323T38\tCreated listener " << *listener);
  457.   }
  458.  
  459.   return CreateTransport();
  460. }
  461.  
  462.  
  463. /////////////////////////////////////////////////////////////////////////////
  464.