Implemented generic signalling component control mechanism.

Protocol data dumping capability for several L2 and L3 components.
Data dumpers can be set at runtime from rmanager command with completion.


git-svn-id: http://voip.null.ro/svn/yate@2210 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2008-09-18 14:05:26 +00:00
parent ca8411d4f0
commit c60f1b10fb
9 changed files with 283 additions and 239 deletions

View File

@ -23,6 +23,7 @@
*/
#include "yatesig.h"
#include <yatephone.h>
using namespace TelEngine;
@ -37,13 +38,14 @@ SignallingDumper::~SignallingDumper()
terminate();
}
void SignallingDumper::setStream(Stream* stream)
void SignallingDumper::setStream(Stream* stream, bool writeHeader)
{
if (stream == m_output)
return;
Stream* tmp = m_output;
m_output = stream;
head();
if (writeHeader)
head();
delete tmp;
}
@ -80,13 +82,21 @@ bool SignallingDumper::dump(void* buf, unsigned int len, bool sent, int link)
u_int32_t hdr[4];
t.toTimeval(&tv);
DataBlock hdr2;
if (m_type == Hdlc) {
switch (m_type) {
case Q931:
case Q921:
case Hdlc:
{
// add LAPD pseudoheader
hdr2.assign(0,16);
unsigned char* ptr2 = (unsigned char*)hdr2.data();
ptr2[6] = sent ? 1 : 0;
ptr2[14] = 0x00;
ptr2[15] = 0x30;
}
break;
default:
break;
}
hdr[0] = tv.tv_sec;
hdr[1] = tv.tv_usec;
@ -116,6 +126,8 @@ void SignallingDumper::head()
hdr[3] = 0; // timestamp accuracy
hdr[4] = 65535; // rather arbitrary snaplen
switch (m_type) {
case Q931:
case Q921:
case Hdlc:
hdr[5] = 177; // DLT_LINUX_LAPD
break;
@ -135,23 +147,77 @@ void SignallingDumper::head()
m_output->writeData(hdr,sizeof(hdr));
}
// Create a dumper
// Create a dumper from file
SignallingDumper* SignallingDumper::create(DebugEnabler* dbg, const char* filename, Type type,
bool create, bool append)
{
if (!filename)
return 0;
SignallingDumper* dumper = 0;
File* f = new File;
if (f->openPath(filename,true,false,create,append,true)) {
dumper = new SignallingDumper(type);
dumper->setStream(f);
}
else {
Debug(dbg,DebugWarn,"Failed to create dumper '%s'",filename);
delete f;
if (f->openPath(filename,true,false,create,append,true))
return SignallingDumper::create(f,type);
Debug(dbg,DebugWarn,"Failed to create dumper '%s'",filename);
delete f;
return 0;
}
// Create a dumper from stream
SignallingDumper* SignallingDumper::create(Stream* stream, Type type, bool writeHeader)
{
if (!stream)
return 0;
if (!stream->valid()) {
delete stream;
return 0;
}
SignallingDumper* dumper = new SignallingDumper(type);
dumper->setStream(stream,writeHeader);
return dumper;
}
void SignallingDumpable::setDumper(SignallingDumper* dumper)
{
if (dumper == m_dumper)
return;
SignallingDumper* tmp = m_dumper;
m_dumper = dumper;
delete tmp;
}
bool SignallingDumpable::setDumper(const String& name, bool create, bool append)
{
if (name.null())
setDumper();
else {
SignallingDumper* dumper = SignallingDumper::create(0,name,m_type,create,append);
if (dumper)
setDumper(dumper);
else
return false;
}
return true;
}
bool SignallingDumpable::control(NamedList& params, SignallingComponent* owner)
{
String* tmp = params.getParam("operation");
if (!(tmp && (*tmp == "sigdump")))
return false;
tmp = params.getParam("component");
if (tmp && *tmp && owner && (owner->toString() != *tmp))
return false;
tmp = params.getParam("completion");
if (tmp) {
if (!owner)
return false;
String part = params.getValue("partword");
return Module::itemComplete(*tmp,owner->toString(),part);
}
tmp = params.getParam("file");
if (tmp)
return setDumper(*tmp);
return false;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -116,6 +116,11 @@ const String& SignallingComponent::toString() const
return m_name;
}
bool SignallingComponent::control(NamedList& params)
{
return false;
}
void SignallingComponent::insert(SignallingComponent* component)
{
if (!component)
@ -223,6 +228,15 @@ bool SignallingEngine::remove(const String& name)
return true;
}
bool SignallingEngine::control(NamedList& params)
{
bool ok = false;
Lock lock(this);
for (ObjList* l = m_components.skipNull(); l; l = l->skipNext())
ok = static_cast<SignallingComponent*>(l->get())->control(params) || ok;
return ok;
}
bool SignallingEngine::start(const char* name, Thread::Priority prio, unsigned long usec)
{
Lock lock(this);

View File

@ -185,18 +185,16 @@ bool SS7Layer2::control(Operation oper, NamedList* params)
SS7MTP2::SS7MTP2(const NamedList& params, unsigned int status)
: Mutex(true),
: SignallingDumpable(SignallingDumper::Mtp2),
Mutex(true),
m_status(status), m_lStatus(OutOfService), m_rStatus(OutOfAlignment),
m_interval(0), m_resend(0), m_abort(0), m_congestion(false),
m_bsn(127), m_fsn(127), m_bib(true), m_fib(true),
m_lastBsn(127), m_lastBib(true), m_errors(0),
m_resendMs(250), m_abortMs(5000), m_dumper(0)
m_resendMs(250), m_abortMs(5000)
{
setName(params.getValue("debugname","mtp2"));
const char* fn = params.getValue("mtp2dump");
if (fn)
setDumper(SignallingDumper::create(this,fn,SignallingDumper::Mtp2));
setDumper(params.getValue("mtp2dump"));
}
SS7MTP2::~SS7MTP2()
@ -438,8 +436,7 @@ ObjList* SS7MTP2::recoverMSU()
// Decode a received packet into signalling units
bool SS7MTP2::receivedPacket(const DataBlock& packet)
{
if (m_dumper)
m_dumper->dump(packet,false,sls());
dump(packet,false,sls());
if (packet.length() < 3) {
XDebug(this,DebugMild,"Received short packet of length %u [%p]",
packet.length(),this);
@ -559,8 +556,7 @@ bool SS7MTP2::receivedPacket(const DataBlock& packet)
bool SS7MTP2::txPacket(const DataBlock& packet, bool repeat, SignallingInterface::PacketType type)
{
if (transmitPacket(packet,repeat,type)) {
if (m_dumper)
m_dumper->dump(packet,true,sls());
dump(packet,true,sls());
return true;
}
return false;
@ -700,13 +696,4 @@ bool SS7MTP2::startProving()
return true;
}
void SS7MTP2::setDumper(SignallingDumper* dumper)
{
if (dumper == m_dumper)
return;
SignallingDumper* tmp = m_dumper;
m_dumper = dumper;
delete tmp;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -337,8 +337,9 @@ void SS7Layer3::printRoutes()
}
SS7MTP3::SS7MTP3(const NamedList& params)
: Mutex(true),
m_total(0), m_active(0), m_dumper(0)
: SignallingDumpable(SignallingDumper::Mtp3),
Mutex(true),
m_total(0), m_active(0)
{
setName(params.getValue("debugname","mtp3"));
// Set point code type for each network indicator
@ -363,10 +364,7 @@ SS7MTP3::SS7MTP3(const NamedList& params)
Debug(this,level,"Point code types are '%s' [%p]",stype.safe(),this);
buildRoutes(params);
const char* fn = params.getValue("mtp3dump");
if (fn)
setDumper(SignallingDumper::create(this,fn,SignallingDumper::Mtp3));
setDumper(params.getValue("mtp3dump"));
}
SS7MTP3::~SS7MTP3()
@ -497,8 +495,7 @@ int SS7MTP3::transmitMSU(const SS7MSU& msu, const SS7Label& label, int sls)
DDebug(this,DebugAll,"Found link %p for SLS=%d [%p]",link,sls,this);
if (link->operational()) {
if (link->transmitMSU(msu)) {
if (m_dumper)
m_dumper->dump(msu,true,sls);
dump(msu,true,sls);
return sls;
}
return -1;
@ -516,8 +513,7 @@ int SS7MTP3::transmitMSU(const SS7MSU& msu, const SS7Label& label, int sls)
continue;
SS7Layer2* link = *p;
if (link->operational() && link->transmitMSU(msu)) {
if (m_dumper)
m_dumper->dump(msu,true,link->sls());
dump(msu,true,link->sls());
return link->sls();
}
}
@ -528,10 +524,7 @@ int SS7MTP3::transmitMSU(const SS7MSU& msu, const SS7Label& label, int sls)
bool SS7MTP3::receivedMSU(const SS7MSU& msu, SS7Layer2* link, int sls)
{
if (m_dumper)
m_dumper->dump(msu,false,sls);
XDebug(this,DebugStub,"Possibly incomplete SS7MTP3::receivedMSU(%p,%p,%d) [%p]",
&msu,link,sls,this);
dump(msu,false,sls);
int netType = msu.getNI();
SS7PointCode::Type cpType = type(netType);
unsigned int llen = SS7Label::length(cpType);
@ -579,14 +572,4 @@ void SS7MTP3::notify(SS7Layer2* link)
SS7Layer3::notify(link ? link->sls() : -1);
}
void SS7MTP3::setDumper(SignallingDumper* dumper)
{
if (dumper == m_dumper)
return;
SignallingDumper* tmp = m_dumper;
m_dumper = dumper;
if (tmp)
delete tmp;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -98,6 +98,7 @@ public:
ISDNQ921::ISDNQ921(const NamedList& params, const char* name)
: ISDNLayer2(params,name),
SignallingReceiver(),
SignallingDumpable(SignallingDumper::Q921),
m_remoteBusy(false),
m_timerRecovery(false),
m_rejectSent(false),
@ -117,7 +118,6 @@ ISDNQ921::ISDNQ921(const NamedList& params, const char* name)
m_rxRejectedFrames(0),
m_rxDroppedFrames(0),
m_hwErrors(0),
m_dumper(0),
m_printFrames(true),
m_extendedDebug(false),
m_errorSend(false),
@ -147,6 +147,7 @@ ISDNQ921::ISDNQ921(const NamedList& params, const char* name)
Debug(this,DebugInfo,"ISDN Data Link type=%s%s [%p]",
linkSide(network()),tmp.safe(),this);
}
setDumper(params.getValue("q921dump"));
}
// Destructor
@ -334,8 +335,8 @@ bool ISDNQ921::receivedPacket(const DataBlock& packet)
frame->toString(tmp,m_extendedDebug);
Debug(this,DebugInfo,"Received frame (%p):%s",frame,tmp.c_str());
}
if (m_dumper && frame->type() < ISDNFrame::Invalid)
m_dumper->dump(frame->buffer(),false);
if (frame->type() < ISDNFrame::Invalid)
dump(frame->buffer(),false);
// Accept
bool reject = false;
// Not accepted:
@ -470,18 +471,6 @@ void ISDNQ921::reset()
m_va = m_vs = m_vr = 0;
}
// Set/remove data dumper
void ISDNQ921::setDumper(SignallingDumper* dumper)
{
Lock lock(m_layer);
if (m_dumper == dumper)
return;
SignallingDumper* tmp = m_dumper;
m_dumper = dumper;
delete tmp;
XDebug(this,DebugAll,"Data dumper set to (%p)",m_dumper);
}
// Acknoledge pending outgoing frames. See Q.921 5.6.3.2
// Remove ack'd frames from queue. Start idle timer
bool ISDNQ921::ackOutgoingFrames(const ISDNFrame* frame)
@ -869,8 +858,7 @@ bool ISDNQ921::sendFrame(const ISDNFrame* frame)
// Dump frame if no error and we have a dumper
if (result) {
m_txFrames++;
if (m_dumper)
m_dumper->dump(frame->buffer(),true);
dump(frame->buffer(),true);
m_errorSend = false;
}
else {
@ -960,12 +948,13 @@ void ISDNQ921::timer(bool start, bool t203, u_int64_t time)
}
/**
* ISDNQ921Pasive
* ISDNQ921Passive
*/
// Constructor. Set data members. Print them
ISDNQ921Pasive::ISDNQ921Pasive(const NamedList& params, const char* name)
ISDNQ921Passive::ISDNQ921Passive(const NamedList& params, const char* name)
: ISDNLayer2(params,name),
SignallingReceiver(),
SignallingDumpable(SignallingDumper::Q921),
m_layer(true),
m_checkLinkSide(false),
m_idleTimer(0),
@ -974,7 +963,6 @@ ISDNQ921Pasive::ISDNQ921Pasive(const NamedList& params, const char* name)
m_rxRejectedFrames(0),
m_rxDroppedFrames(0),
m_hwErrors(0),
m_dumper(0),
m_printFrames(true),
m_extendedDebug(false),
m_errorReceive(false)
@ -989,10 +977,11 @@ ISDNQ921Pasive::ISDNQ921Pasive(const NamedList& params, const char* name)
linkSide(network()),String::boolText(detectType()),
(unsigned int)m_idleTimer.interval(),this);
m_idleTimer.start();
setDumper(params.getValue("q921dump"));
}
// Destructor
ISDNQ921Pasive::~ISDNQ921Pasive()
ISDNQ921Passive::~ISDNQ921Passive()
{
Lock lock(m_layer);
ISDNLayer2::attach(0);
@ -1006,35 +995,23 @@ ISDNQ921Pasive::~ISDNQ921Pasive()
}
// Reset data
void ISDNQ921Pasive::cleanup()
void ISDNQ921Passive::cleanup()
{
Lock lock(m_layer);
m_idleTimer.start();
}
// Get data members pointers
void* ISDNQ921Pasive::getObject(const String& name) const
void* ISDNQ921Passive::getObject(const String& name) const
{
if (name == "ISDNQ921Pasive")
if (name == "ISDNQ921Passive")
return (void*)this;
return 0;
}
// Set/remove data dumper
void ISDNQ921Pasive::setDumper(SignallingDumper* dumper)
{
Lock lock(m_layer);
if (m_dumper == dumper)
return;
SignallingDumper* tmp = m_dumper;
m_dumper = dumper;
delete tmp;
XDebug(this,DebugAll,"Data dumper set to (%p)",m_dumper);
}
// Called periodically by the engine to check timeouts
// Check idle timer. Notify upper layer on timeout
void ISDNQ921Pasive::timerTick(const Time& when)
void ISDNQ921Passive::timerTick(const Time& when)
{
Lock lock(m_layer);
if (!m_idleTimer.timeout(when.msec()))
@ -1047,7 +1024,7 @@ void ISDNQ921Pasive::timerTick(const Time& when)
}
// Process a packet received by the receiver's interface
bool ISDNQ921Pasive::receivedPacket(const DataBlock& packet)
bool ISDNQ921Passive::receivedPacket(const DataBlock& packet)
{
if (!packet.length())
return false;
@ -1067,8 +1044,8 @@ bool ISDNQ921Pasive::receivedPacket(const DataBlock& packet)
frame->toString(tmp,m_extendedDebug);
Debug(this,DebugInfo,"Received frame (%p):%s",frame,tmp.c_str());
}
if (m_dumper && frame->type() < ISDNFrame::Invalid)
m_dumper->dump(frame->buffer(),false);
if (frame->type() < ISDNFrame::Invalid)
dump(frame->buffer(),false);
// Received enough data to parse. Assume the channel not idle (restart timer)
// If accepted, the frame is a data frame or a unnumbered (SABME,DISC,UA,DM) one
// Drop retransmissions of data frames
@ -1093,7 +1070,7 @@ bool ISDNQ921Pasive::receivedPacket(const DataBlock& packet)
}
// Process a notification generated by the attached interface
bool ISDNQ921Pasive::notify(SignallingInterface::Notification event)
bool ISDNQ921Passive::notify(SignallingInterface::Notification event)
{
Lock lock(m_layer);
if (event != SignallingInterface::LinkUp)
@ -1117,7 +1094,7 @@ bool ISDNQ921Pasive::notify(SignallingInterface::Notification event)
// Accept frame according to Q.921 5.8.5
// Filter received frames. Accept only frames that would generate a notification to the upper layer:
// UI/I and valid SABME/DISC/UA/DM
bool ISDNQ921Pasive::acceptFrame(ISDNFrame* frame, bool& cmd, bool& value)
bool ISDNQ921Passive::acceptFrame(ISDNFrame* frame, bool& cmd, bool& value)
{
// Update received frames
m_rxFrames++;
@ -1169,7 +1146,7 @@ bool ISDNQ921Pasive::acceptFrame(ISDNFrame* frame, bool& cmd, bool& value)
return dropFrame(frame);
}
bool ISDNQ921Pasive::dropFrame(const ISDNFrame* frame, const char* reason)
bool ISDNQ921Passive::dropFrame(const ISDNFrame* frame, const char* reason)
{
m_rxDroppedFrames++;
DDebug(this,DebugNote,"Dropping frame (%p): %s. Reason: %s",

View File

@ -2189,7 +2189,8 @@ TokenDict ISDNQ931::s_swType[] = {
ISDNQ931::ISDNQ931(const NamedList& params, const char* name)
: SignallingCallControl(params,"isdn."),
ISDNLayer3(name),
SignallingDumpable(SignallingDumper::Q931),
ISDNLayer3(name),
m_layer(true),
m_q921(0),
m_q921Up(false),
@ -2281,9 +2282,7 @@ ISDNQ931::ISDNQ931(const NamedList& params, const char* name)
#endif
Debug(this,DebugInfo,"ISDN Call Controller %s [%p]",s.c_str(),this);
}
const char* fn = params.getValue("isdndump");
if (fn)
setDumper(SignallingDumper::create(this,fn,SignallingDumper::Hdlc));
setDumper(params.getValue("q931dump"));
m_syncGroupTimer.start();
}
@ -2297,19 +2296,6 @@ ISDNQ931::~ISDNQ931()
DDebug(this,DebugAll,"ISDN Call Controller destroyed [%p]",this);
}
bool ISDNQ931::setDumpFile(const String& file)
{
if (file.null())
setDumper();
else {
SignallingDumper* dumper = SignallingDumper::create(this,file,SignallingDumper::Hdlc);
if (!dumper)
return false;
setDumper(dumper);
}
return true;
}
// Send a message to layer 2
bool ISDNQ931::sendMessage(ISDNQ931Message* msg, String* reason)
{
@ -3146,8 +3132,8 @@ ISDNQ931Monitor::ISDNQ931Monitor(const NamedList& params, const char* name)
ISDNQ931Monitor::~ISDNQ931Monitor()
{
terminateMonitor(0,0);
attach((ISDNQ921Pasive*)0,true);
attach((ISDNQ921Pasive*)0,false);
attach((ISDNQ921Passive*)0,true);
attach((ISDNQ921Passive*)0,false);
attach((SignallingCircuitGroup*)0,true);
attach((SignallingCircuitGroup*)0,false);
m_calls.clear();
@ -3245,14 +3231,14 @@ void ISDNQ931Monitor::receiveData(const DataBlock& data, bool ack, ISDNLayer2* l
}
// Attach ISDN Q.921 pasive transport that monitors one side of the link
void ISDNQ931Monitor::attach(ISDNQ921Pasive* q921, bool net)
void ISDNQ931Monitor::attach(ISDNQ921Passive* q921, bool net)
{
Lock lock(m_layer);
ISDNQ921Pasive* which = net ? m_q921Net : m_q921Cpe;
ISDNQ921Passive* which = net ? m_q921Net : m_q921Cpe;
if (which == q921)
return;
terminateMonitor(0,q921 ? "layer 2 attach" : "layer 2 detach");
ISDNQ921Pasive* tmp = which;
ISDNQ921Passive* tmp = which;
if (net)
m_q921Net = q921;
else

View File

@ -53,8 +53,7 @@ SignallingCallControl::SignallingCallControl(const NamedList& params,
m_verifyTimer(0),
m_circuits(0),
m_strategy(SignallingCircuitGroup::Increment),
m_exiting(false),
m_dumper(0)
m_exiting(false)
{
// Strategy
const char* strategy = params.getValue("strategy","increment");
@ -206,23 +205,6 @@ SignallingEvent* SignallingCallControl::getEvent(const Time& when)
return 0;
}
void SignallingCallControl::setDumper(SignallingDumper* dumper)
{
Lock lock(this);
if (m_dumper == dumper)
return;
SignallingDumper* tmp = m_dumper;
m_dumper = dumper;
delete tmp;
XDebug(DebugAll,"SignallingCallControl. Data dumper set to (%p) [%p]",m_dumper,this);
}
bool SignallingCallControl::setDumpFile(const String& file)
{
Debug(DebugMild,"SignallingCallControl does not support dumping");
return false;
}
// Clear call list
void SignallingCallControl::clearCalls()
{

View File

@ -50,6 +50,7 @@ namespace TelEngine {
// Signalling classes
class SignallingDumper; // A generic data dumper
class SignallingDumpable; // A component that can dump data
class SignallingTimer; // A signalling timer
class SignallingCounter; // A signalling counter
class SignallingFactory; // A signalling component factory
@ -112,7 +113,7 @@ class ISDNLayer2; // Abstract ISDN layer 2 (Q.921) messag
class ISDNLayer3; // Abstract ISDN layer 3 (Q.931) message transport
class ISDNFrame; // An ISDN Q.921 frame
class ISDNQ921; // ISDN Q.921 implementation on top of a hardware interface
class ISDNQ921Pasive; // Stateless ISDN Q.921 implementation on top of a hardware interface
class ISDNQ921Passive; // Stateless ISDN Q.921 implementation on top of a hardware interface
class ISDNIUA; // SIGTRAN ISDN Q.921 User Adaptation Layer
class ISDNQ931IE; // A Q.931 ISDN Layer 3 message Information Element
class ISDNQ931Message; // A Q.931 ISDN Layer 3 message
@ -158,6 +159,8 @@ public:
Raw,
Hexa,
Hdlc,
Q921,
Q931,
Mtp2,
Mtp3,
Sccp,
@ -195,8 +198,9 @@ public:
/**
* Set a new output stream
* @param stream New stream for output, NULL to terminate
* @param writeHeader True to write the header (if any) at start of stream
*/
void setStream(Stream* stream = 0);
void setStream(Stream* stream = 0, bool writeHeader = true);
/**
* Dump the provided data
@ -230,12 +234,92 @@ public:
static SignallingDumper* create(DebugEnabler* dbg, const char* filename, Type type,
bool create = true, bool append = false);
/**
* Create a dumper from an already existing stream
* @param stream Stream to use for output, will be owned by dumper
* @param type The dumper type
* @param writeHeader True to write the header (if any) at start of stream
* @return SignallingDumper pointer on success, 0 on failure
*/
static SignallingDumper* create(Stream* stream, Type type, bool writeHeader = true);
private:
void head();
Type m_type;
Stream* m_output;
};
/**
* A generic base class for components capable of creating data dumps
* @short A data dumping capable component
*/
class YSIG_API SignallingDumpable
{
public:
/**
* Destructor - destroys the data dumper
*/
inline ~SignallingDumpable()
{ setDumper(); }
protected:
/**
* Constructor
* @param type Default type of the data dumper
*/
inline SignallingDumpable(SignallingDumper::Type type)
: m_type(type), m_dumper(0)
{ }
/**
* Dump the provided data if the dumper is valid
* @param buf Pointer to buffer to dump
* @param len Length of the data
* @param sent True if data is being sent, false if is being received
* @param link Link number (relevant to MTP2 only)
* @return True if the data was dumped successfully
*/
inline bool dump(void* buf, unsigned int len, bool sent = false, int link = 0)
{ return (m_dumper && m_dumper->dump(buf,len,sent,link)); }
/**
* Dump data if the dumper is valid
* @param data Buffer to dump
* @param sent True if data is being sent, false if is being received
* @param link Link number (relevant to MTP2 only)
* @return True if the data was dumped successfully
*/
inline bool dump(const DataBlock& data, bool sent = false, int link = 0)
{ return dump(data.data(),data.length(),sent,link); }
/**
* Set or remove the data dumper
* @param dumper Pointer to the data dumper object, 0 to remove
*/
void setDumper(SignallingDumper* dumper = 0);
/**
* Set or remove a file data dumper
* @param name Name of the file to dump to, empty to remove dumper
* @param create True to create the file if doesn't exist
* @param append Append to an existing file. If false and the file already exists, it will be truncated
* @return True if the file dumper was created or removed
*/
bool setDumper(const String& name, bool create = true, bool append = false);
/**
* Handle dumper related control on behalf of the owning component
* @param params Control parameters to handle
* @param owner Optional owning component
* @return True if control operation was applied
*/
bool control(NamedList& params, SignallingComponent* owner = 0);
private:
SignallingDumper::Type m_type;
SignallingDumper* m_dumper;
};
/**
* Timer management class. Used to manage timeouts. The time is kept in miliseconds
* @short A signalling timer
@ -465,6 +549,13 @@ public:
*/
virtual const String& toString() const;
/**
* Query or modify component's settings or operational parameters
* @param params The list of parameters to query or change
* @return True if the control operation was executed
*/
virtual bool control(NamedList& params);
/**
* Get the @ref TelEngine::SignallingEngine that manages this component
* @return Pointer to engine or NULL if not managed by an engine
@ -560,6 +651,13 @@ public:
*/
SignallingComponent* find(const String& name);
/**
* Apply a control operation to all components in the engine
* @param params The list of parameters to query or change
* @return True if the control operation was executed by at least one component
*/
bool control(NamedList& params);
/**
* Check if a component is in the engine's list
* @param component Pointer to component to check
@ -780,18 +878,6 @@ public:
virtual void buildVerifyEvent(NamedList& params)
{}
/**
* Set or remove the data dumper
* @param dumper Pointer to the data dumper object, 0 to remove
*/
void setDumper(SignallingDumper* dumper = 0);
/**
* Set or remove a data dump file
* @param file Name of the file to dump to, empty to remove dumper
*/
virtual bool setDumpFile(const String& file);
protected:
/**
* Get the strategy used by the attached circuit group to allocate circuits
@ -832,19 +918,6 @@ protected:
*/
void removeCall(SignallingCall* call, bool del = false);
/**
* Dump data if the dumper is valid
* This method is thread safe
* @param data Buffer to dump
* @param sent True if data is being sent, false if is being received
* @param link Link number (relevant to MTP2 only)
* @return True if the data was dumped successfully
*/
inline bool dump(const DataBlock& data, bool sent = false, int link = 0) {
Lock lock(this);
return (m_dumper && m_dumper->dump(data.data(),data.length(),sent,link));
}
/**
* List of active calls
*/
@ -871,7 +944,6 @@ private:
SignallingCircuitGroup* m_circuits; // Circuit group
int m_strategy; // Strategy to allocate circuits for outgoing calls
bool m_exiting; // Call control is terminating. Generate a Disable event when no more calls
SignallingDumper* m_dumper; // Data dumper in use
};
/**
@ -4223,7 +4295,7 @@ class YSIG_API SS7M3UA : public SS7Layer3, public SIGTRAN
* Q.703 SS7 Layer 2 (Data Link) implementation on top of a hardware interface
* @short SS7 Layer 2 implementation on top of a hardware interface
*/
class YSIG_API SS7MTP2 : public SS7Layer2, public SignallingReceiver, public Mutex
class YSIG_API SS7MTP2 : public SS7Layer2, public SignallingReceiver, public SignallingDumpable, public Mutex
{
public:
/**
@ -4366,13 +4438,9 @@ protected:
*/
bool startProving();
/**
* Set or remove a data dumper
* @param dumper Pointer to the data dumper object, NULL to remove
*/
void setDumper(SignallingDumper* dumper = 0);
private:
virtual bool control(NamedList& params)
{ return SignallingDumpable::control(params,this); }
bool txPacket(const DataBlock& packet, bool repeat, SignallingInterface::PacketType type = SignallingInterface::Unknown);
void setLocalStatus(unsigned int status);
void setRemoteStatus(unsigned int status);
@ -4402,15 +4470,13 @@ private:
unsigned int m_resendMs;
// packet resend abort interval
unsigned int m_abortMs;
// data dumper in use
SignallingDumper* m_dumper;
};
/**
* Q.704 SS7 Layer 3 (Network) implementation on top of SS7 Layer 2
* @short SS7 Layer 3 implementation on top of Layer 2
*/
class YSIG_API SS7MTP3 : public SS7Layer3, public SS7L2User, public Mutex
class YSIG_API SS7MTP3 : public SS7Layer3, public SS7L2User, public SignallingDumpable, public Mutex
{
public:
/**
@ -4494,20 +4560,14 @@ protected:
*/
unsigned int countLinks();
/**
* Set or remove a data dumper
* @param dumper Pointer to the data dumper object, NULL to remove
*/
void setDumper(SignallingDumper* dumper = 0);
private:
virtual bool control(NamedList& params)
{ return SignallingDumpable::control(params,this); }
ObjList m_links;
// total links in linkset
unsigned int m_total;
// currently active links
unsigned int m_active;
// data dumper in use
SignallingDumper* m_dumper;
};
/**
@ -6120,7 +6180,7 @@ private:
* Q.921 ISDN Layer 2 implementation on top of a hardware HDLC interface
* @short ISDN Q.921 implementation on top of a hardware interface
*/
class YSIG_API ISDNQ921 : public ISDNLayer2, public SignallingReceiver
class YSIG_API ISDNQ921 : public ISDNLayer2, public SignallingReceiver, public SignallingDumpable
{
public:
/**
@ -6197,12 +6257,6 @@ public:
m_extendedDebug = m_printFrames && extendedDebug;
}
/**
* Set or remove a data dumper
* @param dumper Pointer to the data dumper object, 0 to remove
*/
void setDumper(SignallingDumper* dumper = 0);
protected:
/**
* Method called periodically to check timeouts
@ -6234,6 +6288,8 @@ protected:
void reset();
private:
virtual bool control(NamedList& params)
{ return SignallingDumpable::control(params,this); }
// Acknoledge outgoing frames
// @param frame The acknoledging frame
bool ackOutgoingFrames(const ISDNFrame* frame);
@ -6306,8 +6362,6 @@ private:
u_int32_t m_rxRejectedFrames; // The number of rejected frames. Doesn't include dropped frames
u_int32_t m_rxDroppedFrames; // The number of dropped frames. Doesn't include rejected frames
u_int32_t m_hwErrors; // The number of hardware notifications
// Dumper
SignallingDumper* m_dumper; // Data dumper in use
// Debug flags
bool m_printFrames; // Print frames to output
bool m_extendedDebug; // Extended debug flag
@ -6320,7 +6374,7 @@ private:
* Q.921 ISDN Layer 2 pasive (stateless) implementation on top of a hardware HDLC interface
* @short Stateless pasive ISDN Q.921 implementation on top of a hardware interface
*/
class YSIG_API ISDNQ921Pasive : public ISDNLayer2, public SignallingReceiver
class YSIG_API ISDNQ921Passive : public ISDNLayer2, public SignallingReceiver, public SignallingDumpable
{
public:
/**
@ -6329,12 +6383,12 @@ public:
* @param params Layer's and @ref TelEngine::ISDNLayer2 parameters
* @param name Name of this component
*/
ISDNQ921Pasive(const NamedList& params, const char* name = 0);
ISDNQ921Passive(const NamedList& params, const char* name = 0);
/**
* Destructor
*/
virtual ~ISDNQ921Pasive();
virtual ~ISDNQ921Passive();
/**
* Emergency release
@ -6369,12 +6423,6 @@ public:
m_extendedDebug = m_printFrames && extendedDebug;
}
/**
* Set or remove a data dumper
* @param dumper Pointer to the data dumper object, 0 to remove
*/
void setDumper(SignallingDumper* dumper = 0);
protected:
/**
* Method called periodically to check timeouts
@ -6400,6 +6448,8 @@ protected:
virtual bool notify(SignallingInterface::Notification event);
private:
virtual bool control(NamedList& params)
{ return SignallingDumpable::control(params,this); }
// Filter received frames. Accept only frames that would generate a notification to the upper layer:
// UI/I, and Valid SABME/DISC/UA/DM
// On success, if frame is not a data one, prepare cmd and value to notify layer 3
@ -6415,7 +6465,6 @@ private:
u_int32_t m_rxRejectedFrames; // The number of rejected frames. Doesn't include dropped frames
u_int32_t m_rxDroppedFrames; // The number of dropped frames. Doesn't include rejected frames
u_int32_t m_hwErrors; // The number of hardware notifications
SignallingDumper* m_dumper; // Data dumper in use
bool m_printFrames; // Print frames to output
bool m_extendedDebug; // Extended debug flag
bool m_errorReceive; // Receive error
@ -7242,7 +7291,7 @@ public:
* Q.931 ISDN Layer 3 implementation on top of a Layer 2
* @short ISDN Q.931 implementation on top of Q.921
*/
class YSIG_API ISDNQ931 : public SignallingCallControl, public ISDNLayer3
class YSIG_API ISDNQ931 : public SignallingCallControl, public SignallingDumpable, public ISDNLayer3
{
friend class ISDNQ931Call;
public:
@ -7387,12 +7436,6 @@ public:
inline const String& format() const
{ return m_format; }
/**
* Set or remove a data dump file
* @param file Name of the file to dump to, empty to remove dumper
*/
virtual bool setDumpFile(const String& file);
/**
* Send a message
* @param msg The message to be sent
@ -7656,6 +7699,8 @@ protected:
bool initiator, const char* cause, const char* diag = 0,
const char* display = 0, const char* signal = 0);
private:
virtual bool control(NamedList& params)
{ return SignallingDumpable::control(params,this); }
Mutex m_layer; // Lock layer operation
ISDNLayer2* m_q921; // The attached layer 2
bool m_q921Up; // Layer 2 state
@ -7751,7 +7796,7 @@ public:
* @param q921 Pointer to the monitor to attach
* @param net True if this is the network side of the data link, false for user (CPE) side
*/
virtual void attach(ISDNQ921Pasive* q921, bool net);
virtual void attach(ISDNQ921Passive* q921, bool net);
/**
* Attach a circuit group to this call controller
@ -7773,8 +7818,8 @@ public:
*/
virtual void destruct() {
SignallingCallControl::attach(0);
attach((ISDNQ921Pasive*)0,true);
attach((ISDNQ921Pasive*)0,false);
attach((ISDNQ921Passive*)0,true);
attach((ISDNQ921Passive*)0,false);
attach((SignallingCircuitGroup*)0,true);
attach((SignallingCircuitGroup*)0,false);
ISDNLayer3::destruct();
@ -7852,8 +7897,8 @@ private:
bool dropMessage(const ISDNQ931Message* msg);
Mutex m_layer; // Lock layer operation
ISDNQ921Pasive* m_q921Net; // Net side of the link
ISDNQ921Pasive* m_q921Cpe; // CPE side of the link
ISDNQ921Passive* m_q921Net; // Net side of the link
ISDNQ921Passive* m_q921Cpe; // CPE side of the link
SignallingCircuitGroup* m_cicNet; // Circuit group for the net side of the link
SignallingCircuitGroup* m_cicCpe; // Circuit group for the cpe side of the link
ISDNQ931ParserData m_parserData; // Parser settings

View File

@ -217,8 +217,6 @@ public:
{ return m_inband; }
// Set exiting flag for call controller and timeout for the thread
void setExiting(unsigned int msec);
// Set or remove a data dumper on the link or its components
bool setDumpFile(const String& file);
// Initialize (create or reload) the link. Process the debuglayer parameter.
// Fix some type depending parameters
// Return false on failure
@ -351,8 +349,8 @@ private:
String m_netId; // The id of the network side of the data link
String m_cpeId; // The id of the user side of the data link
// Components
ISDNQ921Pasive* m_q921Net;
ISDNQ921Pasive* m_q921Cpe;
ISDNQ921Passive* m_q921Net;
ISDNQ921Passive* m_q921Cpe;
SignallingInterface* m_ifaceNet;
SignallingInterface* m_ifaceCpe;
SigCircuitGroup* m_groupNet;
@ -1315,9 +1313,14 @@ bool SigDriver::commandComplete(Message& msg, const String& partLine,
return false;
}
else if (partLine == "sigdump") {
Lock lock(m_linksMutex);
for (ObjList* o = m_links.skipNull(); o; o = o->skipNext())
itemComplete(msg.retValue(),static_cast<SigLink*>(o->get())->name(),partWord);
if (m_engine) {
NamedList params("");
params.addParam("operation","sigdump");
params.addParam("partword",partWord);
params.addParam("completion",msg.retValue());
if (m_engine->control(params))
msg.retValue() = params.getValue("completion");
}
}
bool status = partLine.startsWith("status");
bool drop = !status && partLine.startsWith("drop");
@ -1362,14 +1365,24 @@ bool SigDriver::commandExecute(String& retVal, const String& line)
{
String tmp = line;
if (tmp.startSkip("sigdump")) {
tmp.trimBlanks();
if (tmp.null() || tmp == "help" || tmp == "?")
retVal << "Usage: " << s_miniHelp << "\r\n" << s_fullHelp;
else {
Lock lock(m_linksMutex);
for (ObjList* o = m_links.skipNull(); o; o = o->skipNext()) {
SigLink* link = static_cast<SigLink*>(o->get());
if (tmp.startSkip(link->name()))
return link->setDumpFile(tmp.trimBlanks());
if (m_engine) {
NamedList params("");
params.addParam("operation","sigdump");
int sep = tmp.find(' ');
if (sep > 0) {
params.addParam("component",tmp.substr(0,sep));
tmp >> " ";
params.addParam("file",tmp.trimBlanks());
}
else {
params.addParam("component",tmp);
params.addParam("file","");
}
return m_engine->control(params);
}
return false;
}
@ -1605,15 +1618,6 @@ void SigLink::setExiting(unsigned int msec)
m_thread->m_timeout = Time::msecNow() + msec;
}
// Set or remove a data dumper on the link or its components
bool SigLink::setDumpFile(const String& file)
{
if (!(m_controller && m_controller->setDumpFile(file)))
return false;
Debug(&plugin,DebugNote,"Link '%s' dumping to '%s'",name().c_str(),file.c_str());
return true;
}
// Initialize (create or reload) the link. Set debug levels for contained objects
// Fix some type depending parameters:
// Force 'readonly' to true for ISDN monitors
@ -2329,12 +2333,12 @@ bool SigIsdnMonitor::create(NamedList& params, String& error)
params.setParam("debugname",compName);
params.setParam("network",String::boolText(true));
params.setParam("print-frames",params.getValue("print-layer2PDU"));
m_q921Net = new ISDNQ921Pasive(params,compName);
m_q921Net = new ISDNQ921Passive(params,compName);
plugin.engine()->insert(m_q921Net);
buildName(compName,"Q921",false);
params.setParam("debugname",compName);
params.setParam("network",String::boolText(false));
m_q921Cpe = new ISDNQ921Pasive(params,compName);
m_q921Cpe = new ISDNQ921Passive(params,compName);
plugin.engine()->insert(m_q921Cpe);
// Q931