////////////////////////////////////////////////////////////////// // // RasPDU.h // // Define RAS PDU for GNU Gatekeeper // Avoid including large h225.h in RasSrv.h // // Copyright (c) Citron Network Inc. 2001-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 // initial version: 05/02/2003 // ////////////////////////////////////////////////////////////////// #ifndef RASPDU_H #define RASPDU_H "@(#) $Id: RasPDU.h,v 1.9 2006/04/14 13:56:19 willamowius Exp $" #include #include "yasocket.h" #include "factory.h" #include "rasinfo.h" class Toolkit; class GkStatus; class RegistrationTable; class CallTable; class RasListener; class MulticastListener; class CallSignalListener; class StatusListener; class RasServer; const unsigned MaxRasTag = H225_RasMessage::e_serviceControlResponse; struct GatekeeperMessage { PPER_Stream m_rasPDU; H225_RasMessage m_recvRAS; H225_RasMessage m_replyRAS; PIPSocket::Address m_peerAddr; WORD m_peerPort; PIPSocket::Address m_localAddr; RasListener *m_socket; unsigned GetTag() const { return m_recvRAS.GetTag(); } const char *GetTagName() const; bool Read(RasListener *); bool Reply() const; }; class RasListener : public UDPSocket { public: RasListener(const Address &, WORD); ~RasListener(); GatekeeperMessage *ReadRas(); bool SendRas(const H225_RasMessage &, const Address &, WORD); WORD GetSignalPort() const { return m_signalPort; } void SetSignalPort(WORD pt) { m_signalPort = pt; } Address GetLocalAddr(const Address &) const; H225_TransportAddress GetRasAddress(const Address &) const; H225_TransportAddress GetCallSignalAddress(const Address &) const; // new virtual function // filter out unwanted message to the listener by returning false virtual bool Filter(GatekeeperMessage *) const; protected: Address m_ip; PMutex m_wmutex; WORD m_signalPort; bool m_virtualInterface; }; class RasMsg : public Task { public: virtual ~RasMsg() { delete m_msg; } //PTRACE(1, "Delete " << m_msg->GetTagName()); } // new virtual function virtual bool Process() = 0; virtual int GetSeqNum() const = 0; virtual H225_NonStandardParameter *GetNonStandardParam() = 0; // override from class Task virtual void Exec(); bool IsFrom(const PIPSocket::Address &, WORD) const; void GetRecvAddress(PIPSocket::Address &, WORD &) const; unsigned GetTag() const { return m_msg->GetTag(); } const char *GetTagName() const { return m_msg->GetTagName(); } void GetRasAddress(H225_TransportAddress &) const; void GetCallSignalAddress(H225_TransportAddress &) const; bool EqualTo(const RasMsg *) const; bool operator==(const RasMsg & other) const { return EqualTo(&other); } bool Reply() const { return m_msg->Reply(); } GatekeeperMessage *operator->() { return m_msg; } const GatekeeperMessage *operator->() const { return m_msg; } void Release(); static void Initialize(); protected: RasMsg(GatekeeperMessage *m) : m_msg(m) {} RasMsg(const RasMsg &); static bool PrintStatus(const PString &); GatekeeperMessage *m_msg; // just pointers to global singleton objects // cache for faster access static Toolkit *Kit; static GkStatus *StatusPort; static RegistrationTable *EndpointTbl; static CallTable *CallTbl; static RasServer *RasSrv; }; template class RasPDU : public RasMsg { public: typedef RAS RasClass; RasPDU(GatekeeperMessage *m) : RasMsg(m), request(m->m_recvRAS) {} // override from class RasMsg virtual bool Process() { return false; } virtual int GetSeqNum() const { return request.m_requestSeqNum; } virtual H225_NonStandardParameter *GetNonStandardParam(); operator RAS & () { return request; } operator const RAS & () const { return request; } H225_RasMessage & BuildConfirm(); H225_RasMessage & BuildReject(unsigned); typedef Factory::Creator1 RasCreator; struct Creator : public RasCreator { Creator() : RasCreator(RasInfo::tag) {} virtual RasMsg *operator()(GatekeeperMessage *m) const { return new RasPDU(m); } }; protected: RAS & request; }; // abstract factory for listeners class GkInterface { public: typedef PIPSocket::Address Address; GkInterface(const Address &); virtual ~GkInterface(); // we can't call virtual functions in constructor // so initialize here virtual bool CreateListeners(RasServer *); bool IsBoundTo(const Address *addr) const { return m_address == *addr; } bool IsReachable(const Address *) const; RasListener *GetRasListener() const { return m_rasListener; } MulticastListener *GetMulticastListener() const { return m_multicastListener; } CallSignalListener *GetCallSignalListener() const { return m_callSignalListener; } StatusListener *GetStatusListener() const { return m_statusListener; } WORD GetRasPort() const { return m_rasPort; } WORD GetMulticastPort() const { return m_multicastPort; } WORD GetSignalPort() const { return m_signalPort; } WORD GetStatusPort() const { return m_statusPort; } protected: bool ValidateSocket(IPSocket *, WORD &); template bool SetListener(WORD nport, WORD & oport, Listener *& listener, Listener *(GkInterface::*creator)()) { if (!listener || !oport || oport != nport) { oport = nport; if (listener) listener->Close(); listener = (this->*creator)(); if (ValidateSocket(listener, oport)) return true; else listener = 0; } return false; } Address m_address; RasListener *m_rasListener; MulticastListener *m_multicastListener; CallSignalListener *m_callSignalListener; StatusListener *m_statusListener; WORD m_rasPort, m_multicastPort, m_signalPort, m_statusPort; RasServer *m_rasSrv; private: virtual RasListener *CreateRasListener(); virtual MulticastListener *CreateMulticastListener(); virtual CallSignalListener *CreateCallSignalListener(); virtual StatusListener *CreateStatusListener(); }; class RasHandler { public: typedef PIPSocket::Address Address; RasHandler(); virtual ~RasHandler() {} // new virtual function // check if the message is the expected one // default behavior: check if the tag is in m_tagArray virtual bool IsExpected(const RasMsg *) const; // process the RasMsg object // the object must be deleted after processed virtual void Process(RasMsg *) = 0; // give the derived class an opportunity to create customized PDU // default behavior: return the original one // Note: call RasMsg::Release() if new one is created virtual RasMsg *CreatePDU(RasMsg *ras) { return ras; } // stop the handler virtual void Stop() {} protected: void AddFilter(unsigned); RasServer *m_rasSrv; private: // delete the object after running RasMsg::Exec() static void ProcessRAS(RasMsg *); bool m_tagArray[MaxRasTag + 1]; }; // encapsulate a gatekeeper request and reply class RasRequester : public RasHandler { public: RasRequester() { Init(); } // note the H225_RasMessage object must have // longer lifetime than this object RasRequester(H225_RasMessage &); RasRequester(H225_RasMessage &, const Address &); ~RasRequester(); WORD GetSeqNum() const { return m_seqNum; } bool WaitForResponse(int); RasMsg *GetReply(); // override from class RasHandler virtual bool IsExpected(const RasMsg *) const; virtual void Process(RasMsg *); virtual void Stop(); // new virtual function virtual bool SendRequest(const Address &, WORD, int = 2); virtual bool OnTimeout(); protected: void AddReply(RasMsg *); H225_RasMessage *m_request; WORD m_seqNum; Address m_txAddr, m_loAddr; WORD m_txPort; PTime m_sentTime; int m_timeout, m_retry; PSyncPoint m_sync; private: void Init(); PMutex m_qmutex; std::list m_queue; std::list::iterator m_iterator; }; template class Requester : public RasRequester { public: typedef typename RasInfo::Tag Tag; typedef typename RasInfo::ConfirmTag ConfirmTag; typedef typename RasInfo::RejectTag RejectTag; Requester(H225_RasMessage &, const Address &); ~Requester() { this->m_rasSrv->UnregisterHandler(this); } // fix for GCC 3.4.2 }; template Requester::Requester(H225_RasMessage & obj_ras, const Address & ip) : RasRequester(obj_ras, ip) { obj_ras.SetTag(Tag()); RAS & ras = obj_ras; ras.m_requestSeqNum = GetSeqNum(); AddFilter(ConfirmTag()); AddFilter(RejectTag()); this->m_rasSrv->RegisterHandler(this); // fix for GCC 3.4.2 } /***************************************************************** The template class let you to modify the default handler of a given RAS message. Just explicitly specialize the Process method. For example, template<> bool HookedPDU::Process() { do_something_before_process(); // call the default handler bool result = m_opdu->Process(); do_something_after_process(); return result; } Then add a creator to hook the interested messages HookedPDU::Creator HookedRRQ; Note the creator must be executed after RasServer::Run(). *****************************************************************/ template class HookedPDU : public RasPDU { public: HookedPDU(GatekeeperMessage *m, RasMsg *p) : RasPDU(m), m_opdu(p) {} ~HookedPDU() { m_opdu->Release(); } virtual bool Process() { return m_opdu->Process(); } typedef typename RasPDU::RasCreator RasCreator; struct Creator : public RasPDU::Creator { Creator() { PAssert(this->m_old, "Error: Hook failed"); } // fix for GCC 3.4.2 virtual RasMsg *operator()(GatekeeperMessage *m) const { return new HookedPDU(m, dynamic_cast(*(this->m_old))(m)); } // fix for GCC 3.4.2 }; private: RasMsg *m_opdu; }; #endif // RASPDU_H