diff --git a/libs/ysig/dumper.cpp b/libs/ysig/dumper.cpp index aaaf9c25..9ebb3f88 100644 --- a/libs/ysig/dumper.cpp +++ b/libs/ysig/dumper.cpp @@ -23,6 +23,7 @@ */ #include "yatesig.h" +#include 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: */ diff --git a/libs/ysig/engine.cpp b/libs/ysig/engine.cpp index 31707327..19c3b7a4 100644 --- a/libs/ysig/engine.cpp +++ b/libs/ysig/engine.cpp @@ -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(l->get())->control(params) || ok; + return ok; +} + bool SignallingEngine::start(const char* name, Thread::Priority prio, unsigned long usec) { Lock lock(this); diff --git a/libs/ysig/layer2.cpp b/libs/ysig/layer2.cpp index bb6eff92..f99e417b 100644 --- a/libs/ysig/layer2.cpp +++ b/libs/ysig/layer2.cpp @@ -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: */ diff --git a/libs/ysig/layer3.cpp b/libs/ysig/layer3.cpp index 748a62b9..9f9f7190 100644 --- a/libs/ysig/layer3.cpp +++ b/libs/ysig/layer3.cpp @@ -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: */ diff --git a/libs/ysig/q921.cpp b/libs/ysig/q921.cpp index 46972844..ead9c884 100644 --- a/libs/ysig/q921.cpp +++ b/libs/ysig/q921.cpp @@ -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", diff --git a/libs/ysig/q931.cpp b/libs/ysig/q931.cpp index 3f622bf8..14dd2b0e 100644 --- a/libs/ysig/q931.cpp +++ b/libs/ysig/q931.cpp @@ -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 diff --git a/libs/ysig/sigcall.cpp b/libs/ysig/sigcall.cpp index ed3da41b..cc4dfa9b 100644 --- a/libs/ysig/sigcall.cpp +++ b/libs/ysig/sigcall.cpp @@ -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() { diff --git a/libs/ysig/yatesig.h b/libs/ysig/yatesig.h index 7fa0e868..79255b53 100644 --- a/libs/ysig/yatesig.h +++ b/libs/ysig/yatesig.h @@ -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 diff --git a/modules/server/ysigchan.cpp b/modules/server/ysigchan.cpp index 4fccd9aa..ca6d10db 100644 --- a/modules/server/ysigchan.cpp +++ b/modules/server/ysigchan.cpp @@ -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(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(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