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 / h323ep.cxx < prev    next >
Text File  |  2003-04-28  |  76KB  |  2,484 lines

  1. /*
  2.  * h323ep.cxx
  3.  *
  4.  * H.323 protocol 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: h323ep.cxx,v $
  30.  * Revision 1.166  2003/04/28 09:01:15  robertj
  31.  * Fixed problem with backward compatibility with non-url based remote
  32.  *   addresses passed to MakeCall()
  33.  *
  34.  * Revision 1.165  2003/04/24 01:49:33  dereks
  35.  * Add ability to set no media timeout interval
  36.  *
  37.  * Revision 1.164  2003/04/10 09:41:26  robertj
  38.  * Added associated transport to new GetInterfaceAddresses() function so
  39.  *   interfaces can be ordered according to active transport links. Improves
  40.  *   interoperability.
  41.  *
  42.  * Revision 1.163  2003/04/10 01:01:56  craigs
  43.  * Added functions to access to lists of interfaces
  44.  *
  45.  * Revision 1.162  2003/04/07 13:09:30  robertj
  46.  * Added ILS support to callto URL parsing in MakeCall(), ie can now call hosts
  47.  *   registered with an ILS directory.
  48.  *
  49.  * Revision 1.161  2003/04/07 11:11:45  craigs
  50.  * Fixed compile problem on Linux
  51.  *
  52.  * Revision 1.160  2003/04/04 08:04:35  robertj
  53.  * Added support for URL's in MakeCall, especially h323 and callto schemes.
  54.  *
  55.  * Revision 1.159  2003/03/04 03:58:32  robertj
  56.  * Fixed missing local interface usage if specified in UseGatekeeper()
  57.  *
  58.  * Revision 1.158  2003/02/28 09:00:37  rogerh
  59.  * remove redundant code
  60.  *
  61.  * Revision 1.157  2003/02/25 23:51:49  robertj
  62.  * Fxied bug where not getting last port in range, thanks Sonya Cooper-Hull
  63.  *
  64.  * Revision 1.156  2003/02/09 00:48:09  robertj
  65.  * Added function to return if registered with gatekeeper.
  66.  *
  67.  * Revision 1.155  2003/02/05 06:32:10  robertj
  68.  * Fixed non-stun symmetric NAT support recently broken.
  69.  *
  70.  * Revision 1.154  2003/02/05 04:56:35  robertj
  71.  * Fixed setting STUN server to enpty string clearing stun variable.
  72.  *
  73.  * Revision 1.153  2003/02/04 07:06:41  robertj
  74.  * Added STUN support.
  75.  *
  76.  * Revision 1.152  2003/02/01 13:31:22  robertj
  77.  * Changes to support CAT authentication in RAS.
  78.  *
  79.  * Revision 1.151  2003/01/26 05:57:29  robertj
  80.  * Changed ParsePartyName so will accept addresses of the form
  81.  *   alias@gk:address which will do an LRQ call to "address" using "alias"
  82.  *   to determine the IP address to connect to.
  83.  *
  84.  * Revision 1.150  2003/01/23 02:36:32  robertj
  85.  * Increased (and made configurable) timeout for H.245 channel TCP connection.
  86.  *
  87.  * Revision 1.149  2003/01/06 06:13:37  robertj
  88.  * Increased maximum possible jitter configuration to 10 seconds.
  89.  *
  90.  * Revision 1.148  2002/11/27 06:54:57  robertj
  91.  * Added Service Control Session management as per Annex K/H.323 via RAS
  92.  *   only at this stage.
  93.  * Added H.248 ASN and very primitive infrastructure for linking into the
  94.  *   Service Control Session management system.
  95.  * Added basic infrastructure for Annex K/H.323 HTTP transport system.
  96.  * Added Call Credit Service Control to display account balances.
  97.  *
  98.  * Revision 1.147  2002/11/19 07:07:44  robertj
  99.  * Changed priority so H.235 standard authentication used by preference.
  100.  *
  101.  * Revision 1.146  2002/11/15 06:53:24  robertj
  102.  * Fixed non facility redirect calls being able to be cleared!
  103.  *
  104.  * Revision 1.145  2002/11/15 05:17:26  robertj
  105.  * Added facility redirect support without changing the call token for access
  106.  *   to the call. If it gets redirected a new H323Connection object is
  107.  *   created but it looks like the same thing to an application.
  108.  *
  109.  * Revision 1.144  2002/11/14 22:06:08  robertj
  110.  * Increased default maximum number of ports.
  111.  *
  112.  * Revision 1.143  2002/11/10 08:10:43  robertj
  113.  * Moved constants for "well known" ports to better place (OPAL change).
  114.  *
  115.  * Revision 1.142  2002/10/31 00:42:41  robertj
  116.  * Enhanced jitter buffer system so operates dynamically between minimum and
  117.  *   maximum values. Altered API to assure app writers note the change!
  118.  *
  119.  * Revision 1.141  2002/10/24 07:18:24  robertj
  120.  * Changed gatekeeper call so if can do local DNS lookup or using IP address
  121.  *   then uses destCallSignalAddress for ARQ instead of destinationInfo.
  122.  *
  123.  * Revision 1.140  2002/10/23 06:06:13  robertj
  124.  * Added function to be smarter in using a gatekeeper for use by endpoint.
  125.  *
  126.  * Revision 1.139  2002/10/01 06:38:36  robertj
  127.  * Removed GNU compiler warning
  128.  *
  129.  * Revision 1.138  2002/10/01 03:07:15  robertj
  130.  * Added version number functions for OpenH323 library itself, plus included
  131.  *   library version in the default vendor information.
  132.  *
  133.  * Revision 1.137  2002/08/15 04:56:56  robertj
  134.  * Fixed operation of ports system assuring RTP is even numbers.
  135.  *
  136.  * Revision 1.136  2002/08/05 10:03:47  robertj
  137.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  138.  *
  139.  * Revision 1.135  2002/07/19 11:25:10  robertj
  140.  * Added extra trace on attempt to clear non existent call.
  141.  *
  142.  * Revision 1.134  2002/07/19 03:39:22  robertj
  143.  * Bullet proofed setting of RTP IP port base, can't be zero!
  144.  *
  145.  * Revision 1.133  2002/07/18 01:50:14  robertj
  146.  * Changed port secltion code to force apps to use function interface.
  147.  *
  148.  * Revision 1.132  2002/07/04 00:11:25  robertj
  149.  * Fixed setting of gk password when password changed in endpoint.
  150.  *
  151.  * Revision 1.131  2002/06/22 05:48:42  robertj
  152.  * Added partial implementation for H.450.11 Call Intrusion
  153.  *
  154.  * Revision 1.130  2002/06/15 03:06:46  robertj
  155.  * Fixed locking of connection on H.250.2 transfer, thanks Gilles Delcayre
  156.  *
  157.  * Revision 1.129  2002/06/13 06:15:20  robertj
  158.  * Allowed TransferCall() to be used on H323Connection as well as H323EndPoint.
  159.  *
  160.  * Revision 1.128  2002/06/12 03:55:21  robertj
  161.  * Added function to add/remove multiple listeners in one go comparing against
  162.  *   what is already running so does not interrupt unchanged listeners.
  163.  *
  164.  * Revision 1.127  2002/05/29 06:40:33  robertj
  165.  * Changed sending of endSession/ReleaseComplete PDU's to occur immediately
  166.  *   on call clearance and not wait for background thread to do it.
  167.  * Stricter compliance by waiting for reply endSession before closing down.
  168.  *
  169.  * Revision 1.126  2002/05/28 06:16:12  robertj
  170.  * Split UDP (for RAS) from RTP port bases.
  171.  * Added current port variable so cycles around the port range specified which
  172.  *   fixes some wierd problems on some platforms, thanks Federico Pinna
  173.  *
  174.  * Revision 1.125  2002/05/17 03:39:01  robertj
  175.  * Fixed problems with H.235 authentication on RAS for server and client.
  176.  *
  177.  * Revision 1.124  2002/05/15 23:57:49  robertj
  178.  * Added function to get the tokens for all active calls.
  179.  * Fixed setting of password info in gatekeeper so is before discovery.
  180.  *
  181.  * Revision 1.123  2002/05/02 07:56:28  robertj
  182.  * Added automatic clearing of call if no media (RTP data) is transferred in a
  183.  *   configurable (default 5 minutes) amount of time.
  184.  *
  185.  * Revision 1.122  2002/04/18 01:40:56  robertj
  186.  * Fixed bad variable name for disabling DTMF detection, very confusing.
  187.  *
  188.  * Revision 1.121  2002/04/17 00:50:57  robertj
  189.  * Added ability to disable the in band DTMF detection.
  190.  *
  191.  * Revision 1.120  2002/04/10 08:09:03  robertj
  192.  * Allowed zero TCP ports
  193.  *
  194.  * Revision 1.119  2002/04/10 06:50:08  robertj
  195.  * Added functions to set port member variables.
  196.  *
  197.  * Revision 1.118  2002/04/01 21:32:24  robertj
  198.  * Fixed problem with busy loop on Solaris, thanks chad@broadmind.com
  199.  *
  200.  * Revision 1.117  2002/02/04 07:17:56  robertj
  201.  * Added H.450.2 Consultation Transfer, thanks Norwood Systems.
  202.  *
  203.  * Revision 1.116  2002/01/24 06:29:06  robertj
  204.  * Added option to disable H.245 negotiation in SETUP pdu, this required
  205.  *   API change so have a bit mask instead of a series of booleans.
  206.  *
  207.  * Revision 1.115  2002/01/17 07:05:04  robertj
  208.  * Added support for RFC2833 embedded DTMF in the RTP stream.
  209.  *
  210.  * Revision 1.114  2002/01/14 00:00:04  robertj
  211.  * Added CallTransfer timeouts to endpoint, hanks Ben Madsen of Norwood Systems.
  212.  *
  213.  * Revision 1.113  2002/01/08 04:45:04  robertj
  214.  * Added MakeCallLocked() so can start a call with the H323Connection instance
  215.  *   initally locked so can do things to it before the call really starts.
  216.  *
  217.  * Revision 1.112  2001/12/22 03:20:05  robertj
  218.  * Added create protocol function to H323Connection.
  219.  *
  220.  * Revision 1.111  2001/12/14 08:36:36  robertj
  221.  * More implementation of T.38, thanks Adam Lazur
  222.  *
  223.  * Revision 1.110  2001/12/13 11:01:37  robertj
  224.  * Fixed missing initialisation of auto fax start variables.
  225.  *
  226.  * Revision 1.109  2001/11/01 06:11:57  robertj
  227.  * Plugged very small mutex hole that could cause crashes.
  228.  *
  229.  * Revision 1.108  2001/11/01 00:59:07  robertj
  230.  * Added auto setting of silence detect mode when using PSoundChannel codec.
  231.  *
  232.  * Revision 1.107  2001/11/01 00:27:35  robertj
  233.  * Added default Fast Start disabled and H.245 tunneling disable flags
  234.  *   to the endpoint instance.
  235.  *
  236.  * Revision 1.106  2001/10/30 07:34:33  robertj
  237.  * Added trace for when cleaner thread start, stops and runs
  238.  *
  239.  * Revision 1.105  2001/10/24 07:25:59  robertj
  240.  * Fixed possible deadlocks during destruction of H323Connection object.
  241.  *
  242.  * Revision 1.104  2001/09/26 06:20:59  robertj
  243.  * Fixed properly nesting connection locking and unlocking requiring a quite
  244.  *   large change to teh implementation of how calls are answered.
  245.  *
  246.  * Revision 1.103  2001/09/13 02:41:21  robertj
  247.  * Fixed call reference generation to use full range and common code.
  248.  *
  249.  * Revision 1.102  2001/09/11 01:24:36  robertj
  250.  * Added conditional compilation to remove video and/or audio codecs.
  251.  *
  252.  * Revision 1.101  2001/09/11 00:21:23  robertj
  253.  * Fixed missing stack sizes in endpoint for cleaner thread and jitter thread.
  254.  *
  255.  * Revision 1.100  2001/08/24 13:38:25  rogerh
  256.  * Free the locally declared listener.
  257.  *
  258.  * Revision 1.99  2001/08/24 13:23:59  rogerh
  259.  * Undo a recent memory leak fix. The listener object has to be deleted in the
  260.  * user application as they use the listener when StartListener() fails.
  261.  * Add a Resume() if StartListener() fails so user applications can delete
  262.  * the suspended thread.
  263.  *
  264.  * Revision 1.98  2001/08/22 06:54:51  robertj
  265.  * Changed connection locking to use double mutex to guarantee that
  266.  *   no threads can ever deadlock or access deleted connection.
  267.  *
  268.  * Revision 1.97  2001/08/16 07:49:19  robertj
  269.  * Changed the H.450 support to be more extensible. Protocol handlers
  270.  *   are now in separate classes instead of all in H323Connection.
  271.  *
  272.  * Revision 1.96  2001/08/10 11:03:52  robertj
  273.  * Major changes to H.235 support in RAS to support server.
  274.  *
  275.  * Revision 1.95  2001/08/08 23:55:27  robertj
  276.  * Fixed problem with setting gk password before have a gk variable.
  277.  * Fixed memory leak if listener fails to open.
  278.  * Fixed problem with being able to specify an alias with an @ in it.
  279.  *
  280.  * Revision 1.94  2001/08/06 07:44:55  robertj
  281.  * Fixed problems with building without SSL
  282.  *
  283.  * Revision 1.93  2001/08/06 03:08:56  robertj
  284.  * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
  285.  *
  286.  * Revision 1.92  2001/08/02 04:31:48  robertj
  287.  * Changed to still maintain gatekeeper link if GRQ succeeded but RRQ
  288.  *   failed. Thanks Ben Madsen & Graeme Reid.
  289.  *
  290.  * Revision 1.91  2001/07/17 04:44:32  robertj
  291.  * Partial implementation of T.120 and T.38 logical channels.
  292.  *
  293.  * Revision 1.90  2001/07/06 07:28:55  robertj
  294.  * Fixed rearranged connection creation to avoid possible nested mutex.
  295.  *
  296.  * Revision 1.89  2001/07/06 04:46:19  robertj
  297.  * Rearranged connection creation to avoid possible nested mutex.
  298.  *
  299.  * Revision 1.88  2001/06/19 08:43:38  robertj
  300.  * Fixed deadlock if ClearCallSynchronous ever called from cleaner thread.
  301.  *
  302.  * Revision 1.87  2001/06/19 03:55:30  robertj
  303.  * Added transport to CreateConnection() function so can use that as part of
  304.  *   the connection creation decision making process.
  305.  *
  306.  * Revision 1.86  2001/06/15 00:55:53  robertj
  307.  * Added thread name for cleaner thread
  308.  *
  309.  * Revision 1.85  2001/06/14 23:18:06  robertj
  310.  * Change to allow for CreateConnection() to return NULL to abort call.
  311.  *
  312.  * Revision 1.84  2001/06/14 04:23:32  robertj
  313.  * Changed incoming call to pass setup pdu to endpoint so it can create
  314.  *   different connection subclasses depending on the pdu eg its alias
  315.  *
  316.  * Revision 1.83  2001/06/02 01:35:32  robertj
  317.  * Added thread names.
  318.  *
  319.  * Revision 1.82  2001/05/30 11:13:54  robertj
  320.  * Fixed possible deadlock when getting connection from endpoint.
  321.  *
  322.  * Revision 1.81  2001/05/14 05:56:28  robertj
  323.  * Added H323 capability registration system so can add capabilities by
  324.  *   string name instead of having to instantiate explicit classes.
  325.  *
  326.  * Revision 1.80  2001/05/01 04:34:11  robertj
  327.  * Changed call transfer API slightly to be consistent with new hold function.
  328.  *
  329.  * Revision 1.79  2001/04/23 01:31:15  robertj
  330.  * Improved the locking of connections especially at shutdown.
  331.  *
  332.  * Revision 1.78  2001/04/11 03:01:29  robertj
  333.  * Added H.450.2 (call transfer), thanks a LOT to Graeme Reid & Norwood Systems
  334.  *
  335.  * Revision 1.77  2001/03/21 04:52:42  robertj
  336.  * Added H.235 security to gatekeepers, thanks Fⁿrbass Franz!
  337.  *
  338.  * Revision 1.76  2001/03/17 00:05:52  robertj
  339.  * Fixed problems with Gatekeeper RIP handling.
  340.  *
  341.  * Revision 1.75  2001/03/15 00:24:47  robertj
  342.  * Added function for setting gatekeeper with address and identifier values.
  343.  *
  344.  * Revision 1.74  2001/02/27 00:03:59  robertj
  345.  * Fixed possible deadlock in FindConnectionsWithLock(), thanks Hans Andersen
  346.  *
  347.  * Revision 1.73  2001/02/16 04:11:35  robertj
  348.  * Added ability for RemoveListener() to remove all listeners.
  349.  *
  350.  * Revision 1.72  2001/01/18 06:04:18  robertj
  351.  * Bullet proofed code so local alias can not be empty string. This actually
  352.  *   fixes an ASN PER encoding bug causing an assert.
  353.  *
  354.  * Revision 1.71  2001/01/11 02:19:15  craigs
  355.  * Fixed problem with possible window of opportunity for ClearCallSynchronous
  356.  * to return even though call has not been cleared
  357.  *
  358.  * Revision 1.70  2000/12/22 03:54:33  craigs
  359.  * Fixed problem with listening fix
  360.  *
  361.  * Revision 1.69  2000/12/21 12:38:24  craigs
  362.  * Fixed problem with "Listener thread did not terminate" assert
  363.  * when listener port is in use
  364.  *
  365.  * Revision 1.68  2000/12/20 00:51:03  robertj
  366.  * Fixed MSVC compatibility issues (No trace).
  367.  *
  368.  * Revision 1.67  2000/12/19 22:33:44  dereks
  369.  * Adjust so that the video channel is used for reading/writing raw video
  370.  * data, which better modularizes the video codec.
  371.  *
  372.  * Revision 1.66  2000/12/18 08:59:20  craigs
  373.  * Added ability to set ports
  374.  *
  375.  * Revision 1.65  2000/12/18 01:22:28  robertj
  376.  * Changed semantics or HasConnection() so returns TRUE until the connection
  377.  *   has been deleted and not just until ClearCall() was executure on it.
  378.  *
  379.  * Revision 1.64  2000/11/27 02:44:06  craigs
  380.  * Added ClearCall Synchronous to H323Connection and H323Endpoint to
  381.  * avoid race conditions with destroying descendant classes
  382.  *
  383.  * Revision 1.63  2000/11/26 23:13:23  craigs
  384.  * Added ability to pass user data to H323Connection constructor
  385.  *
  386.  * Revision 1.62  2000/11/12 23:49:16  craigs
  387.  * Added per connection versions of OnEstablished and OnCleared
  388.  *
  389.  * Revision 1.61  2000/10/25 00:53:52  robertj
  390.  * Used official manafacturer code for the OpenH323 project.
  391.  *
  392.  * Revision 1.60  2000/10/20 06:10:51  robertj
  393.  * Fixed very small race condition on creating new connectionon incoming call.
  394.  *
  395.  * Revision 1.59  2000/10/19 04:07:50  robertj
  396.  * Added function to be able to remove a listener.
  397.  *
  398.  * Revision 1.58  2000/10/04 12:21:07  robertj
  399.  * Changed setting of callToken in H323Connection to be as early as possible.
  400.  *
  401.  * Revision 1.57  2000/09/25 12:59:34  robertj
  402.  * Added StartListener() function that takes a H323TransportAddress to start
  403.  *     listeners bound to specific interfaces.
  404.  *
  405.  * Revision 1.56  2000/09/14 23:03:45  robertj
  406.  * Increased timeout on asserting because of driver lockup
  407.  *
  408.  * Revision 1.55  2000/09/01 02:13:05  robertj
  409.  * Added ability to select a gatekeeper on LAN via it's identifier name.
  410.  *
  411.  * Revision 1.54  2000/08/30 05:37:44  robertj
  412.  * Fixed bogus destCallSignalAddress in ARQ messages.
  413.  *
  414.  * Revision 1.53  2000/08/29 02:59:50  robertj
  415.  * Added some debug output for channel open/close.
  416.  *
  417.  * Revision 1.52  2000/08/25 01:10:28  robertj
  418.  * Added assert if various thrads ever fail to terminate.
  419.  *
  420.  * Revision 1.51  2000/07/13 12:34:41  robertj
  421.  * Split autoStartVideo so can select receive and transmit independently
  422.  *
  423.  * Revision 1.50  2000/07/11 19:30:15  robertj
  424.  * Fixed problem where failure to unregister from gatekeeper prevented new registration.
  425.  *
  426.  * Revision 1.49  2000/07/09 14:59:28  robertj
  427.  * Fixed bug if using default transport (no '@') for address when gatekeeper present, used port 1719.
  428.  *
  429.  * Revision 1.48  2000/07/04 04:15:40  robertj
  430.  * Fixed capability check of "combinations" for fast start cases.
  431.  *
  432.  * Revision 1.47  2000/07/04 01:16:50  robertj
  433.  * Added check for capability allowed in "combinations" set, still needs more done yet.
  434.  *
  435.  * Revision 1.46  2000/06/29 11:00:04  robertj
  436.  * Added user interface for sound buffer depth adjustment.
  437.  *
  438.  * Revision 1.45  2000/06/29 07:10:32  robertj
  439.  * Fixed incorrect setting of default number of audio buffers on Win32 systems.
  440.  *
  441.  * Revision 1.44  2000/06/23 02:48:24  robertj
  442.  * Added ability to adjust sound channel buffer depth, needed increasing under Win32.
  443.  *
  444.  * Revision 1.43  2000/06/20 02:38:28  robertj
  445.  * Changed H323TransportAddress to default to IP.
  446.  *
  447.  * Revision 1.42  2000/06/17 09:13:06  robertj
  448.  * Removed redundent line of code, thanks David Iodice.
  449.  *
  450.  * Revision 1.41  2000/06/07 05:48:06  robertj
  451.  * Added call forwarding.
  452.  *
  453.  * Revision 1.40  2000/06/03 03:16:39  robertj
  454.  * Fixed using the wrong capability table (should be connections) for some operations.
  455.  *
  456.  * Revision 1.39  2000/05/25 00:34:59  robertj
  457.  * Changed default tos on Unix platforms to avoid needing to be root.
  458.  *
  459.  * Revision 1.38  2000/05/23 12:57:37  robertj
  460.  * Added ability to change IP Type Of Service code from applications.
  461.  *
  462.  * Revision 1.37  2000/05/23 11:32:37  robertj
  463.  * Rewrite of capability table to combine 2 structures into one and move functionality into that class
  464.  *    allowing some normalisation of usage across several applications.
  465.  * Changed H323Connection so gets a copy of capabilities instead of using endponts, allows adjustments
  466.  *    to be done depending on the remote client application.
  467.  *
  468.  * Revision 1.36  2000/05/16 07:38:50  robertj
  469.  * Added extra debug info indicating sound channel buffer size.
  470.  *
  471.  * Revision 1.35  2000/05/11 03:48:11  craigs
  472.  * Moved SetBuffer command to fix audio delay
  473.  *
  474.  * Revision 1.34  2000/05/02 04:32:26  robertj
  475.  * Fixed copyright notice comment.
  476.  *
  477.  * Revision 1.33  2000/05/01 13:00:28  robertj
  478.  * Changed SetCapability() to append capabilities to TCS, helps with assuring no gaps in set.
  479.  *
  480.  * Revision 1.32  2000/04/30 03:58:37  robertj
  481.  * Changed PSoundChannel to be only double bufferred, this is all that is needed with jitter bufferring.
  482.  *
  483.  * Revision 1.31  2000/04/11 04:02:48  robertj
  484.  * Improved call initiation with gatekeeper, no longer require @address as
  485.  *    will default to gk alias if no @ and registered with gk.
  486.  * Added new call end reasons for gatekeeper denied calls.
  487.  *
  488.  * Revision 1.30  2000/04/10 20:37:33  robertj
  489.  * Added support for more sophisticated DTMF and hook flash user indication.
  490.  *
  491.  * Revision 1.29  2000/04/06 17:50:17  robertj
  492.  * Added auto-start (including fast start) of video channels, selectable via boolean on the endpoint.
  493.  *
  494.  * Revision 1.28  2000/04/05 03:17:31  robertj
  495.  * Added more RTP statistics gathering and H.245 round trip delay calculation.
  496.  *
  497.  * Revision 1.27  2000/03/29 02:14:45  robertj
  498.  * Changed TerminationReason to CallEndReason to use correct telephony nomenclature.
  499.  * Added CallEndReason for capability exchange failure.
  500.  *
  501.  * Revision 1.26  2000/03/25 02:03:36  robertj
  502.  * Added default transport for gatekeeper to be UDP.
  503.  *
  504.  * Revision 1.25  2000/03/23 02:45:29  robertj
  505.  * Changed ClearAllCalls() so will wait for calls to be closed (usefull in endpoint dtors).
  506.  *
  507.  * Revision 1.24  2000/02/17 12:07:43  robertj
  508.  * Used ne wPWLib random number generator after finding major problem in MSVC rand().
  509.  *
  510.  * Revision 1.23  2000/01/07 08:22:49  robertj
  511.  * Added status functions for connection and added transport independent MakeCall
  512.  *
  513.  * Revision 1.22  1999/12/23 23:02:36  robertj
  514.  * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
  515.  *
  516.  * Revision 1.21  1999/12/11 02:21:00  robertj
  517.  * Added ability to have multiple aliases on local endpoint.
  518.  *
  519.  * Revision 1.20  1999/12/09 23:14:20  robertj
  520.  * Fixed deadock in termination with gatekeeper removal.
  521.  *
  522.  * Revision 1.19  1999/11/19 08:07:27  robertj
  523.  * Changed default jitter time to 50 milliseconds.
  524.  *
  525.  * Revision 1.18  1999/11/06 05:37:45  robertj
  526.  * Complete rewrite of termination of connection to avoid numerous race conditions.
  527.  *
  528.  * Revision 1.17  1999/10/30 12:34:47  robertj
  529.  * Added information callback for closed logical channel on H323EndPoint.
  530.  *
  531.  * Revision 1.16  1999/10/19 00:04:57  robertj
  532.  * Changed OpenAudioChannel and OpenVideoChannel to allow a codec AttachChannel with no autodelete.
  533.  *
  534.  * Revision 1.15  1999/10/14 12:05:03  robertj
  535.  * Fixed deadlock possibilities in clearing calls.
  536.  *
  537.  * Revision 1.14  1999/10/09 01:18:23  craigs
  538.  * Added codecs to OpenAudioChannel and OpenVideoDevice functions
  539.  *
  540.  * Revision 1.13  1999/10/08 08:31:45  robertj
  541.  * Fixed failure to adjust capability when startign channel
  542.  *
  543.  * Revision 1.12  1999/09/23 07:25:12  robertj
  544.  * Added open audio and video function to connection and started multi-frame codec send functionality.
  545.  *
  546.  * Revision 1.11  1999/09/21 14:24:48  robertj
  547.  * Changed SetCapability() so automatically calls AddCapability().
  548.  *
  549.  * Revision 1.10  1999/09/21 14:12:40  robertj
  550.  * Removed warnings when no tracing enabled.
  551.  *
  552.  * Revision 1.9  1999/09/21 08:10:03  craigs
  553.  * Added support for video devices and H261 codec
  554.  *
  555.  * Revision 1.8  1999/09/14 06:52:54  robertj
  556.  * Added better support for multi-homed client hosts.
  557.  *
  558.  * Revision 1.7  1999/09/13 14:23:11  robertj
  559.  * Changed MakeCall() function return value to be something useful.
  560.  *
  561.  * Revision 1.6  1999/09/10 02:55:36  robertj
  562.  * Changed t35 country code to Australia (finally found magic number).
  563.  *
  564.  * Revision 1.5  1999/09/08 04:05:49  robertj
  565.  * Added support for video capabilities & codec, still needs the actual codec itself!
  566.  *
  567.  * Revision 1.4  1999/08/31 12:34:19  robertj
  568.  * Added gatekeeper support.
  569.  *
  570.  * Revision 1.3  1999/08/27 15:42:44  craigs
  571.  * Fixed problem with local call tokens using ambiguous interface names, and connect timeouts not changing connection state
  572.  *
  573.  * Revision 1.2  1999/08/27 09:46:05  robertj
  574.  * Added sepearte function to initialise vendor information from endpoint.
  575.  *
  576.  * Revision 1.1  1999/08/25 05:10:36  robertj
  577.  * File fission (critical mass reached).
  578.  * Improved way in which remote capabilities are created, removed case statement!
  579.  * Changed MakeCall, so immediately spawns thread, no black on TCP connect.
  580.  *
  581.  */
  582.  
  583. #include <ptlib.h>
  584.  
  585. #ifdef __GNUC__
  586. #pragma implementation "h323ep.h"
  587. #endif
  588.  
  589. #include "h323ep.h"
  590. #include "h323pdu.h"
  591. #include "h450pdu.h"
  592. #include "gkclient.h"
  593. #include "t38proto.h"
  594. #include "../version.h"
  595.  
  596. #include <ptclib/random.h>
  597. #include <ptclib/pstun.h>
  598. #include <ptclib/url.h>
  599. #include <ptclib/pils.h>
  600.  
  601.  
  602. #ifndef IPTOS_PREC_CRITIC_ECP
  603. #define IPTOS_PREC_CRITIC_ECP (5 << 5)
  604. #endif
  605.  
  606. #ifndef IPTOS_LOWDELAY
  607. #define IPTOS_LOWDELAY 0x10
  608. #endif
  609.  
  610.  
  611. class H225CallThread : public PThread
  612. {
  613.   PCLASSINFO(H225CallThread, PThread)
  614.  
  615.   public:
  616.     H225CallThread(H323EndPoint & endpoint,
  617.                    H323Connection & connection,
  618.                    H323Transport & transport,
  619.                    const PString & alias,
  620.                    const H323TransportAddress & address);
  621.  
  622.   protected:
  623.     void Main();
  624.  
  625.     H323Connection     & connection;
  626.     H323Transport      & transport;
  627.     PString              alias;
  628.     H323TransportAddress address;
  629. };
  630.  
  631.  
  632. class H323ConnectionsCleaner : public PThread
  633. {
  634.   PCLASSINFO(H323ConnectionsCleaner, PThread)
  635.  
  636.   public:
  637.     H323ConnectionsCleaner(H323EndPoint & endpoint);
  638.     ~H323ConnectionsCleaner();
  639.  
  640.     void Signal() { wakeupFlag.Signal(); }
  641.  
  642.   protected:
  643.     void Main();
  644.  
  645.     H323EndPoint & endpoint;
  646.     BOOL           stopFlag;
  647.     PSyncPoint     wakeupFlag;
  648. };
  649.  
  650.  
  651. #define new PNEW
  652.  
  653. #if !PTRACING // Stuff to remove unised parameters warning
  654. #define PTRACE_caller
  655. #define PTRACE_isEncoding
  656. #define PTRACE_channel
  657. #endif
  658.  
  659.  
  660. /////////////////////////////////////////////////////////////////////////////
  661.  
  662. PString OpalGetVersion()
  663. {
  664. #define AlphaCode   "alpha"
  665. #define BetaCode    "beta"
  666. #define ReleaseCode "."
  667.  
  668.   return psprintf("%u.%u%s%u", MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER);
  669. }
  670.  
  671.  
  672. unsigned OpalGetMajorVersion()
  673. {
  674.   return MAJOR_VERSION;
  675. }
  676.  
  677. unsigned OpalGetMinorVersion()
  678. {
  679.   return MINOR_VERSION;
  680. }
  681.  
  682. unsigned OpalGetBuildNumber()
  683. {
  684.   return BUILD_NUMBER;
  685. }
  686.  
  687.  
  688.  
  689. /////////////////////////////////////////////////////////////////////////////
  690.  
  691. H225CallThread::H225CallThread(H323EndPoint & endpoint,
  692.                                H323Connection & c,
  693.                                H323Transport & t,
  694.                                const PString & a,
  695.                                const H323TransportAddress & addr)
  696.   : PThread(endpoint.GetSignallingThreadStackSize(),
  697.             NoAutoDeleteThread,
  698.             NormalPriority,
  699.             "H225 Caller:%0x"),
  700.     connection(c),
  701.     transport(t),
  702.     alias(a),
  703.     address(addr)
  704. {
  705.   transport.AttachThread(this);
  706.   Resume();
  707. }
  708.  
  709.  
  710. void H225CallThread::Main()
  711. {
  712.   PTRACE(3, "H225\tStarted call thread");
  713.  
  714.   if (connection.Lock()) {
  715.     H323Connection::CallEndReason reason = connection.SendSignalSetup(alias, address);
  716.  
  717.     // Special case, if we aborted the call then already will be unlocked
  718.     if (reason != H323Connection::EndedByCallerAbort)
  719.       connection.Unlock();
  720.  
  721.     // Check if had an error, clear call if so
  722.     if (reason != H323Connection::NumCallEndReasons)
  723.       connection.ClearCall(reason);
  724.     else
  725.       connection.HandleSignallingChannel();
  726.   }
  727. }
  728.  
  729.  
  730. /////////////////////////////////////////////////////////////////////////////
  731.  
  732. H323ConnectionsCleaner::H323ConnectionsCleaner(H323EndPoint & ep)
  733.   : PThread(ep.GetCleanerThreadStackSize(),
  734.             NoAutoDeleteThread,
  735.             NormalPriority,
  736.             "H323 Cleaner"),
  737.     endpoint(ep)
  738. {
  739.   Resume();
  740.   stopFlag = FALSE;
  741. }
  742.  
  743.  
  744. H323ConnectionsCleaner::~H323ConnectionsCleaner()
  745. {
  746.   stopFlag = TRUE;
  747.   wakeupFlag.Signal();
  748.   PAssert(WaitForTermination(10000), "Cleaner thread did not terminate");
  749. }
  750.  
  751.  
  752. void H323ConnectionsCleaner::Main()
  753. {
  754.   PTRACE(3, "H323\tStarted cleaner thread");
  755.  
  756.   for (;;) {
  757.     wakeupFlag.Wait();
  758.     if (stopFlag)
  759.       break;
  760.  
  761.     endpoint.CleanUpConnections();
  762.   }
  763.  
  764.   PTRACE(3, "H323\tStopped cleaner thread");
  765. }
  766.  
  767.  
  768. /////////////////////////////////////////////////////////////////////////////
  769.  
  770. H323EndPoint::H323EndPoint()
  771.   : soundChannelPlayDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Player)),
  772.     soundChannelRecordDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Recorder)),
  773.     signallingChannelCallTimeout(0, 0, 1),  // Minutes
  774.     controlChannelStartTimeout(0, 0, 2),    // Minutes
  775.     endSessionTimeout(0, 10),               // Seconds
  776.     masterSlaveDeterminationTimeout(0, 30), // Seconds
  777.     capabilityExchangeTimeout(0, 30),       // Seconds
  778.     logicalChannelTimeout(0, 30),           // Seconds
  779.     requestModeTimeout(0, 30),              // Seconds
  780.     roundTripDelayTimeout(0, 10),           // Seconds
  781.     roundTripDelayRate(0, 0, 1),            // Minutes
  782.     noMediaTimeout(0, 0, 5),                // Minutes
  783.     gatekeeperRequestTimeout(0, 5),         // Seconds
  784.     rasRequestTimeout(0, 3),                // Seconds
  785.     callTransferT1(0,10),                   // Seconds
  786.     callTransferT2(0,10),                   // Seconds
  787.     callTransferT3(0,10),                   // Seconds
  788.     callTransferT4(0,10),                   // Seconds
  789.     callIntrusionT1(0,30),                  // Seconds
  790.     callIntrusionT2(0,30),                  // Seconds
  791.     callIntrusionT3(0,30),                  // Seconds
  792.     callIntrusionT4(0,30),                  // Seconds
  793.     callIntrusionT5(0,10),                  // Seconds
  794.     callIntrusionT6(0,10)                   // Seconds
  795. {
  796.   PString username = PProcess::Current().GetUserName();
  797.   if (username.IsEmpty())
  798.     username = PProcess::Current().GetName() & "User";
  799.   localAliasNames.AppendString(username);
  800.  
  801.   autoStartReceiveVideo = autoStartTransmitVideo = TRUE;
  802.   autoStartReceiveFax = autoStartTransmitFax = FALSE;
  803.   autoCallForward = TRUE;
  804.   disableFastStart = FALSE;
  805.   disableH245Tunneling = FALSE;
  806.   disableH245inSetup = FALSE;
  807.   disableDetectInBandDTMF = FALSE;
  808.   canDisplayAmountString = FALSE;
  809.   canEnforceDurationLimit = TRUE;
  810.   callIntrusionProtectionLevel = 3; //H45011_CIProtectionLevel::e_fullProtection;
  811.   defaultSilenceDetection = H323AudioCodec::AdaptiveSilenceDetection;
  812.   defaultSendUserInputMode = H323Connection::SendUserInputAsString;
  813.  
  814.   terminalType = e_TerminalOnly;
  815.   minAudioJitterDelay = 50;  // milliseconds
  816.   maxAudioJitterDelay = 250; // milliseconds
  817.   initialBandwidth = 100000; // Standard 10base LAN in 100's of bits/sec
  818.   clearCallOnRoundTripFail = FALSE;
  819.  
  820.   t35CountryCode = 9; // Country code for Australia
  821.   t35Extension = 0;
  822.   manufacturerCode = 61; // Allocated by Australian Communications Authority, Oct 2000
  823.  
  824.   rtpIpPorts.current = rtpIpPorts.base = 5000;
  825.   rtpIpPorts.max = 5999;
  826.  
  827.   // use dynamic port allocation by default
  828.   tcpPorts.current = tcpPorts.base = tcpPorts.max = 0;
  829.   udpPorts.current = udpPorts.base = udpPorts.max = 0;
  830.  
  831.   stun = NULL;
  832.  
  833. #ifdef _WIN32
  834.   // Windows MultMedia stuff seems to need greater depth due to enormous
  835.   // latencies in its operation, need to use DirectSound maybe?
  836.   soundChannelBuffers = 3;
  837.   rtpIpTypeofService = IPTOS_PREC_CRITIC_ECP|IPTOS_LOWDELAY;
  838. #else
  839.   // Should only need double buffering for Unix platforms
  840.   soundChannelBuffers = 2;
  841.   // Don't use IPTOS_PREC_CRITIC_ECP on Unix platforms as then need to be root
  842.   rtpIpTypeofService = IPTOS_LOWDELAY;
  843. #endif
  844.   masterSlaveDeterminationRetries = 10;
  845.   gatekeeperRequestRetries = 2;
  846.   rasRequestRetries = 2;
  847.  
  848.   cleanerThreadStackSize    = 30000;
  849.   listenerThreadStackSize   = 30000;
  850.   signallingThreadStackSize = 30000;
  851.   controlThreadStackSize    = 30000;
  852.   logicalThreadStackSize    = 30000;
  853.   rasThreadStackSize        = 30000;
  854.   jitterThreadStackSize     = 30000;
  855.  
  856.   gatekeeper = NULL;
  857.  
  858.   connectionsActive.DisallowDeleteObjects();
  859.  
  860.   connectionsCleaner = new H323ConnectionsCleaner(*this);
  861.  
  862.   srand((unsigned)time(NULL)+clock());
  863.  
  864.   PTRACE(3, "H323\tCreated endpoint.");
  865. }
  866.  
  867.  
  868. H323EndPoint::~H323EndPoint()
  869. {
  870.   // And shut down the gatekeeper (if there was one)
  871.   RemoveGatekeeper();
  872.  
  873.   // Shut down the listeners as soon as possible to avoid race conditions
  874.   listeners.RemoveAll();
  875.  
  876.   // Clear any pending calls on this endpoint
  877.   ClearAllCalls();
  878.  
  879.   // Shut down the cleaner thread
  880.   delete connectionsCleaner;
  881.  
  882.   // Clean up any connections that the cleaner thread missed
  883.   CleanUpConnections();
  884.  
  885.   delete stun;
  886.  
  887.   PTRACE(3, "H323\tDeleted endpoint.");
  888. }
  889.  
  890.  
  891. void H323EndPoint::SetEndpointTypeInfo(H225_EndpointType & info) const
  892. {
  893.   info.IncludeOptionalField(H225_EndpointType::e_vendor);
  894.   SetVendorIdentifierInfo(info.m_vendor);
  895.  
  896.   switch (terminalType) {
  897.     case e_TerminalOnly :
  898.     case e_TerminalAndMC :
  899.       info.IncludeOptionalField(H225_EndpointType::e_terminal);
  900.       break;
  901.     case e_GatewayOnly :
  902.     case e_GatewayAndMC :
  903.     case e_GatewayAndMCWithDataMP :
  904.     case e_GatewayAndMCWithAudioMP :
  905.     case e_GatewayAndMCWithAVMP :
  906.       info.IncludeOptionalField(H225_EndpointType::e_gateway);
  907.       break;
  908.     case e_GatekeeperOnly :
  909.     case e_GatekeeperWithDataMP :
  910.     case e_GatekeeperWithAudioMP :
  911.     case e_GatekeeperWithAVMP :
  912.       info.IncludeOptionalField(H225_EndpointType::e_gatekeeper);
  913.       break;
  914.     case e_MCUOnly :
  915.     case e_MCUWithDataMP :
  916.     case e_MCUWithAudioMP :
  917.     case e_MCUWithAVMP :
  918.       info.IncludeOptionalField(H225_EndpointType::e_mcu);
  919.       info.m_mc = TRUE;
  920.   }
  921. }
  922.  
  923.  
  924. void H323EndPoint::SetVendorIdentifierInfo(H225_VendorIdentifier & info) const
  925. {
  926.   SetH221NonStandardInfo(info.m_vendor);
  927.  
  928.   info.IncludeOptionalField(H225_VendorIdentifier::e_productId);
  929.   info.m_productId = PProcess::Current().GetManufacturer() & PProcess::Current().GetName();
  930.   info.m_productId.SetSize(info.m_productId.GetSize()+2);
  931.  
  932.   info.IncludeOptionalField(H225_VendorIdentifier::e_versionId);
  933.   info.m_versionId = PProcess::Current().GetVersion(TRUE) + " (OpenH323 v" + OpalGetVersion() + ')';
  934.   info.m_versionId.SetSize(info.m_versionId.GetSize()+2);
  935. }
  936.  
  937.  
  938. void H323EndPoint::SetH221NonStandardInfo(H225_H221NonStandard & info) const
  939. {
  940.   info.m_t35CountryCode = t35CountryCode;
  941.   info.m_t35Extension = t35Extension;
  942.   info.m_manufacturerCode = manufacturerCode;
  943. }
  944.  
  945.  
  946. H323Capability * H323EndPoint::FindCapability(const H245_Capability & cap) const
  947. {
  948.   return capabilities.FindCapability(cap);
  949. }
  950.  
  951.  
  952. H323Capability * H323EndPoint::FindCapability(const H245_DataType & dataType) const
  953. {
  954.   return capabilities.FindCapability(dataType);
  955. }
  956.  
  957.  
  958. H323Capability * H323EndPoint::FindCapability(H323Capability::MainTypes mainType,
  959.                                               unsigned subType) const
  960. {
  961.   return capabilities.FindCapability(mainType, subType);
  962. }
  963.  
  964.  
  965. void H323EndPoint::AddCapability(H323Capability * capability)
  966. {
  967.   capabilities.Add(capability);
  968. }
  969.  
  970.  
  971. PINDEX H323EndPoint::SetCapability(PINDEX descriptorNum,
  972.                                    PINDEX simultaneousNum,
  973.                                    H323Capability * capability)
  974. {
  975.   return capabilities.SetCapability(descriptorNum, simultaneousNum, capability);
  976. }
  977.  
  978.  
  979. PINDEX H323EndPoint::AddAllCapabilities(PINDEX descriptorNum,
  980.                                         PINDEX simultaneous,
  981.                                         const PString & name)
  982. {
  983.   return capabilities.AddAllCapabilities(*this, descriptorNum, simultaneous, name);
  984. }
  985.  
  986.  
  987. void H323EndPoint::AddAllUserInputCapabilities(PINDEX descriptorNum,
  988.                                                PINDEX simultaneous)
  989. {
  990.   H323_UserInputCapability::AddAllCapabilities(capabilities, descriptorNum, simultaneous);
  991. }
  992.  
  993.  
  994. void H323EndPoint::RemoveCapabilities(const PStringArray & codecNames)
  995. {
  996.   capabilities.Remove(codecNames);
  997. }
  998.  
  999.  
  1000. void H323EndPoint::ReorderCapabilities(const PStringArray & preferenceOrder)
  1001. {
  1002.   capabilities.Reorder(preferenceOrder);
  1003. }
  1004.  
  1005.  
  1006. BOOL H323EndPoint::UseGatekeeper(const PString & address,
  1007.                                  const PString & identifier,
  1008.                                  const PString & localAddress)
  1009. {
  1010.   if (gatekeeper != NULL) {
  1011.     BOOL same = TRUE;
  1012.  
  1013.     if (!address)
  1014.       same = gatekeeper->GetTransport().GetRemoteAddress().IsEquivalent(address);
  1015.  
  1016.     if (!same && !identifier)
  1017.       same = gatekeeper->GetIdentifier() == identifier;
  1018.  
  1019.     if (!same && !localAddress)
  1020.       same = gatekeeper->GetTransport().GetLocalAddress().IsEquivalent(localAddress);
  1021.  
  1022.     if (same) {
  1023.       PTRACE(2, "H323\tUsing existing gatekeeper " << *gatekeeper);
  1024.       return TRUE;
  1025.     }
  1026.   }
  1027.  
  1028.   H323Transport * transport = NULL;
  1029.   if (!localAddress.IsEmpty()) {
  1030.     H323TransportAddress iface(localAddress);
  1031.     PIPSocket::Address ip;
  1032.     WORD port = H225_RAS::DefaultRasUdpPort;
  1033.     if (iface.GetIpAndPort(ip, port))
  1034.       transport = new H323TransportUDP(*this, ip, port);
  1035.   }
  1036.  
  1037.   if (address.IsEmpty()) {
  1038.     if (identifier.IsEmpty())
  1039.       return DiscoverGatekeeper(transport);
  1040.     else
  1041.       return LocateGatekeeper(identifier, transport);
  1042.   }
  1043.   else {
  1044.     if (identifier.IsEmpty())
  1045.       return SetGatekeeper(address, transport);
  1046.     else
  1047.       return SetGatekeeperZone(address, identifier, transport);
  1048.   }
  1049. }
  1050.  
  1051.  
  1052. BOOL H323EndPoint::SetGatekeeper(const PString & address, H323Transport * transport)
  1053. {
  1054.   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
  1055.   return InternalRegisterGatekeeper(gk, gk->DiscoverByAddress(address));
  1056. }
  1057.  
  1058.  
  1059. BOOL H323EndPoint::SetGatekeeperZone(const PString & address,
  1060.                                      const PString & identifier,
  1061.                                      H323Transport * transport)
  1062. {
  1063.   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
  1064.   return InternalRegisterGatekeeper(gk, gk->DiscoverByNameAndAddress(identifier, address));
  1065. }
  1066.  
  1067.  
  1068. BOOL H323EndPoint::LocateGatekeeper(const PString & identifier, H323Transport * transport)
  1069. {
  1070.   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
  1071.   return InternalRegisterGatekeeper(gk, gk->DiscoverByName(identifier));
  1072. }
  1073.  
  1074.  
  1075. BOOL H323EndPoint::DiscoverGatekeeper(H323Transport * transport)
  1076. {
  1077.   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
  1078.   return InternalRegisterGatekeeper(gk, gk->DiscoverAny());
  1079. }
  1080.  
  1081.  
  1082. H323Gatekeeper * H323EndPoint::InternalCreateGatekeeper(H323Transport * transport)
  1083. {
  1084.   RemoveGatekeeper(H225_UnregRequestReason::e_reregistrationRequired);
  1085.  
  1086.   if (transport == NULL)
  1087.     transport = new H323TransportUDP(*this);
  1088.  
  1089.   H323Gatekeeper * gk = CreateGatekeeper(transport);
  1090.  
  1091.   gk->SetPassword(gatekeeperPassword);
  1092.  
  1093.   return gk;
  1094. }
  1095.  
  1096.  
  1097. BOOL H323EndPoint::InternalRegisterGatekeeper(H323Gatekeeper * gk, BOOL discovered)
  1098. {
  1099.   if (discovered) {
  1100.     if (gk->RegistrationRequest()) {
  1101.       gatekeeper = gk;
  1102.       return TRUE;
  1103.     }
  1104.  
  1105.     // RRQ was rejected continue trying
  1106.     gatekeeper = gk;
  1107.   }
  1108.   else // Only stop listening if the GRQ was rejected
  1109.     delete gk;
  1110.  
  1111.   return FALSE;
  1112. }
  1113.  
  1114.  
  1115. H323Gatekeeper * H323EndPoint::CreateGatekeeper(H323Transport * transport)
  1116. {
  1117.   return new H323Gatekeeper(*this, transport);
  1118. }
  1119.  
  1120.  
  1121. BOOL H323EndPoint::IsRegisteredWithGatekeeper() const
  1122. {
  1123.   if (gatekeeper == NULL)
  1124.     return FALSE;
  1125.  
  1126.   return gatekeeper->IsRegistered();
  1127. }
  1128.  
  1129.  
  1130. BOOL H323EndPoint::RemoveGatekeeper(int reason)
  1131. {
  1132.   BOOL ok = TRUE;
  1133.  
  1134.   if (gatekeeper == NULL)
  1135.     return ok;
  1136.  
  1137.   ClearAllCalls();
  1138.  
  1139.   if (gatekeeper->IsRegistered()) // If we are registered send a URQ
  1140.     ok = gatekeeper->UnregistrationRequest(reason);
  1141.  
  1142.   delete gatekeeper;
  1143.   gatekeeper = NULL;
  1144.  
  1145.   return ok;
  1146. }
  1147.  
  1148.  
  1149. void H323EndPoint::SetGatekeeperPassword(const PString & password)
  1150. {
  1151.   gatekeeperPassword = password;
  1152.  
  1153.   if (gatekeeper != NULL) {
  1154.     gatekeeper->SetPassword(gatekeeperPassword);
  1155.     if (gatekeeper->IsRegistered()) // If we are registered send a URQ
  1156.       gatekeeper->UnregistrationRequest(H225_UnregRequestReason::e_reregistrationRequired);
  1157.     InternalRegisterGatekeeper(gatekeeper, TRUE);
  1158.   }
  1159. }
  1160.  
  1161.  
  1162. H235Authenticators H323EndPoint::CreateAuthenticators()
  1163. {
  1164.   H235Authenticators authenticators;
  1165.  
  1166. #if P_SSL
  1167.   authenticators.Append(new H235AuthProcedure1);
  1168. #endif
  1169.   authenticators.Append(new H235AuthSimpleMD5);
  1170.   authenticators.Append(new H235AuthCAT);
  1171.  
  1172.   return authenticators;
  1173. }
  1174.  
  1175.  
  1176. BOOL H323EndPoint::StartListeners(const H323TransportAddressArray & ifaces)
  1177. {
  1178.   if (ifaces.IsEmpty())
  1179.     return StartListener("*");
  1180.  
  1181.   PINDEX i;
  1182.  
  1183.   for (i = 0; i < listeners.GetSize(); i++) {
  1184.     BOOL remove = TRUE;
  1185.     for (PINDEX j = 0; j < ifaces.GetSize(); j++) {
  1186.       if (listeners[i].GetTransportAddress().IsEquivalent(ifaces[j])) {
  1187.         remove = FALSE;
  1188.         break;
  1189.       }
  1190.     }
  1191.     if (remove) {
  1192.       PTRACE(3, "H323\tRemoving listener " << listeners[i]);
  1193.       listeners.RemoveAt(i--);
  1194.     }
  1195.   }
  1196.  
  1197.   for (i = 0; i < ifaces.GetSize(); i++) {
  1198.     if (!ifaces[i])
  1199.       StartListener(ifaces[i]);
  1200.   }
  1201.  
  1202.   return listeners.GetSize() > 0;
  1203. }
  1204.  
  1205.  
  1206. BOOL H323EndPoint::StartListener(const H323TransportAddress & iface)
  1207. {
  1208.   H323Listener * listener;
  1209.  
  1210.   if (iface.IsEmpty())
  1211.     listener = new H323ListenerTCP(*this, INADDR_ANY, DefaultTcpPort);
  1212.   else
  1213.     listener = iface.CreateListener(*this);
  1214.  
  1215.   if (H323EndPoint::StartListener(listener))
  1216.     return TRUE;
  1217.  
  1218.   PTRACE(1, "H323\tCould not start listener: " << iface);
  1219.   delete listener;
  1220.   return FALSE;
  1221. }
  1222.  
  1223.  
  1224. BOOL H323EndPoint::StartListener(H323Listener * listener)
  1225. {
  1226.   if (listener == NULL)
  1227.     return FALSE;
  1228.  
  1229.   for (PINDEX i = 0; i < listeners.GetSize(); i++) {
  1230.     if (listeners[i].GetTransportAddress() == listener->GetTransportAddress()) {
  1231.       PTRACE(2, "H323\tAlready have listener for " << *listener);
  1232.       delete listener;
  1233.       return TRUE;
  1234.     }
  1235.   }
  1236.  
  1237.   // as the listener is not open, this will have the effect of immediately
  1238.   // stopping the listener thread. This is good - it means that the 
  1239.   // listener Close function will appear to have stopped the thread
  1240.   if (!listener->Open()) {
  1241.     listener->Resume(); // set the thread running so we can delete it later
  1242.     return FALSE;
  1243.   }
  1244.  
  1245.   PTRACE(3, "H323\tStarted listener " << *listener);
  1246.   listeners.Append(listener);
  1247.   listener->Resume();
  1248.   return TRUE;
  1249. }
  1250.  
  1251.  
  1252. BOOL H323EndPoint::RemoveListener(H323Listener * listener)
  1253. {
  1254.   if (listener != NULL) {
  1255.     PTRACE(3, "H323\tRemoving listener " << *listener);
  1256.     return listeners.Remove(listener);
  1257.   }
  1258.  
  1259.   PTRACE(3, "H323\tRemoving all listeners");
  1260.   listeners.RemoveAll();
  1261.   return TRUE;
  1262. }
  1263.  
  1264.  
  1265. H323TransportAddressArray H323EndPoint::GetInterfaceAddresses(BOOL excludeLocalHost,
  1266.                                                               H323Transport * associatedTransport)
  1267. {
  1268.   return H323GetInterfaceAddresses(listeners, excludeLocalHost, associatedTransport);
  1269. }
  1270.  
  1271.  
  1272. H323Connection * H323EndPoint::MakeCall(const PString & remoteParty,
  1273.                                         PString & token,
  1274.                                         void * userData)
  1275. {
  1276.   return MakeCall(remoteParty, NULL, token, userData);
  1277. }
  1278.  
  1279.  
  1280. H323Connection * H323EndPoint::MakeCall(const PString & remoteParty,
  1281.                                         H323Transport * transport,
  1282.                                         PString & token,
  1283.                                         void * userData)
  1284. {
  1285.   token = PString::Empty();
  1286.   H323Connection * connection = InternalMakeCall(PString::Empty(),
  1287.                                                  PString::Empty(),
  1288.                                                  UINT_MAX,
  1289.                                                  remoteParty,
  1290.                                                  transport,
  1291.                                                  token,
  1292.                                                  userData);
  1293.   if (connection != NULL)
  1294.     connection->Unlock();
  1295.   return connection;
  1296. }
  1297.  
  1298.  
  1299. H323Connection * H323EndPoint::MakeCallLocked(const PString & remoteParty,
  1300.                                               PString & token,
  1301.                                               void * userData,
  1302.                                               H323Transport * transport)
  1303. {
  1304.   token = PString::Empty();
  1305.   return InternalMakeCall(PString::Empty(),
  1306.                           PString::Empty(),
  1307.                           UINT_MAX,
  1308.                           remoteParty,
  1309.                           transport,
  1310.                           token,
  1311.                           userData);
  1312. }
  1313.  
  1314.  
  1315. H323Connection * H323EndPoint::InternalMakeCall(const PString & trasferFromToken,
  1316.                                                 const PString & callIdentity,
  1317.                                                 unsigned capabilityLevel,
  1318.                                                 const PString & remoteParty,
  1319.                                                 H323Transport * transport,
  1320.                                                 PString & newToken,
  1321.                                                 void * userData)
  1322. {
  1323.   PTRACE(2, "H323\tMaking call to: " << remoteParty);
  1324.  
  1325.   PString alias;
  1326.   H323TransportAddress address;
  1327.   if (!ParsePartyName(remoteParty, alias, address)) {
  1328.     PTRACE(2, "H323\tCould not parse \"" << remoteParty << '"');
  1329.     return NULL;
  1330.   }
  1331.  
  1332.   if (transport == NULL) {
  1333.     // Restriction: the call must be made on the same transport as the one
  1334.     // that the gatekeeper is using.
  1335.     if (gatekeeper != NULL)
  1336.       transport = gatekeeper->GetTransport().GetRemoteAddress().CreateTransport(*this);
  1337.     else
  1338.       transport = address.CreateTransport(*this);
  1339.     if (transport == NULL) {
  1340.       PTRACE(1, "H323\tInvalid transport in \"" << remoteParty << '"');
  1341.       return NULL;
  1342.     }
  1343.   }
  1344.  
  1345.   H323Connection * connection;
  1346.  
  1347.   connectionsMutex.Wait();
  1348.  
  1349.   unsigned lastReference;
  1350.   if (newToken.IsEmpty()) {
  1351.     do {
  1352.       lastReference = Q931::GenerateCallReference();
  1353.       newToken = BuildConnectionToken(*transport, lastReference, FALSE);
  1354.     } while (connectionsActive.Contains(newToken));
  1355.   }
  1356.   else {
  1357.     lastReference = newToken.Mid(newToken.Find('/')+1).AsUnsigned();
  1358.  
  1359.     // Move old connection on token to new value and flag for removal
  1360.     PString adjustedToken;
  1361.     unsigned tieBreaker = 0;
  1362.     do {
  1363.       adjustedToken = newToken + "-replaced";
  1364.       adjustedToken.sprintf("-%u", ++tieBreaker);
  1365.     } while (connectionsActive.Contains(adjustedToken));
  1366.     connectionsActive.SetAt(adjustedToken, connectionsActive.RemoveAt(newToken));
  1367.     connectionsToBeCleaned += adjustedToken;
  1368.     PTRACE(3, "H323\tOverwriting call " << newToken << ", renamed to " << adjustedToken);
  1369.   }
  1370.  
  1371.   connection = CreateConnection(lastReference, userData, transport, NULL);
  1372.   if (connection == NULL) {
  1373.     PTRACE(1, "H323\tCreateConnection returned NULL");
  1374.     connectionsMutex.Signal();
  1375.     return NULL;
  1376.   }
  1377.  
  1378.   connection->Lock();
  1379.  
  1380.   connectionsActive.SetAt(newToken, connection);
  1381.  
  1382.   connectionsMutex.Signal();
  1383.  
  1384.   connection->AttachSignalChannel(newToken, transport, FALSE);
  1385.  
  1386.   if (capabilityLevel == UINT_MAX)
  1387.     connection->HandleTransferCall(trasferFromToken, callIdentity);
  1388.   else {
  1389.     connection->HandleIntrudeCall(trasferFromToken, callIdentity);
  1390.     connection->IntrudeCall(capabilityLevel);
  1391.   }
  1392.  
  1393.   PTRACE(3, "H323\tCreated new connection: " << newToken);
  1394.  
  1395.   new H225CallThread(*this, *connection, *transport, alias, address);
  1396.   return connection;
  1397. }
  1398.  
  1399.  
  1400. BOOL H323EndPoint::ParsePartyName(const PString & remoteParty,
  1401.                                   PString & alias,
  1402.                                   H323TransportAddress & address)
  1403. {
  1404.   PURL url(remoteParty, "h323");
  1405.  
  1406.   // Special adjustment if 
  1407.   if (remoteParty.Find('@') == P_MAX_INDEX &&
  1408.       remoteParty.NumCompare(url.GetScheme()) != EqualTo) {
  1409.     if (gatekeeper == NULL)
  1410.       url.Parse("h323:@" + remoteParty);
  1411.     else
  1412.       url.Parse("h323:" + remoteParty);
  1413.   }
  1414.  
  1415.   alias = url.GetUserName();
  1416.  
  1417.   address = url.GetHostName();
  1418.   if (!address && url.GetPort() != 0)
  1419.     address.sprintf(":%u", url.GetPort());
  1420.  
  1421.   if (alias.IsEmpty() && address.IsEmpty()) {
  1422.     PTRACE(1, "H323\tAttempt to use invalid URL \"" << remoteParty << '"');
  1423.     return FALSE;
  1424.   }
  1425.  
  1426.   BOOL gatekeeperSpecified = FALSE;
  1427.   BOOL gatewaySpecified = FALSE;
  1428.  
  1429.   PCaselessString type = url.GetParamVars()("type");
  1430.  
  1431.   if (url.GetScheme() == "callto") {
  1432.     // Do not yet support ILS
  1433.     if (type == "directory") {
  1434. #if P_LDAP
  1435.       PString server = url.GetHostName();
  1436.       if (server.IsEmpty())
  1437.         server = ilsServer;
  1438.       if (server.IsEmpty())
  1439.         return FALSE;
  1440.  
  1441.       PILSSession ils;
  1442.       if (!ils.Open(server, url.GetPort())) {
  1443.         PTRACE(1, "H323\tCould not open ILS server at \"" << server
  1444.                << "\" - " << ils.GetErrorText());
  1445.         return FALSE;
  1446.       }
  1447.  
  1448.       PILSSession::RTPerson person;
  1449.       if (!ils.SearchPerson(alias, person)) {
  1450.         PTRACE(1, "H323\tCould not find "
  1451.                << server << '/' << alias << ": " << ils.GetErrorText());
  1452.         return FALSE;
  1453.       }
  1454.  
  1455.       if (!person.sipAddress.IsValid()) {
  1456.         PTRACE(1, "H323\tILS user " << server << '/' << alias
  1457.                << " does not have a valid IP address");
  1458.         return FALSE;
  1459.       }
  1460.  
  1461.       // Get the IP address
  1462.       address = H323TransportAddress(person.sipAddress);
  1463.  
  1464.       // Get the port if provided
  1465.       for (PINDEX i = 0; i < person.sport.GetSize(); i++) {
  1466.         if (person.sport[i] != 1503) { // Dont use the T.120 port
  1467.           address = H323TransportAddress(person.sipAddress, person.sport[i]);
  1468.           break;
  1469.         }
  1470.       }
  1471.  
  1472.       alias = PString::Empty(); // No alias for ILS lookup, only host
  1473.       return TRUE;
  1474. #else
  1475.       return FALSE;
  1476. #endif
  1477.     }
  1478.  
  1479.     if (url.GetParamVars().Contains("gateway"))
  1480.       gatewaySpecified = TRUE;
  1481.   }
  1482.   else if (url.GetScheme() == "h323") {
  1483.     if (type == "gw")
  1484.       gatewaySpecified = TRUE;
  1485.     else if (type == "gk")
  1486.       gatekeeperSpecified = TRUE;
  1487.     else if (!type) {
  1488.       PTRACE(1, "H323\tUnsupported host type \"" << type << "\" in h323 URL");
  1489.       return FALSE;
  1490.     }
  1491.   }
  1492.  
  1493.   // User explicitly asked fo a look up to a gk
  1494.   if (gatekeeperSpecified) {
  1495.     if (alias.IsEmpty()) {
  1496.       PTRACE(1, "H323\tAttempt to use explict gatekeeper without alias!");
  1497.       return FALSE;
  1498.     }
  1499.  
  1500.     if (address.IsEmpty()) {
  1501.       PTRACE(1, "H323\tAttempt to use explict gatekeeper without address!");
  1502.       return FALSE;
  1503.     }
  1504.  
  1505.     H323TransportAddress gkAddr = address;
  1506.     PTRACE(3, "H323\tLooking for \"" << alias << "\" on gatekeeper at " << gkAddr);
  1507.  
  1508.     H323Gatekeeper * gk = CreateGatekeeper(new H323TransportUDP(*this));
  1509.  
  1510.     BOOL ok = gk->DiscoverByAddress(gkAddr);
  1511.     if (ok) {
  1512.       ok = gk->LocationRequest(alias, address);
  1513.       if (ok) {
  1514.         PTRACE(3, "H323\tLocation Request of \"" << alias << "\" on gk " << gkAddr << " found " << address);
  1515.       }
  1516.       else {
  1517.         PTRACE(1, "H323\tLocation Request failed for \"" << alias << "\" on gk " << gkAddr);
  1518.       }
  1519.     }
  1520.     else {
  1521.       PTRACE(1, "H323\tLocation Request discovery failed for gk " << gkAddr);
  1522.     }
  1523.  
  1524.     delete gk;
  1525.  
  1526.     return ok;
  1527.   }
  1528.  
  1529.   // User explicitly said to use a gw, or we do not have a gk to do look up
  1530.   if (gatekeeper == NULL || gatewaySpecified) {
  1531.     // If URL did not have a host, but user said to use gw, or we do not have
  1532.     // a gk to do a lookup so we MUST have a host, use alias must be host
  1533.     if (address.IsEmpty()) {
  1534.       address = alias;
  1535.       alias = PString::Empty();
  1536.     }
  1537.     return TRUE;
  1538.   }
  1539.  
  1540.   // We have a gatekeeper and user provided a host, all done
  1541.   if (!address)
  1542.     return TRUE;
  1543.  
  1544.   // We have a gk and user did not explicitly supply a host, so lets
  1545.   // do a check to see if it is an IP address or hostname
  1546.   if (alias.FindOneOf("$.:[") != P_MAX_INDEX) {
  1547.     H323TransportAddress test = alias;
  1548.     PIPSocket::Address ip;
  1549.     if (test.GetIpAddress(ip) && ip.IsValid()) {
  1550.       // The alias was a valid internet address, use it as such
  1551.       alias = PString::Empty();
  1552.       address = test;
  1553.     }
  1554.   }
  1555.  
  1556.   return TRUE;
  1557. }
  1558.  
  1559.  
  1560. H323Connection * H323EndPoint::SetupTransfer(const PString & oldToken,
  1561.                                              const PString & callIdentity,
  1562.                                              const PString & remoteParty,
  1563.                                              PString & newToken,
  1564.                                              void * userData)
  1565. {
  1566.   newToken = PString::Empty();
  1567.   H323Connection* connection = InternalMakeCall(oldToken,
  1568.                                                 callIdentity,
  1569.                                                 UINT_MAX,
  1570.                                                 remoteParty,
  1571.                                                 NULL,
  1572.                                                 newToken,
  1573.                                                 userData);
  1574.   if (connection != NULL)
  1575.      connection->Unlock();
  1576.    return connection;
  1577. }
  1578.  
  1579.  
  1580. void H323EndPoint::TransferCall(const PString & token, 
  1581.                                 const PString & remoteParty,
  1582.                                 const PString & callIdentity)
  1583. {
  1584.   H323Connection * connection = FindConnectionWithLock(token);
  1585.   if (connection != NULL) {
  1586.     connection->TransferCall(remoteParty, callIdentity);
  1587.     connection->Unlock();
  1588.   }
  1589. }
  1590.  
  1591.  
  1592. void H323EndPoint::ConsultationTransfer(const PString & primaryCallToken,   
  1593.                                         const PString & secondaryCallToken)
  1594. {
  1595.   H323Connection * secondaryCall = FindConnectionWithLock(secondaryCallToken);
  1596.   if (secondaryCall != NULL) {
  1597.     secondaryCall->ConsultationTransfer(primaryCallToken);
  1598.     secondaryCall->Unlock();
  1599.   }
  1600. }
  1601.  
  1602.  
  1603. void H323EndPoint::HoldCall(const PString & token, BOOL localHold)
  1604. {
  1605.   H323Connection * connection = FindConnectionWithLock(token);
  1606.   if (connection != NULL) {
  1607.     connection->HoldCall(localHold);
  1608.     connection->Unlock();
  1609.   }
  1610. }
  1611.  
  1612.  
  1613. H323Connection * H323EndPoint::IntrudeCall(const PString & remoteParty,
  1614.                                         PString & token,
  1615.                                         unsigned capabilityLevel,
  1616.                                         void * userData)
  1617. {
  1618.   return IntrudeCall(remoteParty, NULL, token, capabilityLevel, userData);
  1619. }
  1620.  
  1621.  
  1622. H323Connection * H323EndPoint::IntrudeCall(const PString & remoteParty,
  1623.                                         H323Transport * transport,
  1624.                                         PString & token,
  1625.                                         unsigned capabilityLevel,
  1626.                                         void * userData)
  1627. {
  1628.   token = PString::Empty();
  1629.   H323Connection * connection = InternalMakeCall(PString::Empty(),
  1630.                                                  PString::Empty(),
  1631.                                                  capabilityLevel,
  1632.                                                  remoteParty,
  1633.                                                  transport,
  1634.                                                  token,
  1635.                                                  userData);
  1636.   if (connection != NULL)
  1637.     connection->Unlock();
  1638.   return connection;
  1639. }
  1640.  
  1641.  
  1642. BOOL H323EndPoint::ClearCall(const PString & token,
  1643.                              H323Connection::CallEndReason reason)
  1644. {
  1645.   return ClearCallSynchronous(token, reason, NULL);
  1646. }
  1647.  
  1648. BOOL H323EndPoint::ClearCallSynchronous(const PString & token,
  1649.                              H323Connection::CallEndReason reason)
  1650. {
  1651.   PSyncPoint sync;
  1652.   return ClearCallSynchronous(token, reason, &sync);
  1653. }
  1654.  
  1655. BOOL H323EndPoint::ClearCallSynchronous(const PString & token,
  1656.                                         H323Connection::CallEndReason reason,
  1657.                                         PSyncPoint * sync)
  1658. {
  1659.   if (PThread::Current() == connectionsCleaner)
  1660.     sync = NULL;
  1661.  
  1662.   /*The hugely multi-threaded nature of the H323Connection objects means that
  1663.     to avoid many forms of race condition, a call is cleared by moving it from
  1664.     the "active" call dictionary to a list of calls to be cleared that will be
  1665.     processed by a background thread specifically for the purpose of cleaning
  1666.     up cleared connections. So that is all that this function actually does.
  1667.     The real work is done in the H323ConnectionsCleaner thread.
  1668.    */
  1669.  
  1670.   {
  1671.     PWaitAndSignal wait(connectionsMutex);
  1672.  
  1673.     // Find the connection by token, callid or conferenceid
  1674.     H323Connection * connection = FindConnectionWithoutLocks(token);
  1675.     if (connection == NULL) {
  1676.       PTRACE(3, "H323\tAttempt to clear unknown call " << token);
  1677.       return FALSE;
  1678.     }
  1679.  
  1680.     PTRACE(3, "H323\tClearing connection " << connection->GetCallToken()
  1681.                                            << " reason=" << reason);
  1682.  
  1683.     // Add this to the set of connections being cleaned, if not in already
  1684.     if (!connectionsToBeCleaned.Contains(connection->GetCallToken())) 
  1685.       connectionsToBeCleaned += connection->GetCallToken();
  1686.  
  1687.     // Now set reason for the connection close
  1688.     connection->SetCallEndReason(reason, sync);
  1689.  
  1690.     // Signal the background threads that there is some stuff to process.
  1691.     connectionsCleaner->Signal();
  1692.   }
  1693.  
  1694.   if (sync != NULL)
  1695.     sync->Wait();
  1696.  
  1697.   return TRUE;
  1698. }
  1699.  
  1700.  
  1701. void H323EndPoint::ClearAllCalls(H323Connection::CallEndReason reason,
  1702.                                  BOOL wait)
  1703. {
  1704.   /*The hugely multi-threaded nature of the H323Connection objects means that
  1705.     to avoid many forms of race condition, a call is cleared by moving it from
  1706.     the "active" call dictionary to a list of calls to be cleared that will be
  1707.     processed by a background thread specifically for the purpose of cleaning
  1708.     up cleared connections. So that is all that this function actually does.
  1709.     The real work is done in the H323ConnectionsCleaner thread.
  1710.    */
  1711.  
  1712.   connectionsMutex.Wait();
  1713.  
  1714.   // Add all connections to the to be deleted set
  1715.   PINDEX i;
  1716.   for (i = 0; i < connectionsActive.GetSize(); i++) {
  1717.     H323Connection & connection = connectionsActive.GetDataAt(i);
  1718.     connectionsToBeCleaned += connection.GetCallToken();
  1719.     // Now set reason for the connection close
  1720.     connection.SetCallEndReason(reason, NULL);
  1721.   }
  1722.  
  1723.   // Signal the background threads that there is some stuff to process.
  1724.   connectionsCleaner->Signal();
  1725.  
  1726.   // Make sure any previous signals are removed before waiting later
  1727.   while (connectionsAreCleaned.Wait(0))
  1728.     ;
  1729.  
  1730.   connectionsMutex.Signal();
  1731.  
  1732.   if (wait)
  1733.     connectionsAreCleaned.Wait();
  1734. }
  1735.  
  1736. void H323EndPoint::CleanUpConnections()
  1737. {
  1738.   PTRACE(3, "H323\tCleaning up connections");
  1739.  
  1740.   // Lock the connections database.
  1741.   connectionsMutex.Wait();
  1742.  
  1743.   // Continue cleaning up until no more connections to clean
  1744.   while (connectionsToBeCleaned.GetSize() > 0) {
  1745.     // Just get the first entry in the set of tokens to clean up.
  1746.     PString token = connectionsToBeCleaned.GetKeyAt(0);
  1747.     H323Connection & connection = connectionsActive[token];
  1748.  
  1749.     // Unlock the structures here so does not block other uses of ClearCall()
  1750.     // for the possibly long time it takes to CleanUpOnCallEnd().
  1751.     connectionsMutex.Signal();
  1752.  
  1753.     // Clean up the connection, waiting for all threads to terminate
  1754.     connection.CleanUpOnCallEnd();
  1755.     connection.OnCleared();
  1756.  
  1757.     // Get the lock again as we remove the connection from our database
  1758.     connectionsMutex.Wait();
  1759.  
  1760.     // Remove the token from the set of connections to be cleaned up
  1761.     connectionsToBeCleaned -= token;
  1762.  
  1763.     // And remove the connection instance itself from the dictionary which will
  1764.     // cause its destructor to be called.
  1765.     H323Connection * connectionToDelete = connectionsActive.RemoveAt(token);
  1766.  
  1767.     // Unlock the structures yet again to avoid possible race conditions when
  1768.     // deleting the connection as well as the delte of a conncetion descendent
  1769.     // is application writer dependent and may cause deadlocks or just consume
  1770.     // lots of time.
  1771.     connectionsMutex.Signal();
  1772.  
  1773.     // Finally we get to delete it!
  1774.     delete connectionToDelete;
  1775.  
  1776.     // Get the lock again as we continue around the loop
  1777.     connectionsMutex.Wait();
  1778.   }
  1779.  
  1780.   // Finished with loop, unlock the connections database.
  1781.   connectionsMutex.Signal();
  1782.  
  1783.   // Signal thread that may be waiting on ClearAllCalls()
  1784.   connectionsAreCleaned.Signal();
  1785. }
  1786.  
  1787.  
  1788. BOOL H323EndPoint::HasConnection(const PString & token)
  1789. {
  1790.   PWaitAndSignal wait(connectionsMutex);
  1791.  
  1792.   return FindConnectionWithoutLocks(token) != NULL;
  1793. }
  1794.  
  1795.  
  1796. H323Connection * H323EndPoint::FindConnectionWithLock(const PString & token)
  1797. {
  1798.   PWaitAndSignal mutex(connectionsMutex);
  1799.  
  1800.   /*We have a very yucky polling loop here as a semi permanant measure.
  1801.     Why? We cannot call Lock() inside the connectionsMutex critical section as
  1802.     it will cause a deadlock with something like a RELEASE-COMPLETE coming in
  1803.     on separate thread. But if we put it outside there is a small window where
  1804.     the connection could get deleted before the Lock() test is done.
  1805.     The solution is to attempt to get the mutex while inside the
  1806.     connectionsMutex but not block. That means a polling loop. There is
  1807.     probably a way to do this properly with mutexes but I don't have time to
  1808.     figure it out.
  1809.    */
  1810.   H323Connection * connection;
  1811.   while ((connection = FindConnectionWithoutLocks(token)) != NULL) {
  1812.     switch (connection->TryLock()) {
  1813.       case 0 :
  1814.         return NULL;
  1815.       case 1 :
  1816.         return connection;
  1817.     }
  1818.     // Could not get connection lock, unlock the endpoint lists so a thread
  1819.     // that has the connection lock gets a chance at the endpoint lists.
  1820.     connectionsMutex.Signal();
  1821.     PThread::Sleep(20);
  1822.     connectionsMutex.Wait();
  1823.   }
  1824.  
  1825.   return NULL;
  1826. }
  1827.  
  1828.  
  1829. H323Connection * H323EndPoint::FindConnectionWithoutLocks(const PString & token)
  1830. {
  1831.   if (token.IsEmpty())
  1832.     return NULL;
  1833.  
  1834.   H323Connection * conn_ptr = connectionsActive.GetAt(token);
  1835.   if (conn_ptr != NULL)
  1836.     return conn_ptr;
  1837.  
  1838.   PINDEX i;
  1839.   for (i = 0; i < connectionsActive.GetSize(); i++) {
  1840.     H323Connection & conn = connectionsActive.GetDataAt(i);
  1841.     if (conn.GetCallIdentifier().AsString() == token)
  1842.       return &conn;
  1843.   }
  1844.  
  1845.   for (i = 0; i < connectionsActive.GetSize(); i++) {
  1846.     H323Connection & conn = connectionsActive.GetDataAt(i);
  1847.     if (conn.GetConferenceIdentifier().AsString() == token)
  1848.       return &conn;
  1849.   }
  1850.  
  1851.   return NULL;
  1852. }
  1853.  
  1854.  
  1855. PStringList H323EndPoint::GetAllConnections()
  1856. {
  1857.   PStringList tokens;
  1858.  
  1859.   connectionsMutex.Wait();
  1860.  
  1861.   for (PINDEX i = 0; i < connectionsActive.GetSize(); i++)
  1862.     tokens.AppendString(connectionsActive.GetKeyAt(i));
  1863.  
  1864.   connectionsMutex.Signal();
  1865.  
  1866.   return tokens;
  1867. }
  1868.  
  1869.  
  1870. BOOL H323EndPoint::OnIncomingCall(H323Connection & /*connection*/,
  1871.                                   const H323SignalPDU & /*setupPDU*/,
  1872.                                   H323SignalPDU & /*alertingPDU*/)
  1873. {
  1874.   return TRUE;
  1875. }
  1876.  
  1877.  
  1878. BOOL H323EndPoint::OnCallTransferInitiate(H323Connection & /*connection*/,
  1879.                                           const PString & /*remoteParty*/)
  1880. {
  1881.   return TRUE;
  1882. }
  1883.  
  1884.  
  1885. BOOL H323EndPoint::OnCallTransferIdentify(H323Connection & /*connection*/)
  1886. {
  1887.   return TRUE;
  1888. }
  1889.  
  1890.  
  1891. H323Connection::AnswerCallResponse
  1892.        H323EndPoint::OnAnswerCall(H323Connection & /*connection*/,
  1893.                                   const PString & PTRACE_caller,
  1894.                                   const H323SignalPDU & /*setupPDU*/,
  1895.                                   H323SignalPDU & /*connectPDU*/)
  1896. {
  1897.   PTRACE(2, "H225\tOnAnswerCall from \"" << PTRACE_caller << '"');
  1898.   return H323Connection::AnswerCallNow;
  1899. }
  1900.  
  1901.  
  1902. BOOL H323EndPoint::OnAlerting(H323Connection & /*connection*/,
  1903.                               const H323SignalPDU & /*alertingPDU*/,
  1904.                               const PString & /*username*/)
  1905. {
  1906.   PTRACE(1, "H225\tReceived alerting PDU.");
  1907.   return TRUE;
  1908. }
  1909.  
  1910.  
  1911. BOOL H323EndPoint::OnConnectionForwarded(H323Connection & /*connection*/,
  1912.                                          const PString & /*forwardParty*/,
  1913.                                          const H323SignalPDU & /*pdu*/)
  1914. {
  1915.   return FALSE;
  1916. }
  1917.  
  1918.  
  1919. BOOL H323EndPoint::ForwardConnection(H323Connection & connection,
  1920.                                      const PString & forwardParty,
  1921.                                      const H323SignalPDU & /*pdu*/)
  1922. {
  1923.   PString token = connection.GetCallToken();
  1924.   H323Connection * newConnection = InternalMakeCall(PString::Empty(),
  1925.                                                     PString::Empty(),
  1926.                                                     UINT_MAX,
  1927.                                                     forwardParty,
  1928.                                                     NULL,
  1929.                                                     token,
  1930.                                                     NULL);
  1931.   if (newConnection == NULL)
  1932.     return FALSE;
  1933.  
  1934.   connection.SetCallEndReason(H323Connection::EndedByCallForwarded);
  1935.  
  1936.   newConnection->Unlock();
  1937.   return TRUE;
  1938. }
  1939.  
  1940.  
  1941. void H323EndPoint::OnConnectionEstablished(H323Connection & /*connection*/,
  1942.                                            const PString & /*token*/)
  1943. {
  1944. }
  1945.  
  1946.  
  1947. BOOL H323EndPoint::IsConnectionEstablished(const PString & token)
  1948. {
  1949.   H323Connection * connection = FindConnectionWithLock(token);
  1950.   if (connection == NULL)
  1951.     return FALSE;
  1952.  
  1953.   BOOL established = connection->IsEstablished();
  1954.   connection->Unlock();
  1955.   return established;
  1956. }
  1957.  
  1958.  
  1959. void H323EndPoint::OnConnectionCleared(H323Connection & /*connection*/,
  1960.                                        const PString & /*token*/)
  1961. {
  1962. }
  1963.  
  1964.  
  1965. PString H323EndPoint::BuildConnectionToken(const H323Transport & transport,
  1966.                                            unsigned callReference,
  1967.                                            BOOL fromRemote)
  1968. {
  1969.   PString token;
  1970.  
  1971.   if (fromRemote)
  1972.     token = transport.GetRemoteAddress();
  1973.   else
  1974.     token = "ip$localhost";
  1975.  
  1976.   token.sprintf("/%u", callReference);
  1977.  
  1978.   return token;
  1979. }
  1980.  
  1981.  
  1982. H323Connection * H323EndPoint::OnIncomingConnection(H323Transport * transport,
  1983.                                                     H323SignalPDU & setupPDU)
  1984. {
  1985.   unsigned callReference = setupPDU.GetQ931().GetCallReference();
  1986.   PString token = BuildConnectionToken(*transport, callReference, TRUE);
  1987.  
  1988.   connectionsMutex.Wait();
  1989.   H323Connection * connection = connectionsActive.GetAt(token);
  1990.   connectionsMutex.Signal();
  1991.  
  1992.   if (connection == NULL) {
  1993.     connection = CreateConnection(callReference, NULL, transport, &setupPDU);
  1994.     if (connection == NULL) {
  1995.       PTRACE(1, "H323\tCreateConnection returned NULL");
  1996.       return NULL;
  1997.     }
  1998.  
  1999.     PTRACE(3, "H323\tCreated new connection: " << token);
  2000.  
  2001.     connectionsMutex.Wait();
  2002.     connectionsActive.SetAt(token, connection);
  2003.     connectionsMutex.Signal();
  2004.   }
  2005.  
  2006.   connection->AttachSignalChannel(token, transport, TRUE);
  2007.  
  2008.   return connection;
  2009. }
  2010.  
  2011.  
  2012. H323Connection * H323EndPoint::CreateConnection(unsigned callReference,
  2013.                                                 void * userData,
  2014.                                                 H323Transport * /*transport*/,
  2015.                                                 H323SignalPDU * /*setupPDU*/)
  2016. {
  2017.   return CreateConnection(callReference, userData);
  2018. }
  2019.  
  2020.  
  2021. H323Connection * H323EndPoint::CreateConnection(unsigned callReference, void * /*userData*/)
  2022. {
  2023.   return CreateConnection(callReference);
  2024. }
  2025.  
  2026. H323Connection * H323EndPoint::CreateConnection(unsigned callReference)
  2027. {
  2028.   return new H323Connection(*this, callReference);
  2029. }
  2030.  
  2031.  
  2032. #if PTRACING
  2033. static void OnStartStopChannel(const char * startstop, const H323Channel & channel)
  2034. {
  2035.   const char * dir;
  2036.   switch (channel.GetDirection()) {
  2037.     case H323Channel::IsTransmitter :
  2038.       dir = "send";
  2039.       break;
  2040.  
  2041.     case H323Channel::IsReceiver :
  2042.       dir = "receiv";
  2043.       break;
  2044.  
  2045.     default :
  2046.       dir = "us";
  2047.       break;
  2048.   }
  2049.  
  2050.   PTRACE(2, "H323\t" << startstop << "ed "
  2051.                      << dir << "ing logical channel: "
  2052.                      << channel.GetCapability());
  2053. }
  2054. #endif
  2055.  
  2056.  
  2057. BOOL H323EndPoint::OnStartLogicalChannel(H323Connection & /*connection*/,
  2058.                                          H323Channel & PTRACE_channel)
  2059. {
  2060. #if PTRACING
  2061.   OnStartStopChannel("Start", PTRACE_channel);
  2062. #endif
  2063.   return TRUE;
  2064. }
  2065.  
  2066.  
  2067. void H323EndPoint::OnClosedLogicalChannel(H323Connection & /*connection*/,
  2068.                                           const H323Channel & PTRACE_channel)
  2069. {
  2070. #if PTRACING
  2071.   OnStartStopChannel("Stopp", PTRACE_channel);
  2072. #endif
  2073. }
  2074.  
  2075.  
  2076. BOOL H323EndPoint::OpenAudioChannel(H323Connection & /*connection*/,
  2077.                                     BOOL isEncoding,
  2078.                                     unsigned bufferSize,
  2079.                                     H323AudioCodec & codec)
  2080. {
  2081.   codec.SetSilenceDetectionMode(GetSilenceDetectionMode());
  2082.  
  2083.   PString deviceName;
  2084.   if (isEncoding)
  2085.     deviceName = GetSoundChannelRecordDevice();
  2086.   else
  2087.     deviceName = GetSoundChannelPlayDevice();
  2088.  
  2089.   PSoundChannel * soundChannel = new PSoundChannel;
  2090.  
  2091.   if (soundChannel->Open(deviceName,
  2092.                          isEncoding ? PSoundChannel::Recorder
  2093.                                     : PSoundChannel::Player,
  2094.                          1, 8000, 16)) {
  2095.     PTRACE(3, "Codec\tOpened sound channel \"" << deviceName
  2096.            << "\" for " << (isEncoding ? "record" : "play")
  2097.            << "ing using " << soundChannelBuffers
  2098.            << 'x' << bufferSize << " byte buffers.");
  2099.     soundChannel->SetBuffers(bufferSize, soundChannelBuffers);
  2100.     return codec.AttachChannel(soundChannel);
  2101.   }
  2102.  
  2103.   PTRACE(1, "Codec\tCould not open sound channel \"" << deviceName
  2104.          << "\" for " << (isEncoding ? "record" : "play")
  2105.          << "ing: " << soundChannel->GetErrorText());
  2106.  
  2107.   delete soundChannel;
  2108.   return FALSE;
  2109. }
  2110.  
  2111.  
  2112. #ifndef NO_H323_VIDEO
  2113. BOOL H323EndPoint::OpenVideoChannel(H323Connection & /*connection*/,
  2114.                                     BOOL PTRACE_isEncoding,
  2115.                                     H323VideoCodec & /*codec*/)
  2116. {
  2117.   PTRACE(1, "Codec\tCould not open video channel for "
  2118.          << (PTRACE_isEncoding ? "captur" : "display")
  2119.          << "ing: not yet implemented");
  2120.   return FALSE;
  2121. }
  2122. #endif // NO_H323_VIDEO
  2123.  
  2124.  
  2125. void H323EndPoint::OnRTPStatistics(const H323Connection & /*connection*/,
  2126.                                    const RTP_Session & /*session*/) const
  2127. {
  2128. }
  2129.  
  2130.  
  2131. void H323EndPoint::OnUserInputString(H323Connection & /*connection*/,
  2132.                                      const PString & /*value*/)
  2133. {
  2134. }
  2135.  
  2136.  
  2137. void H323EndPoint::OnUserInputTone(H323Connection & connection,
  2138.                                    char tone,
  2139.                                    unsigned /*duration*/,
  2140.                                    unsigned /*logicalChannel*/,
  2141.                                    unsigned /*rtpTimestamp*/)
  2142. {
  2143.   connection.OnUserInputString(PString(tone));
  2144. }
  2145.  
  2146.  
  2147. void H323EndPoint::OnHTTPServiceControl(unsigned /*opeartion*/,
  2148.                                         unsigned /*sessionId*/,
  2149.                                         const PString & /*url*/)
  2150. {
  2151. }
  2152.  
  2153.  
  2154. void H323EndPoint::OnCallCreditServiceControl(const PString & /*amount*/, BOOL /*mode*/)
  2155. {
  2156. }
  2157.  
  2158.  
  2159. void H323EndPoint::OnServiceControlSession(unsigned type,
  2160.                                            unsigned sessionId,
  2161.                                            const H323ServiceControlSession & session,
  2162.                                            H323Connection * connection)
  2163. {
  2164.   session.OnChange(type, sessionId, *this, connection);
  2165. }
  2166.  
  2167.  
  2168. H323ServiceControlSession * H323EndPoint::CreateServiceControlSession(const H225_ServiceControlDescriptor & contents)
  2169. {
  2170.   switch (contents.GetTag()) {
  2171.     case H225_ServiceControlDescriptor::e_url :
  2172.       return new H323HTTPServiceControl(contents);
  2173.  
  2174.     case H225_ServiceControlDescriptor::e_callCreditServiceControl :
  2175.       return new H323CallCreditServiceControl(contents);
  2176.   }
  2177.  
  2178.   return NULL;
  2179. }
  2180.  
  2181.  
  2182. OpalT120Protocol * H323EndPoint::CreateT120ProtocolHandler(const H323Connection &) const
  2183. {
  2184.   return NULL;
  2185. }
  2186.  
  2187.  
  2188. OpalT38Protocol * H323EndPoint::CreateT38ProtocolHandler(const H323Connection &) const
  2189. {
  2190.   return NULL;
  2191. }
  2192.  
  2193.  
  2194. void H323EndPoint::SetLocalUserName(const PString & name)
  2195. {
  2196.   PAssert(!name, "Must have non-empty string in AliasAddress!");
  2197.   if (name.IsEmpty())
  2198.     return;
  2199.  
  2200.   localAliasNames.RemoveAll();
  2201.   localAliasNames.AppendString(name);
  2202. }
  2203.  
  2204.  
  2205. BOOL H323EndPoint::AddAliasName(const PString & name)
  2206. {
  2207.   PAssert(!name, "Must have non-empty string in AliasAddress!");
  2208.  
  2209.   if (localAliasNames.GetValuesIndex(name) != P_MAX_INDEX)
  2210.     return FALSE;
  2211.  
  2212.   localAliasNames.AppendString(name);
  2213.   return TRUE;
  2214. }
  2215.  
  2216.  
  2217. BOOL H323EndPoint::RemoveAliasName(const PString & name)
  2218. {
  2219.   PINDEX pos = localAliasNames.GetValuesIndex(name);
  2220.   if (pos == P_MAX_INDEX)
  2221.     return FALSE;
  2222.  
  2223.   PAssert(localAliasNames.GetSize() > 1, "Must have at least one AliasAddress!");
  2224.   if (localAliasNames.GetSize() < 2)
  2225.     return FALSE;
  2226.  
  2227.   localAliasNames.RemoveAt(pos);
  2228.   return TRUE;
  2229. }
  2230.  
  2231.  
  2232. BOOL H323EndPoint::SetSoundChannelPlayDevice(const PString & name)
  2233. {
  2234.   if (PSoundChannel::GetDeviceNames(PSoundChannel::Player).GetValuesIndex(name) == P_MAX_INDEX)
  2235.     return FALSE;
  2236.  
  2237.   soundChannelPlayDevice = name;
  2238.   return TRUE;
  2239. }
  2240.  
  2241.  
  2242. BOOL H323EndPoint::SetSoundChannelRecordDevice(const PString & name)
  2243. {
  2244.   if (PSoundChannel::GetDeviceNames(PSoundChannel::Recorder).GetValuesIndex(name) == P_MAX_INDEX)
  2245.     return FALSE;
  2246.  
  2247.   soundChannelRecordDevice = name;
  2248.   return TRUE;
  2249. }
  2250.  
  2251.  
  2252. void H323EndPoint::SetSoundChannelBufferDepth(unsigned depth)
  2253. {
  2254.   PAssert(depth > 1, PInvalidParameter);
  2255.   soundChannelBuffers = depth;
  2256. }
  2257.  
  2258.  
  2259. BOOL H323EndPoint::IsTerminal() const
  2260. {
  2261.   switch (terminalType) {
  2262.     case e_TerminalOnly :
  2263.     case e_TerminalAndMC :
  2264.       return TRUE;
  2265.  
  2266.     default :
  2267.       return FALSE;
  2268.   }
  2269. }
  2270.  
  2271.  
  2272. BOOL H323EndPoint::IsGateway() const
  2273. {
  2274.   switch (terminalType) {
  2275.     case e_GatewayOnly :
  2276.     case e_GatewayAndMC :
  2277.     case e_GatewayAndMCWithDataMP :
  2278.     case e_GatewayAndMCWithAudioMP :
  2279.     case e_GatewayAndMCWithAVMP :
  2280.       return TRUE;
  2281.  
  2282.     default :
  2283.       return FALSE;
  2284.   }
  2285. }
  2286.  
  2287.  
  2288. BOOL H323EndPoint::IsGatekeeper() const
  2289. {
  2290.   switch (terminalType) {
  2291.     case e_GatekeeperOnly :
  2292.     case e_GatekeeperWithDataMP :
  2293.     case e_GatekeeperWithAudioMP :
  2294.     case e_GatekeeperWithAVMP :
  2295.       return TRUE;
  2296.  
  2297.     default :
  2298.       return FALSE;
  2299.   }
  2300. }
  2301.  
  2302.  
  2303. BOOL H323EndPoint::IsMCU() const
  2304. {
  2305.   switch (terminalType) {
  2306.     case e_MCUOnly :
  2307.     case e_MCUWithDataMP :
  2308.     case e_MCUWithAudioMP :
  2309.     case e_MCUWithAVMP :
  2310.       return TRUE;
  2311.  
  2312.     default :
  2313.       return FALSE;
  2314.   }
  2315. }
  2316.  
  2317.  
  2318. void H323EndPoint::SetAudioJitterDelay(unsigned minDelay, unsigned maxDelay)
  2319. {
  2320.   PAssert(minDelay <= 10000 && maxDelay <= 10000, PInvalidParameter);
  2321.  
  2322.   if (minDelay < 10)
  2323.     minDelay = 10;
  2324.   minAudioJitterDelay = minDelay;
  2325.  
  2326.   if (maxDelay < minDelay)
  2327.     maxDelay = minDelay;
  2328.   maxAudioJitterDelay = maxDelay;
  2329. }
  2330.  
  2331.  
  2332. PSTUNClient * H323EndPoint::GetSTUN(const PIPSocket::Address & ip) const
  2333. {
  2334.   if (ip.IsValid() && IsLocalAddress(ip))
  2335.     return NULL;
  2336.  
  2337.   return stun;
  2338. }
  2339.  
  2340.  
  2341. void H323EndPoint::SetSTUNServer(const PString & server)
  2342. {
  2343.   delete stun;
  2344.  
  2345.   if (server.IsEmpty())
  2346.     stun = NULL;
  2347.   else {
  2348.     stun = new PSTUNClient(server,
  2349.                            GetUDPPortBase(), GetUDPPortMax(),
  2350.                            GetRtpIpPortBase(), GetRtpIpPortMax());
  2351.     PTRACE(2, "H323\tSTUN server \"" << server << "\" replies " << stun->GetNatTypeName());
  2352.   }
  2353. }
  2354.  
  2355.  
  2356. BOOL H323EndPoint::IsLocalAddress(const PIPSocket::Address & ip) const
  2357. {
  2358.   /* Check if the remote address is a private IP address.
  2359.    * RFC 1918 specifies the following private IP addresses
  2360.    * 10.0.0.0    - 10.255.255.255.255
  2361.    * 172.16.0.0  - 172.31.255.255
  2362.    * 192.168.0.0 - 192.168.255.255
  2363.    */
  2364.  
  2365.   return (ip.Byte1() == 10)
  2366.          ||
  2367.          (
  2368.            (ip.Byte1() == 172)
  2369.            &&
  2370.            (ip.Byte2() >= 16) && (ip.Byte2() <= 31)
  2371.          )
  2372.          ||
  2373.          (
  2374.            (ip.Byte1() == 192) 
  2375.            &&
  2376.            (ip.Byte2() == 168)
  2377.          );
  2378. }
  2379.  
  2380.  
  2381. void H323EndPoint::PortInfo::Set(unsigned newBase,
  2382.                                  unsigned newMax,
  2383.                                  unsigned range,
  2384.                                  unsigned dflt)
  2385. {
  2386.   if (newBase == 0) {
  2387.     newBase = dflt;
  2388.     newMax = dflt;
  2389.     if (dflt > 0)
  2390.       newMax += range;
  2391.   }
  2392.   else {
  2393.     if (newBase < 1024)
  2394.       newBase = 1024;
  2395.     else if (newBase > 65500)
  2396.       newBase = 65500;
  2397.  
  2398.     if (newMax <= newBase)
  2399.       newMax = newBase + range;
  2400.     if (newMax > 65535)
  2401.       newMax = 65535;
  2402.   }
  2403.  
  2404.   mutex.Wait();
  2405.  
  2406.   current = base = (WORD)newBase;
  2407.   max = (WORD)newMax;
  2408.  
  2409.   mutex.Signal();
  2410. }
  2411.  
  2412.  
  2413. WORD H323EndPoint::PortInfo::GetNext(unsigned increment)
  2414. {
  2415.   PWaitAndSignal m(mutex);
  2416.  
  2417.   if (current < base || current > (max-increment))
  2418.     current = base;
  2419.  
  2420.   if (current == 0)
  2421.     return 0;
  2422.  
  2423.   WORD p = current;
  2424.   current = (WORD)(current + increment);
  2425.   return p;
  2426. }
  2427.  
  2428.  
  2429. void H323EndPoint::SetTCPPorts(unsigned tcpBase, unsigned tcpMax)
  2430. {
  2431.   tcpPorts.Set(tcpBase, tcpMax, 99, 0);
  2432. }
  2433.  
  2434.  
  2435. WORD H323EndPoint::GetNextTCPPort()
  2436. {
  2437.   return tcpPorts.GetNext(1);
  2438. }
  2439.  
  2440.  
  2441. void H323EndPoint::SetUDPPorts(unsigned udpBase, unsigned udpMax)
  2442. {
  2443.   udpPorts.Set(udpBase, udpMax, 199, 0);
  2444. }
  2445.  
  2446.  
  2447. WORD H323EndPoint::GetNextUDPPort()
  2448. {
  2449.   return udpPorts.GetNext(1);
  2450. }
  2451.  
  2452.  
  2453. void H323EndPoint::SetRtpIpPorts(unsigned rtpIpBase, unsigned rtpIpMax)
  2454. {
  2455.   rtpIpPorts.Set((rtpIpBase+1)&0xfffe, rtpIpMax&0xfffe, 999, 5000);
  2456. }
  2457.  
  2458.  
  2459. WORD H323EndPoint::GetRtpIpPortPair()
  2460. {
  2461.   return rtpIpPorts.GetNext(2);
  2462. }
  2463.  
  2464. const PTimeInterval & H323EndPoint::GetNoMediaTimeout() const
  2465. {
  2466.   PWaitAndSignal m(noMediaMutex);
  2467.   
  2468.   return noMediaTimeout; 
  2469. }
  2470.  
  2471. BOOL H323EndPoint::SetNoMediaTimeout(PTimeInterval newInterval) 
  2472. {
  2473.   PWaitAndSignal m(noMediaMutex);
  2474.  
  2475.   if (newInterval < 0)
  2476.     return FALSE;
  2477.  
  2478.   noMediaTimeout = newInterval; 
  2479.   return TRUE; 
  2480. }
  2481.  
  2482.  
  2483. /////////////////////////////////////////////////////////////////////////////
  2484.