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 / transports.cxx < prev    next >
Text File  |  2003-04-10  |  60KB  |  2,053 lines

  1. /*
  2.  * transports.cxx
  3.  *
  4.  * H.323 transports handler
  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.  * Portions of this code were written with the assisance of funding from
  25.  * Vovida Networks, Inc. http://www.vovida.com.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: transports.cxx,v $
  30.  * Revision 1.134  2003/04/10 09:45:34  robertj
  31.  * Added associated transport to new GetInterfaceAddresses() function so
  32.  *   interfaces can be ordered according to active transport links. Improves
  33.  *   interoperability.
  34.  * Replaced old listener GetTransportPDU() with GetInterfaceAddresses()
  35.  *   and H323SetTransportAddresses() functions.
  36.  *
  37.  * Revision 1.133  2003/04/10 00:58:54  craigs
  38.  * Added functions to access to lists of interfaces
  39.  *
  40.  * Revision 1.132  2003/03/26 06:14:31  robertj
  41.  * More IPv6 support (INADDR_ANY handling), thanks SΘbastien Josset
  42.  *
  43.  * Revision 1.131  2003/03/21 05:24:54  robertj
  44.  * Added setting of remote port in UDP transport constructor.
  45.  *
  46.  * Revision 1.130  2003/03/20 01:51:12  robertj
  47.  * More abstraction of H.225 RAS and H.501 protocols transaction handling.
  48.  *
  49.  * Revision 1.129  2003/03/11 23:15:23  robertj
  50.  * Fixed possible double delete of socket (crash) on garbage input.
  51.  *
  52.  * Revision 1.128  2003/02/06 04:31:02  robertj
  53.  * Added more support for adding things to H323TransportAddressArrays
  54.  *
  55.  * Revision 1.127  2003/02/05 01:57:18  robertj
  56.  * Fixed STUN usage on gatekeeper discovery.
  57.  *
  58.  * Revision 1.126  2003/02/04 07:06:42  robertj
  59.  * Added STUN support.
  60.  *
  61.  * Revision 1.125  2003/01/23 02:36:32  robertj
  62.  * Increased (and made configurable) timeout for H.245 channel TCP connection.
  63.  *
  64.  * Revision 1.124  2002/12/23 22:46:06  robertj
  65.  * Changed gatekeeper discovery so an GRJ does not indicate "discovered".
  66.  *
  67.  * Revision 1.123  2002/11/21 06:40:00  robertj
  68.  * Changed promiscuous mode to be three way. Fixes race condition in gkserver
  69.  *   which can cause crashes or more PDUs to be sent to the wrong place.
  70.  *
  71.  * Revision 1.122  2002/11/12 03:14:18  robertj
  72.  * Fixed gatekeeper discovery so does IP address translation correctly for
  73.  *   hosts inside the firewall.
  74.  *
  75.  * Revision 1.121  2002/11/10 08:10:44  robertj
  76.  * Moved constants for "well known" ports to better place (OPAL change).
  77.  *
  78.  * Revision 1.120  2002/11/05 00:31:48  robertj
  79.  * Prevented a failure to start separate H.245 channel stopping the call until
  80.  *   after a CONNECT is received and have no audio. At that point no H.245
  81.  *   is a useless call and we disconnect.
  82.  *
  83.  * Revision 1.119  2002/11/01 03:38:18  robertj
  84.  * More IPv6 fixes, thanks SΘbastien Josset.
  85.  *
  86.  * Revision 1.118  2002/10/29 08:30:32  robertj
  87.  * Fixed problem with simultaneous startH245 condition possibly shutting down
  88.  *   the call under some circumstances.
  89.  *
  90.  * Revision 1.117  2002/10/16 06:28:20  robertj
  91.  * More IPv6 support changes, especially in unambiguising v6 addresses colons
  92.  *   from the port fields colon, thanks Sebastien Josset
  93.  *
  94.  * Revision 1.116  2002/10/08 23:34:30  robertj
  95.  * Fixed ip v6 usage on H.245 pdu setting.
  96.  *
  97.  * Revision 1.115  2002/10/08 13:08:21  robertj
  98.  * Changed for IPv6 support, thanks SΘbastien Josset.
  99.  *
  100.  * Revision 1.114  2002/08/05 10:03:48  robertj
  101.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  102.  *
  103.  * Revision 1.113  2002/08/05 05:17:41  robertj
  104.  * Fairly major modifications to support different authentication credentials
  105.  *   in ARQ to the logged in ones on RRQ. For both client and server.
  106.  * Various other H.235 authentication bugs and anomalies fixed on the way.
  107.  *
  108.  * Revision 1.112  2002/07/22 09:40:19  robertj
  109.  * Added ability to automatically convert string arrays, lists sorted lists
  110.  *   directly to H323TransportAddressArray.
  111.  *
  112.  * Revision 1.111  2002/07/18 08:25:47  robertj
  113.  * Fixed problem in decoding host when '+' was used without port in address.
  114.  *
  115.  * Revision 1.110  2002/07/10 01:23:33  robertj
  116.  * Added extra debugging output
  117.  *
  118.  * Revision 1.109  2002/07/02 10:02:32  robertj
  119.  * Added H323TransportAddress::GetIpAddress() so don't have to provide port
  120.  *   when you don't need it as in GetIpAndPort(),.
  121.  *
  122.  * Revision 1.108  2002/06/28 03:34:29  robertj
  123.  * Fixed issues with address translation on gatekeeper RAS channel.
  124.  *
  125.  * Revision 1.107  2002/06/24 07:35:23  robertj
  126.  * Fixed ability to do gk discovery on localhost, thanks Artis Kugevics
  127.  *
  128.  * Revision 1.106  2002/06/12 03:52:27  robertj
  129.  * Added function to compare two transport addresses in a more intelligent
  130.  *   way that strict string comparison. Takes into account wildcarding.
  131.  *
  132.  * Revision 1.105  2002/05/28 06:38:08  robertj
  133.  * Split UDP (for RAS) from RTP port bases.
  134.  * Added current port variable so cycles around the port range specified which
  135.  *   fixes some wierd problems on some platforms, thanks Federico Pinna
  136.  *
  137.  * Revision 1.104  2002/05/22 07:39:59  robertj
  138.  * Fixed double increment of port number when making outgoing TCP connection.
  139.  *
  140.  * Revision 1.103  2002/04/18 00:18:58  robertj
  141.  * Increased timeout for thread termination assert, on heavily loaded machines it can
  142.  *   take more than one second to complete.
  143.  *
  144.  * Revision 1.102  2002/04/17 05:36:38  robertj
  145.  * Fixed problems with using pre-bound inferface/port in gk discovery.
  146.  *
  147.  * Revision 1.101  2002/04/12 04:51:28  robertj
  148.  * Fixed small possibility crashes if open and close transport at same time.
  149.  *
  150.  * Revision 1.100  2002/03/08 01:22:30  robertj
  151.  * Fixed possible use of IsSuspended() on terminated thread causing assert.
  152.  *
  153.  * Revision 1.99  2002/03/05 04:49:41  robertj
  154.  * Fixed leak of thread (and file handles) if get incoming connection aborted
  155.  *   very early (before receiving a setup PDU), thanks Hans Bjurstr÷m
  156.  *
  157.  * Revision 1.98  2002/02/28 04:35:43  robertj
  158.  * Added trace output of the socket handle number when have new connection.
  159.  *
  160.  * Revision 1.97  2002/02/28 00:57:03  craigs
  161.  * Changed SetWriteTimeout to SetReadTimeout in connect, as Craig got it wrong!
  162.  *
  163.  * Revision 1.96  2002/02/25 10:55:33  robertj
  164.  * Added ability to speficy dynamically allocated port in transport address.
  165.  *
  166.  * Revision 1.95  2002/02/14 03:36:14  craigs
  167.  * Added default 10sec timeout on connect to IP addresses
  168.  * This prevents indefinite hangs when connecting to IP addresses
  169.  * that don't exist
  170.  *
  171.  * Revision 1.94  2002/02/05 23:29:09  robertj
  172.  * Changed default for H.323 listener to reuse addresses.
  173.  *
  174.  * Revision 1.93  2002/02/01 01:48:18  robertj
  175.  * Fixed ability to shut down a Listener, if it had never been started.
  176.  *
  177.  * Revision 1.92  2002/01/02 06:06:43  craigs
  178.  * Made T.38 UDP socket obey rules
  179.  *
  180.  * Revision 1.91  2001/12/22 01:48:40  robertj
  181.  * Added ability to use local and remote port from transport channel as well
  182.  *   as explicit port in H.245 address PDU setting routine.
  183.  * Added PrintOn() to listener and transport for tracing purposes.
  184.  *
  185.  * Revision 1.90  2001/12/15 07:12:22  robertj
  186.  * Added optimisation so if discovering a static gk on same machine as ep is
  187.  *   running on then uses that specific interface preventing multiple GRQs.
  188.  *
  189.  * Revision 1.89  2001/10/11 07:16:49  robertj
  190.  * Removed port check for gk's that change sockets in mid-stream.
  191.  *
  192.  * Revision 1.88  2001/10/09 12:41:20  robertj
  193.  * Set promiscuous flag back to FALSE after gatkeeper discovery.
  194.  *
  195.  * Revision 1.87  2001/09/10 03:06:29  robertj
  196.  * Major change to fix problem with error codes being corrupted in a
  197.  *   PChannel when have simultaneous reads and writes in threads.
  198.  *
  199.  * Revision 1.86  2001/08/10 11:03:52  robertj
  200.  * Major changes to H.235 support in RAS to support server.
  201.  *
  202.  * Revision 1.85  2001/08/07 02:57:52  robertj
  203.  * Improved tracing on closing transport.
  204.  *
  205.  * Revision 1.84  2001/08/06 03:08:57  robertj
  206.  * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
  207.  *
  208.  * Revision 1.83  2001/07/17 04:44:32  robertj
  209.  * Partial implementation of T.120 and T.38 logical channels.
  210.  *
  211.  * Revision 1.82  2001/07/06 02:31:15  robertj
  212.  * Made sure a release complete is sent if no connection is created.
  213.  *
  214.  * Revision 1.81  2001/07/04 09:02:07  robertj
  215.  * Added more tracing
  216.  *
  217.  * Revision 1.80  2001/06/25 05:50:22  robertj
  218.  * Improved error logging on TCP listener.
  219.  *
  220.  * Revision 1.79  2001/06/25 02:28:34  robertj
  221.  * Allowed TCP listener socket to be opened in non-exclusive mode
  222.  *   (ie SO_REUSEADDR) to avoid daemon restart problems.
  223.  * Added trailing '+' on H323TransportAddress string to invoke above.
  224.  *
  225.  * Revision 1.78  2001/06/22 02:47:12  robertj
  226.  * Took one too many lines out in previous fix!
  227.  *
  228.  * Revision 1.77  2001/06/22 02:40:27  robertj
  229.  * Fixed discovery so uses new promiscuous mode.
  230.  * Also used the RAS GRQ address of server isntead of UDP return address
  231.  *   for address of gatekeeper for future packets.
  232.  *
  233.  * Revision 1.76  2001/06/22 01:54:47  robertj
  234.  * Removed initialisation of localAddress to hosts IP address, does not
  235.  *   work on multi-homed hosts.
  236.  *
  237.  * Revision 1.75  2001/06/22 00:14:46  robertj
  238.  * Added ConnectTo() function to conencto specific address.
  239.  * Added promiscuous mode for UDP channel.
  240.  *
  241.  * Revision 1.74  2001/06/14 23:18:06  robertj
  242.  * Change to allow for CreateConnection() to return NULL to abort call.
  243.  *
  244.  * Revision 1.73  2001/06/14 04:23:32  robertj
  245.  * Changed incoming call to pass setup pdu to endpoint so it can create
  246.  *   different connection subclasses depending on the pdu eg its alias
  247.  *
  248.  * Revision 1.72  2001/06/06 00:29:54  robertj
  249.  * Added trace for when doing TCP connect.
  250.  *
  251.  * Revision 1.71  2001/06/02 01:35:32  robertj
  252.  * Added thread names.
  253.  *
  254.  * Revision 1.70  2001/05/31 07:16:52  craigs
  255.  * Fixed remote address initialisation for incoming H245 channels
  256.  *
  257.  * Revision 1.69  2001/05/17 06:37:04  robertj
  258.  * Added multicast gatekeeper discovery support.
  259.  *
  260.  * Revision 1.68  2001/04/13 07:44:51  robertj
  261.  * Moved starting connection trace message to be on both Connect() and Accept()
  262.  *
  263.  * Revision 1.67  2001/04/10 01:21:02  robertj
  264.  * Added some more error messages into trace log.
  265.  *
  266.  * Revision 1.66  2001/04/09 08:44:19  robertj
  267.  * Added ability to get transport address for a listener.
  268.  * Added '*' to indicate INADDR_ANY ip address.
  269.  *
  270.  * Revision 1.65  2001/03/06 05:03:00  robertj
  271.  * Changed H.245 channel start failure so does not abort call if there were
  272.  *   some fast started media streams opened. Just lose user indications.
  273.  *
  274.  * Revision 1.64  2001/03/05 04:28:50  robertj
  275.  * Added net mask to interface info returned by GetInterfaceTable()
  276.  *
  277.  * Revision 1.63  2001/02/09 05:13:56  craigs
  278.  * Added pragma implementation to (hopefully) reduce the executable image size
  279.  * under Linux
  280.  *
  281.  * Revision 1.62  2001/02/08 22:29:39  robertj
  282.  * Fixed failure to reset fill character in trace log when output interface list.
  283.  *
  284.  * Revision 1.61  2001/01/29 06:43:32  robertj
  285.  * Added printing of entry of interface table.
  286.  *
  287.  * Revision 1.60  2001/01/23 05:06:52  robertj
  288.  * Fixed bug when trying to clear call while waiting on H.245 channel connect, thanks Yura Aksyonov.
  289.  * Fixed missing increment in H.245 listener when specified local port number range.
  290.  *
  291.  * Revision 1.59  2001/01/11 06:41:01  craigs
  292.  * Fixed problem with outgoing sockets failing because of port in use
  293.  *
  294.  * Revision 1.58  2000/12/18 08:59:20  craigs
  295.  * Added ability to set ports
  296.  *
  297.  * Revision 1.57  2000/11/06 06:19:19  robertj
  298.  * Removed reverse DNS lookup for host name as this can cause HUGE delays in
  299.  *    call setup making it look like a call failure.
  300.  *
  301.  * Revision 1.56  2000/10/20 06:18:49  robertj
  302.  * Fixed very small race condition on creating new connectionon incoming call.
  303.  * Fixed memory/socket leak if do TCP connect and don't send valid setup PDU.
  304.  *
  305.  * Revision 1.55  2000/10/04 12:21:07  robertj
  306.  * Changed setting of callToken in H323Connection to be as early as possible.
  307.  *
  308.  * Revision 1.54  2000/10/04 05:59:26  robertj
  309.  * Minor reorganisation of the H.245 secondary channel start up to make it simpler
  310.  *    to override its behaviour.
  311.  *
  312.  * Revision 1.53  2000/09/25 12:59:34  robertj
  313.  * Added StartListener() function that takes a H323TransportAddress to start
  314.  *     listeners bound to specific interfaces.
  315.  *
  316.  * Revision 1.52  2000/08/31 13:14:10  robertj
  317.  * Increased timeout on assert for stuck transport thread.
  318.  *
  319.  * Revision 1.51  2000/08/25 01:10:28  robertj
  320.  * Added assert if various thrads ever fail to terminate.
  321.  *
  322.  * Revision 1.50  2000/08/22 09:01:06  robertj
  323.  * Fixed small window in which control channel could do write through NULL pointer.
  324.  *
  325.  * Revision 1.49  2000/07/10 16:11:49  robertj
  326.  * Fixed inclusion of interfaces with no IP address in GK registration.
  327.  * Fixed possible crash when closing connection during H.245 TCP connect wait.
  328.  *
  329.  * Revision 1.48  2000/06/20 02:38:28  robertj
  330.  * Changed H323TransportAddress to default to IP.
  331.  *
  332.  * Revision 1.47  2000/06/07 05:48:06  robertj
  333.  * Added call forwarding.
  334.  *
  335.  * Revision 1.46  2000/05/23 02:38:15  robertj
  336.  * Shortened the linger onTCP close to 3 seconds, should be adequate for lst end session transmit.
  337.  *
  338.  * Revision 1.45  2000/05/22 05:21:36  robertj
  339.  * Fixed race condition where controlChannel variable could be used before set.
  340.  *
  341.  * Revision 1.44  2000/05/10 05:14:53  robertj
  342.  * Fixed memory leak when doing GK discovery.
  343.  *
  344.  * Revision 1.43  2000/05/08 14:07:35  robertj
  345.  * Improved the provision and detection of calling and caller numbers, aliases and hostnames.
  346.  *
  347.  * Revision 1.42  2000/05/05 04:37:50  robertj
  348.  * Changed TCP transmit of PDU to not use Nagle algorithm delay, this gives
  349.  *     a significant performance benefit for packet based stuff on stream based TCP.
  350.  *
  351.  * Revision 1.41  2000/05/02 04:32:28  robertj
  352.  * Fixed copyright notice comment.
  353.  *
  354.  * Revision 1.40  2000/04/19 01:59:21  robertj
  355.  * Improved some debugging messages.
  356.  * Added code to restore transport state if gatekeeper discovery fails.
  357.  *
  358.  * Revision 1.39  2000/04/14 17:32:39  robertj
  359.  * Changed transport to return some error number when getting malformed TPKT.
  360.  *
  361.  * Revision 1.38  2000/04/11 03:57:25  robertj
  362.  * Fixed uninitialised variabel giving random port numbers for some PDU's (rare).
  363.  *
  364.  * Revision 1.37  2000/04/10 17:41:46  robertj
  365.  * Changed transport address so does not do reverse DNS lookup, can really slow things down on some systems.
  366.  *
  367.  * Revision 1.36  2000/03/29 02:14:46  robertj
  368.  * Changed TerminationReason to CallEndReason to use correct telephony nomenclature.
  369.  * Added CallEndReason for capability exchange failure.
  370.  *
  371.  * Revision 1.35  2000/03/25 02:02:25  robertj
  372.  * Added adjustable caller name on connection by connection basis.
  373.  *
  374.  * Revision 1.34  2000/02/09 00:00:53  robertj
  375.  * Fixed TCP listener socket error message going to stderr, should go through PTRACE.
  376.  *
  377.  * Revision 1.33  2000/01/29 07:13:33  robertj
  378.  * Fixed possible incorect port being used when GK RAS send address set to the
  379.  *    IP address of the responding GK, thanks Stefan Ditscheid.
  380.  *
  381.  * Revision 1.32  2000/01/07 08:24:01  robertj
  382.  * Added transport independent MakeCall requiring change to transport string format
  383.  *
  384.  * Revision 1.31  1999/12/09 21:46:42  robertj
  385.  * Fixed detection of bound interface in gatekeeper discovery (can't use getsockname!)
  386.  *
  387.  * Revision 1.30  1999/12/09 20:25:41  robertj
  388.  * Changed UDP transport to only do gatekeeper discovery on bound interface (if present)
  389.  *
  390.  * Revision 1.29  1999/11/22 00:56:35  robertj
  391.  * Improved reason display for connection failure.
  392.  *
  393.  * Revision 1.28  1999/11/18 12:51:20  robertj
  394.  * Fixed bug that termination connections incorrectly while awaiting answer.
  395.  *
  396.  * Revision 1.27  1999/11/06 05:37:45  robertj
  397.  * Complete rewrite of termination of connection to avoid numerous race conditions.
  398.  *
  399.  * Revision 1.26  1999/10/28 11:17:38  robertj
  400.  * Fixed bug causing delete of deleted object, thanks Benny Prijono
  401.  *
  402.  * Revision 1.25  1999/10/16 03:47:49  robertj
  403.  * Fixed termination of gatekeeper RAS thread problem
  404.  *
  405.  * Revision 1.24  1999/10/14 12:04:11  robertj
  406.  * Fixed ability to hang up call when still doing TCP connect.
  407.  *
  408.  * Revision 1.23  1999/10/13 04:32:41  robertj
  409.  * Fixed missing port number from gatekeeper discovery.
  410.  * Added removal of redundent transport listeners in H225 PDU.
  411.  *
  412.  * Revision 1.22  1999/10/10 14:12:06  robertj
  413.  * Fixed failure to clean up connection if call is refused by user.
  414.  *
  415.  * Revision 1.21  1999/10/10 08:59:47  robertj
  416.  * no message
  417.  *
  418.  * Revision 1.20  1999/09/27 01:37:23  robertj
  419.  * BeOS port issues
  420.  *
  421.  * Revision 1.19  1999/09/17 07:26:17  robertj
  422.  * Fixed attempt to broadcast to down interfaces or ones not bound to IP protocol.
  423.  *
  424.  * Revision 1.18  1999/09/14 08:19:37  robertj
  425.  * Fixed timeout on retry of gatekeeper discover and added more tracing.
  426.  *
  427.  * Revision 1.17  1999/09/14 06:52:54  robertj
  428.  * Added better support for multi-homed client hosts.
  429.  *
  430.  * Revision 1.16  1999/09/10 09:43:59  robertj
  431.  * Removed attempt at determining local interface for gatekeeper, so still has problem on multi-homed hosts.
  432.  *
  433.  * Revision 1.15  1999/09/02 15:25:39  robertj
  434.  * Old GNU C ompiler compatibility
  435.  *
  436.  * Revision 1.14  1999/08/31 12:34:19  robertj
  437.  * Added gatekeeper support.
  438.  *
  439.  * Revision 1.13  1999/08/31 11:37:30  robertj
  440.  * Fixed problem with apparently randomly losing signalling channel.
  441.  *
  442.  * Revision 1.12  1999/08/25 05:12:23  robertj
  443.  * Changed MakeCall, so immediately spawns thread, no black on TCP connect.
  444.  *
  445.  * Revision 1.11  1999/07/23 02:37:53  robertj
  446.  * Fixed problems with hang ups and crash closes of connections.
  447.  *
  448.  * Revision 1.10  1999/07/22 14:34:16  robertj
  449.  * Fixed shut down problem, terminate packets being flushed on exit.
  450.  *
  451.  * Revision 1.9  1999/07/15 14:45:36  robertj
  452.  * Added propagation of codec open error to shut down logical channel.
  453.  * Fixed control channel start up bug introduced with tunnelling.
  454.  *
  455.  * Revision 1.8  1999/07/14 06:06:14  robertj
  456.  * Fixed termination problems (race conditions) with deleting connection object.
  457.  *
  458.  * Revision 1.7  1999/07/09 06:09:52  robertj
  459.  * Major implementation. An ENORMOUS amount of stuff added everywhere.
  460.  *
  461.  * Revision 1.6  1999/06/25 10:25:35  robertj
  462.  * Added maintentance of callIdentifier variable in H.225 channel.
  463.  *
  464.  * Revision 1.5  1999/06/22 13:42:05  robertj
  465.  * Added user question on listener version to accept incoming calls.
  466.  *
  467.  * Revision 1.4  1999/06/14 08:42:30  robertj
  468.  * GNU C++ compatibility
  469.  *
  470.  * Revision 1.3  1999/06/13 12:41:14  robertj
  471.  * Implement logical channel transmitter.
  472.  * Fixed H245 connect on receiving call.
  473.  *
  474.  * Revision 1.2  1999/06/09 06:18:01  robertj
  475.  * GCC compatibiltiy.
  476.  *
  477.  * Revision 1.1  1999/06/09 05:26:20  robertj
  478.  * Major restructuring of classes.
  479.  *
  480.  */
  481.  
  482. #include <ptlib.h>
  483.  
  484. #ifdef __GNUC__
  485. #pragma implementation "transports.h"
  486. #endif
  487.  
  488. #include "transports.h"
  489.  
  490. #include "h323pdu.h"
  491. #include "h323ep.h"
  492. #include "gkclient.h"
  493.  
  494. #include <ptclib/pstun.h>
  495.  
  496.  
  497. class H225TransportThread : public PThread
  498. {
  499.   PCLASSINFO(H225TransportThread, PThread)
  500.  
  501.   public:
  502.     H225TransportThread(H323EndPoint & endpoint, H323Transport * transport);
  503.  
  504.   protected:
  505.     void Main();
  506.  
  507.     H323Transport * transport;
  508. };
  509.  
  510.  
  511. class H245TransportThread : public PThread
  512. {
  513.   PCLASSINFO(H245TransportThread, PThread)
  514.  
  515.   public:
  516.     H245TransportThread(H323EndPoint & endpoint,
  517.                         H323Connection & connection,
  518.                         H323Transport & transport);
  519.  
  520.   protected:
  521.     void Main();
  522.  
  523.     H323Connection & connection;
  524.     H323Transport  & transport;
  525. };
  526.  
  527.  
  528. #define new PNEW
  529.  
  530.  
  531. /////////////////////////////////////////////////////////////////////////////
  532.  
  533. H225TransportThread::H225TransportThread(H323EndPoint & ep, H323Transport * t)
  534.   : PThread(ep.GetSignallingThreadStackSize(),
  535.             AutoDeleteThread,
  536.             NormalPriority,
  537.             "H225 Answer:%0x"),
  538.     transport(t)
  539. {
  540.   Resume();
  541. }
  542.  
  543.  
  544. void H225TransportThread::Main()
  545. {
  546.   PTRACE(3, "H225\tStarted incoming call thread");
  547.  
  548.   if (!transport->HandleFirstSignallingChannelPDU())
  549.     delete transport;
  550. }
  551.  
  552. /////////////////////////////////////////////////////////////////////////////
  553.  
  554. H245TransportThread::H245TransportThread(H323EndPoint & endpoint,
  555.                                          H323Connection & c,
  556.                                          H323Transport & t)
  557.   : PThread(endpoint.GetSignallingThreadStackSize(),
  558.             NoAutoDeleteThread,
  559.             NormalPriority,
  560.             "H245:%0x"),
  561.     connection(c),
  562.     transport(t)
  563. {
  564.   transport.AttachThread(this);
  565.   Resume();
  566. }
  567.  
  568.  
  569. void H245TransportThread::Main()
  570. {
  571.   PTRACE(3, "H245\tStarted thread");
  572.  
  573.   if (transport.AcceptControlChannel(connection))
  574.     connection.HandleControlChannel();
  575. }
  576.  
  577.  
  578. /////////////////////////////////////////////////////////////////////////////
  579.  
  580. static const char IpPrefix[] = "ip$";
  581.  
  582. H323TransportAddress::H323TransportAddress(const char * cstr)
  583.   : PString(cstr)
  584. {
  585.   Validate();
  586. }
  587.  
  588.  
  589. H323TransportAddress::H323TransportAddress(const PString & str)
  590.   : PString(str)
  591. {
  592.   Validate();
  593. }
  594.  
  595.  
  596. static PString BuildIP(const PIPSocket::Address & ip, unsigned port)
  597. {
  598.   PStringStream str;
  599.  
  600.   str << IpPrefix;
  601.  
  602.   if (!ip.IsValid())
  603.     str << '*';
  604.   else
  605. #if P_HAS_IPV6
  606.   if (ip.GetVersion() == 6)
  607.     str << '[' << ip << ']';
  608.   else
  609. #endif
  610.     str << ip;
  611.  
  612.   if (port != 0)
  613.     str << ':' << port;
  614.  
  615.   return str;
  616. }
  617.  
  618.  
  619. H323TransportAddress::H323TransportAddress(const H225_TransportAddress & transport)
  620. {
  621.   switch (transport.GetTag()) {
  622.     case H225_TransportAddress::e_ipAddress :
  623.     {
  624.       const H225_TransportAddress_ipAddress & ip = transport;
  625.       *this = BuildIP(PIPSocket::Address(ip.m_ip.GetSize(), ip.m_ip.GetValue()), ip.m_port);
  626.       break;
  627.     }
  628. #if P_HAS_IPV6
  629.     case H225_TransportAddress::e_ip6Address :
  630.     {
  631.       const H225_TransportAddress_ip6Address & ip = transport;
  632.       *this = BuildIP(PIPSocket::Address(ip.m_ip.GetSize(), ip.m_ip.GetValue()), ip.m_port);
  633.       break;
  634.     }
  635. #endif
  636.   }
  637. }
  638.  
  639.  
  640. H323TransportAddress::H323TransportAddress(const H245_TransportAddress & transport)
  641. {
  642.   switch (transport.GetTag()) {
  643.     case H245_TransportAddress::e_unicastAddress :
  644.     {
  645.       const H245_UnicastAddress & unicast = transport;
  646.       switch (unicast.GetTag()) {
  647.         case H245_UnicastAddress::e_iPAddress :
  648.         {
  649.           const H245_UnicastAddress_iPAddress & ip = unicast;
  650.           *this = BuildIP(PIPSocket::Address(ip.m_network.GetSize(), ip.m_network.GetValue()), ip.m_tsapIdentifier);
  651.           break;
  652.         }
  653. #if P_HAS_IPV6
  654.         case H245_UnicastAddress::e_iP6Address :
  655.         {
  656.           const H245_UnicastAddress_iP6Address & ip = unicast;
  657.           *this = BuildIP(PIPSocket::Address(ip.m_network.GetSize(), ip.m_network.GetValue()), ip.m_tsapIdentifier);
  658.           break;
  659.         }
  660. #endif
  661.       }
  662.       break;
  663.     }
  664.   }
  665. }
  666.  
  667.  
  668. H323TransportAddress::H323TransportAddress(const PIPSocket::Address & ip, WORD port)
  669. {
  670.   *this = BuildIP(ip, port);
  671. }
  672.  
  673.  
  674. void H323TransportAddress::Validate()
  675. {
  676.   if (IsEmpty())
  677.     return;
  678.  
  679.   if (Find('$') == P_MAX_INDEX) {
  680.     Splice(IpPrefix, 0, 0);
  681.     return;
  682.   }
  683.  
  684.   if (strncmp(theArray, IpPrefix, 3) == 0) {
  685.     return;
  686.   }
  687.  
  688.   *this = PString();
  689. }
  690.  
  691.  
  692. BOOL H323TransportAddress::SetPDU(H225_TransportAddress & pdu) const
  693. {
  694.   PIPSocket::Address ip;
  695.   WORD port = H323EndPoint::DefaultTcpPort;
  696.   if (GetIpAndPort(ip, port)) {
  697. #if P_HAS_IPV6
  698.     if (ip.GetVersion() == 6) {
  699.       pdu.SetTag(H225_TransportAddress::e_ip6Address);
  700.       H225_TransportAddress_ip6Address & addr = pdu;
  701.       for (PINDEX i = 0; i < ip.GetSize(); i++)
  702.         addr.m_ip[i] = ip[i];
  703.       addr.m_port = port;
  704.       return TRUE;
  705.     }
  706. #endif
  707.  
  708.     pdu.SetTag(H225_TransportAddress::e_ipAddress);
  709.     H225_TransportAddress_ipAddress & addr = pdu;
  710.     for (PINDEX i = 0; i < 4; i++)
  711.       addr.m_ip[i] = ip[i];
  712.     addr.m_port = port;
  713.     return TRUE;
  714.   }
  715.  
  716.   return FALSE;
  717. }
  718.  
  719.  
  720. BOOL H323TransportAddress::SetPDU(H245_TransportAddress & pdu) const
  721. {
  722.   PIPSocket::Address ip;
  723.   WORD port = 0;
  724.   if (GetIpAndPort(ip, port)) {
  725.     pdu.SetTag(H245_TransportAddress::e_unicastAddress);
  726.  
  727.     H245_UnicastAddress & unicast = pdu;
  728.  
  729. #if P_HAS_IPV6
  730.     if (ip.GetVersion() == 6) {
  731.       unicast.SetTag(H245_UnicastAddress::e_iP6Address);
  732.       H245_UnicastAddress_iP6Address & addr = unicast;
  733.       for (PINDEX i = 0; i < ip.GetSize(); i++)
  734.         addr.m_network[i] = ip[i];
  735.       addr.m_tsapIdentifier = port;
  736.       return TRUE;
  737.     }
  738. #endif
  739.  
  740.     unicast.SetTag(H245_UnicastAddress::e_iPAddress);
  741.     H245_UnicastAddress_iPAddress & addr = unicast;
  742.     for (PINDEX i = 0; i < 4; i++)
  743.       addr.m_network[i] = ip[i];
  744.     addr.m_tsapIdentifier = port;
  745.     return TRUE;
  746.   }
  747.  
  748.   return FALSE;
  749. }
  750.  
  751.  
  752. BOOL H323TransportAddress::IsEquivalent(const H323TransportAddress & address)
  753. {
  754.   if (*this == address)
  755.     return TRUE;
  756.  
  757.   if (IsEmpty() || address.IsEmpty())
  758.     return FALSE;
  759.  
  760.   PIPSocket::Address ip1, ip2;
  761.   WORD port1 = 65535, port2 = 65535;
  762.   return GetIpAndPort(ip1, port1) &&
  763.          address.GetIpAndPort(ip2, port2) &&
  764.          (ip1.IsAny() || ip2.IsAny() || ip1 == ip2) &&
  765.          (port1 == 65535 || port2 == 65535 || port1 == port2);
  766. }
  767.  
  768.  
  769. BOOL H323TransportAddress::GetIpAddress(PIPSocket::Address & ip) const
  770. {
  771.   WORD dummy = 65535;
  772.   return GetIpAndPort(ip, dummy);
  773. }
  774.  
  775.  
  776. static BOOL SplitAddress(const PString & addr, PString & host, PString & service)
  777. {
  778.   if (strncmp(addr, IpPrefix, 3) != 0) {
  779.     PTRACE(2, "H323\tUse of non IP transport address: \"" << addr << '"');
  780.     return FALSE;
  781.   }
  782.  
  783.   PINDEX lastChar = addr.GetLength()-1;
  784.   if (addr[lastChar] == '+')
  785.     lastChar--;
  786.  
  787.   PINDEX bracket = addr.FindLast(']');
  788.   if (bracket == P_MAX_INDEX)
  789.     bracket = 0;
  790.  
  791.   PINDEX colon = addr.Find(':', bracket);
  792.   if (colon == P_MAX_INDEX)
  793.     host = addr(3, lastChar);
  794.   else {
  795.     host = addr.Mid(3, colon-3);
  796.     service = addr.Mid(colon+1, lastChar);
  797.   }
  798.  
  799.   return TRUE;
  800. }
  801.  
  802.  
  803. BOOL H323TransportAddress::GetIpAndPort(PIPSocket::Address & ip,
  804.                                         WORD & port,
  805.                                         const char * proto) const
  806. {
  807.   PString host, service;
  808.   if (!SplitAddress(*this, host, service))
  809.     return FALSE;
  810.  
  811.   if (host.IsEmpty()) {
  812.     PTRACE(2, "H323\tIllegal IP transport address: \"" << *this << '"');
  813.     return FALSE;
  814.   }
  815.  
  816.   if (service == "*")
  817.     port = 0;
  818.   else {
  819.     if (!service)
  820.       port = PIPSocket::GetPortByService(proto, service);
  821.     if (port == 0) {
  822.       PTRACE(2, "H323\tIllegal IP transport port/service: \"" << *this << '"');
  823.       return FALSE;
  824.     }
  825.   }
  826.  
  827.   if (host == "*") {
  828.     ip = PIPSocket::GetDefaultIpAny();
  829.     return TRUE;
  830.   }
  831.  
  832.   if (PIPSocket::GetHostAddress(host, ip))
  833.     return TRUE;
  834.  
  835.   PTRACE(1, "H323\tCould not find host : \"" << host << '"');
  836.   return FALSE;
  837. }
  838.  
  839.  
  840. PString H323TransportAddress::GetHostName() const
  841. {
  842.   PString host, service;
  843.   if (!SplitAddress(*this, host, service))
  844.     return *this;
  845.  
  846.   PIPSocket::Address ip;
  847.   if (PIPSocket::GetHostAddress(host, ip))
  848.     return ip.AsString();
  849.  
  850.   return host;
  851. }
  852.  
  853.  
  854. H323Listener * H323TransportAddress::CreateListener(H323EndPoint & endpoint) const
  855. {
  856.   /*Have transport type name, create the transport object. Hard coded at the
  857.     moment but would like to add some sort of "registration" of transport
  858.     classes so new transports can be added without changing this source file
  859.     every time. As we have one transport type at the moment and may never
  860.     actually have another, we hard code it for now.
  861.    */
  862.  
  863.   PIPSocket::Address ip;
  864.   WORD port = H323EndPoint::DefaultTcpPort;
  865.   if (GetIpAndPort(ip, port))
  866.     return new H323ListenerTCP(endpoint, ip, port, theArray[GetLength()-1] != '+');
  867.  
  868.   return NULL;
  869. }
  870.  
  871.  
  872. H323Listener * H323TransportAddress::CreateCompatibleListener(H323EndPoint & endpoint) const
  873. {
  874.   /*Have transport type name, create the transport object. Hard coded at the
  875.     moment but would like to add some sort of "registration" of transport
  876.     classes so new transports can be added without changing this source file
  877.     every time. As we have one transport type at the moment and may never
  878.     actually have another, we hard code it for now.
  879.    */
  880.  
  881.   PIPSocket::Address ip;
  882.   if (GetIpAddress(ip))
  883.     return new H323ListenerTCP(endpoint, ip, 0, FALSE);
  884.  
  885.   return NULL;
  886. }
  887.  
  888.  
  889. H323Transport * H323TransportAddress::CreateTransport(H323EndPoint & endpoint) const
  890. {
  891.   /*Have transport type name, create the transport object. Hard coded at the
  892.     moment but would like to add some sort of "registration" of transport
  893.     classes so new transports can be added without changing this source file
  894.     every time. As we have one transport type at the moment and may never
  895.     actually have another, we hard code it for now.
  896.    */
  897.  
  898.   if (strncmp(theArray, IpPrefix, 3) == 0)
  899.     return new H323TransportTCP(endpoint);
  900.  
  901.   return NULL;
  902. }
  903.  
  904.  
  905. H323TransportAddressArray H323GetInterfaceAddresses(const H323ListenerList & listeners,
  906.                                                     BOOL excludeLocalHost,
  907.                                                     H323Transport * associatedTransport)
  908. {
  909.   H323TransportAddressArray interfaceAddresses;
  910.  
  911.   PINDEX i;
  912.   for (i = 0; i < listeners.GetSize(); i++) {
  913.     H323TransportAddressArray newAddrs = H323GetInterfaceAddresses(listeners[i].GetTransportAddress(), excludeLocalHost, associatedTransport);
  914.     PINDEX size  = interfaceAddresses.GetSize();
  915.     PINDEX nsize = newAddrs.GetSize();
  916.     interfaceAddresses.SetSize(size + nsize);
  917.     PINDEX j;
  918.     for (j = 0; j < nsize; j++)
  919.       interfaceAddresses.SetAt(size + j, new H323TransportAddress(newAddrs[j]));
  920.   }
  921.  
  922.   return interfaceAddresses;
  923. }
  924.  
  925.  
  926. H323TransportAddressArray H323GetInterfaceAddresses(const H323TransportAddress & addr,
  927.                                                     BOOL excludeLocalHost,
  928.                                                     H323Transport * associatedTransport)
  929. {
  930.   PIPSocket::Address ip;
  931.   WORD port;
  932.   if (!addr.GetIpAndPort(ip, port) || !ip.IsAny())
  933.     return addr;
  934.  
  935.   PIPSocket::InterfaceTable interfaces;
  936.   if (!PIPSocket::GetInterfaceTable(interfaces))
  937.     return addr;
  938.  
  939.   if (interfaces.GetSize() == 1)
  940.     return H323TransportAddress(interfaces[0].GetAddress(), port);
  941.  
  942.   PINDEX i;
  943.   H323TransportAddressArray interfaceAddresses;
  944.   PIPSocket::Address firstAddress(0);
  945.  
  946.   if (associatedTransport != NULL) {
  947.     if (associatedTransport->GetLocalAddress().GetIpAddress(firstAddress)) {
  948.       for (i = 0; i < interfaces.GetSize(); i++) {
  949.         PIPSocket::Address ip = interfaces[i].GetAddress();
  950.         if (ip == firstAddress)
  951.           interfaceAddresses.Append(new H323TransportAddress(ip, port));
  952.       }
  953.     }
  954.   }
  955.  
  956.   for (i = 0; i < interfaces.GetSize(); i++) {
  957.     PIPSocket::Address ip = interfaces[i].GetAddress();
  958.     if (ip != firstAddress && !(excludeLocalHost && ip.IsLoopback()))
  959.       interfaceAddresses.Append(new H323TransportAddress(ip, port));
  960.   }
  961.  
  962.   return interfaceAddresses;
  963. }
  964.  
  965.  
  966. void H323SetTransportAddresses(const H323Transport & associatedTransport,
  967.                                const H323TransportAddressArray & addresses,
  968.                                H225_ArrayOf_TransportAddress & pdu)
  969. {
  970.   for (PINDEX i = 0; i < addresses.GetSize(); i++) {
  971.     H323TransportAddress addr = addresses[i];
  972.  
  973.     PTRACE(4, "TCP\tAppending H.225 transport " << addr
  974.            << " using associated transport " << associatedTransport);
  975.  
  976.     PIPSocket::Address ip;
  977.     WORD port;
  978.     if (addr.GetIpAndPort(ip, port)) {
  979.       PIPSocket::Address remoteIP;
  980.       if (associatedTransport.GetRemoteAddress().GetIpAddress(remoteIP)) {
  981.         associatedTransport.GetEndPoint().TranslateTCPAddress(ip, remoteIP);
  982.         addr = H323TransportAddress(ip, port);
  983.       }
  984.     }
  985.  
  986.     H225_TransportAddress pduAddr;
  987.     addr.SetPDU(pduAddr);
  988.  
  989.     PINDEX lastPos = pdu.GetSize();
  990.  
  991.     // Check for already have had that address.
  992.     PINDEX j;
  993.     for (j = 0; j < lastPos; j++) {
  994.       if (pdu[j] == pduAddr)
  995.         break;
  996.     }
  997.  
  998.     if (j >= lastPos) {
  999.       // Put new listener into array
  1000.       pdu.SetSize(lastPos+1);
  1001.       pdu[lastPos] = pduAddr;
  1002.     }
  1003.   }
  1004. }
  1005.  
  1006.  
  1007. /////////////////////////////////////////////////////////////////////////////
  1008.  
  1009. H323TransportAddressArray::H323TransportAddressArray(const H225_ArrayOf_TransportAddress & addresses)
  1010. {
  1011.   for (PINDEX i = 0; i < addresses.GetSize(); i++)
  1012.     AppendAddress(H323TransportAddress(addresses[i]));
  1013. }
  1014.  
  1015.  
  1016. void H323TransportAddressArray::AppendString(const char * str)
  1017. {
  1018.   AppendAddress(H323TransportAddress(str));
  1019. }
  1020.  
  1021.  
  1022. void H323TransportAddressArray::AppendString(const PString & str)
  1023. {
  1024.   AppendAddress(H323TransportAddress(str));
  1025. }
  1026.  
  1027.  
  1028. void H323TransportAddressArray::AppendAddress(const H323TransportAddress & addr)
  1029. {
  1030.   if (!addr)
  1031.     Append(new H323TransportAddress(addr));
  1032. }
  1033.  
  1034.  
  1035. void H323TransportAddressArray::AppendStringCollection(const PCollection & coll)
  1036. {
  1037.   for (PINDEX i = 0; i < coll.GetSize(); i++) {
  1038.     PObject * obj = coll.GetAt(i);
  1039.     if (obj != NULL && obj->IsDescendant(PString::Class()))
  1040.       AppendAddress(H323TransportAddress(*(PString *)obj));
  1041.   }
  1042. }
  1043.  
  1044.  
  1045. /////////////////////////////////////////////////////////////////////////////
  1046.  
  1047. H323Listener::H323Listener(H323EndPoint & end)
  1048.   : PThread(end.GetListenerThreadStackSize(),
  1049.             NoAutoDeleteThread,
  1050.             NormalPriority,
  1051.             "H323 Listener:%0x"),
  1052.     endpoint(end)
  1053. {
  1054. }
  1055.  
  1056.  
  1057. void H323Listener::PrintOn(ostream & strm) const
  1058. {
  1059.   strm << "Listener[" << GetTransportAddress() << ']';
  1060. }
  1061.  
  1062.  
  1063. /////////////////////////////////////////////////////////////////////////////
  1064.  
  1065. H323Transport::H323Transport(H323EndPoint & end)
  1066.   : endpoint(end)
  1067. {
  1068.   thread = NULL;
  1069. }
  1070.  
  1071.  
  1072. H323Transport::~H323Transport()
  1073. {
  1074.   PAssert(thread == NULL, PLogicError);
  1075. }
  1076.  
  1077.  
  1078. void H323Transport::PrintOn(ostream & strm) const
  1079. {
  1080.   strm << "Transport[";
  1081.   H323TransportAddress addr = GetRemoteAddress();
  1082.   if (!addr)
  1083.     strm << "remote=" << addr << ' ';
  1084.   strm << "if=" << GetLocalAddress() << ']';
  1085. }
  1086.  
  1087.  
  1088. BOOL H323Transport::Close()
  1089. {
  1090.   PTRACE(3, "H323\tH323Transport::Close");
  1091.  
  1092.   /* Do not use PIndirectChannel::Close() as this deletes the sub-channel
  1093.      member field crashing the background thread. Just close the base
  1094.      sub-channel so breaks the threads I/O block.
  1095.    */
  1096.   if (IsOpen()) {
  1097.     channelPointerMutex.StartRead();
  1098.     GetBaseReadChannel()->Close();
  1099.     channelPointerMutex.EndRead();
  1100.   }
  1101.  
  1102.   return TRUE;
  1103. }
  1104.  
  1105.  
  1106. BOOL H323Transport::HandleFirstSignallingChannelPDU()
  1107. {
  1108.   PTRACE(3, "H225\tAwaiting first PDU");
  1109.   SetReadTimeout(15000); // Await 15 seconds after connect for first byte
  1110.   H323SignalPDU pdu;
  1111.   if (!pdu.Read(*this)) {
  1112.     PTRACE(1, "H225\tFailed to get initial Q.931 PDU, connection not started.");
  1113.     return FALSE;
  1114.   }
  1115.  
  1116.   unsigned callReference = pdu.GetQ931().GetCallReference();
  1117.   PTRACE(3, "H225\tIncoming call, first PDU: callReference=" << callReference);
  1118.  
  1119.   // Get a new (or old) connection from the endpoint
  1120.   H323Connection * connection = endpoint.OnIncomingConnection(this, pdu);
  1121.   if (connection == NULL) {
  1122.     PTRACE(1, "H225\tEndpoint could not create connection, "
  1123.               "sending release complete PDU: callRef=" << callReference);
  1124.     Q931 pdu;
  1125.     pdu.BuildReleaseComplete(callReference, TRUE);
  1126.     PBYTEArray rawData;
  1127.     pdu.Encode(rawData);
  1128.     WritePDU(rawData);
  1129.     return FALSE;
  1130.   }
  1131.  
  1132.   // Now attach this thread to the transport, which is in turn attached to the
  1133.   // connection so everything from gets cleaned up by the H323 cleaner thread
  1134.   // from now on. So thread must not auto delete and the "transport" variable
  1135.   // is not deleted either
  1136.   PThread * thread = PThread::Current();
  1137.   AttachThread(thread);
  1138.   thread->SetNoAutoDelete();
  1139.  
  1140.   if (connection->HandleSignalPDU(pdu)) {
  1141.     // All subsequent PDU's should wait forever
  1142.     SetReadTimeout(PMaxTimeInterval);
  1143.     connection->HandleSignallingChannel();
  1144.   }
  1145.   else {
  1146.     connection->ClearCall(H323Connection::EndedByTransportFail);
  1147.     PTRACE(1, "H225\tSignal channel stopped on first PDU.");
  1148.   }
  1149.  
  1150.   return TRUE;
  1151. }
  1152.  
  1153.  
  1154. void H323Transport::StartControlChannel(H323Connection & connection)
  1155. {
  1156.   new H245TransportThread(endpoint, connection, *this);
  1157. }
  1158.  
  1159.  
  1160. void H323Transport::AttachThread(PThread * thrd)
  1161. {
  1162.   PAssert(thread == NULL, PLogicError);
  1163.   thread = thrd;
  1164. }
  1165.  
  1166.  
  1167. void H323Transport::CleanUpOnTermination()
  1168. {
  1169.   Close();
  1170.  
  1171.   if (thread != NULL) {
  1172.     PTRACE(3, "H323\tH323Transport::CleanUpOnTermination for " << thread->GetThreadName());
  1173.     PAssert(thread->WaitForTermination(10000), "Transport thread did not terminate");
  1174.     delete thread;
  1175.     thread = NULL;
  1176.   }
  1177. }
  1178.  
  1179.  
  1180. BOOL H323Transport::IsCompatibleTransport(const H225_TransportAddress & /*pdu*/) const
  1181. {
  1182.   PAssertAlways(PUnimplementedFunction);
  1183.   return FALSE;
  1184. }
  1185.  
  1186.  
  1187. void H323Transport::SetUpTransportPDU(H225_TransportAddress & /*pdu*/,
  1188.                                       BOOL /*localTsap*/) const
  1189. {
  1190.   PAssertAlways(PUnimplementedFunction);
  1191. }
  1192.  
  1193.  
  1194. void H323Transport::SetUpTransportPDU(H245_TransportAddress & /*pdu*/,
  1195.                                       unsigned /*port*/) const
  1196. {
  1197.   PAssertAlways(PUnimplementedFunction);
  1198. }
  1199.  
  1200.  
  1201. void H323Transport::SetPromiscuous(PromisciousModes /*promiscuous*/)
  1202. {
  1203. }
  1204.  
  1205.  
  1206. H323TransportAddress H323Transport::GetLastReceivedAddress() const
  1207. {
  1208.   return GetRemoteAddress();
  1209. }
  1210.  
  1211.  
  1212. H323Transport * H323Transport::CreateControlChannel(H323Connection & /*connection*/)
  1213. {
  1214.   PAssertAlways(PUnimplementedFunction);
  1215.   return NULL;
  1216. }
  1217.  
  1218.  
  1219. BOOL H323Transport::AcceptControlChannel(H323Connection & /*connection*/)
  1220. {
  1221.   PAssertAlways(PUnimplementedFunction);
  1222.   return FALSE;
  1223. }
  1224.  
  1225.  
  1226. BOOL H323Transport::DiscoverGatekeeper(H323Gatekeeper & /*gk*/,
  1227.                                        H323RasPDU & /*pdu*/,
  1228.                                        const H323TransportAddress & /*address*/)
  1229. {
  1230.   PAssertAlways(PUnimplementedFunction);
  1231.   return FALSE;
  1232. }
  1233.  
  1234.  
  1235. /////////////////////////////////////////////////////////////////////////////
  1236.  
  1237. H323ListenerTCP::H323ListenerTCP(H323EndPoint & end,
  1238.                                  PIPSocket::Address binding,
  1239.                                  WORD port,
  1240.                                  BOOL exclusive)
  1241.   : H323Listener(end),
  1242.     listener(port),
  1243.     localAddress(binding)
  1244. {
  1245.   exclusiveListener = exclusive;
  1246. }
  1247.  
  1248.  
  1249. H323ListenerTCP::~H323ListenerTCP()
  1250. {
  1251.   Close();
  1252. }
  1253.  
  1254.  
  1255. BOOL H323ListenerTCP::Open()
  1256. {
  1257.   if (listener.Listen(localAddress, 100, 0,
  1258.                       exclusiveListener ? PSocket::AddressIsExclusive
  1259.                                         : PSocket::CanReuseAddress))
  1260.     return TRUE;
  1261.  
  1262.   PTRACE(1, "TCP\tListen on " << localAddress << ':' << listener.GetPort()
  1263.          << " failed: " << listener.GetErrorText());
  1264.   return FALSE;
  1265. }
  1266.  
  1267.  
  1268. BOOL H323ListenerTCP::Close()
  1269. {
  1270.   BOOL ok = listener.Close();
  1271.  
  1272.   PAssert(PThread::Current() != this, PLogicError);
  1273.  
  1274.   if (!IsTerminated() && !IsSuspended())
  1275.     PAssert(WaitForTermination(10000), "Listener thread did not terminate");
  1276.  
  1277.   return ok;
  1278. }
  1279.  
  1280.  
  1281. H323Transport * H323ListenerTCP::Accept(const PTimeInterval & timeout)
  1282. {
  1283.   if (!listener.IsOpen())
  1284.     return NULL;
  1285.  
  1286.   listener.SetReadTimeout(timeout); // Wait for remote connect
  1287.  
  1288.   PTRACE(4, "TCP\tWaiting on socket accept on " << GetTransportAddress());
  1289.   PTCPSocket * socket = new PTCPSocket;
  1290.   if (socket->Accept(listener)) {
  1291.     H323TransportTCP * transport = new H323TransportTCP(endpoint);
  1292.     if (transport->Open(socket))
  1293.       return transport;
  1294.  
  1295.     PTRACE(1, "TCP\tFailed to open transport, connection not started.");
  1296.     delete transport;
  1297.     return NULL;
  1298.   }
  1299.  
  1300.   if (socket->GetErrorCode() != PChannel::Interrupted) {
  1301.     PTRACE(1, "TCP\tAccept error:" << socket->GetErrorText());
  1302.     listener.Close();
  1303.   }
  1304.  
  1305.   delete socket;
  1306.   return NULL;
  1307. }
  1308.  
  1309.  
  1310. H323TransportAddress H323ListenerTCP::GetTransportAddress() const
  1311. {
  1312.   return H323TransportAddress(localAddress, listener.GetPort());
  1313. }
  1314.  
  1315.  
  1316. BOOL H323ListenerTCP::SetUpTransportPDU(H245_TransportAddress & pdu,
  1317.                                         const H323Transport & associatedTransport)
  1318. {
  1319.   if (!localAddress.IsAny())
  1320.     return GetTransportAddress().SetPDU(pdu);
  1321.  
  1322.   PIPSocket::Address addressOfExistingInterface;
  1323.   if (!associatedTransport.GetLocalAddress().GetIpAddress(addressOfExistingInterface))
  1324.     return FALSE;
  1325.  
  1326.   H323TransportAddress transAddr(addressOfExistingInterface, listener.GetPort());
  1327.   transAddr.SetPDU(pdu);
  1328.   return TRUE;
  1329. }
  1330.  
  1331.  
  1332. void H323ListenerTCP::Main()
  1333. {
  1334.   PTRACE(2, "H323\tAwaiting TCP connections on port " << listener.GetPort());
  1335.  
  1336.   while (listener.IsOpen()) {
  1337.     H323Transport * transport = Accept(PMaxTimeInterval);
  1338.     if (transport != NULL)
  1339.       new H225TransportThread(endpoint, transport);
  1340.   }
  1341. }
  1342.  
  1343.  
  1344. /////////////////////////////////////////////////////////////////////////////
  1345.  
  1346. H323TransportIP::H323TransportIP(H323EndPoint & end, PIPSocket::Address binding, WORD remPort)
  1347.   : H323Transport(end),
  1348.     localAddress(binding),
  1349.     remoteAddress(0)
  1350. {
  1351.   localPort = 0;
  1352.   remotePort = remPort;
  1353. }
  1354.  
  1355.  
  1356. H323TransportAddress H323TransportIP::GetLocalAddress() const
  1357. {
  1358.   return H323TransportAddress(localAddress, localPort);
  1359. }
  1360.  
  1361.  
  1362. H323TransportAddress H323TransportIP::GetRemoteAddress() const
  1363. {
  1364.   return H323TransportAddress(remoteAddress, remotePort);
  1365. }
  1366.  
  1367.  
  1368. BOOL H323TransportIP::IsCompatibleTransport(const H225_TransportAddress & pdu) const
  1369. {
  1370.   return pdu.GetTag() == H225_TransportAddress::e_ipAddress
  1371. #if P_HAS_IPV6
  1372.             || pdu.GetTag() == H225_TransportAddress::e_ip6Address
  1373. #endif
  1374.          ;
  1375. }
  1376.  
  1377.  
  1378. void H323TransportIP::SetUpTransportPDU(H225_TransportAddress & pdu, BOOL localTsap) const
  1379. {
  1380.   H323TransportAddress transAddr;
  1381.   if (!localTsap) 
  1382.     transAddr = H323TransportAddress(remoteAddress, remotePort);
  1383.   else {
  1384.     PIPSocket::Address ipAddr = localAddress;
  1385.     endpoint.TranslateTCPAddress(ipAddr, remoteAddress);
  1386.     transAddr = H323TransportAddress(ipAddr, localPort);
  1387.   }
  1388.  
  1389.   transAddr.SetPDU(pdu);
  1390. }
  1391.  
  1392.  
  1393. void H323TransportIP::SetUpTransportPDU(H245_TransportAddress & pdu, unsigned port) const
  1394. {
  1395.   PIPSocket::Address ipAddr = localAddress;
  1396.   endpoint.TranslateTCPAddress(ipAddr, remoteAddress);
  1397.  
  1398.   switch (port) {
  1399.     case UseLocalTSAP :
  1400.       port = localPort;
  1401.       break;
  1402.     case UseRemoteTSAP :
  1403.       port = remotePort;
  1404.       break;
  1405.   }
  1406.  
  1407.   H323TransportAddress transAddr(ipAddr, (WORD)port);
  1408.   transAddr.SetPDU(pdu);
  1409. }
  1410.  
  1411.  
  1412. /////////////////////////////////////////////////////////////////////////////
  1413.  
  1414. H323TransportTCP::H323TransportTCP(H323EndPoint & end,
  1415.                                    PIPSocket::Address binding,
  1416.                                    BOOL listen)
  1417.   : H323TransportIP(end, binding, H323EndPoint::DefaultTcpPort)
  1418. {
  1419.   h245listener = NULL;
  1420.  
  1421.   // construct listener socket if required
  1422.   if (listen) {
  1423.     h245listener = new PTCPSocket;
  1424.  
  1425.     localPort = end.GetNextTCPPort();
  1426.     WORD firstPort = localPort;
  1427.     while (!h245listener->Listen(binding, 5, localPort)) {
  1428.       localPort = end.GetNextTCPPort();
  1429.       if (localPort == firstPort)
  1430.         break;
  1431.     }
  1432.  
  1433.     if (h245listener->IsOpen()) {
  1434.       localPort = h245listener->GetPort();
  1435.       PTRACE(3, "H225\tTCP Listen for H245 on " << binding << ':' << localPort);
  1436.     }
  1437.     else {
  1438.       PTRACE(1, "H225\tTCP Listen for H245 failed: " << h245listener->GetErrorText());
  1439.       delete h245listener;
  1440.       h245listener = NULL;
  1441.     }
  1442.   }
  1443. }
  1444.  
  1445.  
  1446. H323TransportTCP::~H323TransportTCP()
  1447. {
  1448.   delete h245listener;  // Delete and H245 listener that may be present
  1449. }
  1450.  
  1451.  
  1452. BOOL H323TransportTCP::OnOpen()
  1453. {
  1454.   PIPSocket * socket = (PIPSocket *)GetReadChannel();
  1455.  
  1456.   // Get name of the remote computer for information purposes
  1457.   if (!socket->GetPeerAddress(remoteAddress, remotePort)) {
  1458.     PTRACE(1, "H323TCP\tGetPeerAddress() failed: " << socket->GetErrorText());
  1459.     return FALSE;
  1460.   }
  1461.  
  1462.   // get local address of incoming socket to ensure that multi-homed machines
  1463.   // use a NIC address that is guaranteed to be addressable to destination
  1464.   if (!socket->GetLocalAddress(localAddress, localPort)) {
  1465.     PTRACE(1, "H323TCP\tGetLocalAddress() failed: " << socket->GetErrorText());
  1466.     return FALSE;
  1467.   }
  1468.  
  1469. #ifndef __BEOS__
  1470.   if (!socket->SetOption(TCP_NODELAY, 1, IPPROTO_TCP)) {
  1471.     PTRACE(1, "H323TCP\tSetOption(TCP_NODELAY) failed: " << socket->GetErrorText());
  1472.   }
  1473.  
  1474.   // make sure do not lose outgoing packets on close
  1475.   const linger ling = { 1, 3 };
  1476.   if (!socket->SetOption(SO_LINGER, &ling, sizeof(ling))) {
  1477.     PTRACE(1, "H323TCP\tSetOption(SO_LINGER) failed: " << socket->GetErrorText());
  1478.     return FALSE;
  1479.   }
  1480. #endif
  1481.  
  1482.   PTRACE(2, "H323TCP\tStarted connection: "
  1483.             " host=" << remoteAddress << ':' << remotePort << ","
  1484.             " if=" << localAddress << ':' << localPort << ","
  1485.             " handle=" << socket->GetHandle());
  1486.  
  1487.   return TRUE;
  1488. }
  1489.  
  1490.  
  1491. BOOL H323TransportTCP::Close()
  1492. {
  1493.   // Close listening socket to break waiting accept
  1494.   if (IsListening())
  1495.     h245listener->Close();
  1496.  
  1497.   return H323Transport::Close();
  1498. }
  1499.  
  1500.  
  1501. BOOL H323TransportTCP::SetRemoteAddress(const H323TransportAddress & address)
  1502. {
  1503.   return address.GetIpAndPort(remoteAddress, remotePort, "tcp");
  1504. }
  1505.  
  1506.  
  1507. BOOL H323TransportTCP::ReadPDU(PBYTEArray & pdu)
  1508. {
  1509.   // Make sure is a RFC1006 TPKT
  1510.   switch (ReadChar()) {
  1511.     case -1 :
  1512.       return FALSE;
  1513.  
  1514.     case 3 :  // Only support version 3
  1515.       break;
  1516.  
  1517.     default :  // Unknown version number
  1518.       return SetErrorValues(Miscellaneous, 0x41000000);
  1519.   }
  1520.  
  1521.   // Save timeout
  1522.   PTimeInterval oldTimeout = GetReadTimeout();
  1523.  
  1524.   // Should get all of PDU in 5 seconds or something is seriously wrong,
  1525.   SetReadTimeout(5000);
  1526.  
  1527.   // Get TPKT length
  1528.   BYTE header[3];
  1529.   BOOL ok = ReadBlock(header, sizeof(header));
  1530.   if (ok) {
  1531.     PINDEX packetLength = ((header[1] << 8)|header[2]) - 4;
  1532.     ok = ReadBlock(pdu.GetPointer(packetLength), packetLength);
  1533.   }
  1534.  
  1535.   SetReadTimeout(oldTimeout);
  1536.  
  1537.   return ok;
  1538. }
  1539.  
  1540.  
  1541. BOOL H323TransportTCP::WritePDU(const PBYTEArray & pdu)
  1542. {
  1543.   // We copy the data into a new buffer so we can do a single write call. This
  1544.   // is necessary as we have disabled the Nagle TCP delay algorithm to improve
  1545.   // network performance.
  1546.  
  1547.   int packetLength = pdu.GetSize() + 4;
  1548.  
  1549.   // Send RFC1006 TPKT length
  1550.   PBYTEArray tpkt(packetLength);
  1551.   tpkt[0] = 3;
  1552.   tpkt[1] = 0;
  1553.   tpkt[2] = (BYTE)(packetLength >> 8);
  1554.   tpkt[3] = (BYTE)packetLength;
  1555.   memcpy(tpkt.GetPointer()+4, (const BYTE *)pdu, pdu.GetSize());
  1556.  
  1557.   return Write((const BYTE *)tpkt, packetLength);
  1558. }
  1559.  
  1560.  
  1561. BOOL H323TransportTCP::Connect()
  1562. {
  1563.   if (IsListening())
  1564.     return TRUE;
  1565.  
  1566.   PTCPSocket * socket = new PTCPSocket(remotePort);
  1567.   Open(socket);
  1568.  
  1569.   channelPointerMutex.StartRead();
  1570.  
  1571.   socket->SetReadTimeout(10000);
  1572.  
  1573.   localPort = endpoint.GetNextTCPPort();
  1574.   WORD firstPort = localPort;
  1575.   for (;;) {
  1576.     PTRACE(4, "H323TCP\tConnecting to "
  1577.            << remoteAddress << ':' << remotePort
  1578.            << " (local port=" << localPort << ')');
  1579.     if (socket->Connect(localPort, remoteAddress))
  1580.       break;
  1581.  
  1582.     int errnum = socket->GetErrorNumber();
  1583.     if (localPort == 0 || (errnum != EADDRINUSE && errnum != EADDRNOTAVAIL)) {
  1584.       PTRACE(1, "H323TCP\tCould not connect to "
  1585.                 << remoteAddress << ':' << remotePort
  1586.                 << " (local port=" << localPort << ") - "
  1587.                 << socket->GetErrorText() << '(' << errnum << ')');
  1588.       channelPointerMutex.EndRead();
  1589.       return SetErrorValues(socket->GetErrorCode(), errnum);
  1590.     }
  1591.  
  1592.     localPort = endpoint.GetNextTCPPort();
  1593.     if (localPort == firstPort) {
  1594.       PTRACE(1, "H323TCP\tCould not bind to any port in range " <<
  1595.                 endpoint.GetTCPPortBase() << " to " << endpoint.GetTCPPortMax());
  1596.       channelPointerMutex.EndRead();
  1597.       return SetErrorValues(socket->GetErrorCode(), errnum);
  1598.     }
  1599.   }
  1600.  
  1601.   socket->SetReadTimeout(PMaxTimeInterval);
  1602.  
  1603.   channelPointerMutex.EndRead();
  1604.  
  1605.   return OnOpen();
  1606. }
  1607.  
  1608.  
  1609. H323Transport * H323TransportTCP::CreateControlChannel(H323Connection & connection)
  1610. {
  1611.   H323TransportTCP * tcpTransport = new H323TransportTCP(endpoint, localAddress, TRUE);
  1612.   tcpTransport->SetRemoteAddress(GetRemoteAddress());
  1613.   if (tcpTransport->IsListening()) // Listen() failed
  1614.     return tcpTransport;
  1615.  
  1616.   delete tcpTransport;
  1617.   connection.ClearCall(H323Connection::EndedByTransportFail);
  1618.   return FALSE;
  1619. }
  1620.  
  1621.  
  1622. BOOL H323TransportTCP::AcceptControlChannel(H323Connection & connection)
  1623. {
  1624.   if (IsOpen())
  1625.     return TRUE;
  1626.  
  1627.   if (h245listener == NULL) {
  1628.     PAssertAlways(PLogicError);
  1629.     return FALSE;
  1630.   }
  1631.  
  1632.   PTRACE(3, "H245\tTCP Accept wait");
  1633.  
  1634.   PTCPSocket * h245Socket = new PTCPSocket;
  1635.  
  1636.   h245listener->SetReadTimeout(endpoint.GetControlChannelStartTimeout());
  1637.   if (h245Socket->Accept(*h245listener))
  1638.     return Open(h245Socket);
  1639.  
  1640.   PTRACE(1, "H225\tAccept for H245 failed: " << h245Socket->GetErrorText());
  1641.   delete h245Socket;
  1642.  
  1643.   if (h245listener->IsOpen() &&
  1644.       connection.IsConnected() &&
  1645.       connection.FindChannel(RTP_Session::DefaultAudioSessionID, TRUE) == NULL &&
  1646.       connection.FindChannel(RTP_Session::DefaultAudioSessionID, FALSE) == NULL)
  1647.     connection.ClearCall(H323Connection::EndedByTransportFail);
  1648.  
  1649.   return FALSE;
  1650. }
  1651.  
  1652.  
  1653. BOOL H323TransportTCP::IsListening() const
  1654. {
  1655.   if (IsOpen())
  1656.     return FALSE;
  1657.  
  1658.   if (h245listener == NULL)
  1659.     return FALSE;
  1660.  
  1661.   return h245listener->IsOpen();
  1662. }
  1663.  
  1664.  
  1665. /////////////////////////////////////////////////////////////////////////////
  1666.  
  1667. static BOOL ListenUDP(PUDPSocket & socket,
  1668.                       H323EndPoint & endpoint,
  1669.                       PIPSocket::Address binding,
  1670.                       WORD localPort)
  1671. {
  1672.   if (localPort > 0) {
  1673.     if (socket.Listen(binding, 0, localPort))
  1674.       return TRUE;
  1675.   }
  1676.   else {
  1677.     localPort = endpoint.GetNextUDPPort();
  1678.     WORD firstPort = localPort;
  1679.  
  1680.     for (;;) {
  1681.       if (socket.Listen(binding, 0, localPort))
  1682.         return TRUE;
  1683.  
  1684.       int errnum = socket.GetErrorNumber();
  1685.       if (errnum != EADDRINUSE && errnum != EADDRNOTAVAIL)
  1686.         break;
  1687.  
  1688.       localPort = endpoint.GetNextUDPPort();
  1689.       if (localPort == firstPort) {
  1690.         PTRACE(1, "H323UDP\tCould not bind to any port in range " <<
  1691.                   endpoint.GetUDPPortBase() << " to " << endpoint.GetUDPPortMax());
  1692.         return FALSE;
  1693.       }
  1694.     }
  1695.   }
  1696.  
  1697.   PTRACE(1, "H323UDP\tCould not bind to "
  1698.             << binding << ':' << localPort << " - "
  1699.             << socket.GetErrorText() << '(' << socket.GetErrorNumber() << ')');
  1700.   return FALSE;
  1701. }
  1702.  
  1703.  
  1704. H323TransportUDP::H323TransportUDP(H323EndPoint & ep,
  1705.                                    PIPSocket::Address binding,
  1706.                                    WORD local_port,
  1707.                                    WORD remote_port)
  1708.   : H323TransportIP(ep, binding, remote_port)
  1709. {
  1710.   if (remotePort == 0)
  1711.     remotePort = H225_RAS::DefaultRasUdpPort; // For backward compatibility
  1712.  
  1713.   promiscuousReads = AcceptFromRemoteOnly;
  1714.  
  1715.   PUDPSocket * udp = new PUDPSocket;
  1716.   ListenUDP(*udp, ep, binding, local_port);
  1717.  
  1718.   localPort = udp->GetPort();
  1719.  
  1720.   Open(udp);
  1721.  
  1722.   PTRACE(3, "H323UDP\tBinding to interface: " << binding << ':' << localPort);
  1723. }
  1724.  
  1725.  
  1726. H323TransportUDP::~H323TransportUDP()
  1727. {
  1728.   Close();
  1729. }
  1730.  
  1731.  
  1732. BOOL H323TransportUDP::SetRemoteAddress(const H323TransportAddress & address)
  1733. {
  1734.   return address.GetIpAndPort(remoteAddress, remotePort, "udp");
  1735. }
  1736.  
  1737.  
  1738. BOOL H323TransportUDP::Connect()
  1739. {
  1740.   if (remoteAddress == 0 || remotePort == 0)
  1741.     return FALSE;
  1742.  
  1743.   PUDPSocket * socket;
  1744.  
  1745.   PSTUNClient * stun = endpoint.GetSTUN(remoteAddress);
  1746.   if (stun != NULL) {
  1747.     if (stun->CreateSocket(socket)) {
  1748.       Open(socket);
  1749.       socket->GetLocalAddress(localAddress, localPort);
  1750.       PTRACE(4, "H323UDP\tSTUN created socket: " << localAddress << ':' << localPort);
  1751.     }
  1752.     else
  1753.       PTRACE(4, "H323UDP\tSTUN could not create socket!");
  1754.   }
  1755.  
  1756.   socket = (PUDPSocket *)GetReadChannel();
  1757.   socket->SetSendAddress(remoteAddress, remotePort);
  1758.  
  1759.   return TRUE;
  1760. }
  1761.  
  1762.  
  1763. void H323TransportUDP::SetPromiscuous(PromisciousModes promiscuous)
  1764. {
  1765.   promiscuousReads = promiscuous;
  1766. }
  1767.  
  1768.  
  1769. H323TransportAddress H323TransportUDP::GetLastReceivedAddress() const
  1770. {
  1771.   if (!lastReceivedAddress)
  1772.     return lastReceivedAddress;
  1773.  
  1774.   return H323Transport::GetLastReceivedAddress();
  1775. }
  1776.  
  1777.  
  1778. BOOL H323TransportUDP::ReadPDU(PBYTEArray & pdu)
  1779. {
  1780.   for (;;) {
  1781.     if (!Read(pdu.GetPointer(10000), 10000)) {
  1782.       pdu.SetSize(0);
  1783.       return FALSE;
  1784.     }
  1785.  
  1786.     pdu.SetSize(GetLastReadCount());
  1787.  
  1788.     PUDPSocket * socket = (PUDPSocket *)GetReadChannel();
  1789.  
  1790.     PIPSocket::Address address;
  1791.     WORD port;
  1792.  
  1793.     socket->GetLastReceiveAddress(address, port);
  1794.     lastReceivedAddress = H323TransportAddress(address, port);
  1795.  
  1796.     switch (promiscuousReads) {
  1797.       case AcceptFromRemoteOnly :
  1798.         if (remoteAddress == address)
  1799.           return TRUE;
  1800.         break;
  1801.  
  1802.       case AcceptFromAnyAutoSet :
  1803.         remoteAddress = address;
  1804.         remotePort = port;
  1805.         socket->SetSendAddress(remoteAddress, remotePort);
  1806.         // fall into next case
  1807.  
  1808.       default : //AcceptFromAny
  1809.         return TRUE;
  1810.     }
  1811.  
  1812.     PTRACE(1, "UDP\tReceived PDU from incorrect host: " << address << ':' << port);
  1813.   }
  1814. }
  1815.  
  1816.  
  1817. BOOL H323TransportUDP::WritePDU(const PBYTEArray & pdu)
  1818. {
  1819.   return Write((const BYTE *)pdu, pdu.GetSize());
  1820. }
  1821.  
  1822.  
  1823. BOOL H323TransportUDP::DiscoverGatekeeper(H323Gatekeeper & gk,
  1824.                                           H323RasPDU & request,
  1825.                                           const H323TransportAddress & address)
  1826. {
  1827.   PINDEX i;
  1828.  
  1829.   PTRACE(3, "H225\tStarted gatekeeper discovery of \"" << address << '"');
  1830.  
  1831.   PIPSocket::Address destAddr = INADDR_BROADCAST;
  1832.   WORD destPort = H225_RAS::DefaultRasUdpPort;
  1833.   if (!address) {
  1834.     if (!address.GetIpAndPort(destAddr, destPort, "udp")) {
  1835.       PTRACE(2, "RAS\tError decoding address");
  1836.       return FALSE;
  1837.     }
  1838.   }
  1839.  
  1840.   // Skip over the H323Transport::Close to make sure PUDPSocket is deleted.
  1841.   PIndirectChannel::Close();
  1842.  
  1843.   remoteAddress = 0;
  1844.   remotePort = 0;
  1845.  
  1846.   // Remember the original info for pre-bound socket
  1847.   PIPSocket::Address originalLocalAddress = localAddress;
  1848.   WORD originalLocalPort = 0;
  1849.  
  1850.   // Get the interfaces to try
  1851.   PIPSocket::InterfaceTable interfaces;
  1852.  
  1853.   // See if prebound to interface, only use that if so
  1854.   if (destAddr.IsLoopback()) {
  1855.     PTRACE(3, "RAS\tGatekeeper discovery on loopback interface");
  1856.     localAddress = destAddr;
  1857.   }
  1858.   else if (localAddress != INADDR_ANY) {
  1859.     PTRACE(3, "RAS\tGatekeeper discovery on pre-bound interface: "
  1860.               << localAddress << ':' << localPort);
  1861.     originalLocalPort = localPort;
  1862.   }
  1863.   else if (!PIPSocket::GetInterfaceTable(interfaces)) {
  1864.     PTRACE(1, "RAS\tNo interfaces on system!");
  1865.   }
  1866.   else {
  1867.     PTRACE(4, "RAS\tSearching interfaces:\n" << setfill('\n') << interfaces << setfill(' '));
  1868.     // Check for if destination machine is local machine, if so only use that interface
  1869.     for (i = 0; i < interfaces.GetSize(); i++) {
  1870.       if (interfaces[i].GetAddress() == destAddr) {
  1871.         PTRACE(3, "RAS\tGatekeeper discovery on local interface: " << destAddr);
  1872.         localAddress = destAddr;
  1873.         interfaces.RemoveAll();
  1874.       }
  1875.     }
  1876.   }
  1877.  
  1878.   if (interfaces.IsEmpty())
  1879.     interfaces.Append(new PIPSocket::InterfaceEntry("", localAddress, PIPSocket::Address(0xffffffff), ""));
  1880.  
  1881.   PSTUNClient * stun = endpoint.GetSTUN(remoteAddress);
  1882.  
  1883.   PSocketList sockets;
  1884.   PSocket::SelectList selection;
  1885.   H225_GatekeeperRequest & grq = request;
  1886.  
  1887.   for (i = 0; i < interfaces.GetSize(); i++) {
  1888.     localAddress = interfaces[i].GetAddress();
  1889.     if (localAddress == 0 || (destAddr != localAddress && localAddress.IsLoopback()))
  1890.       continue;
  1891.  
  1892.     // Check for already have had that IP address.
  1893.     PINDEX j;
  1894.     for (j = 0; j < i; j++) {
  1895.       if (localAddress == interfaces[j].GetAddress())
  1896.         break;
  1897.     }
  1898.     if (j < i)
  1899.       continue;
  1900.  
  1901.     PUDPSocket * socket;
  1902.  
  1903.     static PIPSocket::Address MulticastRasAddress(224, 0, 1, 41);
  1904.     if (destAddr != MulticastRasAddress) {
  1905.  
  1906.       // Not explicitly multicast
  1907.       if (stun != NULL && stun->CreateSocket(socket)) {
  1908.         socket->GetLocalAddress(localAddress, localPort);
  1909.         PTRACE(4, "H323UDP\tSTUN created socket: " << localAddress << ':' << localPort);
  1910.       }
  1911.       else {
  1912.         socket = new PUDPSocket;
  1913.         if (!ListenUDP(*socket, endpoint, localAddress, originalLocalPort)) {
  1914.           delete socket;
  1915.           return FALSE;
  1916.         }
  1917.         localPort = socket->GetPort();
  1918.       }
  1919.  
  1920.       sockets.Append(socket);
  1921.  
  1922. #ifndef __BEOS__
  1923.       if (destAddr == INADDR_BROADCAST) {
  1924.         if (!socket->SetOption(SO_BROADCAST, 1)) {
  1925.           PTRACE(2, "RAS\tError allowing broadcast: " << socket->GetErrorText());
  1926.           return FALSE;
  1927.         }
  1928.       }
  1929. #else
  1930.       PTRACE(2, "RAS\tBroadcast option under BeOS is not implemented yet");
  1931. #endif
  1932.  
  1933.       // Adjust the PDU to reflect the interface we are writing to.
  1934.       PIPSocket::Address ipAddr = localAddress;
  1935.       endpoint.TranslateTCPAddress(ipAddr, destAddr);
  1936.       H323TransportAddress(ipAddr, localPort).SetPDU(grq.m_rasAddress);
  1937.  
  1938.       PTRACE(3, "RAS\tGatekeeper discovery on interface: " << localAddress << ':' << localPort);
  1939.  
  1940.       socket->SetSendAddress(destAddr, destPort);
  1941.       writeChannel = socket;
  1942.       if (request.Write(*this))
  1943.         selection.Append(socket);
  1944.       else
  1945.         PTRACE(2, "RAS\tError writing discovery PDU: " << socket->GetErrorText());
  1946.  
  1947. #ifndef __BEOS__
  1948.       if (destAddr == INADDR_BROADCAST)
  1949.         socket->SetOption(SO_BROADCAST, 0);
  1950. #endif
  1951.     }
  1952.  
  1953.  
  1954. #ifdef IP_ADD_MEMBERSHIP
  1955.     // Now do it again for Multicast
  1956.     if (destAddr == INADDR_BROADCAST || destAddr == MulticastRasAddress) {
  1957.       socket = new PUDPSocket;
  1958.       sockets.Append(socket);
  1959.  
  1960.       if (!ListenUDP(*socket, endpoint, localAddress, 0))
  1961.         return FALSE;
  1962.  
  1963.       localPort = socket->GetPort();
  1964.  
  1965.       struct ip_mreq mreq;
  1966.       mreq.imr_multiaddr = MulticastRasAddress;
  1967.       mreq.imr_interface = localAddress;    // ip address of host
  1968.       if (socket->SetOption(IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq), IPPROTO_IP)) {
  1969.         // Adjust the PDU to reflect the interface we are writing to.
  1970.         SetUpTransportPDU(grq.m_rasAddress, TRUE);
  1971.  
  1972.         socket->SetOption(SO_BROADCAST, 1);
  1973.  
  1974.         socket->SetSendAddress(INADDR_BROADCAST, H225_RAS::DefaultRasMulticastPort);
  1975.         writeChannel = socket;
  1976.         if (request.Write(*this))
  1977.           selection.Append(socket);
  1978.         else
  1979.           PTRACE(2, "RAS\tError writing discovery PDU: " << socket->GetErrorText());
  1980.  
  1981.         socket->SetOption(SO_BROADCAST, 0);
  1982.       }
  1983.       else
  1984.         PTRACE(2, "RAS\tError allowing multicast: " << socket->GetErrorText());
  1985.     }
  1986. #endif
  1987.  
  1988.     writeChannel = NULL;
  1989.   }
  1990.  
  1991.   if (sockets.IsEmpty()) {
  1992.     PTRACE(1, "RAS\tNo suitable interfaces for discovery!");
  1993.     return FALSE;
  1994.   }
  1995.  
  1996.   if (PSocket::Select(selection, endpoint.GetGatekeeperRequestTimeout()) != NoError) {
  1997.     PTRACE(3, "RAS\tError on discover request select");
  1998.     return FALSE;
  1999.   }
  2000.  
  2001.   SetReadTimeout(0);
  2002.  
  2003.   for (i = 0; i < selection.GetSize(); i++) {
  2004.     readChannel = &selection[i];
  2005.     promiscuousReads = AcceptFromAnyAutoSet;
  2006.  
  2007.     H323RasPDU response;
  2008.     if (!response.Read(*this)) {
  2009.       PTRACE(3, "RAS\tError on discover request read: " << readChannel->GetErrorText());
  2010.       break;
  2011.     }
  2012.  
  2013.     do {
  2014.       if (gk.HandleTransaction(response)) {
  2015.         if (!gk.IsDiscoveryComplete()) {
  2016.           localAddress = originalLocalAddress;
  2017.           localPort = originalLocalPort;
  2018.           promiscuousReads = AcceptFromRemoteOnly;
  2019.           readChannel = NULL;
  2020.           return TRUE;
  2021.         }
  2022.  
  2023.         PUDPSocket * socket = (PUDPSocket *)readChannel;
  2024.         socket->GetLocalAddress(localAddress, localPort);
  2025.         readChannel = NULL;
  2026.         if (Open(socket) && Connect()) {
  2027.           sockets.DisallowDeleteObjects();
  2028.           sockets.Remove(socket);
  2029.           sockets.AllowDeleteObjects();
  2030.  
  2031.           promiscuousReads = AcceptFromRemoteOnly;
  2032.  
  2033.           PTRACE(2, "RAS\tGatekeeper discovered at: "
  2034.                  << remoteAddress << ':' << remotePort
  2035.                  << " (if="
  2036.                  << localAddress << ':' << localPort << ')');
  2037.           return TRUE;
  2038.         }
  2039.       }
  2040.     } while (response.Read(*this));
  2041.   }
  2042.  
  2043.   PTRACE(2, "RAS\tGatekeeper discovery failed");
  2044.   localAddress = originalLocalAddress;
  2045.   localPort = originalLocalPort;
  2046.   promiscuousReads = AcceptFromRemoteOnly;
  2047.   readChannel = NULL;
  2048.   return FALSE;
  2049. }
  2050.  
  2051.  
  2052. /////////////////////////////////////////////////////////////////////////////
  2053.