//////////////////////////////////////////////////////////////////
//
// Routing.h
//
// Routing Mechanism for GNU Gatekeeper
//
// Copyright (c) Citron Network Inc. 2003
//
// 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.
//
// initial author: Chih-Wei Huang <cwhuang@linux.org.tw>
// initial version: 06/18/2003
//
//////////////////////////////////////////////////////////////////
#ifndef ROUTING_H
#define ROUTING_H "@(#) $Id: Routing.h,v 1.20 2006/04/14 13:56:19 willamowius Exp $"
#include <map>
#include <list>
#include "slist.h"
#include "singleton.h"
#include "RasTbl.h"
// forward references to avoid includes
class H225_AdmissionRequest;
class H225_LocationRequest;
class H225_Setup_UUIE;
class H225_Facility_UUIE;
class H225_TransportAddress;
class H225_ArrayOf_AliasAddress;
class Q931;
class SignalingMsg;
template <class> class H225SignalingMsg;
typedef H225SignalingMsg<H225_Setup_UUIE> SetupMsg;
typedef H225SignalingMsg<H225_Facility_UUIE> FacilityMsg;
class RasMsg;
namespace Routing {
/// An entry for a single call destination route
struct Route {
// a policy can set flags to indicate extra status of a processed request
enum Flags {
e_toParent = 1,
e_toNeighbor = 2
};
Route();
Route(
const endptr &destEndpoint
);
Route(
const PString &policyName,
const H225_TransportAddress &destAddr
);
Route(
const PString &policyName,
const PIPSocket::Address &destIpAddr,
WORD destPort
);
PString AsString() const;
bool IsFailoverActive(
unsigned cause
) const;
H225_TransportAddress m_destAddr; /// destination address for signaling
endptr m_destEndpoint; /// destination endpoint record (if available)
H225_AliasAddress m_srcAddr; /// source alias that matched the route
PString m_policy; /// name of the policy that found the route
PString m_routeId; /// optional policy-specific route identifier
int m_proxyMode; /// per-route proxy mode flag
unsigned m_flags; /// additional route specific flags
unsigned char m_rerouteCauses[16]; /// bit flags to trigger rerouting on particular Q931 causes
};
class RoutingRequest {
public:
enum Flags {
e_aliasesChanged = 1,
e_fromInternal = 2,
e_fromParent = 4,
e_fromNeighbor = 8
};
// note this is not a polymorphic class
RoutingRequest();
RoutingRequest(
const std::list<Route> &failedRoutes
);
~RoutingRequest();
bool AddRoute(
const Route &route
);
bool GetFirstRoute(
Route &route
);
void RemoveAllRoutes();
std::list<Route> &GetRoutes() { return m_routes; }
void SetRejectReason(unsigned reason) { m_reason = reason; }
void SetFlag(unsigned f) { m_flags |= f; }
unsigned GetRejectReason() const { return m_reason; }
unsigned GetFlags() const { return m_flags; }
private:
RoutingRequest(const RoutingRequest&);
RoutingRequest& operator=(const RoutingRequest&);
private:
int m_reason; /// reject reason, if no routes are found
unsigned m_flags; /// request specific flags
std::list<Route> m_routes;
std::list<Route> m_failedRoutes;
};
template<class R, class W>
class Request : public RoutingRequest {
public:
typedef R ReqObj;
typedef W Wrapper;
Request(ReqObj & r, Wrapper *w) : m_request(r), m_wrapper(w) {}
Request(ReqObj & r, Wrapper *w, const std::list<Route> &failedRoutes)
: RoutingRequest(failedRoutes), m_request(r), m_wrapper(w) {}
bool Process();
ReqObj & GetRequest() { return m_request; }
Wrapper *GetWrapper() { return m_wrapper; }
H225_ArrayOf_AliasAddress *GetAliases();
const ReqObj & GetRequest() const { return m_request; }
const Wrapper *GetWrapper() const { return m_wrapper; }
const H225_ArrayOf_AliasAddress *GetAliases() const
{ return const_cast<Request<R, W> *>(this)->GetAliases(); }
private:
ReqObj & m_request;
Wrapper *m_wrapper;
};
typedef Request<H225_AdmissionRequest, RasMsg> AdmissionRequest;
typedef Request<H225_LocationRequest, RasMsg> LocationRequest;
typedef Request<H225_Setup_UUIE, SetupMsg> SetupRequest;
typedef Request<H225_Facility_UUIE, FacilityMsg> FacilityRequest;
class Policy : public SList<Policy> {
public:
Policy() : m_name("Undefined") {}
template <class R> bool HandleRas(Request<R,RasMsg> & request)
{
if( IsActive() ) {
#if PTRACING
const char* tagname = request.GetWrapper()
? request.GetWrapper()->GetTagName() : "unknown";
const unsigned seqnum = request.GetRequest().m_requestSeqNum.GetValue();
PTRACE(5,"ROUTING\tChecking policy "<<m_name
<<" for the request "<<tagname<<' '<<seqnum
);
#endif
if( OnRequest(request) ) {
#if PTRACING
PTRACE(5,"ROUTING\tPolicy "<<m_name
<<" applied to the request "<<tagname<<' '<<seqnum
);
#endif
return true;
}
}
return m_next && m_next->HandleRas(request);
}
bool Handle(SetupRequest &request);
bool Handle(FacilityRequest &request);
protected:
// new virtual function
// if return false, the policy is disable
virtual bool IsActive() { return true; }
// methods to handle the request
// return true: fate of the request is determined (confirm or reject)
// return false: undetermined, try next
virtual bool OnRequest(AdmissionRequest &) { return false; }
virtual bool OnRequest(LocationRequest &) { return false; }
virtual bool OnRequest(SetupRequest &) { return false; }
virtual bool OnRequest(FacilityRequest &) { return false; }
protected:
/// human readable name for the policy - it should be set inside constructors
/// of derived policies, default value is "undefined"
const char* m_name;
};
class AliasesPolicy : public Policy {
public:
AliasesPolicy() { m_name = "Aliases"; }
protected:
// override from class Policy
virtual bool OnRequest(AdmissionRequest &);
virtual bool OnRequest(LocationRequest &);
virtual bool OnRequest(SetupRequest &);
virtual bool OnRequest(FacilityRequest &);
// new virtual function
virtual bool FindByAliases(RoutingRequest&, H225_ArrayOf_AliasAddress &) = 0;
virtual bool FindByAliases(LocationRequest&, H225_ArrayOf_AliasAddress&) = 0;
};
class Analyzer : public Singleton<Analyzer> {
public:
Analyzer();
~Analyzer();
void OnReload();
bool Parse(AdmissionRequest &);
bool Parse(LocationRequest &);
bool Parse(SetupRequest &);
bool Parse(FacilityRequest &);
private:
typedef std::map<PString, Policy *, pstr_prefix_lesser> Rules;
Policy *Create(const PString & policy);
Policy *ChoosePolicy(const H225_ArrayOf_AliasAddress *, Rules &);
Rules m_rules[4];
PReadWriteMutex m_reloadMutex;
};
template<class R, class W>
inline bool Request<R, W>::Process()
{
return Analyzer::Instance()->Parse(*this);
}
/** A class that supports ACD (Automatic Call Distribution). A call
made to specified alias(-es) (called virtual queue) is signalled
via the GK status line to an external application (an ACD application)
that decides where the call should be routed (e.g. what agent should
answe the call). Basically, it rewrites virtual queue alias
into the alias of the specified agent.
The route request is uniquelly identified by (EndpointIdentifier,CRV)
values pair.
*/
class VirtualQueue
{
public:
VirtualQueue();
~VirtualQueue();
/// reload settings from the config file
void OnReload();
/** @return
True if there is at least one virtual queue configured.
*/
bool IsActive() const { return m_active; }
/** Send RouteRequest to the GK status line and wait
for a routing decision to be made by some external application
(ACD application).
@return
True if the external application routed the call (either by specifying
an alias or by rejecting the call), false if timed out waiting
for the routing decision.
If the request was rejected, destinationInfo is set to an epmty array
(0 elements).
*/
bool SendRouteRequest(
/// calling endpoint
const endptr& caller,
/// CRV (Call Reference Value) of the call associated with this request
unsigned crv,
/// destination (virtual queue) aliases as specified
/// by the calling endpoint (modified by this function on successful return)
H225_ArrayOf_AliasAddress* destinationInfo,
/// destinationCallSignalAddr (optionally set by this function on successful return)
PString* callSigAdr,
/// an actual virtual queue name (should be present in destinationInfo too)
const PString& vqueue,
/// a sequence of aliases for the calling endpoint
/// (in the "alias:type[=alias:type]..." format)
const PString& sourceInfo,
/// the callID as string
const PString& callID
);
/** Make a routing decision for a pending route request (inserted
by SendRequest).
@return
True if the matching pending request has been found, false otherwise.
*/
bool RouteToAlias(
/// aliases for the routing target (an agent that the call will be routed to)
/// that will replace the original destination info
const H225_ArrayOf_AliasAddress& agent,
/// ip that will replace the destionationCallSignalAddress (RouteToGateway)
/// used only if set (port != 0)
const PString& destinationip,
/// identifier of the endpoint associated with the route request
const PString& callingEpId,
/// CRV of the call associated with the route request
unsigned crv
);
/** Make a routing decision for a pending route request (inserted
by SendRequest).
@return
True if the matching pending request has been found, false otherwise.
*/
bool RouteToAlias(
/// alias for the routing target that
/// will replace the original destination info
const PString& agent,
/// will replace the original destinationCallSignallAddress
const PString& destinationip,
/// identifier of the endpoint associated with the route request
const PString& callingEpId,
/// CRV of the call associated with the route request
unsigned crv
);
/** Reject a pending route request (inserted by SendRequest).
@return
True if the matching pending request has been found, false otherwise.
*/
bool RouteReject(
/// identifier of the endpoint associated with the route request
const PString& callingEpId,
/// CRV of the call associated with the route request
unsigned crv
);
/** @return
True if the specified alias matches a name of an existing virtual queue.
*/
bool IsDestinationVirtualQueue(
const PString& destinationAlias /// alias to be matched
) const;
private:
/// a holder for a pending route request
struct RouteRequest
{
RouteRequest(
const PString& callingEpId,
unsigned crv,
H225_ArrayOf_AliasAddress* agent,
PString* callsignaladdr
)
:
m_callingEpId((const char*)callingEpId), m_crv(crv),
m_agent(agent), m_callsignaladdr(callsignaladdr) {}
/// identifier for the endpoint associated with this request
PString m_callingEpId;
/// CRV for the call associated with this request
unsigned m_crv;
/// aliases for the virtual queue matched (on input)
/// aliases for the target agent - target route (on output)
H225_ArrayOf_AliasAddress* m_agent;
/// destinationCallSignallAddress for the target agent - target route IF NOT NULL
PString* m_callsignaladdr;
/// a synchronization point for signalling that routing decision
/// has been made by the external application
PSyncPoint m_sync;
};
typedef std::list<RouteRequest *> RouteRequests;
RouteRequest *InsertRequest(
/// identifier for the endpoint associated with this request
const PString& callingEpId,
/// CRV for the call associated with this request
unsigned crv,
/// a pointer to an array to be filled with agent aliases
/// when the routing decision has been made
H225_ArrayOf_AliasAddress* agent,
/// a pointer to a string to be filled with a callSignalAddress
/// when the routing decision has been made (optional)
PString* callSigAdr,
/// set by the function to true if another route request for the same
/// call is pending
bool& duplicate
);
/// an array of names (aliases) for the virtual queues
PStringArray m_virtualQueueAliases;
/// an array of prefixes for the virtual queues
PStringArray m_virtualQueuePrefixes;
/// a regular expression for the virtual queues
PString m_virtualQueueRegex;
/// virtual queues enabled/disabled
bool m_active;
/// time (in milliseconds) to wait for a routing decision to be made
long m_requestTimeout;
/// a list of active (pending) route requests
RouteRequests m_pendingRequests;
/// a mutex protecting pending requests and virtual queues lists
PMutex m_listMutex;
};
} // end of namespace Routing
#endif // ROUTING_H
syntax highlighted by Code2HTML, v. 0.9.1