1 //////////////////////////////////////////////////////////////////
3 // Toolkit base class for the GnuGK
5 // This work is published under the GNU Public License (GPL)
6 // see file COPYING for details.
7 // We also explicitely grant the right to link this code
8 // with the OpenH323 library.
10 //////////////////////////////////////////////////////////////////
12 #if defined(_WIN32) && (_MSC_VER <= 1200)
13 #pragma warning(disable:4786) // warning about too long debug symbol off
14 #pragma warning(disable:4284)
18 #include <ptclib/cypher.h>
25 #if HAS_MYSQL || HAS_PGSQL
34 extern const char *ProxySection;
35 extern const char *RoutedSec;
39 const PString paddingByteConfigKey("KeyFilled");
40 const BYTE AnyRawAddress[16] = {
41 255, 255, 255, 255, 255, 255, 255, 255,
42 255, 255, 255, 255, 255, 255, 255, 255
47 NetworkAddress::NetworkAddress() : m_address(0), m_netmask(0)
51 NetworkAddress::NetworkAddress(
52 const PIPSocket::Address &addr
53 ) : m_address(addr), m_netmask(addr.GetSize(), AnyRawAddress)
57 NetworkAddress::NetworkAddress(
58 const PIPSocket::Address &addr,
59 const PIPSocket::Address &nm
62 // normalize the address
64 const unsigned sz = addr.GetSize();
65 for (unsigned i = 0; i < sz; i++)
66 rawdata[i] = addr[i] & nm[i];
67 m_address = PIPSocket::Address(sz, rawdata);
70 NetworkAddress::NetworkAddress(
71 const PString &str /// an address in a form A.B.C.D, A.B.C.D/24 or A.B.C.D/255.255.255.0
74 Toolkit::GetNetworkFromString(str, m_address, m_netmask);
77 unsigned NetworkAddress::GetNetmaskLen() const
80 const unsigned sz = m_netmask.GetSize() * 8;
81 const char *rawdata = m_netmask.GetPointer();
84 for (int b = sz - 1; b >= 0; b--)
85 if (rawdata[b >> 3] & (0x80 >> (b & 7)))
93 bool NetworkAddress::operator==(const NetworkAddress &addr) const
95 if (m_address.GetSize() != addr.m_address.GetSize())
98 const unsigned sz = m_address.GetSize();
99 for (unsigned i = 0; i < sz; i++)
100 if (m_address[i] != addr.m_address[i] || m_netmask[i] != addr.m_netmask[i])
106 bool NetworkAddress::operator==(const PIPSocket::Address &addr) const
108 if (m_address.GetSize() != addr.GetSize())
111 const unsigned sz = m_address.GetSize();
112 for (unsigned i = 0; i < sz; i++)
113 if (m_netmask[i] != 255 || m_address[i] != addr[i])
119 bool NetworkAddress::operator>>(const NetworkAddress &addr) const
121 if (m_address.GetSize() != addr.m_address.GetSize())
124 const unsigned sz = m_address.GetSize();
125 for (unsigned i = 0; i < sz; i++)
126 if (m_netmask[i] != (addr.m_netmask[i] & m_netmask[i])
127 || m_address[i] != (addr.m_address[i] & m_netmask[i]))
133 bool NetworkAddress::operator<<(const NetworkAddress &addr) const
135 return addr >> *this;
138 bool NetworkAddress::operator>>(const PIPSocket::Address &addr) const
140 if (m_address.GetSize() != addr.GetSize())
143 const unsigned sz = m_address.GetSize();
144 for (unsigned i = 0; i < sz; i++)
145 if (m_address[i] != (addr[i] & m_netmask[i]))
151 int NetworkAddress::Compare(const NetworkAddress &addr) const
153 int diff = m_address.GetSize() - addr.m_address.GetSize();
155 diff = GetNetmaskLen() - addr.GetNetmaskLen();
157 const unsigned sz = m_address.GetSize();
158 for (unsigned i = 0; i < sz; i++) {
159 diff = m_address[i] - addr.m_address[i];
168 PString NetworkAddress::AsString() const
170 return m_address.AsString() + "/" + PString(GetNetmaskLen());
173 bool NetworkAddress::IsAny() const
175 return const_cast<NetworkAddress*>(this)->m_address.IsAny() ? true : false;
178 bool NetworkAddress::operator<(const NetworkAddress &addr) const
180 return Compare(addr) < 0;
183 bool NetworkAddress::operator<=(const NetworkAddress &addr) const
185 return Compare(addr) <= 0;
188 bool NetworkAddress::operator>(const NetworkAddress &addr) const
190 return Compare(addr) > 0;
193 bool NetworkAddress::operator>=(const NetworkAddress &addr) const
195 return Compare(addr) >= 0;
198 bool operator==(const PIPSocket::Address &addr, const NetworkAddress &net)
203 bool operator<<(const PIPSocket::Address &addr, const NetworkAddress &net)
209 // class Toolkit::RouteTable::RouteEntry
210 Toolkit::RouteTable::RouteEntry::RouteEntry(
212 ) : PIPSocket::RouteEntry(0)
214 destination = net.Tokenise("/", FALSE)[0];
215 GetNetworkFromString(net, network, net_mask);
218 Toolkit::RouteTable::RouteEntry::RouteEntry(
219 const PIPSocket::RouteEntry & re,
220 const InterfaceTable & it
221 ) : PIPSocket::RouteEntry(re)
224 for (i = 0; i < it.GetSize(); ++i) {
225 const Address & ip = it[i].GetAddress();
231 for (i = 0; i < it.GetSize(); ++i)
232 if (it[i].GetName() == interfaceName) {
233 destination = it[i].GetAddress();
238 inline bool Toolkit::RouteTable::RouteEntry::Compare(const Address *ip) const
240 return (*ip == destination) || ((*ip & net_mask) == network);
243 // class Toolkit::RouteTable
244 void Toolkit::RouteTable::InitTable()
246 // Workaround for OS doesn't support GetRouteTable
247 PIPSocket::GetHostAddress(defAddr);
253 // Set default IP according to route table
254 PIPSocket::Address defGW;
255 PIPSocket::GetGatewayAddress(defGW);
256 defAddr = GetLocalAddress(defGW);
259 for (RouteEntry *entry = rtable_begin; entry != rtable_end; ++entry)
260 PTRACE(2, "Network=" << entry->GetNetwork() << '/' << entry->GetNetMask() <<
261 ", IP=" << entry->GetDestination());
262 PTRACE(2, "Default IP=" << defAddr);
266 void Toolkit::RouteTable::ClearTable()
269 for (RouteEntry *r = rtable_begin; r != rtable_end; ++r)
271 ::free(rtable_begin);
276 // can't pass a reference of Address, or STL complains...
277 PIPSocket::Address Toolkit::RouteTable::GetLocalAddress(const Address & addr) const
279 // If a dynamic external IP retrieve external IP from DNS entries
280 if (DynExtIP && !addr.IsRFC1918()) {
281 PIPSocket::Address extip;
282 H323TransportAddress ex = H323TransportAddress(ExtIP);
283 ex.GetIpAddress(extip);
287 RouteEntry *entry = find_if(rtable_begin, rtable_end,
288 bind2nd(mem_fun_ref(&RouteEntry::Compare), &addr));
289 return (entry != rtable_end) ? entry->GetDestination() : defAddr;
292 bool Toolkit::RouteTable::CreateRouteTable(const PString & extroute)
294 InterfaceTable if_table;
295 if (!PIPSocket::GetInterfaceTable(if_table)) {
296 PTRACE(1, "Error: Can't get interface table");
300 PTRACE(4, "InterfaceTable:\n" << setfill('\n') << if_table << setfill(' '));
301 PIPSocket::RouteTable r_table;
302 if (!PIPSocket::GetRouteTable(r_table)) {
303 PTRACE(1, "Error: Can't get route table");
307 if (/*!extroute &&*/ AsBool(GkConfig()->GetString(ProxySection, "Enable", "0"))) {
308 for (PINDEX i = 0; i < r_table.GetSize(); ++i) {
309 if (r_table[i].GetNetwork().IsRFC1918() && r_table[i].GetNetMask().AsString() != "255.255.255.255") {
310 PString intAddr = r_table[i].GetNetwork().AsString() + "/" + r_table[i].GetNetMask().AsString();
311 m_internalnetworks.resize( m_internalnetworks.size() + 1);
312 m_internalnetworks[m_internalnetworks.size() - 1] = NetworkAddress(intAddr);
313 PTRACE(2, "Internal Network Detected " << m_internalnetworks.back().AsString());
318 int i = (!extroute) ? r_table.GetSize()+1 : r_table.GetSize();
320 rtable_end = rtable_begin = static_cast<RouteEntry *>(::malloc(i * sizeof(RouteEntry)));
321 for (PINDEX r = 0; r < i ; ++r) {
322 if (!extroute && (r==r_table.GetSize()))
323 ::new (rtable_end++) RouteEntry(extroute);
325 PIPSocket::RouteEntry & r_entry = r_table[r];
326 if (r_entry.GetNetMask() != INADDR_ANY)
327 ::new (rtable_end++) RouteEntry(r_entry, if_table);
334 bool Toolkit::VirtualRouteTable::CreateTable()
336 PString nets = GkConfig()->GetString("NetworkInterfaces", "");
338 PStringArray networks(nets.Tokenise(" ,;\t", FALSE));
339 int i = networks.GetSize();
341 rtable_end = rtable_begin = static_cast<RouteEntry *>(::malloc(i * sizeof(RouteEntry)));
342 for (PINDEX r = 0; r < i ; ++r)
343 ::new (rtable_end++) RouteEntry(networks[r]);
348 // If we have an external IP setting then load the detected Route Table and add a route for the external IP
349 // If dynamic IP then only store the PString value and resolve the DNS when required.
350 PString extip = GkConfig()->GetString("ExternalIP", "");
351 DynExtIP = AsBool(GkConfig()->GetString("ExternalIsDynamic", "0"));
353 PIPSocket::Address ext((DWORD)0);
354 H323TransportAddress ex = H323TransportAddress(extip);
355 ex.GetIpAddress(ext);
356 if (ext.IsValid() && !ext.IsRFC1918()) {
358 PString extroute = PString();
360 extroute = ext.AsString() + "/0";
362 CreateRouteTable(extroute);
363 PTRACE(1,"External IP = " << ExtIP << " dynamic " << DynExtIP);
371 bool Toolkit::VirtualRouteTable::IsMasquerade(PIPSocket::Address & addr)
374 H323TransportAddress ex = H323TransportAddress(ExtIP);
375 ex.GetIpAddress(addr);
382 // class Toolkit::ProxyCriterion
383 Toolkit::ProxyCriterion::ProxyCriterion() : m_enable(false)
387 Toolkit::ProxyCriterion::~ProxyCriterion()
391 void Toolkit::ProxyCriterion::LoadConfig(PConfig *config)
393 m_enable = AsBool(config->GetString(ProxySection, "Enable", "0"));
395 PTRACE(2, "GK\tH.323 Proxy disabled");
399 PTRACE(2, "GK\tH.323 Proxy enabled");
403 PStringArray networks(config->GetString(ProxySection, "InternalNetwork", "").Tokenise(" ,;\t", FALSE));
405 // if no networks specified then use the detected values
406 if (networks.GetSize() == 0) {
407 m_networks = Toolkit::Instance()->GetInternalNetworks();
408 for (unsigned j = 0; j < m_networks.size(); ++j)
409 PTRACE(2, "GK\tInternal Network " << j << " = " << m_networks[j].AsString());
413 for (PINDEX i = 0; i < networks.GetSize(); ++i) {
414 m_networks.resize(m_networks.size() + 1);
415 m_networks[m_networks.size() - 1] = NetworkAddress(networks[i]);
416 PTRACE(2, "GK\tINI Internal Network " << i << " = " << m_networks.back().AsString());
420 bool Toolkit::ProxyCriterion::Required(const Address & ip1, const Address & ip2) const
422 return m_enable ? (m_networks.empty() || (IsInternal(ip1) != IsInternal(ip2))) : false;
425 int Toolkit::ProxyCriterion::IsInternal(const Address & ip) const
427 // Return the network Id. Addresses may be on different internal networks
429 std::vector<NetworkAddress>::const_iterator i = m_networks.begin();
430 while (i != m_networks.end()) {
438 // class Toolkit::RewriteTool
440 static const char *RewriteSection = "RasSrv::RewriteE164";
441 static const char *AliasRewriteSection = "RasSrv::RewriteAlias";
443 void Toolkit::RewriteData::AddSection(PConfig *config, const PString & section)
445 PStringToString cfgs(config->GetAllKeyValues(section));
446 PINDEX n_size = cfgs.GetSize();
448 std::map<PString, PString, pstr_prefix_lesser> rules;
449 for (PINDEX i = 0; i < n_size; ++i) {
450 PString key = cfgs.GetKeyAt(i);
451 PCaselessString first = PCaselessString(key[0]);
452 if (!key && (isdigit(key[0]) || (first.FindOneOf("!.%*#ABCDEFGHIGKLMNOPQRSTUVWXYZ") != P_MAX_INDEX)))
453 rules[key] = cfgs.GetDataAt(i);
455 // now the rules are ascendantly sorted by the keys
456 if ((n_size = rules.size()) > 0) {
457 // Add any existing rules to be resorted
459 for (PINDEX j = 0; j < m_size; ++j) {
460 rules[Key(j)] = Value(j);
463 m_size = m_size + n_size;
464 // replace array constructor with explicit memory allocation
465 // and in-place new operators - workaround for VC compiler
466 // m_RewriteKey = new PString[m_size * 2];
467 m_RewriteKey = (PString*)(new BYTE[sizeof(PString) * m_size * 2]);
468 m_RewriteValue = m_RewriteKey + m_size;
469 std::map<PString, PString, pstr_prefix_lesser>::iterator iter = rules.begin();
472 for (int i = m_size; i-- > 0 ; ++iter) {
473 // m_RewriteKey[i] = iter->first;
474 ::new(m_RewriteKey + i) PString(iter->first);
475 // m_RewriteValue[i] = iter->second;
476 ::new(m_RewriteValue + i) PString(iter->second);
481 Toolkit::RewriteData::RewriteData(PConfig *config, const PString & section)
485 AddSection(config, section);
488 Toolkit::RewriteData::~RewriteData()
490 // delete [] m_RewriteKey;
492 for (int i = 0; i < m_size * 2; i++)
493 (m_RewriteKey+i)->~PString();
494 delete[] ((BYTE*)m_RewriteKey);
497 void Toolkit::RewriteTool::LoadConfig(
501 m_RewriteFastmatch = config->GetString(RewriteSection, "Fastmatch", "");
502 m_TrailingChar = config->GetString("RasSrv::ARQFeatures", "RemoveTrailingChar", " ")[0];
503 m_defaultDomain = config->GetString("Gatekeeper::Main", "DefaultDomain", "");
505 m_Rewrite = new RewriteData(config, RewriteSection);
506 m_Rewrite->AddSection(config,AliasRewriteSection);
509 bool Toolkit::RewriteTool::RewritePString(PString & s) const
511 bool changed = false;
513 // If URL remove the domain if default domain
514 PINDEX at = s.Find('@');
515 if (at != P_MAX_INDEX) {
516 PString num = s.Left(at);
517 // Check if we have a default domain and strip it
518 if (s.Mid(at+1) == m_defaultDomain) {
519 PTRACE(2, "\tRewriteDomain: " << s << " to " << num);
523 // Check if all numeric then is E164 then strip the domain
525 for (j = 0; j < num.GetLength(); ++j)
526 if (!isdigit(num[j]))
529 if (j >= num.GetLength()) { // is numeric
530 PTRACE(2, "\tRewriteToE164: " << s << " to " << num);
537 // remove trailing character
538 if (s.GetLength() > 1 && s[s.GetLength() - 1] == m_TrailingChar) {
539 s = s.Left(s.GetLength() - 1);
543 if (strncmp(s, m_RewriteFastmatch, m_RewriteFastmatch.GetLength()) != 0)
547 for (PINDEX i = 0; i < m_Rewrite->Size(); ++i) {
548 const char *prefix = m_Rewrite->Key(i);
550 s = m_Rewrite->Value(i);
553 const int len = MatchPrefix(s, prefix);
554 // try a prefix match through all keys
555 if (len > 0 || (len == 0 && prefix[0] == '!')) {
556 // Rewrite to #t#. Append the suffix, too.
560 // 01901234 prefix, Config-Rule: 01901234=0521321
563 const char *newprefix = m_Rewrite->Value(i);
567 result = RewriteString(s, prefix, newprefix);
569 result = newprefix + s;
571 PTRACE(2, "\tRewritePString: " << s << " to " << result);
582 // class Toolkit::GWRewriteTool
584 static const char *GWRewriteSection = "RasSrv::GWRewriteE164";
586 Toolkit::GWRewriteTool::~GWRewriteTool() {
587 for (PINDEX i = 0; i < m_GWRewrite.GetSize(); ++i) {
588 delete &(m_GWRewrite.GetDataAt(i));
590 m_GWRewrite.RemoveAll();
593 bool Toolkit::GWRewriteTool::RewritePString(PString gw, bool direction, PString &data) {
595 GWRewriteEntry *gw_entry;
598 // First lookup the GW in the dictionary
599 gw_entry = m_GWRewrite.GetAt(gw);
601 if (gw_entry == NULL)
604 std::vector<pair<PString,PString> >::iterator rule_iterator = direction
605 ? gw_entry->m_entry_data.first.begin() : gw_entry->m_entry_data.second.begin();
606 std::vector<pair<PString,PString> >::iterator end_iterator = direction
607 ? gw_entry->m_entry_data.first.end() : gw_entry->m_entry_data.second.end();
609 for (; rule_iterator != end_iterator; ++rule_iterator) {
611 key = (*rule_iterator).first;
613 const int len = MatchPrefix(data, key);
614 if (len > 0 || (len == 0 && key[0] == '!')) {
616 value = (*rule_iterator).second;
619 value = RewriteString(data, key, value);
621 value = value + data;
624 PTRACE(2, "\tGWRewriteTool::RewritePString: " << data << " to " << value);
635 void Toolkit::GWRewriteTool::PrintData() {
637 std::vector<pair<PString,PString> >::iterator rule_iterator;
639 PTRACE(2, "GK\tLoaded per GW rewrite data:");
641 if (m_GWRewrite.GetSize() == 0) {
642 PTRACE(2, "GK\tNo per GW data loaded");
646 for (PINDEX i = 0; i < m_GWRewrite.GetSize(); ++i) {
649 for (rule_iterator = m_GWRewrite.GetDataAt(i).m_entry_data.first.begin(); rule_iterator != m_GWRewrite.GetDataAt(i).m_entry_data.first.end(); ++rule_iterator) {
650 PTRACE(3, "GK\t" << m_GWRewrite.GetKeyAt(i) << " (in): " << (*rule_iterator).first << " = " << (*rule_iterator).second);
654 for (rule_iterator = m_GWRewrite.GetDataAt(i).m_entry_data.second.begin(); rule_iterator != m_GWRewrite.GetDataAt(i).m_entry_data.second.end(); ++rule_iterator) {
655 PTRACE(3, "GK\t" << m_GWRewrite.GetKeyAt(i) << " (out): " << (*rule_iterator).first << " = " << (*rule_iterator).second);
660 PTRACE(2, "GK\tLoaded " << m_GWRewrite.GetSize() << " GW entries with rewrite info");
665 void Toolkit::GWRewriteTool::LoadConfig(PConfig *config) {
667 PINDEX gw_size, i, j, lines_size;
668 PString key, cfg_value;
669 PStringArray lines, tokenised_line;
670 GWRewriteEntry *gw_entry;
671 std::map<PString,PString> in_strings, out_strings;
672 vector<std::pair<PString,PString> > sorted_in_strings, sorted_out_strings;
673 std::map<PString,PString>::reverse_iterator strings_iterator;
674 pair<PString,PString> rule;
676 PStringToString cfgs(config->GetAllKeyValues(GWRewriteSection));
679 for (i = 0; i < m_GWRewrite.GetSize(); ++i) {
680 delete &(m_GWRewrite.GetDataAt(i));
682 m_GWRewrite.RemoveAll();
684 gw_size = cfgs.GetSize();
686 for (i = 0; i < gw_size; ++i) {
688 // Get the config keys
689 key = cfgs.GetKeyAt(i);
690 cfg_value = cfgs[key];
694 sorted_in_strings.clear();
695 sorted_out_strings.clear();
697 // Split the config data into seperate lines
698 lines = cfg_value.Tokenise(PString(";"));
700 lines_size = lines.GetSize();
702 for (j = 0; j < lines_size; ++j) {
704 // Split the config line into three strings, direction, from string, to string
705 tokenised_line = lines[j].Tokenise(PString("="));
707 if (tokenised_line.GetSize() < 3) {
708 PTRACE(0, "GK\tSyntax error in the GWRewriteE164 rule - missing =, rule: "
709 << key << " => " << lines[j]
714 // Put into appropriate std::map
716 if (tokenised_line[0] == "in")
717 in_strings[tokenised_line[1]] = tokenised_line[2];
718 else if (tokenised_line[0] == "out")
719 out_strings[tokenised_line[1]] = tokenised_line[2];
721 PTRACE(0, "GK\tSyntax error in the GWRewriteE164 rule - unknown rule type ("
722 << tokenised_line[0] << ", rule: " << key << " => " << lines[j]
726 // Put the map contents into reverse sorted vectors
727 for (strings_iterator = in_strings.rbegin(); strings_iterator != in_strings.rend(); ++strings_iterator) {
728 rule = *strings_iterator;
729 sorted_in_strings.push_back(rule);
731 for (strings_iterator = out_strings.rbegin(); strings_iterator != out_strings.rend(); ++strings_iterator) {
732 rule = *strings_iterator;
733 sorted_out_strings.push_back(rule);
738 gw_entry = new GWRewriteEntry();
739 gw_entry->m_entry_data.first = sorted_in_strings;
740 gw_entry->m_entry_data.second = sorted_out_strings;
743 // Add to PDictionary hash table
744 m_GWRewrite.Insert(key,gw_entry);
755 Toolkit::Toolkit() : Singleton<Toolkit>("Toolkit"),
756 m_Config(NULL), m_ConfigDirty(false),
757 m_acctSessionCounter(0), m_acctSessionBase((long)time(NULL)),
758 m_timerManager(new GkTimerManager()),
759 m_timestampFormatStr("Cisco"),
760 m_encKeyPaddingByte(-1), m_encryptAllPasswords(false),
770 PFile::Remove(m_tmpconfig);
771 PFile::Remove(m_extConfigFilePath);
773 delete m_timerManager;
777 Toolkit::RouteTable *Toolkit::GetRouteTable(bool real)
779 return real ? &m_RouteTable : m_VirtualRouteTable.IsEmpty() ? &m_RouteTable : &m_VirtualRouteTable;
782 PConfig* Toolkit::Config()
784 // Make sure the config would not be called before SetConfig
785 PAssert(!m_ConfigDefaultSection, "Error: Call Config() before SetConfig()!");
786 return (m_Config == NULL) ? ReloadConfig() : m_Config;
789 PConfig* Toolkit::Config(const char *section)
791 Config()->SetDefaultSection(section);
795 PConfig* Toolkit::SetConfig(const PFilePath &fp, const PString §ion)
797 m_ConfigFilePath = fp;
798 m_ConfigDefaultSection = section;
800 return ReloadConfig();
803 void Toolkit::SetConfig(int act, const PString & sec, const PString & key, const PString & value)
805 // the original config
806 PConfig cfg(m_ConfigFilePath, m_ConfigDefaultSection);
810 cfg.SetString(sec, key, value);
811 m_Config->SetString(sec, key, value);
814 cfg.DeleteKey(sec, key);
815 m_Config->DeleteKey(sec, key);
818 cfg.DeleteSection(sec);
819 m_Config->DeleteSection(sec);
823 m_ConfigDirty = true;
826 PString Toolkit::GetTempDir() const
831 // check if the directory exists and is accessible (access rights)
832 if (PFile::Exists("/tmp") && PFile::Access("/tmp", PFile::ReadWrite))
837 PConfig cfg(PConfig::Environment);
839 if (cfg.HasKey("TMP"))
840 tmpdir = cfg.GetString("TMP");
841 else if (cfg.HasKey("TEMP"))
842 tmpdir = cfg.GetString("TEMP");
843 else if (cfg.HasKey("TMPDIR"))
844 tmpdir = cfg.GetString("TMPDIR");
847 if (!tmpdir.IsEmpty()) {
848 // strip trailing separator
849 if (tmpdir[tmpdir.GetLength()-1] == PDIR_SEPARATOR)
850 tmpdir = tmpdir.Left(tmpdir.GetLength()-1);
852 // check if the directory exists and is accessible (access rights)
853 if (!(PFile::Exists(tmpdir) && PFile::Access(tmpdir, PFile::ReadWrite)))
860 void Toolkit::CreateConfig()
862 if (m_Config != NULL)
863 PFile::Remove(m_tmpconfig);
865 PString tmpdir = GetTempDir();
868 if (tmpdir.IsEmpty())
869 if (PFile::Access(".", PFile::ReadWrite))
872 const PFilePath fpath(m_ConfigFilePath);
873 tmpdir = fpath.GetDirectory();
876 if (tmpdir.IsEmpty())
880 // generate a unique name
882 m_tmpconfig = tmpdir + PDIR_SEPARATOR + "gnugk.ini-" + PString(PString::Unsigned, rand()%10000);
883 PTRACE(5, "GK\tTrying file name "<< m_tmpconfig << " for temp config");
884 } while (PFile::Exists(m_tmpconfig));
887 // Does WIN32 support symlink?
888 if (PFile::Copy(m_ConfigFilePath, m_tmpconfig)) {
890 if (symlink(m_ConfigFilePath, m_tmpconfig) == 0) {
893 m_Config = new PConfig(m_tmpconfig, m_ConfigDefaultSection);
894 } else { // Oops! Create temporary config file failed, use the original one
895 PTRACE(0, "CONFIG\tCould not create/link config to a temporary file " << m_tmpconfig);
897 m_Config = new PConfig(m_ConfigFilePath, m_ConfigDefaultSection);
900 if (!m_extConfigFilePath)
901 PFile::Remove(m_extConfigFilePath);
903 // generate a unique name
905 m_extConfigFilePath = tmpdir + PDIR_SEPARATOR + "gnugk.ini-" + PString(PString::Unsigned, rand()%10000);
906 PTRACE(5, "GK\tTrying file name "<< m_extConfigFilePath << " for external config");
907 } while (PFile::Exists(m_extConfigFilePath));
909 m_Config = new GatekeeperConfig(
910 m_extConfigFilePath, m_ConfigDefaultSection, m_Config
914 void Toolkit::ReloadSQLConfig()
916 #if HAS_MYSQL || HAS_PGSQL || HAS_FIREBIRD
917 if (m_Config->GetSections().GetStringsIndex("SQLConfig") == P_MAX_INDEX)
920 const PString driverName = m_Config->GetString("SQLConfig", "Driver", "");
921 if (driverName.IsEmpty()) {
922 PTRACE(0, "SQLCONF\tFailed to read config settings from SQL: no driver specified");
926 GkSQLConnection *sqlConn = GkSQLConnection::Create(driverName, "SQLCONF");
927 if (sqlConn == NULL) {
928 PTRACE(0, "SQLCONF\tFailed to create a connection: no driver found for "
929 << driverName << " database"
934 if (!sqlConn->Initialize(m_Config, "SQLConfig")) {
937 PTRACE(0, "SQLCONF\tFailed to read config settings from SQL: could not connect to the database");
941 PTRACE(3, "SQLCONF\tSQL config connection established");
944 GkSQLResult* queryResult;
946 query = m_Config->GetString("SQLConfig", "ConfigQuery", "");
947 if (!query.IsEmpty()) {
948 PTRACE(4, "SQLCONF\tLoading config key=>value pairs from SQL database");
951 queryResult = sqlConn->ExecuteQuery(query, ¶ms);
952 if (queryResult == NULL)
953 PTRACE(0, "SQLCONF\tFailed to load config key=>value pairs from SQL "
954 "database: timeout or fatal error"
956 else if (!queryResult->IsValid())
957 PTRACE(0, "SQLCONF\tFailed to load config key=>value pairs from SQL "
958 "database (" << queryResult->GetErrorCode() << "): "
959 << queryResult->GetErrorMessage()
961 else if (queryResult->GetNumFields() < 3)
962 PTRACE(0, "SQLCONF\tFailed to load config key=>value pairs from SQL "
963 "database: at least 3 columns must be present in the result set"
966 while (queryResult->FetchRow(params))
967 if (params[0].IsEmpty() || params[1].IsEmpty())
968 PTRACE(1, "SQLCONF\tInvalid config key=>value pair entry found "
969 "in the SQL database: '[" << params[0] << "] "
970 << params[1] << '=' << params[1] << '\''
973 m_Config->SetString(params[0], params[1], params[2]);
974 PTRACE(6, "SQLCONF\tConfig entry read: '[" << params[0]
975 << "] " << params[1] << '=' << params[2] << '\''
978 PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows()
979 << " config key=>value pairs loaded from SQL database");
986 query = m_Config->GetString("SQLConfig", "RewriteE164Query", "");
987 if (!query.IsEmpty()) {
988 PTRACE(4, "SQLCONF\tLoading rewrite rules from SQL database");
991 queryResult = sqlConn->ExecuteQuery(query, ¶ms);
992 if (queryResult == NULL)
993 PTRACE(0, "SQLCONF\tFailed to load rewrite rules from SQL database: "
994 "timeout or fatal error"
996 else if (!queryResult->IsValid())
997 PTRACE(0, "SQLCONF\tFailed to load rewrite rules from SQL database ("
998 << queryResult->GetErrorCode() << "): " << queryResult->GetErrorMessage()
1000 else if (queryResult->GetNumFields() < 2)
1001 PTRACE(0, "SQLCONF\tFailed to load rewrite rules from SQL database: "
1002 "at least 2 columns must be present in the result set"
1005 while (queryResult->FetchRow(params))
1006 if (params[0].IsEmpty())
1007 PTRACE(1, "SQLCONF\tInvalid rewrite rule found in the SQL "
1008 "database: '" << params[0] << '=' << params[1] << '\''
1011 m_Config->SetString("RasSrv::RewriteE164", params[0], params[1]);
1012 PTRACE(6, "SQLCONF\tRewrite rule read: '" << params[0]
1013 << '=' << params[1] << '\''
1016 PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " rewrite rules "
1017 "loaded from SQL database"
1024 query = m_Config->GetString("SQLConfig", "NeighborsQuery", "");
1025 if (!query.IsEmpty()) {
1026 PTRACE(4, "SQLCONF\tLoading neighbors from SQL database");
1027 PStringArray params;
1029 queryResult = sqlConn->ExecuteQuery(query, ¶ms);
1030 if (queryResult == NULL)
1031 PTRACE(0, "SQLCONF\tFailed to load neighbors from SQL database: "
1032 "timeout or fatal error"
1034 else if (!queryResult->IsValid())
1035 PTRACE(0, "SQLCONF\tFailed to load neighbors from SQL database ("
1036 << queryResult->GetErrorCode() << "): " << queryResult->GetErrorMessage()
1038 else if (queryResult->GetNumFields() < 6)
1039 PTRACE(0, "SQLCONF\tFailed to load neighbors from SQL database: "
1040 "at least 6 columns must be present in the result set"
1043 while (queryResult->FetchRow(params)) {
1046 value = ";" + params[5];
1047 if (!(params[4].IsEmpty() && value.IsEmpty()))
1048 value = ";" + params[4] + value;
1049 if (!(params[3].IsEmpty() && value.IsEmpty()))
1050 value = ";" + params[3] + value;
1052 value = params[1] + ":" + params[2] + value;
1054 value = params[1] + value;
1055 if (params[0].IsEmpty() || params[1].IsEmpty())
1056 PTRACE(1, "SQLCONF\tInvalid neighbor entry found in the SQL "
1057 "database: '" << params[0] << '=' << value << '\''
1060 m_Config->SetString("RasSrv::Neighbors", params[0], value);
1061 PTRACE(6, "SQLCONF\tNeighbor entry read: '" << params[0]
1062 << '=' << value << '\''
1066 PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " neighbor entries "
1067 "loaded from SQL database"
1074 query = m_Config->GetString("SQLConfig", "PermanentEndpointsQuery", "");
1075 if (!query.IsEmpty()) {
1076 PTRACE(4, "SQLCONF\tLoading permanent endpoints from SQL database");
1077 PStringArray params;
1079 queryResult = sqlConn->ExecuteQuery(query, ¶ms);
1080 if (queryResult == NULL)
1081 PTRACE(0, "SQLCONF\tFailed to load permanent endpoints from SQL "
1082 "database: timeout or fatal error"
1084 else if (!queryResult->IsValid())
1085 PTRACE(0, "SQLCONF\tFailed to load permanent endpoints from SQL database "
1086 "(" << queryResult->GetErrorCode() << "): "
1087 << queryResult->GetErrorMessage()
1089 else if (queryResult->GetNumFields() < 4)
1090 PTRACE(0, "SQLCONF\tFailed to load permanent endpoints from SQL database: "
1091 "at least 4 columns must be present in the result set"
1096 while (queryResult->FetchRow(params)) {
1099 key += ":" + params[1];
1102 value += ";" + params[3];
1103 if (key.IsEmpty() || value.IsEmpty())
1104 PTRACE(1, "SQLCONF\tInvalid permanent endpoint entry found "
1105 "in the SQL database: '" << key << '=' << value << '\''
1108 m_Config->SetString("RasSrv::PermanentEndpoints", key, value);
1109 PTRACE(6, "SQLCONF\tPermanent endpoint read: '" << key
1110 << '=' << value << '\''
1114 PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " permanent "
1115 "endpoints loaded from SQL database"
1122 query = m_Config->GetString("SQLConfig", "GWPrefixesQuery", "");
1123 if (!query.IsEmpty()) {
1124 PTRACE(4, "SQLCONF\tLoading gateway prefixes from SQL database");
1125 PStringArray params;
1127 queryResult = sqlConn->ExecuteQuery(query, ¶ms);
1128 if (queryResult == NULL)
1129 PTRACE(0, "SQLCONF\tFailed to load gateway prefixes from SQL database: "
1130 "timeout or fatal error"
1132 else if (!queryResult->IsValid())
1133 PTRACE(0, "SQLCONF\tFailed to load gateway prefixes from SQL database ("
1134 << queryResult->GetErrorCode() << "): " << queryResult->GetErrorMessage()
1136 else if (queryResult->GetNumFields() < 2)
1137 PTRACE(0, "SQLCONF\tFailed to load gateway prefixes from SQL database: "
1138 "at least 2 columns must be present in the result set"
1141 while (queryResult->FetchRow(params))
1142 if (params[0].IsEmpty() || params[1].IsEmpty())
1143 PTRACE(1, "SQLCONF\tInvalid gateway prefixes entry found "
1144 "in the SQL database: '" << params[0] << '='
1145 << params[1] << '\''
1148 m_Config->SetString("RasSrv::GWPrefixes",
1149 params[0], params[1]
1151 PTRACE(6, "SQLCONF\tGateway prefixes read: '" << params[0]
1152 << '=' << params[1] << '\''
1155 PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " gateway prefixes "
1156 "loaded from SQL database"
1165 PTRACE(3, "SQLCONF\tSQL config connection closed");
1166 #endif // HAS_MYSQL || HAS_PGSQL
1169 PConfig* Toolkit::ReloadConfig()
1173 else // the config have been changed via status port, use it directly
1174 m_ConfigDirty = false;
1176 m_GKName = Config()->GetString("Name", "OpenH323GK");
1178 m_encryptAllPasswords = Toolkit::AsBool(
1179 Config()->GetString("EncryptAllPasswords", "0")
1181 if (Config()->HasKey(paddingByteConfigKey))
1182 m_encKeyPaddingByte = Config()->GetInteger(paddingByteConfigKey, 0);
1184 m_encKeyPaddingByte = m_encryptAllPasswords ? 0 : -1;
1188 m_RouteTable.InitTable();
1189 m_VirtualRouteTable.InitTable();
1190 m_ProxyCriterion.LoadConfig(m_Config);
1191 m_Rewrite.LoadConfig(m_Config);
1192 m_GWRewrite.LoadConfig(m_Config);
1193 PString GKHome(m_Config->GetString("Home", ""));
1194 if (m_GKHome.empty() || !GKHome)
1195 SetGKHome(GKHome.Tokenise(",:;", false));
1197 m_timestampFormatStr = Config()->GetString("TimestampFormat", "Cisco");
1199 delete m_cliRewrite;
1200 m_cliRewrite = new CLIRewrite;
1202 CapacityControl::Instance()->LoadConfig();
1204 LoadCauseMap(m_Config);
1206 LoadReasonMap(m_Config);
1211 void Toolkit::LoadCauseMap(
1215 memset(m_causeMap, 0, 16);
1217 if (! Toolkit::AsBool(cfg->GetString(RoutedSec, "ActivateFailover", "0")))
1220 PStringArray causes(cfg->GetString(RoutedSec, "FailoverCauses", "1-15,21-127").Tokenise(", \t", FALSE));
1222 for (PINDEX i = 0; i < causes.GetSize(); ++i)
1223 if (causes[i].Find('-') == P_MAX_INDEX) {
1224 unsigned c = causes[i].AsUnsigned() & 0x7f;
1225 m_causeMap[c >> 3] |= (1UL << (c & 7));
1227 PStringArray causeRange(causes[i].Tokenise("- ", FALSE));
1228 if (causeRange.GetSize() == 2) {
1229 unsigned cmin = causeRange[0].AsUnsigned() & 0x7f;
1230 unsigned cmax = causeRange[1].AsUnsigned() & 0x7f;
1231 for (; cmin <= cmax; ++cmin)
1232 m_causeMap[cmin >> 3] |= (1UL << (cmin & 7));
1237 // load H.225 reason to Q.931 cause mapping
1238 void Toolkit::LoadReasonMap(
1242 // default to ITU-T Recommendation H.225
1243 unsigned DefaultH225ReasonToQ931Cause[] = {
1244 34, 47, 3, 16, 88, 111, 38, 42, 28, 41, 17, 31, 16, 31, 20, 31, 47, 127,
1247 m_H225ReasonToQ931Cause.assign(&DefaultH225ReasonToQ931Cause[0], &DefaultH225ReasonToQ931Cause[22]);
1249 for(int reason = 0; reason < H225_ReleaseCompleteReason::e_tunnelledSignallingRejected; reason++) {
1251 str_reason.sprintf("%d", reason);
1252 PString cause = cfg->GetString("H225toQ931", str_reason, "");
1253 if (!cause.IsEmpty()) {
1254 m_H225ReasonToQ931Cause[reason] = cause.AsInteger();
1260 BOOL Toolkit::MatchRegex(const PString &str, const PString ®exStr)
1263 PRegularExpression regex(regexStr, PRegularExpression::Extended);
1264 if(regex.GetErrorCode() != PRegularExpression::NoError) {
1265 PTRACE(2, "Errornous '"<< regex.GetErrorText() <<"' compiling regex: " << regexStr);
1268 if(!regex.Execute(str, pos)) {
1269 PTRACE(5, "Gk\tRegex '"<<regexStr<<"' did not match '"<<str<<"'");
1277 bool Toolkit::RewriteE164(H225_AliasAddress &alias)
1279 if ((alias.GetTag() != H225_AliasAddress::e_dialedDigits) &&
1280 (alias.GetTag() != H225_AliasAddress::e_h323_ID) &&
1281 (alias.GetTag() != H225_AliasAddress::e_url_ID))
1284 PString E164 = ::AsString(alias, FALSE);
1286 bool changed = RewritePString(E164);
1288 H323SetAliasAddress(E164, alias);
1293 bool Toolkit::RewriteE164(H225_ArrayOf_AliasAddress & aliases)
1295 bool changed = false;
1296 for (PINDEX n = 0; n < aliases.GetSize(); ++n)
1297 changed |= RewriteE164(aliases[n]);
1301 bool Toolkit::GWRewriteE164(PString gw, bool direction, H225_AliasAddress &alias) {
1306 if (alias.GetTag() != H225_AliasAddress::e_dialedDigits) {
1310 E164 = ::AsString(alias, FALSE);
1311 changed = GWRewritePString(gw,direction,E164);
1314 H323SetAliasAddress(E164, alias);
1320 bool Toolkit::GWRewriteE164(PString gw, bool direction, H225_ArrayOf_AliasAddress &aliases) {
1326 for (n = 0; n < aliases.GetSize(); ++n) {
1327 changed |= GWRewriteE164(gw,direction,aliases[n]);
1333 bool Toolkit::isBehindNAT(PIPSocket::Address & externalIP) {
1335 return (m_VirtualRouteTable.IsMasquerade(externalIP));
1338 std::vector<NetworkAddress> Toolkit::GetInternalNetworks() {
1340 return GkConfig()->HasKey("ExternalIP") ? m_VirtualRouteTable.GetInternalNetworks() : m_RouteTable.GetInternalNetworks();
1343 PString Toolkit::GetGKHome(vector<PIPSocket::Address> & GKHome) const
1347 int hsize = GKHome.size();
1348 for (int i = 0; i < hsize; ++i) {
1349 result += GKHome[i].AsString();
1356 void Toolkit::SetGKHome(const PStringArray & home)
1358 std::vector<PIPSocket::Address>::iterator begin;
1360 int n, i, size = home.GetSize();
1362 for (n = 0; n < size; ++n)
1363 m_GKHome.push_back(home[n]);
1365 PIPSocket::InterfaceTable it;
1366 if (PIPSocket::GetInterfaceTable(it)) {
1367 int is = it.GetSize();
1369 // check if the interface is valid
1370 for (n = 0; n < size; ++n) {
1371 for (i = 0; i < is; ++i)
1372 if (m_GKHome[n] == it[i].GetAddress())
1375 PTRACE(1, "GK\tAddress " << m_GKHome[n] << " not found"
1376 " in the PWLib interface table"
1378 //begin = m_GKHome.begin();
1379 //copy(begin + n + 1, begin + size, begin + n);
1387 for (n = 0; n < size; ++n)
1388 m_GKHome.push_back(it[n].GetAddress());
1390 // remove INADDR_ANY
1391 for (n = 0; n < size; ++n)
1392 if (m_GKHome[n] == INADDR_ANY) {
1393 begin = m_GKHome.begin();
1394 copy(begin + n + 1, begin + size, begin + n);
1399 // remove duplicate interfaces
1400 for (n = 0; n < size; ++n)
1401 for (i = 0; i < n; ++i)
1402 if (m_GKHome[n] == m_GKHome[i]) {
1403 begin = m_GKHome.begin();
1404 copy(begin + n + 1, begin + size, begin + n);
1409 m_GKHome.resize(size);
1410 // put the default IP to the first
1411 begin = find(m_GKHome.begin(), m_GKHome.end(), m_RouteTable.GetLocalAddress());
1412 if (begin != m_GKHome.end())
1413 swap(m_GKHome[0], *begin);
1417 Toolkit::GetInternalExtensionCode( const unsigned &country,
1418 const unsigned &extension,
1419 const unsigned &manufacturer) const
1423 switch (manufacturer) {
1425 switch (extension) {
1426 case t35eFailoverRAS: return iecFailoverRAS;
1433 switch (manufacturer) {
1435 switch (extension) {
1436 case t35eNeighborId:
1437 return iecNeighborId;
1438 case t35eNATTraversal:
1439 return iecNATTraversal;
1446 // default for all other cases
1450 int Toolkit::GetInternalExtensionCode(const H225_H221NonStandard& data) const
1452 return GetInternalExtensionCode(data.m_t35CountryCode,
1453 data.m_t35Extension,
1454 data.m_manufacturerCode);
1457 bool Toolkit::AsBool(const PString & str)
1461 const unsigned char c = (unsigned char)tolower(str[0]);
1462 return ( c=='t' || c=='1' || c=='y' || c=='a' );
1465 void Toolkit::GetNetworkFromString(
1467 PIPSocket::Address &network,
1468 PIPSocket::Address &netmask
1472 network = netmask = INADDR_ANY;
1476 PINDEX slashPos = s.Find('/');
1477 if (slashPos == P_MAX_INDEX) {
1479 static BYTE fullNetMask[16] = {
1480 255, 255, 255, 255, 255, 255, 255, 255,
1481 255, 255, 255, 255, 255, 255, 255, 255
1483 network = PIPSocket::Address(s);
1484 netmask = PIPSocket::Address(network.GetSize(), fullNetMask);
1486 network = PIPSocket::Address(s.Left(slashPos));
1488 const PString netmaskString = s.Mid(slashPos + 1);
1491 if (netmaskString.FindOneOf(".:") != P_MAX_INDEX) {
1492 // netmask as a network address
1493 netmask = PIPSocket::Address(netmaskString);
1495 // netmask as an integer
1496 const DWORD netmaskLen = netmaskString.AsUnsigned();
1497 for (unsigned b = 0; b < (unsigned)(network.GetSize() * 8); b++)
1499 rawData[b >> 3] |= 0x80U >> (b & 7);
1501 rawData[b >> 3] &= ~(0x80U >> (b & 7));
1502 netmask = PIPSocket::Address(network.GetSize(), rawData);
1505 // normalize the address
1506 for (unsigned b = 0; b < (unsigned)(network.GetSize()); b++)
1507 rawData[b] = network[b] & netmask[b];
1509 network = PIPSocket::Address(network.GetSize(), rawData);
1513 PString Toolkit::CypherDecode(const PString & key, const PString & crypto, int s)
1515 size_t sz = key.GetLength();
1516 if (sz > sizeof(PTEACypher::Key))
1517 sz = sizeof(PTEACypher::Key);
1518 PTEACypher::Key thekey;
1519 memset(&thekey, s, sizeof(PTEACypher::Key));
1520 memcpy(&thekey, (const char *)key, sz);
1521 PTEACypher cypher(thekey);
1523 return cypher.Decode(crypto);
1526 PString Toolkit::GenerateAcctSessionId()
1528 PWaitAndSignal lock( m_acctSessionMutex );
1529 return psprintf(PString("%08x%08x"),m_acctSessionBase,++m_acctSessionCounter);
1532 bool Toolkit::AsTimeInterval(
1533 /// formatted time interval string
1534 const char* inputString,
1535 /// variable to store calculated time interval on success
1536 PTimeInterval& interval
1539 if (inputString == NULL)
1542 PTimeInterval result;
1543 bool process_next = true;
1546 while (process_next) {
1547 char* strend = const_cast<char*>(inputString);
1548 long val = strtol(inputString, &strend, 10);
1551 if (strend == inputString)
1554 // integer range overflow
1555 if ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) {
1561 inputString = strend;
1564 if (*inputString == 0) {
1565 result += PTimeInterval(val);
1570 switch (*inputString)
1573 result += PTimeInterval(0,val);
1576 result += PTimeInterval(0,0,val);
1579 result += PTimeInterval(0,0,0,val);
1582 result += PTimeInterval(0,0,0,0,val);
1585 result += PTimeInterval(0,0,0,0,val*7);
1588 result += PTimeInterval(0,0,0,0,val*30);
1591 result += PTimeInterval(0,0,0,0,val*365);
1594 result += PTimeInterval(val);
1595 process_next = false;
1607 PString Toolkit::AsString(
1608 const PTime& tm, /// timestamp to convert into a string
1609 const PString& formatStr /// format string to use
1612 PString fmtStr = !formatStr ? formatStr : m_timestampFormatStr;
1613 if (fmtStr.IsEmpty())
1616 if (fmtStr *= "Cisco")
1617 fmtStr = "%H:%M:%S.%u %Z %a %b %d %Y";
1618 else if (fmtStr *= "ISO8601")
1619 return tm.AsString(PTime::LongISO8601);
1620 else if (fmtStr *= "RFC822")
1621 return tm.AsString(PTime::RFC1123);
1622 else if (fmtStr *= "MySQL" )
1623 fmtStr = "%Y-%m-%d %H:%M:%S";
1626 struct tm* tmptr = &_tm;
1627 time_t t = tm.GetTimeInSeconds();
1630 if (localtime_r(&t, tmptr) != tmptr) {
1632 tmptr = localtime(&t);
1633 if (tmptr == NULL) {
1635 PTRACE(0, "TOOLKIT\tCould not apply timestamp formatting - using default");
1636 return tm.AsString( "hh:mm:ss.uuu z www MMM d yyyy" );
1639 // replace %u with microseconds - this is our extension
1641 PINDEX length = fmtStr.GetLength();
1643 i = fmtStr.Find("%u", i);
1644 if (i != P_MAX_INDEX) {
1645 if (i > 0 && fmtStr[i-1] == '%') {
1649 const PString us(PString::Printf, "%03d", (unsigned)tm.GetMicrosecond());
1650 fmtStr.Splice(us, i, 2);
1651 length += us.GetLength();
1652 i += us.GetLength();
1655 } while (i != P_MAX_INDEX && i < length);
1660 if (strftime(buf.GetPointer(), 128, (const char*)fmtStr, tmptr) == 0) {
1661 PTRACE(0, "TOOLKIT\tCould not apply timestamp formatting - using default");
1662 return tm.AsString( "hh:mm:ss.uuu z www MMM d yyyy" );
1665 buf.MakeMinimumSize();
1669 PString Toolkit::ReadPassword(
1670 const PString &cfgSection, /// config section to read
1671 const PString &cfgKey, /// config key to read an encrypted password from
1675 if (cfgSection.IsEmpty() || cfgKey.IsEmpty())
1678 PConfig* const cfg = Config();
1679 if (!cfg->HasKey(cfgSection, cfgKey))
1682 int paddingByte = m_encKeyPaddingByte;
1683 if (cfg->HasKey(cfgSection, paddingByteConfigKey))
1684 paddingByte = cfg->GetInteger(cfgSection, paddingByteConfigKey, 0);
1686 if (paddingByte == -1)
1687 if (forceEncrypted || m_encryptAllPasswords)
1690 return cfg->GetString(cfgSection, cfgKey, "");
1692 PTEACypher::Key encKey;
1693 memset(&encKey, paddingByte, sizeof(encKey));
1695 const size_t keyLen = cfgKey.GetLength();
1697 memcpy(&encKey, (const char*)cfgKey, min(keyLen, sizeof(encKey)));
1699 PTEACypher cypher(encKey);
1701 if (!cypher.Decode(cfg->GetString(cfgSection, cfgKey, ""), s))
1702 PTRACE(1, "GK\tFailed to decode config password for [" << cfgSection
1703 << "] => " << cfgKey
1708 void Toolkit::RewriteCLI(
1712 m_cliRewrite->InRewrite(msg);
1715 void Toolkit::RewriteCLI(
1717 SetupAuthData &authData,
1718 const PIPSocket::Address &addr
1721 m_cliRewrite->OutRewrite(msg, authData, addr);
1724 void Toolkit::SetRerouteCauses(
1725 unsigned char *causeMap
1728 memcpy(causeMap, m_causeMap, 128/8);
1732 unsigned Toolkit::MapH225ReasonToQ931Cause(
1736 if( reason < 0 || reason > H225_ReleaseCompleteReason::e_tunnelledSignallingRejected )
1739 return m_H225ReasonToQ931Cause[reason];