1 
2 /*
3  * pnat.cxx
4  *
5  * NAT Strategy support for Portable Windows Library.
6  *
7  *
8  * Copyright (c) 2004 ISVO (Asia) Pte Ltd. All Rights Reserved.
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  *
21  * The Original Code is derived from and used in conjunction with the
22  * OpenH323 Project (www.openh323.org/)
23  *
24  * The Initial Developer of the Original Code is ISVO (Asia) Pte Ltd.
25  *
26  *
27  * Contributor(s): ______________________________________.
28  *
29  * $Revision: 24883 $
30  * $Author: shorne $
31  * $Date: 2010-11-18 06:08:04 -0600 (Thu, 18 Nov 2010) $
32  */
33 
34 #include <ptlib.h>
35 #include <ptclib/pnat.h>
36 #include <ptclib/random.h>
37 
38 
39 static const char PNatMethodBaseClass[] = "PNatMethod";
Create(const PString & method) const40 template <> PNatMethod * PDevicePluginFactory<PNatMethod>::Worker::Create(const PString & method) const
41 {
42    return PNatMethod::Create(method);
43 }
44 
45 typedef PDevicePluginAdapter<PNatMethod> PDevicePluginPNatMethod;
46 PFACTORY_CREATE(PFactory<PDevicePluginAdapterBase>, PDevicePluginPNatMethod, PNatMethodBaseClass, true);
47 
48 
PNatStrategy()49 PNatStrategy::PNatStrategy()
50 {
51    pluginMgr = NULL;
52 }
53 
~PNatStrategy()54 PNatStrategy::~PNatStrategy()
55 {
56    natlist.RemoveAll();
57 }
58 
AddMethod(PNatMethod * method)59 void PNatStrategy::AddMethod(PNatMethod * method)
60 {
61   natlist.Append(method);
62 }
63 
GetMethod(const PIPSocket::Address & address)64 PNatMethod * PNatStrategy::GetMethod(const PIPSocket::Address & address)
65 {
66   for (PNatList::iterator i = natlist.begin(); i != natlist.end(); i++) {
67     if (i->IsAvailable(address))
68       return &*i;
69   }
70 
71   return NULL;
72 }
73 
GetMethodByName(const PString & name)74 PNatMethod * PNatStrategy::GetMethodByName(const PString & name)
75 {
76   for (PNatList::iterator i = natlist.begin(); i != natlist.end(); i++) {
77     if (i->GetName() == name) {
78       return &*i;
79 	}
80   }
81 
82   return NULL;
83 }
84 
RemoveMethod(const PString & meth)85 PBoolean PNatStrategy::RemoveMethod(const PString & meth)
86 {
87   for (PNatList::iterator i = natlist.begin(); i != natlist.end(); i++) {
88     if (i->GetName() == meth) {
89       natlist.erase(i);
90       return true;
91     }
92   }
93 
94   return false;
95 }
96 
SetPortRanges(WORD portBase,WORD portMax,WORD portPairBase,WORD portPairMax)97 void PNatStrategy::SetPortRanges(WORD portBase, WORD portMax, WORD portPairBase, WORD portPairMax)
98 {
99   for (PNatList::iterator i = natlist.begin(); i != natlist.end(); i++)
100     i->SetPortRanges(portBase, portMax, portPairBase, portPairMax);
101 }
102 
103 
LoadNatMethod(const PString & name)104 PNatMethod * PNatStrategy::LoadNatMethod(const PString & name)
105 {
106    if (pluginMgr == NULL)
107     pluginMgr = &PPluginManager::GetPluginManager();
108 
109   return (PNatMethod *)pluginMgr->CreatePluginsDeviceByName(name, PNatMethodBaseClass);
110 }
111 
GetRegisteredList()112 PStringArray PNatStrategy::GetRegisteredList()
113 {
114   PPluginManager * plugMgr = &PPluginManager::GetPluginManager();
115   return plugMgr->GetPluginsProviding(PNatMethodBaseClass);
116 }
117 
118 ///////////////////////////////////////////////////////////////////////
119 
PNatMethod()120 PNatMethod::PNatMethod()
121 {
122 
123 }
124 
~PNatMethod()125 PNatMethod::~PNatMethod()
126 {
127 
128 }
129 
Create(const PString & name,PPluginManager * pluginMgr)130 PNatMethod * PNatMethod::Create(const PString & name, PPluginManager * pluginMgr)
131 {
132   if (pluginMgr == NULL)
133     pluginMgr = &PPluginManager::GetPluginManager();
134 
135   return (PNatMethod *)pluginMgr->CreatePluginsDeviceByName(name, PNatMethodBaseClass,0);
136 }
137 
CreateSocketPair(PUDPSocket * & socket1,PUDPSocket * & socket2,const PIPSocket::Address & binding,void *)138 PBoolean PNatMethod::CreateSocketPair(PUDPSocket * & socket1,PUDPSocket * & socket2,
139       const PIPSocket::Address & binding, void * /*userData*/)
140 {
141 	return CreateSocketPair(socket1,socket2,binding);
142 }
143 
PrintOn(ostream & strm) const144 void PNatMethod::PrintOn(ostream & strm) const
145 {
146   strm << GetName() << " server " << GetServer();
147 }
148 
GetServer() const149 PString PNatMethod::GetServer() const
150 {
151   PStringStream str;
152   PIPSocket::Address serverAddress;
153   WORD serverPort;
154   if (GetServerAddress(serverAddress, serverPort))
155     str << serverAddress << ':' << serverPort;
156   return str;
157 }
158 
159 
SetPortRanges(WORD portBase,WORD portMax,WORD portPairBase,WORD portPairMax)160 void PNatMethod::SetPortRanges(WORD portBase, WORD portMax, WORD portPairBase, WORD portPairMax)
161 {
162   singlePortInfo.mutex.Wait();
163 
164   singlePortInfo.basePort = portBase;
165   if (portBase == 0)
166     singlePortInfo.maxPort = 0;
167   else if (portMax == 0)
168     singlePortInfo.maxPort = (WORD)(singlePortInfo.basePort+99);
169   else if (portMax < portBase)
170     singlePortInfo.maxPort = portBase;
171   else
172     singlePortInfo.maxPort = portMax;
173 
174   singlePortInfo.currentPort = singlePortInfo.basePort;
175 
176   singlePortInfo.mutex.Signal();
177 
178   pairedPortInfo.mutex.Wait();
179 
180   pairedPortInfo.basePort = (WORD)((portPairBase+1)&0xfffe);
181   if (portPairBase == 0) {
182     pairedPortInfo.basePort = 0;
183     pairedPortInfo.maxPort = 0;
184   }
185   else if (portPairMax == 0)
186     pairedPortInfo.maxPort = (WORD)(pairedPortInfo.basePort+99);
187   else if (portPairMax < portPairBase)
188     pairedPortInfo.maxPort = portPairBase;
189   else
190     pairedPortInfo.maxPort = portPairMax;
191 
192   pairedPortInfo.currentPort = pairedPortInfo.basePort;
193 
194   pairedPortInfo.mutex.Signal();
195 }
196 
Activate(bool)197 void PNatMethod::Activate(bool /*active*/)
198 {
199 
200 }
201 
SetAlternateAddresses(const PStringArray &,void *)202 void PNatMethod::SetAlternateAddresses(const PStringArray & /*addresses*/, void * /*userData*/)
203 {
204 
205 }
206 
RandomPortPair(unsigned int start,unsigned int end)207 WORD PNatMethod::RandomPortPair(unsigned int start, unsigned int end)
208 {
209 	WORD num;
210 	PRandom rand;
211 	num = (WORD)rand.Generate(start,end);
212 	if (PString(num).Right(1).FindOneOf("13579") != P_MAX_INDEX)
213 			num++;  // Make sure the number is even
214 
215 	return num;
216 }
217 
218