From eba177f5002cf34e871b63cf44657a53b38d7f30 Mon Sep 17 00:00:00 2001 From: paulc Date: Tue, 16 Sep 2008 19:28:32 +0000 Subject: [PATCH] Added still incomplete support for capturing ISDN data at runtime. git-svn-id: http://yate.null.ro/svn/yate/trunk@2205 acf43c95-373e-0410-b603-e72c3f656dc1 --- libs/ysig/dumper.cpp | 22 +++++++++---- libs/ysig/q931.cpp | 16 +++++++++ libs/ysig/sigcall.cpp | 6 ++++ libs/ysig/yatesig.h | 12 +++++++ modules/server/ysigchan.cpp | 65 +++++++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 6 deletions(-) diff --git a/libs/ysig/dumper.cpp b/libs/ysig/dumper.cpp index 77c081f3..aaaf9c25 100644 --- a/libs/ysig/dumper.cpp +++ b/libs/ysig/dumper.cpp @@ -79,11 +79,21 @@ bool SignallingDumper::dump(void* buf, unsigned int len, bool sent, int link) struct timeval tv; u_int32_t hdr[4]; t.toTimeval(&tv); + DataBlock hdr2; + if (m_type == 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; + } hdr[0] = tv.tv_sec; hdr[1] = tv.tv_usec; - hdr[2] = len; - hdr[3] = len; + hdr[2] = len + hdr2.length(); + hdr[3] = hdr[2]; DataBlock blk(hdr,sizeof(hdr)); + blk += hdr2; DataBlock dat(buf,len,false); blk += dat; dat.clear(false); @@ -107,16 +117,16 @@ void SignallingDumper::head() hdr[4] = 65535; // rather arbitrary snaplen switch (m_type) { case Hdlc: - hdr[5] = 0; + hdr[5] = 177; // DLT_LINUX_LAPD break; case Mtp2: - hdr[5] = 140; + hdr[5] = 140; // DLT_MTP2 break; case Mtp3: - hdr[5] = 141; + hdr[5] = 141; // DLT_MTP3 break; case Sccp: - hdr[5] = 142; + hdr[5] = 142; // DLT_SCCP break; default: // compiler, please shut up diff --git a/libs/ysig/q931.cpp b/libs/ysig/q931.cpp index cd15472d..3f622bf8 100644 --- a/libs/ysig/q931.cpp +++ b/libs/ysig/q931.cpp @@ -2281,6 +2281,9 @@ 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)); m_syncGroupTimer.start(); } @@ -2294,6 +2297,19 @@ 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) { diff --git a/libs/ysig/sigcall.cpp b/libs/ysig/sigcall.cpp index 67698270..ed3da41b 100644 --- a/libs/ysig/sigcall.cpp +++ b/libs/ysig/sigcall.cpp @@ -217,6 +217,12 @@ void SignallingCallControl::setDumper(SignallingDumper* dumper) 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 4c52290e..7fa0e868 100644 --- a/libs/ysig/yatesig.h +++ b/libs/ysig/yatesig.h @@ -786,6 +786,12 @@ public: */ 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 @@ -7381,6 +7387,12 @@ 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 diff --git a/modules/server/ysigchan.cpp b/modules/server/ysigchan.cpp index 19c4db39..4fccd9aa 100644 --- a/modules/server/ysigchan.cpp +++ b/modules/server/ysigchan.cpp @@ -144,6 +144,10 @@ private: // Handle command complete requests virtual bool commandComplete(Message& msg, const String& partLine, const String& partWord); + // Custom command handler + virtual bool commandExecute(String& retVal, const String& line); + // Help message handler + bool commandHelp(String& retVal, const String& line); // Delete the given link if found // Clear link list if name is 0 // Clear all stacks without waiting for call termination if name is 0 @@ -213,6 +217,8 @@ 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 @@ -494,6 +500,9 @@ static SigDriver plugin; static Configuration s_cfg; static Configuration s_cfgData; +static const char s_miniHelp[] = "sigdump component [filename]"; +static const char s_fullHelp[] = "Command to dump signalling data to a file"; + inline void applyDebugLevel(DebugEnabler* dbg, int level) { if (dbg) @@ -1092,6 +1101,8 @@ bool SigDriver::received(Message& msg, int id) if (m_engine) m_engine->stop(); return Driver::received(msg,id); + case Help: + return commandHelp(msg.retValue(),msg.getValue("line")); default: return Driver::received(msg,id); } @@ -1299,6 +1310,15 @@ void SigDriver::copySigMsgParams(NamedList& dest, SignallingEvent* event, bool SigDriver::commandComplete(Message& msg, const String& partLine, const String& partWord) { + if (partLine.null() || partLine == "help") { + if (itemComplete(msg.retValue(),"sigdump",partWord)) + 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); + } bool status = partLine.startsWith("status"); bool drop = !status && partLine.startsWith("drop"); if (!(status || drop)) @@ -1337,6 +1357,41 @@ bool SigDriver::commandComplete(Message& msg, const String& partLine, return true; } +// Custom command handler +bool SigDriver::commandExecute(String& retVal, const String& line) +{ + String tmp = line; + if (tmp.startSkip("sigdump")) { + 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()); + } + return false; + } + retVal << "\r\n"; + return true; + } + return Driver::commandExecute(retVal,line); +} + +// Help message handler +bool SigDriver::commandHelp(String& retVal, const String& line) +{ + if (line.null() || line == "sigdump") { + retVal << " " << s_miniHelp << "\r\n"; + if (line) { + retVal << s_fullHelp << "\r\n"; + return true; + } + } + return false; +} + // Append a link to the list. Duplicate names are not allowed bool SigDriver::appendLink(SigLink* link) { @@ -1406,6 +1461,7 @@ void SigDriver::initialize() setup(); installRelay(Masquerade); installRelay(Halt); + installRelay(Help); installRelay(Progress); installRelay(Update); installRelay(Route); @@ -1549,6 +1605,15 @@ 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