Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / h323ep.cxx
blobf77792ba161cf983b6db485a3814b8b4fa9573bc
1 /*
2 * h323ep.cxx
4 * H.323 protocol handler
6 * Open H323 Library
8 * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions of this code were written with the assisance of funding from
25 * Vovida Networks, Inc. http://www.vovida.com.
27 * Contributor(s): ______________________________________.
29 * $Log$
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
41 * More H460 support
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
207 * macros only.
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
246 * interoperability.
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.
789 #include <ptlib.h>
790 #include <ptlib/sound.h>
792 #ifdef __GNUC__
793 #pragma implementation "h323ep.h"
794 #endif
796 #include "openh323buildopts.h"
798 #include "h323ep.h"
799 #include "h323pdu.h"
801 #ifdef H323_H450
802 #include "h450pdu.h"
803 #endif
805 #include "gkclient.h"
807 #ifdef H323_T38
808 #include "t38proto.h"
809 #endif
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>
825 #endif
827 #ifndef IPTOS_PREC_CRITIC_ECP
828 #define IPTOS_PREC_CRITIC_ECP (5 << 5)
829 #endif
831 #ifndef IPTOS_LOWDELAY
832 #define IPTOS_LOWDELAY 0x10
833 #endif
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 //////////////////////////////////////////////////////////////////////////////////////
845 namespace OpalOSP {
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)
857 public:
858 H225CallThread(H323EndPoint & endpoint,
859 H323Connection & connection,
860 H323Transport & transport,
861 const PString & alias,
862 const H323TransportAddress & address);
864 protected:
865 void Main();
867 H323Connection & connection;
868 H323Transport & transport;
869 PString alias;
870 H323TransportAddress address;
871 #ifdef H323_SIGNAL_AGGREGATE
872 BOOL useAggregator;
873 #endif
877 class H323ConnectionsCleaner : public PThread
879 PCLASSINFO(H323ConnectionsCleaner, PThread)
881 public:
882 H323ConnectionsCleaner(H323EndPoint & endpoint);
883 ~H323ConnectionsCleaner();
885 void Signal() { wakeupFlag.Signal(); }
887 protected:
888 void Main();
890 H323EndPoint & endpoint;
891 BOOL stopFlag;
892 PSyncPoint wakeupFlag;
896 #define new PNEW
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()
923 return BUILD_NUMBER;
928 /////////////////////////////////////////////////////////////////////////////
930 H225CallThread::H225CallThread(H323EndPoint & endpoint,
931 H323Connection & c,
932 H323Transport & t,
933 const PString & a,
934 const H323TransportAddress & addr)
935 : PThread(endpoint.GetSignallingThreadStackSize(),
936 NoAutoDeleteThread,
937 NormalPriority,
938 "H225 Caller:%0x"),
939 connection(c),
940 transport(t),
941 alias(a),
942 address(addr)
944 #ifdef H323_SIGNAL_AGGREGATE
945 useAggregator = endpoint.GetSignallingAggregator() != NULL;
946 if (!useAggregator)
947 #endif
949 transport.AttachThread(this);
952 Resume();
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)
965 connection.Unlock();
967 // Check if had an error, clear call if so
968 if (reason != H323Connection::NumCallEndReasons)
969 connection.ClearCall(reason);
970 else {
971 #ifdef H323_SIGNAL_AGGREGATE
972 if (useAggregator) {
973 connection.AggregateSignalChannel(&transport);
974 SetAutoDelete(AutoDeleteThread);
975 return;
977 #endif
978 connection.HandleSignallingChannel();
984 /////////////////////////////////////////////////////////////////////////////
986 H323ConnectionsCleaner::H323ConnectionsCleaner(H323EndPoint & ep)
987 : PThread(ep.GetCleanerThreadStackSize(),
988 NoAutoDeleteThread,
989 NormalPriority,
990 "H323 Cleaner"),
991 endpoint(ep)
993 Resume();
994 stopFlag = FALSE;
998 H323ConnectionsCleaner::~H323ConnectionsCleaner()
1000 stopFlag = TRUE;
1001 wakeupFlag.Signal();
1002 PAssert(WaitForTermination(10000), "Cleaner thread did not terminate");
1006 void H323ConnectionsCleaner::Main()
1008 PTRACE(3, "H323\tStarted cleaner thread");
1010 for (;;) {
1011 wakeupFlag.Wait();
1012 if (stopFlag)
1013 break;
1015 endpoint.CleanUpConnections();
1018 PTRACE(3, "H323\tStopped cleaner thread");
1022 /////////////////////////////////////////////////////////////////////////////
1024 H323EndPoint::H323EndPoint()
1026 #ifdef P_AUDIO
1027 soundChannelPlayDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Player)),
1028 soundChannelRecordDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Recorder)),
1029 #endif
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
1044 #ifdef H323_H450
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)
1057 #endif
1060 PString username = PProcess::Current().GetUserName();
1061 if (username.IsEmpty())
1062 username = PProcess::Current().GetName() & "User";
1063 localAliasNames.AppendString(username);
1065 #ifdef H323_VIDEO
1066 autoStartReceiveVideo = autoStartTransmitVideo = TRUE;
1067 #endif
1069 #ifdef H323_T38
1070 autoStartReceiveFax = autoStartTransmitFax = FALSE;
1071 #endif
1073 #ifdef H323_AUDIO_CODECS
1074 minAudioJitterDelay = 50; // milliseconds
1075 maxAudioJitterDelay = 250; // milliseconds
1076 #endif
1078 autoCallForward = TRUE;
1079 disableFastStart = FALSE;
1080 disableH245Tunneling = FALSE;
1081 disableH245inSetup = FALSE;
1082 disableDetectInBandDTMF = FALSE;
1083 canDisplayAmountString = FALSE;
1084 canEnforceDurationLimit = TRUE;
1086 #ifdef H323_H450
1087 callIntrusionProtectionLevel = 3; //H45011_CIProtectionLevel::e_fullProtection;
1088 #endif
1090 #ifdef H323_AUDIO_CODECS
1091 defaultSilenceDetection = H323AudioCodec::AdaptiveSilenceDetection;
1092 #endif
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;
1111 #ifdef P_STUN
1112 stun = NULL;
1113 #endif
1115 #ifdef _WIN32
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;
1121 # endif
1123 rtpIpTypeofService = IPTOS_PREC_CRITIC_ECP|IPTOS_LOWDELAY;
1125 #else
1127 # ifdef H323_AUDIO_CODECS
1128 // Should only need double buffering for Unix platforms
1129 soundChannelBuffers = 2;
1130 # endif
1132 // Don't use IPTOS_PREC_CRITIC_ECP on Unix platforms as then need to be root
1133 rtpIpTypeofService = IPTOS_LOWDELAY;
1135 #endif
1136 tcpIpTypeofService = IPTOS_LOWDELAY;
1138 masterSlaveDeterminationRetries = 10;
1139 gatekeeperRequestRetries = 2;
1140 rasRequestRetries = 2;
1141 sendGRQ = TRUE;
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;
1154 #endif
1156 #ifdef H323_RTP_AGGREGATE
1157 rtpAggregationSize = 10;
1158 rtpAggregator = NULL;
1159 #endif
1161 channelThreadPriority = PThread::HighestPriority;
1163 gatekeeper = NULL;
1165 connectionsActive.DisallowDeleteObjects();
1167 #ifdef H323_H450
1168 secondaryConnectionsActive.DisallowDeleteObjects();
1169 #endif
1171 connectionsCleaner = new H323ConnectionsCleaner(*this);
1173 srand((unsigned)time(NULL)+clock());
1175 #ifdef H323_TRANSNEXUS_OSP
1176 ospProvider = NULL;
1177 #endif
1179 #ifndef DISABLE_CALLAUTH
1180 SetEPSecurityPolicy(SecNone);
1181 SetEPCredentials(PString(),PString());
1182 isSecureCall = FALSE;
1183 #endif
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);
1194 #endif
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;
1205 #endif
1206 #ifdef H323_SIGNAL_AGGREGATE
1207 if (signallingAggregator != NULL) {
1208 delete signallingAggregator;
1209 signallingAggregator = NULL;
1211 #endif
1213 #endif
1215 // And shut down the gatekeeper (if there was one)
1216 RemoveGatekeeper();
1218 // Shut down the listeners as soon as possible to avoid race conditions
1219 listeners.RemoveAll();
1221 // Clear any pending calls on this endpoint
1222 ClearAllCalls();
1224 // Shut down the cleaner thread
1225 delete connectionsCleaner;
1227 // Clean up any connections that the cleaner thread missed
1228 CleanUpConnections();
1230 #ifdef P_STUN
1231 // delete stun;
1232 #endif
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);
1247 break;
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);
1254 break;
1255 case e_GatekeeperOnly :
1256 case e_GatekeeperWithDataMP :
1257 case e_GatekeeperWithAudioMP :
1258 case e_GatekeeperWithAVMP :
1259 info.IncludeOptionalField(H225_EndpointType::e_gatekeeper);
1260 break;
1261 case e_MCUOnly :
1262 case e_MCUWithDataMP :
1263 case e_MCUWithAudioMP :
1264 case e_MCUWithAVMP :
1265 info.IncludeOptionalField(H225_EndpointType::e_mcu);
1266 info.m_mc = TRUE;
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) {
1358 BOOL same = TRUE;
1360 if (!address)
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);
1369 if (same) {
1370 PTRACE(2, "H323\tUsing existing gatekeeper " << *gatekeeper);
1371 return TRUE;
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);
1387 else
1388 return LocateGatekeeper(identifier, transport);
1390 else {
1391 if (identifier.IsEmpty())
1392 return SetGatekeeper(address, transport);
1393 else
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);
1440 return gk;
1444 BOOL H323EndPoint::InternalRegisterGatekeeper(H323Gatekeeper * gk, BOOL discovered)
1446 if (discovered) {
1447 if (gk->RegistrationRequest()) {
1448 gatekeeper = gk;
1449 return TRUE;
1452 // RRQ was rejected continue trying
1453 gatekeeper = gk;
1455 else // Only stop listening if the GRQ was rejected
1456 delete gk;
1458 return FALSE;
1462 H323Gatekeeper * H323EndPoint::CreateGatekeeper(H323Transport * transport)
1464 return new H323Gatekeeper(*this, transport);
1468 BOOL H323EndPoint::IsRegisteredWithGatekeeper() const
1470 if (gatekeeper == NULL)
1471 return FALSE;
1473 return gatekeeper->IsRegistered();
1477 BOOL H323EndPoint::RemoveGatekeeper(int reason)
1479 BOOL ok = TRUE;
1481 if (gatekeeper == NULL)
1482 return ok;
1484 ClearAllCalls();
1486 if (gatekeeper->IsRegistered()) // If we are registered send a URQ
1487 ok = gatekeeper->UnregistrationRequest(reason);
1489 delete gatekeeper;
1490 gatekeeper = NULL;
1492 return ok;
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;
1545 PString username;
1546 PString password;
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,
1570 PString & username)
1572 if (EPSecurityPassword.IsEmpty())
1573 return FALSE;
1574 else
1575 password = EPSecurityPassword;
1577 if (EPSecurityUserName.IsEmpty())
1578 username = GetLocalUserName();
1579 else
1580 username = EPSecurityUserName;
1582 return TRUE;
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()
1603 return EPAuthList;
1606 BOOL H323EndPoint::OnCallAuthentication(const PString & username,
1607 PString & password)
1609 if (EPAuthList.HasUserName(username)) {
1610 EPAuthList.LoadPassword(username, password);
1611 return TRUE;
1614 return FALSE;
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);
1624 #endif
1626 BOOL H323EndPoint::StartListeners(const H323TransportAddressArray & ifaces)
1628 if (ifaces.IsEmpty())
1629 return StartListener("*");
1631 PINDEX i;
1633 for (i = 0; i < listeners.GetSize(); i++) {
1634 BOOL remove = TRUE;
1635 for (PINDEX j = 0; j < ifaces.GetSize(); j++) {
1636 if (listeners[i].GetTransportAddress().IsEquivalent(ifaces[j])) {
1637 remove = FALSE;
1638 break;
1641 if (remove) {
1642 PTRACE(3, "H323\tRemoving listener " << listeners[i]);
1643 listeners.RemoveAt(i--);
1647 for (i = 0; i < ifaces.GetSize(); i++) {
1648 if (!ifaces[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);
1662 else
1663 listener = iface.CreateListener(*this);
1665 if (H323EndPoint::StartListener(listener))
1666 return TRUE;
1668 PTRACE(1, "H323\tCould not start listener: " << iface);
1669 delete listener;
1670 return FALSE;
1674 BOOL H323EndPoint::StartListener(H323Listener * listener)
1676 if (listener == NULL)
1677 return FALSE;
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);
1682 delete listener;
1683 return TRUE;
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
1692 return FALSE;
1695 PTRACE(3, "H323\tStarted listener " << *listener);
1696 listeners.Append(listener);
1697 listener->Resume();
1698 return TRUE;
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();
1711 return TRUE;
1715 H323TransportAddressArray H323EndPoint::GetInterfaceAddresses(BOOL excludeLocalHost,
1716 H323Transport * associatedTransport)
1718 return H323GetInterfaceAddresses(listeners, excludeLocalHost, associatedTransport);
1721 H323Connection * H323EndPoint::MakeCall(const PString & remoteParty,
1722 PString & token,
1723 void * userData)
1725 return MakeCall(remoteParty, NULL, token, userData);
1729 H323Connection * H323EndPoint::MakeCall(const PString & remoteParty,
1730 H323Transport * transport,
1731 PString & token,
1732 void * userData)
1734 token = PString::Empty();
1736 PStringList Addresses;
1737 if (!ResolveCallParty(remoteParty, Addresses))
1738 return NULL;
1740 H323Connection * connection = NULL;
1741 for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
1742 connection = InternalMakeCall(PString::Empty(),
1743 PString::Empty(),
1744 UINT_MAX,
1745 Addresses[i],
1746 transport,
1747 token,
1748 userData);
1749 if (connection != NULL) {
1750 connection->Unlock();
1751 break;
1755 return connection;
1759 H323Connection * H323EndPoint::MakeCallLocked(const PString & remoteParty,
1760 PString & token,
1761 void * userData,
1762 H323Transport * transport)
1764 token = PString::Empty();
1766 PStringList Addresses;
1767 if (!ResolveCallParty(remoteParty, Addresses))
1768 return NULL;
1770 H323Connection * connection = NULL;
1771 for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
1772 connection = InternalMakeCall(PString::Empty(),
1773 PString::Empty(),
1774 UINT_MAX,
1775 Addresses[i],
1776 transport,
1777 token,
1778 userData);
1779 if (connection != NULL)
1780 break;
1783 return connection;
1787 #ifdef H323_TRANSNEXUS_OSP
1789 static BOOL GetListenerInterfaceAddress(H323Listener & listener, H323TransportAddress & taddr)
1791 taddr = listener.GetTransportAddress();
1792 PIPSocket::Address addr;
1793 WORD port;
1794 if (!taddr.GetIpAndPort(addr, port))
1795 return FALSE;
1797 if (addr.IsValid())
1798 return TRUE;
1800 if (!PIPSocket::GetNetworkInterface(addr))
1801 return FALSE;
1803 taddr = H323TransportAddress(addr, port);
1804 return TRUE;
1807 #endif
1809 H323Connection * H323EndPoint::InternalMakeCall(const PString & trasferFromToken,
1810 const PString & callIdentity,
1811 unsigned capabilityLevel,
1812 const PString & remoteParty,
1813 H323Transport * transport,
1814 PString & newToken,
1815 void * userData)
1817 PTRACE(2, "H323\tMaking call to: " << remoteParty);
1819 PString alias;
1820 H323TransportAddress address;
1821 if (!ParsePartyName(remoteParty, alias, address)) {
1822 PTRACE(2, "H323\tCould not parse \"" << remoteParty << '"');
1823 return NULL;
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");
1838 return NULL;
1840 transport = taddr.CreateTransport(*this);
1842 #endif
1844 // assume address is an IP address/hostname
1845 else
1846 transport = address.CreateTransport(*this);
1848 if (transport == NULL) {
1849 PTRACE(1, "H323\tInvalid transport in \"" << remoteParty << '"');
1850 return NULL;
1854 H323Connection * connection;
1856 connectionsMutex.Wait();
1858 unsigned lastReference;
1859 if (newToken.IsEmpty()) {
1860 do {
1861 lastReference = Q931::GenerateCallReference();
1862 newToken = BuildConnectionToken(*transport, lastReference, FALSE);
1863 } while (connectionsActive.Contains(newToken));
1865 else {
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;
1871 do {
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();
1885 return NULL;
1888 connection->Lock();
1890 connectionsMutex.Wait();
1891 connectionsActive.SetAt(newToken, connection);
1893 connectionsMutex.Signal();
1895 connection->AttachSignalChannel(newToken, transport, FALSE);
1897 #ifdef H323_H450
1898 if (capabilityLevel == UINT_MAX)
1899 connection->HandleTransferCall(trasferFromToken, callIdentity);
1900 else {
1901 connection->HandleIntrudeCall(trasferFromToken, callIdentity);
1902 connection->IntrudeCall(capabilityLevel);
1904 #endif
1906 PTRACE(3, "H323\tCreated new connection: " << newToken);
1908 new H225CallThread(*this, *connection, *transport, alias, address);
1909 return connection;
1912 #if P_DNS
1914 struct LookupRecord {
1915 enum {
1916 CallDirect,
1919 int type;
1920 PIPSocket::Address addr;
1921 WORD port;
1924 static BOOL FindSRVRecords(std::vector<LookupRecord> & recs,
1925 const PString & domain,
1926 int type,
1927 const PString & srv)
1929 PDNS::SRVRecordList srvRecords;
1930 PString srvLookupStr = srv + domain;
1931 BOOL found = PDNS::GetRecords(srvLookupStr, srvRecords);
1932 if (found) {
1933 PDNS::SRVRecord * recPtr = srvRecords.GetFirst();
1934 while (recPtr != NULL) {
1935 LookupRecord rec;
1936 rec.addr = recPtr->hostAddress;
1937 rec.port = recPtr->port;
1938 rec.type = type;
1939 recs.push_back(rec);
1940 recPtr = srvRecords.GetNext();
1941 PTRACE(4, "H323\tFound " << rec.addr << ":" << rec.port << " with SRV " << srv << " using domain " << domain);
1944 return found;
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)) {
1956 LookupRecord rec;
1957 rec.addr = addr;
1958 rec.port = port;
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) {
1969 LookupRecord rec;
1970 rec.addr = recPtr->hostAddress;
1971 rec.port = 1719;
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;
1982 #endif
1984 BOOL H323EndPoint::ResolveCallParty(const PString & _remoteParty, PStringList & addresses)
1986 PString remoteParty = _remoteParty;
1988 #if P_DNS
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);
1999 PINDEX i;
2000 for (i = 0; i < number.GetLength(); ++i)
2001 if (!isdigit(number[i]))
2002 break;
2003 if (i >= number.GetLength()) {
2004 PString str;
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);
2009 } else {
2010 remoteParty = str;
2012 PTRACE(4, "H323\tENUM converted remote party " << _remoteParty << " to " << remoteParty);
2013 } else {
2014 PTRACE(4, "H323\tENUM Cannot resolve remote party " << _remoteParty);
2015 addresses = PStringList(remoteParty);
2016 return FALSE;
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;
2026 PStringList str;
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]);
2032 } else {
2033 PTRACE(4, "H323\tDNS SRV Cannot resolve remote party " << remoteParty);
2034 addresses = PStringList(remoteParty);
2036 } else {
2037 addresses = PStringList(remoteParty);
2039 return TRUE;
2041 #endif
2042 addresses = PStringList(remoteParty);
2043 return TRUE;
2046 BOOL H323EndPoint::ParsePartyName(const PString & _remoteParty,
2047 PString & alias,
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)) {
2058 if (
2059 (gatekeeper == NULL)
2060 #ifdef H323_TRANSNEXUS_OSP
2061 && (ospProvider == NULL)
2062 #endif
2064 url.Parse("h323:@" + remoteParty);
2065 else
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;
2073 } else {
2074 alias = url.GetUserName();
2075 hostOnly = url.GetHostName();
2077 address = hostOnly;
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 << '"');
2085 return FALSE;
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") {
2096 #if P_LDAP
2097 PString server = url.GetHostName();
2098 if (server.IsEmpty())
2099 server = ilsServer;
2100 if (server.IsEmpty())
2101 return FALSE;
2103 PILSSession ils;
2104 if (!ils.Open(server, url.GetPort())) {
2105 PTRACE(1, "H323\tCould not open ILS server at \"" << server
2106 << "\" - " << ils.GetErrorText());
2107 return FALSE;
2110 PILSSession::RTPerson person;
2111 if (!ils.SearchPerson(alias, person)) {
2112 PTRACE(1, "H323\tCould not find "
2113 << server << '/' << alias << ": " << ils.GetErrorText());
2114 return FALSE;
2117 if (!person.sipAddress.IsValid()) {
2118 PTRACE(1, "H323\tILS user " << server << '/' << alias
2119 << " does not have a valid IP address");
2120 return FALSE;
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]);
2130 break;
2134 alias = PString::Empty(); // No alias for ILS lookup, only host
2135 return TRUE;
2136 #else
2137 return FALSE;
2138 #endif
2141 if (url.GetParamVars().Contains("gateway"))
2142 gatewaySpecified = TRUE;
2145 else if (url.GetScheme() == "h323") {
2146 if (type == "gw")
2147 gatewaySpecified = TRUE;
2148 else if (type == "gk")
2149 gatekeeperSpecified = TRUE;
2150 else if (!type) {
2151 PTRACE(1, "H323\tUnsupported host type \"" << type << "\" in h323 URL");
2152 return FALSE;
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!");
2160 return FALSE;
2163 if (address.IsEmpty()) {
2164 PTRACE(1, "H323\tAttempt to use explict gatekeeper without address!");
2165 return FALSE;
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);
2174 if (ok) {
2175 ok = gk->LocationRequest(alias, address);
2176 if (ok) {
2177 PTRACE(3, "H323\tLocation Request of \"" << alias << "\" on gk " << gkAddr << " found " << address);
2179 else {
2180 PTRACE(1, "H323\tLocation Request failed for \"" << alias << "\" on gk " << gkAddr);
2183 else {
2184 PTRACE(1, "H323\tLocation Request discovery failed for gk " << gkAddr);
2187 delete gk;
2189 return ok;
2192 // User explicitly said to use a gw, or we do not have a gk to do look up
2193 if (
2194 #ifdef H323_TRANSNEXUS_OSP
2195 ((ospProvider == NULL) && (gatekeeper == NULL))
2196 #else
2197 (gatekeeper == NULL)
2198 #endif
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()) {
2203 address = alias;
2204 alias = PString::Empty();
2205 return TRUE;
2208 #if P_DNS
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;
2216 switch (rec.type) {
2217 /* case LookupRecord::CallDirect:
2218 address = H323TransportAddress(rec.addr, rec.port);
2219 PTRACE(3, "H323\tParty name \"" << url << "\" mapped to \"" << alias << "@" << address);
2220 return TRUE;
2221 break; */
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);
2228 if (ok)
2229 ok = gk->LocationRequest(alias, newAddr);
2230 delete gk;
2231 if (ok) {
2232 address = newAddr;
2233 PTRACE(3, "H323\tLocation Request of \"" << alias << "\" on gk " << gkAddr << " found " << address);
2234 return TRUE;
2237 break;
2239 default:
2240 break;
2245 #endif // P_DNS
2248 if (!address)
2249 return TRUE;
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();
2259 address = test;
2263 return TRUE;
2266 #ifdef H323_H450
2268 H323Connection * H323EndPoint::SetupTransfer(const PString & oldToken,
2269 const PString & callIdentity,
2270 const PString & remoteParty,
2271 PString & newToken,
2272 void * userData)
2274 newToken = PString::Empty();
2276 PStringList Addresses;
2277 if (!ResolveCallParty(remoteParty, Addresses))
2278 return NULL;
2280 H323Connection * connection = NULL;
2281 for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
2282 connection = InternalMakeCall(oldToken,
2283 callIdentity,
2284 UINT_MAX,
2285 Addresses[i],
2286 NULL,
2287 newToken,
2288 userData);
2289 if (connection != NULL) {
2290 connection->Unlock();
2291 break;
2295 return connection;
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,
2333 PString & token,
2334 unsigned capabilityLevel,
2335 void * userData)
2337 return IntrudeCall(remoteParty, NULL, token, capabilityLevel, userData);
2341 H323Connection * H323EndPoint::IntrudeCall(const PString & remoteParty,
2342 H323Transport * transport,
2343 PString & token,
2344 unsigned capabilityLevel,
2345 void * userData)
2347 token = PString::Empty();
2349 PStringList Addresses;
2350 if (!ResolveCallParty(remoteParty, Addresses))
2351 return NULL;
2353 H323Connection * connection = NULL;
2354 for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
2355 connection = InternalMakeCall(PString::Empty(),
2356 PString::Empty(),
2357 capabilityLevel,
2358 Addresses[i],
2359 transport,
2360 token,
2361 userData);
2362 if (connection != NULL) {
2363 connection->Unlock();
2364 break;
2367 return connection;
2370 void H323EndPoint::OnReceivedInitiateReturnError()
2374 #endif // H323_H450
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)
2391 PSyncPoint sync;
2392 return ClearCallSynchronous(token, reason, &sync);
2395 BOOL H323EndPoint::ClearCallSynchronous(const PString & token,
2396 H323Connection::CallEndReason reason,
2397 PSyncPoint * sync)
2399 if (PThread::Current() == connectionsCleaner)
2400 sync = NULL;
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);
2417 return FALSE;
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();
2436 if (sync != NULL)
2437 sync->Wait();
2439 return TRUE;
2443 void H323EndPoint::ClearAllCalls(H323Connection::CallEndReason reason,
2444 BOOL wait)
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
2457 PINDEX i;
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();
2474 if (wait)
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
2512 // lots of time.
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
2550 figure it out.
2552 H323Connection * connection;
2553 while ((connection = FindConnectionWithoutLocks(token)) != NULL) {
2554 switch (connection->TryLock()) {
2555 case 0 :
2556 return NULL;
2557 case 1 :
2558 return connection;
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();
2563 PThread::Sleep(20);
2564 connectionsMutex.Wait();
2567 return NULL;
2571 H323Connection * H323EndPoint::FindConnectionWithoutLocks(const PString & token)
2573 if (token.IsEmpty())
2574 return NULL;
2576 H323Connection * conn_ptr = connectionsActive.GetAt(token);
2577 if (conn_ptr != NULL)
2578 return conn_ptr;
2580 PINDEX i;
2581 for (i = 0; i < connectionsActive.GetSize(); i++) {
2582 H323Connection & conn = connectionsActive.GetDataAt(i);
2583 if (conn.GetCallIdentifier().AsString() == token)
2584 return &conn;
2587 for (i = 0; i < connectionsActive.GetSize(); i++) {
2588 H323Connection & conn = connectionsActive.GetDataAt(i);
2589 if (conn.GetConferenceIdentifier().AsString() == token)
2590 return &conn;
2593 return NULL;
2597 PStringList H323EndPoint::GetAllConnections()
2599 PStringList tokens;
2601 connectionsMutex.Wait();
2603 for (PINDEX i = 0; i < connectionsActive.GetSize(); i++)
2604 tokens.AppendString(connectionsActive.GetKeyAt(i));
2606 connectionsMutex.Signal();
2608 return tokens;
2612 BOOL H323EndPoint::OnIncomingCall(H323Connection & /*connection*/,
2613 const H323SignalPDU & /*setupPDU*/,
2614 H323SignalPDU & /*alertingPDU*/)
2616 return TRUE;
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*/)
2631 return TRUE;
2635 BOOL H323EndPoint::OnCallTransferIdentify(H323Connection & /*connection*/)
2637 return TRUE;
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.");
2660 return TRUE;
2664 BOOL H323EndPoint::OnConnectionForwarded(H323Connection & /*connection*/,
2665 const PString & /*forwardParty*/,
2666 const H323SignalPDU & /*pdu*/)
2668 return FALSE;
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))
2680 return FALSE;
2682 H323Connection * newConnection = NULL;
2683 for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
2684 newConnection = InternalMakeCall(PString::Empty(),
2685 PString::Empty(),
2686 UINT_MAX,
2687 Addresses[i],
2688 NULL,
2689 token,
2690 NULL);
2691 if (newConnection != NULL)
2692 break;
2696 if (newConnection == NULL)
2697 return FALSE;
2699 connection.SetCallEndReason(H323Connection::EndedByCallForwarded);
2700 newConnection->Unlock();
2701 return TRUE;
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)
2715 return FALSE;
2717 BOOL established = connection->IsEstablished();
2718 connection->Unlock();
2719 return established;
2723 BOOL H323EndPoint::OnOutgoingCall(H323Connection & /*connection*/,
2724 const H323SignalPDU & /*connectPDU*/)
2726 PTRACE(1, "H225\tReceived connect PDU.");
2727 return TRUE;
2731 void H323EndPoint::OnConnectionCleared(H323Connection & /*connection*/,
2732 const PString & /*token*/)
2737 PString H323EndPoint::BuildConnectionToken(const H323Transport & transport,
2738 unsigned callReference,
2739 BOOL fromRemote)
2741 PString token;
2743 if (fromRemote)
2744 token = transport.GetRemoteAddress();
2745 else
2746 token = "ip$localhost";
2748 token.sprintf("/%u", callReference);
2750 return token;
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");
2768 return 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);
2780 return connection;
2784 H323Connection * H323EndPoint::CreateConnection(unsigned callReference,
2785 void * userData,
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);
2804 #if PTRACING
2805 static void OnStartStopChannel(const char * startstop, const H323Channel & channel)
2807 const char * dir;
2808 switch (channel.GetDirection()) {
2809 case H323Channel::IsTransmitter :
2810 dir = "send";
2811 break;
2813 case H323Channel::IsReceiver :
2814 dir = "receiv";
2815 break;
2817 default :
2818 dir = "us";
2819 break;
2822 PTRACE(2, "H323\t" << startstop << "ed "
2823 << dir << "ing logical channel: "
2824 << channel.GetCapability());
2826 #endif
2829 BOOL H323EndPoint::OnStartLogicalChannel(H323Connection & /*connection*/,
2830 H323Channel & PTRACE_PARAM(channel))
2832 #if PTRACING
2833 OnStartStopChannel("Start", channel);
2834 #endif
2835 return TRUE;
2839 void H323EndPoint::OnClosedLogicalChannel(H323Connection & /*connection*/,
2840 const H323Channel & PTRACE_PARAM(channel))
2842 #if PTRACING
2843 OnStartStopChannel("Stopp", channel);
2844 #endif
2848 #ifdef H323_AUDIO_CODECS
2850 BOOL H323EndPoint::OpenAudioChannel(H323Connection & /*connection*/,
2851 BOOL isEncoding,
2852 unsigned bufferSize,
2853 H323AudioCodec & codec)
2855 codec.SetSilenceDetectionMode(GetSilenceDetectionMode());
2857 #ifdef P_AUDIO
2859 int rate = codec.GetMediaFormat().GetTimeUnits() * 1000;
2861 PString deviceName;
2862 PString deviceDriver;
2863 if (isEncoding) {
2864 deviceName = GetSoundChannelRecordDevice();
2865 deviceDriver = GetSoundChannelRecordDriver();
2866 } else {
2867 deviceName = GetSoundChannelPlayDevice();
2868 deviceDriver = GetSoundChannelPlayDriver();
2871 PSoundChannel * soundChannel;
2872 if (!deviceDriver.IsEmpty())
2873 soundChannel = PSoundChannel::CreateChannel(deviceDriver);
2874 else {
2875 soundChannel = new PSoundChannel;
2876 deviceDriver = "default";
2879 if (soundChannel == NULL) {
2880 PTRACE(1, "Codec\tCould not open a sound channel for " << deviceDriver);
2881 return FALSE;
2884 if (soundChannel->Open(deviceName, isEncoding ? PSoundChannel::Recorder
2885 : PSoundChannel::Player,
2886 1, rate, 16)) {
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;
2901 #endif
2903 return FALSE;
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");
2917 return FALSE;
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,
2935 char tone,
2936 unsigned /*duration*/,
2937 unsigned /*logicalChannel*/,
2938 unsigned /*rtpTimestamp*/)
2940 // don't pass through signalUpdate messages
2941 if (tone != ' ')
2942 connection.OnUserInputString(PString(tone));
2945 void H323EndPoint::OnGatekeeperNATDetect(
2946 PIPSocket::Address /* publicAddr*/,
2947 PString & /*gkIdentifier*/,
2948 H323TransportAddress & /*gkRouteAddress*/
2953 #ifdef H323_H248
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,
2972 unsigned sessionId,
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);
2989 return NULL;
2992 #endif // H323_H248
2994 BOOL H323EndPoint::OnConferenceInvite(BOOL /*sending*/,
2995 const H323Connection * /*connection*/,
2996 const H323SignalPDU & /*setupPDU */)
2998 return FALSE;
3001 BOOL H323EndPoint::OnSendCallIndependentSupplementaryService(const H323Connection * /*connection*/,
3002 H323SignalPDU & /* pdu */)
3004 return FALSE;
3007 BOOL H323EndPoint::OnReceiveCallIndependentSupplementaryService(const H323Connection * /*connection*/,
3008 const H323SignalPDU & /* pdu */)
3010 return FALSE;
3013 BOOL H323EndPoint::OnNegotiateConferenceCapabilities(const H323SignalPDU & /* setupPDU */)
3015 return FALSE;
3018 #ifdef H323_T120
3019 OpalT120Protocol * H323EndPoint::CreateT120ProtocolHandler(const H323Connection &) const
3021 return NULL;
3023 #endif
3026 #ifdef H323_T38
3027 OpalT38Protocol * H323EndPoint::CreateT38ProtocolHandler(const H323Connection &) const
3029 return NULL;
3031 #endif
3033 #ifdef OPAL_H224
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);
3047 #endif
3049 void H323EndPoint::SetLocalUserName(const PString & name)
3051 PAssert(!name, "Must have non-empty string in AliasAddress!");
3052 if (name.IsEmpty())
3053 return;
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)
3065 return FALSE;
3067 localAliasNames.AppendString(name);
3068 return TRUE;
3072 BOOL H323EndPoint::RemoveAliasName(const PString & name)
3074 PINDEX pos = localAliasNames.GetValuesIndex(name);
3075 if (pos == P_MAX_INDEX)
3076 return FALSE;
3078 PAssert(localAliasNames.GetSize() > 1, "Must have at least one AliasAddress!");
3079 if (localAliasNames.GetSize() < 2)
3080 return FALSE;
3082 localAliasNames.RemoveAt(pos);
3083 return TRUE;
3086 #ifdef H323_AUDIO_CODECS
3088 #ifdef P_AUDIO
3090 BOOL H323EndPoint::SetSoundChannelPlayDevice(const PString & name)
3092 if (PSoundChannel::GetDeviceNames(PSoundChannel::Player).GetValuesIndex(name) == P_MAX_INDEX)
3093 return FALSE;
3095 soundChannelPlayDevice = name;
3096 return TRUE;
3100 BOOL H323EndPoint::SetSoundChannelRecordDevice(const PString & name)
3102 if (PSoundChannel::GetDeviceNames(PSoundChannel::Recorder).GetValuesIndex(name) == P_MAX_INDEX)
3103 return FALSE;
3105 soundChannelRecordDevice = name;
3106 return TRUE;
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)
3115 return FALSE;
3117 soundChannelPlayDriver = name;
3118 soundChannelPlayDevice.MakeEmpty();
3119 list = PSoundChannel::GetDeviceNames(name, PSoundChannel::Player);
3120 if (list.GetSize() == 0)
3121 return FALSE;
3123 soundChannelPlayDevice = list[0];
3124 return TRUE;
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)
3133 return FALSE;
3135 soundChannelRecordDriver = name;
3136 list = PSoundChannel::GetDeviceNames(name, PSoundChannel::Recorder);
3137 if (list.GetSize() == 0)
3138 return FALSE;
3140 soundChannelRecordDevice = list[0];
3141 return TRUE;
3145 void H323EndPoint::SetSoundChannelBufferDepth(unsigned depth)
3147 PAssert(depth > 1, PInvalidParameter);
3148 soundChannelBuffers = depth;
3151 #endif // P_AUDIO
3153 #endif // H323_AUDIO_CODECS
3156 BOOL H323EndPoint::IsTerminal() const
3158 switch (terminalType) {
3159 case e_TerminalOnly :
3160 case e_TerminalAndMC :
3161 return TRUE;
3163 default :
3164 return FALSE;
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 :
3177 return TRUE;
3179 default :
3180 return FALSE;
3185 BOOL H323EndPoint::IsGatekeeper() const
3187 switch (terminalType) {
3188 case e_GatekeeperOnly :
3189 case e_GatekeeperWithDataMP :
3190 case e_GatekeeperWithAudioMP :
3191 case e_GatekeeperWithAVMP :
3192 return TRUE;
3194 default :
3195 return FALSE;
3200 BOOL H323EndPoint::IsMCU() const
3202 switch (terminalType) {
3203 case e_MCUOnly :
3204 case e_MCUWithDataMP :
3205 case e_MCUWithAudioMP :
3206 case e_MCUWithAVMP :
3207 return TRUE;
3209 default :
3210 return FALSE;
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;
3222 return;
3225 PAssert(minDelay <= 10000 && maxDelay <= 10000, PInvalidParameter);
3227 if (minDelay < 10)
3228 minDelay = 10;
3229 minAudioJitterDelay = minDelay;
3231 if (maxDelay < minDelay)
3232 maxDelay = minDelay;
3233 maxAudioJitterDelay = maxDelay;
3236 #endif
3238 #ifdef P_STUN
3240 PSTUNClient * H323EndPoint::GetSTUN(const PIPSocket::Address & ip) const
3242 if (ip.IsValid() && IsLocalAddress(ip))
3243 return NULL;
3245 return stun;
3248 PNatMethod * H323EndPoint::GetPreferedNatMethod(const PIPSocket::Address & ip)
3251 if (ip.IsValid() && IsLocalAddress(ip))
3252 return NULL;
3254 #if PTRACING
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()) {
3262 meth = &list[i];
3263 break;
3266 } else {
3267 PTRACE(6, "H323\tNo NAT Methods!");
3269 return meth;
3270 #else
3271 return natMethods.GetMethod();
3272 #endif
3276 PNatStrategy H323EndPoint::GetNatMethods()
3278 return natMethods;
3281 void H323EndPoint::SetSTUNServer(const PString & server)
3283 delete stun;
3285 if (server.IsEmpty())
3286 stun = NULL;
3287 else {
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());
3298 #endif // P_STUN
3300 void H323EndPoint::InternalTranslateTCPAddress(PIPSocket::Address & localAddr, const PIPSocket::Address & remoteAddr)
3302 #ifdef P_STUN
3303 // if using STUN server, then translate internal local address to external if required
3304 PIPSocket::Address addr;
3305 if (
3306 stun != NULL && (
3307 (stun->IsSupportingRTP() == PSTUNClient::RTPOK) ||
3308 (stun->IsSupportingRTP() == PSTUNClient::RTPIfSendMedia)
3309 ) &&
3310 localAddr.IsRFC1918() &&
3311 !remoteAddr.IsRFC1918() &&
3312 stun->GetExternalAddress(addr)
3315 localAddr = addr;
3317 else
3318 #endif // P_STUN
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,
3330 unsigned newMax,
3331 unsigned range,
3332 unsigned dflt)
3334 if (newBase == 0) {
3335 newBase = dflt;
3336 newMax = dflt;
3337 if (dflt > 0)
3338 newMax += range;
3340 else {
3341 if (newBase < 1024)
3342 newBase = 1024;
3343 else if (newBase > 65500)
3344 newBase = 65500;
3346 if (newMax <= newBase)
3347 newMax = newBase + range;
3348 if (newMax > 65535)
3349 newMax = 65535;
3352 mutex.Wait();
3354 current = base = (WORD)newBase;
3355 max = (WORD)newMax;
3357 mutex.Signal();
3361 WORD H323EndPoint::PortInfo::GetNext(unsigned increment)
3363 PWaitAndSignal m(mutex);
3365 if (current < base || current > (max-increment))
3366 current = base;
3368 if (current == 0)
3369 return 0;
3371 WORD p = current;
3372 current = (WORD)(current + increment);
3373 return p;
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);
3393 #ifdef P_STUN
3394 natMethods.SetPortRanges(GetUDPPortBase(), GetUDPPortMax(), GetRtpIpPortBase(), GetRtpIpPortMax());
3395 #endif
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);
3409 #ifdef P_STUN
3410 natMethods.SetPortRanges(GetUDPPortBase(), GetUDPPortMax(), GetRtpIpPortBase(), GetRtpIpPortMax());
3411 #endif
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)
3432 return FALSE;
3434 noMediaTimeout = newInterval;
3435 return TRUE;
3438 BOOL H323EndPoint::OnSendFeatureSet(unsigned pdu, H225_FeatureSet & feats)
3440 #ifdef H323_H460
3441 return features.SendFeature(pdu,feats);
3442 #else
3443 return FALSE;
3444 #endif
3447 void H323EndPoint::OnReceiveFeatureSet(unsigned pdu, const H225_FeatureSet & feats)
3449 #ifdef H323_H460
3450 features.ReceiveFeature(pdu,feats);
3451 #endif
3454 void H323EndPoint::LoadBaseFeatureSet()
3457 #ifdef H323_H460
3458 features.AttachEndPoint(this);
3459 features.LoadFeatureSet(H460_Feature::FeatureBase);
3460 #endif
3464 BOOL H323EndPoint::HandleUnsolicitedInformation(const H323SignalPDU & )
3466 return FALSE;
3469 #ifdef H323_RTP_AGGREGATE
3470 PHandleAggregator * H323EndPoint::GetRTPAggregator()
3472 PWaitAndSignal m(connectionsMutex);
3473 if (rtpAggregationSize == 0)
3474 return NULL;
3476 if (rtpAggregator == NULL)
3477 rtpAggregator = new PHandleAggregator(rtpAggregationSize);
3479 return rtpAggregator;
3481 #endif
3483 #ifdef H323_SIGNAL_AGGREGATE
3484 PHandleAggregator * H323EndPoint::GetSignallingAggregator()
3486 PWaitAndSignal m(connectionsMutex);
3487 if (signallingAggregationSize == 0)
3488 return NULL;
3490 if (signallingAggregator == NULL)
3491 signallingAggregator = new PHandleAggregator(signallingAggregationSize);
3493 return signallingAggregator;
3495 #endif
3497 /////////////////////////////////////////////////////////////////////////////
3499 #ifdef H323_TRANSNEXUS_OSP
3501 void H323EndPoint::SetOSPProvider(OpalOSP::Provider * provider)
3503 if (ospProvider != NULL)
3504 delete ospProvider;
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);
3516 if (result != 0)
3517 delete newProvider;
3518 else
3519 SetOSPProvider(newProvider);
3521 return result;
3524 #endif
3526 /////////////////////////////////////////////////////////////////////////////