ISDN BRI support, most Andrei's (andrei@null.ro) work.

Fixes and new features throughout the signalling engine.


git-svn-id: http://voip.null.ro/svn/yate@2505 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2009-03-02 18:51:30 +00:00
parent 3d54351315
commit ec08dd849a
9 changed files with 1639 additions and 457 deletions

View File

@ -22,6 +22,8 @@
; type: string: Specify the link type ; type: string: Specify the link type
; Allowed values: ; Allowed values:
; ss7-isup: SS7 ISDN User Part over synchronous (HDLC) interface(s) ; ss7-isup: SS7 ISDN User Part over synchronous (HDLC) interface(s)
; isdn-bri-net: ISDN network side of a data link over basic rate HDLC interface(s)
; isdn-bri-cpe: ISDN CPE (user) side of a data link over basic rate HDLC interface(s)
; isdn-pri-net: ISDN network side of a data link over one or more primary HDLC interface(s) ; isdn-pri-net: ISDN network side of a data link over one or more primary HDLC interface(s)
; isdn-pri-cpe: ISDN CPE (user) side of a data link over one or more primary HDLC interface(s) ; isdn-pri-cpe: ISDN CPE (user) side of a data link over one or more primary HDLC interface(s)
; isdn-pri-mon: ISDN monitor of one or more primary HDLC interface(s) ; isdn-pri-mon: ISDN monitor of one or more primary HDLC interface(s)

View File

@ -28,8 +28,8 @@
using namespace TelEngine; using namespace TelEngine;
SignallingDumper::SignallingDumper(Type type) SignallingDumper::SignallingDumper(Type type, bool network)
: m_type(type), m_output(0) : m_type(type), m_network(network), m_output(0)
{ {
} }
@ -87,10 +87,15 @@ bool SignallingDumper::dump(void* buf, unsigned int len, bool sent, int link)
case Q921: case Q921:
case Hdlc: case Hdlc:
{ {
// add LAPD pseudoheader // add LAPD pseudoheader - see wiretap/libpcap.c
hdr2.assign(0,16); hdr2.assign(0,16);
unsigned char* ptr2 = (unsigned char*)hdr2.data(); unsigned char* ptr2 = (unsigned char*)hdr2.data();
ptr2[6] = sent ? 1 : 0; // packet type: outgoing 4, sniffed 3, incoming 0
ptr2[0] = 0x00;
ptr2[1] = sent ? 0x04 : 0x00;
// address: are we the network side?
ptr2[6] = m_network ? 1 : 0;
// ETH_P_LAPD
ptr2[14] = 0x00; ptr2[14] = 0x00;
ptr2[15] = 0x30; ptr2[15] = 0x30;
} }
@ -149,20 +154,20 @@ void SignallingDumper::head()
// Create a dumper from file // Create a dumper from file
SignallingDumper* SignallingDumper::create(DebugEnabler* dbg, const char* filename, Type type, SignallingDumper* SignallingDumper::create(DebugEnabler* dbg, const char* filename, Type type,
bool create, bool append) bool network, bool create, bool append)
{ {
if (!filename) if (!filename)
return 0; return 0;
File* f = new File; File* f = new File;
if (f->openPath(filename,true,false,create,append,true)) if (f->openPath(filename,true,false,create,append,true))
return SignallingDumper::create(f,type); return SignallingDumper::create(f,type,network);
Debug(dbg,DebugWarn,"Failed to create dumper '%s'",filename); Debug(dbg,DebugWarn,"Failed to create dumper '%s'",filename);
delete f; delete f;
return 0; return 0;
} }
// Create a dumper from stream // Create a dumper from stream
SignallingDumper* SignallingDumper::create(Stream* stream, Type type, bool writeHeader) SignallingDumper* SignallingDumper::create(Stream* stream, Type type, bool network, bool writeHeader)
{ {
if (!stream) if (!stream)
return 0; return 0;
@ -170,7 +175,7 @@ SignallingDumper* SignallingDumper::create(Stream* stream, Type type, bool write
delete stream; delete stream;
return 0; return 0;
} }
SignallingDumper* dumper = new SignallingDumper(type); SignallingDumper* dumper = new SignallingDumper(type,network);
dumper->setStream(stream,writeHeader); dumper->setStream(stream,writeHeader);
return dumper; return dumper;
} }
@ -195,7 +200,7 @@ bool SignallingDumpable::setDumper(const String& name, bool create, bool append)
type = SignallingDumper::Raw; type = SignallingDumper::Raw;
else if (name.endsWith(".hex") || name.endsWith(".txt")) else if (name.endsWith(".hex") || name.endsWith(".txt"))
type = SignallingDumper::Hexa; type = SignallingDumper::Hexa;
SignallingDumper* dumper = SignallingDumper::create(0,name,type,create,append); SignallingDumper* dumper = SignallingDumper::create(0,name,type,m_dumpNet,create,append);
if (dumper) if (dumper)
setDumper(dumper); setDumper(dumper);
else else

View File

@ -100,6 +100,13 @@ void* SignallingFactory::build(const String& type, const NamedList* name)
} }
SignallingComponent::SignallingComponent(const char* name)
: m_engine(0)
{
DDebug(engine(),DebugAll,"Component '%s' created [%p]",name,this);
setName(name);
}
void SignallingComponent::setName(const char* name) void SignallingComponent::setName(const char* name)
{ {
debugName(0); debugName(0);
@ -127,6 +134,16 @@ bool SignallingComponent::control(NamedList& params)
return false; return false;
} }
void SignallingComponent::engine(SignallingEngine* eng)
{
if (eng == m_engine)
return;
if (eng)
eng->insert(this);
else
detach();
}
void SignallingComponent::insert(SignallingComponent* component) void SignallingComponent::insert(SignallingComponent* component)
{ {
if (!component) if (!component)
@ -395,7 +412,7 @@ static TokenDict s_dict_causeCCITT[] = {
{"noanswer", 0x13}, // No answer from user (user alerted) {"noanswer", 0x13}, // No answer from user (user alerted)
{"rejected", 0x15}, // Call Rejected {"rejected", 0x15}, // Call Rejected
{"moved", 0x16}, // Number changed {"moved", 0x16}, // Number changed
{"non-sel-user-clearing", 0x1a}, // Non-selected user clearing {"answered", 0x1a}, // Non-selected user clearing (answered elsewhere)
{"offline", 0x1b}, // Destination out of order {"offline", 0x1b}, // Destination out of order
{"invalid-number", 0x1c}, // Invalid number format {"invalid-number", 0x1c}, // Invalid number format
{"facility-rejected", 0x1d}, // Facility rejected {"facility-rejected", 0x1d}, // Facility rejected

View File

@ -99,6 +99,14 @@ bool SignallingInterface::notify(Notification event)
} }
YCLASSIMP(SignallingReceiver,SignallingComponent)
SignallingReceiver::SignallingReceiver(const char* name)
: SignallingComponent(name),
m_ifaceMutex(true), m_interface(0)
{
}
SignallingReceiver::~SignallingReceiver() SignallingReceiver::~SignallingReceiver()
{ {
if (m_interface) if (m_interface)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -209,8 +209,9 @@ SignallingEvent* SignallingCallControl::getEvent(const Time& when)
// Clear call list // Clear call list
void SignallingCallControl::clearCalls() void SignallingCallControl::clearCalls()
{ {
Lock lock(this); lock();
m_calls.clear(); m_calls.clear();
unlock();
} }
// Remove a call from list // Remove a call from list
@ -218,11 +219,12 @@ void SignallingCallControl::removeCall(SignallingCall* call, bool del)
{ {
if (!call) if (!call)
return; return;
Lock lock(this); lock();
if (m_calls.remove(call,del)) if (m_calls.remove(call,del))
DDebug(DebugAll, DDebug(DebugAll,
"SignallingCallControl. Call (%p) removed from queue. Deleted: %s [%p]", "SignallingCallControl. Call (%p) removed%s from queue [%p]",
call,String::boolText(del),this); call,(del ? " and deleted" : ""),this);
unlock();
} }
@ -242,9 +244,11 @@ SignallingCall::SignallingCall(SignallingCallControl* controller, bool outgoing,
SignallingCall::~SignallingCall() SignallingCall::~SignallingCall()
{ {
m_callMutex.lock();
m_inMsg.clear(); m_inMsg.clear();
if (m_controller) if (m_controller)
m_controller->removeCall(this,false); m_controller->removeCall(this,false);
m_callMutex.unlock();
} }
// Event termination notification // Event termination notification

File diff suppressed because it is too large Load Diff

View File

@ -202,18 +202,29 @@ class SigLink : public RefObject
{ {
friend class SigLinkThread; // The thread must set m_thread to 0 on terminate friend class SigLinkThread; // The thread must set m_thread to 0 on terminate
public: public:
enum Mask {
MaskSS7 = 0x01,
MaskIsdn = 0x02,
MaskMon = 0x04,
MaskNet = 0x10,
MaskCpe = 0x20,
MaskPri = 0x40,
MaskBri = 0x80,
};
enum Type { enum Type {
SS7Isup, Unknown = 0,
IsdnPriNet, SS7Isup = MaskSS7,
IsdnPriCpe, IsdnPriNet = MaskIsdn | MaskNet | MaskPri,
IsdnPriMon, IsdnBriNet = MaskIsdn | MaskNet | MaskBri,
Unknown IsdnPriCpe = MaskIsdn | MaskCpe | MaskPri,
IsdnBriCpe = MaskIsdn | MaskCpe | MaskBri,
IsdnPriMon = MaskIsdn | MaskMon,
}; };
// Set link name and type. Append to plugin list // Set link name and type. Append to plugin list
SigLink(const char* name, Type type); SigLink(const char* name, Type type);
// Cancel thread. Cleanup. Remove from plugin list // Cancel thread. Cleanup. Remove from plugin list
virtual ~SigLink(); virtual ~SigLink();
inline int type() const inline Type type() const
{ return m_type; } { return m_type; }
inline SignallingCallControl* controller() const inline SignallingCallControl* controller() const
{ return m_controller; } { return m_controller; }
@ -266,7 +277,7 @@ protected:
bool m_init; // True if already initialized bool m_init; // True if already initialized
bool m_inband; // True to send in-band tones through this link bool m_inband; // True to send in-band tones through this link
private: private:
int m_type; // Link type Type m_type; // Link type
String m_name; // Link name String m_name; // Link name
SigLinkThread* m_thread; // Event thread for call controller SigLinkThread* m_thread; // Event thread for call controller
}; };
@ -304,7 +315,7 @@ private:
class SigIsdn : public SigLink class SigIsdn : public SigLink
{ {
public: public:
SigIsdn(const char* name, bool net); SigIsdn(const char* name, Type type);
virtual ~SigIsdn(); virtual ~SigIsdn();
protected: protected:
virtual bool create(NamedList& params, String& error); virtual bool create(NamedList& params, String& error);
@ -314,7 +325,7 @@ protected:
inline ISDNQ931* q931() inline ISDNQ931* q931()
{ return static_cast<ISDNQ931*>(m_controller); } { return static_cast<ISDNQ931*>(m_controller); }
private: private:
ISDNQ921* m_q921; ISDNLayer2* m_q921;
SignallingInterface* m_iface; SignallingInterface* m_iface;
SigCircuitGroup* m_group; SigCircuitGroup* m_group;
}; };
@ -1263,8 +1274,10 @@ void SigDriver::handleEvent(SignallingEvent* event)
// Route the call // Route the call
Message* m = ch->message("call.preroute",false,true); Message* m = ch->message("call.preroute",false,true);
// Parameters to be copied to call.preroute // Parameters to be copied to call.preroute
static String params = "caller,called,callername,format,formats,callernumtype,callernumplan,callerpres,callerscreening,callednumtype,callednumplan,inn"; static String params = "caller,called,callername,format,formats,callernumtype,callernumplan,callerpres,callerscreening,callednumtype,callednumplan,inn,overlapped";
copySigMsgParams(*m,event,&params); copySigMsgParams(*m,event,&params);
if (m->getBoolValue("overlapped") && !m->getValue("called"))
m->setParam("called","off-hook");
// TODO: Add call control parameter ? // TODO: Add call control parameter ?
if (!ch->startRouter(m)) { if (!ch->startRouter(m)) {
ch->hangup("temporary-failure"); ch->hangup("temporary-failure");
@ -1640,8 +1653,10 @@ void SigDriver::initialize()
link = new SigSS7Isup(*sect); link = new SigSS7Isup(*sect);
break; break;
case SigLink::IsdnPriNet: case SigLink::IsdnPriNet:
case SigLink::IsdnBriNet:
case SigLink::IsdnPriCpe: case SigLink::IsdnPriCpe:
link = new SigIsdn(*sect,type == SigLink::IsdnPriNet); case SigLink::IsdnBriCpe:
link = new SigIsdn(*sect,(SigLink::Type)type);
break; break;
case SigLink::IsdnPriMon: case SigLink::IsdnPriMon:
link = new SigIsdnMonitor(*sect); link = new SigIsdnMonitor(*sect);
@ -1675,7 +1690,9 @@ void* SigParams::getObject(const String& name) const
TokenDict SigLink::s_type[] = { TokenDict SigLink::s_type[] = {
{"ss7-isup", SS7Isup}, {"ss7-isup", SS7Isup},
{"isdn-pri-net", IsdnPriNet}, {"isdn-pri-net", IsdnPriNet},
{"isdn-bri-net", IsdnBriNet},
{"isdn-pri-cpe", IsdnPriCpe}, {"isdn-pri-cpe", IsdnPriCpe},
{"isdn-bri-cpe", IsdnBriCpe},
{"isdn-pri-mon", IsdnPriMon}, {"isdn-pri-mon", IsdnPriMon},
{0,0} {0,0}
}; };
@ -1736,7 +1753,9 @@ bool SigLink::initialize(NamedList& params)
minRxUnder = 25; minRxUnder = 25;
break; break;
case SigLink::IsdnPriNet: case SigLink::IsdnPriNet:
case SigLink::IsdnBriNet:
case SigLink::IsdnPriCpe: case SigLink::IsdnPriCpe:
case SigLink::IsdnBriCpe:
minRxUnder = 2500; minRxUnder = 2500;
break; break;
case SigLink::IsdnPriMon: case SigLink::IsdnPriMon:
@ -2168,8 +2187,8 @@ unsigned int SigSS7Isup::setPointCode(const NamedList& sect)
/** /**
* SigIsdn * SigIsdn
*/ */
SigIsdn::SigIsdn(const char* name, bool net) SigIsdn::SigIsdn(const char* name, Type type)
: SigLink(name,net ? IsdnPriNet : IsdnPriCpe), : SigLink(name,type),
m_q921(0), m_q921(0),
m_iface(0), m_iface(0),
m_group(0) m_group(0)
@ -2200,12 +2219,26 @@ bool SigIsdn::create(NamedList& params, String& error)
return false; return false;
// Q921 // Q921
buildName(compName,"Q921"); params.setParam("network",String::boolText(0 != (MaskNet & type())));
params.setParam("debugname",compName);
params.setParam("network",String::boolText(IsdnPriNet == type()));
params.setParam("print-frames",params.getValue("print-layer2PDU")); params.setParam("print-frames",params.getValue("print-layer2PDU"));
m_q921 = new ISDNQ921(params,compName); switch (type()) {
plugin.engine()->insert(m_q921); case IsdnBriNet:
buildName(compName,"Q921Management");
params.setParam("debugname",compName);
m_q921 = new ISDNQ921Management(params,compName,true);
break;
case IsdnBriCpe:
buildName(compName,"Q921Management");
params.setParam("debugname",compName);
m_q921 = new ISDNQ921Management(params,compName,false);
break;
default:
buildName(compName,"Q921");
params.setParam("debugname",compName);
m_q921 = new ISDNQ921(params,compName);
break;
}
m_q921->engine(plugin.engine());
// Q931 // Q931
buildName(compName,"Q931"); buildName(compName,"Q931");
@ -2215,12 +2248,15 @@ bool SigIsdn::create(NamedList& params, String& error)
plugin.engine()->insert(q931()); plugin.engine()->insert(q931());
// Create links between components and enable them // Create links between components and enable them
m_q921->SignallingReceiver::attach(m_iface); SignallingReceiver* recv = YOBJECT(SignallingReceiver,m_q921);
if (recv)
recv->attach(m_iface);
m_iface->control(SignallingInterface::Enable); m_iface->control(SignallingInterface::Enable);
controller()->attach(m_group); controller()->attach(m_group);
m_q921->ISDNLayer2::attach(q931()); m_q921->attach(q931());
q931()->attach(m_q921); q931()->attach(m_q921);
m_q921->multipleFrame(true,false); if (0 == (MaskBri & type()))
m_q921->multipleFrame(0,true,false);
// Start thread // Start thread
if (!startThread(error,plugin.engine()->tickDefault())) if (!startThread(error,plugin.engine()->tickDefault()))
@ -2234,9 +2270,11 @@ bool SigIsdn::reload(NamedList& params)
if (q931()) if (q931())
q931()->setDebug(params.getBoolValue("print-layer3PDU",false), q931()->setDebug(params.getBoolValue("print-layer3PDU",false),
params.getBoolValue("extended-debug",false)); params.getBoolValue("extended-debug",false));
#if 0
if (m_q921) if (m_q921)
m_q921->setDebug(params.getBoolValue("print-layer2PDU",false), m_q921->setDebug(params.getBoolValue("print-layer2PDU",false),
params.getBoolValue("extended-debug",false)); params.getBoolValue("extended-debug",false));
#endif
return true; return true;
} }