//////////////////////////////////////////////////////////////////
//
// Toolkit base class for the GnuGK
//
// This work is published under the GNU Public License (GPL)
// see file COPYING for details.
// We also explicitely grant the right to link this code
// with the OpenH323 library.
//
// History:
// 991227 initial version (Torsten Will, mediaWays)
//
//////////////////////////////////////////////////////////////////
#ifndef TOOLKIT_H
#define TOOLKIT_H "@(#) $Id: Toolkit.h,v 1.37 2006/04/14 13:56:19 willamowius Exp $"
#include <vector>
#include "singleton.h"
class H225_AliasAddress;
class H225_ArrayOf_AliasAddress;
class H225_H221NonStandard;
class H225_Setup_UUIE;
class SignalingMsg;
template <class> class H225SignalingMsg;
typedef H225SignalingMsg<H225_Setup_UUIE> SetupMsg;
struct SetupAuthData;
/// Hold an address of a single host or a whole network
struct NetworkAddress {
/// Build an "any" address
NetworkAddress();
/// Build a single host address
NetworkAddress(
const PIPSocket::Address &addr
);
/// Build an address of the specified network
NetworkAddress(
const PIPSocket::Address &addr,
const PIPSocket::Address &nm
);
/// Build an address from the string
NetworkAddress(
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
);
/// @return Length of the network mask (number of significant bits)
unsigned GetNetmaskLen() const;
/** Compare two network addresses and define their relative order.
Ordering is done accordingly to netmask length and then to IP bytes.
@return <0 if this address is lesser than #addr#, 0 if both are equal,
>0 if this address is greater than #addr#.
*/
int Compare(
const NetworkAddress &addr
) const;
/// @return A string representation of the address in the form A.B.C.D/netmasklen
PString AsString() const;
/// @return True if this is a wildcard address
bool IsAny() const;
/// @return True if the given address is equal to this address
bool operator==(const PIPSocket::Address &addr) const;
bool operator==(const NetworkAddress &addr) const;
/// @return True if the given address is contained within this network
bool operator>>(const PIPSocket::Address &addr) const;
bool operator>>(const NetworkAddress &addr) const;
/// @return True if the given network contains this network
bool operator<<(const NetworkAddress &addr) const;
bool operator<(const NetworkAddress &addr) const;
bool operator<=(const NetworkAddress &addr) const;
bool operator>(const NetworkAddress &addr) const;
bool operator>=(const NetworkAddress &addr) const;
PIPSocket::Address m_address; /// host/network address
PIPSocket::Address m_netmask; /// netmask for the #m_address#
};
/// @return True if the given address equals to this address
bool operator==(const PIPSocket::Address &addr, const NetworkAddress &net);
/// @return True if the given address is contained withing this network
bool operator<<(const PIPSocket::Address &addr, const NetworkAddress &net);
class GkTimerManager;
class CLIRewrite;
class Toolkit : public Singleton<Toolkit>
{
public:
// con- and destructing
explicit Toolkit();
virtual ~Toolkit();
/// returns #basic# for
virtual const PString GetName() const { return "basic"; }
// by cwhuang
// The idea was got from OpenGatekeeper,
// but entirely implemented from scratch. :)
class RouteTable {
typedef PIPSocket::Address Address;
typedef PIPSocket::InterfaceTable InterfaceTable;
public:
RouteTable() : rtable_begin(0) { /* initialize later */ }
virtual ~RouteTable() { ClearTable(); }
Address GetLocalAddress() const { return defAddr; };
Address GetLocalAddress(const Address &) const;
void InitTable();
void ClearTable();
bool IsEmpty() const { return rtable_begin == 0; }
protected:
class RouteEntry : public PIPSocket::RouteEntry {
public:
#ifndef _WIN32
PCLASSINFO( RouteEntry, PIPSocket::RouteEntry )
#endif
RouteEntry(const PString &);
RouteEntry(const PIPSocket::RouteEntry &, const InterfaceTable &);
bool Compare(const Address *) const;
};
virtual bool CreateTable();
RouteEntry *rtable_begin, *rtable_end;
Address defAddr;
};
class VirtualRouteTable : public RouteTable {
// override from class RouteTable
virtual bool CreateTable();
};
RouteTable *GetRouteTable(bool = false);
class ProxyCriterion {
typedef PIPSocket::Address Address;
public:
ProxyCriterion();
~ProxyCriterion();
bool Required(const Address &, const Address &) const;
void LoadConfig(PConfig *);
protected:
bool IsInternal(const Address & ip) const;
private:
bool m_enable;
std::vector<NetworkAddress> m_networks;
};
bool ProxyRequired(const PIPSocket::Address & ip1, const PIPSocket::Address & ip2) const
{ return m_ProxyCriterion.Required(ip1, ip2); }
// Since PStringToString is not thread-safe,
// I write this small class to replace that
class RewriteData {
public:
RewriteData(PConfig *, const PString &);
~RewriteData();
PINDEX Size() const { return m_size; }
const PString & Key(PINDEX i) const { return m_RewriteKey[i]; }
const PString & Value(PINDEX i) const { return m_RewriteValue[i]; }
private:
PString *m_RewriteKey, *m_RewriteValue;
PINDEX m_size;
};
class RewriteTool {
public:
RewriteTool() : m_Rewrite(0) {}
~RewriteTool() { delete m_Rewrite; }
void LoadConfig(PConfig *);
bool RewritePString(PString &) const;
private:
PString m_RewriteFastmatch;
char m_TrailingChar;
RewriteData *m_Rewrite;
};
/// maybe modifies #alias#. returns true if it did
bool RewriteE164(H225_AliasAddress & alias);
bool RewriteE164(H225_ArrayOf_AliasAddress & aliases);
bool RewritePString(PString & s) { return m_Rewrite.RewritePString(s); }
// Class to allow correct use of STL inside PDictionary type
class GWRewriteEntry : public PObject {
PCLASSINFO(GWRewriteEntry, PObject);
public:
std::pair<std::vector<std::pair<PString,PString> >,std::vector<std::pair<PString,PString> > > m_entry_data;
};
// per GW RewriteTool
class GWRewriteTool {
public:
GWRewriteTool() {
m_GWRewrite.AllowDeleteObjects(false);
}
~GWRewriteTool();
void LoadConfig(PConfig *);
void PrintData();
bool RewritePString(PString gw, bool direction, PString &data);
private:
PDictionary<PString, GWRewriteEntry> m_GWRewrite;
};
// Equivalent functions to RewriteE164 group
bool GWRewriteE164(PString gw, bool direction, H225_AliasAddress &alias);
bool GWRewriteE164(PString gw, bool direction, H225_ArrayOf_AliasAddress &aliases);
bool GWRewritePString(PString gw, bool direction, PString &data) { return m_GWRewrite.RewritePString(gw,direction,data); }
PString GetGKHome(std::vector<PIPSocket::Address> &) const;
void SetGKHome(const PStringArray &);
// accessors
/** Accessor and 'Factory' to the static Toolkit.
* If you want to use your own Toolkit class you have to
* overwrite this method and ensure that your version is
* called first -- before any other call to #Toolkit::Instance#.
* Example:
* <pre>
* class MyToolkit: public Toolkit {
* public:
* static Toolkit& Instance() {
* if (m_Instance == NULL) m_Instance = new MyToolkit();
* return m_Instance;
* }
* };
* void main() {
* MyToolkit::Instance();
* }
* </pre>
*/
/** Accessor and 'Factory' for the global (static) configuration.
* With this we are able to implement out own Config-Loader
* in the same way as #Instance()#. And we can use #Config()#
* in the constructor of #Toolkit# (and its descentants).
*/
PConfig* Config();
PConfig* Config(const char *);
/** Sets the config that the toolkit uses to a given config.
* A prior loaded Config is discarded.
*/
PConfig* SetConfig(const PFilePath &fp, const PString §ion);
/* This method modifies the config from status port
* Warning: don't modify the config via status port and change config file simultaneously,
* or the config file may be messed up.
*/
void SetConfig(int act, const PString & sec, const PString & key = PString::Empty(), const PString & value = PString::Empty());
PConfig* ReloadConfig();
/// reads name of the running instance from config
static const PString & GKName();
/// returns an identification of the binary
static const PString GKVersion();
/** simplify PString regex matching.
* @param str String that should match the regex
* @param regexStr the string which is compiled to a regex and executed with #regex.Execute(str, pos)#
* @return TRUE if the regex matched and FALSE if not or any error case.
*/
static BOOL MatchRegex(const PString &str, const PString ®exStr);
/** returns the #BOOL# that #str# represents.
* Case insensitive, "t...", "y...", "a...", "1" are #TRUE#, all other values are #FALSE#.
*/
static bool AsBool(const PString & str);
/** Convert a string to a time interval. The string should be formatted like:
"1d5h" (1 day and 5 hours) or "20s" (20 seconds) or "1h" (1 hour)
or "2000" (2000 milliseconds) or ...
General format is a sequence of number and unit specifier pairs.
Recognized unit specifiers:
y - years
M - months
w - weeks
d - days
h - hours
m - minutes
s - seconds
"empty" - milliseconds
@return
true if the input string contained properly formatted time interval,
false if no conversion has been made
*/
static bool AsTimeInterval(
/// formatted time interval string
const char* inputString,
/// variable to store calculated time interval on success
PTimeInterval& interval
);
static void GetNetworkFromString(const PString &, PIPSocket::Address &, PIPSocket::Address &);
static PString CypherDecode(const PString &, const PString &, int);
/** you may add more extension codes in descendant classes. This codes will not be transferred
* or something it will be the return code of some methods for handling switches easy. */
enum {
iecUnknown = -1, /// internal extension code for an unknown triple(cntry,ext,manuf)
iecFailoverRAS = 1, /// i.e.c. for "This RQ is a failover RQ" and must not be answerd.
iecUserbase = 1000 /// first guaranteed unused 'iec' by GnuGK Toolkit.
};
/** t35 extension or definitions as field for H225_NonStandardIdentifier */
enum {
t35cOpenOrg = 255, /// country code for the "Open Source Organisation" Country
t35mOpenOrg = 4242, /// manufacurers code for the "Open Source Organisation"
t35eFailoverRAS = 255 /// Defined HERE!
};
/** If the triple #(country,extension,manufacturer)# represents an
* extension known to the GnuGK this method returns its 'internal extension code'
# #iecXXX' or #iecUnknow# otherwise.
*
* Overwriting methods should use a simlilar scheme and call
* <code>
* if(inherited::GnuGKExtension(country,extension,menufacturer) == iecUnknown) {
* ...
* (handle own cases)
* ...
* }
* </code>
* This results in 'cascading' calls until a iec!=iecUnkown is returned.
*/
virtual int GetInternalExtensionCode(const unsigned &country,
const unsigned &extension,
const unsigned &manufacturer) const;
int GetInternalExtensionCode(const H225_H221NonStandard& data) const;
/** A c-string (#char*#) hash function that considers the
* whole string #name# ending with #\0#.
*/
inline static unsigned long HashCStr(const unsigned char *name) ;
/** Generate a call id for accounting purposes, that is unique
during subsequent GK start/stop events.
@return
A string with the unique id.
*/
PString GenerateAcctSessionId();
/** @return
A path to a temp directory.
*/
PString GetTempDir() const;
/** @return
A pointer to the GkTimerManager object that allows registration
of time scheduled events.
*/
GkTimerManager* GetTimerManager() const { return m_timerManager; }
/** Convert the timestamp into a string according to the passed
format string or (if it is an empty string) to the default format string.
The format string conforms to strftime formatting rules or can be a one
of predefined constants: Cisco, ISO8601, RFC822, MySQL.
@return Formatted timestamp string.
*/
PString AsString(
const PTime& tm, /// timestamp to convert into a string
const PString& formatStr = PString() /// format string to use
);
/** Read and decrypt a password from the config. As a decryption key
this function is using the given key name padded with bytes of value
specified by the 'KeyFilled' config variable, if it is found
in the given config section, or a global padding byte.
@return
A decrypted password or an empty string, if the given key is missing.
*/
PString ReadPassword(
const PString &cfgSection, /// config section to read
const PString &cfgKey, /// config key to read an encrypted password from
bool forceEncrypted = false /// decrypt even if no KeyFilled is present
);
/// Inbound rewrite for ANI/CLI
void RewriteCLI(
SetupMsg &msg /// Q.931 Setup message to be rewritten
) const;
/// Outbound rewrite for ANI/CLI
void RewriteCLI(
SetupMsg &msg, /// Q.931 Setup message to be rewritten
SetupAuthData &authData, /// additional data
const PIPSocket::Address &destAddr /// callee's IP
) const;
void SetRerouteCauses(
unsigned char *causeMap
);
protected:
void CreateConfig();
void ReloadSQLConfig();
void LoadCauseMap(PConfig *cfg);
PFilePath m_ConfigFilePath;
PFilePath m_extConfigFilePath;
PString m_GKName;
PString m_ConfigDefaultSection;
PConfig* m_Config;
bool m_ConfigDirty;
RewriteTool m_Rewrite;
GWRewriteTool m_GWRewrite; // GW Based RewriteTool
RouteTable m_RouteTable;
VirtualRouteTable m_VirtualRouteTable;
ProxyCriterion m_ProxyCriterion;
std::vector<PIPSocket::Address> m_GKHome;
/// a counter incremented for each generated session id
long m_acctSessionCounter;
/// base part for session id, changed with every GK restart
long m_acctSessionBase;
/// mutex for atomic session id generation (prevents from duplicates)
PMutex m_acctSessionMutex;
private:
PFilePath m_tmpconfig;
/// global manager for time-based events
GkTimerManager* m_timerManager;
/// a default timestamp format string
PString m_timestampFormatStr;
/// a padding byte used during config passwords decryption
int m_encKeyPaddingByte;
/// if true, all passwords in the config are encrypted
bool m_encryptAllPasswords;
/// set of ANI/CLI rewrite rules
CLIRewrite *m_cliRewrite;
/// bit flag failover triggers for 128 Q931 causes
unsigned char m_causeMap[16];
};
inline unsigned long
Toolkit::HashCStr(const unsigned char *name)
{
register unsigned long h = 0, g;
while (*name) {
h = (h << 4) + *name++;
if ( (g = (h & 0xf0000000)) ) h ^= g >> 24;
h &= ~g;
}
return h;
}
inline PConfig *GkConfig()
{
return Toolkit::Instance()->Config();
}
inline PConfig *GkConfig(const char *section)
{
return Toolkit::Instance()->Config(section);
}
inline const PString & Toolkit::GKName()
{
return Toolkit::Instance()->m_GKName;
}
#endif // TOOLKIT_H
syntax highlighted by Code2HTML, v. 0.9.1