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

Fixes and new features throughout the signalling engine.


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

View File

@ -22,6 +22,8 @@
; type: string: Specify the link type
; Allowed values:
; 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-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)

View File

@ -28,8 +28,8 @@
using namespace TelEngine;
SignallingDumper::SignallingDumper(Type type)
: m_type(type), m_output(0)
SignallingDumper::SignallingDumper(Type type, bool network)
: 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 Hdlc:
{
// add LAPD pseudoheader
// add LAPD pseudoheader - see wiretap/libpcap.c
hdr2.assign(0,16);
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[15] = 0x30;
}
@ -149,20 +154,20 @@ void SignallingDumper::head()
// Create a dumper from file
SignallingDumper* SignallingDumper::create(DebugEnabler* dbg, const char* filename, Type type,
bool create, bool append)
bool network, bool create, bool append)
{
if (!filename)
return 0;
File* f = new File;
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);
delete f;
return 0;
}
// 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)
return 0;
@ -170,7 +175,7 @@ SignallingDumper* SignallingDumper::create(Stream* stream, Type type, bool write
delete stream;
return 0;
}
SignallingDumper* dumper = new SignallingDumper(type);
SignallingDumper* dumper = new SignallingDumper(type,network);
dumper->setStream(stream,writeHeader);
return dumper;
}
@ -195,7 +200,7 @@ bool SignallingDumpable::setDumper(const String& name, bool create, bool append)
type = SignallingDumper::Raw;
else if (name.endsWith(".hex") || name.endsWith(".txt"))
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)
setDumper(dumper);
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)
{
debugName(0);
@ -127,6 +134,16 @@ bool SignallingComponent::control(NamedList& params)
return false;
}
void SignallingComponent::engine(SignallingEngine* eng)
{
if (eng == m_engine)
return;
if (eng)
eng->insert(this);
else
detach();
}
void SignallingComponent::insert(SignallingComponent* component)
{
if (!component)
@ -395,7 +412,7 @@ static TokenDict s_dict_causeCCITT[] = {
{"noanswer", 0x13}, // No answer from user (user alerted)
{"rejected", 0x15}, // Call Rejected
{"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
{"invalid-number", 0x1c}, // Invalid number format
{"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()
{
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
void SignallingCallControl::clearCalls()
{
Lock lock(this);
lock();
m_calls.clear();
unlock();
}
// Remove a call from list
@ -218,11 +219,12 @@ void SignallingCallControl::removeCall(SignallingCall* call, bool del)
{
if (!call)
return;
Lock lock(this);
lock();
if (m_calls.remove(call,del))
DDebug(DebugAll,
"SignallingCallControl. Call (%p) removed from queue. Deleted: %s [%p]",
call,String::boolText(del),this);
"SignallingCallControl. Call (%p) removed%s from queue [%p]",
call,(del ? " and deleted" : ""),this);
unlock();
}
@ -242,9 +244,11 @@ SignallingCall::SignallingCall(SignallingCallControl* controller, bool outgoing,
SignallingCall::~SignallingCall()
{
m_callMutex.lock();
m_inMsg.clear();
if (m_controller)
m_controller->removeCall(this,false);
m_callMutex.unlock();
}
// 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
public:
enum Mask {
MaskSS7 = 0x01,
MaskIsdn = 0x02,
MaskMon = 0x04,
MaskNet = 0x10,
MaskCpe = 0x20,
MaskPri = 0x40,
MaskBri = 0x80,
};
enum Type {
SS7Isup,
IsdnPriNet,
IsdnPriCpe,
IsdnPriMon,
Unknown
Unknown = 0,
SS7Isup = MaskSS7,
IsdnPriNet = MaskIsdn | MaskNet | MaskPri,
IsdnBriNet = MaskIsdn | MaskNet | MaskBri,
IsdnPriCpe = MaskIsdn | MaskCpe | MaskPri,
IsdnBriCpe = MaskIsdn | MaskCpe | MaskBri,
IsdnPriMon = MaskIsdn | MaskMon,
};
// Set link name and type. Append to plugin list
SigLink(const char* name, Type type);
// Cancel thread. Cleanup. Remove from plugin list
virtual ~SigLink();
inline int type() const
inline Type type() const
{ return m_type; }
inline SignallingCallControl* controller() const
{ return m_controller; }
@ -266,7 +277,7 @@ protected:
bool m_init; // True if already initialized
bool m_inband; // True to send in-band tones through this link
private:
int m_type; // Link type
Type m_type; // Link type
String m_name; // Link name
SigLinkThread* m_thread; // Event thread for call controller
};
@ -304,7 +315,7 @@ private:
class SigIsdn : public SigLink
{
public:
SigIsdn(const char* name, bool net);
SigIsdn(const char* name, Type type);
virtual ~SigIsdn();
protected:
virtual bool create(NamedList& params, String& error);
@ -314,7 +325,7 @@ protected:
inline ISDNQ931* q931()
{ return static_cast<ISDNQ931*>(m_controller); }
private:
ISDNQ921* m_q921;
ISDNLayer2* m_q921;
SignallingInterface* m_iface;
SigCircuitGroup* m_group;
};
@ -1263,8 +1274,10 @@ void SigDriver::handleEvent(SignallingEvent* event)
// Route the call
Message* m = ch->message("call.preroute",false,true);
// 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);
if (m->getBoolValue("overlapped") && !m->getValue("called"))
m->setParam("called","off-hook");
// TODO: Add call control parameter ?
if (!ch->startRouter(m)) {
ch->hangup("temporary-failure");
@ -1640,8 +1653,10 @@ void SigDriver::initialize()
link = new SigSS7Isup(*sect);
break;
case SigLink::IsdnPriNet:
case SigLink::IsdnBriNet:
case SigLink::IsdnPriCpe:
link = new SigIsdn(*sect,type == SigLink::IsdnPriNet);
case SigLink::IsdnBriCpe:
link = new SigIsdn(*sect,(SigLink::Type)type);
break;
case SigLink::IsdnPriMon:
link = new SigIsdnMonitor(*sect);
@ -1675,7 +1690,9 @@ void* SigParams::getObject(const String& name) const
TokenDict SigLink::s_type[] = {
{"ss7-isup", SS7Isup},
{"isdn-pri-net", IsdnPriNet},
{"isdn-bri-net", IsdnBriNet},
{"isdn-pri-cpe", IsdnPriCpe},
{"isdn-bri-cpe", IsdnBriCpe},
{"isdn-pri-mon", IsdnPriMon},
{0,0}
};
@ -1736,7 +1753,9 @@ bool SigLink::initialize(NamedList& params)
minRxUnder = 25;
break;
case SigLink::IsdnPriNet:
case SigLink::IsdnBriNet:
case SigLink::IsdnPriCpe:
case SigLink::IsdnBriCpe:
minRxUnder = 2500;
break;
case SigLink::IsdnPriMon:
@ -2168,8 +2187,8 @@ unsigned int SigSS7Isup::setPointCode(const NamedList& sect)
/**
* SigIsdn
*/
SigIsdn::SigIsdn(const char* name, bool net)
: SigLink(name,net ? IsdnPriNet : IsdnPriCpe),
SigIsdn::SigIsdn(const char* name, Type type)
: SigLink(name,type),
m_q921(0),
m_iface(0),
m_group(0)
@ -2200,12 +2219,26 @@ bool SigIsdn::create(NamedList& params, String& error)
return false;
// Q921
buildName(compName,"Q921");
params.setParam("debugname",compName);
params.setParam("network",String::boolText(IsdnPriNet == type()));
params.setParam("network",String::boolText(0 != (MaskNet & type())));
params.setParam("print-frames",params.getValue("print-layer2PDU"));
m_q921 = new ISDNQ921(params,compName);
plugin.engine()->insert(m_q921);
switch (type()) {
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
buildName(compName,"Q931");
@ -2215,12 +2248,15 @@ bool SigIsdn::create(NamedList& params, String& error)
plugin.engine()->insert(q931());
// 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);
controller()->attach(m_group);
m_q921->ISDNLayer2::attach(q931());
m_q921->attach(q931());
q931()->attach(m_q921);
m_q921->multipleFrame(true,false);
if (0 == (MaskBri & type()))
m_q921->multipleFrame(0,true,false);
// Start thread
if (!startThread(error,plugin.engine()->tickDefault()))
@ -2234,9 +2270,11 @@ bool SigIsdn::reload(NamedList& params)
if (q931())
q931()->setDebug(params.getBoolValue("print-layer3PDU",false),
params.getBoolValue("extended-debug",false));
#if 0
if (m_q921)
m_q921->setDebug(params.getBoolValue("print-layer2PDU",false),
params.getBoolValue("extended-debug",false));
#endif
return true;
}