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:
parent
3d54351315
commit
ec08dd849a
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
@ -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
|
@ -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,¶ms);
|
copySigMsgParams(*m,event,¶ms);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue