4 * H.323 protocol handler
8 * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions of this code were written with the assisance of funding from
25 * Vovida Networks, Inc. http://www.vovida.com.
27 * Contributor(s): ______________________________________.
30 * Revision 1.229 2007/04/01 20:37:16 shorne
31 * fix for double delete of STUN
33 * Revision 1.228 2006/08/10 04:05:03 csoutheren
34 * Apply 1537305 - Fix compile problems on gcc 4.1
35 * Thanks to Stanislav Brabec
37 * Revision 1.227 2006/06/26 02:52:51 shorne
38 * Moved H460 feature loader from H323EndPoint Constructor
40 * Revision 1.226 2006/06/23 20:01:29 shorne
43 * Revision 1.225 2006/06/23 07:22:40 csoutheren
44 * Fixed compile when H.224 disabled
46 * Revision 1.224 2006/06/23 06:02:44 csoutheren
47 * Added missing declarations for H.224 backport
49 * Revision 1.223 2006/06/21 05:11:48 csoutheren
50 * Fixed build with latest PWLib
52 * Revision 1.222 2006/06/09 06:30:12 csoutheren
53 * Remove compile warning and errors with gcc
55 * Revision 1.221 2006/05/30 11:14:56 hfriederich
56 * Switch from DISABLE_H460 to H323_H460
58 * Revision 1.220 2006/05/16 11:44:09 shorne
59 * extended DNS SRV, H460 Feature , Call Credit, extend conference goals
61 * Revision 1.219 2006/03/07 10:37:46 csoutheren
62 * Add ability to disable GRQ on GK registration
64 * Revision 1.218 2006/03/02 10:08:35 shorne
65 * Corrected Caller Authentcation & added more NAT traversal debug code
67 * Revision 1.217 2006/02/26 14:07:53 shorne
68 * Updated for function name change in PDNS
70 * Revision 1.216 2006/02/26 11:00:57 shorne
71 * Added DNS SRV record lookups to ParseParty
73 * Revision 1.215 2006/01/30 00:51:06 csoutheren
74 * Fixed compile problem on Linux
76 * Revision 1.214 2006/01/27 07:53:40 csoutheren
77 * Fixed for signalling aggregation
79 * Revision 1.213 2006/01/26 03:47:18 shorne
80 * Caller Authentication, more Nat Traversal support, more PBX support
82 * Revision 1.212 2006/01/24 08:15:24 csoutheren
83 * Implement outgoing H.225 aggregation, and H.245 aggregation (disabled by default)
84 * More testing to do, but this looks good :)
86 * Revision 1.211 2006/01/20 00:32:24 csoutheren
87 * First check-in of signalling aggregation code - incomplete and disabled by default
89 * Revision 1.210 2006/01/18 07:46:08 csoutheren
90 * Initial version of RTP aggregation (disabled by default)
92 * Revision 1.209 2005/11/25 03:42:04 csoutheren
93 * Added fix for bug #1326612
94 * H323EndPoint::OpenAudioChannel bug
96 * Revision 1.208 2005/11/22 03:38:45 shorne
97 * Added ToS support to TCP Transports. thx Norbert Bartalsky (TOPCALL)
99 * Revision 1.207 2005/11/21 20:54:43 shorne
100 * Added GnuGK Nat detection support / ParseParrty returns FALSE if no ENUM servers found.
103 * Revision 1.206 2005/09/16 08:12:50 csoutheren
104 * Added ability to set timeout for connect
106 * Revision 1.205 2005/08/04 19:43:20 csoutheren
107 * Applied patch #1240787
108 * Fixed problem when disabling H.450
109 * Thanks to Boris Pavacic
111 * Revision 1.204 2005/07/12 12:28:55 csoutheren
112 * Fixes for H.450 errors and return values
113 * Thanks to Iker Perez San Roman
115 * Revision 1.203 2005/06/07 00:22:24 csoutheren
116 * Added patch 1198111 to allow disabling the audio jitter buffer by calling
117 * H323EndPoint::SetAudioJitterDelay(0, 0). Thanks to Michael Manousos
119 * Revision 1.202 2005/05/03 12:22:55 csoutheren
120 * Unlock connection list when creating connection
121 * Remove chance of race condition with H.245 negotiation timer
122 * Unregister OpalPluginMediaFormat when instance is destroyed
123 * Thank to Paul Cadach
125 * Revision 1.201 2005/03/10 07:01:29 csoutheren
126 * Fixed problem with H.450 call identifiers not being unique across all calls on an
127 * endpoint. Thanks to Thien Nguyen
129 * Revision 1.200 2005/03/07 23:46:25 csoutheren
130 * Fixed problem with namespace of ETSI OSP token
132 * Revision 1.199 2005/01/21 21:26:50 csoutheren
133 * Fixed problem compiling with audio and without sound driver support
135 * Revision 1.198 2005/01/16 20:39:44 csoutheren
136 * Fixed problem with IPv6 INADDR_ANY
138 * Revision 1.197 2005/01/04 08:08:45 csoutheren
139 * More changes to implement the new configuration methodology, and also to
140 * attack the global static problem
142 * Revision 1.196 2005/01/03 14:03:42 csoutheren
143 * Added new configure options and ability to disable/enable modules
145 * Revision 1.195 2005/01/03 06:25:55 csoutheren
146 * Added extensive support for disabling code modules at compile time
148 * Revision 1.194 2004/12/23 22:27:58 csoutheren
149 * Fixed problem with not using specified port when attempting to resolve URLs
150 * hostnames using DNS
152 * Revision 1.193 2004/12/20 02:32:35 csoutheren
153 * Cleeaned up OSP functions
155 * Revision 1.192 2004/12/09 23:38:40 csoutheren
156 * More OSP implementation
158 * Revision 1.191 2004/12/08 05:16:14 csoutheren
159 * Fixed OSP compilation on Linux
161 * Revision 1.190 2004/12/08 01:59:23 csoutheren
162 * initial support for Transnexus OSP toolkit
164 * Revision 1.189 2004/11/30 00:16:54 csoutheren
165 * Don' t convert userIndication::signalUpdate messages into UserInputString messages
167 * Revision 1.188 2004/11/29 23:44:21 csoutheren
168 * Fixed type on TranslateTCPAddress
170 * Revision 1.187 2004/11/29 06:30:54 csoutheren
171 * Added support for wideband codecs
173 * Revision 1.186 2004/11/25 07:38:58 csoutheren
174 * Ensured that external TCP address translation is performed when using STUN to handle UDP
176 * Revision 1.185 2004/11/20 22:00:49 csoutheren
177 * Added hacks for linker problem
179 * Revision 1.184 2004/11/12 06:04:44 csoutheren
180 * Changed H235Authentiators to use PFactory
182 * Revision 1.183 2004/10/16 03:07:52 rjongbloed
183 * Fixed correct detection of when to use STUN, this does not include the local host!
185 * Revision 1.182 2004/09/03 01:06:10 csoutheren
186 * Added initial hooks for H.460 GEF
187 * Thanks to Simon Horne and ISVO (Asia) Pte Ltd. for this contribution
189 * Revision 1.181 2004/08/26 08:05:04 csoutheren
190 * Codecs now appear in abstract factory system
191 * Fixed Windows factory bootstrap system (again)
193 * Revision 1.180 2004/08/04 10:44:10 csoutheren
194 * More guards when testing for resolution via ENUM
196 * Revision 1.179 2004/08/03 23:06:27 csoutheren
197 * Disabled ENUM when calling an IP address
199 * Revision 1.178 2004/08/03 13:38:56 csoutheren
200 * Added support for ENUM when no GK is configured
202 * Revision 1.177 2004/07/27 05:28:45 csoutheren
203 * Added ability to set priority of channel threads
205 * Revision 1.176 2004/07/03 06:51:37 rjongbloed
206 * Added PTRACE_PARAM() macro to fix warnings on parameters used in PTRACE
209 * Revision 1.175 2004/06/15 03:30:01 csoutheren
210 * Added OnSendARQ to allow access to the ARQ message before sent by connection
212 * Revision 1.174 2004/06/01 05:48:03 csoutheren
213 * Changed capability table to use abstract factory routines rather than internal linked list
215 * Revision 1.173 2004/05/18 06:03:45 csoutheren
216 * Removed warnings under Windows
218 * Revision 1.172 2004/05/17 12:14:25 csoutheren
219 * Added support for different SETUP PDU types
221 * Revision 1.171 2004/04/07 05:31:43 csoutheren
222 * Added ability to receive calls from endpoints behind NAT firewalls
224 * Revision 1.170 2004/01/26 11:42:36 rjongbloed
225 * Added pass through of port numbers to STUN client
227 * Revision 1.169 2003/12/29 04:59:25 csoutheren
228 * Added callbacks on H323EndPoint when gatekeeper discovery succeeds or fails
230 * Revision 1.168 2003/12/28 02:37:49 csoutheren
231 * Added H323EndPoint::OnOutgoingCall
233 * Revision 1.167 2003/12/28 00:06:51 csoutheren
234 * Added callbacks on H323EndPoint when gatekeeper registration succeeds or fails
236 * Revision 1.166 2003/04/28 09:01:15 robertj
237 * Fixed problem with backward compatibility with non-url based remote
238 * addresses passed to MakeCall()
240 * Revision 1.165 2003/04/24 01:49:33 dereks
241 * Add ability to set no media timeout interval
243 * Revision 1.164 2003/04/10 09:41:26 robertj
244 * Added associated transport to new GetInterfaceAddresses() function so
245 * interfaces can be ordered according to active transport links. Improves
248 * Revision 1.163 2003/04/10 01:01:56 craigs
249 * Added functions to access to lists of interfaces
251 * Revision 1.162 2003/04/07 13:09:30 robertj
252 * Added ILS support to callto URL parsing in MakeCall(), ie can now call hosts
253 * registered with an ILS directory.
255 * Revision 1.161 2003/04/07 11:11:45 craigs
256 * Fixed compile problem on Linux
258 * Revision 1.160 2003/04/04 08:04:35 robertj
259 * Added support for URL's in MakeCall, especially h323 and callto schemes.
261 * Revision 1.159 2003/03/04 03:58:32 robertj
262 * Fixed missing local interface usage if specified in UseGatekeeper()
264 * Revision 1.158 2003/02/28 09:00:37 rogerh
265 * remove redundant code
267 * Revision 1.157 2003/02/25 23:51:49 robertj
268 * Fxied bug where not getting last port in range, thanks Sonya Cooper-Hull
270 * Revision 1.156 2003/02/09 00:48:09 robertj
271 * Added function to return if registered with gatekeeper.
273 * Revision 1.155 2003/02/05 06:32:10 robertj
274 * Fixed non-stun symmetric NAT support recently broken.
276 * Revision 1.154 2003/02/05 04:56:35 robertj
277 * Fixed setting STUN server to enpty string clearing stun variable.
279 * Revision 1.153 2003/02/04 07:06:41 robertj
280 * Added STUN support.
282 * Revision 1.152 2003/02/01 13:31:22 robertj
283 * Changes to support CAT authentication in RAS.
285 * Revision 1.151 2003/01/26 05:57:29 robertj
286 * Changed ParsePartyName so will accept addresses of the form
287 * alias@gk:address which will do an LRQ call to "address" using "alias"
288 * to determine the IP address to connect to.
290 * Revision 1.150 2003/01/23 02:36:32 robertj
291 * Increased (and made configurable) timeout for H.245 channel TCP connection.
293 * Revision 1.149 2003/01/06 06:13:37 robertj
294 * Increased maximum possible jitter configuration to 10 seconds.
296 * Revision 1.148 2002/11/27 06:54:57 robertj
297 * Added Service Control Session management as per Annex K/H.323 via RAS
298 * only at this stage.
299 * Added H.248 ASN and very primitive infrastructure for linking into the
300 * Service Control Session management system.
301 * Added basic infrastructure for Annex K/H.323 HTTP transport system.
302 * Added Call Credit Service Control to display account balances.
304 * Revision 1.147 2002/11/19 07:07:44 robertj
305 * Changed priority so H.235 standard authentication used by preference.
307 * Revision 1.146 2002/11/15 06:53:24 robertj
308 * Fixed non facility redirect calls being able to be cleared!
310 * Revision 1.145 2002/11/15 05:17:26 robertj
311 * Added facility redirect support without changing the call token for access
312 * to the call. If it gets redirected a new H323Connection object is
313 * created but it looks like the same thing to an application.
315 * Revision 1.144 2002/11/14 22:06:08 robertj
316 * Increased default maximum number of ports.
318 * Revision 1.143 2002/11/10 08:10:43 robertj
319 * Moved constants for "well known" ports to better place (OPAL change).
321 * Revision 1.142 2002/10/31 00:42:41 robertj
322 * Enhanced jitter buffer system so operates dynamically between minimum and
323 * maximum values. Altered API to assure app writers note the change!
325 * Revision 1.141 2002/10/24 07:18:24 robertj
326 * Changed gatekeeper call so if can do local DNS lookup or using IP address
327 * then uses destCallSignalAddress for ARQ instead of destinationInfo.
329 * Revision 1.140 2002/10/23 06:06:13 robertj
330 * Added function to be smarter in using a gatekeeper for use by endpoint.
332 * Revision 1.139 2002/10/01 06:38:36 robertj
333 * Removed GNU compiler warning
335 * Revision 1.138 2002/10/01 03:07:15 robertj
336 * Added version number functions for OpenH323 library itself, plus included
337 * library version in the default vendor information.
339 * Revision 1.137 2002/08/15 04:56:56 robertj
340 * Fixed operation of ports system assuring RTP is even numbers.
342 * Revision 1.136 2002/08/05 10:03:47 robertj
343 * Cosmetic changes to normalise the usage of pragma interface/implementation.
345 * Revision 1.135 2002/07/19 11:25:10 robertj
346 * Added extra trace on attempt to clear non existent call.
348 * Revision 1.134 2002/07/19 03:39:22 robertj
349 * Bullet proofed setting of RTP IP port base, can't be zero!
351 * Revision 1.133 2002/07/18 01:50:14 robertj
352 * Changed port secltion code to force apps to use function interface.
354 * Revision 1.132 2002/07/04 00:11:25 robertj
355 * Fixed setting of gk password when password changed in endpoint.
357 * Revision 1.131 2002/06/22 05:48:42 robertj
358 * Added partial implementation for H.450.11 Call Intrusion
360 * Revision 1.130 2002/06/15 03:06:46 robertj
361 * Fixed locking of connection on H.250.2 transfer, thanks Gilles Delcayre
363 * Revision 1.129 2002/06/13 06:15:20 robertj
364 * Allowed TransferCall() to be used on H323Connection as well as H323EndPoint.
366 * Revision 1.128 2002/06/12 03:55:21 robertj
367 * Added function to add/remove multiple listeners in one go comparing against
368 * what is already running so does not interrupt unchanged listeners.
370 * Revision 1.127 2002/05/29 06:40:33 robertj
371 * Changed sending of endSession/ReleaseComplete PDU's to occur immediately
372 * on call clearance and not wait for background thread to do it.
373 * Stricter compliance by waiting for reply endSession before closing down.
375 * Revision 1.126 2002/05/28 06:16:12 robertj
376 * Split UDP (for RAS) from RTP port bases.
377 * Added current port variable so cycles around the port range specified which
378 * fixes some wierd problems on some platforms, thanks Federico Pinna
380 * Revision 1.125 2002/05/17 03:39:01 robertj
381 * Fixed problems with H.235 authentication on RAS for server and client.
383 * Revision 1.124 2002/05/15 23:57:49 robertj
384 * Added function to get the tokens for all active calls.
385 * Fixed setting of password info in gatekeeper so is before discovery.
387 * Revision 1.123 2002/05/02 07:56:28 robertj
388 * Added automatic clearing of call if no media (RTP data) is transferred in a
389 * configurable (default 5 minutes) amount of time.
391 * Revision 1.122 2002/04/18 01:40:56 robertj
392 * Fixed bad variable name for disabling DTMF detection, very confusing.
394 * Revision 1.121 2002/04/17 00:50:57 robertj
395 * Added ability to disable the in band DTMF detection.
397 * Revision 1.120 2002/04/10 08:09:03 robertj
398 * Allowed zero TCP ports
400 * Revision 1.119 2002/04/10 06:50:08 robertj
401 * Added functions to set port member variables.
403 * Revision 1.118 2002/04/01 21:32:24 robertj
404 * Fixed problem with busy loop on Solaris, thanks chad@broadmind.com
406 * Revision 1.117 2002/02/04 07:17:56 robertj
407 * Added H.450.2 Consultation Transfer, thanks Norwood Systems.
409 * Revision 1.116 2002/01/24 06:29:06 robertj
410 * Added option to disable H.245 negotiation in SETUP pdu, this required
411 * API change so have a bit mask instead of a series of booleans.
413 * Revision 1.115 2002/01/17 07:05:04 robertj
414 * Added support for RFC2833 embedded DTMF in the RTP stream.
416 * Revision 1.114 2002/01/14 00:00:04 robertj
417 * Added CallTransfer timeouts to endpoint, hanks Ben Madsen of Norwood Systems.
419 * Revision 1.113 2002/01/08 04:45:04 robertj
420 * Added MakeCallLocked() so can start a call with the H323Connection instance
421 * initally locked so can do things to it before the call really starts.
423 * Revision 1.112 2001/12/22 03:20:05 robertj
424 * Added create protocol function to H323Connection.
426 * Revision 1.111 2001/12/14 08:36:36 robertj
427 * More implementation of T.38, thanks Adam Lazur
429 * Revision 1.110 2001/12/13 11:01:37 robertj
430 * Fixed missing initialisation of auto fax start variables.
432 * Revision 1.109 2001/11/01 06:11:57 robertj
433 * Plugged very small mutex hole that could cause crashes.
435 * Revision 1.108 2001/11/01 00:59:07 robertj
436 * Added auto setting of silence detect mode when using PSoundChannel codec.
438 * Revision 1.107 2001/11/01 00:27:35 robertj
439 * Added default Fast Start disabled and H.245 tunneling disable flags
440 * to the endpoint instance.
442 * Revision 1.106 2001/10/30 07:34:33 robertj
443 * Added trace for when cleaner thread start, stops and runs
445 * Revision 1.105 2001/10/24 07:25:59 robertj
446 * Fixed possible deadlocks during destruction of H323Connection object.
448 * Revision 1.104 2001/09/26 06:20:59 robertj
449 * Fixed properly nesting connection locking and unlocking requiring a quite
450 * large change to teh implementation of how calls are answered.
452 * Revision 1.103 2001/09/13 02:41:21 robertj
453 * Fixed call reference generation to use full range and common code.
455 * Revision 1.102 2001/09/11 01:24:36 robertj
456 * Added conditional compilation to remove video and/or audio codecs.
458 * Revision 1.101 2001/09/11 00:21:23 robertj
459 * Fixed missing stack sizes in endpoint for cleaner thread and jitter thread.
461 * Revision 1.100 2001/08/24 13:38:25 rogerh
462 * Free the locally declared listener.
464 * Revision 1.99 2001/08/24 13:23:59 rogerh
465 * Undo a recent memory leak fix. The listener object has to be deleted in the
466 * user application as they use the listener when StartListener() fails.
467 * Add a Resume() if StartListener() fails so user applications can delete
468 * the suspended thread.
470 * Revision 1.98 2001/08/22 06:54:51 robertj
471 * Changed connection locking to use double mutex to guarantee that
472 * no threads can ever deadlock or access deleted connection.
474 * Revision 1.97 2001/08/16 07:49:19 robertj
475 * Changed the H.450 support to be more extensible. Protocol handlers
476 * are now in separate classes instead of all in H323Connection.
478 * Revision 1.96 2001/08/10 11:03:52 robertj
479 * Major changes to H.235 support in RAS to support server.
481 * Revision 1.95 2001/08/08 23:55:27 robertj
482 * Fixed problem with setting gk password before have a gk variable.
483 * Fixed memory leak if listener fails to open.
484 * Fixed problem with being able to specify an alias with an @ in it.
486 * Revision 1.94 2001/08/06 07:44:55 robertj
487 * Fixed problems with building without SSL
489 * Revision 1.93 2001/08/06 03:08:56 robertj
490 * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
492 * Revision 1.92 2001/08/02 04:31:48 robertj
493 * Changed to still maintain gatekeeper link if GRQ succeeded but RRQ
494 * failed. Thanks Ben Madsen & Graeme Reid.
496 * Revision 1.91 2001/07/17 04:44:32 robertj
497 * Partial implementation of T.120 and T.38 logical channels.
499 * Revision 1.90 2001/07/06 07:28:55 robertj
500 * Fixed rearranged connection creation to avoid possible nested mutex.
502 * Revision 1.89 2001/07/06 04:46:19 robertj
503 * Rearranged connection creation to avoid possible nested mutex.
505 * Revision 1.88 2001/06/19 08:43:38 robertj
506 * Fixed deadlock if ClearCallSynchronous ever called from cleaner thread.
508 * Revision 1.87 2001/06/19 03:55:30 robertj
509 * Added transport to CreateConnection() function so can use that as part of
510 * the connection creation decision making process.
512 * Revision 1.86 2001/06/15 00:55:53 robertj
513 * Added thread name for cleaner thread
515 * Revision 1.85 2001/06/14 23:18:06 robertj
516 * Change to allow for CreateConnection() to return NULL to abort call.
518 * Revision 1.84 2001/06/14 04:23:32 robertj
519 * Changed incoming call to pass setup pdu to endpoint so it can create
520 * different connection subclasses depending on the pdu eg its alias
522 * Revision 1.83 2001/06/02 01:35:32 robertj
523 * Added thread names.
525 * Revision 1.82 2001/05/30 11:13:54 robertj
526 * Fixed possible deadlock when getting connection from endpoint.
528 * Revision 1.81 2001/05/14 05:56:28 robertj
529 * Added H323 capability registration system so can add capabilities by
530 * string name instead of having to instantiate explicit classes.
532 * Revision 1.80 2001/05/01 04:34:11 robertj
533 * Changed call transfer API slightly to be consistent with new hold function.
535 * Revision 1.79 2001/04/23 01:31:15 robertj
536 * Improved the locking of connections especially at shutdown.
538 * Revision 1.78 2001/04/11 03:01:29 robertj
539 * Added H.450.2 (call transfer), thanks a LOT to Graeme Reid & Norwood Systems
541 * Revision 1.77 2001/03/21 04:52:42 robertj
542 * Added H.235 security to gatekeepers, thanks Fürbass Franz!
544 * Revision 1.76 2001/03/17 00:05:52 robertj
545 * Fixed problems with Gatekeeper RIP handling.
547 * Revision 1.75 2001/03/15 00:24:47 robertj
548 * Added function for setting gatekeeper with address and identifier values.
550 * Revision 1.74 2001/02/27 00:03:59 robertj
551 * Fixed possible deadlock in FindConnectionsWithLock(), thanks Hans Andersen
553 * Revision 1.73 2001/02/16 04:11:35 robertj
554 * Added ability for RemoveListener() to remove all listeners.
556 * Revision 1.72 2001/01/18 06:04:18 robertj
557 * Bullet proofed code so local alias can not be empty string. This actually
558 * fixes an ASN PER encoding bug causing an assert.
560 * Revision 1.71 2001/01/11 02:19:15 craigs
561 * Fixed problem with possible window of opportunity for ClearCallSynchronous
562 * to return even though call has not been cleared
564 * Revision 1.70 2000/12/22 03:54:33 craigs
565 * Fixed problem with listening fix
567 * Revision 1.69 2000/12/21 12:38:24 craigs
568 * Fixed problem with "Listener thread did not terminate" assert
569 * when listener port is in use
571 * Revision 1.68 2000/12/20 00:51:03 robertj
572 * Fixed MSVC compatibility issues (No trace).
574 * Revision 1.67 2000/12/19 22:33:44 dereks
575 * Adjust so that the video channel is used for reading/writing raw video
576 * data, which better modularizes the video codec.
578 * Revision 1.66 2000/12/18 08:59:20 craigs
579 * Added ability to set ports
581 * Revision 1.65 2000/12/18 01:22:28 robertj
582 * Changed semantics or HasConnection() so returns TRUE until the connection
583 * has been deleted and not just until ClearCall() was executure on it.
585 * Revision 1.64 2000/11/27 02:44:06 craigs
586 * Added ClearCall Synchronous to H323Connection and H323Endpoint to
587 * avoid race conditions with destroying descendant classes
589 * Revision 1.63 2000/11/26 23:13:23 craigs
590 * Added ability to pass user data to H323Connection constructor
592 * Revision 1.62 2000/11/12 23:49:16 craigs
593 * Added per connection versions of OnEstablished and OnCleared
595 * Revision 1.61 2000/10/25 00:53:52 robertj
596 * Used official manafacturer code for the OpenH323 project.
598 * Revision 1.60 2000/10/20 06:10:51 robertj
599 * Fixed very small race condition on creating new connectionon incoming call.
601 * Revision 1.59 2000/10/19 04:07:50 robertj
602 * Added function to be able to remove a listener.
604 * Revision 1.58 2000/10/04 12:21:07 robertj
605 * Changed setting of callToken in H323Connection to be as early as possible.
607 * Revision 1.57 2000/09/25 12:59:34 robertj
608 * Added StartListener() function that takes a H323TransportAddress to start
609 * listeners bound to specific interfaces.
611 * Revision 1.56 2000/09/14 23:03:45 robertj
612 * Increased timeout on asserting because of driver lockup
614 * Revision 1.55 2000/09/01 02:13:05 robertj
615 * Added ability to select a gatekeeper on LAN via it's identifier name.
617 * Revision 1.54 2000/08/30 05:37:44 robertj
618 * Fixed bogus destCallSignalAddress in ARQ messages.
620 * Revision 1.53 2000/08/29 02:59:50 robertj
621 * Added some debug output for channel open/close.
623 * Revision 1.52 2000/08/25 01:10:28 robertj
624 * Added assert if various thrads ever fail to terminate.
626 * Revision 1.51 2000/07/13 12:34:41 robertj
627 * Split autoStartVideo so can select receive and transmit independently
629 * Revision 1.50 2000/07/11 19:30:15 robertj
630 * Fixed problem where failure to unregister from gatekeeper prevented new registration.
632 * Revision 1.49 2000/07/09 14:59:28 robertj
633 * Fixed bug if using default transport (no '@') for address when gatekeeper present, used port 1719.
635 * Revision 1.48 2000/07/04 04:15:40 robertj
636 * Fixed capability check of "combinations" for fast start cases.
638 * Revision 1.47 2000/07/04 01:16:50 robertj
639 * Added check for capability allowed in "combinations" set, still needs more done yet.
641 * Revision 1.46 2000/06/29 11:00:04 robertj
642 * Added user interface for sound buffer depth adjustment.
644 * Revision 1.45 2000/06/29 07:10:32 robertj
645 * Fixed incorrect setting of default number of audio buffers on Win32 systems.
647 * Revision 1.44 2000/06/23 02:48:24 robertj
648 * Added ability to adjust sound channel buffer depth, needed increasing under Win32.
650 * Revision 1.43 2000/06/20 02:38:28 robertj
651 * Changed H323TransportAddress to default to IP.
653 * Revision 1.42 2000/06/17 09:13:06 robertj
654 * Removed redundent line of code, thanks David Iodice.
656 * Revision 1.41 2000/06/07 05:48:06 robertj
657 * Added call forwarding.
659 * Revision 1.40 2000/06/03 03:16:39 robertj
660 * Fixed using the wrong capability table (should be connections) for some operations.
662 * Revision 1.39 2000/05/25 00:34:59 robertj
663 * Changed default tos on Unix platforms to avoid needing to be root.
665 * Revision 1.38 2000/05/23 12:57:37 robertj
666 * Added ability to change IP Type Of Service code from applications.
668 * Revision 1.37 2000/05/23 11:32:37 robertj
669 * Rewrite of capability table to combine 2 structures into one and move functionality into that class
670 * allowing some normalisation of usage across several applications.
671 * Changed H323Connection so gets a copy of capabilities instead of using endponts, allows adjustments
672 * to be done depending on the remote client application.
674 * Revision 1.36 2000/05/16 07:38:50 robertj
675 * Added extra debug info indicating sound channel buffer size.
677 * Revision 1.35 2000/05/11 03:48:11 craigs
678 * Moved SetBuffer command to fix audio delay
680 * Revision 1.34 2000/05/02 04:32:26 robertj
681 * Fixed copyright notice comment.
683 * Revision 1.33 2000/05/01 13:00:28 robertj
684 * Changed SetCapability() to append capabilities to TCS, helps with assuring no gaps in set.
686 * Revision 1.32 2000/04/30 03:58:37 robertj
687 * Changed PSoundChannel to be only double bufferred, this is all that is needed with jitter bufferring.
689 * Revision 1.31 2000/04/11 04:02:48 robertj
690 * Improved call initiation with gatekeeper, no longer require @address as
691 * will default to gk alias if no @ and registered with gk.
692 * Added new call end reasons for gatekeeper denied calls.
694 * Revision 1.30 2000/04/10 20:37:33 robertj
695 * Added support for more sophisticated DTMF and hook flash user indication.
697 * Revision 1.29 2000/04/06 17:50:17 robertj
698 * Added auto-start (including fast start) of video channels, selectable via boolean on the endpoint.
700 * Revision 1.28 2000/04/05 03:17:31 robertj
701 * Added more RTP statistics gathering and H.245 round trip delay calculation.
703 * Revision 1.27 2000/03/29 02:14:45 robertj
704 * Changed TerminationReason to CallEndReason to use correct telephony nomenclature.
705 * Added CallEndReason for capability exchange failure.
707 * Revision 1.26 2000/03/25 02:03:36 robertj
708 * Added default transport for gatekeeper to be UDP.
710 * Revision 1.25 2000/03/23 02:45:29 robertj
711 * Changed ClearAllCalls() so will wait for calls to be closed (usefull in endpoint dtors).
713 * Revision 1.24 2000/02/17 12:07:43 robertj
714 * Used ne wPWLib random number generator after finding major problem in MSVC rand().
716 * Revision 1.23 2000/01/07 08:22:49 robertj
717 * Added status functions for connection and added transport independent MakeCall
719 * Revision 1.22 1999/12/23 23:02:36 robertj
720 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
722 * Revision 1.21 1999/12/11 02:21:00 robertj
723 * Added ability to have multiple aliases on local endpoint.
725 * Revision 1.20 1999/12/09 23:14:20 robertj
726 * Fixed deadock in termination with gatekeeper removal.
728 * Revision 1.19 1999/11/19 08:07:27 robertj
729 * Changed default jitter time to 50 milliseconds.
731 * Revision 1.18 1999/11/06 05:37:45 robertj
732 * Complete rewrite of termination of connection to avoid numerous race conditions.
734 * Revision 1.17 1999/10/30 12:34:47 robertj
735 * Added information callback for closed logical channel on H323EndPoint.
737 * Revision 1.16 1999/10/19 00:04:57 robertj
738 * Changed OpenAudioChannel and OpenVideoChannel to allow a codec AttachChannel with no autodelete.
740 * Revision 1.15 1999/10/14 12:05:03 robertj
741 * Fixed deadlock possibilities in clearing calls.
743 * Revision 1.14 1999/10/09 01:18:23 craigs
744 * Added codecs to OpenAudioChannel and OpenVideoDevice functions
746 * Revision 1.13 1999/10/08 08:31:45 robertj
747 * Fixed failure to adjust capability when startign channel
749 * Revision 1.12 1999/09/23 07:25:12 robertj
750 * Added open audio and video function to connection and started multi-frame codec send functionality.
752 * Revision 1.11 1999/09/21 14:24:48 robertj
753 * Changed SetCapability() so automatically calls AddCapability().
755 * Revision 1.10 1999/09/21 14:12:40 robertj
756 * Removed warnings when no tracing enabled.
758 * Revision 1.9 1999/09/21 08:10:03 craigs
759 * Added support for video devices and H261 codec
761 * Revision 1.8 1999/09/14 06:52:54 robertj
762 * Added better support for multi-homed client hosts.
764 * Revision 1.7 1999/09/13 14:23:11 robertj
765 * Changed MakeCall() function return value to be something useful.
767 * Revision 1.6 1999/09/10 02:55:36 robertj
768 * Changed t35 country code to Australia (finally found magic number).
770 * Revision 1.5 1999/09/08 04:05:49 robertj
771 * Added support for video capabilities & codec, still needs the actual codec itself!
773 * Revision 1.4 1999/08/31 12:34:19 robertj
774 * Added gatekeeper support.
776 * Revision 1.3 1999/08/27 15:42:44 craigs
777 * Fixed problem with local call tokens using ambiguous interface names, and connect timeouts not changing connection state
779 * Revision 1.2 1999/08/27 09:46:05 robertj
780 * Added sepearte function to initialise vendor information from endpoint.
782 * Revision 1.1 1999/08/25 05:10:36 robertj
783 * File fission (critical mass reached).
784 * Improved way in which remote capabilities are created, removed case statement!
785 * Changed MakeCall, so immediately spawns thread, no black on TCP connect.
790 #include <ptlib/sound.h>
793 #pragma implementation "h323ep.h"
796 #include "openh323buildopts.h"
805 #include "gkclient.h"
808 #include "t38proto.h"
811 #include "../version.h"
812 #include "h323pluginmgr.h"
814 #include <ptlib/sound.h>
815 #include <ptclib/random.h>
816 #include <ptclib/pstun.h>
817 #include <ptclib/url.h>
818 #include <ptclib/pils.h>
819 #include <ptclib/enum.h>
821 #include <h224handler.h>
823 #if defined(H323_RTP_AGGREGATE) || defined(H323_SIGNAL_AGGREGATE)
824 #include <ptclib/sockagg.h>
827 #ifndef IPTOS_PREC_CRITIC_ECP
828 #define IPTOS_PREC_CRITIC_ECP (5 << 5)
831 #ifndef IPTOS_LOWDELAY
832 #define IPTOS_LOWDELAY 0x10
835 #include "opalglobalstatics.cxx"
837 //////////////////////////////////////////////////////////////////////////////////////
839 BYTE
H323EndPoint::defaultT35CountryCode
= 9; // Country code for Australia
840 BYTE
H323EndPoint::defaultT35Extension
= 0;
841 WORD
H323EndPoint::defaultManufacturerCode
= 61; // Allocated by Australian Communications Authority, Oct 2000;
843 //////////////////////////////////////////////////////////////////////////////////////
846 // OSP token identifier as per section ETSI TS 101 32 D.3, using XML format
847 // itu-t(0), identifier-organization(4), etsi(0), ts-101-1321(1321), token(1), xml-format(2)
848 const char * ETSIXMLTokenOID
= "0.4.0.1321.1.2";
851 //////////////////////////////////////////////////////////////////////////////////////
853 class H225CallThread
: public PThread
855 PCLASSINFO(H225CallThread
, PThread
)
858 H225CallThread(H323EndPoint
& endpoint
,
859 H323Connection
& connection
,
860 H323Transport
& transport
,
861 const PString
& alias
,
862 const H323TransportAddress
& address
);
867 H323Connection
& connection
;
868 H323Transport
& transport
;
870 H323TransportAddress address
;
871 #ifdef H323_SIGNAL_AGGREGATE
877 class H323ConnectionsCleaner
: public PThread
879 PCLASSINFO(H323ConnectionsCleaner
, PThread
)
882 H323ConnectionsCleaner(H323EndPoint
& endpoint
);
883 ~H323ConnectionsCleaner();
885 void Signal() { wakeupFlag
.Signal(); }
890 H323EndPoint
& endpoint
;
892 PSyncPoint wakeupFlag
;
899 /////////////////////////////////////////////////////////////////////////////
901 PString
OpalGetVersion()
903 #define AlphaCode "alpha"
904 #define BetaCode "beta"
905 #define ReleaseCode "."
907 return psprintf("%u.%u%s%u", MAJOR_VERSION
, MINOR_VERSION
, BUILD_TYPE
, BUILD_NUMBER
);
911 unsigned OpalGetMajorVersion()
913 return MAJOR_VERSION
;
916 unsigned OpalGetMinorVersion()
918 return MINOR_VERSION
;
921 unsigned OpalGetBuildNumber()
928 /////////////////////////////////////////////////////////////////////////////
930 H225CallThread::H225CallThread(H323EndPoint
& endpoint
,
934 const H323TransportAddress
& addr
)
935 : PThread(endpoint
.GetSignallingThreadStackSize(),
944 #ifdef H323_SIGNAL_AGGREGATE
945 useAggregator
= endpoint
.GetSignallingAggregator() != NULL
;
949 transport
.AttachThread(this);
956 void H225CallThread::Main()
958 PTRACE(3, "H225\tStarted call thread");
960 if (connection
.Lock()) {
961 H323Connection::CallEndReason reason
= connection
.SendSignalSetup(alias
, address
);
963 // Special case, if we aborted the call then already will be unlocked
964 if (reason
!= H323Connection::EndedByCallerAbort
)
967 // Check if had an error, clear call if so
968 if (reason
!= H323Connection::NumCallEndReasons
)
969 connection
.ClearCall(reason
);
971 #ifdef H323_SIGNAL_AGGREGATE
973 connection
.AggregateSignalChannel(&transport
);
974 SetAutoDelete(AutoDeleteThread
);
978 connection
.HandleSignallingChannel();
984 /////////////////////////////////////////////////////////////////////////////
986 H323ConnectionsCleaner::H323ConnectionsCleaner(H323EndPoint
& ep
)
987 : PThread(ep
.GetCleanerThreadStackSize(),
998 H323ConnectionsCleaner::~H323ConnectionsCleaner()
1001 wakeupFlag
.Signal();
1002 PAssert(WaitForTermination(10000), "Cleaner thread did not terminate");
1006 void H323ConnectionsCleaner::Main()
1008 PTRACE(3, "H323\tStarted cleaner thread");
1015 endpoint
.CleanUpConnections();
1018 PTRACE(3, "H323\tStopped cleaner thread");
1022 /////////////////////////////////////////////////////////////////////////////
1024 H323EndPoint::H323EndPoint()
1027 soundChannelPlayDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Player
)),
1028 soundChannelRecordDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Recorder
)),
1030 signallingChannelConnectTimeout(0, 10, 0), // seconds
1031 signallingChannelCallTimeout(0, 0, 1), // Minutes
1032 controlChannelStartTimeout(0, 0, 2), // Minutes
1033 endSessionTimeout(0, 10), // Seconds
1034 masterSlaveDeterminationTimeout(0, 30), // Seconds
1035 capabilityExchangeTimeout(0, 30), // Seconds
1036 logicalChannelTimeout(0, 30), // Seconds
1037 requestModeTimeout(0, 30), // Seconds
1038 roundTripDelayTimeout(0, 10), // Seconds
1039 roundTripDelayRate(0, 0, 1), // Minutes
1040 noMediaTimeout(0, 0, 5), // Minutes
1041 gatekeeperRequestTimeout(0, 5), // Seconds
1042 rasRequestTimeout(0, 3) // Seconds
1046 callTransferT1(0,10), // Seconds
1047 callTransferT2(0,10), // Seconds
1048 callTransferT3(0,10), // Seconds
1049 callTransferT4(0,10), // Seconds
1050 callIntrusionT1(0,30), // Seconds
1051 callIntrusionT2(0,30), // Seconds
1052 callIntrusionT3(0,30), // Seconds
1053 callIntrusionT4(0,30), // Seconds
1054 callIntrusionT5(0,10), // Seconds
1055 callIntrusionT6(0,10), // Seconds
1056 nextH450CallIdentity(0)
1060 PString username
= PProcess::Current().GetUserName();
1061 if (username
.IsEmpty())
1062 username
= PProcess::Current().GetName() & "User";
1063 localAliasNames
.AppendString(username
);
1066 autoStartReceiveVideo
= autoStartTransmitVideo
= TRUE
;
1070 autoStartReceiveFax
= autoStartTransmitFax
= FALSE
;
1073 #ifdef H323_AUDIO_CODECS
1074 minAudioJitterDelay
= 50; // milliseconds
1075 maxAudioJitterDelay
= 250; // milliseconds
1078 autoCallForward
= TRUE
;
1079 disableFastStart
= FALSE
;
1080 disableH245Tunneling
= FALSE
;
1081 disableH245inSetup
= FALSE
;
1082 disableDetectInBandDTMF
= FALSE
;
1083 canDisplayAmountString
= FALSE
;
1084 canEnforceDurationLimit
= TRUE
;
1087 callIntrusionProtectionLevel
= 3; //H45011_CIProtectionLevel::e_fullProtection;
1090 #ifdef H323_AUDIO_CODECS
1091 defaultSilenceDetection
= H323AudioCodec::AdaptiveSilenceDetection
;
1094 defaultSendUserInputMode
= H323Connection::SendUserInputAsString
;
1096 terminalType
= e_TerminalOnly
;
1097 initialBandwidth
= 100000; // Standard 10base LAN in 100's of bits/sec
1098 clearCallOnRoundTripFail
= FALSE
;
1100 t35CountryCode
= defaultT35CountryCode
; // Country code for Australia
1101 t35Extension
= defaultT35Extension
;
1102 manufacturerCode
= defaultManufacturerCode
; // Allocated by Australian Communications Authority, Oct 2000
1104 rtpIpPorts
.current
= rtpIpPorts
.base
= 5000;
1105 rtpIpPorts
.max
= 5999;
1107 // use dynamic port allocation by default
1108 tcpPorts
.current
= tcpPorts
.base
= tcpPorts
.max
= 0;
1109 udpPorts
.current
= udpPorts
.base
= udpPorts
.max
= 0;
1117 # if defined(H323_AUDIO_CODECS) && defined(P_AUDIO)
1118 // Windows MultiMedia stuff seems to need greater depth due to enormous
1119 // latencies in its operation, need to use DirectSound maybe?
1120 soundChannelBuffers
= 3;
1123 rtpIpTypeofService
= IPTOS_PREC_CRITIC_ECP
|IPTOS_LOWDELAY
;
1127 # ifdef H323_AUDIO_CODECS
1128 // Should only need double buffering for Unix platforms
1129 soundChannelBuffers
= 2;
1132 // Don't use IPTOS_PREC_CRITIC_ECP on Unix platforms as then need to be root
1133 rtpIpTypeofService
= IPTOS_LOWDELAY
;
1136 tcpIpTypeofService
= IPTOS_LOWDELAY
;
1138 masterSlaveDeterminationRetries
= 10;
1139 gatekeeperRequestRetries
= 2;
1140 rasRequestRetries
= 2;
1143 cleanerThreadStackSize
= 30000;
1144 listenerThreadStackSize
= 30000;
1145 signallingThreadStackSize
= 30000;
1146 controlThreadStackSize
= 30000;
1147 logicalThreadStackSize
= 30000;
1148 rasThreadStackSize
= 30000;
1149 jitterThreadStackSize
= 30000;
1151 #ifdef H323_SIGNAL_AGGREGATE
1152 signallingAggregationSize
= 25;
1153 signallingAggregator
= NULL
;
1156 #ifdef H323_RTP_AGGREGATE
1157 rtpAggregationSize
= 10;
1158 rtpAggregator
= NULL
;
1161 channelThreadPriority
= PThread::HighestPriority
;
1165 connectionsActive
.DisallowDeleteObjects();
1168 secondaryConnectionsActive
.DisallowDeleteObjects();
1171 connectionsCleaner
= new H323ConnectionsCleaner(*this);
1173 srand((unsigned)time(NULL
)+clock());
1175 #ifdef H323_TRANSNEXUS_OSP
1179 #ifndef DISABLE_CALLAUTH
1180 SetEPSecurityPolicy(SecNone
);
1181 SetEPCredentials(PString(),PString());
1182 isSecureCall
= FALSE
;
1185 PTRACE(3, "H323\tCreated endpoint.");
1189 H323EndPoint::~H323EndPoint()
1191 #ifdef H323_TRANSNEXUS_OSP
1192 // close the OSP provider (if there was one)
1193 SetOSPProvider(NULL
);
1196 #if defined(H323_RTP_AGGREGATE) || defined (H323_SIGNAL_AGGREGATE)
1197 // delete aggregators
1199 PWaitAndSignal
m(connectionsMutex
);
1200 #ifdef H323_RTP_AGGREGATE
1201 if (rtpAggregator
!= NULL
) {
1202 delete rtpAggregator
;
1203 rtpAggregator
= NULL
;
1206 #ifdef H323_SIGNAL_AGGREGATE
1207 if (signallingAggregator
!= NULL
) {
1208 delete signallingAggregator
;
1209 signallingAggregator
= NULL
;
1215 // And shut down the gatekeeper (if there was one)
1218 // Shut down the listeners as soon as possible to avoid race conditions
1219 listeners
.RemoveAll();
1221 // Clear any pending calls on this endpoint
1224 // Shut down the cleaner thread
1225 delete connectionsCleaner
;
1227 // Clean up any connections that the cleaner thread missed
1228 CleanUpConnections();
1234 PTRACE(3, "H323\tDeleted endpoint.");
1238 void H323EndPoint::SetEndpointTypeInfo(H225_EndpointType
& info
) const
1240 info
.IncludeOptionalField(H225_EndpointType::e_vendor
);
1241 SetVendorIdentifierInfo(info
.m_vendor
);
1243 switch (terminalType
) {
1244 case e_TerminalOnly
:
1245 case e_TerminalAndMC
:
1246 info
.IncludeOptionalField(H225_EndpointType::e_terminal
);
1248 case e_GatewayOnly
:
1249 case e_GatewayAndMC
:
1250 case e_GatewayAndMCWithDataMP
:
1251 case e_GatewayAndMCWithAudioMP
:
1252 case e_GatewayAndMCWithAVMP
:
1253 info
.IncludeOptionalField(H225_EndpointType::e_gateway
);
1255 case e_GatekeeperOnly
:
1256 case e_GatekeeperWithDataMP
:
1257 case e_GatekeeperWithAudioMP
:
1258 case e_GatekeeperWithAVMP
:
1259 info
.IncludeOptionalField(H225_EndpointType::e_gatekeeper
);
1262 case e_MCUWithDataMP
:
1263 case e_MCUWithAudioMP
:
1264 case e_MCUWithAVMP
:
1265 info
.IncludeOptionalField(H225_EndpointType::e_mcu
);
1271 void H323EndPoint::SetVendorIdentifierInfo(H225_VendorIdentifier
& info
) const
1273 SetH221NonStandardInfo(info
.m_vendor
);
1275 info
.IncludeOptionalField(H225_VendorIdentifier::e_productId
);
1276 info
.m_productId
= PProcess::Current().GetManufacturer() & PProcess::Current().GetName();
1277 info
.m_productId
.SetSize(info
.m_productId
.GetSize()+2);
1279 info
.IncludeOptionalField(H225_VendorIdentifier::e_versionId
);
1280 info
.m_versionId
= PProcess::Current().GetVersion(TRUE
) + " (OpenH323 v" + OpalGetVersion() + ')';
1281 info
.m_versionId
.SetSize(info
.m_versionId
.GetSize()+2);
1285 void H323EndPoint::SetH221NonStandardInfo(H225_H221NonStandard
& info
) const
1287 info
.m_t35CountryCode
= t35CountryCode
;
1288 info
.m_t35Extension
= t35Extension
;
1289 info
.m_manufacturerCode
= manufacturerCode
;
1293 H323Capability
* H323EndPoint::FindCapability(const H245_Capability
& cap
) const
1295 return capabilities
.FindCapability(cap
);
1299 H323Capability
* H323EndPoint::FindCapability(const H245_DataType
& dataType
) const
1301 return capabilities
.FindCapability(dataType
);
1305 H323Capability
* H323EndPoint::FindCapability(H323Capability::MainTypes mainType
,
1306 unsigned subType
) const
1308 return capabilities
.FindCapability(mainType
, subType
);
1312 void H323EndPoint::AddCapability(H323Capability
* capability
)
1314 capabilities
.Add(capability
);
1318 PINDEX
H323EndPoint::SetCapability(PINDEX descriptorNum
,
1319 PINDEX simultaneousNum
,
1320 H323Capability
* capability
)
1322 return capabilities
.SetCapability(descriptorNum
, simultaneousNum
, capability
);
1326 PINDEX
H323EndPoint::AddAllCapabilities(PINDEX descriptorNum
,
1327 PINDEX simultaneous
,
1328 const PString
& name
)
1330 return capabilities
.AddAllCapabilities(descriptorNum
, simultaneous
, name
);
1334 void H323EndPoint::AddAllUserInputCapabilities(PINDEX descriptorNum
,
1335 PINDEX simultaneous
)
1337 H323_UserInputCapability::AddAllCapabilities(capabilities
, descriptorNum
, simultaneous
);
1341 void H323EndPoint::RemoveCapabilities(const PStringArray
& codecNames
)
1343 capabilities
.Remove(codecNames
);
1347 void H323EndPoint::ReorderCapabilities(const PStringArray
& preferenceOrder
)
1349 capabilities
.Reorder(preferenceOrder
);
1353 BOOL
H323EndPoint::UseGatekeeper(const PString
& address
,
1354 const PString
& identifier
,
1355 const PString
& localAddress
)
1357 if (gatekeeper
!= NULL
) {
1361 same
= gatekeeper
->GetTransport().GetRemoteAddress().IsEquivalent(address
);
1363 if (!same
&& !identifier
)
1364 same
= gatekeeper
->GetIdentifier() == identifier
;
1366 if (!same
&& !localAddress
)
1367 same
= gatekeeper
->GetTransport().GetLocalAddress().IsEquivalent(localAddress
);
1370 PTRACE(2, "H323\tUsing existing gatekeeper " << *gatekeeper
);
1375 H323Transport
* transport
= NULL
;
1376 if (!localAddress
.IsEmpty()) {
1377 H323TransportAddress
iface(localAddress
);
1378 PIPSocket::Address ip
;
1379 WORD port
= H225_RAS::DefaultRasUdpPort
;
1380 if (iface
.GetIpAndPort(ip
, port
))
1381 transport
= new H323TransportUDP(*this, ip
, port
);
1384 if (address
.IsEmpty()) {
1385 if (identifier
.IsEmpty())
1386 return DiscoverGatekeeper(transport
);
1388 return LocateGatekeeper(identifier
, transport
);
1391 if (identifier
.IsEmpty())
1392 return SetGatekeeper(address
, transport
);
1394 return SetGatekeeperZone(address
, identifier
, transport
);
1399 BOOL
H323EndPoint::SetGatekeeper(const PString
& address
, H323Transport
* transport
)
1401 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
1402 return InternalRegisterGatekeeper(gk
, gk
->DiscoverByAddress(address
));
1406 BOOL
H323EndPoint::SetGatekeeperZone(const PString
& address
,
1407 const PString
& identifier
,
1408 H323Transport
* transport
)
1410 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
1411 return InternalRegisterGatekeeper(gk
, gk
->DiscoverByNameAndAddress(identifier
, address
));
1415 BOOL
H323EndPoint::LocateGatekeeper(const PString
& identifier
, H323Transport
* transport
)
1417 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
1418 return InternalRegisterGatekeeper(gk
, gk
->DiscoverByName(identifier
));
1422 BOOL
H323EndPoint::DiscoverGatekeeper(H323Transport
* transport
)
1424 H323Gatekeeper
* gk
= InternalCreateGatekeeper(transport
);
1425 return InternalRegisterGatekeeper(gk
, gk
->DiscoverAny());
1429 H323Gatekeeper
* H323EndPoint::InternalCreateGatekeeper(H323Transport
* transport
)
1431 RemoveGatekeeper(H225_UnregRequestReason::e_reregistrationRequired
);
1433 if (transport
== NULL
)
1434 transport
= new H323TransportUDP(*this);
1436 H323Gatekeeper
* gk
= CreateGatekeeper(transport
);
1438 gk
->SetPassword(gatekeeperPassword
);
1444 BOOL
H323EndPoint::InternalRegisterGatekeeper(H323Gatekeeper
* gk
, BOOL discovered
)
1447 if (gk
->RegistrationRequest()) {
1452 // RRQ was rejected continue trying
1455 else // Only stop listening if the GRQ was rejected
1462 H323Gatekeeper
* H323EndPoint::CreateGatekeeper(H323Transport
* transport
)
1464 return new H323Gatekeeper(*this, transport
);
1468 BOOL
H323EndPoint::IsRegisteredWithGatekeeper() const
1470 if (gatekeeper
== NULL
)
1473 return gatekeeper
->IsRegistered();
1477 BOOL
H323EndPoint::RemoveGatekeeper(int reason
)
1481 if (gatekeeper
== NULL
)
1486 if (gatekeeper
->IsRegistered()) // If we are registered send a URQ
1487 ok
= gatekeeper
->UnregistrationRequest(reason
);
1496 void H323EndPoint::SetGatekeeperPassword(const PString
& password
)
1498 gatekeeperPassword
= password
;
1500 if (gatekeeper
!= NULL
) {
1501 gatekeeper
->SetPassword(gatekeeperPassword
);
1502 if (gatekeeper
->IsRegistered()) // If we are registered send a URQ
1503 gatekeeper
->UnregistrationRequest(H225_UnregRequestReason::e_reregistrationRequired
);
1504 InternalRegisterGatekeeper(gatekeeper
, TRUE
);
1508 void H323EndPoint::OnGatekeeperConfirm()
1512 void H323EndPoint::OnGatekeeperReject()
1516 void H323EndPoint::OnRegistrationConfirm()
1520 void H323EndPoint::OnRegistrationReject()
1524 H235Authenticators
H323EndPoint::CreateAuthenticators()
1526 H235Authenticators authenticators
;
1528 PFactory
<H235Authenticator
>::KeyList_T keyList
= PFactory
<H235Authenticator
>::GetKeyList();
1529 PFactory
<H235Authenticator
>::KeyList_T::const_iterator r
;
1530 for (r
= keyList
.begin(); r
!= keyList
.end(); ++r
) {
1531 H235Authenticator
* Auth
= PFactory
<H235Authenticator
>::CreateInstance(*r
);
1532 if ((Auth
->GetApplication() == H235Authenticator::GKAdmission
) ||
1533 (Auth
->GetApplication() == H235Authenticator::AnyApplication
))
1534 authenticators
.Append(Auth
);
1537 return authenticators
;
1540 #ifndef DISABLE_CALLAUTH
1541 H235Authenticators
H323EndPoint::CreateEPAuthenticators()
1543 H235Authenticators authenticators
;
1548 if ((GetEPSecurityPolicy() != SecNone
) || (isSecureCall
)) {
1549 if (GetEPCredentials(password
, username
)) {
1550 PFactory
<H235Authenticator
>::KeyList_T keyList
= PFactory
<H235Authenticator
>::GetKeyList();
1551 PFactory
<H235Authenticator
>::KeyList_T::const_iterator r
;
1552 for (r
= keyList
.begin(); r
!= keyList
.end(); ++r
) {
1553 H235Authenticator
* Auth
= PFactory
<H235Authenticator
>::CreateInstance(*r
);
1554 if ((Auth
->GetApplication() == H235Authenticator::EPAuthentication
) ||
1555 (Auth
->GetApplication() == H235Authenticator::AnyApplication
)) {
1556 Auth
->SetLocalId(username
);
1557 Auth
->SetPassword(password
);
1558 authenticators
.Append(Auth
);
1561 SetEPCredentials(PString(),PString());
1563 isSecureCall
= FALSE
;
1566 return authenticators
;
1569 BOOL
H323EndPoint::GetEPCredentials(PString
& password
,
1572 if (EPSecurityPassword
.IsEmpty())
1575 password
= EPSecurityPassword
;
1577 if (EPSecurityUserName
.IsEmpty())
1578 username
= GetLocalUserName();
1580 username
= EPSecurityUserName
;
1585 void H323EndPoint::SetEPCredentials(PString password
, PString username
)
1587 EPSecurityPassword
= password
;
1588 EPSecurityUserName
= username
;
1591 void H323EndPoint::SetEPSecurityPolicy(EPSecurityPolicy policy
)
1593 CallAuthPolicy
= policy
;
1596 H323EndPoint::EPSecurityPolicy
H323EndPoint::GetEPSecurityPolicy()
1598 return CallAuthPolicy
;
1601 H235AuthenticatorList
H323EndPoint::GetAuthenticatorList()
1606 BOOL
H323EndPoint::OnCallAuthentication(const PString
& username
,
1609 if (EPAuthList
.HasUserName(username
)) {
1610 EPAuthList
.LoadPassword(username
, password
);
1617 H323Connection
* H323EndPoint::MakeAuthenticatedCall(const PString
& remoteParty
,
1618 const PString
& UserName
, const PString
& Password
, PString
& token
, void * userData
)
1620 isSecureCall
= TRUE
;
1621 SetEPCredentials(Password
,UserName
);
1622 return MakeCall(remoteParty
, token
, userData
);
1626 BOOL
H323EndPoint::StartListeners(const H323TransportAddressArray
& ifaces
)
1628 if (ifaces
.IsEmpty())
1629 return StartListener("*");
1633 for (i
= 0; i
< listeners
.GetSize(); i
++) {
1635 for (PINDEX j
= 0; j
< ifaces
.GetSize(); j
++) {
1636 if (listeners
[i
].GetTransportAddress().IsEquivalent(ifaces
[j
])) {
1642 PTRACE(3, "H323\tRemoving listener " << listeners
[i
]);
1643 listeners
.RemoveAt(i
--);
1647 for (i
= 0; i
< ifaces
.GetSize(); i
++) {
1649 StartListener(ifaces
[i
]);
1652 return listeners
.GetSize() > 0;
1656 BOOL
H323EndPoint::StartListener(const H323TransportAddress
& iface
)
1658 H323Listener
* listener
;
1660 if (iface
.IsEmpty())
1661 listener
= new H323ListenerTCP(*this, PIPSocket::GetDefaultIpAny(), DefaultTcpPort
);
1663 listener
= iface
.CreateListener(*this);
1665 if (H323EndPoint::StartListener(listener
))
1668 PTRACE(1, "H323\tCould not start listener: " << iface
);
1674 BOOL
H323EndPoint::StartListener(H323Listener
* listener
)
1676 if (listener
== NULL
)
1679 for (PINDEX i
= 0; i
< listeners
.GetSize(); i
++) {
1680 if (listeners
[i
].GetTransportAddress() == listener
->GetTransportAddress()) {
1681 PTRACE(2, "H323\tAlready have listener for " << *listener
);
1687 // as the listener is not open, this will have the effect of immediately
1688 // stopping the listener thread. This is good - it means that the
1689 // listener Close function will appear to have stopped the thread
1690 if (!listener
->Open()) {
1691 listener
->Resume(); // set the thread running so we can delete it later
1695 PTRACE(3, "H323\tStarted listener " << *listener
);
1696 listeners
.Append(listener
);
1702 BOOL
H323EndPoint::RemoveListener(H323Listener
* listener
)
1704 if (listener
!= NULL
) {
1705 PTRACE(3, "H323\tRemoving listener " << *listener
);
1706 return listeners
.Remove(listener
);
1709 PTRACE(3, "H323\tRemoving all listeners");
1710 listeners
.RemoveAll();
1715 H323TransportAddressArray
H323EndPoint::GetInterfaceAddresses(BOOL excludeLocalHost
,
1716 H323Transport
* associatedTransport
)
1718 return H323GetInterfaceAddresses(listeners
, excludeLocalHost
, associatedTransport
);
1721 H323Connection
* H323EndPoint::MakeCall(const PString
& remoteParty
,
1725 return MakeCall(remoteParty
, NULL
, token
, userData
);
1729 H323Connection
* H323EndPoint::MakeCall(const PString
& remoteParty
,
1730 H323Transport
* transport
,
1734 token
= PString::Empty();
1736 PStringList Addresses
;
1737 if (!ResolveCallParty(remoteParty
, Addresses
))
1740 H323Connection
* connection
= NULL
;
1741 for (PINDEX i
= 0; i
< Addresses
.GetSize(); i
++) {
1742 connection
= InternalMakeCall(PString::Empty(),
1749 if (connection
!= NULL
) {
1750 connection
->Unlock();
1759 H323Connection
* H323EndPoint::MakeCallLocked(const PString
& remoteParty
,
1762 H323Transport
* transport
)
1764 token
= PString::Empty();
1766 PStringList Addresses
;
1767 if (!ResolveCallParty(remoteParty
, Addresses
))
1770 H323Connection
* connection
= NULL
;
1771 for (PINDEX i
= 0; i
< Addresses
.GetSize(); i
++) {
1772 connection
= InternalMakeCall(PString::Empty(),
1779 if (connection
!= NULL
)
1787 #ifdef H323_TRANSNEXUS_OSP
1789 static BOOL
GetListenerInterfaceAddress(H323Listener
& listener
, H323TransportAddress
& taddr
)
1791 taddr
= listener
.GetTransportAddress();
1792 PIPSocket::Address addr
;
1794 if (!taddr
.GetIpAndPort(addr
, port
))
1800 if (!PIPSocket::GetNetworkInterface(addr
))
1803 taddr
= H323TransportAddress(addr
, port
);
1809 H323Connection
* H323EndPoint::InternalMakeCall(const PString
& trasferFromToken
,
1810 const PString
& callIdentity
,
1811 unsigned capabilityLevel
,
1812 const PString
& remoteParty
,
1813 H323Transport
* transport
,
1817 PTRACE(2, "H323\tMaking call to: " << remoteParty
);
1820 H323TransportAddress address
;
1821 if (!ParsePartyName(remoteParty
, alias
, address
)) {
1822 PTRACE(2, "H323\tCould not parse \"" << remoteParty
<< '"');
1826 if (transport
== NULL
) {
1827 // Restriction: the call must be made on the same transport as the one
1828 // that the gatekeeper is using.
1829 if (gatekeeper
!= NULL
)
1830 transport
= gatekeeper
->GetTransport().GetRemoteAddress().CreateTransport(*this);
1832 #ifdef H323_TRANSNEXUS_OSP
1833 // Restriction: the call must be made on the same transport used by the endpoint listener
1834 else if (ospProvider
!= NULL
&& (listeners
.GetSize() > 0)) {
1835 H323TransportAddress taddr
;
1836 if (!GetListenerInterfaceAddress(listeners
[0], taddr
)) {
1837 PTRACE(1, "H323\tCannot find an interface to use for the OSP-based connection");
1840 transport
= taddr
.CreateTransport(*this);
1844 // assume address is an IP address/hostname
1846 transport
= address
.CreateTransport(*this);
1848 if (transport
== NULL
) {
1849 PTRACE(1, "H323\tInvalid transport in \"" << remoteParty
<< '"');
1854 H323Connection
* connection
;
1856 connectionsMutex
.Wait();
1858 unsigned lastReference
;
1859 if (newToken
.IsEmpty()) {
1861 lastReference
= Q931::GenerateCallReference();
1862 newToken
= BuildConnectionToken(*transport
, lastReference
, FALSE
);
1863 } while (connectionsActive
.Contains(newToken
));
1866 lastReference
= newToken
.Mid(newToken
.Find('/')+1).AsUnsigned();
1868 // Move old connection on token to new value and flag for removal
1869 PString adjustedToken
;
1870 unsigned tieBreaker
= 0;
1872 adjustedToken
= newToken
+ "-replaced";
1873 adjustedToken
.sprintf("-%u", ++tieBreaker
);
1874 } while (connectionsActive
.Contains(adjustedToken
));
1875 connectionsActive
.SetAt(adjustedToken
, connectionsActive
.RemoveAt(newToken
));
1876 connectionsToBeCleaned
+= adjustedToken
;
1877 PTRACE(3, "H323\tOverwriting call " << newToken
<< ", renamed to " << adjustedToken
);
1879 connectionsMutex
.Signal();
1881 connection
= CreateConnection(lastReference
, userData
, transport
, NULL
);
1882 if (connection
== NULL
) {
1883 PTRACE(1, "H323\tCreateConnection returned NULL");
1884 connectionsMutex
.Signal();
1890 connectionsMutex
.Wait();
1891 connectionsActive
.SetAt(newToken
, connection
);
1893 connectionsMutex
.Signal();
1895 connection
->AttachSignalChannel(newToken
, transport
, FALSE
);
1898 if (capabilityLevel
== UINT_MAX
)
1899 connection
->HandleTransferCall(trasferFromToken
, callIdentity
);
1901 connection
->HandleIntrudeCall(trasferFromToken
, callIdentity
);
1902 connection
->IntrudeCall(capabilityLevel
);
1906 PTRACE(3, "H323\tCreated new connection: " << newToken
);
1908 new H225CallThread(*this, *connection
, *transport
, alias
, address
);
1914 struct LookupRecord
{
1920 PIPSocket::Address addr
;
1924 static BOOL
FindSRVRecords(std::vector
<LookupRecord
> & recs
,
1925 const PString
& domain
,
1927 const PString
& srv
)
1929 PDNS::SRVRecordList srvRecords
;
1930 PString srvLookupStr
= srv
+ domain
;
1931 BOOL found
= PDNS::GetRecords(srvLookupStr
, srvRecords
);
1933 PDNS::SRVRecord
* recPtr
= srvRecords
.GetFirst();
1934 while (recPtr
!= NULL
) {
1936 rec
.addr
= recPtr
->hostAddress
;
1937 rec
.port
= recPtr
->port
;
1939 recs
.push_back(rec
);
1940 recPtr
= srvRecords
.GetNext();
1941 PTRACE(4, "H323\tFound " << rec
.addr
<< ":" << rec
.port
<< " with SRV " << srv
<< " using domain " << domain
);
1947 static BOOL
FindRoutes(const PString
& domain
, WORD port
, std::vector
<LookupRecord
> & routes
)
1949 BOOL hasGK
= FindSRVRecords( routes
, domain
, LookupRecord::LRQ
, "_h323ls._udp.");
1950 hasGK
= hasGK
|| FindSRVRecords(routes
, domain
, LookupRecord::LRQ
, "_h323rs._udp.");
1951 FindSRVRecords( routes
, domain
, LookupRecord::CallDirect
, "_h323cs._tcp.");
1953 // see if the domain is actually a host
1954 PIPSocket::Address addr
;
1955 if (PIPSocket::GetHostAddress(domain
, addr
)) {
1959 rec
.type
= LookupRecord::CallDirect
;
1960 PTRACE(4, "H323\tDomain " << domain
<< " is a host - using as call signal address");
1961 routes
.push_back(rec
);
1964 if (routes
.size() != 0) {
1965 PDNS::MXRecordList mxRecords
;
1966 if (PDNS::GetRecords(domain
, mxRecords
)) {
1967 PDNS::MXRecord
* recPtr
= mxRecords
.GetFirst();
1968 while (recPtr
!= NULL
) {
1970 rec
.addr
= recPtr
->hostAddress
;
1972 rec
.type
= LookupRecord::LRQ
;
1973 routes
.push_back(rec
);
1974 recPtr
= mxRecords
.GetNext();
1975 PTRACE(4, "H323\tFound " << rec
.addr
<< ":" << rec
.port
<< " with MX for domain " << domain
);
1980 return routes
.size() != 0;
1984 BOOL
H323EndPoint::ResolveCallParty(const PString
& _remoteParty
, PStringList
& addresses
)
1986 PString remoteParty
= _remoteParty
;
1989 // if there is no gatekeeper,
1990 if (gatekeeper
== NULL
) {
1992 //if there is no '@', and there is no URL scheme, then attempt to use ENUM
1993 if ((_remoteParty
.Find(':') == P_MAX_INDEX
) && (remoteParty
.Find('@') == P_MAX_INDEX
)) {
1995 PString number
= _remoteParty
;
1996 if (number
.Left(5) *= "h323:")
1997 number
= number
.Mid(5);
2000 for (i
= 0; i
< number
.GetLength(); ++i
)
2001 if (!isdigit(number
[i
]))
2003 if (i
>= number
.GetLength()) {
2005 if (PDNS::ENUMLookup(number
, "E2U+h323", str
)) {
2006 if ((str
.Find("//1") != P_MAX_INDEX
) &&
2007 (str
.Find('@') != P_MAX_INDEX
)) {
2008 remoteParty
= "h323:" + number
+ str
.Mid(str
.Find('@')-1);
2012 PTRACE(4, "H323\tENUM converted remote party " << _remoteParty
<< " to " << remoteParty
);
2014 PTRACE(4, "H323\tENUM Cannot resolve remote party " << _remoteParty
);
2015 addresses
= PStringList(remoteParty
);
2020 // attempt a DNS SRV lookup to detect a call signalling entry
2021 if (remoteParty
.Find('@') != P_MAX_INDEX
) {
2022 PString number
= _remoteParty
;
2023 if (number
.Left(5) != "h323:")
2024 number
= "h323:" + number
;
2027 if (PDNS::LookupSRV(number
,"_h323cs._tcp.",str
)) {
2028 for (PINDEX i
=0; i
<str
.GetSize(); i
++) {
2029 PTRACE(4, "H323\tDNS SRV converted remote party " << _remoteParty
<< " to " << str
[i
]);
2030 addresses
.AppendString(str
[i
]);
2033 PTRACE(4, "H323\tDNS SRV Cannot resolve remote party " << remoteParty
);
2034 addresses
= PStringList(remoteParty
);
2037 addresses
= PStringList(remoteParty
);
2042 addresses
= PStringList(remoteParty
);
2046 BOOL
H323EndPoint::ParsePartyName(const PString
& _remoteParty
,
2048 H323TransportAddress
& address
)
2050 PString remoteParty
= _remoteParty
;
2052 // convert the remote party string to a URL, with a default URL of "h323:"
2053 PURL
url(remoteParty
, "h323");
2055 // if the scheme does not match the prefix of the remote party, then
2056 // the URL parser got confused, so force the URL to be of type "h323"
2057 if ((remoteParty
.Find('@') == P_MAX_INDEX
) && (remoteParty
.NumCompare(url
.GetScheme()) != EqualTo
)) {
2059 (gatekeeper
== NULL
)
2060 #ifdef H323_TRANSNEXUS_OSP
2061 && (ospProvider
== NULL
)
2064 url
.Parse("h323:@" + remoteParty
);
2066 url
.Parse("h323:" + remoteParty
);
2069 // get the various parts of the name
2070 PString hostOnly
= PString();
2071 if ((gatekeeper
!= NULL
) && (remoteParty
.Find('@') != P_MAX_INDEX
)) {
2072 alias
= "url:" + remoteParty
;
2074 alias
= url
.GetUserName();
2075 hostOnly
= url
.GetHostName();
2079 // make sure the address contains the port, if not default
2080 if (!address
&& (url
.GetPort() != 0))
2081 address
.sprintf(":%u", url
.GetPort());
2083 if (alias
.IsEmpty() && address
.IsEmpty()) {
2084 PTRACE(1, "H323\tAttempt to use invalid URL \"" << remoteParty
<< '"');
2088 BOOL gatekeeperSpecified
= FALSE
;
2089 BOOL gatewaySpecified
= FALSE
;
2091 PCaselessString type
= url
.GetParamVars()("type");
2093 if (url
.GetScheme() == "callto") {
2094 // Do not yet support ILS
2095 if (type
== "directory") {
2097 PString server
= url
.GetHostName();
2098 if (server
.IsEmpty())
2100 if (server
.IsEmpty())
2104 if (!ils
.Open(server
, url
.GetPort())) {
2105 PTRACE(1, "H323\tCould not open ILS server at \"" << server
2106 << "\" - " << ils
.GetErrorText());
2110 PILSSession::RTPerson person
;
2111 if (!ils
.SearchPerson(alias
, person
)) {
2112 PTRACE(1, "H323\tCould not find "
2113 << server
<< '/' << alias
<< ": " << ils
.GetErrorText());
2117 if (!person
.sipAddress
.IsValid()) {
2118 PTRACE(1, "H323\tILS user " << server
<< '/' << alias
2119 << " does not have a valid IP address");
2123 // Get the IP address
2124 address
= H323TransportAddress(person
.sipAddress
);
2126 // Get the port if provided
2127 for (PINDEX i
= 0; i
< person
.sport
.GetSize(); i
++) {
2128 if (person
.sport
[i
] != 1503) { // Dont use the T.120 port
2129 address
= H323TransportAddress(person
.sipAddress
, person
.sport
[i
]);
2134 alias
= PString::Empty(); // No alias for ILS lookup, only host
2141 if (url
.GetParamVars().Contains("gateway"))
2142 gatewaySpecified
= TRUE
;
2145 else if (url
.GetScheme() == "h323") {
2147 gatewaySpecified
= TRUE
;
2148 else if (type
== "gk")
2149 gatekeeperSpecified
= TRUE
;
2151 PTRACE(1, "H323\tUnsupported host type \"" << type
<< "\" in h323 URL");
2156 // User explicitly asked to use a GK for lookup
2157 if (gatekeeperSpecified
) {
2158 if (alias
.IsEmpty()) {
2159 PTRACE(1, "H323\tAttempt to use explict gatekeeper without alias!");
2163 if (address
.IsEmpty()) {
2164 PTRACE(1, "H323\tAttempt to use explict gatekeeper without address!");
2168 H323TransportAddress gkAddr
= address
;
2169 PTRACE(3, "H323\tLooking for \"" << alias
<< "\" on gatekeeper at " << gkAddr
);
2171 H323Gatekeeper
* gk
= CreateGatekeeper(new H323TransportUDP(*this));
2173 BOOL ok
= gk
->DiscoverByAddress(gkAddr
);
2175 ok
= gk
->LocationRequest(alias
, address
);
2177 PTRACE(3, "H323\tLocation Request of \"" << alias
<< "\" on gk " << gkAddr
<< " found " << address
);
2180 PTRACE(1, "H323\tLocation Request failed for \"" << alias
<< "\" on gk " << gkAddr
);
2184 PTRACE(1, "H323\tLocation Request discovery failed for gk " << gkAddr
);
2192 // User explicitly said to use a gw, or we do not have a gk to do look up
2194 #ifdef H323_TRANSNEXUS_OSP
2195 ((ospProvider
== NULL
) && (gatekeeper
== NULL
))
2197 (gatekeeper
== NULL
)
2199 || gatewaySpecified
) {
2200 // If URL did not have a host, but user said to use gw, or we do not have
2201 // a gk to do a lookup so we MUST have a host, use alias must be host
2202 if (address
.IsEmpty()) {
2204 alias
= PString::Empty();
2209 // if we have an address and the correct scheme, then check DNS
2210 if (!address
&& (url
.GetScheme() *= "h323")) {
2211 std::vector
<LookupRecord
> routes
;
2212 if (FindRoutes(hostOnly
, url
.GetPort(), routes
)) {
2213 std::vector
<LookupRecord
>::const_iterator r
;
2214 for (r
= routes
.begin(); r
!= routes
.end(); ++r
) {
2215 const LookupRecord
& rec
= *r
;
2217 /* case LookupRecord::CallDirect:
2218 address = H323TransportAddress(rec.addr, rec.port);
2219 PTRACE(3, "H323\tParty name \"" << url << "\" mapped to \"" << alias << "@" << address);
2223 case LookupRecord::LRQ
:
2225 H323TransportAddress newAddr
, gkAddr(rec
.addr
, rec
.port
);
2226 H323Gatekeeper
* gk
= CreateGatekeeper(new H323TransportUDP(*this));
2227 BOOL ok
= gk
->DiscoverByAddress(gkAddr
);
2229 ok
= gk
->LocationRequest(alias
, newAddr
);
2233 PTRACE(3, "H323\tLocation Request of \"" << alias
<< "\" on gk " << gkAddr
<< " found " << address
);
2251 // We have a gk and user did not explicitly supply a host, so lets
2252 // do a check to see if it is an IP address or hostname
2253 if (alias
.FindOneOf("$.:[") != P_MAX_INDEX
) {
2254 H323TransportAddress test
= alias
;
2255 PIPSocket::Address ip
;
2256 if (test
.GetIpAddress(ip
) && ip
.IsValid()) {
2257 // The alias was a valid internet address, use it as such
2258 alias
= PString::Empty();
2268 H323Connection
* H323EndPoint::SetupTransfer(const PString
& oldToken
,
2269 const PString
& callIdentity
,
2270 const PString
& remoteParty
,
2274 newToken
= PString::Empty();
2276 PStringList Addresses
;
2277 if (!ResolveCallParty(remoteParty
, Addresses
))
2280 H323Connection
* connection
= NULL
;
2281 for (PINDEX i
= 0; i
< Addresses
.GetSize(); i
++) {
2282 connection
= InternalMakeCall(oldToken
,
2289 if (connection
!= NULL
) {
2290 connection
->Unlock();
2299 void H323EndPoint::TransferCall(const PString
& token
,
2300 const PString
& remoteParty
,
2301 const PString
& callIdentity
)
2303 H323Connection
* connection
= FindConnectionWithLock(token
);
2304 if (connection
!= NULL
) {
2305 connection
->TransferCall(remoteParty
, callIdentity
);
2306 connection
->Unlock();
2311 void H323EndPoint::ConsultationTransfer(const PString
& primaryCallToken
,
2312 const PString
& secondaryCallToken
)
2314 H323Connection
* secondaryCall
= FindConnectionWithLock(secondaryCallToken
);
2315 if (secondaryCall
!= NULL
) {
2316 secondaryCall
->ConsultationTransfer(primaryCallToken
);
2317 secondaryCall
->Unlock();
2322 void H323EndPoint::HoldCall(const PString
& token
, BOOL localHold
)
2324 H323Connection
* connection
= FindConnectionWithLock(token
);
2325 if (connection
!= NULL
) {
2326 connection
->HoldCall(localHold
);
2327 connection
->Unlock();
2332 H323Connection
* H323EndPoint::IntrudeCall(const PString
& remoteParty
,
2334 unsigned capabilityLevel
,
2337 return IntrudeCall(remoteParty
, NULL
, token
, capabilityLevel
, userData
);
2341 H323Connection
* H323EndPoint::IntrudeCall(const PString
& remoteParty
,
2342 H323Transport
* transport
,
2344 unsigned capabilityLevel
,
2347 token
= PString::Empty();
2349 PStringList Addresses
;
2350 if (!ResolveCallParty(remoteParty
, Addresses
))
2353 H323Connection
* connection
= NULL
;
2354 for (PINDEX i
= 0; i
< Addresses
.GetSize(); i
++) {
2355 connection
= InternalMakeCall(PString::Empty(),
2362 if (connection
!= NULL
) {
2363 connection
->Unlock();
2370 void H323EndPoint::OnReceivedInitiateReturnError()
2377 BOOL
H323EndPoint::ClearCall(const PString
& token
,
2378 H323Connection::CallEndReason reason
)
2380 return ClearCallSynchronous(token
, reason
, NULL
);
2383 void H323EndPoint::OnCallClearing(H323Connection
* /*connection*/,
2384 H323Connection::CallEndReason
/*reason*/)
2388 BOOL
H323EndPoint::ClearCallSynchronous(const PString
& token
,
2389 H323Connection::CallEndReason reason
)
2392 return ClearCallSynchronous(token
, reason
, &sync
);
2395 BOOL
H323EndPoint::ClearCallSynchronous(const PString
& token
,
2396 H323Connection::CallEndReason reason
,
2399 if (PThread::Current() == connectionsCleaner
)
2402 /*The hugely multi-threaded nature of the H323Connection objects means that
2403 to avoid many forms of race condition, a call is cleared by moving it from
2404 the "active" call dictionary to a list of calls to be cleared that will be
2405 processed by a background thread specifically for the purpose of cleaning
2406 up cleared connections. So that is all that this function actually does.
2407 The real work is done in the H323ConnectionsCleaner thread.
2411 PWaitAndSignal
wait(connectionsMutex
);
2413 // Find the connection by token, callid or conferenceid
2414 H323Connection
* connection
= FindConnectionWithoutLocks(token
);
2415 if (connection
== NULL
) {
2416 PTRACE(3, "H323\tAttempt to clear unknown call " << token
);
2420 PTRACE(3, "H323\tClearing connection " << connection
->GetCallToken()
2421 << " reason=" << reason
);
2423 OnCallClearing(connection
,reason
);
2425 // Add this to the set of connections being cleaned, if not in already
2426 if (!connectionsToBeCleaned
.Contains(connection
->GetCallToken()))
2427 connectionsToBeCleaned
+= connection
->GetCallToken();
2429 // Now set reason for the connection close
2430 connection
->SetCallEndReason(reason
, sync
);
2432 // Signal the background threads that there is some stuff to process.
2433 connectionsCleaner
->Signal();
2443 void H323EndPoint::ClearAllCalls(H323Connection::CallEndReason reason
,
2446 /*The hugely multi-threaded nature of the H323Connection objects means that
2447 to avoid many forms of race condition, a call is cleared by moving it from
2448 the "active" call dictionary to a list of calls to be cleared that will be
2449 processed by a background thread specifically for the purpose of cleaning
2450 up cleared connections. So that is all that this function actually does.
2451 The real work is done in the H323ConnectionsCleaner thread.
2454 connectionsMutex
.Wait();
2456 // Add all connections to the to be deleted set
2458 for (i
= 0; i
< connectionsActive
.GetSize(); i
++) {
2459 H323Connection
& connection
= connectionsActive
.GetDataAt(i
);
2460 connectionsToBeCleaned
+= connection
.GetCallToken();
2461 // Now set reason for the connection close
2462 connection
.SetCallEndReason(reason
, NULL
);
2465 // Signal the background threads that there is some stuff to process.
2466 connectionsCleaner
->Signal();
2468 // Make sure any previous signals are removed before waiting later
2469 while (connectionsAreCleaned
.Wait(0))
2472 connectionsMutex
.Signal();
2475 connectionsAreCleaned
.Wait();
2478 void H323EndPoint::CleanUpConnections()
2480 PTRACE(3, "H323\tCleaning up connections");
2482 // Lock the connections database.
2483 connectionsMutex
.Wait();
2485 // Continue cleaning up until no more connections to clean
2486 while (connectionsToBeCleaned
.GetSize() > 0) {
2487 // Just get the first entry in the set of tokens to clean up.
2488 PString token
= connectionsToBeCleaned
.GetKeyAt(0);
2489 H323Connection
& connection
= connectionsActive
[token
];
2491 // Unlock the structures here so does not block other uses of ClearCall()
2492 // for the possibly long time it takes to CleanUpOnCallEnd().
2493 connectionsMutex
.Signal();
2495 // Clean up the connection, waiting for all threads to terminate
2496 connection
.CleanUpOnCallEnd();
2497 connection
.OnCleared();
2499 // Get the lock again as we remove the connection from our database
2500 connectionsMutex
.Wait();
2502 // Remove the token from the set of connections to be cleaned up
2503 connectionsToBeCleaned
-= token
;
2505 // And remove the connection instance itself from the dictionary which will
2506 // cause its destructor to be called.
2507 H323Connection
* connectionToDelete
= connectionsActive
.RemoveAt(token
);
2509 // Unlock the structures yet again to avoid possible race conditions when
2510 // deleting the connection as well as the delte of a conncetion descendent
2511 // is application writer dependent and may cause deadlocks or just consume
2513 connectionsMutex
.Signal();
2515 // Finally we get to delete it!
2516 delete connectionToDelete
;
2518 // Get the lock again as we continue around the loop
2519 connectionsMutex
.Wait();
2522 // Finished with loop, unlock the connections database.
2523 connectionsMutex
.Signal();
2525 // Signal thread that may be waiting on ClearAllCalls()
2526 connectionsAreCleaned
.Signal();
2530 BOOL
H323EndPoint::HasConnection(const PString
& token
)
2532 PWaitAndSignal
wait(connectionsMutex
);
2534 return FindConnectionWithoutLocks(token
) != NULL
;
2538 H323Connection
* H323EndPoint::FindConnectionWithLock(const PString
& token
)
2540 PWaitAndSignal
mutex(connectionsMutex
);
2542 /*We have a very yucky polling loop here as a semi permanant measure.
2543 Why? We cannot call Lock() inside the connectionsMutex critical section as
2544 it will cause a deadlock with something like a RELEASE-COMPLETE coming in
2545 on separate thread. But if we put it outside there is a small window where
2546 the connection could get deleted before the Lock() test is done.
2547 The solution is to attempt to get the mutex while inside the
2548 connectionsMutex but not block. That means a polling loop. There is
2549 probably a way to do this properly with mutexes but I don't have time to
2552 H323Connection
* connection
;
2553 while ((connection
= FindConnectionWithoutLocks(token
)) != NULL
) {
2554 switch (connection
->TryLock()) {
2560 // Could not get connection lock, unlock the endpoint lists so a thread
2561 // that has the connection lock gets a chance at the endpoint lists.
2562 connectionsMutex
.Signal();
2564 connectionsMutex
.Wait();
2571 H323Connection
* H323EndPoint::FindConnectionWithoutLocks(const PString
& token
)
2573 if (token
.IsEmpty())
2576 H323Connection
* conn_ptr
= connectionsActive
.GetAt(token
);
2577 if (conn_ptr
!= NULL
)
2581 for (i
= 0; i
< connectionsActive
.GetSize(); i
++) {
2582 H323Connection
& conn
= connectionsActive
.GetDataAt(i
);
2583 if (conn
.GetCallIdentifier().AsString() == token
)
2587 for (i
= 0; i
< connectionsActive
.GetSize(); i
++) {
2588 H323Connection
& conn
= connectionsActive
.GetDataAt(i
);
2589 if (conn
.GetConferenceIdentifier().AsString() == token
)
2597 PStringList
H323EndPoint::GetAllConnections()
2601 connectionsMutex
.Wait();
2603 for (PINDEX i
= 0; i
< connectionsActive
.GetSize(); i
++)
2604 tokens
.AppendString(connectionsActive
.GetKeyAt(i
));
2606 connectionsMutex
.Signal();
2612 BOOL
H323EndPoint::OnIncomingCall(H323Connection
& /*connection*/,
2613 const H323SignalPDU
& /*setupPDU*/,
2614 H323SignalPDU
& /*alertingPDU*/)
2619 BOOL
H323EndPoint::OnIncomingCall(H323Connection
& connection
,
2620 const H323SignalPDU
& setupPDU
,
2621 H323SignalPDU
& alertingPDU
,
2622 H323Connection::CallEndReason
& reason
)
2624 reason
= H323Connection::EndedByNoAccept
;
2625 return connection
.OnIncomingCall(setupPDU
, alertingPDU
);
2628 BOOL
H323EndPoint::OnCallTransferInitiate(H323Connection
& /*connection*/,
2629 const PString
& /*remoteParty*/)
2635 BOOL
H323EndPoint::OnCallTransferIdentify(H323Connection
& /*connection*/)
2640 void H323EndPoint::OnSendARQ(H323Connection
& /*conn*/, H225_AdmissionRequest
& /*arq*/)
2644 H323Connection::AnswerCallResponse
2645 H323EndPoint::OnAnswerCall(H323Connection
& /*connection*/,
2646 const PString
& PTRACE_PARAM(caller
),
2647 const H323SignalPDU
& /*setupPDU*/,
2648 H323SignalPDU
& /*connectPDU*/)
2650 PTRACE(2, "H225\tOnAnswerCall from \"" << caller
<< '"');
2651 return H323Connection::AnswerCallNow
;
2655 BOOL
H323EndPoint::OnAlerting(H323Connection
& /*connection*/,
2656 const H323SignalPDU
& /*alertingPDU*/,
2657 const PString
& /*username*/)
2659 PTRACE(1, "H225\tReceived alerting PDU.");
2664 BOOL
H323EndPoint::OnConnectionForwarded(H323Connection
& /*connection*/,
2665 const PString
& /*forwardParty*/,
2666 const H323SignalPDU
& /*pdu*/)
2672 BOOL
H323EndPoint::ForwardConnection(H323Connection
& connection
,
2673 const PString
& forwardParty
,
2674 const H323SignalPDU
& /*pdu*/)
2676 PString token
= connection
.GetCallToken();
2678 PStringList Addresses
;
2679 if (!ResolveCallParty(forwardParty
, Addresses
))
2682 H323Connection
* newConnection
= NULL
;
2683 for (PINDEX i
= 0; i
< Addresses
.GetSize(); i
++) {
2684 newConnection
= InternalMakeCall(PString::Empty(),
2691 if (newConnection
!= NULL
)
2696 if (newConnection
== NULL
)
2699 connection
.SetCallEndReason(H323Connection::EndedByCallForwarded
);
2700 newConnection
->Unlock();
2705 void H323EndPoint::OnConnectionEstablished(H323Connection
& /*connection*/,
2706 const PString
& /*token*/)
2711 BOOL
H323EndPoint::IsConnectionEstablished(const PString
& token
)
2713 H323Connection
* connection
= FindConnectionWithLock(token
);
2714 if (connection
== NULL
)
2717 BOOL established
= connection
->IsEstablished();
2718 connection
->Unlock();
2723 BOOL
H323EndPoint::OnOutgoingCall(H323Connection
& /*connection*/,
2724 const H323SignalPDU
& /*connectPDU*/)
2726 PTRACE(1, "H225\tReceived connect PDU.");
2731 void H323EndPoint::OnConnectionCleared(H323Connection
& /*connection*/,
2732 const PString
& /*token*/)
2737 PString
H323EndPoint::BuildConnectionToken(const H323Transport
& transport
,
2738 unsigned callReference
,
2744 token
= transport
.GetRemoteAddress();
2746 token
= "ip$localhost";
2748 token
.sprintf("/%u", callReference
);
2754 H323Connection
* H323EndPoint::OnIncomingConnection(H323Transport
* transport
,
2755 H323SignalPDU
& setupPDU
)
2757 unsigned callReference
= setupPDU
.GetQ931().GetCallReference();
2758 PString token
= BuildConnectionToken(*transport
, callReference
, TRUE
);
2760 connectionsMutex
.Wait();
2761 H323Connection
* connection
= connectionsActive
.GetAt(token
);
2762 connectionsMutex
.Signal();
2764 if (connection
== NULL
) {
2765 connection
= CreateConnection(callReference
, NULL
, transport
, &setupPDU
);
2766 if (connection
== NULL
) {
2767 PTRACE(1, "H323\tCreateConnection returned NULL");
2771 PTRACE(3, "H323\tCreated new connection: " << token
);
2773 connectionsMutex
.Wait();
2774 connectionsActive
.SetAt(token
, connection
);
2775 connectionsMutex
.Signal();
2778 connection
->AttachSignalChannel(token
, transport
, TRUE
);
2784 H323Connection
* H323EndPoint::CreateConnection(unsigned callReference
,
2786 H323Transport
* /*transport*/,
2787 H323SignalPDU
* /*setupPDU*/)
2789 return CreateConnection(callReference
, userData
);
2793 H323Connection
* H323EndPoint::CreateConnection(unsigned callReference
, void * /*userData*/)
2795 return CreateConnection(callReference
);
2798 H323Connection
* H323EndPoint::CreateConnection(unsigned callReference
)
2800 return new H323Connection(*this, callReference
);
2805 static void OnStartStopChannel(const char * startstop
, const H323Channel
& channel
)
2808 switch (channel
.GetDirection()) {
2809 case H323Channel::IsTransmitter
:
2813 case H323Channel::IsReceiver
:
2822 PTRACE(2, "H323\t" << startstop
<< "ed "
2823 << dir
<< "ing logical channel: "
2824 << channel
.GetCapability());
2829 BOOL
H323EndPoint::OnStartLogicalChannel(H323Connection
& /*connection*/,
2830 H323Channel
& PTRACE_PARAM(channel
))
2833 OnStartStopChannel("Start", channel
);
2839 void H323EndPoint::OnClosedLogicalChannel(H323Connection
& /*connection*/,
2840 const H323Channel
& PTRACE_PARAM(channel
))
2843 OnStartStopChannel("Stopp", channel
);
2848 #ifdef H323_AUDIO_CODECS
2850 BOOL
H323EndPoint::OpenAudioChannel(H323Connection
& /*connection*/,
2852 unsigned bufferSize
,
2853 H323AudioCodec
& codec
)
2855 codec
.SetSilenceDetectionMode(GetSilenceDetectionMode());
2859 int rate
= codec
.GetMediaFormat().GetTimeUnits() * 1000;
2862 PString deviceDriver
;
2864 deviceName
= GetSoundChannelRecordDevice();
2865 deviceDriver
= GetSoundChannelRecordDriver();
2867 deviceName
= GetSoundChannelPlayDevice();
2868 deviceDriver
= GetSoundChannelPlayDriver();
2871 PSoundChannel
* soundChannel
;
2872 if (!deviceDriver
.IsEmpty())
2873 soundChannel
= PSoundChannel::CreateChannel(deviceDriver
);
2875 soundChannel
= new PSoundChannel
;
2876 deviceDriver
= "default";
2879 if (soundChannel
== NULL
) {
2880 PTRACE(1, "Codec\tCould not open a sound channel for " << deviceDriver
);
2884 if (soundChannel
->Open(deviceName
, isEncoding
? PSoundChannel::Recorder
2885 : PSoundChannel::Player
,
2887 PTRACE(3, "Codec\tOpened sound channel \"" << deviceName
2888 << "\" for " << (isEncoding
? "record" : "play")
2889 << "ing at " << rate
<< " samples/second using " << soundChannelBuffers
2890 << 'x' << bufferSize
<< " byte buffers.");
2891 soundChannel
->SetBuffers(bufferSize
, soundChannelBuffers
);
2892 return codec
.AttachChannel(soundChannel
);
2895 PTRACE(1, "Codec\tCould not open " << deviceDriver
<< " sound channel \"" << deviceName
2896 << "\" for " << (isEncoding
? "record" : "play")
2897 << "ing: " << soundChannel
->GetErrorText());
2899 delete soundChannel
;
2906 #endif // H323_AUDIO_CODECS
2909 #ifndef NO_H323_VIDEO
2910 BOOL
H323EndPoint::OpenVideoChannel(H323Connection
& /*connection*/,
2911 BOOL
PTRACE_PARAM(isEncoding
),
2912 H323VideoCodec
& /*codec*/)
2914 PTRACE(1, "Codec\tCould not open video channel for "
2915 << (isEncoding
? "captur" : "display")
2916 << "ing: not yet implemented");
2919 #endif // NO_H323_VIDEO
2922 void H323EndPoint::OnRTPStatistics(const H323Connection
& /*connection*/,
2923 const RTP_Session
& /*session*/) const
2928 void H323EndPoint::OnUserInputString(H323Connection
& /*connection*/,
2929 const PString
& /*value*/)
2934 void H323EndPoint::OnUserInputTone(H323Connection
& connection
,
2936 unsigned /*duration*/,
2937 unsigned /*logicalChannel*/,
2938 unsigned /*rtpTimestamp*/)
2940 // don't pass through signalUpdate messages
2942 connection
.OnUserInputString(PString(tone
));
2945 void H323EndPoint::OnGatekeeperNATDetect(
2946 PIPSocket::Address
/* publicAddr*/,
2947 PString
& /*gkIdentifier*/,
2948 H323TransportAddress
& /*gkRouteAddress*/
2955 void H323EndPoint::OnHTTPServiceControl(unsigned /*opeartion*/,
2956 unsigned /*sessionId*/,
2957 const PString
& /*url*/)
2961 void H323EndPoint::OnCallCreditServiceControl(const PString
& amount
, BOOL mode
, const unsigned & /*durationLimit*/)
2963 OnCallCreditServiceControl(amount
, mode
);
2966 void H323EndPoint::OnCallCreditServiceControl(const PString
& /*amount*/, BOOL
/*mode*/)
2971 void H323EndPoint::OnServiceControlSession(unsigned type
,
2973 const H323ServiceControlSession
& session
,
2974 H323Connection
* connection
)
2976 session
.OnChange(type
, sessionId
, *this, connection
);
2979 H323ServiceControlSession
* H323EndPoint::CreateServiceControlSession(const H225_ServiceControlDescriptor
& contents
)
2981 switch (contents
.GetTag()) {
2982 case H225_ServiceControlDescriptor::e_url
:
2983 return new H323HTTPServiceControl(contents
);
2985 case H225_ServiceControlDescriptor::e_callCreditServiceControl
:
2986 return new H323CallCreditServiceControl(contents
);
2994 BOOL
H323EndPoint::OnConferenceInvite(BOOL
/*sending*/,
2995 const H323Connection
* /*connection*/,
2996 const H323SignalPDU
& /*setupPDU */)
3001 BOOL
H323EndPoint::OnSendCallIndependentSupplementaryService(const H323Connection
* /*connection*/,
3002 H323SignalPDU
& /* pdu */)
3007 BOOL
H323EndPoint::OnReceiveCallIndependentSupplementaryService(const H323Connection
* /*connection*/,
3008 const H323SignalPDU
& /* pdu */)
3013 BOOL
H323EndPoint::OnNegotiateConferenceCapabilities(const H323SignalPDU
& /* setupPDU */)
3019 OpalT120Protocol
* H323EndPoint::CreateT120ProtocolHandler(const H323Connection
&) const
3027 OpalT38Protocol
* H323EndPoint::CreateT38ProtocolHandler(const H323Connection
&) const
3035 OpalH224Handler
* H323EndPoint::CreateH224ProtocolHandler(H323Connection
& connection
,
3036 unsigned sessionID
) const
3038 return new OpalH224Handler(connection
, sessionID
);
3042 OpalH281Handler
* H323EndPoint::CreateH281ProtocolHandler(OpalH224Handler
& h224Handler
) const
3044 return new OpalH281Handler(h224Handler
);
3049 void H323EndPoint::SetLocalUserName(const PString
& name
)
3051 PAssert(!name
, "Must have non-empty string in AliasAddress!");
3055 localAliasNames
.RemoveAll();
3056 localAliasNames
.AppendString(name
);
3060 BOOL
H323EndPoint::AddAliasName(const PString
& name
)
3062 PAssert(!name
, "Must have non-empty string in AliasAddress!");
3064 if (localAliasNames
.GetValuesIndex(name
) != P_MAX_INDEX
)
3067 localAliasNames
.AppendString(name
);
3072 BOOL
H323EndPoint::RemoveAliasName(const PString
& name
)
3074 PINDEX pos
= localAliasNames
.GetValuesIndex(name
);
3075 if (pos
== P_MAX_INDEX
)
3078 PAssert(localAliasNames
.GetSize() > 1, "Must have at least one AliasAddress!");
3079 if (localAliasNames
.GetSize() < 2)
3082 localAliasNames
.RemoveAt(pos
);
3086 #ifdef H323_AUDIO_CODECS
3090 BOOL
H323EndPoint::SetSoundChannelPlayDevice(const PString
& name
)
3092 if (PSoundChannel::GetDeviceNames(PSoundChannel::Player
).GetValuesIndex(name
) == P_MAX_INDEX
)
3095 soundChannelPlayDevice
= name
;
3100 BOOL
H323EndPoint::SetSoundChannelRecordDevice(const PString
& name
)
3102 if (PSoundChannel::GetDeviceNames(PSoundChannel::Recorder
).GetValuesIndex(name
) == P_MAX_INDEX
)
3105 soundChannelRecordDevice
= name
;
3110 BOOL
H323EndPoint::SetSoundChannelPlayDriver(const PString
& name
)
3112 PPluginManager
& pluginMgr
= PPluginManager::GetPluginManager();
3113 PStringList list
= pluginMgr
.GetPluginsProviding("PSoundChannel");
3114 if (list
.GetValuesIndex(name
) == P_MAX_INDEX
)
3117 soundChannelPlayDriver
= name
;
3118 soundChannelPlayDevice
.MakeEmpty();
3119 list
= PSoundChannel::GetDeviceNames(name
, PSoundChannel::Player
);
3120 if (list
.GetSize() == 0)
3123 soundChannelPlayDevice
= list
[0];
3128 BOOL
H323EndPoint::SetSoundChannelRecordDriver(const PString
& name
)
3130 PPluginManager
& pluginMgr
= PPluginManager::GetPluginManager();
3131 PStringList list
= pluginMgr
.GetPluginsProviding("PSoundChannel");
3132 if (list
.GetValuesIndex(name
) == P_MAX_INDEX
)
3135 soundChannelRecordDriver
= name
;
3136 list
= PSoundChannel::GetDeviceNames(name
, PSoundChannel::Recorder
);
3137 if (list
.GetSize() == 0)
3140 soundChannelRecordDevice
= list
[0];
3145 void H323EndPoint::SetSoundChannelBufferDepth(unsigned depth
)
3147 PAssert(depth
> 1, PInvalidParameter
);
3148 soundChannelBuffers
= depth
;
3153 #endif // H323_AUDIO_CODECS
3156 BOOL
H323EndPoint::IsTerminal() const
3158 switch (terminalType
) {
3159 case e_TerminalOnly
:
3160 case e_TerminalAndMC
:
3169 BOOL
H323EndPoint::IsGateway() const
3171 switch (terminalType
) {
3172 case e_GatewayOnly
:
3173 case e_GatewayAndMC
:
3174 case e_GatewayAndMCWithDataMP
:
3175 case e_GatewayAndMCWithAudioMP
:
3176 case e_GatewayAndMCWithAVMP
:
3185 BOOL
H323EndPoint::IsGatekeeper() const
3187 switch (terminalType
) {
3188 case e_GatekeeperOnly
:
3189 case e_GatekeeperWithDataMP
:
3190 case e_GatekeeperWithAudioMP
:
3191 case e_GatekeeperWithAVMP
:
3200 BOOL
H323EndPoint::IsMCU() const
3202 switch (terminalType
) {
3204 case e_MCUWithDataMP
:
3205 case e_MCUWithAudioMP
:
3206 case e_MCUWithAVMP
:
3214 #ifdef H323_AUDIO_CODECS
3216 void H323EndPoint::SetAudioJitterDelay(unsigned minDelay
, unsigned maxDelay
)
3218 if (minDelay
== 0 && maxDelay
== 0) {
3219 // Disable jitter buffer
3220 minAudioJitterDelay
= 0;
3221 maxAudioJitterDelay
= 0;
3225 PAssert(minDelay
<= 10000 && maxDelay
<= 10000, PInvalidParameter
);
3229 minAudioJitterDelay
= minDelay
;
3231 if (maxDelay
< minDelay
)
3232 maxDelay
= minDelay
;
3233 maxAudioJitterDelay
= maxDelay
;
3240 PSTUNClient
* H323EndPoint::GetSTUN(const PIPSocket::Address
& ip
) const
3242 if (ip
.IsValid() && IsLocalAddress(ip
))
3248 PNatMethod
* H323EndPoint::GetPreferedNatMethod(const PIPSocket::Address
& ip
)
3251 if (ip
.IsValid() && IsLocalAddress(ip
))
3255 PNatMethod
* meth
= NULL
;
3256 PNatList list
= natMethods
.GetNATList();
3258 if (list
.GetSize() > 0) {
3259 for (PINDEX i
=0; i
< list
.GetSize(); i
++) {
3260 PTRACE(6, "H323\tNat Method " << i
<< " " << list
[i
].GetNatMethodName() << " Ready: " << list
[i
].IsAvailable());
3261 if (list
[i
].IsAvailable()) {
3267 PTRACE(6, "H323\tNo NAT Methods!");
3271 return natMethods
.GetMethod();
3276 PNatStrategy
H323EndPoint::GetNatMethods()
3281 void H323EndPoint::SetSTUNServer(const PString
& server
)
3285 if (server
.IsEmpty())
3288 stun
= new PSTUNClient(server
,
3289 GetUDPPortBase(), GetUDPPortMax(),
3290 GetRtpIpPortBase(), GetRtpIpPortMax());
3292 natMethods
.AddMethod(stun
);
3294 PTRACE(2, "H323\tSTUN server \"" << server
<< "\" replies " << stun
->GetNatTypeName());
3300 void H323EndPoint::InternalTranslateTCPAddress(PIPSocket::Address
& localAddr
, const PIPSocket::Address
& remoteAddr
)
3303 // if using STUN server, then translate internal local address to external if required
3304 PIPSocket::Address addr
;
3307 (stun
->IsSupportingRTP() == PSTUNClient::RTPOK
) ||
3308 (stun
->IsSupportingRTP() == PSTUNClient::RTPIfSendMedia
)
3310 localAddr
.IsRFC1918() &&
3311 !remoteAddr
.IsRFC1918() &&
3312 stun
->GetExternalAddress(addr
)
3319 TranslateTCPAddress(localAddr
, remoteAddr
);
3322 BOOL
H323EndPoint::IsLocalAddress(const PIPSocket::Address
& ip
) const
3324 /* Check if the remote address is a private IP, broadcast, or us */
3325 return ip
.IsRFC1918() || ip
.IsBroadcast() || PIPSocket::IsLocalHost(ip
);
3329 void H323EndPoint::PortInfo::Set(unsigned newBase
,
3343 else if (newBase
> 65500)
3346 if (newMax
<= newBase
)
3347 newMax
= newBase
+ range
;
3354 current
= base
= (WORD
)newBase
;
3361 WORD
H323EndPoint::PortInfo::GetNext(unsigned increment
)
3363 PWaitAndSignal
m(mutex
);
3365 if (current
< base
|| current
> (max
-increment
))
3372 current
= (WORD
)(current
+ increment
);
3377 void H323EndPoint::SetTCPPorts(unsigned tcpBase
, unsigned tcpMax
)
3379 tcpPorts
.Set(tcpBase
, tcpMax
, 99, 0);
3383 WORD
H323EndPoint::GetNextTCPPort()
3385 return tcpPorts
.GetNext(1);
3389 void H323EndPoint::SetUDPPorts(unsigned udpBase
, unsigned udpMax
)
3391 udpPorts
.Set(udpBase
, udpMax
, 199, 0);
3394 natMethods
.SetPortRanges(GetUDPPortBase(), GetUDPPortMax(), GetRtpIpPortBase(), GetRtpIpPortMax());
3399 WORD
H323EndPoint::GetNextUDPPort()
3401 return udpPorts
.GetNext(1);
3405 void H323EndPoint::SetRtpIpPorts(unsigned rtpIpBase
, unsigned rtpIpMax
)
3407 rtpIpPorts
.Set((rtpIpBase
+1)&0xfffe, rtpIpMax
&0xfffe, 999, 5000);
3410 natMethods
.SetPortRanges(GetUDPPortBase(), GetUDPPortMax(), GetRtpIpPortBase(), GetRtpIpPortMax());
3415 WORD
H323EndPoint::GetRtpIpPortPair()
3417 return rtpIpPorts
.GetNext(2);
3420 const PTimeInterval
& H323EndPoint::GetNoMediaTimeout() const
3422 PWaitAndSignal
m(noMediaMutex
);
3424 return noMediaTimeout
;
3427 BOOL
H323EndPoint::SetNoMediaTimeout(PTimeInterval newInterval
)
3429 PWaitAndSignal
m(noMediaMutex
);
3431 if (newInterval
< 0)
3434 noMediaTimeout
= newInterval
;
3438 BOOL
H323EndPoint::OnSendFeatureSet(unsigned pdu
, H225_FeatureSet
& feats
)
3441 return features
.SendFeature(pdu
,feats
);
3447 void H323EndPoint::OnReceiveFeatureSet(unsigned pdu
, const H225_FeatureSet
& feats
)
3450 features
.ReceiveFeature(pdu
,feats
);
3454 void H323EndPoint::LoadBaseFeatureSet()
3458 features
.AttachEndPoint(this);
3459 features
.LoadFeatureSet(H460_Feature::FeatureBase
);
3464 BOOL
H323EndPoint::HandleUnsolicitedInformation(const H323SignalPDU
& )
3469 #ifdef H323_RTP_AGGREGATE
3470 PHandleAggregator
* H323EndPoint::GetRTPAggregator()
3472 PWaitAndSignal
m(connectionsMutex
);
3473 if (rtpAggregationSize
== 0)
3476 if (rtpAggregator
== NULL
)
3477 rtpAggregator
= new PHandleAggregator(rtpAggregationSize
);
3479 return rtpAggregator
;
3483 #ifdef H323_SIGNAL_AGGREGATE
3484 PHandleAggregator
* H323EndPoint::GetSignallingAggregator()
3486 PWaitAndSignal
m(connectionsMutex
);
3487 if (signallingAggregationSize
== 0)
3490 if (signallingAggregator
== NULL
)
3491 signallingAggregator
= new PHandleAggregator(signallingAggregationSize
);
3493 return signallingAggregator
;
3497 /////////////////////////////////////////////////////////////////////////////
3499 #ifdef H323_TRANSNEXUS_OSP
3501 void H323EndPoint::SetOSPProvider(OpalOSP::Provider
* provider
)
3503 if (ospProvider
!= NULL
)
3506 ospProvider
= provider
;
3509 int H323EndPoint::SetOSPProvider(const PString
& server
, const PDirectory
& ospDir
)
3511 OpalOSP::Provider
* newProvider
= new OpalOSP::Provider();
3513 int result
= newProvider
->Open(server
, ospDir
);
3514 PTRACE_IF(1, result
!= 0, "H323\tCannot create OSP provider - result = " << result
);
3519 SetOSPProvider(newProvider
);
3526 /////////////////////////////////////////////////////////////////////////////