1 /*
2  * h323ep.cxx
3  *
4  * H.323 protocol handler
5  *
6  * H323Plus Library
7  *
8  * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Open H323 Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Portions of this code were written with the assisance of funding from
25  * Vovida Networks, Inc. http://www.vovida.com.
26  *
27  * Contributor(s): ______________________________________.
28  *
29  * $Id$
30  *
31  */
32 
33 #include <ptlib.h>
34 #include <ptlib/sound.h>
35 
36 #ifdef __GNUC__
37 #pragma implementation "h323ep.h"
38 #endif
39 
40 #include "openh323buildopts.h"
41 
42 #include "h323ep.h"
43 #include "h323pdu.h"
44 
45 #ifdef H323_H235
46 #include "h235/h2356.h"
47 #endif
48 
49 #ifdef H323_H450
50 #include "h450/h450pdu.h"
51 #endif
52 
53 #ifdef H323_H460
54 #include "h460/h460.h"
55 #include "h225.h"
56 
57 #ifdef H323_H4609
58 #include "h460/h460_std9.h"
59 #endif
60 
61 #ifdef H323_H46017
62 #include "h460/h460_std17.h"
63 #endif
64 
65 #ifdef H323_H46018
66 #include "h460/h460_std18.h"
67 #include "h460/h46018_h225.h"
68 #endif
69 
70 #ifdef H323_TLS
71 #include "h460/h460_std22.h"
72 #endif
73 
74 #ifdef H323_H46023
75 #include "h460/h460_std23.h"
76 #endif
77 
78 #ifdef H323_H46025
79 #include "h460/h460_std25.h"
80 #endif
81 
82 #ifdef H323_H46026
83 #include "h460/h460_std26.h"
84 #endif
85 
86 #ifdef H323_UPnP
87 #include "h460/upnpcp.h"
88 #endif
89 
90 #ifdef H323_H460IM
91 #include "h460/h460_oid1.h"
92 #endif
93 
94 #ifdef H323_H460P
95 #include "h460/h460_oid3.h"
96 #endif
97 
98 #ifdef H323_H460PRE
99 #include "h460/h460_oid6.h"
100 #endif
101 
102 #ifdef H323_H460COM
103 #include "h460/h460_oid9.h"
104 #endif
105 
106 #endif  // H323_H460
107 
108 #include "gkclient.h"
109 
110 #ifdef H323_T38
111 #include "t38proto.h"
112 #endif
113 
114 #include "../version.h"
115 #include "h323pluginmgr.h"
116 
117 #include <ptlib/sound.h>
118 #include <ptclib/random.h>
119 #include <ptclib/pstun.h>
120 #include <ptclib/url.h>
121 #include <ptclib/pils.h>
122 #include <ptclib/enum.h>
123 
124 #ifdef H323_FILE
125 #include "h323filetransfer.h"
126 #endif
127 
128 #ifdef H323_GNUGK
129 #include "gnugknat.h"
130 #endif
131 
132 
133 #if defined(H323_RTP_AGGREGATE) || defined(H323_SIGNAL_AGGREGATE)
134 #include <ptclib/sockagg.h>
135 #endif
136 
137 #ifndef IPTOS_PREC_CRITIC_ECP
138 #define IPTOS_PREC_CRITIC_ECP (5 << 5)
139 #endif
140 
141 #ifndef IPTOS_LOWDELAY
142 #define IPTOS_LOWDELAY 0x10
143 #endif
144 
145 #include "opalglobalstatics.cxx"
146 #include <algorithm>
147 
148 //////////////////////////////////////////////////////////////////////////////////////
149 
150 BYTE H323EndPoint::defaultT35CountryCode    = 9; // Country code for Australia
151 BYTE H323EndPoint::defaultT35Extension      = 0;
152 WORD H323EndPoint::defaultManufacturerCode  = 61; // Allocated by Australian Communications Authority, Oct 2000;
153 
154 //////////////////////////////////////////////////////////////////////////////////////
155 // TLS Context (This may be moved later on to its own file) - SH
156 #ifdef H323_TLS
157 
158 extern "C" {
159 #include <openssl/opensslv.h>
160 #include <openssl/ssl.h>
161 #include <openssl/err.h>
162 #include <openssl/rand.h>
163 }
164 
tls_info_cb(const SSL * s,int where,int ret)165 void tls_info_cb(const SSL * s, int where, int ret)
166 {
167     const char * str = NULL;
168     int w = where & ~SSL_ST_MASK;
169 
170     if (w & SSL_ST_CONNECT) str = "Connect";
171     else if (w & SSL_ST_ACCEPT) str = "Accept";
172     else str = "Undefined";
173 
174     if (where & SSL_CB_LOOP) {
175         PTRACE(6, "TLS\t" << str << ": " << SSL_state_string_long(s));
176     } else if (where & SSL_CB_ALERT) {
177         str = (where & SSL_CB_READ)?"Read":"Write";
178         PTRACE(6, "TLS\tSSL3 alert " <<	str << ": " << SSL_alert_type_string_long(ret) << ":" << SSL_alert_desc_string_long(ret));
179     } else if (where & SSL_CB_EXIT) {
180         if (ret == 0)
181             PTRACE(6, str << ":failed in " << SSL_state_string_long(s));
182         else if (ret < 0) {
183             // Do nothing...
184         }
185     }
186 }
187 
tls_passwd_cb(char * buf,int size,int rwflag,void * password)188 int tls_passwd_cb(char * buf, int size, int rwflag, void * password)
189 {
190     strncpy(buf, (char *)(password), size);
191     buf[size - 1] = '\0';
192     return(strlen(buf));
193 }
194 
tls_verify_cb(int ok,X509_STORE_CTX * store)195 int tls_verify_cb(int ok, X509_STORE_CTX * store)
196 {
197     if (!ok) {
198         char data[256];
199         X509 * cert = X509_STORE_CTX_get_current_cert(store);
200         int depth = X509_STORE_CTX_get_error_depth(store);
201         int err = X509_STORE_CTX_get_error(store);
202 
203         PTRACE(6, "TLS\tError with certificate at depth " << depth);
204         X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
205         PTRACE(6, "TLS\t  issuer  = " << data);
206         X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
207         PTRACE(6, "TLS\t  subject = " << data);
208         PTRACE(6, "TLS\t  err " << err << ": " << X509_verify_cert_error_string(err));
209     }
210     return ok;
211 }
212 
213 class H323_TLSContext : public PSSLContext
214 {
215   public:
216 
217     /**Create a new context for SSL channels.
218     */
219     H323_TLSContext();
220 
221     /**Set CA File.
222     */
223     PBoolean UseCAFile(const PFilePath & caFile);
224 
225     /**Use CA Directory.
226     */
227     PBoolean UseCADirectory(const PDirectory & certDir);
228 
229     /**Set CA Certificate.
230     */
231     PBoolean AddCACertificate(const PString & caData);
232 
233     /**Set User Certificate
234     */
235     PBoolean UseCertificate(const PFilePath & certFile);
236 
237     /**Set Private key
238     */
239     PBoolean UsePrivateKey(const PFilePath & privFile, const PString & password);
240 
241     /**Set custom DiffieHellman parameters from a PEM encoded PKCS#3 file
242     */
243     PBoolean SetDHParameters(const PFilePath & pkcs3);
244 
245     /**Set custom DiffieHellman parameters from implemeter
246     */
247     PBoolean SetDHParameters(const PBYTEArray & dh_p, const PBYTEArray & dh_g);
248 
249     /**Initialise Context
250     */
251     PBoolean Initialise();
252 
253   protected:
254     PBoolean        m_useCA;
255 
256 };
257 
H323_TLSContext()258 H323_TLSContext::H323_TLSContext()
259 : m_useCA(false)
260 {
261     // delete the default PTLIB context
262 #if PTLIB_VER < 2120
263     ssl_ctx_st * m_context = context;
264 #endif
265 
266     if (m_context) {
267         SSL_CTX_free(m_context);
268         m_context = NULL;
269     }
270 
271     m_context = SSL_CTX_new(SSLv23_method());
272     SSL_CTX_set_options(m_context, SSL_OP_NO_SSLv2);	// remove unsafe SSLv2 (eg. due to DROWN)
273     SSL_CTX_set_options(m_context, SSL_OP_NO_SSLv3);	// remove unsafe SSLv3 (eg. due to POODLE)
274     SSL_CTX_set_options(m_context, SSL_OP_NO_COMPRESSION);	// remove unsafe SSL compression (eg. due to CRIME)
275     SSL_CTX_set_mode(m_context, SSL_MODE_AUTO_RETRY);   // handle re-negotiations automatically
276 
277 #if PTLIB_VER < 2120
278     context = m_context;
279 #endif
280 
281     // no anonymous DH (ADH), no <= 64 bit (LOW), no export ciphers (EXP), no MD5 + RC4, no elliptic curve ciphers (ECDH + ECDSA)
282     PString cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:!RC4:!ECDH:!ECDSA:@STRENGTH";
283     SetCipherList(cipherList);
284     SSL_CTX_set_info_callback(m_context, tls_info_cb);
285 }
286 
UseCAFile(const PFilePath & caFile)287 PBoolean H323_TLSContext::UseCAFile(const PFilePath & caFile)
288 {
289     if (!PFile::Exists(caFile)) {
290         PTRACE(1, "TLS\tInvalid CA file path " << caFile);
291         return false;
292     }
293 
294 #if PTLIB_VER < 2120
295     ssl_ctx_st * m_context = context;
296 #endif
297     if (SSL_CTX_load_verify_locations(m_context, caFile, NULL) != 1) {
298         char msg[256];
299         PTRACE(1, "TLS\tError loading CA file " << caFile);
300         ERR_error_string(ERR_get_error(), msg);
301         PTRACE(1, "TLS\tOpenSSL error: " << msg);
302         return false;
303     }
304     m_useCA = SSL_CTX_set_default_verify_paths(m_context);
305     return m_useCA;
306 }
307 
UseCADirectory(const PDirectory & certDir)308 PBoolean H323_TLSContext::UseCADirectory(const PDirectory & certDir)
309 {
310 #if PTLIB_VER < 2120
311     ssl_ctx_st * m_context = context;
312 #endif
313     if (SSL_CTX_load_verify_locations(m_context, NULL, certDir) != 1) {
314 		char msg[256];
315         PTRACE(1, "TLS\tError setting CA directory " << certDir);
316         ERR_error_string(ERR_get_error(), msg);
317         PTRACE(1, "TLS\tOpenSSL error: " << msg);
318         return false;
319     }
320     m_useCA = SSL_CTX_set_default_verify_paths(m_context);
321     return m_useCA;
322 }
323 
AddCACertificate(const PString & caData)324 PBoolean H323_TLSContext::AddCACertificate(const PString & caData)
325 {
326     if (!m_useCA)
327         return false;
328 
329 #if PTLIB_VER < 2120
330     ssl_ctx_st * m_context = context;
331 #endif
332     BIO *mem = BIO_new(BIO_s_mem());
333     BIO_puts(mem, caData);
334     X509 *x = PEM_read_bio_X509_AUX(mem,NULL,NULL,NULL);
335     if (!x) {
336         PTRACE(1, "TLS\tBad Certificate read " << caData);
337         BIO_free(mem);
338         return false;
339     }
340     X509_STORE *store = SSL_CTX_get_cert_store(m_context);
341     if (!store) {
342         PTRACE(1, "TLS\tCould not access certificate store.");
343         X509_free(x);
344         BIO_free(mem);
345         return false;
346     }
347     if (!X509_STORE_add_cert(store, x)) {
348         PTRACE(1, "TLS\tCould not add certificate to store.");
349         X509_free(x);
350         BIO_free(mem);
351         return false;
352     }
353     X509_free(x);
354     BIO_free(mem);
355     return true;
356 }
357 
UseCertificate(const PFilePath & certFile)358 PBoolean H323_TLSContext::UseCertificate(const PFilePath & certFile)
359 {
360     if (!PFile::Exists(certFile)) {
361         PTRACE(1, "TLS\tInvalid certificate file path " << certFile);
362         return false;
363     }
364 #if PTLIB_VER < 2120
365     ssl_ctx_st * m_context = context;
366 #endif
367     if (SSL_CTX_use_certificate_chain_file(m_context, certFile) != 1) {
368     	char msg[256];
369         PTRACE(1, "TLS\tError loading certificate file: " << certFile);
370         ERR_error_string(ERR_get_error(), msg);
371         PTRACE(1, "TLS\tOpenSSL error: " << msg);
372         return false;
373     }
374     return true;
375 }
376 
UsePrivateKey(const PFilePath & privFile,const PString & password)377 PBoolean H323_TLSContext::UsePrivateKey(const PFilePath & privFile, const PString & password)
378 {
379     if (!PFile::Exists(privFile)) {
380         PTRACE(1, "TLS\tInvalid Private Key file" << privFile);
381         return false;
382     }
383 
384 #if PTLIB_VER < 2120
385     ssl_ctx_st * m_context = context;
386 #endif
387     if (!password) {
388         SSL_CTX_set_default_passwd_cb(m_context, tls_passwd_cb);
389         SSL_CTX_set_default_passwd_cb_userdata(m_context, (void *)(const char *)password);
390     }
391 
392     if (SSL_CTX_use_PrivateKey_file(m_context, privFile, SSL_FILETYPE_PEM) != 1) {
393     	char msg[256];
394         PTRACE(1, "TLS\tError loading private key file: " << privFile);
395         ERR_error_string(ERR_get_error(), msg);
396         PTRACE(1, "TLS\tOpenSSL error: " << msg);
397         return false;
398     }
399     return true;
400 }
401 
SetDHParameters(const PFilePath & pkcs3)402 PBoolean H323_TLSContext::SetDHParameters(const PFilePath & pkcs3)
403 {
404 
405  DH *dh = NULL;
406  FILE *paramfile;
407  paramfile = fopen(pkcs3, "r");
408  if (paramfile) {
409    dh = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
410    fclose(paramfile);
411  } else {
412    return false;
413  }
414  if (dh == NULL)
415     return false;
416 
417 #if PTLIB_VER < 2120
418  ssl_ctx_st * m_context = context;
419 #endif
420 
421  if (SSL_CTX_set_tmp_dh(m_context, dh) != 1) {
422     DH_free(dh);
423     return false;
424  }
425 
426  SSL_CTX_set_options(m_context, SSL_OP_SINGLE_DH_USE);  // Generate a new DH Session key on every connection
427  return true;
428 }
429 
SetDHParameters(const PBYTEArray & dh_p,const PBYTEArray & dh_g)430 PBoolean H323_TLSContext::SetDHParameters(const PBYTEArray & dh_p, const PBYTEArray & dh_g)
431 {
432   DH *dh = DH_new();
433   if (dh == NULL) {
434     PTRACE(2, "TLS\tFailed to allocate DH");
435     return false;
436   };
437 
438   BIGNUM* p = BN_bin2bn(dh_p, dh_p.GetSize(), NULL);
439   BIGNUM* g = BN_bin2bn(dh_g, dh_g.GetSize(), NULL);
440   if (p != NULL && g != NULL)
441   {
442 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
443     dh->p = p;
444     dh->g = g;
445 #else
446     if (!DH_set0_pqg(dh, p, NULL, g)) {
447       BN_free(g);
448       BN_free(p);
449       DH_free(dh);
450       return false;
451     }
452 #endif
453   }
454   else {
455     if (g)
456       BN_free(g);
457     if (p)
458       BN_free(p);
459     DH_free(dh);
460     return false;
461   }
462 
463 #if PTLIB_VER < 2120
464   ssl_ctx_st * m_context = context;
465 #endif
466 
467  if (SSL_CTX_set_tmp_dh(m_context, dh) != 1) {
468     DH_free(dh);
469     return false;
470  }
471 
472  SSL_CTX_set_options(m_context, SSL_OP_SINGLE_DH_USE);  // Generate a new DH Session key on every connection
473  return true;
474 }
475 
Initialise()476 PBoolean H323_TLSContext::Initialise()
477 {
478 #if PTLIB_VER < 2120
479     ssl_ctx_st * m_context = context;
480 #endif
481 
482     if (!m_useCA) {
483         SSL_CTX_set_verify(m_context, SSL_VERIFY_NONE, tls_verify_cb);
484         PTRACE(4, "TLS\tInitialised: WARNING! No Peer verification (Local Cert Authority missing)");
485     } else {
486         SSL_CTX_set_verify(m_context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
487         PTRACE(4, "TLS\tInitialised: Peer Certificate required.");
488     }
489 	SSL_CTX_set_verify_depth(m_context, 5);
490     return true;
491 }
492 
493 #else
494 
495   #ifdef _MSC_VER
496     #pragma message("TLS support DISABLED (missing OpenSSL)")
497   #endif
498 
499 #endif
500 
501 /////////////////////////////////////////////////////////////////////////////////////
502 
503 class H225CallThread : public PThread
504 {
505   PCLASSINFO(H225CallThread, PThread)
506 
507   public:
508     H225CallThread(H323EndPoint & endpoint,
509                    H323Connection & connection,
510                    H323Transport & transport,
511                    const PString & alias,
512                    const H323TransportAddress & address);
513 
514   protected:
515     void Main();
516 
517     H323Connection     & connection;
518     H323Transport      & transport;
519     PString              alias;
520     H323TransportAddress address;
521 #ifdef H323_SIGNAL_AGGREGATE
522     PBoolean                 useAggregator;
523 #endif
524 };
525 
526 
527 class H323ConnectionsCleaner : public PThread
528 {
529   PCLASSINFO(H323ConnectionsCleaner, PThread)
530 
531   public:
532     H323ConnectionsCleaner(H323EndPoint & endpoint);
533     ~H323ConnectionsCleaner();
534 
Signal()535     void Signal() { wakeupFlag.Signal(); }
536 
537   protected:
538     void Main();
539 
540     H323EndPoint & endpoint;
541     PBoolean           stopFlag;
542     PSyncPoint     wakeupFlag;
543 };
544 
545 
546 #define new PNEW
547 
548 
549 /////////////////////////////////////////////////////////////////////////////
550 
OpalGetVersion()551 PString OpalGetVersion()
552 {
553 #define AlphaCode   "alpha"
554 #define BetaCode    "beta"
555 #define ReleaseCode "."
556 
557   return psprintf("%u.%u%s%u", MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER);
558 }
559 
560 
OpalGetMajorVersion()561 unsigned OpalGetMajorVersion()
562 {
563   return MAJOR_VERSION;
564 }
565 
OpalGetMinorVersion()566 unsigned OpalGetMinorVersion()
567 {
568   return MINOR_VERSION;
569 }
570 
OpalGetBuildNumber()571 unsigned OpalGetBuildNumber()
572 {
573   return BUILD_NUMBER;
574 }
575 
576 
577 
578 /////////////////////////////////////////////////////////////////////////////
579 
H225CallThread(H323EndPoint & endpoint,H323Connection & c,H323Transport & t,const PString & a,const H323TransportAddress & addr)580 H225CallThread::H225CallThread(H323EndPoint & endpoint,
581                                H323Connection & c,
582                                H323Transport & t,
583                                const PString & a,
584                                const H323TransportAddress & addr)
585   : PThread(endpoint.GetSignallingThreadStackSize(),
586             NoAutoDeleteThread,
587             NormalPriority,
588             "H225 Caller:%0x"),
589     connection(c),
590     transport(t),
591     alias(a),
592     address(addr)
593 {
594 #ifdef H323_SIGNAL_AGGREGATE
595   useAggregator = endpoint.GetSignallingAggregator() != NULL;
596   if (!useAggregator)
597 #endif
598   {
599     transport.AttachThread(this);
600   }
601 
602   Resume();
603 }
604 
605 
Main()606 void H225CallThread::Main()
607 {
608   PTRACE(3, "H225\tStarted call thread");
609 
610   if (connection.Lock()) {
611     H323Connection::CallEndReason reason = connection.SendSignalSetup(alias, address);
612 
613     // Special case, if we aborted the call then already will be unlocked
614     if (reason != H323Connection::EndedByCallerAbort)
615       connection.Unlock();
616 
617     // Check if had an error, clear call if so
618     if (reason != H323Connection::NumCallEndReasons)
619       connection.ClearCall(reason);
620     else {
621 #ifdef H323_SIGNAL_AGGREGATE
622       if (useAggregator) {
623         connection.AggregateSignalChannel(&transport);
624         SetAutoDelete(AutoDeleteThread);
625         return;
626       }
627 #endif
628       connection.HandleSignallingChannel();
629     }
630   }
631 }
632 
633 
634 /////////////////////////////////////////////////////////////////////////////
635 
H323ConnectionsCleaner(H323EndPoint & ep)636 H323ConnectionsCleaner::H323ConnectionsCleaner(H323EndPoint & ep)
637   : PThread(ep.GetCleanerThreadStackSize(),
638             NoAutoDeleteThread,
639             NormalPriority,
640             "H323 Cleaner"),
641     endpoint(ep)
642 {
643   Resume();
644   stopFlag = FALSE;
645 }
646 
647 
~H323ConnectionsCleaner()648 H323ConnectionsCleaner::~H323ConnectionsCleaner()
649 {
650   stopFlag = TRUE;
651   wakeupFlag.Signal();
652   PAssert(WaitForTermination(10000), "Cleaner thread did not terminate");
653 }
654 
655 
Main()656 void H323ConnectionsCleaner::Main()
657 {
658   PTRACE(3, "H323\tStarted cleaner thread");
659 
660   for (;;) {
661     wakeupFlag.Wait();
662     if (stopFlag)
663       break;
664 
665     endpoint.CleanUpConnections();
666   }
667 
668   PTRACE(3, "H323\tStopped cleaner thread");
669 }
670 
671 
672 /////////////////////////////////////////////////////////////////////////////
673 
H323EndPoint()674 H323EndPoint::H323EndPoint()
675   :
676 #ifdef H323_AUDIO_CODECS
677 #ifdef P_AUDIO
678     soundChannelPlayDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Player)),
679     soundChannelRecordDevice(PSoundChannel::GetDefaultDevice(PSoundChannel::Recorder)),
680 #endif
681 #endif
682     signallingChannelConnectTimeout(0, 10, 0), // seconds
683     signallingChannelCallTimeout(0, 0, 1),  // Minutes
684     controlChannelStartTimeout(0, 0, 2),    // Minutes
685     endSessionTimeout(0, 3),                // Seconds
686     masterSlaveDeterminationTimeout(0, 30), // Seconds
687     capabilityExchangeTimeout(0, 30),       // Seconds
688     logicalChannelTimeout(0, 30),           // Seconds
689     requestModeTimeout(0, 30),              // Seconds
690     roundTripDelayTimeout(0, 10),           // Seconds
691     roundTripDelayRate(0, 0, 1),            // Minutes
692     noMediaTimeout(0, 0, 5),                // Minutes
693     gatekeeperRequestTimeout(0, 5),         // Seconds
694     rasRequestTimeout(0, 3),                // Seconds
695     registrationTimeToLive(0, 0, 1)         // Minutes
696 
697 #ifdef H323_H450
698     ,
699     callTransferT1(0,10),                   // Seconds
700     callTransferT2(0,10),                   // Seconds
701     callTransferT3(0,10),                   // Seconds
702     callTransferT4(0,10),                   // Seconds
703     callIntrusionT1(0,30),                  // Seconds
704     callIntrusionT2(0,30),                  // Seconds
705     callIntrusionT3(0,30),                  // Seconds
706     callIntrusionT4(0,30),                  // Seconds
707     callIntrusionT5(0,10),                  // Seconds
708     callIntrusionT6(0,10),                   // Seconds
709     nextH450CallIdentity(0)
710 #endif
711 
712 {
713   PString username = PProcess::Current().GetUserName();
714   if (username.IsEmpty())
715     username = PProcess::Current().GetName() & "User";
716   localAliasNames.AppendString(username);
717 
718 #if defined(P_AUDIO) && defined(_WIN32)
719   PString DefaultAudioDriver = "WindowsMultimedia";
720   SetSoundChannelPlayDriver(DefaultAudioDriver);
721   SetSoundChannelRecordDriver(DefaultAudioDriver);
722 #endif
723 
724 #ifdef H323_AUDIO_CODECS
725   autoStartReceiveAudio = autoStartTransmitAudio = TRUE;
726 #endif
727 
728 #ifdef H323_VIDEO
729   autoStartReceiveVideo = autoStartTransmitVideo = TRUE;
730 
731 #ifdef H323_H239
732   autoStartReceiveExtVideo = autoStartTransmitExtVideo = FALSE;
733 #endif
734 #endif
735 
736 #ifdef H323_T38
737   autoStartReceiveFax = autoStartTransmitFax = FALSE;
738 #endif
739 
740 #ifdef H323_AUDIO_CODECS
741   minAudioJitterDelay = 50;  // milliseconds
742   maxAudioJitterDelay = 250;  // milliseconds
743 #endif
744 
745   autoCallForward = true;
746   disableFastStart = true;
747   disableH245Tunneling = false;
748   disableH245inSetup = true;
749   disableH245QoS = true;
750   disableDetectInBandDTMF = false;
751   disableRFC2833InBandDTMF = false;
752   disableExtendedUserInput = true;
753   canDisplayAmountString = false;
754   canEnforceDurationLimit = true;
755   useQ931Display = false;
756 
757 #ifdef H323_H450
758   callIntrusionProtectionLevel = 3; //H45011_CIProtectionLevel::e_fullProtection;
759 
760   mwiMsgCentre = PString();
761 #endif
762 
763 #ifdef H323_AUDIO_CODECS
764   defaultSilenceDetection = H323AudioCodec::NoSilenceDetection;  //AdaptiveSilenceDetection; TODO Till Encryption fixed
765 #endif
766 
767   defaultSendUserInputMode = H323Connection::SendUserInputAsString;
768 
769   terminalType = e_TerminalOnly;
770   rewriteParsePartyName = true;
771   initialBandwidth = 100000; // Standard 10base LAN in 100's of bits/sec
772   clearCallOnRoundTripFail = FALSE;
773 
774   t35CountryCode   = defaultT35CountryCode;   // Country code for Australia
775   t35Extension     = defaultT35Extension;
776   manufacturerCode = defaultManufacturerCode; // Allocated by Australian Communications Authority, Oct 2000
777 
778   rtpIpPorts.current = rtpIpPorts.base = 5001;
779   rtpIpPorts.max = 5999;
780 
781   // use dynamic port allocation by default
782   tcpPorts.current = tcpPorts.base = tcpPorts.max = 0;
783   udpPorts.current = udpPorts.base = udpPorts.max = 0;
784 
785 #ifdef P_STUN
786   natMethods = new H323NatStrategy();
787 #endif
788 
789 #ifdef H323_H46019M
790   defaultMultiRTPPort = 2776;
791   rtpMuxID.current = rtpMuxID.base = PRandom::Number(999900);
792   rtpMuxID.max   = (unsigned)1000000;
793 #endif
794 
795 #ifdef _WIN32
796 
797 #  if defined(H323_AUDIO_CODECS) && defined(P_AUDIO)
798      // Windows MultiMedia stuff seems to need greater depth due to enormous
799      // latencies in its operation, need to use DirectSound maybe?
800      // for Win2000 and XP you need 5, for Vista you need 10! so set to 10! -SH
801      soundChannelBuffers = 10;
802 #  endif
803 
804   rtpIpTypeofService = IPTOS_PREC_CRITIC_ECP|IPTOS_LOWDELAY;
805 
806 #else
807 
808 #  ifdef H323_AUDIO_CODECS
809 #ifdef P_AUDIO
810      // Should only need double buffering for Unix platforms
811      soundChannelBuffers = 2;
812 #endif
813 #  endif
814 
815   // Don't use IPTOS_PREC_CRITIC_ECP on Unix platforms as then need to be root
816   rtpIpTypeofService = IPTOS_LOWDELAY;
817 
818 #endif
819   tcpIpTypeofService = IPTOS_LOWDELAY;
820 
821   masterSlaveDeterminationRetries = 10;
822   gatekeeperRequestRetries = 2;
823   rasRequestRetries = 2;
824   sendGRQ = TRUE;
825 
826   cleanerThreadStackSize    = 30000;
827   listenerThreadStackSize   = 30000;
828   signallingThreadStackSize = 30000;
829   controlThreadStackSize    = 30000;
830   logicalThreadStackSize    = 30000;
831   rasThreadStackSize        = 30000;
832   jitterThreadStackSize     = 30000;
833   useJitterBuffer            = true;
834 
835 #ifdef H323_SIGNAL_AGGREGATE
836   signallingAggregationSize = 25;
837   signallingAggregator = NULL;
838 #endif
839 
840 #ifdef H323_RTP_AGGREGATE
841   rtpAggregationSize        = 10;
842   rtpAggregator = NULL;
843 #endif
844 
845   channelThreadPriority     = PThread::HighestPriority;
846 
847   gatekeeper = NULL;
848   RegThread = NULL;
849 
850   connectionsActive.DisallowDeleteObjects();
851 
852 #ifdef H323_H450
853   secondaryConnectionsActive.DisallowDeleteObjects();
854 #endif
855 
856   connectionsCleaner = new H323ConnectionsCleaner(*this);
857 
858   srand((unsigned)time(NULL)+clock());
859 
860   SetEPSecurityPolicy(SecNone);
861   SetEPCredentials(PString(),PString());
862   isSecureCall = FALSE;
863   m_disableMD5Authenticators = FALSE;
864 
865 #ifdef H323_H460
866   disableH460 = false;
867 
868 #ifdef H323_H46017
869   m_tryingH46017 = false;           // set to true when attempting H.460.17
870   m_registeredWithH46017 = false;   // set to true when gatekeeper accepts it
871   m_h46017Transport = NULL;
872 #endif
873 
874 #ifdef H323_H46018
875   m_h46018enabled = true;
876 #endif
877 
878 #ifdef H323_H46019M
879   m_h46019Menabled = true;
880   m_h46019Msend = false;
881 #endif
882 
883 #ifdef H323_H46023
884   m_h46023enabled = true;
885 #endif
886 
887 #ifdef H323_H46023
888   m_h46025enabled = false;
889 #endif
890 
891 #ifdef H323_H46026
892   m_h46026enabled = true;
893 #endif
894 
895 #ifdef H323_UPnP
896   m_UPnPenabled = false;
897 #endif
898 
899 #ifdef H323_H460IM
900   m_IMenabled   = false;
901   m_IMcall      = false;
902   m_IMsession   = false;
903   m_IMwriteevent = false;
904   m_IMmsg       = PString();
905 #endif
906 
907 #ifdef H323_H460P
908   presenceHandler = NULL;
909 #endif
910 
911 #ifdef H323_H460PRE
912     m_regPrior=0;
913     m_preempt=false;
914     m_preempted=false;
915 #endif
916 
917 #ifdef H323_H461
918    m_ASSETEnabled=false;
919    m_h461ASSETMode=e_H461Disabled;
920    m_h461DataStore=NULL;
921 #endif
922 
923 #endif
924 
925 #ifdef H323_AEC
926   enableAEC = false;
927 #endif
928 
929 #ifdef H323_GNUGK
930   gnugk = NULL;
931 #endif
932 
933 #ifdef H323_TLS
934   m_transportContext = NULL;
935 #endif
936 
937 #ifdef H323_FRAMEBUFFER
938   useVideoBuffer = false;
939 #endif
940 
941   m_useH225KeepAlive = PFalse;
942   m_useH245KeepAlive = PFalse;
943 
944   PTRACE(3, "H323\tCreated endpoint.");
945 }
946 
947 
~H323EndPoint()948 H323EndPoint::~H323EndPoint()
949 {
950 
951 #if defined(H323_RTP_AGGREGATE) || defined (H323_SIGNAL_AGGREGATE)
952   // delete aggregators
953   {
954     PWaitAndSignal m(connectionsMutex);
955 #ifdef H323_RTP_AGGREGATE
956     if (rtpAggregator != NULL) {
957       delete rtpAggregator;
958       rtpAggregator = NULL;
959     }
960 #endif
961 #ifdef H323_SIGNAL_AGGREGATE
962     if (signallingAggregator != NULL) {
963       delete signallingAggregator;
964       signallingAggregator = NULL;
965     }
966 #endif
967   }
968 #endif
969 
970   // And shut down the gatekeeper (if there was one)
971   RemoveGatekeeper();
972 
973 #ifdef H323_GNUGK
974   delete gnugk;
975 #endif
976 
977   // Shut down the listeners as soon as possible to avoid race conditions
978   listeners.RemoveAll();
979 
980   // Clear any pending calls on this endpoint
981   ClearAllCalls();
982 
983   // Shut down the cleaner thread
984   delete connectionsCleaner;
985 
986   // Clean up any connections that the cleaner thread missed
987   CleanUpConnections();
988 
989 #ifdef H323_TLS
990   if (m_transportContext) {
991     delete m_transportContext;
992   }
993   // OpenSSL Cleanup
994   EVP_cleanup();
995   CRYPTO_cleanup_all_ex_data();
996 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
997   ERR_remove_thread_state(NULL);
998 #endif
999   ERR_free_strings();
1000 #endif
1001 
1002 #ifdef P_STUN
1003   delete natMethods;
1004 #endif
1005 
1006 #ifdef H323_H460P
1007   delete presenceHandler;
1008 #endif
1009 
1010 #ifdef H323_H461
1011   delete m_h461DataStore;
1012 #endif
1013 
1014   PTRACE(3, "H323\tDeleted endpoint.");
1015 }
1016 
1017 
SetEndpointTypeInfo(H225_EndpointType & info) const1018 void H323EndPoint::SetEndpointTypeInfo(H225_EndpointType & info) const
1019 {
1020   info.IncludeOptionalField(H225_EndpointType::e_vendor);
1021   SetVendorIdentifierInfo(info.m_vendor);
1022 
1023   switch (terminalType) {
1024     case e_TerminalOnly :
1025     case e_TerminalAndMC :
1026       info.IncludeOptionalField(H225_EndpointType::e_terminal);
1027       break;
1028     case e_GatewayOnly :
1029     case e_GatewayAndMC :
1030     case e_GatewayAndMCWithDataMP :
1031     case e_GatewayAndMCWithAudioMP :
1032     case e_GatewayAndMCWithAVMP :
1033       info.IncludeOptionalField(H225_EndpointType::e_gateway);
1034       if (SetGatewaySupportedProtocol(info.m_gateway.m_protocol))
1035           info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
1036       break;
1037     case e_GatekeeperOnly :
1038     case e_GatekeeperWithDataMP :
1039     case e_GatekeeperWithAudioMP :
1040     case e_GatekeeperWithAVMP :
1041       info.IncludeOptionalField(H225_EndpointType::e_gatekeeper);
1042       break;
1043     case e_MCUOnly :
1044     case e_MCUWithDataMP :
1045     case e_MCUWithAudioMP :
1046     case e_MCUWithAVMP :
1047       info.IncludeOptionalField(H225_EndpointType::e_mcu);
1048       info.m_mc = TRUE;
1049       if (SetGatewaySupportedProtocol(info.m_mcu.m_protocol))
1050           info.m_mcu.IncludeOptionalField(H225_McuInfo::e_protocol);
1051       break;
1052 #if H323_H461
1053     case e_SET_H461 :
1054       info.IncludeOptionalField(H225_EndpointType::e_set);
1055       info.m_set.Set(3);
1056       return;
1057 #endif
1058   }
1059 
1060 #if H323_H461
1061   if (m_h461ASSETMode > 0) {
1062       info.IncludeOptionalField(H225_EndpointType::e_set);
1063       info.m_set.Set(3);
1064   }
1065 #endif
1066 }
1067 
SetGatewaySupportedProtocol(H225_ArrayOf_SupportedProtocols & protocols) const1068 PBoolean H323EndPoint::SetGatewaySupportedProtocol(H225_ArrayOf_SupportedProtocols & protocols) const
1069 {
1070     PStringList prefixes;
1071 
1072     if (OnSetGatewayPrefixes(prefixes)) {
1073         H225_SupportedProtocols proto;
1074         proto.SetTag(H225_SupportedProtocols::e_h323);
1075         H225_H323Caps & caps = proto;
1076         caps.IncludeOptionalField(H225_H323Caps::e_supportedPrefixes);
1077          H225_ArrayOf_SupportedPrefix & pre = caps.m_supportedPrefixes;
1078          pre.SetSize(prefixes.GetSize());
1079           for (PINDEX i=0; i < prefixes.GetSize(); i++) {
1080              H225_SupportedPrefix p;
1081                H225_AliasAddress & alias = p.m_prefix;
1082                H323SetAliasAddress(prefixes[i],alias);
1083              pre[i] = p;
1084           }
1085         protocols.SetSize(1);
1086         protocols[0] = proto;
1087         return TRUE;
1088     }
1089 
1090     return FALSE;
1091 }
1092 
OnSetGatewayPrefixes(PStringList &) const1093 PBoolean H323EndPoint::OnSetGatewayPrefixes(PStringList & /*prefixes*/) const
1094 {
1095     return FALSE;
1096 }
1097 
SetVendorIdentifierInfo(H225_VendorIdentifier & info) const1098 void H323EndPoint::SetVendorIdentifierInfo(H225_VendorIdentifier & info) const
1099 {
1100   SetH221NonStandardInfo(info.m_vendor);
1101 
1102   info.IncludeOptionalField(H225_VendorIdentifier::e_productId);
1103   info.m_productId = PProcess::Current().GetManufacturer() & PProcess::Current().GetName();
1104   info.m_productId.SetSize(info.m_productId.GetSize()+2);
1105 
1106   info.IncludeOptionalField(H225_VendorIdentifier::e_versionId);
1107   info.m_versionId = PProcess::Current().GetVersion(TRUE) + " (H323plus v" + OpalGetVersion() + ')';
1108   info.m_versionId.SetSize(info.m_versionId.GetSize()+2);
1109 }
1110 
1111 
SetH221NonStandardInfo(H225_H221NonStandard & info) const1112 void H323EndPoint::SetH221NonStandardInfo(H225_H221NonStandard & info) const
1113 {
1114   info.m_t35CountryCode = t35CountryCode;
1115   info.m_t35Extension = t35Extension;
1116   info.m_manufacturerCode = manufacturerCode;
1117 }
1118 
1119 
FindCapability(const H245_Capability & cap) const1120 H323Capability * H323EndPoint::FindCapability(const H245_Capability & cap) const
1121 {
1122   return capabilities.FindCapability(cap);
1123 }
1124 
1125 
FindCapability(const H245_DataType & dataType) const1126 H323Capability * H323EndPoint::FindCapability(const H245_DataType & dataType) const
1127 {
1128   return capabilities.FindCapability(dataType);
1129 }
1130 
1131 
FindCapability(H323Capability::MainTypes mainType,unsigned subType) const1132 H323Capability * H323EndPoint::FindCapability(H323Capability::MainTypes mainType,
1133                                               unsigned subType) const
1134 {
1135   return capabilities.FindCapability(mainType, subType);
1136 }
1137 
1138 
AddCapability(H323Capability * capability)1139 void H323EndPoint::AddCapability(H323Capability * capability)
1140 {
1141   capabilities.Add(capability);
1142 }
1143 
1144 
SetCapability(PINDEX descriptorNum,PINDEX simultaneousNum,H323Capability * capability)1145 PINDEX H323EndPoint::SetCapability(PINDEX descriptorNum,
1146                                    PINDEX simultaneousNum,
1147                                    H323Capability * capability)
1148 {
1149   return capabilities.SetCapability(descriptorNum, simultaneousNum, capability);
1150 }
1151 
RemoveCapability(H323Capability::MainTypes capabilityType)1152 PBoolean H323EndPoint::RemoveCapability(H323Capability::MainTypes capabilityType)
1153 {
1154     return capabilities.RemoveCapability(capabilityType);
1155 }
1156 
1157 #ifdef H323_VIDEO
SetVideoEncoder(unsigned frameWidth,unsigned frameHeight,unsigned frameRate)1158 PBoolean H323EndPoint::SetVideoEncoder(unsigned frameWidth, unsigned frameHeight, unsigned frameRate)
1159 {
1160     return capabilities.SetVideoEncoder(frameWidth, frameHeight, frameRate);
1161 }
1162 
SetVideoFrameSize(H323Capability::CapabilityFrameSize frameSize,int frameUnits)1163 PBoolean H323EndPoint::SetVideoFrameSize(H323Capability::CapabilityFrameSize frameSize,
1164                           int frameUnits)
1165 {
1166     return capabilities.SetVideoFrameSize(frameSize,frameUnits);
1167 }
1168 #endif
1169 
AddAllCapabilities(PINDEX descriptorNum,PINDEX simultaneous,const PString & name)1170 PINDEX H323EndPoint::AddAllCapabilities(PINDEX descriptorNum,
1171                                         PINDEX simultaneous,
1172                                         const PString & name)
1173 {
1174     PINDEX reply = capabilities.AddAllCapabilities(descriptorNum, simultaneous, name);
1175 #ifdef H323_VIDEO
1176 #ifdef H323_H239
1177     AddAllExtendedVideoCapabilities(descriptorNum, simultaneous);
1178 #endif
1179 #endif
1180   return reply;
1181 }
1182 
1183 
AddAllUserInputCapabilities(PINDEX descriptorNum,PINDEX simultaneous)1184 void H323EndPoint::AddAllUserInputCapabilities(PINDEX descriptorNum,
1185                                                PINDEX simultaneous)
1186 {
1187   H323_UserInputCapability::AddAllCapabilities(capabilities, descriptorNum, simultaneous);
1188 }
1189 
1190 #ifdef H323_VIDEO
1191 #ifdef H323_H239
OpenExtendedVideoSession(const PString & token)1192 PBoolean H323EndPoint::OpenExtendedVideoSession(const PString & token)
1193 {
1194   H323Connection * connection = FindConnectionWithLock(token);
1195 
1196   PBoolean success = FALSE;
1197   if (connection != NULL) {
1198     success = connection->OpenH239Channel();
1199     connection->Unlock();
1200   }
1201   return success;
1202 }
1203 
OpenExtendedVideoSession(const PString & token,H323ChannelNumber &)1204 PBoolean H323EndPoint::OpenExtendedVideoSession(const PString & token,H323ChannelNumber & /*num*/)
1205 {
1206   return OpenExtendedVideoSession(token);
1207 }
1208 
CloseExtendedVideoSession(const PString & token)1209 PBoolean H323EndPoint::CloseExtendedVideoSession(
1210                                const PString & token
1211                                )
1212 {
1213   H323Connection * connection = FindConnectionWithLock(token);
1214 
1215   PBoolean success = FALSE;
1216   if (connection != NULL) {
1217     success = connection->CloseH239Channel();
1218     connection->Unlock();
1219   }
1220   return success;
1221 }
1222 
CloseExtendedVideoSession(const PString & token,const H323ChannelNumber &)1223 PBoolean H323EndPoint::CloseExtendedVideoSession(
1224                                const PString & token,
1225                                const H323ChannelNumber & /*num*/
1226                                )
1227 {
1228   return CloseExtendedVideoSession(token);
1229 }
1230 
AddAllExtendedVideoCapabilities(PINDEX descriptorNum,PINDEX simultaneous)1231 void H323EndPoint::AddAllExtendedVideoCapabilities(PINDEX descriptorNum,
1232                                                    PINDEX simultaneous)
1233 {
1234   H323ExtendedVideoCapability::AddAllCapabilities(capabilities, descriptorNum, simultaneous);
1235 }
1236 #endif  // H323_H239
1237 #endif  // H323_VIDEO
1238 
RemoveCapabilities(const PStringArray & codecNames)1239 void H323EndPoint::RemoveCapabilities(const PStringArray & codecNames)
1240 {
1241 #if PTLIB_VER > 2130
1242   capabilities.Remove("dummy", codecNames);
1243 #else
1244   capabilities.Remove(codecNames);
1245 #endif
1246 }
1247 
1248 
ReorderCapabilities(const PStringArray & preferenceOrder)1249 void H323EndPoint::ReorderCapabilities(const PStringArray & preferenceOrder)
1250 {
1251   capabilities.Reorder(preferenceOrder);
1252 }
1253 
1254 
UseGatekeeper(const PString & address,const PString & identifier,const PString & localAddress)1255 PBoolean H323EndPoint::UseGatekeeper(const PString & address,
1256                                  const PString & identifier,
1257                                  const PString & localAddress)
1258 {
1259   if (gatekeeper != NULL) {
1260     PBoolean same = TRUE;
1261 
1262     if (!address)
1263       same = gatekeeper->GetTransport().GetRemoteAddress().IsEquivalent(address);
1264 
1265     if (!same && !identifier)
1266       same = gatekeeper->GetIdentifier() == identifier;
1267 
1268     if (!same && !localAddress)
1269       same = gatekeeper->GetTransport().GetLocalAddress().IsEquivalent(localAddress);
1270 
1271     if (same) {
1272       PTRACE(2, "H323\tUsing existing gatekeeper " << *gatekeeper);
1273       return TRUE;
1274     }
1275   }
1276 
1277   H323Transport * transport = NULL;
1278   if (!localAddress.IsEmpty()) {
1279     H323TransportAddress iface(localAddress);
1280     PIPSocket::Address ip;
1281     WORD port = H225_RAS::DefaultRasUdpPort;
1282     if (iface.GetIpAndPort(ip, port))
1283       transport = new H323TransportUDP(*this, ip, port);
1284   }
1285 
1286   if (address.IsEmpty()) {
1287     if (identifier.IsEmpty())
1288       return DiscoverGatekeeper(transport);
1289     else
1290       return LocateGatekeeper(identifier, transport);
1291   }
1292   else {
1293     if (identifier.IsEmpty())
1294       return SetGatekeeper(address, transport);
1295     else
1296       return SetGatekeeperZone(address, identifier, transport);
1297   }
1298 }
1299 
1300 
SetGatekeeper(const PString & address,H323Transport * transport)1301 PBoolean H323EndPoint::SetGatekeeper(const PString & address, H323Transport * transport)
1302 {
1303   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
1304   return InternalRegisterGatekeeper(gk, gk->DiscoverByAddress(address));
1305 }
1306 
1307 
SetGatekeeperZone(const PString & address,const PString & identifier,H323Transport * transport)1308 PBoolean H323EndPoint::SetGatekeeperZone(const PString & address,
1309                                      const PString & identifier,
1310                                      H323Transport * transport)
1311 {
1312   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
1313   return InternalRegisterGatekeeper(gk, gk->DiscoverByNameAndAddress(identifier, address));
1314 }
1315 
1316 
LocateGatekeeper(const PString & identifier,H323Transport * transport)1317 PBoolean H323EndPoint::LocateGatekeeper(const PString & identifier, H323Transport * transport)
1318 {
1319   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
1320   return InternalRegisterGatekeeper(gk, gk->DiscoverByName(identifier));
1321 }
1322 
1323 
DiscoverGatekeeper(H323Transport * transport)1324 PBoolean H323EndPoint::DiscoverGatekeeper(H323Transport * transport)
1325 {
1326   H323Gatekeeper * gk = InternalCreateGatekeeper(transport);
1327   return InternalRegisterGatekeeper(gk, gk->DiscoverAny());
1328 }
1329 
1330 
InternalCreateGatekeeper(H323Transport * transport)1331 H323Gatekeeper * H323EndPoint::InternalCreateGatekeeper(H323Transport * transport)
1332 {
1333   RemoveGatekeeper(H225_UnregRequestReason::e_reregistrationRequired);
1334 
1335   if (transport == NULL)
1336     transport = new H323TransportUDP(*this, PIPSocket::Address::GetAny(4));
1337 
1338   H323Gatekeeper * gk = CreateGatekeeper(transport);
1339 
1340   gk->SetPassword(gatekeeperPassword);
1341 
1342   return gk;
1343 }
1344 
1345 
InternalRegisterGatekeeper(H323Gatekeeper * gk,PBoolean discovered)1346 PBoolean H323EndPoint::InternalRegisterGatekeeper(H323Gatekeeper * gk, PBoolean discovered)
1347 {
1348   if (discovered) {
1349     if (gk->RegistrationRequest()) {
1350       gatekeeper = gk;
1351       return TRUE;
1352     }
1353 
1354     // RRQ was rejected continue trying
1355     gatekeeper = gk;
1356   }
1357   else // Only stop listening if the GRQ was rejected
1358     delete gk;
1359 
1360   return FALSE;
1361 }
1362 
1363 
CreateGatekeeper(H323Transport * transport)1364 H323Gatekeeper * H323EndPoint::CreateGatekeeper(H323Transport * transport)
1365 {
1366   return new H323Gatekeeper(*this, transport);
1367 }
1368 
1369 
IsRegisteredWithGatekeeper() const1370 PBoolean H323EndPoint::IsRegisteredWithGatekeeper() const
1371 {
1372   if (gatekeeper == NULL)
1373     return FALSE;
1374 
1375   return gatekeeper->IsRegistered();
1376 }
1377 
1378 
RemoveGatekeeper(int reason)1379 PBoolean H323EndPoint::RemoveGatekeeper(int reason)
1380 {
1381   PBoolean ok = TRUE;
1382 
1383   if (gatekeeper == NULL)
1384     return ok;
1385 
1386   ClearAllCalls();
1387 
1388   if (gatekeeper->IsRegistered()) // If we are registered send a URQ
1389     ok = gatekeeper->UnregistrationRequest(reason);
1390 
1391   delete gatekeeper;
1392   gatekeeper = NULL;
1393 
1394 #ifdef H323_H46017
1395   if (m_registeredWithH46017) {
1396        H460_FeatureStd17 * h46017 = (H460_FeatureStd17 *)features.GetFeature(17);
1397        if(h46017)
1398            h46017->UnInitialise();
1399   }
1400 #endif
1401   return ok;
1402 }
1403 
ForceGatekeeperReRegistration()1404 void H323EndPoint::ForceGatekeeperReRegistration()
1405 {
1406     if (gatekeeper != NULL)
1407         RegInvokeReRegistration();
1408 }
1409 
SetGatekeeperPassword(const PString & password)1410 void H323EndPoint::SetGatekeeperPassword(const PString & password)
1411 {
1412   gatekeeperPassword = password;
1413 
1414   if (gatekeeper != NULL) {
1415     gatekeeper->SetPassword(gatekeeperPassword);
1416     if (gatekeeper->IsRegistered()) // If we are registered send a URQ
1417       gatekeeper->UnregistrationRequest(H225_UnregRequestReason::e_reregistrationRequired);
1418     InternalRegisterGatekeeper(gatekeeper, TRUE);
1419   }
1420 }
1421 
GatekeeperCheckIP(const H323TransportAddress &,H323TransportAddress &)1422 PBoolean H323EndPoint::GatekeeperCheckIP(const H323TransportAddress & /*oldAddr*/,
1423                                      H323TransportAddress & /*newaddress*/)
1424 {
1425     return FALSE;
1426 }
1427 
OnAdmissionRequest(H323Connection &)1428 void H323EndPoint::OnAdmissionRequest(H323Connection & /*connection*/)
1429 {
1430 }
1431 
OnGatekeeperConfirm()1432 void H323EndPoint::OnGatekeeperConfirm()
1433 {
1434 }
1435 
OnGatekeeperReject()1436 void H323EndPoint::OnGatekeeperReject()
1437 {
1438 }
1439 
OnRegistrationConfirm(const H323TransportAddress &)1440 void H323EndPoint::OnRegistrationConfirm(const H323TransportAddress & /*rasAddress*/)
1441 {
1442 }
1443 
OnRegistrationReject()1444 void H323EndPoint::OnRegistrationReject()
1445 {
1446 }
1447 
OnUnRegisterRequest()1448 void H323EndPoint::OnUnRegisterRequest()
1449 {
1450 }
1451 
OnUnRegisterConfirm()1452 void H323EndPoint::OnUnRegisterConfirm()
1453 {
1454 }
1455 
OnRegisterTTLFail()1456 void H323EndPoint::OnRegisterTTLFail()
1457 {
1458 }
1459 
OnDetectedIPChange(PIPSocket::Address newIP)1460 PBoolean H323EndPoint::OnDetectedIPChange(PIPSocket::Address newIP)
1461 {
1462     if (!newIP.IsValid() || newIP.IsAny() || newIP.IsLoopback()) {
1463         PTRACE(2,"EP\tInvalid Listening Interface \"" << newIP << '"');
1464         return false;
1465     }
1466 
1467     if (!gatekeeper) {
1468         PTRACE(2,"EP\tExisting Gatekeeper is NULL!");
1469         return false;
1470     }
1471 
1472     WORD oldPort = DefaultTcpPort;
1473     if (listeners.GetSize() > 0) {
1474         H323TransportAddress localAddress = listeners[0].GetTransportAddress();
1475         PIPSocket::Address oldIP;
1476         localAddress.GetIpAndPort(oldIP,oldPort);
1477         if (oldIP == newIP) {
1478             PTRACE(2,"EP\tNo IP Change already listening on \"" << newIP << '"');
1479             return true;
1480         }
1481         listeners.RemoveAll();
1482         PTRACE(2,"EP\tStopped Listener on \"" << oldIP << '"');
1483     }
1484 
1485     H323ListenerTCP * listener = new H323ListenerTCP(*this, newIP, oldPort);
1486     if (!StartListener(listener)) {
1487          PTRACE(4,"EP\tCould not bind listener port on \"" << newIP << '"');
1488          return false;
1489     }
1490     PTRACE(2,"EP\tBound listener port on \"" << newIP << '"');
1491 
1492     H323TransportAddress add = gatekeeper->GetGatekeeperRouteAddress();
1493     RemoveGatekeeper(H225_UnregRequestReason::e_maintenance);
1494     PThread::Sleep(500);
1495 
1496     H323TransportUDP * transport = new H323TransportUDP(*this, newIP);
1497     H323Gatekeeper * gk = CreateGatekeeper(transport);
1498     if (gk) {
1499        gk->SetPassword(gatekeeperPassword);
1500        InternalRegisterGatekeeper(gk, gk->StartDiscovery(add));
1501        return true;
1502     }
1503 
1504     PTRACE(2,"EP\tERROR: Failed with IP Change to \"" << newIP << '"');
1505     return false;
1506 }
1507 
SetAuthenticatorOrder(PStringList & names)1508 void H323EndPoint::SetAuthenticatorOrder(PStringList & names)
1509 {
1510     gkAuthenticatorOrder = names;
1511 }
1512 
CreateAuthenticators()1513 H235Authenticators H323EndPoint::CreateAuthenticators()
1514 {
1515   H235Authenticators authenticators;
1516 
1517   PStringList orgAuths = H235Authenticator::GetAuthenticatorList();
1518   PStringList auths;
1519 
1520   PINDEX i=0;
1521   if (gkAuthenticatorOrder.GetSize() > 0) {
1522       for (i = 0; i < gkAuthenticatorOrder.GetSize(); ++i) {
1523         if (orgAuths.GetStringsIndex(gkAuthenticatorOrder[i]) != P_MAX_INDEX) {
1524             if (m_disableMD5Authenticators && ((gkAuthenticatorOrder[i] == "MD5") || (gkAuthenticatorOrder[i] == "CAT"))) {
1525                 PTRACE(3, "H235\tAuthenticator disabled: " << gkAuthenticatorOrder[i]);
1526             } else {
1527                 auths.AppendString(gkAuthenticatorOrder[i]);
1528             }
1529          }
1530       }
1531       for (i = 0; i < orgAuths.GetSize(); ++i) {
1532         if (gkAuthenticatorOrder.GetStringsIndex(orgAuths[i]) == P_MAX_INDEX) {
1533             if (m_disableMD5Authenticators && ((orgAuths[i] == "MD5") || (orgAuths[i] == "CAT"))) {
1534                 PTRACE(3, "H235\tAuthenticator disabled: " << orgAuths[i]);
1535             } else {
1536                 auths.AppendString(orgAuths[i]);
1537             }
1538         }
1539       }
1540   } else
1541       auths = orgAuths;
1542 
1543 
1544     for (i = 0; i < auths.GetSize(); ++i) {
1545 #if PTLIB_VER >= 2130
1546         H235Authenticator * Auth = H235Authenticator::CreateAuthenticator(auths[i]);
1547 #else
1548         H235Authenticator * Auth = PFactory<H235Authenticator>::CreateInstance(auths[i]);
1549 #endif
1550         if (!Auth) continue;
1551         if (m_disableMD5Authenticators && ((PString("MD5") == Auth->GetName()) || (PString("CAT") == Auth->GetName()))) {
1552           PTRACE(3, "H235\tAuthenticator disabled: " << Auth->GetName());
1553           delete Auth;
1554           continue;
1555         }
1556         if (Auth->GetApplication() == H235Authenticator::GKAdmission ||
1557             Auth->GetApplication() == H235Authenticator::AnyApplication)
1558                         authenticators.Append(Auth);
1559         else
1560             delete Auth;
1561     }
1562 
1563     return authenticators;
1564 }
1565 
CreateEPAuthenticators()1566 H235Authenticators H323EndPoint::CreateEPAuthenticators()
1567 {
1568   H235Authenticators authenticators;
1569 
1570   PString username;
1571   PString password;
1572 
1573 #if PTLIB_VER >= 2130
1574      PStringList auths = H235Authenticator::GetAuthenticatorList();
1575       for (PINDEX i = 0; i < auths.GetSize(); ++i) {
1576         H235Authenticator * Auth = H235Authenticator::CreateAuthenticator(auths[i]);
1577 #else
1578      PFactory<H235Authenticator>::KeyList_T keyList = PFactory<H235Authenticator>::GetKeyList();
1579      PFactory<H235Authenticator>::KeyList_T::const_iterator r;
1580       for (r = keyList.begin(); r != keyList.end(); ++r) {
1581         H235Authenticator * Auth = PFactory<H235Authenticator>::CreateInstance(*r);
1582 #endif
1583         if (Auth == NULL || Auth->GetApplication() == H235Authenticator::GKAdmission ||
1584             Auth->GetApplication() == H235Authenticator::LRQOnly) {
1585               delete Auth;
1586               continue;
1587         }
1588 
1589         if (m_disableMD5Authenticators && ((PString("MD5") == Auth->GetName()) || (PString("CAT") == Auth->GetName()))) {
1590           PTRACE(3, "H235\tAuthenticator disabled: " << Auth->GetName());
1591           delete Auth;
1592           continue;
1593         }
1594 
1595         if ((Auth->GetApplication() == H235Authenticator::EPAuthentication ||
1596              Auth->GetApplication() == H235Authenticator::AnyApplication) &&
1597              GetEPCredentials(password, username)) {
1598                 if ((PString(Auth->GetName()) == "H.235.1") && IsRegisteredWithGatekeeper()) {
1599                   H323Gatekeeper * gk = GetGatekeeper();
1600                   if (gk) {
1601                     Auth->SetLocalId(gk->GetEndpointIdentifier());
1602                     PString gkID = gk->GetName();
1603                     PINDEX at = gkID.Find('@');
1604 					if (at != P_MAX_INDEX)
1605 						gkID = gkID.Left(at);
1606                     Auth->SetRemoteId(gkID);
1607                   }
1608                 } else {
1609                   Auth->SetLocalId(username);
1610                 }
1611                 Auth->SetPassword(password);
1612         }
1613         authenticators.Append(Auth);
1614       }
1615      SetEPCredentials(PString(),PString());
1616 
1617   return authenticators;
1618 }
1619 
1620 PBoolean H323EndPoint::GetEPCredentials(PString & password,
1621                                     PString & username)
1622 {
1623   if (EPSecurityPassword.IsEmpty())
1624      return FALSE;
1625   else
1626      password = EPSecurityPassword;
1627 
1628   if (EPSecurityUserName.IsEmpty())
1629       username = GetLocalUserName();
1630   else
1631       username = EPSecurityUserName;
1632 
1633   return TRUE;
1634 }
1635 
1636 void H323EndPoint::SetEPCredentials(PString password, PString username)
1637 {
1638     EPSecurityPassword = password;
1639     EPSecurityUserName = username;
1640 }
1641 
1642 void H323EndPoint::SetEPSecurityPolicy(EPSecurityPolicy policy)
1643 {
1644     CallAuthPolicy = policy;
1645 }
1646 
1647 H323EndPoint::EPSecurityPolicy H323EndPoint::GetEPSecurityPolicy()
1648 {
1649     return CallAuthPolicy;
1650 }
1651 
1652 H235AuthenticatorList H323EndPoint::GetAuthenticatorList()
1653 {
1654     return EPAuthList;
1655 }
1656 
1657 PBoolean H323EndPoint::OnCallAuthentication(const PString & username,
1658                                         PString & password)
1659 {
1660     if (EPAuthList.HasUserName(username)) {
1661         EPAuthList.LoadPassword(username, password);
1662         return TRUE;
1663     }
1664 
1665     return FALSE;
1666 }
1667 
1668 H323Connection * H323EndPoint::MakeAuthenticatedCall(const PString & remoteParty,
1669         const PString & UserName, const PString & Password, PString & token, void * userData)
1670 {
1671   isSecureCall = TRUE;
1672   SetEPCredentials(Password,UserName);
1673   return MakeCall(remoteParty, token, userData);
1674 }
1675 
1676 #ifdef H323_H235
1677 void H323EndPoint::SetH235MediaEncryption(H235MediaPolicy policy, H235MediaCipher level, unsigned maxTokenSize)
1678 {
1679     H235Authenticators::SetEncryptionPolicy(policy);
1680     H235Authenticators::SetMaxCipherLength(level);
1681     H235Authenticators::SetMaxTokenLength(maxTokenSize);
1682 }
1683 
1684 H323EndPoint::H235MediaPolicy H323EndPoint::GetH235MediaPolicy()
1685 {
1686     return static_cast<H235MediaPolicy>(H235Authenticators::GetEncryptionPolicy());
1687 }
1688 
1689 H323EndPoint::H235MediaCipher H323EndPoint::GetH235MediaCipher()
1690 {
1691     return static_cast<H235MediaCipher>(H235Authenticators::GetMaxCipherLength());
1692 }
1693 
1694 void H323EndPoint::H235SetDiffieHellmanFiles(const PString & file)
1695 {
1696     SetEncryptionCacheFiles(file);
1697 }
1698 
1699 void H323EndPoint::SetEncryptionCacheFiles(const PString & cachefile)
1700 {
1701     H235Authenticators::SetDHParameterFile(cachefile);
1702 }
1703 
1704 const PString & H323EndPoint::GetEncryptionCacheFiles()
1705 {
1706     return H235Authenticators::GetDHParameterFile();
1707 }
1708 
1709 void H323EndPoint::LoadDiffieHellmanParameters(const PString & oid,
1710                                                const PBYTEArray & pData, const PBYTEArray & gData)
1711 {
1712     H235Authenticators::LoadDHData(oid, pData, gData);
1713 }
1714 
1715 void H323EndPoint::EncryptionCacheInitialise()
1716 {
1717   if (H235Authenticators::GetEncryptionPolicy()) {
1718        H2356_Authenticator::InitialiseCache(H235Authenticators::GetMaxCipherLength(),
1719                                             H235Authenticators::GetMaxTokenLength());
1720   }
1721 }
1722 
1723 void H323EndPoint::EncryptionCacheRemove()
1724 {
1725   H2356_Authenticator::RemoveCache();
1726 }
1727 #endif
1728 
1729 H323Connection * H323EndPoint::MakeSupplimentaryCall(const PString & remoteParty,
1730                         PString & token, void * userData)
1731 {
1732     return MakeCall(remoteParty, token, userData, true);
1733 }
1734 
1735 PBoolean H323EndPoint::StartListeners(const H323TransportAddressArray & ifaces)
1736 {
1737   if (ifaces.IsEmpty())
1738     return StartListener("*");
1739 
1740   PINDEX i;
1741 
1742   for (i = 0; i < listeners.GetSize(); i++) {
1743     PBoolean remove = TRUE;
1744     for (PINDEX j = 0; j < ifaces.GetSize(); j++) {
1745       if (listeners[i].GetTransportAddress().IsEquivalent(ifaces[j])) {
1746         remove = FALSE;
1747         break;
1748       }
1749     }
1750     if (remove) {
1751       PTRACE(3, "H323\tRemoving " << listeners[i]);
1752       listeners.RemoveAt(i--);
1753     }
1754   }
1755 
1756   for (i = 0; i < ifaces.GetSize(); i++) {
1757     if (!ifaces[i])
1758       StartListener(ifaces[i]);
1759   }
1760 
1761   return listeners.GetSize() > 0;
1762 }
1763 
1764 
1765 PBoolean H323EndPoint::StartListener(const H323TransportAddress & iface)
1766 {
1767   H323Listener * listener;
1768 
1769   if (iface.IsEmpty())
1770     listener = new H323ListenerTCP(*this, PIPSocket::GetDefaultIpAny(), DefaultTcpPort);
1771   else
1772     listener = iface.CreateListener(*this);
1773 
1774   if (H323EndPoint::StartListener(listener))
1775     return TRUE;
1776 
1777   PTRACE(1, "H323\tCould not start " << iface);
1778   delete listener;
1779   return FALSE;
1780 }
1781 
1782 
1783 PBoolean H323EndPoint::StartListener(H323Listener * listener)
1784 {
1785   if (listener == NULL)
1786     return FALSE;
1787 
1788   for (PINDEX i = 0; i < listeners.GetSize(); i++) {
1789     if (listeners[i].GetTransportAddress() == listener->GetTransportAddress() &&
1790         listeners[i].GetSecurity() == listener->GetSecurity()) {
1791           PTRACE(2, "H323\tAlready have " << *listener);
1792           delete listener;
1793           return TRUE;
1794     }
1795   }
1796 
1797   // as the listener is not open, this will have the effect of immediately
1798   // stopping the listener thread. This is good - it means that the
1799   // listener Close function will appear to have stopped the thread
1800   if (!listener->Open()) {
1801     listener->Resume(); // set the thread running so we can delete it later
1802     return FALSE;
1803   }
1804 
1805   PTRACE(3, "H323\tStarted " << *listener);
1806   listeners.Append(listener);
1807   listener->Resume();
1808   return TRUE;
1809 }
1810 
1811 
1812 PBoolean H323EndPoint::RemoveListener(H323Listener * listener)
1813 {
1814   if (listener != NULL) {
1815     PTRACE(3, "H323\tRemoving " << *listener);
1816     return listeners.Remove(listener);
1817   }
1818 
1819   PTRACE(3, "H323\tRemoving all listeners");
1820   listeners.RemoveAll();
1821   return TRUE;
1822 }
1823 
1824 
1825 H323TransportAddressArray H323EndPoint::GetInterfaceAddresses(PBoolean excludeLocalHost,
1826                                                               H323Transport * associatedTransport)
1827 {
1828      return H323GetInterfaceAddresses(listeners, excludeLocalHost, associatedTransport);
1829 }
1830 
1831 H323Connection * H323EndPoint::MakeCall(const PString & remoteParty,
1832                                         PString & token,
1833                                         void * userData,
1834                                         PBoolean supplementary
1835                                         )
1836 {
1837   return MakeCall(remoteParty, NULL, token, userData, supplementary);
1838 }
1839 
1840 
1841 H323Connection * H323EndPoint::MakeCall(const PString & remoteParty,
1842                                         H323Transport * transport,
1843                                         PString & token,
1844                                         void * userData,
1845                                         PBoolean supplementary
1846                                         )
1847 {
1848   token = PString::Empty();
1849 
1850   PStringList Addresses;
1851   if (!ResolveCallParty(remoteParty, Addresses))
1852     return NULL;
1853 
1854   H323Connection * connection = NULL;
1855   for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
1856        connection = InternalMakeCall(PString::Empty(),
1857                                      PString::Empty(),
1858                                      UINT_MAX,
1859                                      Addresses[i],
1860                                      transport,
1861                                      token,
1862                                      userData,
1863                                      supplementary
1864                                      );
1865     if (connection != NULL) {
1866         connection->Unlock();
1867         break;
1868     }
1869   }
1870 
1871   return connection;
1872 }
1873 
1874 
1875 H323Connection * H323EndPoint::MakeCallLocked(const PString & remoteParty,
1876                                               PString & token,
1877                                               void * userData,
1878                                               H323Transport * transport)
1879 {
1880   token = PString::Empty();
1881 
1882   PStringList Addresses;
1883   if (!ResolveCallParty(remoteParty, Addresses))
1884     return NULL;
1885 
1886   H323Connection * connection = NULL;
1887   for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
1888       connection = InternalMakeCall(PString::Empty(),
1889                              PString::Empty(),
1890                              UINT_MAX,
1891                              Addresses[i],
1892                              transport,
1893                              token,
1894                              userData);
1895      if (connection != NULL)
1896             break;
1897   }
1898 
1899   return connection;
1900 
1901 }
1902 
1903 H323Connection * H323EndPoint::InternalMakeCall(const PString & trasferFromToken,
1904                                                 const PString & callIdentity,
1905                                                 unsigned capabilityLevel,
1906                                                 const PString & remoteParty,
1907                                                 H323Transport * transport,
1908                                                 PString & newToken,
1909                                                 void * userData,
1910                                                 PBoolean supplementary
1911                                                 )
1912 {
1913   PTRACE(2, "H323\tMaking call to: " << remoteParty);
1914 
1915   PString alias;
1916   H323TransportAddress address;
1917   if (!ParsePartyName(remoteParty, alias, address)) {
1918     PTRACE(2, "H323\tCould not parse \"" << remoteParty << '"');
1919     return NULL;
1920   }
1921 
1922 #ifdef H323_H46017
1923   // If H.460.17 use the existing H.460.17 Transport
1924   if (transport == NULL && RegisteredWithH46017())
1925       transport = GetH46017Transport();
1926 #endif
1927 
1928   if (transport == NULL) {
1929     // Restriction: the call must be made on the same transport as the one
1930     // that the gatekeeper is using.
1931     if (gatekeeper != NULL)
1932       transport = gatekeeper->GetTransport().GetRemoteAddress().CreateTransport(*this);
1933 
1934     // assume address is an IP address/hostname
1935     else
1936       transport = address.CreateTransport(*this);
1937 
1938     if (transport == NULL) {
1939       PTRACE(1, "H323\tInvalid transport in \"" << remoteParty << '"');
1940       return NULL;
1941     }
1942   }
1943 
1944   H323Connection * connection;
1945 
1946   connectionsMutex.Wait();
1947 
1948   unsigned lastReference;
1949   PString adjustedToken = PString();
1950   if (newToken.IsEmpty()) {
1951     do {
1952       lastReference = Q931::GenerateCallReference();
1953       newToken = BuildConnectionToken(*transport, lastReference, FALSE);
1954     } while (connectionsActive.Contains(newToken));
1955   }
1956   else {
1957     lastReference = newToken.Mid(newToken.Find('/')+1).AsUnsigned();
1958 
1959     // Move old connection on token to new value and flag for removal
1960     unsigned tieBreaker = 0;
1961     do {
1962       adjustedToken = newToken + "-replaced";
1963       adjustedToken.sprintf("-%u", ++tieBreaker);
1964     } while (connectionsActive.Contains(adjustedToken));
1965     connectionsActive.SetAt(adjustedToken, connectionsActive.RemoveAt(newToken));
1966     connectionsToBeCleaned += adjustedToken;
1967     PTRACE(3, "H323\tOverwriting call " << newToken << ", renamed to " << adjustedToken);
1968   }
1969   connectionsMutex.Signal();
1970 
1971   connection = CreateConnection(lastReference, userData, transport, NULL);
1972   if (connection == NULL) {
1973     PTRACE(2, "H323\tCreateConnection returned NULL");
1974     if (!adjustedToken.IsEmpty())  {
1975         connectionsMutex.Wait();
1976         connectionsActive.SetAt(newToken, connectionsActive.RemoveAt(adjustedToken));
1977         connectionsToBeCleaned -= adjustedToken;
1978         PTRACE(3, "H323\tOverwriting call " << adjustedToken << ", renamed to " << newToken);
1979         connectionsMutex.Signal();
1980     }
1981     return NULL;
1982   }
1983   connection->SetRemotePartyName(remoteParty);
1984 
1985   if (supplementary)
1986       connection->SetNonCallConnection();
1987 
1988   (void)connection->Lock();
1989 
1990   connectionsMutex.Wait();
1991   connectionsActive.SetAt(newToken, connection);
1992 
1993   connectionsMutex.Signal();
1994 
1995   connection->AttachSignalChannel(newToken, transport, FALSE);
1996 
1997 #ifdef H323_H450
1998   if (capabilityLevel == UINT_MAX)
1999     connection->HandleTransferCall(trasferFromToken, callIdentity);
2000   else {
2001     connection->HandleIntrudeCall(trasferFromToken, callIdentity);
2002     connection->IntrudeCall(capabilityLevel);
2003   }
2004 #endif
2005 
2006   PTRACE(3, "H323\tCreated new connection: " << newToken);
2007 
2008 #ifdef H323_H46017
2009   if (RegisteredWithH46017()) {
2010     H323Connection::CallEndReason reason = connection->SendSignalSetup(alias, address);
2011     if (reason != H323Connection::NumCallEndReasons)
2012       connection->ClearCall(reason);
2013   } else
2014 #endif
2015       new H225CallThread(*this, *connection, *transport, alias, address);
2016 
2017   return connection;
2018 }
2019 
2020 #if P_DNS
2021 
2022 struct LookupRecord {
2023   enum {
2024     CallDirect,
2025     LRQ
2026   };
2027   int type;
2028   PIPSocket::Address addr;
2029   WORD port;
2030 };
2031 /*
2032 static PBoolean FindSRVRecords(std::vector<LookupRecord> & recs,
2033                     const PString & domain,
2034                     int type,
2035                     const PString & srv)
2036 {
2037   PDNS::SRVRecordList srvRecords;
2038   PString srvLookupStr = srv + domain;
2039   PBoolean found = PDNS::GetRecords(srvLookupStr, srvRecords);
2040   if (found) {
2041     PDNS::SRVRecord * recPtr = srvRecords.GetFirst();
2042     while (recPtr != NULL) {
2043       LookupRecord rec;
2044       rec.addr = recPtr->hostAddress;
2045       rec.port = recPtr->port;
2046       rec.type = type;
2047       recs.push_back(rec);
2048       recPtr = srvRecords.GetNext();
2049       PTRACE(4, "H323\tFound " << rec.addr << ":" << rec.port << " with SRV " << srv << " using domain " << domain);
2050     }
2051   }
2052   return found;
2053 }
2054 
2055 static PBoolean FindRoutes(const PString & domain, WORD port, std::vector<LookupRecord> & routes)
2056 {
2057   PBoolean hasGK = FindSRVRecords(    routes, domain, LookupRecord::LRQ,        "_h323ls._udp.");
2058   hasGK = hasGK || FindSRVRecords(routes, domain, LookupRecord::LRQ,        "_h323rs._udp.");
2059   FindSRVRecords(                 routes, domain, LookupRecord::CallDirect, "_h323cs._tcp.");
2060 
2061   // see if the domain is actually a host
2062   PIPSocket::Address addr;
2063   if (PIPSocket::GetHostAddress(domain, addr)) {
2064     LookupRecord rec;
2065     rec.addr = addr;
2066     rec.port = port;
2067     rec.type = LookupRecord::CallDirect;
2068     PTRACE(4, "H323\tDomain " << domain << " is a host - using as call signal address");
2069     routes.push_back(rec);
2070   }
2071 
2072   if (routes.size() != 0) {
2073     PDNS::MXRecordList mxRecords;
2074     if (PDNS::GetRecords(domain, mxRecords)) {
2075       PDNS::MXRecord * recPtr = mxRecords.GetFirst();
2076       while (recPtr != NULL) {
2077         LookupRecord rec;
2078         rec.addr = recPtr->hostAddress;
2079         rec.port = 1719;
2080         rec.type = LookupRecord::LRQ;
2081         routes.push_back(rec);
2082         recPtr = mxRecords.GetNext();
2083         PTRACE(4, "H323\tFound " << rec.addr << ":" << rec.port << " with MX for domain " << domain);
2084       }
2085     }
2086   }
2087 
2088   return routes.size() != 0;
2089 }
2090 */
2091 #endif
2092 
2093 PBoolean H323EndPoint::ResolveCallParty(const PString & _remoteParty, PStringList & addresses)
2094 {
2095   PString remoteParty = _remoteParty;
2096 
2097 #if P_DNS
2098   // if there is no gatekeeper,
2099   if (gatekeeper == NULL) {
2100 
2101     PString number = _remoteParty;
2102     PString proto = "h323";
2103 
2104      //if there is no '@', and there is no URL scheme, then attempt to use ENUM
2105     if ((_remoteParty.Find(':') == P_MAX_INDEX) && (remoteParty.Find('@') == P_MAX_INDEX)) {
2106 
2107     if (number.Left(5) *= "h323:")
2108        number = number.Mid(5);
2109     if (remoteParty.Left(6) *= "h323s:") {
2110        number = number.Mid(6);
2111        proto = "h323s";
2112     }
2113 
2114     PINDEX i;
2115     for (i = 0; i < number.GetLength(); ++i) {
2116         if (!isdigit(number[i]))
2117             break;
2118     }
2119     if (i >= number.GetLength()) {
2120         PString str;
2121         if (PDNS::ENUMLookup(number, "E2U+h323", str)) {
2122             str.Replace("+","");
2123             if ((str.Find("//1") != P_MAX_INDEX) &&
2124                  (str.Find('@') != P_MAX_INDEX)) {
2125                remoteParty = proto + ":" + number + str.Mid(str.Find('@')-1);
2126             } else {
2127                remoteParty = str;
2128             }
2129             PTRACE(4, "H323\tENUM converted remote party " << _remoteParty << " to " << remoteParty);
2130         } else {
2131             PTRACE(4, "H323\tENUM Cannot resolve remote party " << _remoteParty);
2132             return false;
2133         }
2134      }
2135    }
2136 
2137 #ifdef H323_IPV6
2138   // Again horrible code should be able to get interface listing for a given protocol - SH
2139   PBoolean ipv6IPv4Discover = false;
2140   if (PIPSocket::GetDefaultIpAddressFamily() == AF_INET6) {
2141       PIPSocket::SetDefaultIpAddressFamilyV4();
2142       ipv6IPv4Discover = true;
2143   }
2144 #endif
2145 
2146    // attempt a DNS SRV lookup to detect a call signalling entry
2147    if (remoteParty.Find('@') != P_MAX_INDEX) {
2148        PString number = remoteParty;
2149        if (number.Left(5) != proto)
2150           number = proto + ":" + number;
2151 
2152        PStringList str;
2153        PBoolean found = FALSE;
2154 
2155        if (!found) str.RemoveAll();
2156        if (!found && (PDNS::LookupSRV(number,"_h323cs._tcp.",str))) {
2157            for (PINDEX i=0; i<str.GetSize(); i++) {
2158              PString dom = str[i].Mid(str[i].Find('@')+1);
2159              if (dom.Left(7) == "0.0.0.0") {
2160                 PTRACE(2, "EP\tERROR in CS SRV lookup (" << str[i] << ")");
2161                 continue;
2162              }
2163              PTRACE(4, "H323\tDNS SRV CS located remote party " << _remoteParty << " at " << dom);
2164              addresses.AppendString(str[i]);
2165              found = TRUE;
2166            }
2167        }
2168 /*
2169        if (!found) str.RemoveAll();
2170        if (!found && (PDNS::LookupSRV(number,"_h323ls._udp.",str))) {
2171            for (PINDEX j=0; j<str.GetSize(); j++) {
2172             PString a = str[j].Mid(str[j].Find('@')+1);
2173                 H323TransportAddress newAddr, gkAddr(a);
2174                 H323Gatekeeper * gk = CreateGatekeeper(new H323TransportUDP(*this));
2175                 PBoolean ok = gk->DiscoverByAddress(gkAddr);
2176                 if (ok)
2177                   ok = gk->LocationRequest(remoteParty, newAddr);
2178                 delete gk;
2179                 if (ok) {
2180                   PTRACE(3, "H323\tDNS SRV LR of \"" << remoteParty << "\" on gk " << gkAddr << " found " << newAddr);
2181                   addresses.AppendString(newAddr);
2182                   found = TRUE;
2183                 }
2184            }
2185        }
2186 */
2187        if (!found) {
2188            PTRACE(4, "H323\tDNS SRV Cannot resolve remote party " << remoteParty);
2189            addresses = PStringList(remoteParty);
2190        }
2191     } else {
2192        addresses = PStringList(remoteParty);
2193     }
2194 #ifdef H323_IPV6
2195      if (ipv6IPv4Discover)
2196         PIPSocket::SetDefaultIpAddressFamilyV6();
2197 #endif
2198     return true;
2199    }
2200 #endif
2201     addresses = PStringList(remoteParty);
2202     return true;
2203 }
2204 
2205 PBoolean H323EndPoint::ParsePartyName(const PString & _remoteParty,
2206                                   PString & alias,
2207                                   H323TransportAddress & address)
2208 {
2209   PString remoteParty = _remoteParty;
2210 
2211   PString proto = "h323";
2212   PString number = remoteParty;
2213     if (number.Left(5) *= "h323:")
2214         number = number.Mid(5);
2215     if (remoteParty.Left(6) *= "h323s:") {
2216         proto = "h323s";
2217         number = number.Mid(6);
2218     }
2219     if (remoteParty.Left(11) *= "h323cs-sec:") {
2220         proto = "h323s";
2221         number = number.Mid(11);
2222     }
2223 
2224     if (rewriteParsePartyName) {
2225         // Support [address]##[Alias] dialing
2226         PINDEX hash = number.Find("##");
2227         if (hash != P_MAX_INDEX) {
2228             remoteParty = proto + ":" + number.Mid(hash + 2) + "@" + number.Left(hash);
2229             PTRACE(4, "H323\tConverted " << _remoteParty << " to " << remoteParty);
2230         }
2231 
2232         /*
2233           PINDEX phash = _remoteParty.Find("#");
2234           if (phash != P_MAX_INDEX) {
2235             remoteParty.Replace("#","%");
2236             PTRACE(4, "H323\tAdjusted " << remoteParty);
2237           }
2238         */
2239     }
2240 
2241   //check if IPv6 address
2242   PINDEX ipv6 = remoteParty.Find("::");
2243   if (ipv6 != P_MAX_INDEX) {
2244       PINDEX at = remoteParty.Find('@');
2245       if (at != P_MAX_INDEX) {
2246           remoteParty = remoteParty.Left(at+1) + "[" + remoteParty.Mid(at+1) + "]";
2247       } else
2248           remoteParty = "[" + remoteParty + "]";
2249   }
2250 
2251   // convert the remote party string to a URL, with a default URL of "h323:"
2252   PURL url(remoteParty, proto);
2253 
2254   // If the URL schema does not match send the request to gatekeeper to route
2255   if (gatekeeper != NULL && url.GetScheme() != proto) {
2256      alias = url.AsString();
2257      return true;
2258   }
2259 
2260   // if the scheme does not match the prefix of the remote party, then
2261   // the URL parser got confused, so force the URL to be of type "h323"
2262   if ((remoteParty.Find('@') == P_MAX_INDEX) && (remoteParty.NumCompare(url.GetScheme()) != EqualTo)) {
2263     if (gatekeeper == NULL)
2264       url.Parse(proto + ":@" + remoteParty);
2265     else
2266       url.Parse(proto + ":" + remoteParty);
2267   }
2268 
2269   // get the various parts of the name
2270   PString hostOnly = PString();
2271   if (remoteParty.Find('@') != P_MAX_INDEX) {
2272     if (gatekeeper != NULL)
2273       alias = url.AsString();
2274     else {
2275       alias = remoteParty.Left(remoteParty.Find('@'));
2276       hostOnly = remoteParty.Mid(remoteParty.Find('@')+1);
2277     }
2278   } else {
2279      alias = url.GetUserName();
2280      hostOnly = url.GetHostName();
2281   }
2282   address = hostOnly;
2283 
2284   // make sure the address contains the port, if not default
2285   if (!address && (url.GetPort() != 0))
2286     address.sprintf(":%u", url.GetPort());
2287 
2288   if (alias.IsEmpty() && address.IsEmpty()) {
2289     PTRACE(1, "H323\tAttempt to use invalid URL \"" << remoteParty << '"');
2290     return FALSE;
2291   }
2292 
2293   PBoolean gatekeeperSpecified = FALSE;
2294   PBoolean gatewaySpecified = FALSE;
2295 
2296   PCaselessString type = url.GetParamVars()("type");
2297 
2298   if (url.GetScheme() == "callto") {
2299     // Do not yet support ILS
2300     if (type == "directory") {
2301 #if P_LDAP
2302       PString server = url.GetHostName();
2303       if (server.IsEmpty())
2304         server = ilsServer;
2305       if (server.IsEmpty())
2306         return FALSE;
2307 
2308       PILSSession ils;
2309       if (!ils.Open(server, url.GetPort())) {
2310         PTRACE(1, "H323\tCould not open ILS server at \"" << server
2311                << "\" - " << ils.GetErrorText());
2312         return FALSE;
2313       }
2314 
2315       PILSSession::RTPerson person;
2316       if (!ils.SearchPerson(alias, person)) {
2317         PTRACE(1, "H323\tCould not find "
2318                << server << '/' << alias << ": " << ils.GetErrorText());
2319         return FALSE;
2320       }
2321 
2322       if (!person.sipAddress.IsValid()) {
2323         PTRACE(1, "H323\tILS user " << server << '/' << alias
2324                << " does not have a valid IP address");
2325         return FALSE;
2326       }
2327 
2328       // Get the IP address
2329       address = H323TransportAddress(person.sipAddress);
2330 
2331       // Get the port if provided
2332       for (PINDEX i = 0; i < person.sport.GetSize(); i++) {
2333         if (person.sport[i] != 1503) { // Dont use the T.120 port
2334           address = H323TransportAddress(person.sipAddress, person.sport[i]);
2335           break;
2336         }
2337       }
2338 
2339       alias = PString::Empty(); // No alias for ILS lookup, only host
2340       return TRUE;
2341 #else
2342       return FALSE;
2343 #endif
2344     }
2345 
2346     if (url.GetParamVars().Contains("gateway"))
2347       gatewaySpecified = TRUE;
2348   }
2349 
2350   else if (url.GetScheme() == proto) {
2351     if (type == "gw")
2352       gatewaySpecified = TRUE;
2353     else if (type == "gk")
2354       gatekeeperSpecified = TRUE;
2355     else if (!type) {
2356       PTRACE(1, "H323\tUnsupported host type \"" << type << "\" in h323 URL");
2357       return FALSE;
2358     }
2359   }
2360 
2361   // User explicitly asked to use a GK for lookup
2362   if (gatekeeperSpecified) {
2363     if (alias.IsEmpty()) {
2364       PTRACE(1, "H323\tAttempt to use explicit gatekeeper without alias!");
2365       return FALSE;
2366     }
2367 
2368     if (address.IsEmpty()) {
2369       PTRACE(1, "H323\tAttempt to use explicit gatekeeper without address!");
2370       return FALSE;
2371     }
2372 
2373     H323TransportAddress gkAddr = address;
2374     PTRACE(3, "H323\tLooking for \"" << alias << "\" on gatekeeper at " << gkAddr);
2375 
2376     H323Gatekeeper * gk = CreateGatekeeper(new H323TransportUDP(*this));
2377 
2378     PBoolean ok = gk->DiscoverByAddress(gkAddr);
2379     if (ok) {
2380       ok = gk->LocationRequest(alias, address);
2381       if (ok) {
2382         PTRACE(3, "H323\tLocation Request of \"" << alias << "\" on gk " << gkAddr << " found " << address);
2383       }
2384       else {
2385         PTRACE(1, "H323\tLocation Request failed for \"" << alias << "\" on gk " << gkAddr);
2386       }
2387     }
2388     else {
2389       PTRACE(1, "H323\tLocation Request discovery failed for gk " << gkAddr);
2390     }
2391 
2392     delete gk;
2393 
2394     return ok;
2395   }
2396 
2397   // User explicitly said to use a gw, or we do not have a gk to do look up
2398   if (gatekeeper == NULL
2399       || gatewaySpecified) {
2400     // If URL did not have a host, but user said to use gw, or we do not have
2401     // a gk to do a lookup so we MUST have a host, use alias must be host
2402     if (address.IsEmpty()) {
2403       address = alias + ":" + PString(url.GetPort());
2404       if (url.GetScheme() == "h323s" && m_transportSecurity.IsTLSEnabled())
2405           address.SetTLS(true);
2406       alias = PString::Empty();
2407       return TRUE;
2408     }
2409 /*
2410 #if P_DNS
2411     // if we have an address and the correct scheme, then check DNS
2412     if (!address && (url.GetScheme() *= "h323")) {
2413       std::vector<LookupRecord> routes;
2414       if (FindRoutes(hostOnly, url.GetPort(), routes)) {
2415         std::vector<LookupRecord>::const_iterator r;
2416         for (r = routes.begin(); r != routes.end(); ++r) {
2417           const LookupRecord & rec = *r;
2418           switch (rec.type) {
2419             case LookupRecord::CallDirect:
2420               address = H323TransportAddress(rec.addr, rec.port);
2421               PTRACE(3, "H323\tParty name \"" << url << "\" mapped to \"" << alias << "@" << address);
2422               return TRUE;
2423               break;
2424 
2425             case LookupRecord::LRQ:
2426               {
2427                 H323TransportAddress newAddr, gkAddr(rec.addr, rec.port);
2428                 H323Gatekeeper * gk = CreateGatekeeper(new H323TransportUDP(*this));
2429                 PBoolean ok = gk->DiscoverByAddress(gkAddr);
2430                 if (ok)
2431                   ok = gk->LocationRequest(alias, newAddr);
2432                 delete gk;
2433                 if (ok) {
2434                   address = newAddr;
2435                   PTRACE(3, "H323\tLocation Request of \"" << alias << "\" on gk " << gkAddr << " found " << address);
2436                   return TRUE;
2437                 }
2438               }
2439               break;
2440 
2441             default:
2442               break;
2443           }
2444         }
2445       }
2446     }
2447 #endif   // P_DNS
2448 */
2449   }
2450 
2451   if (!address)
2452     return TRUE;
2453 
2454   // We do not have a gk and user did not explicitly supply a host, so lets
2455   // do a check to see if it is a valid IP address or hostname if not registered.
2456   if (alias.FindOneOf("$.:[") != P_MAX_INDEX && (gatekeeper == NULL ||
2457       alias.FindRegEx(PRegularExpression("^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$", PRegularExpression::Extended)) != P_MAX_INDEX || // IPv4
2458      (alias.Left(1) == "[" && alias.Right(1) == "]" && alias.FindRegEx(PRegularExpression("\\]:[0-9]+$", PRegularExpression::Extended)) != P_MAX_INDEX))) {  // IPv6
2459        H323TransportAddress test = alias;
2460 	   PIPSocket::Address ip;
2461        if (test.GetIpAddress(ip) && ip.IsValid() && !ip.IsAny()) {
2462           // The alias was a valid internet address, use it as such
2463           alias = PString::Empty();
2464           address = test;
2465        }
2466   }
2467 
2468   return TRUE;
2469 }
2470 
2471 #ifdef H323_H450
2472 
2473 H323Connection * H323EndPoint::SetupTransfer(const PString & oldToken,
2474                                              const PString & callIdentity,
2475                                              const PString & remoteParty,
2476                                              PString & newToken,
2477                                              void * userData)
2478 {
2479   newToken = PString::Empty();
2480 
2481   PStringList Addresses;
2482   if (!ResolveCallParty(remoteParty, Addresses))
2483     return NULL;
2484 
2485   H323Connection * connection = NULL;
2486      for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
2487          connection = InternalMakeCall(oldToken,
2488                                        callIdentity,
2489                                        UINT_MAX,
2490                                        Addresses[i],
2491                                        NULL,
2492                                        newToken,
2493                                        userData);
2494         if (connection != NULL) {
2495             connection->Unlock();
2496             break;
2497         }
2498      }
2499 
2500    return connection;
2501 }
2502 
2503 
2504 void H323EndPoint::TransferCall(const PString & token,
2505                                 const PString & remoteParty,
2506                                 const PString & callIdentity)
2507 {
2508   H323Connection * connection = FindConnectionWithLock(token);
2509   if (connection != NULL) {
2510     connection->TransferCall(remoteParty, callIdentity);
2511     connection->Unlock();
2512   }
2513 }
2514 
2515 
2516 void H323EndPoint::ConsultationTransfer(const PString & primaryCallToken,
2517                                         const PString & secondaryCallToken)
2518 {
2519   H323Connection * secondaryCall = FindConnectionWithLock(secondaryCallToken);
2520   if (secondaryCall != NULL) {
2521     secondaryCall->ConsultationTransfer(primaryCallToken);
2522     secondaryCall->Unlock();
2523   }
2524 }
2525 
2526 
2527 void H323EndPoint::HoldCall(const PString & token, PBoolean localHold)
2528 {
2529   H323Connection * connection = FindConnectionWithLock(token);
2530   if (connection != NULL) {
2531     connection->HoldCall(localHold);
2532     connection->Unlock();
2533   }
2534 }
2535 
2536 
2537 H323Connection * H323EndPoint::IntrudeCall(const PString & remoteParty,
2538                                         PString & token,
2539                                         unsigned capabilityLevel,
2540                                         void * userData)
2541 {
2542   return IntrudeCall(remoteParty, NULL, token, capabilityLevel, userData);
2543 }
2544 
2545 
2546 H323Connection * H323EndPoint::IntrudeCall(const PString & remoteParty,
2547                                         H323Transport * transport,
2548                                         PString & token,
2549                                         unsigned capabilityLevel,
2550                                         void * userData)
2551 {
2552   token = PString::Empty();
2553 
2554  PStringList Addresses;
2555   if (!ResolveCallParty(remoteParty, Addresses))
2556     return NULL;
2557 
2558   H323Connection * connection = NULL;
2559      for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
2560              connection = InternalMakeCall(PString::Empty(),
2561                                            PString::Empty(),
2562                                            capabilityLevel,
2563                                            Addresses[i],
2564                                            transport,
2565                                            token,
2566                                            userData);
2567          if (connection != NULL) {
2568             connection->Unlock();
2569             break;
2570          }
2571      }
2572   return connection;
2573 }
2574 
2575 void H323EndPoint::OnReceivedInitiateReturnError()
2576 {
2577 }
2578 
2579 PBoolean H323EndPoint::OnReceivedMWI(const H323Connection::MWIInformation & mwiInfo)
2580 {
2581     PTRACE(2,"EP\tReceived MWI for " << mwiInfo.mwiUser << " NoOfCalls " << mwiInfo.mwiCalls << " Message Ctr " << mwiInfo.mwiCtrId);
2582 
2583     return true;
2584 }
2585 
2586 PBoolean H323EndPoint::OnReceivedMWIClear(const PString & user)
2587 {
2588    PTRACE(2,"EP\tReceived MWI clear for " << user);
2589 
2590    return true;
2591 }
2592 
2593 PBoolean H323EndPoint::OnReceivedMWIRequest(H323Connection * /*connection*/, const PString & user)
2594 {
2595    PTRACE(2,"EP\tReceived MWI Request for " << user);
2596 
2597    return true;
2598 }
2599 
2600 #endif  // H323_H450
2601 
2602 
2603 PBoolean H323EndPoint::ClearCall(const PString & token,
2604                              H323Connection::CallEndReason reason)
2605 {
2606   return ClearCallSynchronous(token, reason, NULL);
2607 }
2608 
2609 void H323EndPoint::OnCallClearing(H323Connection * /*connection*/,
2610                              H323Connection::CallEndReason /*reason*/)
2611 {
2612 }
2613 
2614 PBoolean H323EndPoint::ClearCallSynchronous(const PString & token,
2615                              H323Connection::CallEndReason reason)
2616 {
2617   PSyncPoint sync;
2618   return ClearCallSynchronous(token, reason, &sync);
2619 }
2620 
2621 PBoolean H323EndPoint::ClearCallSynchronous(const PString & token,
2622                                         H323Connection::CallEndReason reason,
2623                                         PSyncPoint * sync)
2624 {
2625   if (PThread::Current() == connectionsCleaner)
2626     sync = NULL;
2627 
2628   /*The hugely multi-threaded nature of the H323Connection objects means that
2629     to avoid many forms of race condition, a call is cleared by moving it from
2630     the "active" call dictionary to a list of calls to be cleared that will be
2631     processed by a background thread specifically for the purpose of cleaning
2632     up cleared connections. So that is all that this function actually does.
2633     The real work is done in the H323ConnectionsCleaner thread.
2634    */
2635 
2636   {
2637     PWaitAndSignal wait(connectionsMutex);
2638 
2639     // Find the connection by token, callid or conferenceid
2640     H323Connection * connection = FindConnectionWithoutLocks(token);
2641     if (connection == NULL) {
2642       PTRACE(3, "H323\tAttempt to clear unknown call " << token);
2643       return FALSE;
2644     }
2645 
2646     PTRACE(3, "H323\tClearing connection " << connection->GetCallToken()
2647                                            << " reason=" << reason);
2648 
2649     OnCallClearing(connection,reason);
2650 
2651     // Add this to the set of connections being cleaned, if not in already
2652     if (!connectionsToBeCleaned.Contains(connection->GetCallToken()))
2653       connectionsToBeCleaned += connection->GetCallToken();
2654 
2655     // Now set reason for the connection close
2656     connection->SetCallEndReason(reason, sync);
2657 
2658     // Signal the background threads that there is some stuff to process.
2659     connectionsCleaner->Signal();
2660   }
2661 
2662   if (sync != NULL)
2663     sync->Wait();
2664 
2665   return TRUE;
2666 }
2667 
2668 
2669 void H323EndPoint::ClearAllCalls(H323Connection::CallEndReason reason,
2670                                  PBoolean wait)
2671 {
2672   /*The hugely multi-threaded nature of the H323Connection objects means that
2673     to avoid many forms of race condition, a call is cleared by moving it from
2674     the "active" call dictionary to a list of calls to be cleared that will be
2675     processed by a background thread specifically for the purpose of cleaning
2676     up cleared connections. So that is all that this function actually does.
2677     The real work is done in the H323ConnectionsCleaner thread.
2678    */
2679 
2680   connectionsMutex.Wait();
2681 
2682   // Add all connections to the to be deleted set
2683   PINDEX i;
2684   for (i = 0; i < connectionsActive.GetSize(); i++) {
2685     H323Connection & connection = connectionsActive.GetDataAt(i);
2686     connectionsToBeCleaned += connection.GetCallToken();
2687     // Now set reason for the connection close
2688     connection.SetCallEndReason(reason, NULL);
2689   }
2690 
2691   // Signal the background threads that there is some stuff to process.
2692   connectionsCleaner->Signal();
2693 
2694   // Make sure any previous signals are removed before waiting later
2695   while (connectionsAreCleaned.Wait(0))
2696     ;
2697 
2698   connectionsMutex.Signal();
2699 
2700   if (wait)
2701     connectionsAreCleaned.Wait();
2702 }
2703 
2704 void H323EndPoint::CleanUpConnections()
2705 {
2706   PTRACE(3, "H323\tCleaning up connections");
2707 
2708   // Lock the connections database.
2709   connectionsMutex.Wait();
2710 
2711   // Continue cleaning up until no more connections to clean
2712   while (connectionsToBeCleaned.GetSize() > 0) {
2713     // Just get the first entry in the set of tokens to clean up.
2714     PString token = connectionsToBeCleaned.GetKeyAt(0);
2715     H323Connection & connection = connectionsActive[token];
2716 
2717     // Unlock the structures here so does not block other uses of ClearCall()
2718     // for the possibly long time it takes to CleanUpOnCallEnd().
2719     connectionsMutex.Signal();
2720 
2721     // Clean up the connection, waiting for all threads to terminate
2722     connection.CleanUpOnCallEnd();
2723     connection.OnCleared();
2724 
2725     // Get the lock again as we remove the connection from our database
2726     connectionsMutex.Wait();
2727 
2728     // Remove the token from the set of connections to be cleaned up
2729     connectionsToBeCleaned -= token;
2730 
2731     // And remove the connection instance itself from the dictionary which will
2732     // cause its destructor to be called.
2733     H323Connection * connectionToDelete = connectionsActive.RemoveAt(token);
2734 
2735     // Unlock the structures yet again to avoid possible race conditions when
2736     // deleting the connection as well as the delte of a conncetion descendent
2737     // is application writer dependent and may cause deadlocks or just consume
2738     // lots of time.
2739     connectionsMutex.Signal();
2740 
2741     // Finally we get to delete it!
2742     // TODO: Clang Analysizer determines a false positive
2743     // Argument to 'delete' is a constant address (x), which is not memory allocated by 'new'
2744     delete connectionToDelete;
2745 
2746     // Get the lock again as we continue around the loop
2747     connectionsMutex.Wait();
2748   }
2749 
2750   // Finished with loop, unlock the connections database.
2751   connectionsMutex.Signal();
2752 
2753   // Signal thread that may be waiting on ClearAllCalls()
2754   connectionsAreCleaned.Signal();
2755 }
2756 
2757 PBoolean H323EndPoint::WillConnectionMutexBlock()
2758 {
2759     return !connectionsMutex.Try();
2760 }
2761 
2762 PBoolean H323EndPoint::HasConnection(const PString & token)
2763 {
2764   PWaitAndSignal wait(connectionsMutex);
2765 
2766   return FindConnectionWithoutLocks(token) != NULL;
2767 }
2768 
2769 H323Connection * H323EndPoint::FindConnectionWithLock(const PString & token)
2770 {
2771   PWaitAndSignal mutex(connectionsMutex);
2772 
2773   /*We have a very yucky polling loop here as a semi permanant measure.
2774     Why? We cannot call Lock() inside the connectionsMutex critical section as
2775     it will cause a deadlock with something like a RELEASE-COMPLETE coming in
2776     on separate thread. But if we put it outside there is a small window where
2777     the connection could get deleted before the Lock() test is done.
2778     The solution is to attempt to get the mutex while inside the
2779     connectionsMutex but not block. That means a polling loop. There is
2780     probably a way to do this properly with mutexes but I don't have time to
2781     figure it out.
2782    */
2783   H323Connection * connection;
2784   while ((connection = FindConnectionWithoutLocks(token)) != NULL) {
2785     switch (connection->TryLock()) {
2786       case 0 :
2787         return NULL;
2788       case 1 :
2789         return connection;
2790     }
2791     // Could not get connection lock, unlock the endpoint lists so a thread
2792     // that has the connection lock gets a chance at the endpoint lists.
2793     connectionsMutex.Signal();
2794     PThread::Sleep(20);
2795     connectionsMutex.Wait();
2796   }
2797 
2798   return NULL;
2799 }
2800 
2801 
2802 H323Connection * H323EndPoint::FindConnectionWithoutLocks(const PString & token)
2803 {
2804   if (token.IsEmpty())
2805     return NULL;
2806 
2807   H323Connection * conn_ptr = connectionsActive.GetAt(token);
2808   if (conn_ptr != NULL)
2809     return conn_ptr;
2810 
2811   PINDEX i;
2812   for (i = 0; i < connectionsActive.GetSize(); i++) {
2813     H323Connection & conn = connectionsActive.GetDataAt(i);
2814     if (conn.GetCallIdentifier().AsString() == token)
2815       return &conn;
2816   }
2817 
2818   for (i = 0; i < connectionsActive.GetSize(); i++) {
2819     H323Connection & conn = connectionsActive.GetDataAt(i);
2820     if (conn.GetConferenceIdentifier().AsString() == token)
2821       return &conn;
2822   }
2823 
2824   return NULL;
2825 }
2826 
2827 
2828 PStringList H323EndPoint::GetAllConnections()
2829 {
2830   PStringList tokens;
2831 
2832   connectionsMutex.Wait();
2833 
2834   for (PINDEX i = 0; i < connectionsActive.GetSize(); i++)
2835     tokens.AppendString(connectionsActive.GetKeyAt(i));
2836 
2837   connectionsMutex.Signal();
2838 
2839   return tokens;
2840 }
2841 
2842 
2843 PBoolean H323EndPoint::OnIncomingCall(H323Connection & /*connection*/,
2844                                   const H323SignalPDU & /*setupPDU*/,
2845                                   H323SignalPDU & /*alertingPDU*/)
2846 {
2847   return TRUE;
2848 }
2849 
2850 PBoolean H323EndPoint::OnIncomingCall(H323Connection & connection,
2851                              const H323SignalPDU & setupPDU,
2852                                    H323SignalPDU & alertingPDU,
2853                    H323Connection::CallEndReason & reason)
2854 {
2855   reason = H323Connection::EndedByNoAccept;
2856   return connection.OnIncomingCall(setupPDU, alertingPDU);
2857 }
2858 
2859 PBoolean H323EndPoint::OnCallTransferInitiate(H323Connection & /*connection*/,
2860                                           const PString & /*remoteParty*/)
2861 {
2862   return TRUE;
2863 }
2864 
2865 
2866 PBoolean H323EndPoint::OnCallTransferIdentify(H323Connection & /*connection*/)
2867 {
2868   return TRUE;
2869 }
2870 
2871 void H323EndPoint::OnSendARQ(H323Connection & /*conn*/, H225_AdmissionRequest & /*arq*/)
2872 {
2873 }
2874 
2875 void H323EndPoint::OnReceivedACF(H323Connection & /*conn*/, const H225_AdmissionConfirm & /*arq*/)
2876 {
2877 }
2878 
2879 void H323EndPoint::OnReceivedARJ(H323Connection & /*conn*/, const H225_AdmissionReject & /*arq*/)
2880 {
2881 }
2882 
2883 H323Connection::AnswerCallResponse
2884        H323EndPoint::OnAnswerCall(H323Connection & /*connection*/,
2885                                   const PString & PTRACE_PARAM(caller),
2886                                   const H323SignalPDU & /*setupPDU*/,
2887                                   H323SignalPDU & /*connectPDU*/)
2888 {
2889   PTRACE(2, "H225\tOnAnswerCall from \"" << caller << '"');
2890   return H323Connection::AnswerCallNow;
2891 }
2892 
2893 
2894 PBoolean H323EndPoint::OnAlerting(H323Connection & /*connection*/,
2895                               const H323SignalPDU & /*alertingPDU*/,
2896                               const PString & /*username*/)
2897 {
2898   PTRACE(1, "H225\tReceived alerting PDU.");
2899   return TRUE;
2900 }
2901 
2902 
2903 PBoolean H323EndPoint::OnConnectionForwarded(H323Connection & /*connection*/,
2904                                          const PString & /*forwardParty*/,
2905                                          const H323SignalPDU & /*pdu*/)
2906 {
2907   return FALSE;
2908 }
2909 
2910 
2911 PBoolean H323EndPoint::ForwardConnection(H323Connection & connection,
2912                                      const PString & forwardParty,
2913                                      const H323SignalPDU & /*pdu*/)
2914 {
2915   PString token = connection.GetCallToken();
2916 
2917  PStringList Addresses;
2918   if (!ResolveCallParty(forwardParty, Addresses))
2919     return FALSE;
2920 
2921   H323Connection * newConnection = NULL;
2922      for (PINDEX i = 0; i < Addresses.GetSize(); i++) {
2923           newConnection = InternalMakeCall(PString::Empty(),
2924                                            PString::Empty(),
2925                                            UINT_MAX,
2926                                            Addresses[i],
2927                                            NULL,
2928                                            token,
2929                                            NULL);
2930         if (newConnection != NULL)
2931              break;
2932      }
2933 
2934 
2935      if (newConnection == NULL)
2936          return FALSE;
2937 
2938      connection.SetCallEndReason(H323Connection::EndedByCallForwarded);
2939      newConnection->Unlock();
2940      return TRUE;
2941 }
2942 
2943 
2944 void H323EndPoint::OnConnectionEstablished(H323Connection & /*connection*/,
2945                                            const PString & /*token*/)
2946 {
2947 }
2948 
2949 
2950 PBoolean H323EndPoint::IsConnectionEstablished(const PString & token)
2951 {
2952   H323Connection * connection = FindConnectionWithLock(token);
2953   if (connection == NULL)
2954     return FALSE;
2955 
2956   PBoolean established = connection->IsEstablished();
2957   connection->Unlock();
2958   return established;
2959 }
2960 
2961 
2962 PBoolean H323EndPoint::OnOutgoingCall(H323Connection & /*connection*/,
2963                              const H323SignalPDU & /*connectPDU*/)
2964 {
2965   PTRACE(1, "H225\tReceived connect PDU.");
2966   return TRUE;
2967 }
2968 
2969 
2970 void H323EndPoint::OnConnectionCleared(H323Connection & /*connection*/,
2971                                        const PString & /*token*/)
2972 {
2973 }
2974 
2975 
2976 PString H323EndPoint::BuildConnectionToken(const H323Transport & transport,
2977                                            unsigned callReference,
2978                                            PBoolean fromRemote)
2979 {
2980   PString token;
2981 
2982   if (fromRemote)
2983     token = transport.GetRemoteAddress();
2984   else
2985     token = "ip$localhost";
2986 
2987   token.sprintf("/%u", callReference);
2988 
2989   return token;
2990 }
2991 
2992 
2993 H323Connection * H323EndPoint::OnIncomingConnection(H323Transport * transport,
2994                                                     H323SignalPDU & setupPDU)
2995 {
2996   unsigned callReference = setupPDU.GetQ931().GetCallReference();
2997   PString token = BuildConnectionToken(*transport, callReference, TRUE);
2998 
2999   connectionsMutex.Wait();
3000   H323Connection * connection = connectionsActive.GetAt(token);
3001   connectionsMutex.Signal();
3002 
3003   if (connection == NULL) {
3004     connection = CreateConnection(callReference, NULL, transport, &setupPDU);
3005     if (connection == NULL) {
3006       PTRACE(1, "H323\tCreateConnection returned NULL");
3007       return NULL;
3008     }
3009 
3010     PTRACE(3, "H323\tCreated new connection: " << token);
3011 
3012     connectionsMutex.Wait();
3013     connectionsActive.SetAt(token, connection);
3014     connectionsMutex.Signal();
3015   }
3016 
3017   connection->AttachSignalChannel(token, transport, TRUE);
3018 
3019   return connection;
3020 }
3021 
3022 
3023 H323Connection * H323EndPoint::CreateConnection(unsigned callReference,
3024                                                 void * userData,
3025                                                 H323Transport * /*transport*/,
3026                                                 H323SignalPDU * /*setupPDU*/)
3027 {
3028   return CreateConnection(callReference, userData);
3029 }
3030 
3031 
3032 H323Connection * H323EndPoint::CreateConnection(unsigned callReference, void * /*userData*/)
3033 {
3034   return CreateConnection(callReference);
3035 }
3036 
3037 H323Connection * H323EndPoint::CreateConnection(unsigned callReference)
3038 {
3039   return new H323Connection(*this, callReference);
3040 }
3041 
3042 
3043 #if PTRACING
3044 static void OnStartStopChannel(const char * startstop, const H323Channel & channel)
3045 {
3046   const char * dir;
3047   switch (channel.GetDirection()) {
3048     case H323Channel::IsTransmitter :
3049       dir = "send";
3050       break;
3051 
3052     case H323Channel::IsReceiver :
3053       dir = "receiv";
3054       break;
3055 
3056     default :
3057       dir = "us";
3058       break;
3059   }
3060 
3061   PTRACE(2, "H323\t" << startstop << "ed "
3062                      << dir << "ing logical channel: "
3063                      << channel.GetCapability());
3064 }
3065 #endif
3066 
3067 
3068 PBoolean H323EndPoint::OnStartLogicalChannel(H323Connection & /*connection*/,
3069                                          H323Channel & PTRACE_PARAM(channel))
3070 {
3071 #if PTRACING
3072   OnStartStopChannel("Start", channel);
3073 #endif
3074   return TRUE;
3075 }
3076 
3077 
3078 void H323EndPoint::OnClosedLogicalChannel(H323Connection & /*connection*/,
3079                                           const H323Channel & PTRACE_PARAM(channel))
3080 {
3081 #if PTRACING
3082   OnStartStopChannel("Stopp", channel);
3083 #endif
3084 }
3085 
3086 
3087 #ifdef H323_AUDIO_CODECS
3088 
3089 PBoolean H323EndPoint::OpenAudioChannel(H323Connection & /*connection*/,
3090                                     PBoolean isEncoding,
3091                                     unsigned bufferSize,
3092                                     H323AudioCodec & codec)
3093 {
3094   codec.SetSilenceDetectionMode(GetSilenceDetectionMode());
3095 
3096 #ifdef P_AUDIO
3097 
3098   int rate = codec.GetMediaFormat().GetTimeUnits() * 1000;
3099 
3100   PString deviceName;
3101   PString deviceDriver;
3102   if (isEncoding) {
3103     deviceName   = GetSoundChannelRecordDevice();
3104     deviceDriver = GetSoundChannelRecordDriver();
3105   } else {
3106     deviceName = GetSoundChannelPlayDevice();
3107     deviceDriver = GetSoundChannelPlayDriver();
3108   }
3109 
3110   PSoundChannel * soundChannel;
3111   if (!deviceDriver.IsEmpty())
3112     soundChannel = PSoundChannel::CreateChannel(deviceDriver);
3113   else {
3114     soundChannel = new PSoundChannel;
3115     deviceDriver = "default";
3116   }
3117 
3118   if (soundChannel == NULL) {
3119     PTRACE(1, "Codec\tCould not open a sound channel for " << deviceDriver);
3120     return FALSE;
3121   }
3122 
3123   if (soundChannel->Open(deviceName, isEncoding ? PSoundChannel::Recorder
3124                                                 : PSoundChannel::Player,
3125                          1, rate, 16
3126 #if PTLIB_VER >= 2130
3127                          , NULL
3128 #endif
3129                          )) {
3130 
3131     PTRACE(3, "Codec\tOpened sound channel \"" << deviceName
3132            << "\" for " << (isEncoding ? "record" : "play")
3133            << "ing at " << rate << " samples/second using " << soundChannelBuffers
3134            << 'x' << bufferSize << " byte buffers.");
3135     soundChannel->SetBuffers(bufferSize, soundChannelBuffers);
3136     return codec.AttachChannel(soundChannel);
3137   }
3138 
3139   PTRACE(1, "Codec\tCould not open " << deviceDriver << " sound channel \"" << deviceName
3140          << "\" for " << (isEncoding ? "record" : "play")
3141          << "ing: " << soundChannel->GetErrorText());
3142 
3143   delete soundChannel;
3144 
3145 #endif
3146 
3147   return FALSE;
3148 }
3149 
3150 #endif // H323_AUDIO_CODECS
3151 
3152 
3153 #ifdef H323_VIDEO
3154 PBoolean H323EndPoint::OpenVideoChannel(H323Connection & /*connection*/,
3155                                     PBoolean PTRACE_PARAM(isEncoding),
3156                                     H323VideoCodec & /*codec*/)
3157 {
3158   PTRACE(1, "Codec\tCould not open video channel for "
3159          << (isEncoding ? "captur" : "display")
3160          << "ing: not yet implemented");
3161   return FALSE;
3162 }
3163 
3164 #ifdef H323_H239
3165 PBoolean H323EndPoint::OpenExtendedVideoChannel(H323Connection & /*connection*/,
3166                                             PBoolean PTRACE_PARAM(isEncoding),
3167                                             H323VideoCodec & /*codec*/)
3168 {
3169   PTRACE(1, "Codec\tCould not open extended video channel for "
3170          << (isEncoding ? "captur" : "display")
3171          << "ing: not yet implemented");
3172   return FALSE;
3173 }
3174 #endif // H323_H239
3175 #endif // NO_H323_VIDEO
3176 
3177 
3178 void H323EndPoint::OnRTPStatistics(const H323Connection & /*connection*/,
3179                                    const RTP_Session & /*session*/) const
3180 {
3181 }
3182 
3183 void H323EndPoint::OnRTPFinalStatistics(const H323Connection & /*connection*/,
3184                                    const RTP_Session & /*session*/) const
3185 {
3186 }
3187 
3188 
3189 void H323EndPoint::OnUserInputString(H323Connection & /*connection*/,
3190                                      const PString & /*value*/)
3191 {
3192 }
3193 
3194 
3195 void H323EndPoint::OnUserInputTone(H323Connection & connection,
3196                                    char tone,
3197                                    unsigned /*duration*/,
3198                                    unsigned /*logicalChannel*/,
3199                                    unsigned /*rtpTimestamp*/)
3200 {
3201   // don't pass through signalUpdate messages
3202   if (tone != ' ')
3203     connection.OnUserInputString(PString(tone));
3204 }
3205 
3206 #ifdef H323_GNUGK
3207 void H323EndPoint::OnGatekeeperNATDetect(
3208                                    PIPSocket::Address publicAddr,
3209                                    const PString & gkIdentifier,
3210                            H323TransportAddress & gkRouteAddress
3211                                    )
3212 {
3213     if (gnugk != NULL) {
3214         if (gnugk->ReRegister(gkIdentifier))
3215             return;
3216         else {
3217                PTRACE(4, "GNUGK\tReRegistration Failure. Attempting new connection");
3218             if (!gnugk->CreateNewTransport()) {
3219               PTRACE(4, "GNUGK\tNAT Support Failure: Retry from scratch");
3220                delete gnugk;
3221                gnugk = NULL;
3222             }
3223         }
3224     }
3225 
3226     gnugk = new GNUGK_Feature(*this,gkRouteAddress,gkIdentifier);
3227 
3228 #ifdef P_STUN
3229      if (gnugk->IsOpen()) {
3230           PTRACE(4, "GNUGK\tNat Address " << gkRouteAddress);
3231 
3232          PNatMethod_GnuGk * natMethod = (PNatMethod_GnuGk *)natMethods->LoadNatMethod("GnuGk");
3233          if (natMethods) {
3234              natMethod->AttachEndPoint(this);
3235              natMethod->SetAvailable();
3236              natMethods->AddMethod(natMethod);
3237          }
3238          return;
3239      }
3240 #endif
3241 
3242       PTRACE(4, "GNUGK\tConnection failed. Disabling support.");
3243       delete gnugk;
3244       gnugk = NULL;
3245 }
3246 
3247 void H323EndPoint::OnGatekeeperOpenNATDetect(
3248                           const PString & /*gkIdentifier*/,
3249                    H323TransportAddress & /*gkRouteAddress*/
3250                                    )
3251 {
3252 }
3253 #endif
3254 
3255 PBoolean H323EndPoint::OnGatekeeperAliases(
3256         const H225_ArrayOf_AliasAddress & /*aliases*/
3257                                       )
3258 {
3259     return FALSE;
3260 }
3261 
3262 #ifdef H323_H248
3263 
3264 void H323EndPoint::OnHTTPServiceControl(unsigned /*opeartion*/,
3265                                         unsigned /*sessionId*/,
3266                                         const PString & /*url*/)
3267 {
3268 }
3269 
3270 void H323EndPoint::OnCallCreditServiceControl(const PString & amount, PBoolean mode, const unsigned & /*durationLimit*/)
3271 {
3272     OnCallCreditServiceControl(amount, mode);
3273 }
3274 
3275 void H323EndPoint::OnCallCreditServiceControl(const PString & /*amount*/, PBoolean /*mode*/)
3276 {
3277 }
3278 
3279 #ifdef H323_H350
3280 void H323EndPoint::OnH350ServiceControl(const PString & /*url*/,
3281                                         const PString & /*BaseDN*/)
3282 {
3283 }
3284 #endif
3285 
3286 void H323EndPoint::OnServiceControlSession(unsigned type,
3287                                            unsigned sessionId,
3288                                            const H323ServiceControlSession & session,
3289                                            H323Connection * connection)
3290 {
3291   session.OnChange(type, sessionId, *this, connection);
3292 }
3293 
3294 H323ServiceControlSession * H323EndPoint::CreateServiceControlSession(const H225_ServiceControlDescriptor & contents)
3295 {
3296   switch (contents.GetTag()) {
3297     case H225_ServiceControlDescriptor::e_url :
3298       return new H323HTTPServiceControl(contents);
3299 
3300     case H225_ServiceControlDescriptor::e_callCreditServiceControl :
3301       return new H323CallCreditServiceControl(contents);
3302 #ifdef H323_H350
3303     case H225_ServiceControlDescriptor::e_nonStandard  :
3304       return new H323H350ServiceControl(contents);
3305 #endif
3306   }
3307 
3308   return NULL;
3309 }
3310 
3311 #endif // H323_H248
3312 
3313 PBoolean H323EndPoint::OnConferenceInvite(PBoolean /*sending*/,
3314       const H323Connection * /*connection*/,
3315       const H323SignalPDU & /*setupPDU */)
3316 {
3317   return FALSE;
3318 }
3319 
3320 PBoolean H323EndPoint::OnSendCallIndependentSupplementaryService(const H323Connection * connection,
3321                                                              H323SignalPDU & pdu )
3322 {
3323 
3324 #ifdef H323_H460
3325 
3326   if (!connection->IsNonCallConnection())
3327       return false;
3328 
3329   H225_Setup_UUIE & setup = pdu.m_h323_uu_pdu.m_h323_message_body;
3330   setup.m_conferenceGoal.SetTag(H225_Setup_UUIE_conferenceGoal::e_callIndependentSupplementaryService);
3331 
3332   PTRACE(6,"EP\tSending H.460 Call Independent Supplementary Service");
3333   return true;
3334 
3335 #else
3336   return false;
3337 #endif
3338 }
3339 
3340 PBoolean H323EndPoint::OnReceiveCallIndependentSupplementaryService(const H323Connection * connection,
3341                                                                 const H323SignalPDU & pdu)
3342 {
3343     PTRACE(2,"EP\tRejected CallIndependentSupplementaryService as no support in EndPoint.");
3344     return false;
3345 }
3346 
3347 PBoolean H323EndPoint::OnNegotiateConferenceCapabilities(const H323SignalPDU & /* setupPDU */)
3348 {
3349   return FALSE;
3350 }
3351 
3352 #ifdef H323_T120
3353 OpalT120Protocol * H323EndPoint::CreateT120ProtocolHandler(const H323Connection &) const
3354 {
3355   return NULL;
3356 }
3357 #endif
3358 
3359 
3360 #ifdef H323_T38
3361 OpalT38Protocol * H323EndPoint::CreateT38ProtocolHandler(const H323Connection &) const
3362 {
3363   return NULL;
3364 }
3365 #endif
3366 
3367 #ifdef H323_H224
3368 
3369 OpalH224Handler * H323EndPoint::CreateH224ProtocolHandler(H323Channel::Directions dir, H323Connection & connection,
3370                                                           unsigned sessionID) const
3371 {
3372     return new OpalH224Handler(dir, connection, sessionID);
3373 }
3374 
3375 PBoolean H323EndPoint::OnCreateH224Handler(H323Channel::Directions /*dir*/, const H323Connection & /*connection*/, const PString & id, H224_Handler * /*m_handler*/) const
3376 {
3377     if (id == "H281")
3378         return true;
3379     else
3380         return false;
3381 }
3382 
3383 #ifdef H224_H281
3384 H224_H281Handler * H323EndPoint::CreateH281ProtocolHandler(OpalH224Handler & h224Handler) const
3385 {
3386     return new H224_H281Handler(h224Handler);
3387 }
3388 #endif
3389 
3390 #endif
3391 
3392 #ifdef H323_T140
3393 H323_RFC4103Handler * H323EndPoint::CreateRFC4103ProtocolHandler(H323Channel::Directions dir, H323Connection & connection, unsigned sessionID)
3394 {
3395     return new H323_RFC4103Handler(dir, connection, sessionID);
3396 }
3397 #endif // H323_T140
3398 
3399 #ifdef H323_FILE
3400 PBoolean H323EndPoint::OpenFileTransferSession( const H323FileTransferList & list,
3401                                                 const PString & token,
3402                                                 H323ChannelNumber & num
3403                                                 )
3404 {
3405   H323Connection * connection = FindConnectionWithLock(token);
3406 
3407   PBoolean success = FALSE;
3408   if (connection != NULL) {
3409     success = connection->OpenFileTransferSession(list,num);
3410     connection->Unlock();
3411   }
3412 
3413   return success;
3414 }
3415 
3416 PBoolean H323EndPoint::OpenFileTransferChannel(H323Connection & connection,
3417                                              PBoolean PTRACE_PARAM(isEncoder),
3418                                              H323FileTransferList & filelist
3419                                             )
3420 {
3421    PTRACE(2,"FT\tAttempt to open File Transfer session! Not implemented Yet!");
3422    return FALSE;
3423 }
3424 #endif
3425 
3426 void H323EndPoint::SetLocalUserName(const PString & name)
3427 {
3428   if (name.IsEmpty()) {
3429     PTRACE(1, "Error: Must have non-empty string in AliasAddress!");
3430     return;
3431   }
3432 
3433   localAliasNames.RemoveAll();
3434   localAliasNames.SetSize(0);
3435   localAliasNames.AppendString(name);
3436 }
3437 
3438 
3439 PBoolean H323EndPoint::AddAliasName(const PString & name)
3440 {
3441   if (name.IsEmpty()) {
3442     PTRACE(1, "Error: Must have non-empty string in AliasAddress!");
3443     return FALSE;
3444   }
3445 
3446   if (localAliasNames.GetValuesIndex(name) != P_MAX_INDEX)
3447     return FALSE;
3448 
3449   localAliasNames.AppendString(name);
3450   return TRUE;
3451 }
3452 
3453 
3454 PBoolean H323EndPoint::RemoveAliasName(const PString & name)
3455 {
3456   PINDEX pos = localAliasNames.GetValuesIndex(name);
3457   if (pos == P_MAX_INDEX)
3458     return FALSE;
3459 
3460   if (localAliasNames.GetSize() < 2) {
3461     PTRACE(1, "Error: Must have at least one AliasAddress!");
3462     return FALSE;
3463   }
3464 
3465 #if PTLIB_VER >= 2110
3466   localAliasNames.Remove(&name);
3467 #else
3468   localAliasNames.RemoveAt(pos);
3469 #endif
3470   return TRUE;
3471 }
3472 
3473 #ifdef H323_AUDIO_CODECS
3474 
3475 #ifdef P_AUDIO
3476 
3477 PBoolean H323EndPoint::SetSoundChannelPlayDevice(const PString & name)
3478 {
3479   if (PSoundChannel::GetDeviceNames(soundChannelPlayDriver,PSoundChannel::Player).GetValuesIndex(name) == P_MAX_INDEX)
3480     return FALSE;
3481 
3482   soundChannelPlayDevice = name;
3483   return TRUE;
3484 }
3485 
3486 
3487 PBoolean H323EndPoint::SetSoundChannelRecordDevice(const PString & name)
3488 {
3489   if (PSoundChannel::GetDeviceNames(soundChannelRecordDriver,PSoundChannel::Recorder).GetValuesIndex(name) == P_MAX_INDEX)
3490     return FALSE;
3491 
3492   soundChannelRecordDevice = name;
3493   return TRUE;
3494 }
3495 
3496 
3497 PBoolean H323EndPoint::SetSoundChannelPlayDriver(const PString & name)
3498 {
3499   PPluginManager & pluginMgr = PPluginManager::GetPluginManager();
3500 #if PTLIB_VER >= 2130
3501   PStringList list = pluginMgr.GetPluginsProviding("PSoundChannel", false);
3502 #else
3503   PStringList list = pluginMgr.GetPluginsProviding("PSoundChannel");
3504 #endif
3505   if (list.GetValuesIndex(name) == P_MAX_INDEX)
3506     return FALSE;
3507 
3508   soundChannelPlayDriver = name;
3509   soundChannelPlayDevice.MakeEmpty();
3510   list = PSoundChannel::GetDeviceNames(name, PSoundChannel::Player);
3511   if (list.GetSize() == 0)
3512     return FALSE;
3513 
3514   soundChannelPlayDevice = list[0];
3515   return TRUE;
3516 }
3517 
3518 
3519 PBoolean H323EndPoint::SetSoundChannelRecordDriver(const PString & name)
3520 {
3521   PPluginManager & pluginMgr = PPluginManager::GetPluginManager();
3522 #if PTLIB_VER >= 2130
3523   PStringList list = pluginMgr.GetPluginsProviding("PSoundChannel", false);
3524 #else
3525   PStringList list = pluginMgr.GetPluginsProviding("PSoundChannel");
3526 #endif
3527   if (list.GetValuesIndex(name) == P_MAX_INDEX)
3528     return FALSE;
3529 
3530   soundChannelRecordDriver = name;
3531   list = PSoundChannel::GetDeviceNames(name, PSoundChannel::Recorder);
3532   if (list.GetSize() == 0)
3533     return FALSE;
3534 
3535   soundChannelRecordDevice = list[0];
3536   return TRUE;
3537 }
3538 
3539 
3540 void H323EndPoint::SetSoundChannelBufferDepth(unsigned depth)
3541 {
3542   PAssert(depth > 1, PInvalidParameter);
3543   soundChannelBuffers = depth;
3544 }
3545 
3546 #endif  // P_AUDIO
3547 
3548 #endif  // H323_AUDIO_CODECS
3549 
3550 
3551 void H323EndPoint::SetTerminalType(TerminalTypes type)
3552 {
3553     terminalType = type;
3554     rewriteParsePartyName = (terminalType < e_GatewayOnly);
3555 }
3556 
3557 
3558 PBoolean H323EndPoint::IsTerminal() const
3559 {
3560   switch (terminalType) {
3561     case e_TerminalOnly :
3562     case e_TerminalAndMC :
3563       return TRUE;
3564 
3565     default :
3566       return FALSE;
3567   }
3568 }
3569 
3570 
3571 PBoolean H323EndPoint::IsGateway() const
3572 {
3573   switch (terminalType) {
3574     case e_GatewayOnly :
3575     case e_GatewayAndMC :
3576     case e_GatewayAndMCWithDataMP :
3577     case e_GatewayAndMCWithAudioMP :
3578     case e_GatewayAndMCWithAVMP :
3579       return TRUE;
3580 
3581     default :
3582       return FALSE;
3583   }
3584 }
3585 
3586 
3587 PBoolean H323EndPoint::IsGatekeeper() const
3588 {
3589   switch (terminalType) {
3590     case e_GatekeeperOnly :
3591     case e_GatekeeperWithDataMP :
3592     case e_GatekeeperWithAudioMP :
3593     case e_GatekeeperWithAVMP :
3594       return TRUE;
3595 
3596     default :
3597       return FALSE;
3598   }
3599 }
3600 
3601 
3602 PBoolean H323EndPoint::IsMCU() const
3603 {
3604   switch (terminalType) {
3605     case e_MCUOnly :
3606     case e_MCUWithDataMP :
3607     case e_MCUWithAudioMP :
3608     case e_MCUWithAVMP :
3609       return TRUE;
3610 
3611     default :
3612       return FALSE;
3613   }
3614 }
3615 
3616 PBoolean H323EndPoint::IsSimpleEndPoint() const
3617 {
3618 #ifdef H323_H461
3619   switch (terminalType) {
3620     case e_SET_H461 :
3621       return TRUE;
3622     default :
3623       break;
3624   }
3625 #endif
3626   return FALSE;
3627 }
3628 
3629 #ifdef H323_AUDIO_CODECS
3630 
3631 void H323EndPoint::SetAudioJitterDelay(unsigned minDelay, unsigned maxDelay)
3632 {
3633   if (minDelay == 0 && maxDelay == 0) {
3634     // Disable jitter buffer
3635     minAudioJitterDelay = 0;
3636     maxAudioJitterDelay = 0;
3637     return;
3638   }
3639 
3640   PAssert(minDelay <= 10000 && maxDelay <= 10000, PInvalidParameter);
3641 
3642   if (minDelay < 10)
3643     minDelay = 10;
3644   minAudioJitterDelay = minDelay;
3645 
3646   if (maxDelay < minDelay)
3647     maxDelay = minDelay;
3648   maxAudioJitterDelay = maxDelay;
3649 }
3650 
3651 #endif
3652 
3653 #ifdef P_STUN
3654 
3655 PSTUNClient * H323EndPoint::GetSTUN(const PIPSocket::Address & ip) const
3656 {
3657   if (ip.IsValid() && IsLocalAddress(ip))
3658     return NULL;
3659 
3660   return (PSTUNClient *)GetNatMethods().GetMethodByName("STUN");
3661 }
3662 
3663 PNatMethod * H323EndPoint::GetPreferedNatMethod(const PIPSocket::Address & ip)
3664 {
3665 
3666 #if PTRACING
3667     PNatMethod * meth = NULL;
3668     const H323NatList & list = natMethods->GetNATList();
3669     if (list.GetSize() > 0) {
3670       for (PINDEX i=0; i < list.GetSize(); i++) {
3671 #if PTLIB_VER >= 2130
3672         PString name = list[i].GetMethodName();
3673 #else
3674         PString name = list[i].GetName();
3675 #endif
3676         PTRACE(6, "H323\tNAT Method " << i << " " << name
3677             << " Ready: " << (list[i].IsAvailable(ip) ? "Yes" : "No"));
3678         if (list[i].IsAvailable(ip)) {
3679              meth = &list[i];
3680              break;
3681         }
3682       }
3683     } else {
3684        PTRACE(6, "H323\tNo NAT Methods!");
3685     }
3686     return meth;
3687 #else
3688   return natMethods->GetMethod(ip);
3689 #endif
3690 
3691 }
3692 
3693 H323NatStrategy & H323EndPoint::GetNatMethods() const
3694 {
3695     return *natMethods;
3696 }
3697 
3698 void H323EndPoint::SetSTUNServer(const PString & server)
3699 {
3700   natMethods->RemoveMethod("STUN");
3701 
3702   if (!server.IsEmpty()) {
3703     PSTUNClient * stun = (PSTUNClient *)GetNatMethods().LoadNatMethod("STUN");
3704     stun->SetServer(server);
3705     stun->SetPortRanges(GetUDPPortBase(), GetUDPPortMax(),
3706                            GetRtpIpPortBase(), GetRtpIpPortMax());
3707 
3708     natMethods->AddMethod(stun);
3709 
3710     PTRACE(2, "H323\tSTUN server \"" << server << "\" replies " << stun->GetNatTypeName());
3711 
3712     STUNNatType((int)stun->GetNatType());
3713   }
3714 }
3715 
3716 #endif // P_STUN
3717 
3718 #ifdef H323_UPnP
3719 PBoolean H323EndPoint::InitialiseUPnP()
3720 {
3721      if (!m_UPnPenabled)
3722          return false;
3723 
3724      PNatMethod_UPnP * natMethod = (PNatMethod_UPnP *)GetNatMethods().GetMethodByName("UPnP");
3725      if (natMethod)
3726          return true;
3727 
3728      natMethod = (PNatMethod_UPnP *)GetNatMethods().LoadNatMethod("UPnP");
3729      if (!natMethod)
3730          return false;
3731 
3732      PTRACE(4,"EP\tStarting UPnP");
3733      natMethod->AttachEndPoint(this);
3734      GetNatMethods().AddMethod(natMethod);
3735      return true;
3736 }
3737 
3738 PBoolean H323EndPoint::OnUPnPAvailable(const PString & device, const PIPSocket::Address & publicIP, PNatMethod_UPnP * nat)
3739 {
3740     PTRACE(2,"EP\tUPnP Device " << device << " Public IP: " << publicIP);
3741 
3742     NATMethodCallBack("UPnP", 1, "Available");
3743     NATMethodCallBack("UPnP", 3,  publicIP);
3744 
3745     return false;
3746 }
3747 
3748 #endif  // H323_UPnP
3749 
3750 void H323EndPoint::InternalTranslateTCPAddress(PIPSocket::Address & localAddr, const PIPSocket::Address & remoteAddr,
3751                                                const H323Connection * connection)
3752 {
3753 
3754   if (remoteAddr.GetVersion() != 4)
3755       return;
3756 
3757 #ifdef P_STUN
3758   // if using NAT Method, then translate internal local address to external if required
3759   if (connection && !connection->HasNATSupport())
3760       return;
3761 
3762   if (localAddr.IsRFC1918() && !remoteAddr.IsRFC1918()) {
3763       if (!connection) {
3764         PNatMethod * stun = GetNatMethods().GetMethodByName("STUN");
3765         if (stun && stun->IsAvailable(remoteAddr) && stun->GetExternalAddress(localAddr)) {
3766            PTRACE(2,"EP\tSTUN set localIP as " << localAddr);
3767         } else {
3768             const H323NatList & list = natMethods->GetNATList();
3769               for (PINDEX i=0; i < list.GetSize(); i++) {
3770 #if PTLIB_VER >= 2130
3771                   PString name = list[i].GetMethodName();
3772 #else
3773                   PString name = list[i].GetName();
3774 #endif
3775                   if (list[i].IsAvailable(remoteAddr) && list[i].GetExternalAddress(localAddr)) {
3776                      PTRACE(2,"EP\tNATMethod " << name
3777                          << " rewrite localIP as " << localAddr);
3778                      break;
3779                   }
3780               }
3781         }
3782       }
3783    }
3784   else
3785 #endif // P_STUN
3786      TranslateTCPAddress(localAddr, remoteAddr);
3787 }
3788 
3789 PBoolean H323EndPoint::IsLocalAddress(const PIPSocket::Address & ip) const
3790 {
3791   /* Check if the remote address is a private IP, broadcast, or us */
3792   return ip.IsRFC1918() || ip.IsBroadcast() || PIPSocket::IsLocalHost(ip);
3793 }
3794 
3795 
3796 void H323EndPoint::PortInfo::Set(unsigned newBase,
3797                                  unsigned newMax,
3798                                  unsigned range,
3799                                  unsigned dflt)
3800 {
3801   if (newBase == 0) {
3802     newBase = dflt;
3803     newMax = dflt;
3804     if (dflt > 0)
3805       newMax += range;
3806   }
3807   else {
3808     if (newBase < 1024)
3809       newBase = 1024;
3810     else if (newBase > 65500)
3811       newBase = 65500;
3812 
3813     if (newMax <= newBase)
3814       newMax = newBase + range;
3815     if (newMax > 65535)
3816       newMax = 65535;
3817   }
3818 
3819   mutex.Wait();
3820 
3821   current = base = (WORD)newBase;
3822   max = (WORD)newMax;
3823 
3824   mutex.Signal();
3825 }
3826 
3827 
3828 WORD H323EndPoint::PortInfo::GetNext(unsigned increment)
3829 {
3830   PWaitAndSignal m(mutex);
3831 
3832   if (current < base || current > (max-increment))
3833     current = base;
3834 
3835   if (current == 0)
3836     return 0;
3837 
3838   WORD p = current;
3839   current = (WORD)(current + increment);
3840   return p;
3841 }
3842 
3843 #ifdef H323_H46019M
3844 unsigned H323EndPoint::MuxIDInfo::GetNext(unsigned increment)
3845 {
3846   PWaitAndSignal m(mutex);
3847 
3848   if (current < base || current > (max-increment))
3849     current = base;
3850 
3851   if (current == 0)
3852     return 0;
3853 
3854   current = current + increment;
3855   return current;
3856 }
3857 #endif
3858 
3859 void H323EndPoint::SetTCPPorts(unsigned tcpBase, unsigned tcpMax)
3860 {
3861   tcpPorts.Set(tcpBase, tcpMax, 99, 0);
3862 }
3863 
3864 
3865 WORD H323EndPoint::GetNextTCPPort()
3866 {
3867   return tcpPorts.GetNext(1);
3868 }
3869 
3870 
3871 void H323EndPoint::SetUDPPorts(unsigned udpBase, unsigned udpMax)
3872 {
3873   udpPorts.Set(udpBase, udpMax, 199, 0);
3874 
3875 #ifdef P_STUN
3876     natMethods->SetPortRanges(GetUDPPortBase(), GetUDPPortMax(), GetRtpIpPortBase(), GetRtpIpPortMax());
3877 #endif
3878 }
3879 
3880 
3881 WORD H323EndPoint::GetNextUDPPort()
3882 {
3883   return udpPorts.GetNext(1);
3884 }
3885 
3886 
3887 void H323EndPoint::SetRtpIpPorts(unsigned rtpIpBase, unsigned rtpIpMax)
3888 {
3889   rtpIpPorts.Set((rtpIpBase+1)&0xfffe, rtpIpMax&0xfffe, 999, 5000);
3890 
3891 #ifdef P_STUN
3892   natMethods->SetPortRanges(GetUDPPortBase(), GetUDPPortMax(), GetRtpIpPortBase(), GetRtpIpPortMax());
3893 #endif
3894 }
3895 
3896 
3897 WORD H323EndPoint::GetRtpIpPortPair()
3898 {
3899   return rtpIpPorts.GetNext(2);
3900 }
3901 
3902 #ifdef H323_H46019M
3903 void H323EndPoint::SetMultiplexPort(unsigned rtpPort)
3904 {
3905     defaultMultiRTPPort = rtpPort;
3906 }
3907 
3908 WORD H323EndPoint::GetMultiplexPort()
3909 {
3910     return defaultMultiRTPPort;
3911 }
3912 
3913 unsigned H323EndPoint::GetMultiplexID()
3914 {
3915    return rtpMuxID.GetNext(1);
3916 }
3917 #endif
3918 
3919 const PTimeInterval & H323EndPoint::GetNoMediaTimeout() const
3920 {
3921   PWaitAndSignal m(noMediaMutex);
3922 
3923   return noMediaTimeout;
3924 }
3925 
3926 PBoolean H323EndPoint::SetNoMediaTimeout(PTimeInterval newInterval)
3927 {
3928   PWaitAndSignal m(noMediaMutex);
3929 
3930   if (newInterval < 0)
3931     return FALSE;
3932 
3933   noMediaTimeout = newInterval;
3934   return TRUE;
3935 }
3936 
3937 PBoolean H323EndPoint::OnSendFeatureSet(unsigned pdu, H225_FeatureSet & feats, PBoolean advertise)
3938 {
3939 #ifdef H323_H460
3940     return features.SendFeature(pdu,feats,advertise);
3941 #else
3942     return FALSE;
3943 #endif
3944 }
3945 
3946 void H323EndPoint::OnReceiveFeatureSet(unsigned pdu, const H225_FeatureSet & feats, PBoolean genericData)
3947 {
3948 #ifdef H323_H460
3949     features.ReceiveFeature(pdu,feats,genericData);
3950 #endif
3951 }
3952 
3953 #ifdef H323_H460
3954 H460_FeatureSet * H323EndPoint::GetGatekeeperFeatures()
3955 {
3956     if (gatekeeper != NULL) {
3957         return &gatekeeper->GetFeatures();
3958     }
3959 
3960     return NULL;
3961 }
3962 #endif
3963 
3964 void H323EndPoint::LoadBaseFeatureSet()
3965 {
3966 #ifdef H323_H460
3967   features.AttachEndPoint(this);
3968   features.LoadFeatureSet(H460_Feature::FeatureBase);
3969 #endif
3970 }
3971 
3972 #ifdef H323_H46017
3973 PBoolean H323EndPoint::H46017CreateConnection(const PString & gatekeeper, PBoolean useSRV)
3974 {
3975    m_registeredWithH46017 = false;
3976    H460_FeatureStd17 * h46017 = (H460_FeatureStd17 *)features.GetFeature(17);
3977    if(!h46017) {
3978        PTRACE(4, "EP\tCan't create H.460.17 feature - plugin loaded ?");
3979        return false;
3980    }
3981 
3982    m_tryingH46017 = true;
3983    registrationTimeToLive = PTimeInterval(0, 19);
3984    m_registeredWithH46017 = h46017->Initialise(&m_transportSecurity, gatekeeper, useSRV);
3985    if (!m_registeredWithH46017) {
3986        PTRACE(4, "EP\tH.460.17 Gatekeeper connection failed");
3987        m_tryingH46017 = false;
3988        return false;
3989    }
3990 
3991    m_tryingH46017 = false;
3992    m_h46017Transport = h46017->GetHandler()->GetTransport();
3993 
3994    // We are registered so we need to create the media tunnelling.
3995 #ifdef H323_H46026
3996   if (H46026IsEnabled()) {
3997      H460_FeatureStd26 * h46026 = (H460_FeatureStd26 *)features.GetFeature(26);
3998      if (h46026) {
3999        h46026->AttachH46017(h46017->GetHandler());
4000 
4001        PNatMethod_H46026 * natMethod = NULL;
4002        if (natMethods)
4003          natMethod = (PNatMethod_H46026 *)natMethods->LoadNatMethod("H46026");
4004        if (natMethod) {
4005            h46026->AttachNatMethod(natMethod);
4006            natMethod->AttachEndPoint(this);
4007            natMethod->AttachManager(h46026->GetTunnel());
4008            natMethods->AddMethod(natMethod);
4009        }
4010      }
4011    }
4012 #endif
4013    return true;
4014 }
4015 #endif
4016 
4017 #ifdef H323_H46018
4018 void H323EndPoint::H46018Enable(PBoolean enable)
4019 {
4020     m_h46018enabled = enable;
4021     if (enable) {
4022         // Must set reregistrations at between 15 and 45 sec
4023         // otherwise the Pinhole in NAT will close
4024         registrationTimeToLive = PTimeInterval(0, 19);
4025     } else {
4026         // Set timer to whatever gk allocates...
4027         registrationTimeToLive = PTimeInterval();
4028     }
4029 }
4030 
4031 PBoolean H323EndPoint::H46018IsEnabled()
4032 {
4033     return m_h46018enabled;
4034 }
4035 #endif  // H323_H46018
4036 
4037 #ifdef H323_H46019M
4038 void H323EndPoint::H46019MEnable(PBoolean enable)
4039 {
4040     m_h46019Menabled = enable;
4041 }
4042 
4043 PBoolean H323EndPoint::H46019MIsEnabled()
4044 {
4045     return m_h46019Menabled;
4046 }
4047 
4048 void H323EndPoint::H46019MSending(PBoolean enable)
4049 {
4050     m_h46019Msend = enable;
4051 }
4052 
4053 PBoolean H323EndPoint::H46019MIsSending()
4054 {
4055     return (m_h46019Menabled && m_h46019Msend);
4056 }
4057 #endif  // H323_H46019M
4058 
4059 #ifdef H323_H46023
4060 void H323EndPoint::H46023Enable(PBoolean enable)
4061 {
4062     m_h46023enabled = enable;
4063 }
4064 
4065 PBoolean H323EndPoint::H46023IsEnabled()
4066 {
4067     return m_h46023enabled;
4068 }
4069 
4070 PBoolean H323EndPoint::H46023NatMethodSelection(const PString & method)
4071 {
4072     if (!gatekeeper)
4073         return false;
4074 
4075     H460_FeatureStd23 * h46023 = (H460_FeatureStd23 *)GetGatekeeper()->GetFeatures().GetFeature(23);
4076     if (!h46023 || !h46023->IsAvailable()) {
4077         PTRACE(4,"EP\tH.460.23 Not in use cannot verify media method");
4078         return true;
4079     }
4080     PBoolean udpAvailable = h46023->IsUDPAvailable();  // Whether STUN reports UDP ports open
4081 
4082 #ifdef H323_H46017
4083     if (RegisteredWithH46017()) {
4084         // TODO There is a bug in GnuGk which prevents H.460.24 interworking with H.460.17 Uncomment once resolved - SH
4085 /*      PBoolean useAlternate = h46023->UseAlternate();    // Whether alternate (UPnP) is available
4086         if (useAlternate) {
4087             if (method == "Std24" || method == "Std19") {
4088                 PTRACE(4,"EP\tRegistered with H.460.17 and alternate available select " << method << " for media");
4089                 return true;
4090             } else {
4091                 PTRACE(4,"EP\tRegistered with H.460.17 Method " << method << " disabled as using H.460.24 (alternate)" );
4092                 return false;
4093             }
4094         } else */
4095         if (udpAvailable) {
4096             if (method == "Std19") {
4097                 PTRACE(4,"EP\tRegistered with H.460.17 and UDP available select " << method << " for media");
4098                 return true;
4099             } else {
4100                 PTRACE(4,"EP\tRegistered with H.460.17 Method " << method << " disabled.");
4101                 return false;
4102             }
4103         } else if (method == "Std26") {
4104             PTRACE(4,"EP\tRegistered with H.460.17 and no UDP available select " << method << " for media");
4105             return true;
4106         } else {
4107             PTRACE(4,"EP\tRegistered with H.460.17 Method " << method << " disabled as UDP Not Available" );
4108             return false;
4109         }
4110     }
4111 #endif
4112     if (udpAvailable)
4113         return true;
4114     else
4115         return false;
4116 }
4117 #endif  // H323_H46023
4118 
4119 #ifdef H323_H46025
4120 void H323EndPoint::H46025Enable(PBoolean enable)
4121 {
4122     m_h46025enabled = enable;
4123 }
4124 
4125 PBoolean H323EndPoint::H46025IsEnabled()
4126 {
4127     return m_h46025enabled;
4128 }
4129 
4130 bool H323EndPoint::H46025DeviceInformation(H323_H46025_Message::Device & device)
4131 {
4132     device.username = GetLocalUserName();
4133     return true;
4134 }
4135 
4136 bool H323EndPoint::H46025CivicInformation(H323_H46025_Message::Civic & /*civic*/)
4137 {
4138     return false;
4139 }
4140 
4141 bool H323EndPoint::H46025GPSInformation(H323_H46025_Message::Geodetic & /*gps*/)
4142 {
4143     return false;
4144 }
4145 #endif  // H323_H46025
4146 
4147 #ifdef H323_FRAMEBUFFER
4148 void H323EndPoint::EnableVideoFrameBuffer(PBoolean enable)
4149 {
4150     if (useVideoBuffer == enable)
4151         return;
4152 
4153     // Increase the min Jitter delay
4154     if (enable)
4155         minAudioJitterDelay = minAudioJitterDelay + 50;  // milliseconds
4156     else
4157         minAudioJitterDelay = minAudioJitterDelay - 50;  // milliseconds
4158 
4159     useVideoBuffer = enable;
4160 }
4161 
4162 PBoolean H323EndPoint::HasVideoFrameBuffer()
4163 {
4164     return useVideoBuffer;
4165 }
4166 #endif
4167 
4168 #ifdef H323_UPnP
4169 void H323EndPoint::SetUPnP(PBoolean active)
4170 {
4171     m_UPnPenabled = active;
4172 }
4173 #endif  // H323_UPnP
4174 
4175 #ifdef H323_TLS
4176 PBoolean H323EndPoint::TLS_SetCAFile(const PFilePath & caFile)
4177 {
4178     if (!InitialiseTransportContext())
4179         return false;
4180 
4181     return ((H323_TLSContext*)m_transportContext)->UseCAFile(caFile);
4182 }
4183 
4184 PBoolean H323EndPoint::TLS_SetCADirectory(const PDirectory & certDir)
4185 {
4186     if (!InitialiseTransportContext())
4187         return false;
4188 
4189     return ((H323_TLSContext*)m_transportContext)->UseCADirectory(certDir);
4190 }
4191 
4192 PBoolean H323EndPoint::TLS_AddCACertificate(const PString & caData)
4193 {
4194     if (!InitialiseTransportContext())
4195         return false;
4196 
4197     return ((H323_TLSContext*)m_transportContext)->AddCACertificate(caData);
4198 }
4199 
4200 PBoolean H323EndPoint::TLS_SetCertificate(const PFilePath & certFile)
4201 {
4202     if (!InitialiseTransportContext())
4203         return false;
4204 
4205     return ((H323_TLSContext*)m_transportContext)->UseCertificate(certFile);
4206 }
4207 
4208 PBoolean H323EndPoint::TLS_SetPrivateKey(const PFilePath & privFile, const PString & password)
4209 {
4210     if (!InitialiseTransportContext())
4211         return false;
4212 
4213     return ((H323_TLSContext*)m_transportContext)->UsePrivateKey(privFile,password);
4214 }
4215 
4216 PBoolean H323EndPoint::TLS_SetCipherList(const PString & ciphers)
4217 {
4218     if (!InitialiseTransportContext())
4219         return false;
4220 
4221     return ((H323_TLSContext*)m_transportContext)->SetCipherList(ciphers);
4222 }
4223 
4224 PBoolean H323EndPoint::TLS_SetDHParameters(const PFilePath & pkcs3)
4225 {
4226     if (!InitialiseTransportContext())
4227         return false;
4228 
4229     return ((H323_TLSContext*)m_transportContext)->SetDHParameters(pkcs3);
4230 }
4231 
4232 PBoolean H323EndPoint::TLS_SetDHParameters(const PBYTEArray & dh_p, const PBYTEArray & dh_g)
4233 {
4234     if (!InitialiseTransportContext())
4235         return false;
4236 
4237     return ((H323_TLSContext*)m_transportContext)->SetDHParameters(dh_p,dh_g);
4238 }
4239 
4240 PBoolean H323EndPoint::TLS_Initialise(const PIPSocket::Address & binding, WORD port)
4241 {
4242     if (!InitialiseTransportContext())
4243         return false;
4244 
4245     if (!((H323_TLSContext*)m_transportContext)->Initialise())
4246         return false;
4247 
4248     m_transportSecurity.EnableTLS(true);
4249 
4250     if (!listeners.GetTLSListener()) {
4251         H323Listener * listener = new H323ListenerTLS(*this, binding, port);
4252         StartListener(listener);
4253     }
4254 
4255     return true;
4256 }
4257 
4258 PBoolean H323EndPoint::InitialiseTransportContext()
4259 {
4260     if (m_transportContext != NULL)
4261         return true;
4262 
4263     if (!SSL_library_init()) {
4264         PTRACE(1, "TLS\tOpenSSL init failed");
4265         return false;
4266     }
4267 
4268     SSL_load_error_strings();
4269     OpenSSL_add_all_algorithms();	// needed for OpenSSL < 1.0
4270     if (!RAND_status()) {
4271         PTRACE(3, "TLS\tPRNG needs seeding");
4272 #ifdef P_LINUX
4273         RAND_load_file("/dev/urandom", 1024);
4274 #else
4275         BYTE seed[1024];
4276         for (size_t i = 0; i < sizeof(seed); i++)
4277             seed[i] = (BYTE)rand();
4278         RAND_seed(seed, sizeof(seed));
4279 #endif
4280     }
4281 
4282     // VLD found memory leak in PTLIB v2.12 and prior version of PSSLContext - SH
4283     m_transportContext = new H323_TLSContext();
4284     return true;
4285 }
4286 
4287 PSSLContext * H323EndPoint::GetTransportContext()
4288 {
4289     return m_transportContext;
4290 }
4291 
4292 void H323EndPoint::EnableIPSec(PBoolean enable)
4293 {
4294     m_transportSecurity.EnableIPSec(enable);
4295 }
4296 #endif
4297 
4298 PBoolean H323EndPoint::IsTLSEnabled()
4299 {
4300     return m_transportSecurity.IsTLSEnabled();
4301 }
4302 
4303 PBoolean H323EndPoint::IsIPSecEnabled()
4304 {
4305     return m_transportSecurity.IsIPSecEnabled();
4306 }
4307 
4308 void H323EndPoint::SetTLSMediaPolicy(H323TransportSecurity::Policy policy)
4309 {
4310     m_transportSecurity.SetMediaPolicy(policy);
4311 }
4312 
4313 H323TransportSecurity * H323EndPoint::GetTransportSecurity() {
4314 	return &m_transportSecurity;
4315 }
4316 
4317 #ifdef H323_H460IM
4318 
4319 void H323EndPoint::IMSupport(const PString & token)
4320 {
4321     PWaitAndSignal m(m_IMmutex);
4322 
4323     m_IMsessions.AppendString(token);
4324 }
4325 
4326 void H323EndPoint::IMReceived(const PString & token, const PString & msg, PBoolean session)
4327 {
4328 
4329     PString addr = PString();
4330     if (!session) {
4331 
4332         H323Connection * connection = FindConnectionWithLock(token);
4333         if (connection != NULL) {
4334             IMSessionDetails(token, connection->GetRemotePartyName(),
4335                 connection->GetRemotePartyName(),
4336                 ""
4337                 );
4338             connection->Unlock();
4339         }
4340 
4341         OnIMSessionState(token, uiIMQuick);
4342     }
4343 
4344     OnIMReceived(token, msg);
4345 }
4346 
4347 PBoolean H323EndPoint::IMMakeCall(const PString & number, PBoolean session, PString & token, const PString & msg)
4348 {
4349     PWaitAndSignal m(m_IMmutex);
4350 
4351     m_IMcall = true;         // Is an IM Call
4352     m_IMsession = session;   // Start an IM Session
4353 
4354     if (!session) {
4355         PTRACE(4, "IM\tCall not a session");
4356         m_IMmsg = msg;          // Message to send and disconnect
4357     }
4358 
4359     if (!MakeSupplimentaryCall(number, token)) {
4360         m_IMcall = false;
4361         m_IMsession = false;
4362         return false;
4363     }
4364 
4365     return true;
4366 
4367 }
4368 
4369 void H323EndPoint::IMSend(const PString & msg)
4370 {
4371     PWaitAndSignal m(m_IMmutex);
4372 
4373     if (!m_IMenabled)
4374         return;
4375 
4376     if (msg.GetLength() == 0)
4377         return;
4378 
4379     for (PINDEX i = 0; i < m_IMsessions.GetSize(); i++)
4380     {
4381         H323Connection * connection = FindConnectionWithLock(m_IMsessions[i]);
4382         if (connection != NULL) {
4383             if (connection->IMSession()) {
4384                 connection->SetIMMsg(msg);
4385                 IMWriteFacility(connection);
4386             }
4387             connection->Unlock();
4388         }
4389     }
4390 }
4391 
4392 void H323EndPoint::IMOpenSession(const PString & token)
4393 {
4394     PWaitAndSignal m(m_IMmutex);
4395 
4396     H323Connection * connection = FindConnectionWithLock(token);
4397     if (connection != NULL) {
4398         if (!connection->IMSupport())
4399             IMSessionError(token, H323Connection::EndedByNoFeatureSupport);
4400         else {
4401             connection->SetIMSession(true);
4402             IMWriteFacility(connection);
4403         }
4404         connection->Unlock();
4405     }
4406     else {
4407         IMSessionError(token, H323Connection::EndedByNoUser);
4408     }
4409 }
4410 
4411 void H323EndPoint::IMCloseSession()
4412 {
4413     PWaitAndSignal m(m_IMmutex);
4414 
4415     for (PINDEX i = 0; i < m_IMsessions.GetSize(); i++)
4416     {
4417         H323Connection * connection = FindConnectionWithLock(m_IMsessions[i]);
4418         if (connection != NULL) {
4419             if (connection->IMSession()) {
4420                 connection->SetIMSession(false);
4421                 IMWriteFacility(connection);
4422                 connection->Unlock();
4423             }
4424         }
4425     }
4426 }
4427 
4428 void H323EndPoint::IMClearConnection(const PString & token)
4429 {
4430     PWaitAndSignal m(m_IMmutex);
4431 
4432     for (PINDEX i = 0; i < m_IMsessions.GetSize(); i++)
4433     {
4434         if (m_IMsessions[i] == token)
4435 #if PTLIB_VER >= 2110
4436             m_IMsessions.Remove(&token);
4437 #else
4438             m_IMsessions.RemoveAt(i);
4439 #endif
4440     }
4441 }
4442 
4443 
4444 void H323EndPoint::IMSessionOpen(const PString & token)
4445 {
4446     PWaitAndSignal m(m_IMmutex);
4447 
4448     H323Connection * connection = FindConnectionWithLock(token);
4449 
4450     PString addr = PString();
4451     if (connection != NULL) {
4452         IMSessionDetails(token, connection->GetRemotePartyNumber(),
4453             connection->GetRemotePartyName(),
4454             ""
4455             );
4456         connection->Unlock();
4457     }
4458 
4459     OnIMSessionState(token, uiIMOpen);
4460 
4461 }
4462 
4463 void H323EndPoint::IMSessionClosed(const PString & token)
4464 {
4465     OnIMSessionState(token, uiIMClose);
4466 }
4467 
4468 
4469 void H323EndPoint::IMWrite(PBoolean start)
4470 {
4471     PWaitAndSignal m(m_IMmutex);
4472 
4473     if (start)
4474         uiIMstate = uiIMStartWrite;
4475     else
4476         uiIMstate = uiIMEndWrite;
4477 
4478     m_IMwriteevent = true;
4479 
4480     for (PINDEX i = 0; i < m_IMsessions.GetSize(); i++)
4481     {
4482         H323Connection * connection = FindConnectionWithLock(m_IMsessions[i]);
4483         if (connection != NULL) {
4484             if (connection->IMSession())
4485                 IMWriteFacility(connection);
4486             connection->Unlock();
4487         }
4488     }
4489 
4490     m_IMwriteevent = false;
4491     uiIMstate = uiIMIdle;
4492 }
4493 
4494 PBoolean H323EndPoint::IMWriteEvent(PBoolean & state)
4495 {
4496     if (m_IMwriteevent) {
4497         switch (uiIMstate) {
4498         case uiIMStartWrite:
4499             state = true;
4500             return true;
4501         case uiIMEndWrite:
4502             state = false;
4503             return true;
4504         default:
4505             return false;
4506         }
4507     }
4508     return false;
4509 }
4510 
4511 void H323EndPoint::IMWriteFacility(H323Connection * connection)
4512 {
4513     if (connection != NULL) {
4514         H323SignalPDU facilityPDU;
4515         facilityPDU.BuildFacility(*connection, false, H225_FacilityReason::e_featureSetUpdate);
4516         connection->WriteSignalPDU(facilityPDU);
4517     }
4518 }
4519 
4520 void H323EndPoint::IMSessionInvite(const PString & username)
4521 {
4522     PString token = PString();
4523     IMMakeCall(username, true, token);
4524 }
4525 
4526 void H323EndPoint::IMSessionError(const PString & token, int reason)
4527 {
4528     OnIMSessionError(token, reason);
4529 }
4530 
4531 void H323EndPoint::IMSent(const PString & token, PBoolean success, int reason)
4532 {
4533     OnIMSent(token, success, reason);
4534 }
4535 
4536 void H323EndPoint::IMSessionDetails(const PString & token,
4537     const PString & number,
4538     const PString & CallerID,
4539     const PString & enc)
4540 {
4541     OnIMSessionDetails(token, number, CallerID, enc);
4542 }
4543 
4544 void H323EndPoint::IMSessionWrite(const PString & token, PBoolean state)
4545 {
4546     if (state)
4547         OnIMSessionState(token, uiIMStartWrite);
4548     else
4549         OnIMSessionState(token, uiIMEndWrite);
4550 }
4551 
4552 #endif
4553 
4554 #ifdef H323_H460P
4555 void H323EndPoint::PresenceSetLocalState(const PStringList & alias, presenceStates localstate, const PString & localdisplay, PBoolean updateOnly)
4556 {
4557     if (presenceHandler == NULL)
4558         presenceHandler = new H460PresenceHandler(*this);
4559 
4560     presenceHandler->SetPresenceState(alias,localstate, localdisplay, updateOnly);
4561 }
4562 
4563 void H323EndPoint::PresenceAddFeature(presenceFeature feat)
4564 {
4565     if (presenceHandler == NULL)
4566         presenceHandler = new H460PresenceHandler(*this);
4567 
4568     presenceHandler->AddEndpointFeature(feat);
4569 }
4570 
4571 void H323EndPoint::PresenceAddFeatureH460()
4572 {
4573     if (presenceHandler == NULL)
4574         presenceHandler = new H460PresenceHandler(*this);
4575 
4576     H460FeatureList plist;
4577     if (H460_Feature::FeatureList(H460_Feature::FeaturePresence,plist,this)) {
4578         H460FeatureList::const_iterator it = plist.begin();
4579         while (it != plist.end()) {
4580             presenceHandler->AddEndpointH460Feature(*it->second, it->first);
4581             ++it;
4582         }
4583         features.LoadFeatureSet(H460_Feature::FeaturePresence);
4584     }
4585     DeleteFeatureList(plist);
4586 }
4587 
4588 void H323EndPoint::PresenceSetLocale(const presenceLocale & info)
4589 {
4590     if (presenceHandler == NULL)
4591         presenceHandler = new H460PresenceHandler(*this);
4592 
4593     H460PresenceHandler::localeInfo & loc = presenceHandler->GetLocationInfo();
4594 
4595     loc.m_region = info.m_region;
4596     loc.m_country = info.m_country;
4597     loc.m_locale = info.m_locale;
4598     loc.m_countryCode = info.m_countryCode;
4599     loc.m_latitude = info.m_latitude;
4600     loc.m_longitude = info.m_longitude;
4601     loc.m_elevation = info.m_elevation;
4602 }
4603 
4604 void H323EndPoint::PresenceSetInstruction(const PString & epalias, unsigned type, const PString & alias, const PString & display)
4605 {
4606     if (presenceHandler == NULL)
4607         return;
4608 
4609     PresenceInstructList instList;
4610     instList.insert(pair<PString, PString>(alias,display));
4611 
4612     presenceHandler->AddInstruction(epalias,(H323PresenceHandler::InstType)type,instList,true);
4613 }
4614 
4615 void H323EndPoint::PresenceSetInstruction(const PString & epalias, unsigned type, const PStringList & list, PBoolean autoSend)
4616 {
4617     if (presenceHandler == NULL)
4618         return;
4619 
4620     PString display = PString();
4621     if (autoSend) {
4622         int sz = localAliasNames.GetSize();
4623         if (sz > 0)
4624            display = localAliasNames[sz-1];
4625     }
4626 
4627     PresenceInstructList instList;
4628     for (PINDEX i=0; i < list.GetSize(); ++i) {
4629         instList.insert(pair<PString, PString>(list[i],display));
4630     }
4631 
4632     presenceHandler->AddInstruction(epalias,(H323PresenceHandler::InstType)type,instList,autoSend);
4633 }
4634 
4635 void H323EndPoint::PresenceSendAuthorization(const OpalGloballyUniqueID & id, const PString & epalias,PBoolean approved, const PStringList & list)
4636 {
4637     if (presenceHandler == NULL)
4638         return;
4639 
4640     presenceHandler->AddAuthorization(id,epalias,approved,list);
4641 }
4642 
4643 void H323EndPoint::PresenceNotification(const PString & locAlias,
4644                                         const PString & subAlias,
4645                                         unsigned state,
4646                                         const PString & display)
4647 {
4648     PTRACE(4,"EP\tAlias " << subAlias << " PresenceState now " << state << " - "
4649                           << H323PresenceNotification::GetStateString(state)
4650                           << " " << display);
4651 }
4652 
4653 void H323EndPoint::PresenceInstruction(const PString & locAlias, unsigned type, const PString & subAlias, const PString & subDisplay)
4654 {
4655     PTRACE(4,"EP\tReceived Gatekeeper Instruction to "
4656                 << H323PresenceInstruction::GetInstructionString(type)
4657                 << " " << subAlias << " " << subDisplay);
4658 }
4659 
4660 void H323EndPoint::PresenceInstruction(const PString & locAlias, unsigned type, const PString & subAlias,
4661                                        const PString & subDisplay, const PString & subAvatar)
4662 {
4663     PresenceInstruction(locAlias, type, subAlias, subDisplay);
4664 }
4665 
4666 void H323EndPoint::PresenceInstruction(const PString & locAlias, unsigned type, const PString & subAlias,
4667                                        const PString & subDisplay, const PString & subAvatar, unsigned category)
4668 {
4669     PresenceInstruction(locAlias, type, subAlias, subDisplay, subAvatar);
4670 }
4671 
4672 
4673 void H323EndPoint::PresenceAuthorization(const OpalGloballyUniqueID & id,
4674                                     const PString & locAlias,
4675                                     const std::map<PString,PresSubDetails> & Aliases)
4676 {
4677     PStringStream s;
4678 
4679     s << "EP\tReceived Presence Authorization " << id.AsString();
4680     PresenceSubscriberList::const_iterator i;
4681     for (i = Aliases.begin(); i != Aliases.end(); ++i) {
4682        s << "\n from Alias " << i->first << " " << i->second.m_display;
4683     }
4684     PTRACE(4, s);
4685 }
4686 #endif  // H323_H460P
4687 
4688 #ifdef H323_H460PRE
4689 
4690 unsigned H323EndPoint::GetRegistrationPriority()
4691 {
4692     return m_regPrior;
4693 }
4694 
4695 void H323EndPoint::SetRegistrationPriority(unsigned value)
4696 {
4697     m_regPrior = value;
4698 }
4699 
4700 PBoolean H323EndPoint::GetPreempt()
4701 {
4702     return m_preempt;
4703 }
4704 
4705 void H323EndPoint::SetPreempt(PBoolean topreempt)
4706 {
4707     m_preempt = topreempt;
4708     m_preempted = false;
4709 }
4710 
4711 PBoolean H323EndPoint::IsPreempted()
4712 {
4713     return m_preempted;
4714 }
4715 
4716 void H323EndPoint::SetPreempted(PBoolean ispreempted)
4717 {
4718     m_preempted = ispreempted;
4719 }
4720 
4721 void H323EndPoint::PreemptRegistration()
4722 {
4723     // Pre-empt the other registration
4724     if (gatekeeper) {
4725         SetPreempt(true);
4726         InternalRegisterGatekeeper(gatekeeper, true);
4727     }
4728 }
4729 
4730 void H323EndPoint::OnNotifyPreempt(PBoolean unregister)
4731 {
4732 
4733 }
4734 
4735 void H323EndPoint::OnNotifyPriority()
4736 {
4737 
4738 }
4739 
4740 #endif  // H323_H460PRE
4741 
4742 #ifdef H323_H461
4743 void H323EndPoint::SetASSETEnabled(PBoolean success)
4744 {
4745     m_ASSETEnabled = success;
4746 }
4747 
4748 PBoolean H323EndPoint::IsASSETEnabled()
4749 {
4750     return m_ASSETEnabled;
4751 }
4752 
4753 void H323EndPoint::SetEndPointASSETMode(H323EndPoint::H461Mode mode)
4754 {
4755     m_h461ASSETMode = mode;
4756 }
4757 
4758 H323EndPoint::H461Mode H323EndPoint::GetEndPointASSETMode()
4759 {
4760     return m_h461ASSETMode;
4761 }
4762 
4763 H461DataStore * H323EndPoint::GetASSETDataStore()
4764 {
4765     return m_h461DataStore;
4766 }
4767 
4768 void H323EndPoint::SetASSETDataStore(H461DataStore * dataStore)
4769 {
4770     m_h461DataStore = dataStore;
4771     if (m_h461DataStore != NULL)
4772         m_ASSETEnabled = true;
4773 }
4774 
4775 #endif
4776 
4777 PBoolean H323EndPoint::OnFeatureInstance(int /*instType*/, const PString & /*identifer*/)
4778 {
4779     return TRUE;
4780 }
4781 
4782 PBoolean H323EndPoint::HandleUnsolicitedInformation(const H323SignalPDU & )
4783 {
4784   return FALSE;
4785 }
4786 
4787 #ifdef H323_RTP_AGGREGATE
4788 PHandleAggregator * H323EndPoint::GetRTPAggregator()
4789 {
4790   PWaitAndSignal m(connectionsMutex);
4791   if (rtpAggregationSize == 0)
4792     return NULL;
4793 
4794   if (rtpAggregator == NULL)
4795     rtpAggregator = new PHandleAggregator(rtpAggregationSize);
4796 
4797   return rtpAggregator;
4798 }
4799 #endif
4800 
4801 #ifdef H323_SIGNAL_AGGREGATE
4802 PHandleAggregator * H323EndPoint::GetSignallingAggregator()
4803 {
4804   PWaitAndSignal m(connectionsMutex);
4805   if (signallingAggregationSize == 0)
4806     return NULL;
4807 
4808   if (signallingAggregator == NULL)
4809     signallingAggregator = new PHandleAggregator(signallingAggregationSize);
4810 
4811   return signallingAggregator;
4812 }
4813 #endif
4814 
4815 #ifdef H323_GNUGK
4816 void H323EndPoint::NATLostConnection(PBoolean lost)
4817 {
4818     PTRACE(4,"GNUGK\tNAT Connection" << (lost ? "Lost" : " Re-established"));
4819     if (!lost)
4820         RegInvokeReRegistration();
4821 }
4822 #endif
4823 
4824 void H323EndPoint::RegInvokeReRegistration()
4825 {
4826      RegThread = PThread::Create(PCREATE_NOTIFIER(RegMethod), 0,
4827                     PThread::AutoDeleteThread,
4828                     PThread::NormalPriority,
4829                     "regmeth:%x");
4830 }
4831 
4832 void H323EndPoint::RegMethod(PThread &, H323_INT)
4833 {
4834     PWaitAndSignal m(reregmutex);
4835 
4836     gatekeeper->ReRegisterNow();
4837 }
4838 
4839 
4840 
4841 
4842