From 9870e16a4ca0da2f16fe192f73e241c1a3448834 Mon Sep 17 00:00:00 2001 From: paulc Date: Tue, 24 Aug 2010 03:42:31 +0000 Subject: [PATCH] Fixed MTP management, included test timers and inhibit flag in SS7Layer2. git-svn-id: http://voip.null.ro/svn/yate@3500 acf43c95-373e-0410-b603-e72c3f656dc1 --- conf.d/ysigchan.conf.sample | 10 +++ libs/ysig/layer3.cpp | 146 +++++++++++++++++++++++++++++++----- libs/ysig/yatesig.h | 36 ++++++++- 3 files changed, 174 insertions(+), 18 deletions(-) diff --git a/conf.d/ysigchan.conf.sample b/conf.d/ysigchan.conf.sample index 164997b7..afc6cd6c 100644 --- a/conf.d/ysigchan.conf.sample +++ b/conf.d/ysigchan.conf.sample @@ -443,9 +443,19 @@ ; If no router is attached only a single User Part can be connected ;router=ss7router +; link: string: Name of a SS7 Layer 2 link to create in the linkset +; This parameter can be repeated to add more links to the linkset +; An explicit SLS can be provided after a comma +; Example: link=mtp2_to_hq,3 +;link= + ; autostart: bool: Automatically enable the linkset at startup ;autostart=yes +; maintenance: integer: Interval in msec for sending SLTM messages (Q.707 T2) +; A value of zero disables sending SLTM else it is clamped to range 5s - 10m +;maintenance=60000 + ; layer3dump: string: Filename to dump MTP3 packets to ;layer3dump= diff --git a/libs/ysig/layer3.cpp b/libs/ysig/layer3.cpp index e7750548..983ad39e 100644 --- a/libs/ysig/layer3.cpp +++ b/libs/ysig/layer3.cpp @@ -490,7 +490,7 @@ SS7MTP3::SS7MTP3(const NamedList& params) : SignallingComponent(params.safe("SS7MTP3"),¶ms), SignallingDumpable(SignallingDumper::Mtp3), Mutex(true,"SS7MTP3"), - m_total(0), m_active(0), m_inhibit(false) + m_total(0), m_active(0), m_inhibit(false), m_check(0) { #ifdef DEBUG if (debugAt(DebugAll)) { @@ -531,6 +531,14 @@ SS7MTP3::SS7MTP3(const NamedList& params) Debug(this,level,"Point code types are '%s' [%p]",stype.safe(),this); m_inhibit = !params.getBoolValue("autostart",true); + int check = params.getIntValue("maintenance",60000); + if (check > 0) { + if (check < 5000) + check = 5000; + else if (check > 600000) + check = 600000; + m_check = 1000 * check; + } buildRoutes(params); setDumper(params.getValue("layer3dump")); } @@ -569,12 +577,31 @@ bool SS7MTP3::operational(int sls) const L2Pointer* p = static_cast(l->get()); if (!(p && *p)) continue; - if ((*p)->sls() == sls) + if (sls < 0) { + if ((*p)->operational() && !(*p)->inhibited()) + return true; + } + else if ((*p)->sls() == sls) return (*p)->operational(); } return false; } +bool SS7MTP3::inhibited(int sls) const +{ + if (sls < 0) + return true; + const ObjList* l = &m_links; + for (; l; l = l->next()) { + L2Pointer* p = static_cast(l->get()); + if (!(p && *p)) + continue; + if ((*p)->sls() == sls) + return (*p)->inhibited(); + } + return true; +} + int SS7MTP3::getSequence(int sls) const { if (sls < 0) @@ -605,18 +632,36 @@ void SS7MTP3::attach(SS7Layer2* link) return; } } - // Attach in the first free SLS - int sls = 0; - ObjList* before = m_links.skipNull(); - for (; before; before = before->skipNext()) { - L2Pointer* p = static_cast(before->get()); - if (!*p) - continue; - if (sls < (*p)->sls()) - break; - sls++; + ObjList* before = 0; + int sls = link->sls(); + if (sls >= 0) { + before = m_links.skipNull(); + for (; before; before = before->skipNext()) { + L2Pointer* p = static_cast(before->get()); + if (!*p) + continue; + if (sls < (*p)->sls()) + break; + if (sls == (*p)->sls()) { + sls = -1; + break; + } + } + } + if (sls < 0) { + // Attach in the first free SLS + sls = 0; + before = m_links.skipNull(); + for (; before; before = before->skipNext()) { + L2Pointer* p = static_cast(before->get()); + if (!*p) + continue; + if (sls < (*p)->sls()) + break; + sls++; + } + link->sls(sls); } - link->sls(sls); if (!before) m_links.append(new L2Pointer(link)); else @@ -670,6 +715,18 @@ bool SS7MTP3::control(Operation oper, NamedList* params) if (ok != operational()) SS7Layer3::notify(-1); } + if (params && params->getBoolValue("emergency")) { + unsigned int cnt = 0; + const ObjList* l = &m_links; + for (; l; l = l->next()) { + L2Pointer* p = static_cast(l->get()); + if (!(p && *p)) + continue; + cnt++; + (*p)->control(SS7Layer2::Resume,params); + } + Debug(this,DebugNote,"Emergency resume attempt on %u links [%p]",cnt,this); + } return true; case Status: return ok; @@ -724,8 +781,15 @@ bool SS7MTP3::initialize(const NamedList* config) continue; NamedPointer* ptr = YOBJECT(NamedPointer,param); NamedList* linkConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0; - NamedList params(param->c_str()); - params.addParam("basename",*param); + String linkName(*param); + int linkSls = -1; + int sep = linkName.find(','); + if (sep >= 0) { + linkSls = linkName.substr(sep + 1).toInteger(-1); + linkName = linkName.substr(0,sep); + } + NamedList params(linkName); + params.addParam("basename",linkName); if (linkConfig) params.copyParams(*linkConfig); else { @@ -735,6 +799,8 @@ bool SS7MTP3::initialize(const NamedList* config) SS7Layer2* link = YSIGCREATE(SS7Layer2,¶ms); if (!link) continue; + if (linkSls >= 0) + link->sls(linkSls); attach(link); if (!link->initialize(linkConfig)) { detach(link); @@ -779,7 +845,7 @@ int SS7MTP3::transmitMSU(const SS7MSU& msu, const SS7Label& label, int sls) SS7Layer2* link = *p; if (link->sls() == sls) { XDebug(this,DebugAll,"Found link %p for SLS=%d [%p]",link,sls,this); - if (link->operational()) { + if (link->operational() && !link->inhibited()) { if (link->transmitMSU(msu)) { DDebug(this,DebugAll,"Sent MSU over link '%s' %p with SLS=%d%s [%p]", link->toString().c_str(),link,sls, @@ -801,7 +867,7 @@ int SS7MTP3::transmitMSU(const SS7MSU& msu, const SS7Label& label, int sls) if (!*p) continue; SS7Layer2* link = *p; - if (link->operational() && link->transmitMSU(msu)) { + if (link->operational() && !link->inhibited() && link->transmitMSU(msu)) { sls = link->sls(); DDebug(this,DebugAll,"Sent MSU over link '%s' %p with SLS=%d%s [%p]", link->toString().c_str(),link,sls, @@ -861,6 +927,8 @@ void SS7MTP3::notify(SS7Layer2* link) tmp << "Link '" << link->toString() << "' is " << (link->operational()?"":"not ") << "operational. "; Debug(this,DebugInfo,"%sLinkset has %u/%u active links [%p]",tmp.null()?"":tmp.c_str(),m_active,m_total,this); #endif + if (link && link->operational()) + link->m_check = Time::now() + 50000 + (::random() % 200000); // if operational status of a link changed notify upper layer if (act != m_active) { Debug(this,DebugNote,"Linkset is%s operational [%p]", @@ -869,4 +937,48 @@ void SS7MTP3::notify(SS7Layer2* link) } } +void SS7MTP3::timerTick(const Time& when) +{ + Lock lock(this); + if (!m_check) + return; + for (ObjList* o = m_links.skipNull(); o; o = o->skipNext()) { + L2Pointer* p = static_cast(o->get()); + if (!(p && *p && (*p)->m_check && (*p)->operational())) + continue; + if ((*p)->m_check < when) { + (*p)->m_check = when + m_check; + for (unsigned int i = 0; i < YSS7_PCTYPE_COUNT; i++) { + SS7PointCode::Type type = (SS7PointCode::Type)(i + 1); + unsigned int local = getLocal(type); + if (!local) + continue; + ObjList* o = getRoutes(type); + if (!o) + continue; + unsigned char sio = getNI(type) | SS7MSU::MTN; + for (o = o->skipNull(); o; o = o->skipNext()) { + const SS7Route* r = static_cast(o->get()); + if (r->priority()) + continue; + // build and send a SLTM to the adjacent node + unsigned int len = 4; + SS7Label lbl(type,r->packed(),local,(*p)->sls()); + SS7MSU sltm(sio,lbl,0,len+2); + unsigned char* d = sltm.getData(lbl.length()+1,len+2); + if (!d) + continue; + *d++ = SS7MsgMTN::SLTM; + *d++ = len << 4; + unsigned char patt = (*p)->sls(); + patt = (patt << 4) | (patt & 0x0f); + while (len--) + *d++ = patt++; + (*p)->transmitMSU(sltm); + } + } + } + } +} + /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/libs/ysig/yatesig.h b/libs/ysig/yatesig.h index 829d5616..907f3d4c 100644 --- a/libs/ysig/yatesig.h +++ b/libs/ysig/yatesig.h @@ -4826,6 +4826,7 @@ protected: class YSIG_API SS7Layer2 : virtual public SignallingComponent { YCLASS(SS7Layer2,SignallingComponent) + friend class SS7MTP3; public: /** * LSSU Status Indications @@ -4928,6 +4929,13 @@ public: inline void sls(int linkSel) { if ((m_sls < 0) || !m_l2user) m_sls = linkSel; } + /** + * Check if the link is inhibited by MTP3 Management + * @return True if the link is inhibited and should not be used + */ + inline bool inhibited() const + { return m_inhibited; } + /** * Get the sequence number of the last MSU received * @return Last FSN received, negative if not available @@ -4958,7 +4966,8 @@ protected: */ inline SS7Layer2() : m_lastSeqRx(-1), - m_l2userMutex(true,"SS7Layer2::l2user"), m_l2user(0), m_sls(-1) + m_l2userMutex(true,"SS7Layer2::l2user"), m_l2user(0), m_sls(-1), + m_check(0), m_inhibited(false) { } /** @@ -4995,6 +5004,8 @@ private: Mutex m_l2userMutex; SS7L2User* m_l2user; int m_sls; + u_int64_t m_check; + bool m_inhibited; }; /** @@ -5231,6 +5242,14 @@ public: */ virtual bool operational(int sls = -1) const = 0; + /** + * Check if a specific link is inhibited + * @param sls Signalling Link to check + * @return True if the specified link is inhibited and should not be used + */ + virtual bool inhibited(int sls) const + { return false; } + /** * Get the sequence number of the last MSU received on a link * @param sls Signalling Link to retrieve MSU number from @@ -6429,6 +6448,13 @@ public: */ virtual bool operational(int sls = -1) const; + /** + * Check if a specific link is inhibited + * @param sls Signalling Link to check + * @return True if the specified link is inhibited and should not be used + */ + virtual bool inhibited(int sls) const; + /** * Get the sequence number of the last MSU received on a link * @param sls Signalling Link to retrieve MSU number from @@ -6484,6 +6510,12 @@ protected: */ virtual void destroyed(); + /** + * Periodical timer tick used to perform housekeeping and link checking + * @param when Time to use as computing base for events and timeouts + */ + virtual void timerTick(const Time& when); + /** * Process a MSU received from the Layer 2 component * @param msu Message data, starting with Service Indicator Octet @@ -6514,6 +6546,8 @@ private: unsigned int m_active; // inhibited flag bool m_inhibit; + // maintenance check interval + u_int64_t m_check; }; /**