//////////////////////////////////////////////////////////////////
//
// bookkeeping for RAS-Server in H.323 gatekeeper
//
// 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:
// 990500 initial version (Xiang Ping Chen, Rajat Todi, Joe Metzger)
// 990600 ported to OpenH323 V. 1.08 (Jan Willamowius)
// 991003 switched to STL (Jan Willamowius)
//
//////////////////////////////////////////////////////////////////
#ifndef RASTBL_H
#define RASTBL_H "@(#) $Id: RasTbl.h,v 1.97 2006/06/12 13:26:43 zvision Exp $"
#include <list>
#include <vector>
#include <string>
#include "rwlock.h"
#include "singleton.h"
#include "h225.h"
#include "sigmsg.h"
#include "h323util.h"
#include "pwlib_compat.h"
#if (_MSC_VER >= 1200)
#pragma warning( disable : 4786 ) // warning about too long debug symbol off
#pragma warning( disable : 4800 )
#endif
namespace Routing {
struct Route;
}
class GkDestAnalysisList;
class USocket;
class CallSignalSocket;
class RasServer;
class Q931;
class SignalingMsg;
template <class> class H225SignalingMsg;
typedef H225SignalingMsg<H225_Setup_UUIE> SetupMsg;
// Template of smart pointer
// The class T must have Lock() & Unlock() methods
template<class T> class SmartPtr {
public:
explicit SmartPtr(T *t = 0) : pt(t) { Inc(); }
SmartPtr(const SmartPtr<T> & p) : pt(p.pt) { Inc(); }
~SmartPtr() { Dec(); }
operator bool() const { return pt != 0; }
T *operator->() const { return pt; }
bool operator==(const SmartPtr<T> & p) const { return pt == p.pt; }
bool operator!=(const SmartPtr<T> & p) const { return pt != p.pt; }
SmartPtr<T> &operator=(const SmartPtr<T> & p) {
if (pt != p.pt)
Dec(), pt = p.pt, Inc();
return *this;
}
private:
void Inc() const { if (pt) pt->Lock(); }
void Dec() const { if (pt) pt->Unlock(); }
T &operator*();
T *pt;
};
class EndpointRec
{
public:
/** Construct internal/outer zone endpoint from the specified RAS message.
RRQ builds an internal zone endpoint, ARQ, ACF and LCF build outer zone
endpoints.
*/
EndpointRec(
/// RRQ, ARQ, ACF or LCF that contains a description of the endpoint
const H225_RasMessage& ras,
/// permanent endpoint flag
bool permanent = false
);
virtual ~EndpointRec();
// public interface to access EndpointRec
H225_TransportAddress GetRasAddress() const;
H225_TransportAddress GetCallSignalAddress() const;
H225_EndpointIdentifier GetEndpointIdentifier() const;
H225_ArrayOf_AliasAddress GetAliases() const;
H225_EndpointType GetEndpointType() const;
int GetTimeToLive() const;
PIPSocket::Address GetNATIP() const;
CallSignalSocket *GetSocket();
int GetCallTypeOfNumber(bool called = true) const { return called ? m_calledTypeOfNumber : m_callingTypeOfNumber; }
unsigned GetProxyType() const { return m_proxy; }
/** checks if the given aliases are prefixes of the aliases which are stored
for the endpoint in the registration table. #fullMatch# returns #TRUE# if
a full match is found.
@returns #TRUE# if a match is found
*/
bool PrefixMatch_IncompleteAddress(const H225_ArrayOf_AliasAddress &aliases,
bool &fullMatch) const;
virtual void SetRasAddress(const H225_TransportAddress &);
virtual void SetEndpointIdentifier(const H225_EndpointIdentifier &);
virtual void SetTimeToLive(int);
virtual void SetAliases(const H225_ArrayOf_AliasAddress &);
virtual void SetEndpointType(const H225_EndpointType &);
virtual void Update(const H225_RasMessage & lightweightRRQ);
virtual bool IsGateway() const { return false; }
/** Find if one of the given aliases matches any alias for this endpoint.
@return
true if the match has been found, false otherwise.
*/
virtual bool CompareAlias(
/// aliases to be matched (one of them)
const H225_ArrayOf_AliasAddress* aliases
) const;
/** Find if one of the given aliases matches any alias for this endpoint
and return an index for the matching alias.
@return
true if the match has been found, false otherwise.
*/
virtual bool MatchAlias(
/// aliases to be matched (one of them)
const H225_ArrayOf_AliasAddress& aliases,
/// filled with an index into aliases for the matching alias (if found)
int& matchedalias
) const;
/** Load additional endpoint settings from the config file.
Derived classes should call LoadConfig method of their base class
at the beginning of the overriden LoadConfig.
@return
True if the configuration has been updated successfully.
*/
virtual bool LoadConfig();
virtual EndpointRec *Unregister();
virtual EndpointRec *Expired();
//virtual void BuildACF(H225_AdmissionConfirm &) const;
//virtual void BuildLCF(H225_LocationConfirm &) const;
virtual PString PrintOn(bool verbose) const;
void SetNAT(bool nat);
void SetNATAddress(const PIPSocket::Address &);
void SetSocket(CallSignalSocket *);
/** @return
true if this is a permanent endpoint loaded from the config file entry.
*/
bool IsPermanent() const;
bool IsUsed() const;
bool IsUpdated(const PTime *) const;
bool IsFromParent() const;
bool IsNATed() const;
bool HasNATSocket() const;
PTime GetUpdatedTime() const;
/** If this Endpoint would be register itself again with all the same data
* how would this RRQ would look like? May be implemented with a
* built-together-RRQ, but for the moment a stored RRQ.
*/
H225_RasMessage GetCompleteRegistrationRequest() const;
void AddCall();
void AddConnectedCall();
void RemoveCall();
void Lock();
void Unlock();
bool SendIRQ();
bool HasCallCreditCapabilities() const;
/** Append a call credit related service control descriptor to the array
of service control sessions, if the endpoint supports call credit
capabilities.
*/
virtual void AddCallCreditServiceControl(
H225_ArrayOf_ServiceControlSession& sessions, /// array to add the service control descriptor to
const PString& amountStr, /// user's account balance amount string
int billingMode, /// user's account billing mode (-1 if not set)
long callDurationLimit /// call duration limit (-1 if not set)
);
/** @return
Maximum call capacity for this endpoint. -1 if there is not capacity
limit set.
*/
int GetCapacity() const { return m_capacity; }
/** Set maximum number of concurrent calls this endpoint can handle.
Pass -1 to disable the limit.
*/
void SetCapacity(
int newCapacity /// max number of concurrent calls, -1 means no limit
);
/** @return
True if the endpoint can handle at least one more concurrent call.
*/
bool HasAvailableCapacity() const { return m_capacity == -1 || m_activeCall < m_capacity; }
// smart pointer for EndpointRec
typedef SmartPtr<EndpointRec> Ptr;
protected:
void SetEndpointRec(H225_RegistrationRequest &);
void SetEndpointRec(H225_AdmissionRequest &);
void SetEndpointRec(H225_AdmissionConfirm &);
void SetEndpointRec(H225_LocationConfirm &);
bool SendURQ(H225_UnregRequestReason::Choices);
private:
/// Load general endpoint settings from the config
void LoadEndpointConfig();
EndpointRec();
EndpointRec(const EndpointRec &);
EndpointRec & operator= (const EndpointRec &);
protected:
/**This field may disappear sometime when GetCompleteRegistrationRequest() can
* build its return value itself.
* @see GetCompleteRegistrationRequest()
*/
H225_RasMessage m_RasMsg;
H225_TransportAddress m_rasAddress;
H225_TransportAddress m_callSignalAddress;
H225_EndpointIdentifier m_endpointIdentifier;
H225_ArrayOf_AliasAddress m_terminalAliases;
H225_EndpointType *m_terminalType;
int m_timeToLive; // seconds
int m_activeCall, m_connectedCall, m_totalCall;
int m_pollCount, m_usedCount;
mutable PMutex m_usedLock;
PTime m_updatedTime;
bool m_fromParent, m_nat;
PIPSocket::Address m_natip;
CallSignalSocket *m_natsocket;
/// permanent (preconfigured) endpoint flag
bool m_permanent;
/// can understand H.225 CallCreditServiceControl
bool m_hasCallCreditCapabilities;
/// session number for call credit service control session
int m_callCreditSession;
/// endpoint call capacity, -1 means no limit
int m_capacity;
int m_calledTypeOfNumber, m_callingTypeOfNumber;
unsigned m_proxy;
};
typedef EndpointRec::Ptr endptr;
class GatewayRec : public EndpointRec {
public:
typedef std::vector<std::string>::iterator prefix_iterator;
typedef std::vector<std::string>::const_iterator const_prefix_iterator;
GatewayRec(const H225_RasMessage & completeRAS, bool Permanent=false);
virtual void SetEndpointType(const H225_EndpointType &);
virtual void Update(const H225_RasMessage & lightweightRRQ);
virtual bool IsGateway() const { return true; }
/// Overiden from EndpointRec
virtual bool LoadConfig();
/** Find if at least one of the given aliases matches any prefix
for this gateway.
@return
Length (number of characters) of the match, 0 if no match has been
found and this is the default gateway, -1 if no match has been found
and this is not the default gateway.
*/
virtual int PrefixMatch(
/// aliases to be matched (one of them)
const H225_ArrayOf_AliasAddress& aliases
) const;
/** Find if at least one of the given aliases matches any prefix
for this gateway and return an index of the matched alias.
@return
Length (number of characters) of the match, 0 if no match has been
found and this is the default gateway, -1 if no match has been found
and this is not the default gateway.
*/
virtual int PrefixMatch(
/// aliases to be matched (one of them)
const H225_ArrayOf_AliasAddress& aliases,
/// filled with an index of the matching alias (if found)
int& matchedalias
) const;
//virtual void BuildLCF(H225_LocationConfirm &) const;
virtual PString PrintOn(bool verbose) const;
void AddPrefixes(const H225_ArrayOf_SupportedProtocols &);
void AddPrefixes(const PString &);
void SortPrefixes();
/** @return
Priority for this gateway, when more than one gateway matches
a dialed number.
*/
int GetPriority() const { return priority; }
/// Set the priority for this gateway.
void SetPriority(
int newPriority
);
private:
/// Load gateway specific settings from the config
void LoadGatewayConfig();
GatewayRec();
GatewayRec(const GatewayRec&);
GatewayRec& operator=(const GatewayRec&);
protected:
// strange! can't compile in debug mode, anybody know why??
//vector<PString> Prefixes;
std::vector<std::string> Prefixes;
bool defaultGW;
/// priority for this gateway (when more than one gw matches a dialed number)
int priority;
};
class OuterZoneEPRec : public EndpointRec {
public:
OuterZoneEPRec(const H225_RasMessage & completeRAS, const H225_EndpointIdentifier &);
virtual EndpointRec *Unregister() { return this; }
virtual EndpointRec *Expired() { return this; }
};
class OuterZoneGWRec : public GatewayRec {
public:
OuterZoneGWRec(const H225_RasMessage & completeRAS, const H225_EndpointIdentifier &);
virtual EndpointRec *Unregister() { return this; }
virtual EndpointRec *Expired() { return this; }
};
class RegistrationTable : public Singleton<RegistrationTable> {
public:
typedef std::list<EndpointRec *>::iterator iterator;
typedef std::list<EndpointRec *>::const_iterator const_iterator;
RegistrationTable();
~RegistrationTable();
void Initialize(GkDestAnalysisList & list) { m_destAnalysisList = &list; }
endptr InsertRec(H225_RasMessage & rrq, PIPSocket::Address = INADDR_ANY);
void RemoveByEndptr(const endptr & eptr);
void RemoveByEndpointId(const H225_EndpointIdentifier & endpointId);
endptr FindByEndpointId(const H225_EndpointIdentifier & endpointId) const;
endptr FindBySignalAdr(const H225_TransportAddress &, PIPSocket::Address = INADDR_ANY) const;
endptr FindOZEPBySignalAdr(const H225_TransportAddress &) const;
endptr FindByAliases(const H225_ArrayOf_AliasAddress & alias) const;
endptr FindEndpoint(const H225_ArrayOf_AliasAddress & alias, bool RoundRobin, bool SearchOuterZone = true);
endptr FindEndpoint(const H225_ArrayOf_AliasAddress & alias, bool RoundRobin, bool SearchOuterZone, const list<H225_TransportAddress> & ignoreList);
void FindEndpoint(
const H225_ArrayOf_AliasAddress &aliases,
bool roundRobin,
bool searchOuterZone,
std::list<Routing::Route> &routes
);
void ClearTable();
void CheckEndpoints();
void PrintAllRegistrations(USocket *client, BOOL verbose=FALSE);
void PrintAllCached(USocket *client, BOOL verbose=FALSE);
void PrintRemoved(USocket *client, BOOL verbose=FALSE);
PString PrintStatistics() const;
// void PrintOn( ostream &strm ) const;
/** Updates Prefix + Flags for all aliases */
void LoadConfig();
PINDEX Size() const { return regSize; }
public:
enum enumGatewayFlags {
e_SCNType // "trunk" or "residential"
};
private:
endptr InternalInsertEP(H225_RasMessage &);
endptr InternalInsertOZEP(H225_RasMessage &, H225_LocationConfirm &);
endptr InternalInsertOZEP(H225_RasMessage &, H225_AdmissionConfirm &);
void InternalPrint(USocket *, BOOL, std::list<EndpointRec *> *, PString &);
void InternalStatistics(const std::list<EndpointRec *> *, unsigned & s, unsigned & t, unsigned & g, unsigned & n) const;
void InternalRemove(iterator);
template<class F> endptr InternalFind(const F & FindObject) const
{ return InternalFind(FindObject, &EndpointList); }
template<class F> endptr InternalFind(const F & FindObject, const std::list<EndpointRec *> *ListToBeFound) const
{ // The function body must be put here,
// or the Stupid VC would fail to instantiate it
ReadLock lock(listLock);
const_iterator Iter(find_if(ListToBeFound->begin(), ListToBeFound->end(), FindObject));
return endptr((Iter != ListToBeFound->end()) ? *Iter : 0);
}
endptr InternalFindEP(const H225_ArrayOf_AliasAddress & alias, std::list<EndpointRec *> *ListToBeFound, bool roundrobin, const list<H225_TransportAddress> & ignoreList);
void InternalFindEP(const H225_ArrayOf_AliasAddress & alias, std::list<EndpointRec *> *ListToBeFound, bool roundrobin, list<Routing::Route> &routes);
void GenerateEndpointId(H225_EndpointIdentifier &);
void GenerateAlias(H225_ArrayOf_AliasAddress &, const H225_EndpointIdentifier &) const;
GkDestAnalysisList & getGkDestAnalysisList() { return *m_destAnalysisList; }
std::list<EndpointRec *> EndpointList;
std::list<EndpointRec *> OuterZoneList;
std::list<EndpointRec *> RemovedList;
int regSize;
mutable PReadWriteMutex listLock;
GkDestAnalysisList * m_destAnalysisList;
// counter to generate endpoint identifier
// this is NOT the count of endpoints!
int recCnt, ozCnt;
PString endpointIdSuffix; // Suffix of the generated Endpoint IDs
// not assignable
RegistrationTable(const RegistrationTable &);
RegistrationTable& operator=(const RegistrationTable &);
};
template<class> class RasPDU;
// record of one active call
class CallRec {
public:
/// flag to overwrite proxy settings for the call
enum ProxyMode {
ProxyDetect, /// use global settings from the config
ProxyEnabled, /// force full proxy mode
ProxyDisabled /// disable full proxy mode
};
/// who disconnected the call
enum ReleaseSource {
ReleasedByGatekeeper,
ReleasedByCaller,
ReleasedByCallee
};
/// build a new call record from the received ARQ message
CallRec(
/// ARQ with call information
const RasPDU<H225_AdmissionRequest>& arq,
/// bandwidth occupied by the call
int bandwidth,
/// called party's aliases in a string form
const PString& destInfo,
/// override proxy mode global setting from the config
int proxyMode = ProxyDetect
);
/// build a new call record from the received Setup message
CallRec(
/// Q.931 Setup pdu with call information
const Q931& q931pdu,
/// H.225.0 Setup-UUIE pdu with call information
const H225_Setup_UUIE& setup,
/// force H.245 routed mode
bool routeH245,
/// called party's aliases in a string form
const PString& destInfo,
/// override proxy mode global setting from the config
int proxyMode = ProxyDetect
);
CallRec(
CallRec *oldCall
);
virtual ~CallRec();
enum NATType { // who is nated?
none = 0,
callingParty = 1,
calledParty = 2,
both = 3,
citronNAT = 4 // caller with Citron NAT Technology?
};
PINDEX GetCallNumber() const
{ return m_CallNumber; }
const H225_CallIdentifier & GetCallIdentifier() const
{ return m_callIdentifier; }
const H225_ConferenceIdentifier & GetConferenceIdentifier() const
{ return m_conferenceIdentifier; }
endptr GetCallingParty() const { return m_Calling; }
endptr GetCalledParty() const { return m_Called; }
endptr GetForwarder() const { return m_Forwarder; }
int GetBandwidth() const { return m_bandwidth; }
/** @return
A bit mask with NAT flags for calling and called parties.
See #NATType enum# for more details.
*/
int GetNATType() const { return m_nattype; }
int GetNATType(
/// filled with NAT IP of the calling party (if nat type is callingParty)
PIPSocket::Address& callingPartyNATIP,
/// filled with NAT IP of the called party (if nat type is calledParty)
PIPSocket::Address& calledPartyNATIP
) const;
/** @return
Current proxy mode flag (see #ProxyMode enum#).
*/
int GetProxyMode() const { return m_proxyMode; }
/// Override proxy mode global setting from the config
void SetProxyMode(
int mode /// proxy mode flag (see #ProxyMode enum#)
);
CallSignalSocket *GetCallSignalSocketCalled() { return m_calledSocket; }
CallSignalSocket *GetCallSignalSocketCalling() { return m_callingSocket; }
const H225_ArrayOf_CryptoH323Token & GetAccessTokens() const { return m_accessTokens; }
PString GetInboundRewriteId() const { return m_inbound_rewrite_id; }
PString GetOutboundRewriteId() const { return m_outbound_rewrite_id; }
void SetCallNumber(PINDEX i) { m_CallNumber = i; }
void SetCalling(const endptr & NewCalling);
void SetCalled(const endptr & NewCalled);
void SetForward(CallSignalSocket *, const H225_TransportAddress &, const endptr &, const PString &, const PString &);
void SetBandwidth(int bandwidth) { m_bandwidth = bandwidth; }
void SetSocket(CallSignalSocket *, CallSignalSocket *);
void SetCallSignalSocketCalling(CallSignalSocket* socket);
void SetCallSignalSocketCalled(CallSignalSocket* socket);
void SetToParent(bool toParent) { m_toParent = toParent; }
void SetAccessTokens(const H225_ArrayOf_CryptoH323Token & tokens) { m_accessTokens = tokens; }
void SetInboundRewriteId(PString id) { m_inbound_rewrite_id = id; }
void SetOutboundRewriteId(PString id) { m_outbound_rewrite_id = id; }
void SetConnected();
void Disconnect(bool = false); // Send Release Complete?
void RemoveAll();
void RemoveSocket();
void SendReleaseComplete(const H225_CallTerminationCause * = 0);
void BuildDRQ(H225_DisengageRequest &, unsigned reason) const;
int CountEndpoints() const;
bool CompareCallId(const H225_CallIdentifier *CallId) const;
bool CompareCRV(WORD crv) const;
bool CompareCallNumber(PINDEX CallNumber) const;
bool CompareEndpoint(const endptr *) const;
bool CompareSigAdr(const H225_TransportAddress *adr) const;
bool IsUsed() const { return (m_usedCount != 0); }
/** @return
true if the call has been connected - a Connect message
has been received in gk routed signalling or the call has been admitted
(ARQ->ACF) in direct signalling. Does not necessary mean
that the call is still in progress (may have been already disconnected).
*/
bool IsConnected() const { return (m_connectTime != 0); }
bool IsH245Routed() const { return m_h245Routed; }
bool IsToParent() const { return m_toParent; }
bool IsForwarded() const { return m_forwarded; }
bool IsSocketAttached() const { return (m_callingSocket != 0); }
PString GenerateCDR(
/// timestamp formatting string (empty for a default RFC822 format)
const PString& timestampFormat = PString()
) const;
PString PrintOn(bool verbose) const;
void Lock();
void Unlock();
/** @return
Q.931 ReleaseComplete cause code for the call.
0 if the disconnect cause could not be determined.
*/
unsigned GetDisconnectCause() const;
/** Set Q.931 ReleaseComplete cause code associated with this call. */
void SetDisconnectCause(
unsigned causeCode
);
/// @return Information about who disconnected the call (see #ReleaseSource enum#)
int GetReleaseSource() const;
/// Set information about who disconnected the call
void SetReleaseSource(
int releaseSentFrom /// see #ReleaseSource enum#
);
/** Set maximum duration limit (in seconds) for this call */
void SetDurationLimit(
long seconds /// duration limit to be set
);
/** @return
Duration limit (in seconds) set for this call.
0 if call duration is not limited.
*/
long GetDurationLimit() const;
/** This function can be used to determine, if the call has been
disconnected due to call duration limit excess.
@return
true if the call duration limit has been exceeded, false otherwise.
*/
bool IsDurationLimitExceeded() const;
/** @return
Timestamp (number of seconds since 1st January 1970) for the call creation
(when this CallRec object has been instantiated).
*/
time_t GetCreationTime() const;
/** @return
Timestamp (number of seconds since 1st January 1970)
for the Setup message associated with this call. 0 if Setup
has not been yet received.
Meaningful only in GK routed mode.
*/
time_t GetSetupTime() const;
/** Set timestamp for a Setup message associated with this call. */
void SetSetupTime(
time_t tm /// timestamp (seconds since 1st January 1970)
);
/** @return
Timestamp (number of seconds since 1st January 1970)
for the Alerting message associated with this call. 0 if Alerting
has not been yet received.
Meaningful only in GK routed mode.
*/
time_t GetAlertingTime() const;
/** Set timestamp for a Alerting message associated with this call. */
void SetAlertingTime(
time_t tm /// timestamp (seconds since 1st January 1970)
);
/** @return
Timestamp (number of seconds since 1st January 1970)
for the Connect message associated with this call. 0 if Connect
has not been yet received. If GK is not in routed mode, this is
timestamp for ACF generated as a response to ARQ.
*/
time_t GetConnectTime() const;
/** Set timestamp for a Connect (or ACF) message associated with this call. */
void SetConnectTime(
time_t tm /// timestamp (seconds since 1st January 1970)
);
/** @return
Timestamp (number of seconds since 1st January 1970)
for the call disconnect event. 0 if call has not been yet disconnected
or connected.
*/
time_t GetDisconnectTime() const;
/** Set timestamp for a disconnect event for this call. */
void SetDisconnectTime(
time_t tm /// timestamp (seconds since 1st January 1970)
);
/** @return
Timestamp for the most recent accounting update event logged for this call.
*/
time_t GetLastAcctUpdateTime() const { return m_acctUpdateTime; }
/** Set timestamp for the most recent accounting update event logged
for this call.
*/
void SetLastAcctUpdateTime(
const time_t tm /// timestamp of the recent accounting update operation
)
{
m_acctUpdateTime = tm;
}
/** Check if:
- a signalling channel associated with this call is not timed out
and the call should be disconnected (removed from CallTable);
- call duration limit has been exceeded
- call should be disconnected from other reason
@return
true if call is timed out and should be disconnected, false otherwise.
*/
bool IsTimeout(
/// point in time for timeouts to be measured relatively to
/// (made as a parameter for performance reasons)
const time_t now
) const;
/** @return
Call duration in seconds. 0 for unconnected calls. Actual
duration for calls in progress.
*/
long GetDuration() const;
/** @return
Call total time in seconds. 0 for calls without disconnect.
*/
long GetTotalCallDuration() const;
/** @return
Call Post Dial Delay in seconds.
*/
long GetPostDialDelay() const;
/** @return
Call ring time in seconds. 0 for calls without Alerting.
*/
long GetRingTime() const;
/** @return
A string that identifies uniquelly this call for accounting
purposes. This string should be unique across subsequent GK
start/stop events.
*/
PString GetAcctSessionId() const { return m_acctSessionId; }
/** @return
A string with ARQ.m_srcInfo for registered endpoints
and Setup.m_sourceAddress for unregistered endpoints.
The string has alias type appended (example: '772:dialedDigits')
and for forwarded calls contains alias of forwarding
after '=' (example: '772:dialedDigits=775:forward').
*/
PString GetSrcInfo() const { return m_srcInfo; }
/** Set a new address for the calling party signalling channel.
*/
void SetSrcSignalAddr(
const H225_TransportAddress & addr /// new signalling transport address
);
/** Set the unregistered calling party signalling channel as NATed.
*/
void SetSrcNATed(PIPSocket::Address & natip);
/** Set a new address for the called party signalling channel.
*/
void SetDestSignalAddr(
const H225_TransportAddress & addr /// new signalling transport address
);
/** Get IP and port for the calling party. It is a signal address
for registered endpoints and remote signalling socket address
for unregistered endpoints.
@return
true if the address has been retrieved successfully, false otherwise.
*/
bool GetSrcSignalAddr(
PIPSocket::Address& addr, /// will receive the IP address
WORD& port /// will receive the port number
) const;
H225_TransportAddress GetDestSignalAddr() const;
/** Get IP and port for the called party. It is a signal address
for registered endpoints and remote signalling socket address
for unregistered endpoints.
@return
true if the address has been retrieved successfully, false otherwise.
*/
bool GetDestSignalAddr(
PIPSocket::Address& addr, /// will receive the IP address
WORD& port /// will receive the port number
) const;
/** @return
A string with ARQ.m_destinationInfo or ARQ.m_destCallSignalAddress
or "unknown" for registered endpoints
and Setup.m_destinationAddress or called endpoint IP address
for unregistered endpoints.
The string has alias type appended (example: '772:dialedDigits')
and for forwarded calls contains alias of forwarding
after '=' (example: '772:dialedDigits=775:forward').
*/
PString GetDestInfo() const { return m_destInfo; }
/** @return
Calling party's aliases, as presented in ARQ or Setup messages.
This does not change during the call.
*/
const H225_ArrayOf_AliasAddress& GetSourceAddress() const
{ return m_sourceAddress; }
/** @return
Called party's aliases, as presented in ARQ or Setup messages.
This does not change during the call now, but should be fixed
to handle gatekeeper call forwarding properly.
*/
const H225_ArrayOf_AliasAddress& GetDestinationAddress() const
{ return m_destinationAddress; }
/** @return
Calling party's number or an empty string, if the number has not been
yet determined.
*/
PString GetCallingStationId();
/// Set calling party's number
void SetCallingStationId(
const PString& id /// Calling-Station-Id
);
/** @return
Called party's number or an empty string, if the number has not been
yet determined.
*/
PString GetCalledStationId();
/// Set calling party's number
void SetCalledStationId(
const PString& id /// Called-Station-Id
);
/** @return
Called party's number before rewrite or an empty string,
if the number has not been yet determined.
*/
PString GetDialedNumber();
/// Set dialed number
void SetDialedNumber(
const PString& number /// Dialed-Number
);
/** @return
Fixed destination address for the call (NULL if not set).
*/
H225_AliasAddress* GetRouteToAlias() const;
/// Set fixed destination address for the call
void SetRouteToAlias(
const H225_AliasAddress& alias /// alias to set
);
// smart pointer for CallRec
typedef SmartPtr<CallRec> Ptr;
/// update IRR timers
void Update(const H225_InfoRequestResponse & irr);
void SetNewRoutes(
const std::list<Routing::Route> &routes
);
void SetFailedRoutes(
const std::list<Routing::Route> &routes
);
const std::list<Routing::Route> &GetNewRoutes() const { return m_newRoutes; }
const std::list<Routing::Route> &GetFailedRoutes() const { return m_failedRoutes; }
bool MoveToNextRoute();
bool IsCallInProgress() const;
void SetCallInProgress();
bool IsH245ResponseReceived() const;
void SetH245ResponseReceived();
bool IsFastStartResponseReceived() const;
void SetFastStartResponseReceived();
bool SingleFailoverCDR() const;
int GetNoCallAttempts() const;
int GetNoRemainingRoutes() const;
void SetCodec(const PString &codec);
PString GetCodec() const;
void SetMediaOriginatingIp(const PIPSocket::Address &addr);
bool GetMediaOriginatingIp(PIPSocket::Address &addr) const;
private:
void SendDRQ();
void InternalSetEP(endptr &, const endptr &);
CallRec(const CallRec & Other);
CallRec & operator= (const CallRec & other);
private:
/// internal call number generated by the gatekeeper
PINDEX m_CallNumber;
/// H.323 Call Identifier (identifies this particular call leg)
H225_CallIdentifier m_callIdentifier;
/// H.323 Conference Identifier
H225_ConferenceIdentifier m_conferenceIdentifier;
/// Call Reference Value for the call
WORD m_crv;
/// EndpointRec for the calling party (if it is a registered endpoint)
/// NOTE: it does not change during CallRec lifetime
endptr m_Calling;
/// EndpointRec for the called party (if it is a registered endpoint)
/// NOTE: it can change during CallRec lifetime
endptr m_Called;
/// aliases identifying a calling party (as presented in ARQ or Setup)
H225_ArrayOf_AliasAddress m_sourceAddress;
/// aliases identifying a called party (as presented in ARQ or Setup)
H225_ArrayOf_AliasAddress m_destinationAddress;
/// calling party aliases in a string form
PString m_srcInfo;
/// called party aliases in a string form
PString m_destInfo;
/// bandwidth occupied by this call (as declared in ARQ)
int m_bandwidth;
PString m_callerAddr, m_callerId;
PString m_calleeAddr, m_calleeId;
// rewrite id for inbound leg of call
PString m_inbound_rewrite_id;
// rewrite id for outbound leg of call
PString m_outbound_rewrite_id;
/// current timeout (or duration limit) for the call
long m_timeout;
/// timestamp for call timeout measuring
time_t m_timer;
/// timestamp (seconds since 1st January, 1970) for the call creation
/// (triggered by ARQ or Setup)
time_t m_creationTime;
/// timestamp (seconds since 1st January, 1970) for a Setup message reception
time_t m_setupTime;
/// timestamp (seconds since 1st January, 1970) for a Alerting message reception
time_t m_alertingTime;
/// timestamp (seconds since 1st January, 1970) for a Connect (routed mode)
/// or ARQ/ACF (direct mode) message reception
time_t m_connectTime;
/// timestamp (seconds since 1st January, 1970) for the call disconnect
time_t m_disconnectTime;
/// timestamp for the most recent accounting update event logged for this call
time_t m_acctUpdateTime;
/// duration limit (seconds) for this call, 0 means no limit
long m_durationLimit;
/// Q.931 release complete cause code
unsigned m_disconnectCause;
/// who disconnected the call (see #RelaseSource enum#)
int m_releaseSource;
/// unique accounting session id associated with this call
PString m_acctSessionId;
/// signalling transport address of the calling party
H225_TransportAddress m_srcSignalAddress;
/// signalling transport address of the called party
H225_TransportAddress m_destSignalAddress;
/// calling party's number
PString m_callingStationId;
/// called party's number
PString m_calledStationId;
/// dialed number (called party's number before rewrite)
PString m_dialedNumber;
/// fixed destination alias
H225_AliasAddress* m_routeToAlias;
CallSignalSocket *m_callingSocket, *m_calledSocket;
int m_usedCount;
mutable PTimedMutex m_usedLock, m_sockLock;
int m_nattype;
/// unregistered caller NAT'd
bool m_unregNAT;
PIPSocket::Address m_srcunregNATAddress;
bool m_h245Routed;
/// the call is routed to this gatekeeper's parent gatekeeper
bool m_toParent;
bool m_forwarded;
endptr m_Forwarder;
/// enable/disable proxy mode (override global settings from the config)
int m_proxyMode;
H225_ArrayOf_CryptoH323Token m_accessTokens;
/// IRR checking
long m_irrFrequency;
bool m_irrCheck;
time_t m_irrCallerTimer;
time_t m_irrCalleeTimer;
std::list<Routing::Route> m_failedRoutes;
std::list<Routing::Route> m_newRoutes;
bool m_callInProgress;
bool m_h245ResponseReceived;
bool m_fastStartResponseReceived;
bool m_singleFailoverCDR;
PString m_codec;
PIPSocket::Address m_mediaOriginatingIp;
};
typedef CallRec::Ptr callptr;
// all active calls
class CallTable : public Singleton<CallTable>
{
public:
typedef std::list<CallRec *>::iterator iterator;
typedef std::list<CallRec *>::const_iterator const_iterator;
CallTable();
~CallTable();
void Insert(CallRec * NewRec);
// bandwidth management
void SetTotalBandwidth(int bw);
bool GetAdmission(int bw);
bool GetAdmission(int bw, const callptr &);
int GetAvailableBW() const { return m_capacity; }
callptr FindCallRec(const H225_CallIdentifier & CallId) const;
callptr FindCallRec(const H225_CallReferenceValue & CallRef) const;
callptr FindCallRec(PINDEX CallNumber) const;
callptr FindCallRec(const endptr &) const;
callptr FindBySignalAdr(const H225_TransportAddress & SignalAdr) const;
void ClearTable();
void CheckCalls(
RasServer* rassrv // to avoid call RasServer::Instance every second
);
void RemoveCall(const H225_DisengageRequest & obj_drq, const endptr &);
void RemoveCall(const callptr &);
void RemoveFailedLeg(const callptr &);
void PrintCurrentCalls(USocket *client, BOOL verbose=FALSE) const;
PString PrintStatistics() const;
void AddForwardedCall(const callptr &);
endptr IsForwardedCall(const callptr &);
void LoadConfig();
PINDEX Size() const { return m_activeCall; }
/** @return
Timeout value for a signalling channel to be opened after ACF
and for an Alerting message to be received after signalling start.
The value is expressed in milliseconds.
*/
long GetSignalTimeout() const { return m_signalTimeout; }
/** @return
Timeout value for Connect message to be received after a call entered
the Alerting state. The value is expressed in milliseconds.
*/
long GetAlertingTimeout() const { return m_alertingTimeout; }
/** @return
Default call duration limit value (seconds).
*/
long GetDefaultDurationLimit() const { return m_defaultDurationLimit; }
/// @return True to log accounting for each call leg
bool SingleFailoverCDR() const { return m_singleFailoverCDR; }
private:
template<class F> callptr InternalFind(const F & FindObject) const
{
ReadLock lock(listLock);
const_iterator Iter(find_if(CallList.begin(), CallList.end(), FindObject));
return callptr((Iter != CallList.end()) ? *Iter : 0);
}
bool InternalRemovePtr(CallRec *call);
void InternalRemove(const H225_CallIdentifier & CallId);
void InternalRemove(WORD CallRef);
void InternalRemove(iterator);
void InternalRemoveFailedLeg(iterator);
void InternalStatistics(unsigned & n, unsigned & act, unsigned & nb, unsigned & np, PString & msg, BOOL verbose) const;
std::list<CallRec *> CallList;
std::list<CallRec *> RemovedList;
bool m_genNBCDR;
bool m_genUCCDR;
PINDEX m_CallNumber;
mutable PReadWriteMutex listLock;
int m_capacity;
// statistics
unsigned m_CallCount, m_successCall, m_neighborCall, m_parentCall, m_activeCall;
/// timeout for a Connect message to be received
/// and for a signalling channel to be opened after ACF/ARQ
/// (0 if GK is not in routed mode)
long m_signalTimeout;
/// timeout for a Connect message to be received after getting an Alerting message
long m_alertingTimeout;
/// default call duration limit read from the config
long m_defaultDurationLimit;
/// default interval (seconds) for accounting updates to be logged
long m_acctUpdateInterval;
/// timestamp formatting string for CDRs
PString m_timestampFormat;
/// flag to trigger per call leg accounting
bool m_singleFailoverCDR;
CallTable(const CallTable &);
CallTable& operator==(const CallTable &);
};
// inline functions of EndpointRec
inline H225_TransportAddress EndpointRec::GetRasAddress() const
{
PWaitAndSignal lock(m_usedLock);
return m_rasAddress;
}
inline H225_TransportAddress EndpointRec::GetCallSignalAddress() const
{
PWaitAndSignal lock(m_usedLock);
return m_callSignalAddress;
}
inline H225_EndpointIdentifier EndpointRec::GetEndpointIdentifier() const
{
PWaitAndSignal lock(m_usedLock);
return m_endpointIdentifier;
}
inline int EndpointRec::GetTimeToLive() const
{
return m_timeToLive;
}
inline H225_ArrayOf_AliasAddress EndpointRec::GetAliases() const
{
PWaitAndSignal lock(m_usedLock);
return m_terminalAliases;
}
inline H225_EndpointType EndpointRec::GetEndpointType() const
{
PWaitAndSignal lock(m_usedLock);
return *m_terminalType;
}
inline void EndpointRec::SetNAT(bool nat)
{
m_nat = nat;
}
inline bool EndpointRec::IsNATed() const
{
return m_nat;
}
inline PIPSocket::Address EndpointRec::GetNATIP() const
{
PWaitAndSignal lock(m_usedLock);
return m_natip;
}
inline CallSignalSocket *EndpointRec::GetSocket()
{
PWaitAndSignal lock(m_usedLock);
CallSignalSocket *socket = m_natsocket;
m_natsocket = 0;
return socket;
}
inline bool EndpointRec::IsPermanent() const
{
return m_permanent;
}
inline bool EndpointRec::IsUsed() const
{
PWaitAndSignal lock(m_usedLock);
return (m_activeCall > 0 || m_usedCount > 0);
}
inline bool EndpointRec::IsUpdated(const PTime *now) const
{
PWaitAndSignal lock(m_usedLock);
return (!m_timeToLive || (*now - m_updatedTime).GetSeconds() < m_timeToLive);
}
inline bool EndpointRec::IsFromParent() const
{
return m_fromParent;
}
inline bool EndpointRec::HasNATSocket() const
{
return m_natsocket;
}
inline PTime EndpointRec::GetUpdatedTime() const
{
PWaitAndSignal lock(m_usedLock);
return m_updatedTime;
}
inline H225_RasMessage EndpointRec::GetCompleteRegistrationRequest() const
{
PWaitAndSignal lock(m_usedLock);
return m_RasMsg;
}
inline bool EndpointRec::HasCallCreditCapabilities() const
{
return m_hasCallCreditCapabilities;
}
inline void EndpointRec::AddCall()
{
PWaitAndSignal lock(m_usedLock);
++m_activeCall, ++m_totalCall;
}
inline void EndpointRec::AddConnectedCall()
{
PWaitAndSignal lock(m_usedLock);
++m_connectedCall;
}
inline void EndpointRec::RemoveCall()
{
PWaitAndSignal lock(m_usedLock);
--m_activeCall;
}
inline void EndpointRec::Lock()
{
PWaitAndSignal lock(m_usedLock);
++m_usedCount;
}
inline void EndpointRec::Unlock()
{
PWaitAndSignal lock(m_usedLock);
--m_usedCount;
}
// inline functions of CallRec
inline void CallRec::Lock()
{
PWaitAndSignal lock(m_usedLock);
++m_usedCount;
}
inline void CallRec::Unlock()
{
PWaitAndSignal lock(m_usedLock);
--m_usedCount;
}
inline bool CallRec::CompareCallId(const H225_CallIdentifier *CallId) const
{
return (m_callIdentifier == *CallId);
}
inline bool CallRec::CompareCRV(WORD crv) const
{
return m_crv == (crv & 0x7fffu);
}
inline bool CallRec::CompareCallNumber(PINDEX CallNumber) const
{
return (m_CallNumber == CallNumber);
}
inline bool CallRec::CompareEndpoint(const endptr *ep) const
{
return (m_Calling && m_Calling == *ep) || (m_Called && m_Called == *ep);
}
inline bool CallRec::CompareSigAdr(const H225_TransportAddress *adr) const
{
return (m_Calling && m_Calling->GetCallSignalAddress() == *adr) ||
(m_Called && m_Called->GetCallSignalAddress() == *adr);
}
inline long CallRec::GetDurationLimit() const
{
return m_durationLimit;
}
inline time_t CallRec::GetCreationTime() const
{
return m_creationTime;
}
inline time_t CallRec::GetSetupTime() const
{
return m_setupTime;
}
inline time_t CallRec::GetAlertingTime() const
{
return m_alertingTime;
}
inline time_t CallRec::GetConnectTime() const
{
return m_connectTime;
}
inline time_t CallRec::GetDisconnectTime() const
{
return m_disconnectTime;
}
inline unsigned CallRec::GetDisconnectCause() const
{
return m_disconnectCause;
}
inline void CallRec::SetDisconnectCause( unsigned causeCode )
{
// set the cause only if it has not been already set
if( m_disconnectCause == 0 )
m_disconnectCause = causeCode;
}
inline bool CallRec::IsTimeout(const time_t now) const
{
bool result = (m_timeout > 0) && (now >= m_timer) && ((now - m_timer) >= m_timeout);
if (m_irrCheck && (m_irrFrequency > 0)) {
if (m_Calling)
result |= (now >= m_irrCallerTimer) && ((now - m_irrCallerTimer) >= 2 * m_irrFrequency);
if (m_Called)
result |= (now >= m_irrCalleeTimer) && ((now - m_irrCalleeTimer) >= 2 * m_irrFrequency);
}
return result;
}
#endif // RASTBL_H
syntax highlighted by Code2HTML, v. 0.9.1