1 /* H460_std23.cxx
2 *
3 * Copyright (c) 2009 ISVO (Asia) Pte Ltd. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Alternatively, the contents of this file may be used under the terms
11 * of the General Public License (the "GNU License"), in which case the
12 * provisions of GNU License are applicable instead of those
13 * above. If you wish to allow use of your version of this file only
14 * under the terms of the GNU License and not to allow others to use
15 * your version of this file under the MPL, indicate your decision by
16 * deleting the provisions above and replace them with the notice and
17 * other provisions required by the GNU License. If you do not delete
18 * the provisions above, a recipient may use your version of this file
19 * under either the MPL or the GNU License."
20 *
21 * Software distributed under the License is distributed on an "AS IS"
22 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
23 * the License for the specific language governing rights and limitations
24 * under the License.
25 *
26 * The Original Code is derived from and used in conjunction with the
27 * H323Plus Project (www.h323plus.org/)
28 *
29 * The Initial Developer of the Original Code is ISVO (Asia) Pte Ltd.
30 *
31 *
32 * Contributor(s): ______________________________________.
33 *
34 * $Id$
35 *
36 */
37 #include <ptlib.h>
38 #include <openh323buildopts.h>
39
40 #ifdef H323_H46023
41
42 #include <h323.h>
43 #include "h460/h460_std23.h"
44 #include <ptclib/random.h>
45 #include <ptclib/pdns.h>
46 #ifdef H323_H46018
47 #include <h460/h460_std18.h>
48 #endif
49 #ifdef H323_H46019M
50 #include <h460/h46018_h225.h>
51 #endif
52 #ifdef H323_UPnP
53 #include "h460/upnpcp.h"
54 #endif
55
56 #if _WIN32
57 #pragma message("H.460.23/.24 Enabled. Contact support@h323plus.org for licensing terms.")
58 #else
59 #warning("H.460.23/.24 Enabled. Contact support@h323plus.org for licensing terms.")
60 #endif
61
62 #ifdef _MSC_VER
63 #pragma warning(disable : 4239)
64 #endif
65
66
67 // H.460.23 NAT Detection Feature
68 #define remoteNATOID 1 // bool if endpoint has remote NAT support
69 #define AnnexAOID 2 // bool if endpoint supports H.460.24 Annex A
70 #define localNATOID 3 // bool if endpoint is NATed
71 #define NATDetRASOID 4 // Detected RAS H225_TransportAddress
72 #define STUNServOID 5 // H225_TransportAddress of STUN Server
73 #define NATTypeOID 6 // integer 8 Endpoint NAT Type
74 #define AnnexBOID 7 // bool if endpoint supports H.460.24 Annex B
75
76
77 // H.460.24 P2Pnat Feature
78 #define NATProxyOID 1 // PBoolean if gatekeeper will proxy
79 #define remoteMastOID 2 // PBoolean if remote endpoint can assist local endpoint directly
80 #define mustProxyOID 3 // PBoolean if gatekeeper must proxy to reach local endpoint
81 #define calledIsNatOID 4 // PBoolean if local endpoint is behind a NAT/FW
82 #define NatRemoteTypeOID 5 // integer 8 reported NAT type
83 #define apparentSourceOID 6 // H225_TransportAddress of apparent source address of endpoint
84 #define SupAnnexAOID 7 // PBoolean if local endpoint supports H.460.24 Annex A
85 #define NATInstOID 8 // integer 8 Instruction on how NAT is to be Traversed
86 #define SupAnnexBOID 9 // bool if endpoint supports H.460.24 Annex B
87
88
89 //////////////////////////////////////////////////////////////////////
90
91 #if PTLIB_VER >= 2130
92 PCREATE_NAT_PLUGIN(H46024, "H.460.24");
93 #else
94 PCREATE_NAT_PLUGIN(H46024);
95 #endif
96
PNatMethod_H46024()97 PNatMethod_H46024::PNatMethod_H46024()
98 : mainThread(NULL)
99 {
100 natType = PSTUNClient::UnknownNat;
101 isAvailable = false;
102 isActive = false;
103 feat = NULL;
104 }
105
~PNatMethod_H46024()106 PNatMethod_H46024::~PNatMethod_H46024()
107 {
108 natType = PSTUNClient::UnknownNat;
109 delete mainThread;
110 }
111
SetPortInformation(PortInfo & pairedPortInfo,WORD portPairBase,WORD portPairMax)112 void PNatMethod_H46024::SetPortInformation(PortInfo & pairedPortInfo, WORD portPairBase, WORD portPairMax)
113 {
114 pairedPortInfo.basePort = (WORD)((portPairBase+1)&0xfffe);
115 if (portPairBase == 0) {
116 pairedPortInfo.basePort = 0;
117 pairedPortInfo.maxPort = 0;
118 }
119 else if (portPairMax == 0)
120 pairedPortInfo.maxPort = (WORD)(pairedPortInfo.basePort+99);
121 else if (portPairMax < portPairBase)
122 pairedPortInfo.maxPort = portPairBase;
123 else
124 pairedPortInfo.maxPort = portPairMax;
125
126 pairedPortInfo.currentPort = pairedPortInfo.basePort;
127
128 }
129
Start(const PString & server,H460_FeatureStd23 * _feat)130 void PNatMethod_H46024::Start(const PString & server,H460_FeatureStd23 * _feat)
131 {
132 feat = _feat;
133
134 H323EndPoint * ep = feat->GetEndPoint();
135
136 SetServer(server);
137 #ifdef H323_H46019M
138 WORD muxBase = ep->GetMultiplexPort();
139 SetPortInformation(multiplexPorts,muxBase-2, muxBase+2);
140 SetPortInformation(standardPorts, ep->GetRtpIpPortBase(), ep->GetRtpIpPortMax());
141 SetPortRanges(muxBase-2, muxBase+2, muxBase-2, muxBase+20);
142 #else
143 SetPortRanges(ep->GetRtpIpPortBase(), ep->GetRtpIpPortMax(), ep->GetRtpIpPortBase(), ep->GetRtpIpPortMax());
144 #endif
145
146 mainThread = PThread::Create(PCREATE_NOTIFIER(MainMethod), 0,
147 PThread::NoAutoDeleteThread, PThread::NormalPriority, "H.460.24");
148 }
149
150
151
NATTest()152 PSTUNClient::NatTypes PNatMethod_H46024::NATTest()
153 {
154
155 PSTUNClient::NatTypes testtype;
156 WORD testport;
157 #ifdef H323_H46019M
158 testport = (WORD)feat->GetEndPoint()->GetMultiplexPort()-1;
159 #else
160 PRandom rand;
161 testport = (WORD)rand.Generate(singlePortInfo.basePort , singlePortInfo.maxPort);
162 #endif
163
164 singlePortInfo.currentPort = testport;
165 PTRACE(4,"Std23\tSTUN Test Port " << singlePortInfo.currentPort+1);
166
167 testtype = GetNatType(true);
168
169 #ifdef H323_H46019M
170 // if we have a cone NAT check the RTCP Port to see if not existing binding
171 if (testtype == PSTUNClient::ConeNat || natType == PSTUNClient::UnknownNat) {
172 PThread::Sleep(10);
173 PTRACE(4,"Std23\tCone NAT Detected rechecking. Test Port " << singlePortInfo.currentPort+1);
174 PSTUNClient::NatTypes test2 = GetNatType(true);
175 if (test2 > testtype)
176 testtype = test2;
177 }
178 #endif
179
180 return testtype;
181 }
182
183 int recheckTime = 300000; // 5 minutes
184
MainMethod(PThread &,H323_INT)185 void PNatMethod_H46024::MainMethod(PThread &, H323_INT)
186 {
187
188 while (natType == PSTUNClient::UnknownNat ||
189 natType == PSTUNClient::ConeNat) {
190 PSTUNClient::NatTypes testtype = NATTest();
191 if (natType != testtype) {
192 natType = testtype;
193 PIPSocket::Address extIP;
194 if (GetExternalAddress(extIP)) {
195 feat->GetEndPoint()->NATMethodCallBack(GetName(),2,natType);
196 feat->OnNATTypeDetection(natType, extIP);
197 }
198 }
199
200 if (natType == PSTUNClient::ConeNat) {
201 isAvailable = true;
202 PThread::Sleep(recheckTime);
203 continue;
204 }
205
206 isAvailable = false;
207 if (natType == PSTUNClient::UnknownNat) {
208 PTRACE(1,"Std24\tNAT Test failed to resolve NAT Type");
209 break;
210 }
211 }
212
213 }
214
IsAvailable(const PIPSocket::Address &)215 bool PNatMethod_H46024::IsAvailable(const PIPSocket::Address & /*binding*/)
216 {
217 if (!isActive)
218 return false;
219
220 return isAvailable;
221 }
222
SetAvailable()223 void PNatMethod_H46024::SetAvailable()
224 {
225 feat->GetEndPoint()->NATMethodCallBack(GetName(),1,"Available");
226 isAvailable = true;
227 }
228
Activate(bool act)229 void PNatMethod_H46024::Activate(bool act)
230 {
231 if (act && !isAvailable) // Special case where activated but not available.
232 isAvailable = true;
233
234 isActive = act;
235 }
236
GetNATType()237 PSTUNClient::NatTypes PNatMethod_H46024::GetNATType()
238 {
239 return natType;
240 }
241
CreateRandomPortPair(unsigned int start,unsigned int end)242 WORD PNatMethod_H46024::CreateRandomPortPair(unsigned int start, unsigned int end)
243 {
244 WORD num;
245 PRandom rand;
246 num = (WORD)rand.Generate(start,end);
247 if (num %2 != 0)
248 num++; // Make sure the number is even
249
250 return num;
251 }
252
253
CreateSocketPair(PUDPSocket * & socket1,PUDPSocket * & socket2,const PIPSocket::Address & binding,void * userData)254 PBoolean PNatMethod_H46024::CreateSocketPair(PUDPSocket * & socket1,
255 PUDPSocket * & socket2,
256 const PIPSocket::Address & binding,
257 void * userData
258 )
259 {
260 PWaitAndSignal m(portMute);
261
262 H323Connection::SessionInformation * info = (H323Connection::SessionInformation *)userData;
263 #ifdef H323_H46019M
264 PNatMethod_H46019 * handler =
265 (PNatMethod_H46019 *)feat->GetEndPoint()->GetNatMethods().GetMethodByName("H46019");
266
267 if (handler && info && (info->GetRecvMultiplexID() > 0)) {
268 if (!handler->IsMultiplexed()) {
269 // Set Multiplex ports here
270 SetPortRanges(multiplexPorts.basePort, multiplexPorts.maxPort, multiplexPorts.basePort, multiplexPorts.maxPort);
271
272 H46019MultiplexSocket * & muxSocket1 = (H46019MultiplexSocket * &)handler->GetMultiplexSocket(true);
273 H46019MultiplexSocket * & muxSocket2 = (H46019MultiplexSocket * &)handler->GetMultiplexSocket(false);
274 muxSocket1 = new H46019MultiplexSocket(true);
275 muxSocket2 = new H46019MultiplexSocket(false);
276 pairedPortInfo.currentPort = feat->GetEndPoint()->GetMultiplexPort()-1;
277
278 #if PTLIB_VER >= 2130
279 if (!PSTUNClient::CreateSocketPair(muxSocket1->GetSubSocket(), muxSocket2->GetSubSocket(), binding, (PObject *)1))
280 #else
281 if (!PSTUNClient::CreateSocketPair(muxSocket1->GetSubSocket(), muxSocket2->GetSubSocket(), binding))
282 #endif
283 return false;
284
285 PIPSocket::Address stunAddress;
286 muxSocket1->GetSubSocket()->GetLocalAddress(stunAddress);
287 PTRACE(1,"Std24\tMux STUN Created: " << stunAddress << " "
288 << muxSocket1->GetSubSocket()->GetPort() << "-" << muxSocket2->GetSubSocket()->GetPort());
289
290 handler->StartMultiplexListener(); // Start Multiplexing Listening thread;
291 handler->EnableMultiplex(true);
292 }
293
294 socket1 = new H46019UDPSocket(*handler->GetHandler(),info,true); /// Data
295 socket2 = new H46019UDPSocket(*handler->GetHandler(),info,false); /// Signal
296
297 PNatMethod_H46019::RegisterSocket(true ,info->GetRecvMultiplexID(), socket1);
298 PNatMethod_H46019::RegisterSocket(false,info->GetRecvMultiplexID(), socket2);
299
300 } else {
301 // Set standard ports here
302 SetPortRanges(standardPorts.basePort, standardPorts.maxPort, standardPorts.basePort, standardPorts.maxPort);
303 #else
304 {
305 #endif
306
307 #if PTLIB_VER >= 2130
308 if (!PSTUNClient::CreateSocketPair(socket1,socket2,binding, NULL))
309 #else
310 if (!PSTUNClient::CreateSocketPair(socket1,socket2,binding))
311 #endif
312 return false;
313 }
314
315 SetConnectionSockets(socket1, socket2, info);
316 return true;
317 }
318
319
320 void PNatMethod_H46024::SetConnectionSockets(PUDPSocket * data, PUDPSocket * control,
321 H323Connection::SessionInformation * info)
322 {
323 if (info != NULL) {
324 H323Connection * connection = PRemoveConst(H323Connection, info->GetConnection());
325 if (connection != NULL)
326 connection->SetRTPNAT(info->GetSessionID(), data,control);
327 }
328 }
329
330 //////////////////////////////////////////////////////////////////////
331
332 H460_FEATURE(Std23);
333
334 H460_FeatureStd23::H460_FeatureStd23()
335 : H460_FeatureStd(23)
336 {
337 PTRACE(6,"Std23\tInstance Created");
338
339 FeatureCategory = FeatureSupported;
340
341 EP = NULL;
342 alg = false;
343 isavailable = true;
344 isEnabled = false;
345 natType = PSTUNClient::UnknownNat;
346 externalIP = PIPSocket::GetDefaultIpAny();
347 useAlternate = 0;
348 natNotify = false;
349
350 }
351
352 H460_FeatureStd23::~H460_FeatureStd23()
353 {
354 }
355
356 void H460_FeatureStd23::AttachEndPoint(H323EndPoint * _ep)
357 {
358 EP = _ep;
359 isEnabled = EP->H46023IsEnabled();
360
361 // Ignore if already manually using STUN
362 isavailable = (EP->GetSTUN() == NULL);
363 }
364
365 PBoolean H460_FeatureStd23::OnSendGatekeeperRequest(H225_FeatureDescriptor & pdu)
366 {
367 if (!isEnabled)
368 return false;
369
370 if (!isavailable)
371 return FALSE;
372
373 H460_FeatureStd feat = H460_FeatureStd(23);
374 pdu = feat;
375 return TRUE;
376 }
377
378 PBoolean H460_FeatureStd23::OnSendRegistrationRequest(H225_FeatureDescriptor & pdu)
379 {
380 if (!isEnabled)
381 return false;
382
383 if (!isavailable)
384 return FALSE;
385
386 // Build Message
387 H460_FeatureStd feat = H460_FeatureStd(23);
388
389 if ((EP->GetGatekeeper() == NULL) ||
390 (!EP->GetGatekeeper()->IsRegistered())) {
391 // First time registering
392 // We always support remote
393 feat.Add(remoteNATOID,H460_FeatureContent(true));
394 #ifdef H323_H46024A
395 feat.Add(AnnexAOID,H460_FeatureContent(true));
396 #endif
397 #ifdef H323_H46024B
398 feat.Add(AnnexBOID,H460_FeatureContent(true));
399 #endif
400 } else {
401 if (alg) {
402 // We should be disabling H.460.23/.24 support but
403 // we will disable H.460.18/.19 instead :) and say we have no NAT..
404 feat.Add(NATTypeOID,H460_FeatureContent(1,8));
405 feat.Add(remoteNATOID,H460_FeatureContent(false));
406 isavailable = false;
407 alg = false;
408 } else {
409 if (natNotify || AlternateNATMethod()) {
410 feat.Add(NATTypeOID,H460_FeatureContent(natType,8));
411 natNotify = false;
412 }
413 }
414 }
415
416 pdu = feat;
417
418 return true;
419 }
420
421 void H460_FeatureStd23::OnReceiveGatekeeperConfirm(const H225_FeatureDescriptor & /*pdu*/)
422 {
423 isEnabled = true;
424 }
425
426 void H460_FeatureStd23::OnReceiveRegistrationConfirm(const H225_FeatureDescriptor & pdu)
427 {
428 isEnabled = true;
429
430 H460_FeatureStd & feat = (H460_FeatureStd &)pdu;
431
432 // Ignore whether the gatekeeper detected as being behind NAT
433 // The STUN test will confirm - SH
434 //PBoolean NATdetect = false;
435 //if (feat.Contains(localNATOID))
436 // NATdetect = feat.Value(localNATOID);
437
438 if (feat.Contains(STUNServOID)) {
439 H323TransportAddress addr = feat.Value(STUNServOID);
440 StartSTUNTest(addr.Mid(3));
441 }
442
443 if (feat.Contains(NATDetRASOID)) {
444 H323TransportAddress addr = feat.Value(NATDetRASOID);
445 PIPSocket::Address ip;
446 addr.GetIpAddress(ip);
447 if (DetectALG(ip)) {
448 // if we have an ALG then to be on the safe side
449 // disable .23/.24 so that the ALG has more chance
450 // of behaving properly...
451 alg = true;
452 DelayedReRegistration();
453 }
454 }
455 }
456
457
458 void H460_FeatureStd23::OnNATTypeDetection(PSTUNClient::NatTypes type, const PIPSocket::Address & ExtIP)
459 {
460 if (natType == type)
461 return;
462
463 externalIP = ExtIP;
464
465 if (natType == PSTUNClient::UnknownNat) {
466 PTRACE(4,"Std23\tSTUN Test Result: " << type << " forcing reregistration.");
467 #ifdef H323_UPnP
468 if (type > PSTUNClient::ConeNat) {
469 PString name = PString();
470 if (IsAlternateAvailable(name))
471 EP->NATMethodCallBack(name,1,"Available");
472 else
473 EP->InitialiseUPnP();
474 }
475 #endif
476 natType = type; // first time detection
477 } else {
478 PTRACE(2,"Std23\tBAD NAT Detected: Was " << natType << " Now " << type << " Disabling H.460.23/.24");
479 natType = PSTUNClient::UnknownNat; // Leopard changed it spots (disable H.460.23/.24)
480 }
481
482 natNotify = true;
483 EP->ForceGatekeeperReRegistration();
484 }
485
486 bool H460_FeatureStd23::DetectALG(const PIPSocket::Address & detectAddress)
487 {
488
489 #ifdef H323_IPV6
490 // Again horrible code should be able to get interface listing for a given protocol - SH
491 PBoolean ipv6IPv4Discover = false;
492 if (detectAddress.GetVersion() == 4 && PIPSocket::GetDefaultIpAddressFamily() == AF_INET6) {
493 PIPSocket::SetDefaultIpAddressFamilyV4();
494 ipv6IPv4Discover = true;
495 }
496 #endif
497 bool found = true;
498 PIPSocket::InterfaceTable if_table;
499 if (!PIPSocket::GetInterfaceTable(if_table)) {
500 PTRACE(1, "Std23\tERROR: Can't get interface table");
501 found = false;
502 } else {
503 for (PINDEX i=0; i< if_table.GetSize(); i++) {
504 if (detectAddress == if_table[i].GetAddress()) {
505 PTRACE(4, "Std23\tNo Intermediary device detected between EP and GK");
506 found = false;
507 break;
508 }
509 }
510 }
511 #ifdef H323_IPV6
512 if (ipv6IPv4Discover)
513 PIPSocket::SetDefaultIpAddressFamilyV6();
514 #endif
515 if (found) {
516 PTRACE(4, "Std23\tWARNING: Intermediary device detected!");
517 EP->NATMethodCallBack("ALG",1,"Available");
518 return true;
519 }
520
521 return false;
522 }
523
524 void H460_FeatureStd23::StartSTUNTest(const PString & server)
525 {
526 PString s;
527 #ifdef P_DNS
528 PStringList SRVs;
529 PStringList x = server.Tokenise(":");
530 PString number = "h323:user@" + x[0];
531 if (PDNS::LookupSRV(number,"_stun._udp.",SRVs))
532 s = SRVs[0];
533 else
534 #endif
535 s = server;
536
537 // Remove any previous NAT methods.
538 EP->GetNatMethods().RemoveMethod("H46024");
539 natType = PSTUNClient::UnknownNat;
540
541 PNatMethod_H46024 * xnat = (PNatMethod_H46024 *)EP->GetNatMethods().LoadNatMethod("H46024");
542 #ifdef H323_UPnP
543 PString name = PString();
544 if (IsAlternateAvailable(name)) {
545 EP->NATMethodCallBack(name,1,"Available");
546 EP->ForceGatekeeperReRegistration();
547 } else
548 #endif
549 xnat->Start(s,this);
550
551 EP->GetNatMethods().AddMethod(xnat);
552 }
553
554 bool H460_FeatureStd23::IsAvailable()
555 {
556 return isEnabled;
557 }
558
559 #if H323_UPnP
560 bool H460_FeatureStd23::IsAlternateAvailable(PString & name)
561 {
562 PNatMethod_UPnP * upnpMethod = (PNatMethod_UPnP *)EP->GetNatMethods().GetMethodByName("UPnP");
563 if (upnpMethod && upnpMethod->IsAvailable(PIPSocket::Address::GetAny(4))) {
564 PTRACE(4,"Std23\tSTUN Setting alternate: UPnP");
565 name = upnpMethod->GetName();
566 natType = PSTUNClient::ConeNat;
567 natNotify = true;
568 useAlternate = 1;
569 upnpMethod->Activate(true);
570 return true;
571 }
572 return false;
573 }
574 #endif
575
576 void H460_FeatureStd23::DelayedReRegistration()
577 {
578 PThread::Sleep(1000);
579 EP->ForceGatekeeperReRegistration(); // We have an ALG so notify the gatekeeper
580 }
581
582 bool H460_FeatureStd23::AlternateNATMethod()
583 {
584 #ifdef H323_UPnP
585 if (natType <= PSTUNClient::ConeNat || useAlternate > 0)
586 return false;
587
588 H323NatList & natlist = EP->GetNatMethods().GetNATList();
589
590 for (PINDEX i=0; i< natlist.GetSize(); i++) {
591 #if PTLIB_VER >= 2130
592 PString methName = natlist[i].GetMethodName();
593 #else
594 PString methName = natlist[i].GetName();
595 #endif
596 if (methName == "UPnP" &&
597 natlist[i].GetRTPSupport() == PSTUNClient::RTPSupported) {
598 PIPSocket::Address extIP;
599 natlist[i].GetExternalAddress(extIP);
600 if (extIP.IsAny() || !extIP.IsValid() || externalIP.IsLoopback() || extIP == externalIP) {
601 PTRACE(4,"H46023\tUPnP Change NAT from " << natType << " to " << PSTUNClient::ConeNat);
602 natType = PSTUNClient::ConeNat;
603 useAlternate = 1;
604 natlist[i].Activate(true);
605 EP->NATMethodCallBack(methName,1,"Available");
606 return true;
607 } else {
608 PTRACE(4,"H46023\tUPnP Unavailable subNAT STUN: " << externalIP << " UPnP " << extIP);
609 useAlternate = 2;
610 }
611 }
612 }
613 #endif
614 return false;
615 }
616
617 bool H460_FeatureStd23::UseAlternate()
618 {
619 return (useAlternate == 1);
620 }
621
622 bool H460_FeatureStd23::IsUDPAvailable()
623 {
624 return (natType < PSTUNClient::BlockedNat);
625 }
626
627 ///////////////////////////////////////////////////////////////////
628
629
630 H460_FEATURE(Std24);
631
632 H460_FeatureStd24::H460_FeatureStd24()
633 : H460_FeatureStd(24),
634 EP(NULL), CON(NULL), natconfig(H460_FeatureStd24::e_unknown),
635 isEnabled(false), useAlternate(false)
636 {
637 PTRACE(6,"Std24\tInstance Created");
638
639 FeatureCategory = FeatureSupported;
640 }
641
642 H460_FeatureStd24::~H460_FeatureStd24()
643 {
644 }
645
646 void H460_FeatureStd24::AttachEndPoint(H323EndPoint * _ep)
647 {
648 EP = _ep;
649 // We only enable IF the gatekeeper supports H.460.23
650 H460_FeatureSet * gkfeat = EP->GetGatekeeperFeatures();
651 if (gkfeat && gkfeat->HasFeature(23)) {
652 H460_FeatureStd23 * feat = (H460_FeatureStd23 *)gkfeat->GetFeature(23);
653 isEnabled = feat->IsAvailable();
654 useAlternate = feat->UseAlternate();
655 } else {
656 PTRACE(4,"Std24\tH.460.24 disabled as H.460.23 is disabled!");
657 isEnabled = false;
658 }
659 }
660
661 void H460_FeatureStd24::AttachConnection(H323Connection * _conn)
662 {
663 CON = _conn;
664 }
665
666 PBoolean H460_FeatureStd24::OnSendAdmissionRequest(H225_FeatureDescriptor & pdu)
667 {
668 // Ignore if already not enabled or manually using STUN
669 if (!isEnabled)
670 return FALSE;
671
672 #ifdef H323_H46023
673 if (!EP->H46023NatMethodSelection(GetFeatureName()[0]))
674 return false;
675 #endif
676
677 PWaitAndSignal m(h460mute);
678
679 // Build Message
680 PTRACE(6,"Std24\tSending ARQ ");
681 H460_FeatureStd feat = H460_FeatureStd(24);
682
683 if (natconfig != e_unknown) {
684 feat.Add(NATInstOID,H460_FeatureContent((unsigned)natconfig,8));
685 }
686
687 pdu = feat;
688 return TRUE;
689 }
690
691 void H460_FeatureStd24::OnReceiveAdmissionConfirm(const H225_FeatureDescriptor & pdu)
692 {
693 H460_FeatureStd & feat = (H460_FeatureStd &)pdu;
694
695 if (feat.Contains(NATInstOID)) {
696 PTRACE(6,"Std24\tReading ACF");
697 unsigned NATinst = feat.Value(NATInstOID);
698 natconfig = (NatInstruct)NATinst;
699 HandleNATInstruction(natconfig);
700 }
701 }
702
703 void H460_FeatureStd24::OnReceiveAdmissionReject(const H225_FeatureDescriptor & pdu)
704 {
705 PTRACE(6,"Std24\tARJ Received");
706 HandleNATInstruction(H460_FeatureStd24::e_natFailure);
707 }
708
709 PBoolean H460_FeatureStd24::OnSendSetup_UUIE(H225_FeatureDescriptor & pdu)
710 {
711 // Ignore if already not enabled or manually using STUN
712 if (!isEnabled)
713 return FALSE;
714
715 PTRACE(6,"Std24\tSend Setup");
716 if (natconfig == H460_FeatureStd24::e_unknown)
717 return FALSE;
718
719 H460_FeatureStd feat = H460_FeatureStd(24);
720
721 int remoteconfig;
722 switch (natconfig) {
723 case H460_FeatureStd24::e_noassist:
724 remoteconfig = H460_FeatureStd24::e_noassist;
725 break;
726 case H460_FeatureStd24::e_localMaster:
727 remoteconfig = H460_FeatureStd24::e_remoteMaster;
728 break;
729 case H460_FeatureStd24::e_remoteMaster:
730 remoteconfig = H460_FeatureStd24::e_localMaster;
731 break;
732 case H460_FeatureStd24::e_localProxy:
733 remoteconfig = H460_FeatureStd24::e_remoteProxy;
734 break;
735 case H460_FeatureStd24::e_remoteProxy:
736 remoteconfig = H460_FeatureStd24::e_localProxy;
737 break;
738 default:
739 remoteconfig = natconfig;
740 }
741
742 feat.Add(NATInstOID,H460_FeatureContent(remoteconfig,8));
743 pdu = feat;
744 return TRUE;
745 }
746
747 void H460_FeatureStd24::OnReceiveSetup_UUIE(const H225_FeatureDescriptor & pdu)
748 {
749
750 PWaitAndSignal m(h460mute);
751
752 H460_FeatureStd & feat = (H460_FeatureStd &)pdu;
753
754 if (feat.Contains(NATInstOID)) {
755 PTRACE(6,"Std24\tReceive Setup");
756
757 unsigned NATinst = feat.Value(NATInstOID);
758 natconfig = (NatInstruct)NATinst;
759 HandleNATInstruction(natconfig);
760 }
761
762 }
763
764 void H460_FeatureStd24::HandleNATInstruction(NatInstruct _config)
765 {
766
767 PTRACE(4,"Std24\tNAT Instruction Received: " << _config);
768 switch (_config) {
769 case H460_FeatureStd24::e_localMaster:
770 PTRACE(4,"Std24\tLocal NAT Support: H.460.24 ENABLED");
771 CON->SetRemoteNAT(true);
772 CON->H46019SetOffload();
773 SetNATMethods(e_enable);
774 break;
775
776 case H460_FeatureStd24::e_remoteMaster:
777 PTRACE(4,"Std24\tRemote NAT Support: ALL NAT DISABLED");
778 CON->H46019SetOffload();
779 if (IsNatSendAvailable()) { // If we can use STUN do it!
780 CON->SetRemoteNAT(false);
781 SetNATMethods(e_enable);
782 } else
783 SetNATMethods(e_disable);
784 break;
785
786 case H460_FeatureStd24::e_remoteProxy:
787 PTRACE(4,"Std24\tRemote Proxy Support: H.460.24 DISABLED");
788 SetNATMethods(e_default);
789 break;
790
791 case H460_FeatureStd24::e_localProxy:
792 PTRACE(4,"Std24\tCall Local Proxy: H.460.24 DISABLED");
793 SetNATMethods(e_default);
794 break;
795
796 #ifdef H323_H46024A
797 case H460_FeatureStd24::e_natAnnexA:
798 PTRACE(4,"Std24\tSame NAT: H.460.24 AnnexA ENABLED");
799 CON->H46024AEnabled();
800 SetNATMethods(e_AnnexA);
801 break;
802 #endif
803
804 #ifdef H323_H46024B
805 case H460_FeatureStd24::e_natAnnexB:
806 PTRACE(4,"Std24\tSame NAT: H.460.24 AnnexA ENABLED");
807 CON->H46024BEnabled();
808 //CON->H46024AEnabled(); // Might be on same internal network
809 SetNATMethods(e_AnnexB);
810 break;
811 #endif
812
813 case H460_FeatureStd24::e_natFailure:
814 PTRACE(4,"Std24\tCall Failure Detected");
815 EP->FeatureCallBack(GetFeatureName()[0],1,"Call Failure");
816 break;
817 case H460_FeatureStd24::e_noassist:
818 PTRACE(4,"Std24\tNAT Call direct");
819 // fallthrough intended
820 default:
821 PTRACE(4,"Std24\tNo Assist: H.460.24 DISABLED.");
822 CON->DisableNATSupport();
823 SetNATMethods(e_default);
824 break;
825 }
826 }
827
828 void H460_FeatureStd24::SetH46019State(bool state)
829 {
830 #ifdef H323_H46018
831 if (CON->GetFeatureSet()->HasFeature(19)) {
832 H460_Feature * feat = CON->GetFeatureSet()->GetFeature(19);
833
834 PTRACE(4,"H46024\t" << (state ? "En" : "Dis") << "abling H.460.19 support for call");
835 ((H460_FeatureStd19 *)feat)->SetAvailable(state);
836 }
837 #endif
838 }
839
840 PBoolean H460_FeatureStd24::IsNatSendAvailable()
841 {
842 H323NatList & natlist = EP->GetNatMethods().GetNATList();
843
844 PBoolean available = false;
845 PINDEX i=0;
846 for (i=0; i< natlist.GetSize(); i++) {
847 #if PTLIB_VER >= 2130
848 if (natlist[i].GetMethodName() == "H46024") break;
849 #else
850 if (natlist[i].GetName() == "H46024") break;
851 #endif
852 }
853 if (i < natlist.GetSize()) {
854 PNatMethod_H46024 & meth = (PNatMethod_H46024 &)natlist[i];
855 switch (meth.GetNatType(false)) {
856 case PSTUNClient::ConeNat :
857 case PSTUNClient::RestrictedNat :
858 case PSTUNClient::PortRestrictedNat :
859 available = true;
860 break;
861 case PSTUNClient::SymmetricNat :
862 default : // UnknownNet, SymmetricFirewall, BlockedNat
863 break;
864 }
865 }
866 return available;
867 }
868
869 void H460_FeatureStd24::SetNATMethods(H46024NAT state)
870 {
871
872 H323NatList & natlist = EP->GetNatMethods().GetNATList();
873
874 for (PINDEX i=0; i< natlist.GetSize(); i++) {
875 #if PTLIB_VER >= 2130
876 PString name = natlist[i].GetMethodName();
877 #else
878 PString name = natlist[i].GetName();
879 #endif
880 switch (state) {
881 case H460_FeatureStd24::e_AnnexA: // To do Annex A Implementation.
882 case H460_FeatureStd24::e_AnnexB: // To do Annex B Implementation.
883 case H460_FeatureStd24::e_default:
884 if (name == "H46024" || name == "UPnP")
885 natlist[i].Activate(false);
886 break;
887 case H460_FeatureStd24::e_enable:
888 if (name == "H46024" && !useAlternate)
889 natlist[i].Activate(true);
890 else if (name == "UPnP" && useAlternate)
891 natlist[i].Activate(true);
892 else
893 natlist[i].Activate(false);
894 break;
895 case H460_FeatureStd24::e_disable:
896 if (name == "H46019" && CON->IsH46019Multiplexed())
897 natlist[i].Activate(true);
898 else
899 natlist[i].Activate(false);
900 break;
901 default:
902 break;
903 }
904 }
905
906 PTRACE(6,"Std24\tNAT Methods " << GetH460NATString(state));
907 for (PINDEX i=0; i< natlist.GetSize(); i++) {
908 #if PTLIB_VER >= 2130
909 PString name = natlist[i].GetMethodName();
910 #else
911 PString name = natlist[i].GetName();
912 #endif
913 PTRACE(6, "H323\tNAT Method " << i << " " << name << " Ready: "
914 << (natlist[i].IsAvailable(PIPSocket::Address::GetAny(4)) ? "Yes" : "No"));
915 }
916 }
917
918 PString H460_FeatureStd24::GetNATStrategyString(NatInstruct method)
919 {
920 static const char * const Names[10] = {
921 "Unknown Strategy",
922 "No Assistance",
923 "Local Master",
924 "Remote Master",
925 "Local Proxy",
926 "Remote Proxy",
927 "Full Proxy",
928 "AnnexA SameNAT",
929 "AnnexB NAToffload",
930 "Call Failure!"
931 };
932
933 if (method < 10)
934 return Names[method];
935
936 return psprintf("<NAT Strategy %u>", method);
937 }
938
939 PString H460_FeatureStd24::GetH460NATString(H46024NAT method)
940 {
941 static const char * const Names[5] = {
942 "default"
943 "enable"
944 "AnnexA"
945 "AnnexB"
946 "disable"
947 };
948
949 if (method < 5)
950 return Names[method];
951
952 return psprintf("<H460NAT %u>", method);
953 }
954
955
956
957 #ifdef _MSC_VER
958 #pragma warning(default : 4239)
959 #endif
960
961 #endif // Win32_WCE
962