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