Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / gkclient.cxx
blob76d0c8efe3a0f5fbbe38a8c58a96ddceeda9d400
1 /*
2 * gkclient.cxx
4 * Gatekeeper client protocol handler
6 * Open H323 Library
8 * Copyright (c) 1999-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 * iFace In, http://www.iface.com
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.165 2006/07/23 23:27:55 shorne
31 * supportsAssignedGK made optional field in RRQ & GRQ for backwards interoperability
33 * Revision 1.164 2006/07/21 16:29:13 csoutheren
34 * Initialise mandatory extension elements in GRQ and RRQ for H.225 V6
36 * Revision 1.163 2006/06/30 05:26:43 csoutheren
37 * Applied 1509255 - Checking whether SetSize succeeds in GkClient
38 * Thanks to Borko Jandras
40 * Revision 1.162 2006/06/09 06:30:12 csoutheren
41 * Remove compile warning and errors with gcc
43 * Revision 1.161 2006/05/30 11:14:56 hfriederich
44 * Switch from DISABLE_H460 to H323_H460
46 * Revision 1.160 2006/05/29 02:31:45 shorne
47 * H460 functions now get called
49 * Revision 1.159 2006/05/18 17:15:54 shorne
50 * Added H460 Support
52 * Revision 1.158 2006/05/16 11:39:39 shorne
53 * call linkage support
55 * Revision 1.157 2006/03/07 10:37:46 csoutheren
56 * Add ability to disable GRQ on GK registration
58 * Revision 1.156 2005/11/21 20:52:35 shorne
59 * Added GnuGK Nat detection support
61 * Revision 1.155 2005/01/16 20:39:44 csoutheren
62 * Fixed problem with IPv6 INADDR_ANY
64 * Revision 1.154 2005/01/03 06:25:54 csoutheren
65 * Added extensive support for disabling code modules at compile time
67 * Revision 1.153 2004/11/20 22:00:10 csoutheren
68 * Check address from RequestLocation due to stupid gatekeepers
70 * Revision 1.152 2004/09/07 23:51:46 rjongbloed
71 * Fixed MSVC6 warning
73 * Revision 1.151 2004/09/03 01:06:09 csoutheren
74 * Added initial hooks for H.460 GEF
75 * Thanks to Simon Horne and ISVO (Asia) Pte Ltd. for this contribution
77 * Revision 1.150 2004/06/15 03:30:00 csoutheren
78 * Added OnSendARQ to allow access to the ARQ message before sent by connection
80 * Revision 1.149 2004/04/03 08:28:06 csoutheren
81 * Remove pseudo-RTTI and replaced with real RTTI
83 * Revision 1.148 2004/01/17 18:20:15 csoutheren
84 * No longer force re-register on completion of LRQ
86 * Revision 1.147 2003/12/29 04:59:25 csoutheren
87 * Added callbacks on H323EndPoint when gatekeeper discovery succeeds or fails
89 * Revision 1.146 2003/12/28 00:06:34 csoutheren
90 * Added callbacks on H323EndPoint when gatekeeper registration succeeds or fails
92 * Revision 1.145 2003/05/01 05:04:00 robertj
93 * Fixed inclusion of 127.0.0.1 into listener lists when no needed.
95 * Revision 1.144 2003/04/30 07:25:32 robertj
96 * Fixed setting of remote ID in alternate credentials.
98 * Revision 1.143 2003/04/30 00:28:54 robertj
99 * Redesigned the alternate credentials in ARQ system as old implementation
100 * was fraught with concurrency issues, most importantly it can cause false
101 * detection of replay attacks taking out an endpoint completely.
103 * Revision 1.142 2003/04/10 09:44:31 robertj
104 * Added associated transport to new GetInterfaceAddresses() function so
105 * interfaces can be ordered according to active transport links. Improves
106 * interoperability.
107 * Replaced old listener GetTransportPDU() with GetInterfaceAddresses()
108 * and H323SetTransportAddresses() functions.
110 * Revision 1.141 2003/04/09 03:08:10 robertj
111 * Fixed race condition in shutting down transactor (pure virtual call)
113 * Revision 1.140 2003/03/26 00:46:28 robertj
114 * Had another go at making H323Transactor being able to be created
115 * without having a listener running.
117 * Revision 1.139 2003/03/20 01:51:11 robertj
118 * More abstraction of H.225 RAS and H.501 protocols transaction handling.
120 * Revision 1.138 2003/02/21 05:25:45 craigs
121 * Abstracted out underlying transports for use with peerelements
123 * Revision 1.137 2003/02/12 23:59:25 robertj
124 * Fixed adding missing endpoint identifer in SETUP packet when gatekeeper
125 * routed, pointed out by Stefan Klein
126 * Also fixed correct rutrn of gk routing in IRR packet.
128 * Revision 1.136 2003/02/11 04:46:37 robertj
129 * Fixed keep alive RRQ being rejected with full registration required
130 * reason actually doing a full registration!
132 * Revision 1.135 2003/02/10 01:51:50 robertj
133 * Fixed bad tokens causing an apparent "transport error", now correctly
134 * indicates a security error.
136 * Revision 1.134 2003/02/07 06:38:47 robertj
137 * Changed registration state to an enum so can determine why the RRQ failed.
139 * Revision 1.133 2003/02/04 07:04:45 robertj
140 * Prevent multiple calls to Connect() if did not change the gk.
142 * Revision 1.132 2003/02/01 13:31:21 robertj
143 * Changes to support CAT authentication in RAS.
145 * Revision 1.131 2003/01/11 05:04:03 robertj
146 * Added checks for valid URQ packet, thanks Chih-Wei Huang
148 * Revision 1.130 2003/01/09 04:45:04 robertj
149 * Fixed problem where if gets GRJ which does not have an alternate gatekeeper
150 * the system gets into an infinite loop, pointed out by Vladimir Toncar
152 * Revision 1.129 2003/01/06 07:09:43 robertj
153 * Further fixes for alternate gatekeeper, thanks Kevin Bouchard
155 * Revision 1.128 2002/12/23 22:47:53 robertj
156 * Changed gatekeeper discovery so an GRJ does not indicate "discovered".
157 * Added trace output of alternate gatekeepers list.
158 * Fixed receiving GRJ with alternate gatekeepers to immediately do discover
159 * and registration on the alternate.
161 * Revision 1.127 2002/12/19 23:52:53 robertj
162 * Fixed probelm with registering with alternate gk, thanks Kevin Bouchard
164 * Revision 1.126 2002/12/10 23:39:03 robertj
165 * Added some extra tracing.
167 * Revision 1.125 2002/11/28 04:41:48 robertj
168 * Added support for RAS ServiceControlIndication command.
170 * Revision 1.124 2002/11/27 06:54:56 robertj
171 * Added Service Control Session management as per Annex K/H.323 via RAS
172 * only at this stage.
173 * Added H.248 ASN and very primitive infrastructure for linking into the
174 * Service Control Session management system.
175 * Added basic infrastructure for Annex K/H.323 HTTP transport system.
176 * Added Call Credit Service Control to display account balances.
178 * Revision 1.123 2002/11/22 07:16:14 robertj
179 * Changed ARQ to include all local aliases for connection.
181 * Revision 1.122 2002/11/21 07:29:15 robertj
182 * Fixed GNU warning
184 * Revision 1.121 2002/11/21 07:21:49 robertj
185 * Improvements to alternate gatekeeper client code, thanks Kevin Bouchard
187 * Revision 1.120 2002/11/12 03:13:24 robertj
188 * Removed redundent code.
190 * Revision 1.119 2002/11/10 08:10:43 robertj
191 * Moved constants for "well known" ports to better place (OPAL change).
193 * Revision 1.118 2002/11/01 03:48:18 robertj
194 * Fixed previous two hacks!! Neither of which would have worked.
196 * Revision 1.117 2002/10/31 23:31:41 dereks
197 * Fix for previous quick hack. Thanks Damien Sandras.
199 * Revision 1.116 2002/10/31 21:40:28 dereks
200 * Quick (and temporary) hack to enable compilation on redhat 8.0 boxes.
202 * Revision 1.115 2002/09/19 23:19:25 robertj
203 * Fixed setting of info request rate, broken in a previous patch
205 * Revision 1.114 2002/09/18 06:58:32 robertj
206 * Fixed setting of IRR frequency, an RCF could reset timer so it did not time
207 * out correctly and send IRR in time causing problems with gatekeeper.
209 * Revision 1.113 2002/09/09 23:59:59 robertj
210 * Fixed incorrect inserting of UUIE pdu's into IRR, thanks Ravelli Rossano
212 * Revision 1.112 2002/08/29 07:02:19 robertj
213 * Allowed network latency deadband in unsolicited IRR response time.
215 * Revision 1.111 2002/08/28 00:07:02 robertj
216 * Added supportsAltGK capability flag in GRQ & RRQ.
218 * Revision 1.110 2002/08/15 09:38:55 robertj
219 * Added more logging for when endpoint becomes unregistered.
221 * Revision 1.109 2002/08/15 04:12:54 robertj
222 * Fixed correct status of isRegistered flag on various reject/errors.
224 * Revision 1.108 2002/08/12 05:38:24 robertj
225 * Changes to the RAS subsystem to support ability to make requests to client
226 * from gkserver without causing bottlenecks and race conditions.
228 * Revision 1.107 2002/08/11 23:30:36 robertj
229 * Fixed typo in previous patch.
231 * Revision 1.106 2002/08/11 23:24:24 robertj
232 * Fixed problem with retrying ARQ after getting error saying are not
233 * registered and reregistering, needed new sequence number.
234 * Fixed return of correct error in ARQ response when is a transport error
235 * rather than a reject reason from ARJ.
237 * Revision 1.105 2002/08/05 10:03:47 robertj
238 * Cosmetic changes to normalise the usage of pragma interface/implementation.
240 * Revision 1.104 2002/08/05 05:17:41 robertj
241 * Fairly major modifications to support different authentication credentials
242 * in ARQ to the logged in ones on RRQ. For both client and server.
243 * Various other H.235 authentication bugs and anomalies fixed on the way.
245 * Revision 1.103 2002/07/19 10:20:03 robertj
246 * Fixed bug of missing test for IRR frequency in RCF, thanks Thien Nguyen
248 * Revision 1.102 2002/07/18 03:03:19 robertj
249 * Fixed bug with continually doing lightweight RRQ if no timeToLive present
250 * and it should not be doing it at all, ditto for unsolicited IRR.
252 * Revision 1.101 2002/07/17 00:04:10 robertj
253 * Fixed missing initialisation of alternat gk pointer to NULL, thanks Kevin Bouchard
255 * Revision 1.100 2002/07/16 13:19:13 robertj
256 * Minor optimisation of unsolicited IRR when no calls active.
258 * Revision 1.99 2002/07/16 11:06:27 robertj
259 * Added more alternate gatekeeper implementation, thanks Kevin Bouchard
261 * Revision 1.98 2002/07/11 09:34:32 robertj
262 * Fixed minor compliance to letter of specification.
264 * Revision 1.97 2002/07/11 01:34:37 robertj
265 * Temporary fix for IRR frequency provided in ACF
267 * Revision 1.96 2002/07/07 02:08:53 robertj
268 * Fixed missing originator field in IRR perCallInfo, thanks Ravelli Rossano
270 * Revision 1.95 2002/06/28 03:34:28 robertj
271 * Fixed issues with address translation on gatekeeper RAS channel.
273 * Revision 1.94 2002/06/26 03:47:49 robertj
274 * Added support for alternate gatekeepers.
276 * Revision 1.93 2002/06/26 00:50:12 robertj
277 * Added other error code in ARJ that indicates we should reregister.
279 * Revision 1.92 2002/06/05 09:20:07 robertj
280 * Added IRQ redirect of IRR to different address, thanks "thsuk".
282 * Revision 1.91 2002/05/29 00:03:19 robertj
283 * Fixed unsolicited IRR support in gk client and server,
284 * including support for IACK and INAK.
286 * Revision 1.90 2002/05/17 04:01:53 robertj
287 * Fixed problems with H.235 authentication on RAS for server and client.
288 * Added support for unsolicited IRR transmission in background (heartbeat).
290 * Revision 1.89 2002/05/09 05:43:44 robertj
291 * Added reattempt of full RRQ if get fullRegistrationRequired RRJ.
293 * Revision 1.88 2002/05/01 06:39:41 robertj
294 * Fixed incorrect setting of srcCallSignalAddress in ARQ for outgoing call as
295 * putting in incorrect data is worse than not putting anything in at all! So
296 * unless the correct data is available it is now left out.
298 * Revision 1.87 2002/03/20 02:12:49 robertj
299 * Added missing return value for number of endpoints returned in ACF
301 * Revision 1.86 2002/03/19 05:17:25 robertj
302 * Normalised ACF destExtraCallIInfo to be same as other parameters.
303 * Added ability to get multiple endpoint addresses and tokens from ACF.
305 * Revision 1.85 2002/03/01 04:06:44 robertj
306 * Fixed autoreregister on ARQ failing due to unregistered endpoint.
308 * Revision 1.84 2002/02/11 04:25:57 robertj
309 * Added ability to automatically reregister if do an ARQ and are told are not
310 * registered. Can occur if gk is restarted and is faster than waiting for TTL..
312 * Revision 1.83 2002/01/13 23:58:48 robertj
313 * Added ability to set destination extra call info in ARQ
314 * Filled in destinationInfo in ARQ when answering call.
315 * Allowed application to override srcInfo in ARQ on outgoing call by
316 * changing localPartyName.
317 * Added better end call codes for some ARJ reasons.
318 * Thanks Ben Madsen of Norwood Systems.
320 * Revision 1.82 2001/12/15 10:10:48 robertj
321 * GCC compatibility
323 * Revision 1.81 2001/12/15 08:36:49 robertj
324 * Added previous call times to all the other PDU's it is supposed to be in!
326 * Revision 1.80 2001/12/15 08:09:21 robertj
327 * Added alerting, connect and end of call times to be sent to RAS server.
329 * Revision 1.79 2001/12/14 06:41:36 robertj
330 * Added call end reason codes in DisengageRequest for GK server use.
332 * Revision 1.78 2001/12/13 11:00:13 robertj
333 * Changed search for access token in ACF to be able to look for two OID's.
335 * Revision 1.77 2001/12/06 06:44:42 robertj
336 * Removed "Win32 SSL xxx" build configurations in favour of system
337 * environment variables to select optional libraries.
339 * Revision 1.76 2001/10/12 04:14:31 robertj
340 * Changed gk unregister so only way it doe not actually unregister is if
341 * get URJ with reason code callInProgress, thanks Chris Purvis.
343 * Revision 1.75 2001/10/09 08:04:59 robertj
344 * Fixed unregistration so still unregisters if gk goes offline, thanks Chris Purvis
346 * Revision 1.74 2001/10/08 01:37:42 robertj
347 * Fixed uninitialised variable for ARQ authentication override.
349 * Revision 1.73 2001/09/26 07:03:08 robertj
350 * Added needed mutex for SeparateAuthenticationInARQ mode, thanks Nick Hoath
352 * Revision 1.72 2001/09/18 10:36:57 robertj
353 * Allowed multiple overlapping requests in RAS channel.
355 * Revision 1.71 2001/09/13 03:21:16 robertj
356 * Added ability to override authentication credentials for ARQ, thanks Nick Hoath
358 * Revision 1.70 2001/09/13 01:15:20 robertj
359 * Added flag to H235Authenticator to determine if gkid and epid is to be
360 * automatically set as the crypto token remote id and local id.
362 * Revision 1.69 2001/09/13 00:32:24 robertj
363 * Added missing gkid in ARQ, thanks Nick Hoath
365 * Revision 1.68 2001/09/12 07:48:05 robertj
366 * Fixed various problems with tracing.
368 * Revision 1.67 2001/09/12 06:58:00 robertj
369 * Added support for iNow Access Token from gk, thanks Nick Hoath
371 * Revision 1.66 2001/09/12 06:04:38 robertj
372 * Added support for sending UUIE's to gk on request, thanks Nick Hoath
374 * Revision 1.65 2001/09/05 01:16:32 robertj
375 * Added overloaded AdmissionRequest for backward compatibility.
377 * Revision 1.64 2001/08/14 04:26:46 robertj
378 * Completed the Cisco compatible MD5 authentications, thanks Wolfgang Platzer.
380 * Revision 1.63 2001/08/13 01:27:03 robertj
381 * Changed GK admission so can return multiple aliases to be used in
382 * setup packet, thanks Nick Hoath.
384 * Revision 1.62 2001/08/13 00:22:14 robertj
385 * Allowed for received DRQ not having call ID (eg v1 gk), uses conference ID
387 * Revision 1.61 2001/08/10 11:03:52 robertj
388 * Major changes to H.235 support in RAS to support server.
390 * Revision 1.60 2001/08/06 07:44:55 robertj
391 * Fixed problems with building without SSL
393 * Revision 1.59 2001/08/06 03:18:38 robertj
394 * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
395 * Improved access to H.235 secure RAS functionality.
396 * Changes to H.323 secure RAS contexts to help use with gk server.
398 * Revision 1.58 2001/08/02 04:30:43 robertj
399 * Added ability for AdmissionRequest to alter destination alias used in
400 * the outgoing call. Thanks Ben Madsen & Graeme Reid.
402 * Revision 1.57 2001/06/22 00:21:10 robertj
403 * Fixed bug in H.225 RAS protocol with 16 versus 32 bit sequence numbers.
405 * Revision 1.56 2001/06/18 23:35:01 robertj
406 * Removed condition that prevented aliases on non-terminal endpoints.
408 * Revision 1.55 2001/06/18 06:23:50 robertj
409 * Split raw H.225 RAS protocol out of gatekeeper client class.
411 * Revision 1.54 2001/05/17 03:29:13 robertj
412 * Fixed missing replyAddress in LRQ, thanks Alexander Smirnov.
413 * Added some extra optional fields to LRQ.
415 * Revision 1.53 2001/04/19 08:03:21 robertj
416 * Fixed scale on RIp delay, is milliseconds!
418 * Revision 1.52 2001/04/13 07:44:20 robertj
419 * Fixed setting isRegistered flag to false when get RRJ
421 * Revision 1.51 2001/04/05 03:39:43 robertj
422 * Fixed deadlock if tried to do discovery in time to live timeout.
424 * Revision 1.50 2001/03/28 07:13:06 robertj
425 * Changed RAS thread interlock to allow for what should not happen, the
426 * syncpoint being signalled before receiving any packets.
428 * Revision 1.49 2001/03/27 02:19:22 robertj
429 * Changed to send gk a GRQ if it gives a discoveryRequired error on RRQ.
430 * Fixed BIG condition in use of sequence numbers.
432 * Revision 1.48 2001/03/26 05:06:03 robertj
433 * Added code to do full registration if RRJ indicates discovery to be redone.
435 * Revision 1.47 2001/03/24 00:51:41 robertj
436 * Added retry every minute of time to live registration if fails.
438 * Revision 1.46 2001/03/23 01:47:49 robertj
439 * Improved debug trace message on RAS packet retry.
441 * Revision 1.45 2001/03/23 01:19:25 robertj
442 * Fixed usage of secure RAS in GRQ, should not do for that one PDU.
444 * Revision 1.44 2001/03/21 04:52:42 robertj
445 * Added H.235 security to gatekeepers, thanks Fürbass Franz!
447 * Revision 1.43 2001/03/19 23:32:30 robertj
448 * Fixed problem with auto-reregister doing so in the RAS receive thread.
450 * Revision 1.42 2001/03/19 05:50:52 robertj
451 * Fixed trace display of timeout value.
453 * Revision 1.41 2001/03/18 22:21:29 robertj
454 * Fixed GNU C++ problem.
456 * Revision 1.40 2001/03/17 00:05:52 robertj
457 * Fixed problems with Gatekeeper RIP handling.
459 * Revision 1.39 2001/03/16 06:46:21 robertj
460 * Added ability to set endpoints desired time to live on a gatekeeper.
462 * Revision 1.38 2001/03/15 00:25:58 robertj
463 * Fixed bug in receiving RIP packet, did not restart timeout.
465 * Revision 1.37 2001/03/09 02:55:53 robertj
466 * Fixed bug in RAS IRR, optional field not being included, thanks Erik Larsson.
468 * Revision 1.36 2001/03/02 06:59:59 robertj
469 * Enhanced the globally unique identifier class.
471 * Revision 1.35 2001/02/28 00:20:16 robertj
472 * Added DiscoverByNameAndAddress() function, thanks Chris Purvis.
474 * Revision 1.34 2001/02/18 22:33:47 robertj
475 * Added better handling of URJ, thanks Chris Purvis.
477 * Revision 1.33 2001/02/09 05:13:55 craigs
478 * Added pragma implementation to (hopefully) reduce the executable image size
479 * under Linux
481 * Revision 1.32 2001/01/25 01:44:26 robertj
482 * Reversed order of changing alias list to avoid assert if delete all aliases.
484 * Revision 1.31 2000/11/01 03:30:27 robertj
485 * Changed gatekeeper registration time to live to update in slightly less than the
486 * time to live time. Allows for system/network latency. Thanks Laurent PELLETIER.
488 * Revision 1.30 2000/09/25 06:48:11 robertj
489 * Removed use of alias if there is no alias present, ie only have transport address.
491 * Revision 1.29 2000/09/01 02:12:37 robertj
492 * Fixed problem when multiple GK's on LAN, only discovered first one.
493 * Added ability to select a gatekeeper on LAN via it's identifier name.
495 * Revision 1.28 2000/07/15 09:54:21 robertj
496 * Fixed problem with having empty or unusable assigned aliases.
498 * Revision 1.27 2000/07/11 19:26:39 robertj
499 * Fixed problem with endpoint identifiers from some gatekeepers not being a string, just binary info.
501 * Revision 1.26 2000/06/20 03:18:04 robertj
502 * Added function to get name of gatekeeper, subtle difference from getting identifier.
504 * Revision 1.25 2000/05/09 12:14:32 robertj
505 * Added adjustment of endpoints alias list as approved by gatekeeper.
507 * Revision 1.24 2000/05/09 08:52:50 robertj
508 * Added support for preGrantedARQ fields on registration.
510 * Revision 1.23 2000/05/04 10:43:54 robertj
511 * Fixed problem with still trying to RRQ if got a GRJ.
513 * Revision 1.22 2000/05/02 04:32:26 robertj
514 * Fixed copyright notice comment.
516 * Revision 1.21 2000/04/27 02:52:58 robertj
517 * Added keepAlive field to RRQ if already registered,
519 * Revision 1.20 2000/04/12 21:22:16 robertj
520 * Fixed warning in No Trace mode.
522 * Revision 1.19 2000/04/11 04:00:55 robertj
523 * Filled in destCallSignallingAddress if specified by caller, used for gateway permissions.
525 * Revision 1.18 2000/04/11 03:11:12 robertj
526 * Added ability to reject reason on gatekeeper requests.
528 * Revision 1.17 2000/03/29 02:14:43 robertj
529 * Changed TerminationReason to CallEndReason to use correct telephony nomenclature.
530 * Added CallEndReason for capability exchange failure.
532 * Revision 1.16 2000/03/23 02:45:28 robertj
533 * Changed ClearAllCalls() so will wait for calls to be closed (usefull in endpoint dtors).
535 * Revision 1.15 2000/03/21 23:17:55 robertj
536 * Changed GK client so does not fill in destCallSignalAddress on outgoing call.
538 * Revision 1.14 2000/01/28 00:56:48 robertj
539 * Changed ACF to return destination address irrespective of callModel, thanks Chris Gindel.
541 * Revision 1.13 1999/12/23 23:02:35 robertj
542 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
544 * Revision 1.12 1999/12/11 02:20:58 robertj
545 * Added ability to have multiple aliases on local endpoint.
547 * Revision 1.11 1999/12/10 01:43:25 robertj
548 * Fixed outgoing call Admissionrequestion addresses.
550 * Revision 1.10 1999/12/09 21:49:18 robertj
551 * Added reregister on unregister and time to live reregistration
553 * Revision 1.9 1999/11/06 05:37:45 robertj
554 * Complete rewrite of termination of connection to avoid numerous race conditions.
556 * Revision 1.8 1999/10/16 03:47:48 robertj
557 * Fixed termination of gatekeeper RAS thread problem
559 * Revision 1.7 1999/10/15 05:55:50 robertj
560 * Fixed crash in responding to InfoRequest
562 * Revision 1.6 1999/09/23 08:48:45 robertj
563 * Changed register request so cannot do it of have no listeners.
565 * Revision 1.5 1999/09/21 14:09:19 robertj
566 * Removed warnings when no tracing enabled.
568 * Revision 1.4 1999/09/14 08:19:37 robertj
569 * Fixed timeout on retry of gatekeeper discover and added more tracing.
571 * Revision 1.3 1999/09/14 06:52:54 robertj
572 * Added better support for multi-homed client hosts.
574 * Revision 1.2 1999/09/10 02:45:31 robertj
575 * Added missing binding of address to transport when a specific gatway is used.
577 * Revision 1.1 1999/08/31 12:34:18 robertj
578 * Added gatekeeper support.
582 #include <ptlib.h>
584 #ifdef __GNUC__
585 #pragma implementation "gkclient.h"
586 #endif
588 #include "gkclient.h"
590 #include "h323ep.h"
591 #include "h323rtp.h"
592 #include "h323pdu.h"
594 #ifdef H323_H460
595 #include "h4601.h"
596 #endif
598 #define new PNEW
601 static PTimeInterval AdjustTimeout(unsigned seconds)
603 // Allow for an incredible amount of system/network latency
604 static unsigned TimeoutDeadband = 5; // seconds
606 return PTimeInterval(0, seconds > TimeoutDeadband
607 ? (seconds - TimeoutDeadband)
608 : TimeoutDeadband);
612 /////////////////////////////////////////////////////////////////////////////
614 H323Gatekeeper::H323Gatekeeper(H323EndPoint & ep, H323Transport * trans)
615 : H225_RAS(ep, trans),
616 requestMutex(1, 1),
617 authenticators(ep.CreateAuthenticators())
618 #ifdef H323_H460
619 ,features(ep.GetFeatureSet())
620 #endif
622 alternatePermanent = FALSE;
623 discoveryComplete = FALSE;
624 registrationFailReason = UnregisteredLocally;
626 pregrantMakeCall = pregrantAnswerCall = RequireARQ;
628 autoReregister = TRUE;
629 reregisterNow = FALSE;
630 requiresDiscovery = FALSE;
632 timeToLive.SetNotifier(PCREATE_NOTIFIER(TickleMonitor));
633 infoRequestRate.SetNotifier(PCREATE_NOTIFIER(TickleMonitor));
635 willRespondToIRR = FALSE;
636 monitorStop = FALSE;
638 monitor = PThread::Create(PCREATE_NOTIFIER(MonitorMain), 0,
639 PThread::NoAutoDeleteThread,
640 PThread::NormalPriority,
641 "GkMonitor:%x");
642 #ifdef H323_H460
643 features.LoadFeatureSet(H460_Feature::FeatureRas);
644 #endif
648 H323Gatekeeper::~H323Gatekeeper()
650 if (monitor != NULL) {
651 monitorStop = TRUE;
652 monitorTickle.Signal();
653 monitor->WaitForTermination();
654 delete monitor;
657 StopChannel();
661 PString H323Gatekeeper::GetName() const
663 PStringStream s;
664 s << *this;
665 return s;
669 BOOL H323Gatekeeper::DiscoverAny()
671 gatekeeperIdentifier = PString();
672 return StartDiscovery(H323TransportAddress());
676 BOOL H323Gatekeeper::DiscoverByName(const PString & identifier)
678 gatekeeperIdentifier = identifier;
679 return StartDiscovery(H323TransportAddress());
683 BOOL H323Gatekeeper::DiscoverByAddress(const H323TransportAddress & address)
685 gatekeeperIdentifier = PString();
686 return StartDiscovery(address);
690 BOOL H323Gatekeeper::DiscoverByNameAndAddress(const PString & identifier,
691 const H323TransportAddress & address)
693 gatekeeperIdentifier = identifier;
694 return StartDiscovery(address);
697 BOOL H323Gatekeeper::StartDiscovery(const H323TransportAddress & initialAddress)
699 if (PAssertNULL(transport) == NULL)
700 return FALSE;
702 /// don't send GRQ if not requested
703 if (!endpoint.GetSendGRQ() && !initialAddress.IsEmpty()) {
704 transport->SetRemoteAddress(initialAddress);
705 if (!transport->Connect()) {
706 PTRACE(2, "RAS\tUnable to connect to gatekeeper at " << initialAddress);
707 return FALSE;
709 transport->SetPromiscuous(H323Transport::AcceptFromRemoteOnly);
710 StartChannel();
711 PTRACE(2, "RAS\tSkipping gatekeeper discovery for " << initialAddress);
712 return TRUE;
715 H323RasPDU pdu;
716 Request request(SetupGatekeeperRequest(pdu), pdu);
718 H323TransportAddress address = initialAddress;
719 request.responseInfo = &address;
721 requestsMutex.Wait();
722 requests.SetAt(request.sequenceNumber, &request);
723 requestsMutex.Signal();
725 discoveryComplete = FALSE;
726 unsigned retries = endpoint.GetGatekeeperRequestRetries();
727 while (!discoveryComplete) {
728 if (transport->DiscoverGatekeeper(*this, pdu, address)) {
729 if (address == initialAddress)
730 break;
731 /// If get here must have been GRJ with an alternate gk, start again
733 else {
734 // Transport failure, retry
735 if (--retries == 0)
736 break;
740 requestsMutex.Wait();
741 requests.SetAt(request.sequenceNumber, NULL);
742 requestsMutex.Signal();
744 if (discoveryComplete) {
745 if (transport->Connect())
746 StartChannel();
749 return discoveryComplete;
753 unsigned H323Gatekeeper::SetupGatekeeperRequest(H323RasPDU & request)
755 if (PAssertNULL(transport) == NULL)
756 return 0;
758 H225_GatekeeperRequest & grq = request.BuildGatekeeperRequest(GetNextSequenceNumber());
760 endpoint.SetEndpointTypeInfo(grq.m_endpointType);
761 transport->SetUpTransportPDU(grq.m_rasAddress, TRUE);
763 grq.IncludeOptionalField(H225_GatekeeperRequest::e_endpointAlias);
764 H323SetAliasAddresses(endpoint.GetAliasNames(), grq.m_endpointAlias);
766 if (!gatekeeperIdentifier) {
767 grq.IncludeOptionalField(H225_GatekeeperRequest::e_gatekeeperIdentifier);
768 grq.m_gatekeeperIdentifier = gatekeeperIdentifier;
771 grq.IncludeOptionalField(H225_GatekeeperRequest::e_supportsAltGK);
773 OnSendGatekeeperRequest(grq);
775 discoveryComplete = FALSE;
777 return grq.m_requestSeqNum;
781 void H323Gatekeeper::OnSendGatekeeperRequest(H225_GatekeeperRequest & grq)
783 H225_RAS::OnSendGatekeeperRequest(grq);
785 for (PINDEX i = 0; i < authenticators.GetSize(); i++) {
786 if (authenticators[i].SetCapability(grq.m_authenticationCapability, grq.m_algorithmOIDs)) {
787 grq.IncludeOptionalField(H225_GatekeeperRequest::e_authenticationCapability);
788 grq.IncludeOptionalField(H225_GatekeeperRequest::e_algorithmOIDs);
794 BOOL H323Gatekeeper::OnReceiveGatekeeperConfirm(const H225_GatekeeperConfirm & gcf)
796 if (!H225_RAS::OnReceiveGatekeeperConfirm(gcf))
797 return FALSE;
799 PINDEX i;
801 for (i = 0; i < authenticators.GetSize(); i++) {
802 H235Authenticator & authenticator = authenticators[i];
803 if (authenticator.UseGkAndEpIdentifiers())
804 authenticator.SetRemoteId(gatekeeperIdentifier);
807 if (gcf.HasOptionalField(H225_GatekeeperConfirm::e_authenticationMode) &&
808 gcf.HasOptionalField(H225_GatekeeperConfirm::e_algorithmOID)) {
809 for (i = 0; i < authenticators.GetSize(); i++) {
810 H235Authenticator & authenticator = authenticators[i];
811 authenticator.Enable(authenticator.IsCapability(gcf.m_authenticationMode,
812 gcf.m_algorithmOID));
816 H323TransportAddress locatedAddress = gcf.m_rasAddress;
817 PTRACE(2, "RAS\tGatekeeper discovery found " << locatedAddress);
819 if (!transport->SetRemoteAddress(locatedAddress)) {
820 PTRACE(2, "RAS\tInvalid gatekeeper discovery address: \"" << locatedAddress << '"');
821 //return FALSE;
824 if (gcf.HasOptionalField(H225_GatekeeperConfirm::e_alternateGatekeeper))
825 SetAlternates(gcf.m_alternateGatekeeper, FALSE);
827 endpoint.OnGatekeeperConfirm();
829 discoveryComplete = TRUE;
830 return TRUE;
834 BOOL H323Gatekeeper::OnReceiveGatekeeperReject(const H225_GatekeeperReject & grj)
836 if (!H225_RAS::OnReceiveGatekeeperReject(grj))
837 return FALSE;
839 if (grj.HasOptionalField(H225_GatekeeperReject::e_altGKInfo)) {
840 SetAlternates(grj.m_altGKInfo.m_alternateGatekeeper,
841 grj.m_altGKInfo.m_altGKisPermanent);
843 if (lastRequest->responseInfo != NULL) {
844 H323TransportAddress & gkAddress = *(H323TransportAddress *)lastRequest->responseInfo;
845 gkAddress = alternates[0].rasAddress;
849 endpoint.OnGatekeeperReject();
851 return TRUE;
855 BOOL H323Gatekeeper::RegistrationRequest(BOOL autoReg)
857 if (PAssertNULL(transport) == NULL)
858 return FALSE;
860 autoReregister = autoReg;
862 H323RasPDU pdu;
863 H225_RegistrationRequest & rrq = pdu.BuildRegistrationRequest(GetNextSequenceNumber());
865 // If discoveryComplete flag is FALSE then do lightweight reregister
866 rrq.m_discoveryComplete = discoveryComplete;
868 rrq.m_rasAddress.SetSize(1);
869 transport->SetUpTransportPDU(rrq.m_rasAddress[0], TRUE);
871 H323TransportAddressArray listeners = endpoint.GetInterfaceAddresses(TRUE, transport);
872 if (listeners.IsEmpty()) {
873 PTRACE(1, "RAS\tCannot register with Gatekeeper without a H323Listener!");
874 return FALSE;
877 H323SetTransportAddresses(*transport, listeners, rrq.m_callSignalAddress);
879 endpoint.SetEndpointTypeInfo(rrq.m_terminalType);
880 endpoint.SetVendorIdentifierInfo(rrq.m_endpointVendor);
882 rrq.IncludeOptionalField(H225_RegistrationRequest::e_terminalAlias);
883 H323SetAliasAddresses(endpoint.GetAliasNames(), rrq.m_terminalAlias);
885 rrq.m_willSupplyUUIEs = TRUE;
886 rrq.IncludeOptionalField(H225_RegistrationRequest::e_usageReportingCapability);
887 rrq.m_usageReportingCapability.IncludeOptionalField(H225_RasUsageInfoTypes::e_startTime);
888 rrq.m_usageReportingCapability.IncludeOptionalField(H225_RasUsageInfoTypes::e_endTime);
889 rrq.m_usageReportingCapability.IncludeOptionalField(H225_RasUsageInfoTypes::e_terminationCause);
890 rrq.IncludeOptionalField(H225_RegistrationRequest::e_supportsAltGK);
892 if (!gatekeeperIdentifier) {
893 rrq.IncludeOptionalField(H225_RegistrationRequest::e_gatekeeperIdentifier);
894 rrq.m_gatekeeperIdentifier = gatekeeperIdentifier;
897 if (!endpointIdentifier.IsEmpty()) {
898 rrq.IncludeOptionalField(H225_RegistrationRequest::e_endpointIdentifier);
899 rrq.m_endpointIdentifier = endpointIdentifier;
902 PTimeInterval ttl = endpoint.GetGatekeeperTimeToLive();
903 if (ttl > 0) {
904 rrq.IncludeOptionalField(H225_RegistrationRequest::e_timeToLive);
905 rrq.m_timeToLive = (int)ttl.GetSeconds();
908 if (endpoint.CanDisplayAmountString()) {
909 rrq.IncludeOptionalField(H225_RegistrationRequest::e_callCreditCapability);
910 rrq.m_callCreditCapability.IncludeOptionalField(H225_CallCreditCapability::e_canDisplayAmountString);
911 rrq.m_callCreditCapability.m_canDisplayAmountString = TRUE;
914 if (endpoint.CanEnforceDurationLimit()) {
915 rrq.IncludeOptionalField(H225_RegistrationRequest::e_callCreditCapability);
916 rrq.m_callCreditCapability.IncludeOptionalField(H225_CallCreditCapability::e_canEnforceDurationLimit);
917 rrq.m_callCreditCapability.m_canEnforceDurationLimit = TRUE;
920 if (IsRegistered()) {
921 rrq.IncludeOptionalField(H225_RegistrationRequest::e_keepAlive);
922 rrq.m_keepAlive = TRUE;
925 // After doing full register, do lightweight reregisters from now on
926 discoveryComplete = FALSE;
928 Request request(rrq.m_requestSeqNum, pdu);
929 if (MakeRequest(request))
930 return TRUE;
932 PTRACE(3, "RAS\tFailed registration of " << endpointIdentifier << " with " << gatekeeperIdentifier);
933 switch (request.responseResult) {
934 case Request::RejectReceived :
935 switch (request.rejectReason) {
936 case H225_RegistrationRejectReason::e_discoveryRequired :
937 // If have been told by GK that we need to discover it again, set flag
938 // for next register done by timeToLive handler to do discovery
939 requiresDiscovery = TRUE;
940 // Do next case
942 case H225_RegistrationRejectReason::e_fullRegistrationRequired :
943 registrationFailReason = GatekeeperLostRegistration;
944 // Set timer to retry registration
945 reregisterNow = TRUE;
946 monitorTickle.Signal();
947 break;
949 // Onse below here are permananent errors, so don't try again
950 case H225_RegistrationRejectReason::e_invalidCallSignalAddress :
951 registrationFailReason = InvalidListener;
952 break;
954 case H225_RegistrationRejectReason::e_duplicateAlias :
955 registrationFailReason = DuplicateAlias;
956 break;
958 case H225_RegistrationRejectReason::e_securityDenial :
959 registrationFailReason = SecurityDenied;
960 break;
962 default :
963 registrationFailReason = (RegistrationFailReasons)(request.rejectReason|RegistrationRejectReasonMask);
964 break;
966 break;
968 case Request::BadCryptoTokens :
969 registrationFailReason = SecurityDenied;
970 break;
972 default :
973 registrationFailReason = TransportError;
974 break;
977 return FALSE;
981 BOOL H323Gatekeeper::OnReceiveRegistrationConfirm(const H225_RegistrationConfirm & rcf)
983 if (!H225_RAS::OnReceiveRegistrationConfirm(rcf))
984 return FALSE;
986 registrationFailReason = RegistrationSuccessful;
988 endpointIdentifier = rcf.m_endpointIdentifier;
989 PTRACE(3, "RAS\tRegistered " << endpointIdentifier << " with " << gatekeeperIdentifier);
992 if (rcf.HasOptionalField(H225_RegistrationConfirm::e_alternateGatekeeper))
993 SetAlternates(rcf.m_alternateGatekeeper, FALSE);
995 if (rcf.HasOptionalField(H225_RegistrationConfirm::e_timeToLive))
996 timeToLive = AdjustTimeout(rcf.m_timeToLive);
997 else
998 timeToLive = 0; // zero disables lightweight RRQ
1000 // At present only support first call signal address to GK
1001 if (rcf.m_callSignalAddress.GetSize() > 0)
1002 gkRouteAddress = rcf.m_callSignalAddress[0];
1004 willRespondToIRR = rcf.m_willRespondToIRR;
1006 pregrantMakeCall = pregrantAnswerCall = RequireARQ;
1007 if (rcf.HasOptionalField(H225_RegistrationConfirm::e_preGrantedARQ)) {
1008 if (rcf.m_preGrantedARQ.m_makeCall)
1009 pregrantMakeCall = rcf.m_preGrantedARQ.m_useGKCallSignalAddressToMakeCall
1010 ? PreGkRoutedARQ : PregrantARQ;
1011 if (rcf.m_preGrantedARQ.m_answerCall)
1012 pregrantAnswerCall = rcf.m_preGrantedARQ.m_useGKCallSignalAddressToAnswer
1013 ? PreGkRoutedARQ : PregrantARQ;
1014 if (rcf.m_preGrantedARQ.HasOptionalField(H225_RegistrationConfirm_preGrantedARQ::e_irrFrequencyInCall))
1015 SetInfoRequestRate(AdjustTimeout(rcf.m_preGrantedARQ.m_irrFrequencyInCall));
1016 else
1017 ClearInfoRequestRate();
1019 else
1020 ClearInfoRequestRate();
1022 // Remove the endpoint aliases that the gatekeeper did not like and add the
1023 // ones that it really wants us to be.
1024 if (rcf.HasOptionalField(H225_RegistrationConfirm::e_terminalAlias)) {
1025 const PStringList & currentAliases = endpoint.GetAliasNames();
1026 PStringList aliasesToChange;
1027 PINDEX i, j;
1029 for (i = 0; i < rcf.m_terminalAlias.GetSize(); i++) {
1030 PString alias = H323GetAliasAddressString(rcf.m_terminalAlias[i]);
1031 if (!alias) {
1032 for (j = 0; j < currentAliases.GetSize(); j++) {
1033 if (alias *= currentAliases[j])
1034 break;
1036 if (j >= currentAliases.GetSize())
1037 aliasesToChange.AppendString(alias);
1040 for (i = 0; i < aliasesToChange.GetSize(); i++) {
1041 PTRACE(2, "RAS\tGatekeeper add of alias \"" << aliasesToChange[i] << '"');
1042 endpoint.AddAliasName(aliasesToChange[i]);
1045 aliasesToChange.RemoveAll();
1047 for (i = 0; i < currentAliases.GetSize(); i++) {
1048 for (j = 0; j < rcf.m_terminalAlias.GetSize(); j++) {
1049 if (currentAliases[i] *= H323GetAliasAddressString(rcf.m_terminalAlias[j]))
1050 break;
1052 if (j >= rcf.m_terminalAlias.GetSize())
1053 aliasesToChange.AppendString(currentAliases[i]);
1055 for (i = 0; i < aliasesToChange.GetSize(); i++) {
1056 PTRACE(2, "RAS\tGatekeeper removal of alias \"" << aliasesToChange[i] << '"');
1057 endpoint.RemoveAliasName(aliasesToChange[i]);
1061 #ifdef H323_H248
1062 if (rcf.HasOptionalField(H225_RegistrationConfirm::e_serviceControl))
1063 OnServiceControlSessions(rcf.m_serviceControl, NULL);
1064 #endif
1066 // NAT Detection with GNUGK
1067 if (rcf.HasOptionalField(H225_RegistrationConfirm::e_nonStandardData))
1069 PString NATaddr = rcf.m_nonStandardData.m_data.AsString();
1070 if ((!NATaddr.IsEmpty()) && (NATaddr.Left(4) == "NAT="))
1071 endpoint.OnGatekeeperNATDetect(NATaddr.Right(NATaddr.GetLength()-4),endpointIdentifier,gkRouteAddress);
1074 endpoint.OnRegistrationConfirm();
1076 return TRUE;
1080 BOOL H323Gatekeeper::OnReceiveRegistrationReject(const H225_RegistrationReject & rrj)
1082 if (!H225_RAS::OnReceiveRegistrationReject(rrj))
1083 return FALSE;
1085 if (rrj.HasOptionalField(H225_RegistrationReject::e_altGKInfo))
1086 SetAlternates(rrj.m_altGKInfo.m_alternateGatekeeper,
1087 rrj.m_altGKInfo.m_altGKisPermanent);
1089 endpoint.OnRegistrationReject();
1091 return TRUE;
1095 void H323Gatekeeper::RegistrationTimeToLive()
1097 PTRACE(3, "RAS\tTime To Live reregistration");
1099 if (requiresDiscovery) {
1100 PTRACE(2, "RAS\tRepeating discovery on gatekeepers request.");
1102 H323RasPDU pdu;
1103 Request request(SetupGatekeeperRequest(pdu), pdu);
1104 if (!MakeRequest(request) || !discoveryComplete) {
1105 PTRACE(2, "RAS\tRediscovery failed, retrying in 1 minute.");
1106 timeToLive = PTimeInterval(0, 0, 1);
1107 return;
1110 requiresDiscovery = FALSE;
1113 if (!RegistrationRequest(autoReregister)) {
1114 PTRACE_IF(2, !reregisterNow, "RAS\tTime To Live reregistration failed, retrying in 1 minute");
1115 timeToLive = PTimeInterval(0, 0, 1);
1120 BOOL H323Gatekeeper::UnregistrationRequest(int reason)
1122 if (PAssertNULL(transport) == NULL)
1123 return FALSE;
1125 PINDEX i;
1126 H323RasPDU pdu;
1127 H225_UnregistrationRequest & urq = pdu.BuildUnregistrationRequest(GetNextSequenceNumber());
1129 H225_TransportAddress rasAddress;
1130 transport->SetUpTransportPDU(rasAddress, TRUE);
1132 H323SetTransportAddresses(*transport,
1133 endpoint.GetInterfaceAddresses(TRUE, transport),
1134 urq.m_callSignalAddress);
1136 urq.IncludeOptionalField(H225_UnregistrationRequest::e_endpointAlias);
1137 H323SetAliasAddresses(endpoint.GetAliasNames(), urq.m_endpointAlias);
1139 if (!gatekeeperIdentifier) {
1140 urq.IncludeOptionalField(H225_UnregistrationRequest::e_gatekeeperIdentifier);
1141 urq.m_gatekeeperIdentifier = gatekeeperIdentifier;
1144 if (!endpointIdentifier.IsEmpty()) {
1145 urq.IncludeOptionalField(H225_UnregistrationRequest::e_endpointIdentifier);
1146 urq.m_endpointIdentifier = endpointIdentifier;
1149 if (reason >= 0) {
1150 urq.IncludeOptionalField(H225_UnregistrationRequest::e_reason);
1151 urq.m_reason = reason;
1154 Request request(urq.m_requestSeqNum, pdu);
1156 BOOL requestResult = MakeRequest(request);
1158 for (i = 0; i < alternates.GetSize(); i++) {
1159 AlternateInfo & altgk = alternates[i];
1160 if (altgk.registrationState == AlternateInfo::IsRegistered) {
1161 Connect(altgk.rasAddress,altgk.gatekeeperIdentifier);
1162 UnregistrationRequest(reason);
1166 if (requestResult)
1167 return TRUE;
1169 switch (request.responseResult) {
1170 case Request::NoResponseReceived :
1171 registrationFailReason = TransportError;
1172 timeToLive = 0; // zero disables lightweight RRQ
1173 break;
1175 case Request::BadCryptoTokens :
1176 registrationFailReason = SecurityDenied;
1177 timeToLive = 0; // zero disables lightweight RRQ
1178 break;
1180 default :
1181 break;
1184 return !IsRegistered();
1188 BOOL H323Gatekeeper::OnReceiveUnregistrationConfirm(const H225_UnregistrationConfirm & ucf)
1190 if (!H225_RAS::OnReceiveUnregistrationConfirm(ucf))
1191 return FALSE;
1193 registrationFailReason = UnregisteredLocally;
1194 timeToLive = 0; // zero disables lightweight RRQ
1196 return TRUE;
1200 BOOL H323Gatekeeper::OnReceiveUnregistrationRequest(const H225_UnregistrationRequest & urq)
1202 if (!H225_RAS::OnReceiveUnregistrationRequest(urq))
1203 return FALSE;
1205 PTRACE(2, "RAS\tUnregistration received");
1206 if (!urq.HasOptionalField(H225_UnregistrationRequest::e_gatekeeperIdentifier) ||
1207 urq.m_gatekeeperIdentifier.GetValue() != gatekeeperIdentifier) {
1208 PTRACE(1, "RAS\tInconsistent gatekeeperIdentifier!");
1209 return FALSE;
1212 if (!urq.HasOptionalField(H225_UnregistrationRequest::e_endpointIdentifier) ||
1213 urq.m_endpointIdentifier.GetValue() != endpointIdentifier) {
1214 PTRACE(1, "RAS\tInconsistent endpointIdentifier!");
1215 return FALSE;
1218 endpoint.ClearAllCalls(H323Connection::EndedByGatekeeper, FALSE);
1220 PTRACE(3, "RAS\tUnregistered, calls cleared");
1221 registrationFailReason = UnregisteredByGatekeeper;
1222 timeToLive = 0; // zero disables lightweight RRQ
1224 if (urq.HasOptionalField(H225_UnregistrationRequest::e_alternateGatekeeper))
1225 SetAlternates(urq.m_alternateGatekeeper, FALSE);
1227 H323RasPDU response(authenticators);
1228 response.BuildUnregistrationConfirm(urq.m_requestSeqNum);
1229 BOOL ok = WritePDU(response);
1231 if (autoReregister) {
1232 PTRACE(3, "RAS\tReregistering by setting timeToLive");
1233 reregisterNow = TRUE;
1234 monitorTickle.Signal();
1237 return ok;
1241 BOOL H323Gatekeeper::OnReceiveUnregistrationReject(const H225_UnregistrationReject & urj)
1243 if (!H225_RAS::OnReceiveUnregistrationReject(urj))
1244 return FALSE;
1246 if (lastRequest->rejectReason != H225_UnregRejectReason::e_callInProgress) {
1247 registrationFailReason = UnregisteredLocally;
1248 timeToLive = 0; // zero disables lightweight RRQ
1251 return TRUE;
1255 BOOL H323Gatekeeper::LocationRequest(const PString & alias,
1256 H323TransportAddress & address)
1258 PStringList aliases;
1259 aliases.AppendString(alias);
1260 return LocationRequest(aliases, address);
1264 BOOL H323Gatekeeper::LocationRequest(const PStringList & aliases,
1265 H323TransportAddress & address)
1267 if (PAssertNULL(transport) == NULL)
1268 return FALSE;
1270 H323RasPDU pdu;
1271 H225_LocationRequest & lrq = pdu.BuildLocationRequest(GetNextSequenceNumber());
1273 H323SetAliasAddresses(aliases, lrq.m_destinationInfo);
1275 if (!endpointIdentifier.IsEmpty()) {
1276 lrq.IncludeOptionalField(H225_LocationRequest::e_endpointIdentifier);
1277 lrq.m_endpointIdentifier = endpointIdentifier;
1280 transport->SetUpTransportPDU(lrq.m_replyAddress, TRUE);
1282 lrq.IncludeOptionalField(H225_LocationRequest::e_sourceInfo);
1283 H323SetAliasAddresses(endpoint.GetAliasNames(), lrq.m_sourceInfo);
1285 if (!gatekeeperIdentifier) {
1286 lrq.IncludeOptionalField(H225_LocationRequest::e_gatekeeperIdentifier);
1287 lrq.m_gatekeeperIdentifier = gatekeeperIdentifier;
1290 Request request(lrq.m_requestSeqNum, pdu);
1291 request.responseInfo = &address;
1292 if (!MakeRequest(request))
1293 return FALSE;
1295 // sanity check the address - some Gks return address 0.0.0.0 and port 0
1296 PIPSocket::Address ipAddr;
1297 WORD port;
1298 return address.GetIpAndPort(ipAddr, port) && (port != 0);
1302 H323Gatekeeper::AdmissionResponse::AdmissionResponse()
1304 rejectReason = UINT_MAX;
1306 gatekeeperRouted = FALSE;
1307 endpointCount = 1;
1308 transportAddress = NULL;
1309 accessTokenData = NULL;
1311 aliasAddresses = NULL;
1312 destExtraCallInfo = NULL;
1316 struct AdmissionRequestResponseInfo {
1317 AdmissionRequestResponseInfo(
1318 H323Gatekeeper::AdmissionResponse & r,
1319 H323Connection & c
1320 ) : param(r), connection(c) { }
1322 H323Gatekeeper::AdmissionResponse & param;
1323 H323Connection & connection;
1324 unsigned allocatedBandwidth;
1325 unsigned uuiesRequested;
1326 PString accessTokenOID1;
1327 PString accessTokenOID2;
1331 BOOL H323Gatekeeper::AdmissionRequest(H323Connection & connection,
1332 AdmissionResponse & response,
1333 BOOL ignorePreGrantedARQ)
1335 BOOL answeringCall = connection.HadAnsweredCall();
1337 if (!ignorePreGrantedARQ) {
1338 switch (answeringCall ? pregrantAnswerCall : pregrantMakeCall) {
1339 case RequireARQ :
1340 break;
1341 case PregrantARQ :
1342 return TRUE;
1343 case PreGkRoutedARQ :
1344 if (gkRouteAddress.IsEmpty()) {
1345 response.rejectReason = UINT_MAX;
1346 return FALSE;
1348 if (response.transportAddress != NULL)
1349 *response.transportAddress = gkRouteAddress;
1350 response.gatekeeperRouted = TRUE;
1351 return TRUE;
1355 H323RasPDU pdu;
1356 H225_AdmissionRequest & arq = pdu.BuildAdmissionRequest(GetNextSequenceNumber());
1358 arq.m_callType.SetTag(H225_CallType::e_pointToPoint);
1359 arq.m_endpointIdentifier = endpointIdentifier;
1360 arq.m_answerCall = answeringCall;
1361 arq.m_canMapAlias = TRUE; // Stack supports receiving a different number in the ACF
1362 // to the one sent in the ARQ
1363 arq.m_willSupplyUUIEs = TRUE;
1365 if (!gatekeeperIdentifier) {
1366 arq.IncludeOptionalField(H225_AdmissionRequest::e_gatekeeperIdentifier);
1367 arq.m_gatekeeperIdentifier = gatekeeperIdentifier;
1370 PString destInfo = connection.GetRemotePartyName();
1371 arq.m_srcInfo.SetSize(1);
1372 if (answeringCall) {
1373 H323SetAliasAddress(destInfo, arq.m_srcInfo[0]);
1374 if (!connection.GetLocalPartyName()) {
1375 arq.IncludeOptionalField(H225_AdmissionRequest::e_destinationInfo);
1376 H323SetAliasAddresses(connection.GetLocalAliasNames(), arq.m_destinationInfo);
1379 else {
1380 H323SetAliasAddresses(connection.GetLocalAliasNames(), arq.m_srcInfo);
1381 if (response.transportAddress == NULL || destInfo != *response.transportAddress) {
1382 arq.IncludeOptionalField(H225_AdmissionRequest::e_destinationInfo);
1383 arq.m_destinationInfo.SetSize(1);
1384 H323SetAliasAddress(destInfo, arq.m_destinationInfo[0]);
1388 const H323Transport * signallingChannel = connection.GetSignallingChannel();
1389 if (answeringCall) {
1390 arq.IncludeOptionalField(H225_AdmissionRequest::e_srcCallSignalAddress);
1391 signallingChannel->SetUpTransportPDU(arq.m_srcCallSignalAddress, FALSE);
1392 arq.IncludeOptionalField(H225_AdmissionRequest::e_destCallSignalAddress);
1393 signallingChannel->SetUpTransportPDU(arq.m_destCallSignalAddress, TRUE);
1395 else {
1396 if (signallingChannel != NULL && signallingChannel->IsOpen()) {
1397 arq.IncludeOptionalField(H225_AdmissionRequest::e_srcCallSignalAddress);
1398 signallingChannel->SetUpTransportPDU(arq.m_srcCallSignalAddress, TRUE);
1400 if (response.transportAddress != NULL && !response.transportAddress->IsEmpty()) {
1401 arq.IncludeOptionalField(H225_AdmissionRequest::e_destCallSignalAddress);
1402 response.transportAddress->SetPDU(arq.m_destCallSignalAddress);
1406 arq.m_bandWidth = connection.GetBandwidthAvailable();
1407 arq.m_callReferenceValue = connection.GetCallReference();
1408 arq.m_conferenceID = connection.GetConferenceIdentifier();
1409 arq.m_callIdentifier.m_guid = connection.GetCallIdentifier();
1411 connection.SetCallLinkage(pdu);
1413 AdmissionRequestResponseInfo info(response, connection);
1414 info.accessTokenOID1 = connection.GetGkAccessTokenOID();
1415 PINDEX comma = info.accessTokenOID1.Find(',');
1416 if (comma == P_MAX_INDEX)
1417 info.accessTokenOID2 = info.accessTokenOID1;
1418 else {
1419 info.accessTokenOID2 = info.accessTokenOID1.Mid(comma+1);
1420 info.accessTokenOID1.Delete(comma, P_MAX_INDEX);
1423 connection.OnSendARQ(arq);
1425 Request request(arq.m_requestSeqNum, pdu);
1426 request.responseInfo = &info;
1428 if (!authenticators.IsEmpty()) {
1429 pdu.Prepare(arq.m_tokens, H225_AdmissionRequest::e_tokens,
1430 arq.m_cryptoTokens, H225_AdmissionRequest::e_cryptoTokens);
1432 H235Authenticators adjustedAuthenticators;
1433 if (connection.GetAdmissionRequestAuthentication(arq, adjustedAuthenticators)) {
1434 PTRACE(3, "RAS\tAuthenticators credentials replaced with \""
1435 << setfill(',') << adjustedAuthenticators << setfill(' ') << "\" during ARQ");
1437 for (PINDEX i = 0; i < adjustedAuthenticators.GetSize(); i++) {
1438 H235Authenticator & authenticator = adjustedAuthenticators[i];
1439 if (authenticator.UseGkAndEpIdentifiers())
1440 authenticator.SetRemoteId(gatekeeperIdentifier);
1443 adjustedAuthenticators.PreparePDU(pdu,
1444 arq.m_tokens, H225_AdmissionRequest::e_tokens,
1445 arq.m_cryptoTokens, H225_AdmissionRequest::e_cryptoTokens);
1446 pdu.SetAuthenticators(adjustedAuthenticators);
1450 if (!MakeRequest(request)) {
1451 response.rejectReason = request.rejectReason;
1453 // See if we are registered.
1454 if (request.responseResult == Request::RejectReceived &&
1455 response.rejectReason != H225_AdmissionRejectReason::e_callerNotRegistered &&
1456 response.rejectReason != H225_AdmissionRejectReason::e_invalidEndpointIdentifier)
1457 return FALSE;
1459 PTRACE(2, "RAS\tEndpoint has become unregistered during ARQ from gatekeeper " << gatekeeperIdentifier);
1461 // Have been told we are not registered (or gk offline)
1462 switch (request.responseResult) {
1463 case Request::NoResponseReceived :
1464 registrationFailReason = TransportError;
1465 response.rejectReason = UINT_MAX;
1466 break;
1468 case Request::BadCryptoTokens :
1469 registrationFailReason = SecurityDenied;
1470 response.rejectReason = H225_AdmissionRejectReason::e_securityDenial;
1471 break;
1473 default :
1474 registrationFailReason = GatekeeperLostRegistration;
1477 // If we are not registered and auto register is set ...
1478 if (!autoReregister)
1479 return FALSE;
1481 // Then immediately reregister.
1482 if (!RegistrationRequest(autoReregister))
1483 return FALSE;
1485 // Reset the gk info in ARQ
1486 arq.m_endpointIdentifier = endpointIdentifier;
1487 if (!gatekeeperIdentifier) {
1488 arq.IncludeOptionalField(H225_AdmissionRequest::e_gatekeeperIdentifier);
1489 arq.m_gatekeeperIdentifier = gatekeeperIdentifier;
1491 else
1492 arq.RemoveOptionalField(H225_AdmissionRequest::e_gatekeeperIdentifier);
1494 // Is new request so need new sequence number as well.
1495 arq.m_requestSeqNum = GetNextSequenceNumber();
1496 request.sequenceNumber = arq.m_requestSeqNum;
1498 if (!MakeRequest(request)) {
1499 response.rejectReason = request.responseResult == Request::RejectReceived
1500 ? request.rejectReason : UINT_MAX;
1502 return FALSE;
1506 connection.SetBandwidthAvailable(info.allocatedBandwidth);
1507 connection.SetUUIEsRequested(info.uuiesRequested);
1509 return TRUE;
1513 void H323Gatekeeper::OnSendAdmissionRequest(H225_AdmissionRequest & /*arq*/)
1515 // Override default function as it sets crypto tokens and this is really
1516 // done by the AdmissionRequest() function.
1520 static unsigned GetUUIEsRequested(const H225_UUIEsRequested & pdu)
1522 unsigned uuiesRequested = 0;
1524 if ((BOOL)pdu.m_setup)
1525 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_setup);
1526 if ((BOOL)pdu.m_callProceeding)
1527 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_callProceeding);
1528 if ((BOOL)pdu.m_connect)
1529 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_connect);
1530 if ((BOOL)pdu.m_alerting)
1531 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_alerting);
1532 if ((BOOL)pdu.m_information)
1533 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_information);
1534 if ((BOOL)pdu.m_releaseComplete)
1535 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_releaseComplete);
1536 if ((BOOL)pdu.m_facility)
1537 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_facility);
1538 if ((BOOL)pdu.m_progress)
1539 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_progress);
1540 if ((BOOL)pdu.m_empty)
1541 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_empty);
1543 if (pdu.HasOptionalField(H225_UUIEsRequested::e_status) && (BOOL)pdu.m_status)
1544 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_status);
1545 if (pdu.HasOptionalField(H225_UUIEsRequested::e_statusInquiry) && (BOOL)pdu.m_statusInquiry)
1546 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_statusInquiry);
1547 if (pdu.HasOptionalField(H225_UUIEsRequested::e_setupAcknowledge) && (BOOL)pdu.m_setupAcknowledge)
1548 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_setupAcknowledge);
1549 if (pdu.HasOptionalField(H225_UUIEsRequested::e_notify) && (BOOL)pdu.m_notify)
1550 uuiesRequested |= (1<<H225_H323_UU_PDU_h323_message_body::e_notify);
1552 return uuiesRequested;
1556 static void ExtractToken(const AdmissionRequestResponseInfo & info,
1557 const H225_ArrayOf_ClearToken & tokens,
1558 PBYTEArray & accessTokenData)
1560 if (!info.accessTokenOID1 && tokens.GetSize() > 0) {
1561 PTRACE(4, "Looking for OID " << info.accessTokenOID1 << " in ACF to copy.");
1562 for (PINDEX i = 0; i < tokens.GetSize(); i++) {
1563 if (tokens[i].m_tokenOID == info.accessTokenOID1) {
1564 PTRACE(4, "Looking for OID " << info.accessTokenOID2 << " in token to copy.");
1565 if (tokens[i].HasOptionalField(H235_ClearToken::e_nonStandard) &&
1566 tokens[i].m_nonStandard.m_nonStandardIdentifier == info.accessTokenOID2) {
1567 PTRACE(4, "Copying ACF nonStandard OctetString.");
1568 accessTokenData = tokens[i].m_nonStandard.m_data;
1569 break;
1577 BOOL H323Gatekeeper::OnReceiveAdmissionConfirm(const H225_AdmissionConfirm & acf)
1579 if (!H225_RAS::OnReceiveAdmissionConfirm(acf))
1580 return FALSE;
1582 AdmissionRequestResponseInfo & info = *(AdmissionRequestResponseInfo *)lastRequest->responseInfo;
1583 info.allocatedBandwidth = acf.m_bandWidth;
1584 if (info.param.transportAddress != NULL)
1585 *info.param.transportAddress = acf.m_destCallSignalAddress;
1587 info.param.gatekeeperRouted = acf.m_callModel.GetTag() == H225_CallModel::e_gatekeeperRouted;
1589 // Remove the endpoint aliases that the gatekeeper did not like and add the
1590 // ones that it really wants us to be.
1591 if (info.param.aliasAddresses != NULL &&
1592 acf.HasOptionalField(H225_AdmissionConfirm::e_destinationInfo)) {
1593 PTRACE(3, "RAS\tGatekeeper specified " << acf.m_destinationInfo.GetSize() << " aliases in ACF");
1594 *info.param.aliasAddresses = acf.m_destinationInfo;
1597 if (acf.HasOptionalField(H225_AdmissionConfirm::e_uuiesRequested))
1598 info.uuiesRequested = GetUUIEsRequested(acf.m_uuiesRequested);
1600 if (info.param.destExtraCallInfo != NULL &&
1601 acf.HasOptionalField(H225_AdmissionConfirm::e_destExtraCallInfo))
1602 *info.param.destExtraCallInfo = acf.m_destExtraCallInfo;
1604 if (info.param.accessTokenData != NULL && acf.HasOptionalField(H225_AdmissionConfirm::e_tokens))
1605 ExtractToken(info, acf.m_tokens, *info.param.accessTokenData);
1607 if (info.param.transportAddress != NULL) {
1608 PINDEX count = 1;
1609 for (PINDEX i = 0; i < acf.m_alternateEndpoints.GetSize() && count < info.param.endpointCount; i++) {
1610 if (acf.m_alternateEndpoints[i].HasOptionalField(H225_Endpoint::e_callSignalAddress) &&
1611 acf.m_alternateEndpoints[i].m_callSignalAddress.GetSize() > 0) {
1612 info.param.transportAddress[count] = acf.m_alternateEndpoints[i].m_callSignalAddress[0];
1613 if (info.param.accessTokenData != NULL)
1614 ExtractToken(info, acf.m_alternateEndpoints[i].m_tokens, info.param.accessTokenData[count]);
1615 count++;
1618 info.param.endpointCount = count;
1621 if (acf.HasOptionalField(H225_AdmissionConfirm::e_irrFrequency))
1622 SetInfoRequestRate(AdjustTimeout(acf.m_irrFrequency));
1623 willRespondToIRR = acf.m_willRespondToIRR;
1625 #ifdef H323_H248
1626 if (acf.HasOptionalField(H225_AdmissionConfirm::e_serviceControl))
1627 OnServiceControlSessions(acf.m_serviceControl, &info.connection);
1628 #endif
1630 return TRUE;
1634 BOOL H323Gatekeeper::OnReceiveAdmissionReject(const H225_AdmissionReject & arj)
1636 if (!H225_RAS::OnReceiveAdmissionReject(arj))
1637 return FALSE;
1639 #ifdef H323_H248
1640 if (arj.HasOptionalField(H225_AdmissionConfirm::e_serviceControl))
1641 OnServiceControlSessions(arj.m_serviceControl,
1642 &((AdmissionRequestResponseInfo *)lastRequest->responseInfo)->connection);
1643 #endif
1645 return TRUE;
1649 static void SetRasUsageInformation(const H323Connection & connection,
1650 H225_RasUsageInformation & usage)
1652 unsigned time = connection.GetAlertingTime().GetTimeInSeconds();
1653 if (time != 0) {
1654 usage.IncludeOptionalField(H225_RasUsageInformation::e_alertingTime);
1655 usage.m_alertingTime = time;
1658 time = connection.GetConnectionStartTime().GetTimeInSeconds();
1659 if (time != 0) {
1660 usage.IncludeOptionalField(H225_RasUsageInformation::e_connectTime);
1661 usage.m_connectTime = time;
1664 time = connection.GetConnectionEndTime().GetTimeInSeconds();
1665 if (time != 0) {
1666 usage.IncludeOptionalField(H225_RasUsageInformation::e_endTime);
1667 usage.m_endTime = time;
1672 BOOL H323Gatekeeper::DisengageRequest(const H323Connection & connection, unsigned reason)
1674 H323RasPDU pdu;
1675 H225_DisengageRequest & drq = pdu.BuildDisengageRequest(GetNextSequenceNumber());
1677 drq.m_endpointIdentifier = endpointIdentifier;
1678 drq.m_conferenceID = connection.GetConferenceIdentifier();
1679 drq.m_callReferenceValue = connection.GetCallReference();
1680 drq.m_callIdentifier.m_guid = connection.GetCallIdentifier();
1681 drq.m_disengageReason.SetTag(reason);
1682 drq.m_answeredCall = connection.HadAnsweredCall();
1684 drq.IncludeOptionalField(H225_DisengageRequest::e_usageInformation);
1685 SetRasUsageInformation(connection, drq.m_usageInformation);
1687 drq.IncludeOptionalField(H225_DisengageRequest::e_terminationCause);
1688 drq.m_terminationCause.SetTag(H225_CallTerminationCause::e_releaseCompleteReason);
1689 Q931::CauseValues cause = H323TranslateFromCallEndReason(connection, drq.m_terminationCause);
1690 if (cause != Q931::ErrorInCauseIE) {
1691 drq.m_terminationCause.SetTag(H225_CallTerminationCause::e_releaseCompleteCauseIE);
1692 PASN_OctetString & rcReason = drq.m_terminationCause;
1693 rcReason.SetSize(2);
1694 rcReason[0] = 0x80;
1695 rcReason[1] = (BYTE)(0x80|cause);
1698 if (!gatekeeperIdentifier) {
1699 drq.IncludeOptionalField(H225_DisengageRequest::e_gatekeeperIdentifier);
1700 drq.m_gatekeeperIdentifier = gatekeeperIdentifier;
1703 Request request(drq.m_requestSeqNum, pdu);
1704 return MakeRequestWithReregister(request, H225_DisengageRejectReason::e_notRegistered);
1708 BOOL H323Gatekeeper::OnReceiveDisengageRequest(const H225_DisengageRequest & drq)
1710 if (!H225_RAS::OnReceiveDisengageRequest(drq))
1711 return FALSE;
1713 OpalGloballyUniqueID id = NULL;
1714 if (drq.HasOptionalField(H225_DisengageRequest::e_callIdentifier))
1715 id = drq.m_callIdentifier.m_guid;
1716 if (id == NULL)
1717 id = drq.m_conferenceID;
1719 H323RasPDU response(authenticators);
1720 H323Connection * connection = endpoint.FindConnectionWithLock(id.AsString());
1721 if (connection == NULL)
1722 response.BuildDisengageReject(drq.m_requestSeqNum,
1723 H225_DisengageRejectReason::e_requestToDropOther);
1724 else {
1725 H225_DisengageConfirm & dcf = response.BuildDisengageConfirm(drq.m_requestSeqNum);
1727 dcf.IncludeOptionalField(H225_DisengageConfirm::e_usageInformation);
1728 SetRasUsageInformation(*connection, dcf.m_usageInformation);
1730 connection->ClearCall(H323Connection::EndedByGatekeeper);
1731 connection->Unlock();
1734 #ifdef H323_H248
1735 if (drq.HasOptionalField(H225_DisengageRequest::e_serviceControl))
1736 OnServiceControlSessions(drq.m_serviceControl, connection);
1737 #endif
1739 return WritePDU(response);
1743 BOOL H323Gatekeeper::BandwidthRequest(H323Connection & connection,
1744 unsigned requestedBandwidth)
1746 H323RasPDU pdu;
1747 H225_BandwidthRequest & brq = pdu.BuildBandwidthRequest(GetNextSequenceNumber());
1749 brq.m_endpointIdentifier = endpointIdentifier;
1750 brq.m_conferenceID = connection.GetConferenceIdentifier();
1751 brq.m_callReferenceValue = connection.GetCallReference();
1752 brq.m_callIdentifier.m_guid = connection.GetCallIdentifier();
1753 brq.m_bandWidth = requestedBandwidth;
1754 brq.IncludeOptionalField(H225_BandwidthRequest::e_usageInformation);
1755 SetRasUsageInformation(connection, brq.m_usageInformation);
1757 Request request(brq.m_requestSeqNum, pdu);
1759 unsigned allocatedBandwidth;
1760 request.responseInfo = &allocatedBandwidth;
1762 if (!MakeRequestWithReregister(request, H225_BandRejectReason::e_notBound))
1763 return FALSE;
1765 connection.SetBandwidthAvailable(allocatedBandwidth);
1766 return TRUE;
1770 BOOL H323Gatekeeper::OnReceiveBandwidthConfirm(const H225_BandwidthConfirm & bcf)
1772 if (!H225_RAS::OnReceiveBandwidthConfirm(bcf))
1773 return FALSE;
1775 if (lastRequest->responseInfo != NULL)
1776 *(unsigned *)lastRequest->responseInfo = bcf.m_bandWidth;
1778 return TRUE;
1782 BOOL H323Gatekeeper::OnReceiveBandwidthRequest(const H225_BandwidthRequest & brq)
1784 if (!H225_RAS::OnReceiveBandwidthRequest(brq))
1785 return FALSE;
1787 OpalGloballyUniqueID id = brq.m_callIdentifier.m_guid;
1788 H323Connection * connection = endpoint.FindConnectionWithLock(id.AsString());
1790 H323RasPDU response(authenticators);
1791 if (connection == NULL)
1792 response.BuildBandwidthReject(brq.m_requestSeqNum,
1793 H225_BandRejectReason::e_invalidConferenceID);
1794 else {
1795 if (connection->SetBandwidthAvailable(brq.m_bandWidth))
1796 response.BuildBandwidthConfirm(brq.m_requestSeqNum, brq.m_bandWidth);
1797 else
1798 response.BuildBandwidthReject(brq.m_requestSeqNum,
1799 H225_BandRejectReason::e_insufficientResources);
1800 connection->Unlock();
1803 return WritePDU(response);
1807 void H323Gatekeeper::SetInfoRequestRate(const PTimeInterval & rate)
1809 if (rate < infoRequestRate.GetResetTime() || infoRequestRate.GetResetTime() == 0) {
1810 // Have to be sneaky here becuase we do not want to actually change the
1811 // amount of time to run on the timer.
1812 PTimeInterval timeToGo = infoRequestRate;
1813 infoRequestRate = rate;
1814 if (rate > timeToGo)
1815 infoRequestRate.PTimeInterval::operator=(timeToGo);
1820 void H323Gatekeeper::ClearInfoRequestRate()
1822 // Only reset rate to zero (disabled) if no calls present
1823 if (endpoint.GetAllConnections().IsEmpty())
1824 infoRequestRate = 0;
1828 H225_InfoRequestResponse & H323Gatekeeper::BuildInfoRequestResponse(H323RasPDU & response,
1829 unsigned seqNum)
1831 H225_InfoRequestResponse & irr = response.BuildInfoRequestResponse(seqNum);
1833 endpoint.SetEndpointTypeInfo(irr.m_endpointType);
1834 irr.m_endpointIdentifier = endpointIdentifier;
1835 transport->SetUpTransportPDU(irr.m_rasAddress, TRUE);
1836 H323SetTransportAddresses(*transport,
1837 endpoint.GetInterfaceAddresses(TRUE, transport),
1838 irr.m_callSignalAddress);
1840 irr.IncludeOptionalField(H225_InfoRequestResponse::e_endpointAlias);
1841 H323SetAliasAddresses(endpoint.GetAliasNames(), irr.m_endpointAlias);
1843 return irr;
1847 BOOL H323Gatekeeper::SendUnsolicitedIRR(H225_InfoRequestResponse & irr,
1848 H323RasPDU & response)
1850 irr.m_unsolicited = TRUE;
1852 if (willRespondToIRR) {
1853 PTRACE(4, "RAS\tSending unsolicited IRR and awaiting acknowledgement");
1854 Request request(irr.m_requestSeqNum, response);
1855 return MakeRequest(request);
1858 PTRACE(4, "RAS\tSending unsolicited IRR and without acknowledgement");
1859 response.SetAuthenticators(authenticators);
1860 return WritePDU(response);
1864 static void AddInfoRequestResponseCall(H225_InfoRequestResponse & irr,
1865 const H323Connection & connection)
1867 irr.IncludeOptionalField(H225_InfoRequestResponse::e_perCallInfo);
1869 PINDEX sz = irr.m_perCallInfo.GetSize();
1870 if (!irr.m_perCallInfo.SetSize(sz+1))
1871 return;
1873 H225_InfoRequestResponse_perCallInfo_subtype & info = irr.m_perCallInfo[sz];
1875 info.m_callReferenceValue = connection.GetCallReference();
1876 info.m_callIdentifier.m_guid = connection.GetCallIdentifier();
1877 info.m_conferenceID = connection.GetConferenceIdentifier();
1878 info.IncludeOptionalField(H225_InfoRequestResponse_perCallInfo_subtype::e_originator);
1879 info.m_originator = !connection.HadAnsweredCall();
1881 H323_RTP_Session * session = connection.GetSessionCallbacks(RTP_Session::DefaultAudioSessionID);
1882 if (session != NULL) {
1883 info.IncludeOptionalField(H225_InfoRequestResponse_perCallInfo_subtype::e_audio);
1884 info.m_audio.SetSize(1);
1885 session->OnSendRasInfo(info.m_audio[0]);
1888 session = connection.GetSessionCallbacks(RTP_Session::DefaultVideoSessionID);
1889 if (session != NULL) {
1890 info.IncludeOptionalField(H225_InfoRequestResponse_perCallInfo_subtype::e_video);
1891 info.m_video.SetSize(1);
1892 session->OnSendRasInfo(info.m_video[0]);
1895 const H323Transport & controlChannel = connection.GetControlChannel();
1896 controlChannel.SetUpTransportPDU(info.m_h245.m_recvAddress, TRUE);
1897 controlChannel.SetUpTransportPDU(info.m_h245.m_sendAddress, FALSE);
1899 info.m_callType.SetTag(H225_CallType::e_pointToPoint);
1900 info.m_bandWidth = connection.GetBandwidthUsed();
1901 info.m_callModel.SetTag(connection.IsGatekeeperRouted() ? H225_CallModel::e_gatekeeperRouted
1902 : H225_CallModel::e_direct);
1904 info.IncludeOptionalField(H225_InfoRequestResponse_perCallInfo_subtype::e_usageInformation);
1905 SetRasUsageInformation(connection, info.m_usageInformation);
1909 static BOOL AddAllInfoRequestResponseCall(H225_InfoRequestResponse & irr,
1910 H323EndPoint & endpoint,
1911 const PStringList & tokens)
1913 BOOL addedOne = FALSE;
1915 for (PINDEX i = 0; i < tokens.GetSize(); i++) {
1916 H323Connection * connection = endpoint.FindConnectionWithLock(tokens[i]);
1917 if (connection != NULL) {
1918 AddInfoRequestResponseCall(irr, *connection);
1919 connection->Unlock();
1920 addedOne = TRUE;
1924 return addedOne;
1928 void H323Gatekeeper::InfoRequestResponse()
1930 PStringList tokens = endpoint.GetAllConnections();
1931 if (tokens.IsEmpty())
1932 return;
1934 H323RasPDU response;
1935 H225_InfoRequestResponse & irr = BuildInfoRequestResponse(response, GetNextSequenceNumber());
1937 if (AddAllInfoRequestResponseCall(irr, endpoint, tokens))
1938 SendUnsolicitedIRR(irr, response);
1942 void H323Gatekeeper::InfoRequestResponse(const H323Connection & connection)
1944 H323RasPDU response;
1945 H225_InfoRequestResponse & irr = BuildInfoRequestResponse(response, GetNextSequenceNumber());
1947 AddInfoRequestResponseCall(irr, connection);
1949 SendUnsolicitedIRR(irr, response);
1953 void H323Gatekeeper::InfoRequestResponse(const H323Connection & connection,
1954 const H225_H323_UU_PDU & pdu,
1955 BOOL sent)
1957 // Are unknown Q.931 PDU
1958 if (pdu.m_h323_message_body.GetTag() == P_MAX_INDEX)
1959 return;
1961 // Check mask of things to report on
1962 if ((connection.GetUUIEsRequested() & (1<<pdu.m_h323_message_body.GetTag())) == 0)
1963 return;
1965 PTRACE(3, "RAS\tSending unsolicited IRR for requested UUIE");
1967 // Report the PDU
1968 H323RasPDU response;
1969 H225_InfoRequestResponse & irr = BuildInfoRequestResponse(response, GetNextSequenceNumber());
1971 AddInfoRequestResponseCall(irr, connection);
1973 irr.m_perCallInfo[0].IncludeOptionalField(H225_InfoRequestResponse_perCallInfo_subtype::e_pdu);
1974 irr.m_perCallInfo[0].m_pdu.SetSize(1);
1975 irr.m_perCallInfo[0].m_pdu[0].m_sent = sent;
1976 irr.m_perCallInfo[0].m_pdu[0].m_h323pdu = pdu;
1978 SendUnsolicitedIRR(irr, response);
1982 BOOL H323Gatekeeper::OnReceiveInfoRequest(const H225_InfoRequest & irq)
1984 if (!H225_RAS::OnReceiveInfoRequest(irq))
1985 return FALSE;
1987 H323RasPDU response(authenticators);
1988 H225_InfoRequestResponse & irr = BuildInfoRequestResponse(response, irq.m_requestSeqNum);
1990 if (irq.m_callReferenceValue == 0) {
1991 if (!AddAllInfoRequestResponseCall(irr, endpoint, endpoint.GetAllConnections())) {
1992 irr.IncludeOptionalField(H225_InfoRequestResponse::e_irrStatus);
1993 irr.m_irrStatus.SetTag(H225_InfoRequestResponseStatus::e_invalidCall);
1996 else {
1997 OpalGloballyUniqueID id = irq.m_callIdentifier.m_guid;
1998 H323Connection * connection = endpoint.FindConnectionWithLock(id.AsString());
1999 if (connection == NULL) {
2000 irr.IncludeOptionalField(H225_InfoRequestResponse::e_irrStatus);
2001 irr.m_irrStatus.SetTag(H225_InfoRequestResponseStatus::e_invalidCall);
2003 else {
2004 if (irq.HasOptionalField(H225_InfoRequest::e_uuiesRequested))
2005 connection->SetUUIEsRequested(::GetUUIEsRequested(irq.m_uuiesRequested));
2007 AddInfoRequestResponseCall(irr, *connection);
2009 connection->Unlock();
2013 if (!irq.HasOptionalField(H225_InfoRequest::e_replyAddress))
2014 return WritePDU(response);
2016 H323TransportAddress replyAddress = irq.m_replyAddress;
2017 if (replyAddress.IsEmpty())
2018 return FALSE;
2020 H323TransportAddress oldAddress = transport->GetRemoteAddress();
2022 BOOL ok = transport->ConnectTo(replyAddress) && WritePDU(response);
2024 transport->ConnectTo(oldAddress);
2026 return ok;
2029 #ifdef H323_H248
2031 BOOL H323Gatekeeper::OnReceiveServiceControlIndication(const H225_ServiceControlIndication & sci)
2033 if (!H225_RAS::OnReceiveServiceControlIndication(sci))
2034 return FALSE;
2036 H323Connection * connection = NULL;
2038 if (sci.HasOptionalField(H225_ServiceControlIndication::e_callSpecific)) {
2039 OpalGloballyUniqueID id = sci.m_callSpecific.m_callIdentifier.m_guid;
2040 if (id.IsNULL())
2041 id = sci.m_callSpecific.m_conferenceID;
2042 connection = endpoint.FindConnectionWithLock(id.AsString());
2045 OnServiceControlSessions(sci.m_serviceControl, connection);
2048 H323RasPDU response(authenticators);
2049 response.BuildServiceControlResponse(sci.m_requestSeqNum);
2050 return WritePDU(response);
2054 void H323Gatekeeper::OnServiceControlSessions(const H225_ArrayOf_ServiceControlSession & serviceControl,
2055 H323Connection * connection)
2057 for (PINDEX i = 0; i < serviceControl.GetSize(); i++) {
2058 H225_ServiceControlSession & pdu = serviceControl[i];
2060 H323ServiceControlSession * session = NULL;
2061 unsigned sessionId = pdu.m_sessionId;
2063 if (serviceControlSessions.Contains(sessionId)) {
2064 session = &serviceControlSessions[sessionId];
2065 if (pdu.HasOptionalField(H225_ServiceControlSession::e_contents)) {
2066 if (!session->OnReceivedPDU(pdu.m_contents)) {
2067 PTRACE(2, "SvcCtrl\tService control for session has changed!");
2068 session = NULL;
2073 if (session == NULL && pdu.HasOptionalField(H225_ServiceControlSession::e_contents)) {
2074 session = endpoint.CreateServiceControlSession(pdu.m_contents);
2075 serviceControlSessions.SetAt(sessionId, session);
2078 if (session != NULL)
2079 endpoint.OnServiceControlSession(sessionId, pdu.m_reason.GetTag(), *session, connection);
2083 #endif // H323_H248
2086 void H323Gatekeeper::SetPassword(const PString & password,
2087 const PString & username)
2089 PString localId = username;
2090 if (localId.IsEmpty())
2091 localId = endpoint.GetLocalUserName();
2093 for (PINDEX i = 0; i < authenticators.GetSize(); i++) {
2094 authenticators[i].SetLocalId(localId);
2095 authenticators[i].SetPassword(password);
2100 void H323Gatekeeper::MonitorMain(PThread &, INT)
2102 PTRACE(3, "RAS\tBackground thread started");
2104 for (;;) {
2105 monitorTickle.Wait();
2106 if (monitorStop)
2107 break;
2109 if (reregisterNow ||
2110 (!timeToLive.IsRunning() && timeToLive.GetResetTime() > 0)) {
2111 RegistrationTimeToLive();
2112 timeToLive.Reset();
2115 if (!infoRequestRate.IsRunning() && infoRequestRate.GetResetTime() > 0) {
2116 InfoRequestResponse();
2117 infoRequestRate.Reset();
2121 PTRACE(3, "RAS\tBackground thread ended");
2125 void H323Gatekeeper::TickleMonitor(PTimer &, INT)
2127 monitorTickle.Signal();
2131 void H323Gatekeeper::SetAlternates(const H225_ArrayOf_AlternateGK & alts, BOOL permanent)
2133 PINDEX i;
2135 if (!alternatePermanent) {
2136 // don't want to replace alternates gatekeepers if this is an alternate and it's not permanent
2137 for (i = 0; i < alternates.GetSize(); i++) {
2138 if (transport->GetRemoteAddress().IsEquivalent(alternates[i].rasAddress) &&
2139 gatekeeperIdentifier == alternates[i].gatekeeperIdentifier)
2140 return;
2144 alternates.RemoveAll();
2145 for (i = 0; i < alts.GetSize(); i++) {
2146 AlternateInfo * alt = new AlternateInfo(alts[i]);
2147 if (alt->rasAddress.IsEmpty())
2148 delete alt;
2149 else
2150 alternates.Append(alt);
2153 alternatePermanent = permanent;
2155 PTRACE(3, "RAS\tSet alternate gatekeepers:\n"
2156 << setfill('\n') << alternates << setfill(' '));
2160 BOOL H323Gatekeeper::MakeRequestWithReregister(Request & request, unsigned unregisteredTag)
2162 if (MakeRequest(request))
2163 return TRUE;
2165 if (request.responseResult == Request::RejectReceived &&
2166 request.rejectReason != unregisteredTag)
2167 return FALSE;
2169 PTRACE(2, "RAS\tEndpoint has become unregistered from gatekeeper " << gatekeeperIdentifier);
2171 // Have been told we are not registered (or gk offline)
2172 switch (request.responseResult) {
2173 case Request::NoResponseReceived :
2174 registrationFailReason = TransportError;
2175 break;
2177 case Request::BadCryptoTokens :
2178 registrationFailReason = SecurityDenied;
2179 break;
2181 default :
2182 registrationFailReason = GatekeeperLostRegistration;
2185 // If we are not registered and auto register is set ...
2186 if (!autoReregister)
2187 return FALSE;
2189 reregisterNow = TRUE;
2190 monitorTickle.Signal();
2191 return FALSE;
2195 void H323Gatekeeper::Connect(const H323TransportAddress & address,
2196 const PString & gkid)
2198 if (transport == NULL)
2199 transport = new H323TransportUDP(endpoint, PIPSocket::GetDefaultIpAny());
2201 transport->SetRemoteAddress(address);
2202 transport->Connect();
2203 gatekeeperIdentifier = gkid;
2207 BOOL H323Gatekeeper::MakeRequest(Request & request)
2209 if (PAssertNULL(transport) == NULL)
2210 return FALSE;
2212 // Set authenticators if not already set by caller
2213 requestMutex.Wait();
2215 if (request.requestPDU.GetAuthenticators().IsEmpty())
2216 request.requestPDU.SetAuthenticators(authenticators);
2218 /* To be sure that the H323 Cleaner, H225 Caller or Monitor don't set the
2219 transport address of the alternate while the other is in timeout. We
2220 have to block the function */
2222 H323TransportAddress tempAddr = transport->GetRemoteAddress();
2223 PString tempIdentifier = gatekeeperIdentifier;
2225 PINDEX alt = 0;
2226 for (;;) {
2227 if (H225_RAS::MakeRequest(request)) {
2228 if (!alternatePermanent &&
2229 (transport->GetRemoteAddress() != tempAddr ||
2230 gatekeeperIdentifier != tempIdentifier))
2231 Connect(tempAddr, tempIdentifier);
2232 requestMutex.Signal();
2233 return TRUE;
2236 if (request.responseResult != Request::NoResponseReceived &&
2237 request.responseResult != Request::TryAlternate) {
2238 // try alternate in those cases and see if it's successful
2239 requestMutex.Signal();
2240 return FALSE;
2243 AlternateInfo * altInfo;
2244 PIPSocket::Address localAddress;
2245 WORD localPort;
2246 do {
2247 if (alt >= alternates.GetSize()) {
2248 if (!alternatePermanent)
2249 Connect(tempAddr,tempIdentifier);
2250 requestMutex.Signal();
2251 return FALSE;
2254 altInfo = &alternates[alt++];
2255 transport->GetLocalAddress().GetIpAndPort(localAddress,localPort);
2256 transport->CleanUpOnTermination();
2257 delete transport;
2259 transport = new H323TransportUDP(endpoint,localAddress,localPort);
2260 transport->SetRemoteAddress (altInfo->rasAddress);
2261 transport->Connect();
2262 gatekeeperIdentifier = altInfo->gatekeeperIdentifier;
2263 StartChannel();
2264 } while (altInfo->registrationState == AlternateInfo::RegistrationFailed);
2266 if (altInfo->registrationState == AlternateInfo::NeedToRegister) {
2267 altInfo->registrationState = AlternateInfo::RegistrationFailed;
2268 registrationFailReason = TransportError;
2269 discoveryComplete = FALSE;
2270 H323RasPDU pdu;
2271 Request req(SetupGatekeeperRequest(pdu), pdu);
2273 if (H225_RAS::MakeRequest(req)) {
2274 requestMutex.Signal(); // avoid deadlock...
2275 if (RegistrationRequest(autoReregister)) {
2276 altInfo->registrationState = AlternateInfo::IsRegistered;
2277 // The wanted registration is done, we can return
2278 if (request.requestPDU.GetChoice().GetTag() == H225_RasMessage::e_registrationRequest) {
2279 if (!alternatePermanent)
2280 Connect(tempAddr,tempIdentifier);
2281 return TRUE;
2284 requestMutex.Wait();
2291 H323Gatekeeper::AlternateInfo::AlternateInfo(H225_AlternateGK & alt)
2292 : rasAddress(alt.m_rasAddress),
2293 gatekeeperIdentifier(alt.m_gatekeeperIdentifier.GetValue()),
2294 priority(alt.m_priority)
2296 registrationState = alt.m_needToRegister ? NeedToRegister : NoRegistrationNeeded;
2300 H323Gatekeeper::AlternateInfo::~AlternateInfo ()
2306 PObject::Comparison H323Gatekeeper::AlternateInfo::Compare(const PObject & obj)
2308 PAssert(PIsDescendant(&obj, H323Gatekeeper), PInvalidCast);
2309 unsigned otherPriority = ((const AlternateInfo & )obj).priority;
2310 if (priority < otherPriority)
2311 return LessThan;
2312 if (priority > otherPriority)
2313 return GreaterThan;
2314 return EqualTo;
2318 void H323Gatekeeper::AlternateInfo::PrintOn(ostream & strm) const
2320 if (!gatekeeperIdentifier)
2321 strm << gatekeeperIdentifier << '@';
2323 strm << rasAddress;
2325 if (priority > 0)
2326 strm << ";priority=" << priority;
2329 BOOL H323Gatekeeper::OnSendFeatureSet(unsigned pduType, H225_FeatureSet & feats) const
2331 #ifdef H323_H460
2332 return features.SendFeature(pduType, feats);
2333 #else
2334 return endpoint.OnSendFeatureSet(pduType, feats);
2335 #endif
2338 void H323Gatekeeper::OnReceiveFeatureSet(unsigned pduType, const H225_FeatureSet & feats) const
2340 #ifdef H323_H460
2341 features.ReceiveFeature(pduType, feats);
2342 #else
2343 endpoint.OnReceiveFeatureSet(pduType, feats);
2344 #endif
2347 /////////////////////////////////////////////////////////////////////////////