Major rewrite of signalling components creation and configuration.

The creation of subcomponents is offloaded to each component to allow for proper building of the component stack.


git-svn-id: http://voip.null.ro/svn/yate@2650 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2009-05-26 13:43:24 +00:00
parent 663b3ad280
commit a46886c059
24 changed files with 2385 additions and 1607 deletions

View File

@ -0,0 +1,61 @@
;[session]
; Each such section configures parameters for talking to a Cisco Session Manager
; The name of the section is referenced by session users
; You can have a single session to each Cisco Session Manager
; Most parameters are related to the RUDP protocol
; rudp_sequence: int: Initial RUDP sequence number, 0-255
;rudp_sequence=0
; rudp_maxretrans: int: Maximum retransmissions until RUDP is disconnected
;rudp_maxretrans=2
; rudp_maxcumulative: int: Maximum number of segments in a cumulative ACK
;rudp_maxcumulative=3
; rudp_retransmission: int: RUDP retransmission interval in ms, 400+
;rudp_retransmission=600
; rudp_cumulative: int: RUDP cumulative ACK send timer in ms, 100+
;rudp_cumulative=300
; rudp_nulltimer: int: RUDP NULL transmission timer in ms, 1500+
;rudp_nulltimer=2000
; rudp_syntimer: int: RUDP SYN transmission timer in ms, 900+
;rudp_syntimer=1000
; rudp_checksum: bool: Attach RUDP checksums in sent packets
;rudp_checksum=no
; rudp_sendsyn: bool: Actively send RUDP SYN when connection is down
;rudp_sendsyn=no
; remote_host: ipaddr: IPv6 address of remote Cisco SM, mandatory
;remote_host=
; remote_port: int: Port for RUDP on remote Cisco SM
;remote_port=8060
; local_host: ipaddr: Address of local interface, zero address for kernel default
;local_host=0.0.0.0
; local_port: int: Local UDP port number for RUDP session
;local_port=same as remote_port
;[slt_name]
; SLT sections create on demand SS7 Layer 2 transports (remote MTP2 links)
; The name of the section is referenced as link= from a MTP3 configuration
; session: string: Name of section describing the Cisco Session Manager to use
;session=session
; channel: int: Number of the channel inside the session, must match remote config
;channel=0
; configuration: int: Configuration request retransmission interval in ms, 250+
;configuration=5000
; printslt: bool: Display SLT communication for debugging purposes
;printslt=no

View File

@ -0,0 +1,26 @@
; Configuration for each TDMV API span on available wanpipe cards
[general]
; This section configures common settings and defaults for all interfaces
; buflen: int: Size of data buffer in bytes
;buflen=160
; idlevalue: int: Byte value to use as filler when no data is available
;idlevalue=255
; priority: keyword: Data thread priority: normal, high, highest
;priority=normal
;[tdm1]
; Each such section configures a Layer 1 TDM interface
; The section name is referenced from upper layers to create signalling
; interfaces (like D channels) and voice circuit groups (B channels)
; The buflen, idlevalue and priority can be overriden in each section
; span: int: TDM span number as configured in wanrouter configuration
;span=1
; type: keyword: Type of the interface, one of: E1, T1, NET, CPE
;type=E1

View File

@ -1,72 +1,87 @@
; This file keep signalling channel configuration
; Each section (except for 'general' section) configure a link
; For call controllers, the name of the section will be used to route outgoing calls
; Each section (except for 'general' section) configure a call controller (trunk)
; or a signalling component
; For call controllers (trunks), the name of the section will be used to route
; outgoing calls
[general]
; This section keep general settings for the signalling module:
; - Default values for missing or invalid parameters in link sections
; This section keep general or default settings for the signalling module:
; debuglevel: string: Comma separated list of debug levels for module and SS7 components
; Set to 0 to disable any debug message or -1 (or void) to left it unchanged
; Keep in mind that all objects are chained in module, so any subsequent changes in
; module's debug level is propagated to the SS7 objects
; The order is: Module, Signalling engine, SS7 router, SS7 management, SS7 maintenance
; debuglevel: int: Debug level for the plugin
; This parameter is applied on reload
;debuglevel=
; debuglevel_engine: int: Debug level for the signalling engine
; This parameter is applied on reload
;debuglevel_engine=
;Example of an 'isdn-pri-net' link
;[link1]
; dtmfinband: boolean: Enable to try to send the DTMF data in band when an audio
; channel is available. If disabled or no audio channel available, the DTMF will
; be sent through the signalling channel if any
;dtmfinband=no
; type: string: Specify the link type
; Each section except [general] can have some common parameters
; To disable the component without deleting the entire section.
; The default is to enable the component
; enable: bool: Allow creation of the component corresponding to the section
;enable=yes
; Debug name as reported in Yate logs, default is derived from component name
; This parameter is used only when a component is created
; debugname: string: Debug name of the created component
;debugname=
; Debug level to apply on creation or reload
; debuglevel: int: Debug level of the component
;debuglevel=
; Example of an ISDN trunk
;[trunk1]
; type: keyword: Specify the trunk 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)
; NOTE: isdn-pri-net and isdn-pri-cpe are identical, except for the side of the link
;type=isdn-pri-net
; enable: boolean: Enable or disable this call controller
; yes: Create this call controller. If already exists, apply settings (the settings
; that can be changed on reload are explicitely specified in place)
; no: Remove call controller if already created
; Defaults to yes
;enable=yes
; sig: string: Specify the span(s) containing the signalling channel(s)
; For example wanpipe1 or any other section specified in any of the telephony
; modules like wpcard or zapcard
; Ignored if type is isdn-pri-mon
;sig=wanpipe1
; voice: string: Specify the span(s) containing the voice channel(s)
; Multiple cards may be specified by simply separating them with a comma (',') character
; Defaults to the span specified in the sig parameter
; Ignored if type is isdn-pri-mon
;voice=
;type=
; switchtype: string: The switch type of this group
; This parameter refers only to ISDN. It defines a set of flags modifying the
; call controller's behaviour
; This parameter defines a set of flags modifying the call controller's behaviour
; Allowed values: euro-isdn-e1, euro-isdn-t1, national-isdn, dms100, lucent5e, att4ess, qsig, unknown
; Defaults to unknown
;switchtype=
;switchtype=unknown
; dtmfinband: boolean: Enable to try to send the DTMF data in band when an audio channel is available
; If disabled or no audio channel available, the DTMF will be sent through the signalling channel if any
; Defaults to disable
;dtmfinband = disable
; sig: string: Specify the span(s) containing the signalling channel (D)
; For example wanpipe1 or any other section specified in any of the telephony
; modules like wpcard or zapcard
;sig=
; voice: string: Specify the span(s) containing the voice channels (B)
; Multiple cards may be specified by simply separating them with a comma (',')
; character
; Defaults to the trunk name if missing
;voice=
; number: string: Prefix of numbers we accept call setups for, empty to accept all
; Only used by isdn-pri-cpe, makes sense when NET side is Point-to-Multipoint
; Setups are ignored if called number is present but doesn't start with this prefix
;number=
; rxunderrun: int: Maximum interval in ms between two packets before we report
; an underrun condition, zero to disable or 2500+
;rxunderrun=0
; strategy: string: The strategy used to allocate voice channels for outgoing calls
; Allowed values:
; - increment Do an incremental search for an idle channel starting with the last allocated channel
; - decrement Do an decremental search for an idle channel starting with the last allocated channel
; - lowest Do an incremental search for an idle channel starting with the first channel in group
; - highest Do an decremental search for an idle channel starting with the last channel in group
; - increment Incremental search an idle channel starting with the last allocated channel
; - decrement Decremental search an idle channel starting with the last allocated channel
; - lowest Incremental search an idle channel starting with the first channel in group
; - highest Decremental search an idle channel starting with the last channel in group
; - random Randomly choose an idle channel
; Defaults to increment
;strategy=increment
@ -76,21 +91,20 @@
; Allowed values:
; even Allocate only even channels
; odd Allocate only odd channels
; even-fallback Allocate even channels. Fallback to odd channels when no more even channels
; odd-fallback Allocate odd channels. Fallback to even channels when no more odd channels
; even-fallback Allocate even channels, fall back to odd channels
; odd-fallback Allocate odd channels, fall back to even channels
;strategy-restrict=
; channelsync: integer: The interval (in seconds) at which the call controller
; will try to re-sync idle channels
; The call controller will notify the other side of the link of idle channels
; Set to 0 to disable
; Defaults to minimum value if missing or invalid
; Defaults to minimum value (500s) if missing or invalid
;channelsync=1000
; numplan: string: Default numbering plan for outgoing calls
; Values: unknown, isdn, data, telex, national, private
; Defaults to unknown if missing or incorrect
; This parameter refers only to ISDN
;numplan=unknown
; numtype: string: Default number type for outgoing calls
@ -108,78 +122,72 @@
; Defaults to user-provided if missing or incorrect
;screening=user-provided
; earlyacm: boolean: Convert received early ACM user state into progress or ringing
; Defaults to enable
;earlyacm=enable
; format: string: Default data format for outgoing calls. Values: alaw, mulaw, g721
; Defaults to alaw if missing or incorrect
; alaw is used commonly in Europe while mulaw is used commonly in US and Japan.
;format=alaw
; number: string: Prefix of numbers we accept call setups for, empty to accept all
; Only used in ISDN BRI CPE, makes sense when NET side is Point-to-Multipoint
; Setups are ignored if called number is present but doesn't start with this prefix
;number=
; print-layer2PDU: boolean: Print layer 2 (Q.921) protocol data units to output
; For ISDN this option is applied on reload
; Defaults to no
;print-layer2PDU=no
; print-layer3PDU: boolean: Print layer 3 (Q.931) protocol data units to output
; For ISDN this option is applied on reload
; Defaults to no
;print-layer3PDU=no
; print-layer4PDU: boolean: Print layer 4 (SS7-ISUP) protocol data units to output
; print-messages: boolean: Print decoded protocol data units to output
; This option is applied on reload
; Defaults to no
;print-layer4PDU=no
;print-messages=no
; extended-debug: boolean: Print extented debug data (such as raw hex data) to output
; For ISDN this parameter is used in conjuction with print-layer2PDU and print-layer3PDU and
; is ignored if it's pair is not enabled
; For SS7 this parameter is used in conjuction with print-layer4PDU and
; is ignored if it's pair is not enabled
; print-frames: boolean: Print decoded Layer 2 (Q.921) frames to output
; This option is applied on reload
; Defaults to no
;print-frames=no
; extended-debug: boolean: Print extended debug data (such as raw hex data) to output
; This option is applied on reload
; Defaults to no
;extended-debug=no
; layer2dump: string: Filename to dump Q.921 packets to
;layer2dump=
; layer3dump: string: Filename to dump Q.931 packets to
;layer3dump=
; Example of an ISDN passive recorder
;[recorder1]
; type: keyword: Specify the trunk type
; Allowed values:
; isdn-pri-mon: ISDN monitor of one or more primary HDLC interface(s)
;type=isdn-pri-mon
; sig-net: string: Specify the span(s) containing the signalling channel(s) for the network side of the monitored link
; For example wanpipe1 or any other section specified in any of the telephony
; modules like wpcard or zapcard
; Ignored if type is not isdn-pri-mon
;sig-net=
; sig-cpe: string: Specify the span(s) containing the signalling channel(s) for the user side of the monitored link
; For example wanpipe1 or any other section specified in any of the telephony
; modules like wpcard or zapcard
; Ignored if type is not isdn-pri-mon
;sig-cpe=
; voice-net: string: Specify the span(s) containing the voice channel(s) for the network side of the monitored link
; Multiple cards may be specified by simply separating them with a comma (',') character
; Defaults to the span specified in the sig-net parameter
; Ignored if type is not isdn-pri-mon
;voice-net=
; voice-cpe: string: Specify the span(s) containing the voice channel(s) for the user side of the monitored link
; Multiple cards may be specified by simply separating them with a comma (',') character
; Defaults to the span specified in the sig-cpe parameter
; Ignored if type is not isdn-pri-mon
;voice-cpe=
; detect: boolean: Change the side of the link on each captured request for watched signalling span(s)
; If disabled and the side of the link is not correct, the monitor will not be notified on
; data link state change. This may lead to malfunction
; Defaults to enable
; Ignored if type is not isdn-pri-mon
;detect=enable
;detect=yes
; idletimeout: integer: HDLC data link idle timeout, should be 3 * T203
; The minimum allowed value is 4000ms. Defaults to 30000 if missing or invalid
;idletimeout=30000
; muxchanbuffer: integer: The buffer size for one channel of the audio multiplexer
; Defaults to 160 if 0 or missing
; Ignored if type is not isdn-pri-mon
;muxchanbuffer=160
; idlevalue: integer: The value used by the audio multiplexer to fill missing data
@ -189,21 +197,21 @@
; Ignored if type is not isdn-pri-mon
;idlevalue=255
; idletimeout: integer: HDLC data link idle timeout, should be 3 * T203
; The minimum allowed value is 4000. Defaults to 30000 if missing or invalid
; Ignored if type is not isdn-pri-mon
;idletimeout=30000
; layer2dump-net: string: Filename to dump NET Q.921 packets to
;layer2dump-net=
; emergency: boolean: Emergency align SS7 MTP2 layer at startup
; Defaults to no
;emergency=yes
; layer2dump-cpe: string: Filename to dump CPE Q.921 packets to
;layer2dump-cpe=
; rxunderruninterval: integer: The interval (in miliseconds) allowed between
; 2 packets received on the signalling channel (required)
; Minimum value is 5 for SS7 links and 3000 for ISDN links
;rxunderruninterval=10
; pointcodetype: string: SS7 point code type for ISUP (required)
; Example of a SS7 ISUP trunk
;[isup1]
; type: keyword: Specify the trunk type
; Allowed values:
; ss7-isup: SS7 ISDN User Part
;type=ss7-isup
; pointcodetype: string: SS7 point code type (required)
; Allowed values:
; ITU ITU-T Q.704
; ANSI ANSI T1.111.4
@ -213,61 +221,142 @@
; Japan5 5-bit SLS
;pointcodetype=
; pointcode: string: Point code serviced by this link
; The format is network-cluster-member
; Parameter pointcode may be repeated to add more local point codes
;pointcode=
; defaultpointcode: string: Default originating point code used for outgoing calls
; If missing or invalid the first point code added to MTP3 is used
; If no point codes are added no calls can be made (incoming or outgoing)
; through this trunk
; The format is network-cluster-member
; If missing or invalid the first point code added is used
; If no point codes are added no calls can be made (incoming or outgoing) through this link
;defaultpointcode=
; remotepointcode: string: Default destination point code used for outgoing calls and maintenance messages
; remotepointcode: string: Default destination point code used for outgoing
; calls and maintenance messages
; If missing or invalid, no maintenance message will be sent
; The format is network-cluster-member
;remotepointcode=
; netind2pctype: string: Comma separated list of point code types used to map an incoming
; network indicator to a specific point code type
; earlyacm: boolean: Convert received early ACM user state into progress or ringing
;earlyacm=yes
; voice: string: Specify the span(s) containing the voice channels (L1)
; Multiple cards may be specified by simply separating them with a comma (',')
; character
; Defaults to the trunk name if missing
;voice=
; strategy: string: The strategy used to allocate voice channels for outgoing calls
; Allowed values:
; - increment Incremental search an idle channel starting with the last allocated channel
; - decrement Decremental search an idle channel starting with the last allocated channel
; - lowest Incremental search an idle channel starting with the first channel in group
; - highest Decremental search an idle channel starting with the last channel in group
; - random Randomly choose an idle channel
; Defaults to increment
;strategy=increment
; strategy-restrict: string: Define channel allocation restrictions and behaviour
; This option is ignored when strategy is random
; Allowed values:
; even Allocate only even channels
; odd Allocate only odd channels
; even-fallback Allocate even channels, fall back to odd channels
; odd-fallback Allocate odd channels, fall back to even channels
;strategy-restrict=
; channelsync: integer: The interval (in seconds) at which the call controller
; will try to re-sync idle channels
; The call controller will notify the other side of the link of idle channels
; Set to 0 to disable
; Defaults to minimum value (60s) if missing or invalid
;channelsync=1000
; numplan: string: Default numbering plan for outgoing calls
; Values: unknown, isdn, data, telex, national, private
; Defaults to unknown if missing or incorrect
;numplan=unknown
; numtype: string: Default number type for outgoing calls
; Values: unknown,international,national,net-specific,subscriber,abbreviated,reserved
; Defaults to unknown if missing or incorrect
;numtype=unknown
; presentation: string: Default number presentation for outgoing calls
; Values: allowed, restricted, unavailable
; Defaults to allowed if missing or incorrect
;presentation=allowed
; screening: string: Default number screening for outgoing calls
; Values: user-provided, user-provided-passed, user-provided-failed, network-provided
; Defaults to user-provided if missing or incorrect
;screening=user-provided
; format: string: Default data format for outgoing calls. Values: alaw, mulaw, g721
; Defaults to alaw if missing or incorrect
; alaw is used commonly in Europe while mulaw is used commonly in US and Japan.
;format=alaw
; print-messages: boolean: Print decoded protocol data units to output
; This option is applied on reload
; Defaults to no
;print-messages=no
; extended-debug: boolean: Print extended debug data (such as raw hex data) to output
; This option is applied on reload
; Defaults to no
;extended-debug=no
; Example of a SS7 MTP3 network (linkset)
;[linkset1]
; type: keyword: Specify the linkset type
; Allowed values:
; ss7-mtp3: SS7 Message Transfer Part - Layer 3
;type=ss7-mtp3
; netind2pctype: string: Comma separated list of point code types used to map an
; incoming network indicator to a specific point code type
; This option is required and is used to configure a SS7 MTP3 network
; The list must contain 4 values indicating the point code type for International,
; SpareInternational, National and ReservedNational network indicators
; See the pointcodetype option for allowed values
; NOTE: If an incoming packet comes with an unconfigured network indicator it will be dropped
; The list must contain either a singe type or 4 values indicating the point
; code type for International, SpareInternational, National and ReservedNational
; network indicators
; If only a single type is specified it will be used to configure all types of
; network indicators
; See the ISUP pointcodetype option for allowed values
; NOTE: An incoming packet with an unconfigured network indicator will be dropped
; Examples:
; netind2pctype=ITU,ITU,ITU,ITU
; netind2pctype=ITU
; netind2pctype=ITU,ANSI,ITU,ITU
; netind2pctype=ANSI8,ITU,ANSI,ITU
;netind2pctype=
; route: string: Build a destination route for a SS7 MTP3 network
; route: string: Build a destination route for the SS7 network
; The format of this option is pointcodetype,label,priority
; This parameter can be repeated to build multiple destination routes
; The network will notify the router about its destination(s) and priority
; Example: route=ITU,2-2-2,0
;route=
; filllink: boolean: Configure MTP2 to request link fill (packet repeat) when sending
; FISU/LSSU packets
; Defaults to yes
;filllink=yes
; debuglevel: string: Comma separated list of debug levels for link layers
; Set to 0 to disable any debug message or -1 (or void) to left it unchanged
; ss7-isup: Interface,Circuit group, MTP2, MTP3, ISUP
; isdn-pri-net,isdn-pri-cpe: Interface,Circuit group, Q921, Q931
;debuglevel=
; layer2dump: string: Filename to dump Q.921 or MTP2 packets to (if applicable)
;layer2dump=
; layer3dump: string: Filename to dump Q.931 or MTP3 packets to (if applicable)
; layer3dump: string: Filename to dump MTP3 packets to
;layer3dump=
; layer2dump-net: string: Filename to dump NET Q.921 packets to (passive only)
;layer2dump-net=
; layer2dump-cpe: string: Filename to dump CPE Q.921 packets to (passive only)
;layer2dump-cpe=
; Example of a SS7 MTP2 link
;[link1]
; type: keyword: Specify the link type
; Allowed values:
; ss7-mtp2: SS7 Message Transfer Part - Layer 2
;type=ss7-mtp2
; emergency: boolean: Emergency align SS7 MTP2 layer at startup
;emergency=yes
; filllink: boolean: Configure MTP2 to request link fill (packet repeat) when
; sending FISU or LSSU packets
;filllink=yes
; rxunderrun: int: Maximum interval in ms between two packets before we report
; an underrun condition, zero to disable or 25+
;rxunderrun=0
; layer2dump: string: Filename to dump MTP2 packets to
;layer2dump=

View File

@ -52,12 +52,15 @@ private:
using namespace TelEngine;
static ObjList s_factories;
static Mutex s_mutex(true);
static Mutex s_mutex(true,"SignallingFactory");
SignallingFactory::SignallingFactory()
SignallingFactory::SignallingFactory(bool fallback)
{
s_mutex.lock();
s_factories.append(this)->setDelete(false);
if (!s_factories.find(this)) {
ObjList* l = fallback ? s_factories.append(this) : s_factories.insert(this);
l->setDelete(false);
}
s_mutex.unlock();
}
@ -68,7 +71,7 @@ SignallingFactory::~SignallingFactory()
s_mutex.unlock();
}
void* SignallingFactory::build(const String& type, const NamedList* name)
SignallingComponent* SignallingFactory::build(const String& type, const NamedList* name)
{
if (type.null())
return 0;
@ -80,29 +83,58 @@ void* SignallingFactory::build(const String& type, const NamedList* name)
SignallingFactory* f = static_cast<SignallingFactory*>(l->get());
if (!f)
continue;
XDebug(DebugAll,"Attempting to create a %s %s using factory %p",
DDebug(DebugAll,"Attempting to create a '%s' %s using factory %p",
name->c_str(),type.c_str(),f);
void* obj = f->create(type,*name);
SignallingComponent* obj = f->create(type,*name);
if (obj)
return obj;
}
lock.drop();
DDebug(DebugInfo,"Factory creating default '%s' named '%s'",type.c_str(),name->c_str());
// now build some objects we know about
if (type == "SignallingEngine")
return new SignallingEngine;
else if (type == "SS7MTP2")
if (type == "SS7MTP2")
return new SS7MTP2(*name);
else if (type == "SS7MTP3")
return new SS7MTP3(*name);
else if (type == "SS7Router")
return new SS7Router(*name);
else return 0;
else if (type == "SS7Management")
return new SS7Management(*name);
else if (type == "SS7Maintenance")
return new SS7Maintenance(*name);
else if (type == "ISDNQ921")
return new ISDNQ921(*name,*name);
else if (type == "ISDNQ931")
return new ISDNQ931(*name,*name);
else if (type == "ISDNQ931Monitor")
return new ISDNQ931Monitor(*name,*name);
Debug(DebugMild,"Factory could not create '%s' named '%s'",type.c_str(),name->c_str());
return 0;
}
void* SignallingFactory::buildInternal(const String& type, const NamedList* name)
{
SignallingComponent* c = build(type,name);
if (!c)
return 0;
void* raw = c->getObject(type);
if (!raw)
Debug(DebugFail,"Built component %p could not be casted back to type '%s'",c,type.c_str());
#ifdef DEBUG
else
Debug(DebugAll,"Built component %p type '%s' interface at %p",c,type.c_str(),raw);
#endif
return raw;
}
SignallingComponent::SignallingComponent(const char* name)
SignallingComponent::SignallingComponent(const char* name, const NamedList* params)
: m_engine(0)
{
if (params) {
name = params->getValue("debugname",name);
debugLevel(params->getIntValue("debuglevel",-1));
}
DDebug(engine(),DebugAll,"Component '%s' created [%p]",name,this);
setName(name);
}
@ -129,6 +161,11 @@ const String& SignallingComponent::toString() const
return m_name;
}
bool SignallingComponent::initialize(const NamedList* config)
{
return true;
}
bool SignallingComponent::control(NamedList& params)
{
return false;
@ -180,7 +217,7 @@ unsigned long SignallingComponent::tickSleep(unsigned long usec) const
SignallingEngine::SignallingEngine(const char* name)
: Mutex(true),
: Mutex(true,"SignallingEngine"),
m_thread(0), m_listChanged(true),
m_usecSleep(DEF_TICK_SLEEP), m_tickSleep(0)
{
@ -195,33 +232,75 @@ SignallingEngine::~SignallingEngine()
stop();
}
lock();
unsigned int n = m_components.count();
if (n)
Debug(this,DebugNote,"Cleaning up %u components [%p]",n,this);
m_components.clear();
unlock();
}
SignallingComponent* SignallingEngine::find(const String& name)
{
Lock lock(this);
Lock mylock(this);
return static_cast<SignallingComponent*>(m_components[name]);
}
SignallingComponent* SignallingEngine::find(const String& name, const String& type, const SignallingComponent* start)
{
Lock mylock(this);
ObjList* l = m_components.skipNull();
if (start) {
l = m_components.find(start);
if (!l)
return 0;
l = l->skipNext();
}
for (; l; l = l->skipNext()) {
SignallingComponent* c = static_cast<SignallingComponent*>(l->get());
if ((name.null() || (c->toString() == name)) &&
(type.null() || c->getObject(type)))
return c;
}
return 0;
}
bool SignallingEngine::find(const SignallingComponent* component)
{
if (!component)
return false;
Lock lock(this);
Lock mylock(this);
return m_components.find(component) != 0;
}
SignallingComponent* SignallingEngine::build(const String& type, const NamedList& params, bool init)
{
Lock mylock(this);
SignallingComponent* c = find(params,type);
if (c && c->alive()) {
DDebug(this,DebugAll,"Engine returning existing component '%s' @%p [%p]",
c->toString().c_str(),c,this);
return c;
}
c = SignallingFactory::build(type,&params);
XDebug(this,DebugAll,"Created component @%p [%p]",c,this);
insert(c);
if (init && c)
c->initialize(&params);
return c;
}
void SignallingEngine::insert(SignallingComponent* component)
{
if (!component)
return;
Lock lock(this);
Lock mylock(this);
if (component->engine() == this)
return;
DDebug(this,DebugAll,"Engine inserting component '%s' @%p [%p]",
component->toString().c_str(),component,this);
#ifdef DEBUG
const char* dupl = m_components.find(component->toString()) ? " (duplicate)" : "";
Debug(this,DebugAll,"Engine inserting component '%s'%s @%p [%p]",
component->toString().c_str(),dupl,component,this);
#endif
component->detach();
component->m_engine = this;
component->debugChain(this);
@ -232,21 +311,21 @@ void SignallingEngine::remove(SignallingComponent* component)
{
if (!component)
return;
Lock lock(this);
Lock mylock(this);
if (component->engine() != this)
return;
DDebug(this,DebugAll,"Engine removing component @%p '%s' [%p]",
component,component->toString().c_str(),this);
m_components.remove(component,false);
component->m_engine = 0;
component->detach();
m_components.remove(component,false);
}
bool SignallingEngine::remove(const String& name)
{
if (name.null())
return false;
Lock lock(this);
Lock mylock(this);
SignallingComponent* component = find(name);
if (!component)
return false;
@ -261,7 +340,7 @@ bool SignallingEngine::remove(const String& name)
bool SignallingEngine::control(NamedList& params)
{
bool ok = false;
Lock lock(this);
Lock mylock(this);
for (ObjList* l = m_components.skipNull(); l; l = l->skipNext())
ok = static_cast<SignallingComponent*>(l->get())->control(params) || ok;
return ok;
@ -269,7 +348,7 @@ bool SignallingEngine::control(NamedList& params)
bool SignallingEngine::start(const char* name, Thread::Priority prio, unsigned long usec)
{
Lock lock(this);
Lock mylock(this);
if (m_thread)
return m_thread->running();
// defaults and sanity checks

View File

@ -99,11 +99,9 @@ bool SignallingInterface::notify(Notification event)
}
YCLASSIMP(SignallingReceiver,SignallingComponent)
SignallingReceiver::SignallingReceiver(const char* name)
: SignallingComponent(name),
m_ifaceMutex(true), m_interface(0)
m_ifaceMutex(true,"SignallingReceiver::interface"), m_interface(0)
{
}
@ -111,30 +109,36 @@ SignallingReceiver::~SignallingReceiver()
{
if (m_interface)
Debug(this,DebugGoOn,"Destroyed with interface (%p) attached",m_interface);
TelEngine::destruct(attach(0));
}
void SignallingReceiver::attach(SignallingInterface* iface)
SignallingInterface* SignallingReceiver::attach(SignallingInterface* iface)
{
Lock lock(m_ifaceMutex);
if (m_interface == iface)
return;
return 0;
SignallingInterface* tmp = m_interface;
m_interface = iface;
lock.drop();
if (tmp) {
const char* name = 0;
if (engine() && engine()->find(tmp)) {
name = tmp->toString().safe();
if (tmp->receiver() == this) {
Debug(this,DebugAll,"Detaching interface (%p,'%s') [%p]",
tmp,tmp->toString().safe(),this);
tmp->attach(0);
}
Debug(this,DebugAll,"Detached interface (%p,'%s') [%p]",tmp,name,this);
else {
Debug(this,DebugNote,"Interface (%p,'%s') was not attached to us [%p]",
tmp,tmp->toString().safe(),this);
tmp = 0;
}
}
if (!iface)
return;
return tmp;
Debug(this,DebugAll,"Attached interface (%p,'%s') [%p]",
iface,iface->toString().safe(),this);
insert(iface);
iface->attach(this);
return tmp;
}
bool SignallingReceiver::notify(SignallingInterface::Notification event)

View File

@ -1381,13 +1381,6 @@ void SS7MsgISUP::toString(String& dest, const SS7Label& label, bool params,
dest << enclose;
}
void* SS7MsgISUP::getObject(const String& name) const
{
if (name == "SS7MsgISUP")
return (void*)this;
return SignallingMessage::getObject(name);
}
/**
* Helper functions used to transmit responses
@ -1484,7 +1477,7 @@ SS7ISUPCall::~SS7ISUPCall()
// received by the controller
void SS7ISUPCall::stopWaitSegment(bool discard)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (!m_sgmMsg)
return;
m_sgmRecvTimer.stop();
@ -1508,7 +1501,7 @@ inline bool timeout(SS7ISUP* isup, SS7ISUPCall* call, SignallingTimer& timer,
// Get an event from this call
SignallingEvent* SS7ISUPCall::getEvent(const Time& when)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (m_lastEvent || m_state == Released)
return 0;
SS7MsgISUP* msg = 0;
@ -1605,7 +1598,7 @@ SignallingEvent* SS7ISUPCall::getEvent(const Time& when)
// Send an event to this call
bool SS7ISUPCall::sendEvent(SignallingEvent* event)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (!event)
return false;
if (m_terminate || m_state == Released) {
@ -1690,7 +1683,7 @@ void* SS7ISUPCall::getObject(const String& name) const
// On failure set the termination flag and release the new circuit if valid
bool SS7ISUPCall::replaceCircuit(SignallingCircuit* circuit)
{
Lock lock(m_callMutex);
Lock mylock(this);
clearQueue();
if (m_state > Setup || !circuit || !outgoing()) {
m_iamTimer.stop();
@ -2015,31 +2008,38 @@ SS7ISUP* SS7ISUPCall::isup()
* SS7ISUP
*/
SS7ISUP::SS7ISUP(const NamedList& params)
: SignallingCallControl(params,"isup."),
m_cicLen(2),
m_type(SS7PointCode::Other),
m_defPoint(0),
m_remotePoint(0),
m_priossf(0),
m_sls(255),
m_earlyAcm(true),
m_inn(false),
m_l3LinkUp(false),
m_uptTimer(0),
m_userPartAvail(true),
m_uptCicCode(0),
m_rscTimer(0),
m_rscCic(0),
m_lockTimer(0),
m_lockNeed(true),
m_hwFailReq(false),
m_blockReq(false),
m_lockCicCode(0),
m_printMsg(false),
m_extendedDebug(false)
: SignallingComponent(params.safe("SS7ISUP"),&params),
SignallingCallControl(params,"isup."),
m_cicLen(2),
m_type(SS7PointCode::Other),
m_defPoint(0),
m_remotePoint(0),
m_priossf(0),
m_sls(255),
m_earlyAcm(true),
m_inn(false),
m_l3LinkUp(false),
m_uptTimer(0),
m_userPartAvail(true),
m_uptCicCode(0),
m_rscTimer(0),
m_rscCic(0),
m_lockTimer(0),
m_lockNeed(true),
m_hwFailReq(false),
m_blockReq(false),
m_lockCicCode(0),
m_printMsg(false),
m_extendedDebug(false)
{
setName(params.getValue("debugname","isup"));
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"SS7ISUP::SS7ISUP(%p) [%p]%s",
&params,this,tmp.c_str());
}
#endif
const char* stype = params.getValue("pointcodetype");
m_type = SS7PointCode::lookup(stype);
if (m_type == SS7PointCode::Other) {
@ -2087,8 +2087,8 @@ SS7ISUP::SS7ISUP(const NamedList& params)
if (m_uptTimer.interval())
m_userPartAvail = false;
setDebug(params.getBoolValue("print-layer4PDU",m_printMsg),
params.getBoolValue("extended-debug",m_extendedDebug));
setDebug(params.getBoolValue("print-messages",false),
params.getBoolValue("extended-debug",false));
if (debugAt(DebugInfo)) {
String s;
@ -2117,13 +2117,37 @@ SS7ISUP::~SS7ISUP()
Debug(this,DebugInfo,"ISUP Call Controller destroyed [%p]",this);
}
bool SS7ISUP::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"SS7ISUP::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config) {
debugLevel(config->getIntValue("debuglevel_isup",
config->getIntValue("debuglevel",-1)));
setDebug(config->getBoolValue("print-messages",false),
config->getBoolValue("extended-debug",false));
}
if (engine() && !network()) {
NamedList params("ss7router");
if (config)
static_cast<String&>(params) = config->getValue("router",params);
if (params.toBoolean(true))
SS7Layer4::attach(YOBJECT(SS7Router,engine()->build("SS7Router",params,true)));
}
return SS7Layer4::initialize(config);
}
// Append a point code to the list of point codes serviced by this controller
// Set default point code
bool SS7ISUP::setPointCode(SS7PointCode* pc, bool def)
{
if (!(pc && pc->pack(m_type)))
return false;
Lock lock(this);
Lock mylock(this);
// Force default if we are not having one or the list is empty
def = def || !m_defPoint || !m_pointCodes.skipNull();
// Force not default if the received point code is the same as the default one
@ -2149,7 +2173,7 @@ bool SS7ISUP::setPointCode(SS7PointCode* pc, bool def)
// Check if the given point code is serviced by this controller
SS7PointCode* SS7ISUP::hasPointCode(const SS7PointCode& pc)
{
Lock lock(this);
Lock mylock(this);
for (ObjList* o = m_pointCodes.skipNull(); o; o = o->skipNext()) {
SS7PointCode* p = static_cast<SS7PointCode*>(o->get());
if (*p == pc)
@ -2188,7 +2212,7 @@ SignallingCall* SS7ISUP::call(SignallingMessage* msg, String& reason)
SignallingCircuit* cic = 0;
const char* range = msg->params().getValue("circuits");
reason.clear();
Lock lock(this);
Lock mylock(this);
// Check
while (true) {
if (!m_defPoint) {
@ -2223,7 +2247,7 @@ SignallingCall* SS7ISUP::call(SignallingMessage* msg, String& reason)
if (!m_rscCic && m_rscTimer.interval())
m_rscTimer.start();
// Drop lock and send the event
lock.drop();
mylock.drop();
event->sendEvent();
}
TelEngine::destruct(msg);
@ -2296,14 +2320,6 @@ void SS7ISUP::cleanup(const char* reason)
clearCalls();
}
// Get a pointer to this object or other data
void* SS7ISUP::getObject(const String& name) const
{
if (name == "SS7ISUP")
return (void*)this;
return SS7Layer4::getObject(name);
}
// Remove all links with other layers. Disposes the memory
void SS7ISUP::destroyed()
{
@ -2317,7 +2333,7 @@ void SS7ISUP::destroyed()
void SS7ISUP::timerTick(const Time& when)
{
Lock lock(this);
Lock mylock(this);
if (!(m_l3LinkUp && circuits()))
return;
@ -2344,7 +2360,8 @@ void SS7ISUP::timerTick(const Time& when)
if (!m_lockTimer.timeout(when.msec()))
return;
Debug(this,DebugMild,"Circuit %sblocking timed out cic=%u map=%s",
m_blockReq?"":"un",m_lockCicCode,m_lockMap.c_str());
(m_blockReq ? "" : "un"),
m_lockCicCode,m_lockMap.c_str());
}
if (sendLocalLock(when.msec()))
return;
@ -2378,17 +2395,19 @@ void SS7ISUP::notify(SS7Layer3* link, int sls)
{
if (!link)
return;
Lock lock(this);
Lock mylock(this);
m_l3LinkUp = link->operational(-1);
// Reset remote user part's availablity state if supported
// Reset remote user part's availability state if supported
// Force UPT re-send
if (m_uptTimer.interval() && !m_l3LinkUp) {
m_uptTimer.stop();
m_userPartAvail = false;
}
Debug(this,DebugInfo,
"L3 (%p,'%s') is %soperational sls=%d. Remote User Part is %savailable",link,
link->toString().safe(),m_l3LinkUp?"":"not ",sls,m_userPartAvail?"":"un");
"L3 (%p,'%s') is %soperational sls=%d. Remote User Part is %savailable",
link,link->toString().safe(),
(m_l3LinkUp ? "" : "not "),sls,
(m_userPartAvail ? "" : "un"));
}
SS7MSU* SS7ISUP::buildMSU(SS7MsgISUP::Type type, unsigned char sio,
@ -2913,7 +2932,8 @@ void SS7ISUP::processControllerMsg(SS7MsgISUP* msg, const SS7Label& label, int s
case SS7MsgISUP::CNF: // Confusion
// TODO: check if this message was received in response to RSC, UBL, UBK, CGB, CGU
Debug(this,DebugNote,"%s with cause='%s' diagnostic='%s'",msg->name(),
msg->params().getValue("CauseIndicators"),msg->params().getValue("CauseIndicators.diagnostic"));
msg->params().getValue("CauseIndicators"),
msg->params().getValue("CauseIndicators.diagnostic"));
stopSGM = true;
break;
case SS7MsgISUP::RLC: // Release Complete
@ -3124,8 +3144,10 @@ bool SS7ISUP::blockCircuit(unsigned int cic, bool block, bool remote, bool hwFai
something = circuit->maintLock(block,remote,changed,changedState);
if (something) {
Debug(this,DebugNote,"%slocked %s side of circuit %u. Current flags 0x%x",
block?"B":"Unb",remote?"remote":"local",cic,circuit->locked(-1));
Debug(this,DebugNote,"%s %s side of circuit %u. Current flags 0x%x",
(block ? "Blocked" : "Unblocked"),
(remote ? "remote" : "local"),
cic,circuit->locked(-1));
m_verifyEvent = true;
}
return true;
@ -3133,7 +3155,7 @@ bool SS7ISUP::blockCircuit(unsigned int cic, bool block, bool remote, bool hwFai
SS7ISUPCall* SS7ISUP::findCall(unsigned int cic)
{
Lock lock(this);
Lock mylock(this);
for (ObjList* o = m_calls.skipNull(); o; o = o->skipNext()) {
SS7ISUPCall* call = static_cast<SS7ISUPCall*>(o->get());
if (call->id() == cic)
@ -3223,22 +3245,17 @@ bool SS7ISUP::sendLocalLock(u_int64_t when)
SS7MsgISUP* msg = 0;
m_lockMap.assign(d,lockRange);
if (m_lockMap.length() > 1 || m_hwFailReq) {
if (m_blockReq)
msg = new SS7MsgISUP(SS7MsgISUP::CGB,m_lockCicCode);
else
msg = new SS7MsgISUP(SS7MsgISUP::CGU,m_lockCicCode);
if (m_hwFailReq)
msg->params().addParam("GroupSupervisionTypeIndicator","hw-failure");
else
msg->params().addParam("GroupSupervisionTypeIndicator","maintenance");
msg = new SS7MsgISUP((m_blockReq ? SS7MsgISUP::CGB : SS7MsgISUP::CGU),
m_lockCicCode);
msg->params().addParam("GroupSupervisionTypeIndicator",
(m_hwFailReq ? "hw-failure" : "maintenance"));
msg->params().addParam("RangeAndStatus",String(m_lockMap.length()));
msg->params().addParam("RangeAndStatus.map",m_lockMap);
}
else
if (m_blockReq)
msg = new SS7MsgISUP(SS7MsgISUP::BLK,m_lockCicCode);
else
msg = new SS7MsgISUP(SS7MsgISUP::UBL,m_lockCicCode);
else {
msg = new SS7MsgISUP((m_blockReq ? SS7MsgISUP::BLK : SS7MsgISUP::UBL),
m_lockCicCode);
}
SS7Label label(m_type,*m_remotePoint,*m_defPoint,m_sls);
transmitMessage(msg,label,false);
m_lockTimer.start(when);
@ -3250,9 +3267,9 @@ bool SS7ISUP::sendLocalLock(u_int64_t when)
* SS7BICC
*/
SS7BICC::SS7BICC(const NamedList& params)
: SS7ISUP(params)
: SignallingComponent(params.safe("SS7BICC"),&params),
SS7ISUP(params)
{
setName(params.getValue("debugname","bicc"));
m_cicLen = 4;
Debug(this,DebugInfo,"BICC Call Controller [%p]",this);
}
@ -3269,14 +3286,6 @@ SS7MSU* SS7BICC::createMSU(SS7MsgISUP::Type type, unsigned char ssf,
return buildMSU(type,SS7MSU::BICC | (ssf & 0xf0),label,cic,params);
}
// Get a pointer to this object or other data
void* SS7BICC::getObject(const String& name) const
{
if (name == "SS7BICC")
return (void*)this;
return SS7ISUP::getObject(name);
}
bool SS7BICC::receivedMSU(const SS7MSU& msu, const SS7Label& label, SS7Layer3* network, int sls)
{
if (msu.getSIF() != SS7MSU::BICC || !hasPointCode(label.dpc()))

View File

@ -188,18 +188,25 @@ ObjList* SS7Layer2::recoverMSU()
return 0;
}
YCLASSIMP2(SS7MTP2,SS7Layer2,SignallingReceiver)
SS7MTP2::SS7MTP2(const NamedList& params, unsigned int status)
: SignallingDumpable(SignallingDumper::Mtp2),
Mutex(true),
: SignallingComponent(params.safe("SS7MTP2"),&params),
SignallingDumpable(SignallingDumper::Mtp2),
Mutex(true,"SS7MTP2"),
m_status(status), m_lStatus(OutOfService), m_rStatus(OutOfAlignment),
m_interval(0), m_resend(0), m_abort(0), m_fillTime(0), m_congestion(false),
m_bsn(127), m_fsn(127), m_bib(true), m_fib(true),
m_lastFsn(128), m_lastBsn(127), m_lastBib(true), m_errors(0),
m_resendMs(250), m_abortMs(5000), m_fillIntervalMs(20), m_fillLink(true)
{
setName(params.getValue("debugname","mtp2"));
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"SS7MTP2::SS7MTP2(%p,%s) [%p]%s",
&params,statusName(true),this,tmp.c_str());
}
#endif
m_fillLink = params.getBoolValue("filllink",m_fillLink);
setDumper(params.getValue("layer2dump"));
}
@ -244,6 +251,46 @@ bool SS7MTP2::operational() const
return aligned() && !m_interval;
}
bool SS7MTP2::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"SS7MTP2::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config)
debugLevel(config->getIntValue("debuglevel_mtp2",
config->getIntValue("debuglevel",-1)));
if (config && !iface()) {
NamedString* name = config->getParam("sig");
if (!name)
name = config->getParam("basename");
if (name) {
NamedPointer* ptr = YOBJECT(NamedPointer,name);
NamedList* ifConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(name->c_str());
params.addParam("basename",*name);
params.addParam("protocol","ss7");
if (ifConfig) {
params.copyParams(*ifConfig);
int rx = params.getIntValue("rxunderrun");
if ((rx > 0) && (rx < 25))
params.setParam("rxunderrun","25");
}
else
ifConfig = &params;
SignallingInterface* ifc = YSIGCREATE(SignallingInterface,&params);
if (!ifc)
return false;
SignallingReceiver::attach(ifc);
if (!ifc->initialize(ifConfig))
TelEngine::destruct(SignallingReceiver::attach(0));
}
}
return iface() && control(Resume,const_cast<NamedList*>(config));
}
bool SS7MTP2::control(Operation oper, NamedList* params)
{
switch (oper) {

View File

@ -336,31 +336,49 @@ void SS7Layer3::printRoutes()
Debug(this,DebugAll,"No %s [%p]",router?"routes":"destinations",this);
}
SS7MTP3::SS7MTP3(const NamedList& params)
: SignallingDumpable(SignallingDumper::Mtp3),
Mutex(true),
: SignallingComponent(params.safe("SS7MTP3"),&params),
SignallingDumpable(SignallingDumper::Mtp3),
Mutex(true,"SS7MTP3"),
m_total(0), m_active(0)
{
setName(params.getValue("debugname","mtp3"));
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"SS7MTP3::SS7MTP3(%p) [%p]%s",
&params,this,tmp.c_str());
}
#endif
// Set point code type for each network indicator
static const unsigned char ni[4] = { SS7MSU::International,
SS7MSU::SpareInternational, SS7MSU::National, SS7MSU::ReservedNational };
String stype = params.getValue("netind2pctype");
ObjList* obj = stype.split(',',false);
int level = DebugAll;
unsigned char ni[4] = {SS7MSU::International,SS7MSU::SpareInternational,
SS7MSU::National,SS7MSU::ReservedNational};
ObjList* o = obj->skipNull();
for (unsigned int i = 0; i < 4; i++) {
String* s = 0;
if (o) {
s = static_cast<String*>(o->get());
o = o->skipNext();
if (stype.find(',') >= 0) {
ObjList* obj = stype.split(',',false);
ObjList* o = obj->skipNull();
for (unsigned int i = 0; i < 4; i++) {
String* s = 0;
if (o) {
s = static_cast<String*>(o->get());
o = o->skipNext();
}
SS7PointCode::Type type = SS7PointCode::lookup(s?s->c_str():0);
if (type == SS7PointCode::Other)
level = DebugNote;
setType(type,ni[i]);
}
SS7PointCode::Type type = SS7PointCode::lookup(s?s->c_str():0);
TelEngine::destruct(obj);
}
else {
SS7PointCode::Type type = SS7PointCode::lookup(stype.c_str());
if (type == SS7PointCode::Other)
level = DebugNote;
setType(type,ni[i]);
for (unsigned int i = 0; i < 4; i++)
setType(type,ni[i]);
}
TelEngine::destruct(obj);
Debug(this,level,"Point code types are '%s' [%p]",stype.safe(),this);
buildRoutes(params);
@ -461,6 +479,53 @@ void SS7MTP3::detach(SS7Layer2* link)
}
}
// Configure and initialize MTP3 and its links
bool SS7MTP3::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"SS7MTP3::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config)
debugLevel(config->getIntValue("debuglevel_mtp3",
config->getIntValue("debuglevel",-1)));
countLinks();
if (config && (0 == m_total)) {
unsigned int n = config->length();
for (unsigned int i = 0; i < n; i++) {
NamedString* param = config->getParam(i);
if (!(param && param->name() == "link"))
continue;
NamedPointer* ptr = YOBJECT(NamedPointer,param);
NamedList* linkConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(param->c_str());
params.addParam("basename",*param);
if (linkConfig)
params.copyParams(*linkConfig);
else
linkConfig = &params;
SS7Layer2* link = YSIGCREATE(SS7Layer2,&params);
if (!link)
continue;
attach(link);
if (!link->initialize(linkConfig)) {
detach(link);
TelEngine::destruct(link);
}
}
}
if (engine() && !user()) {
NamedList params("ss7router");
if (config)
static_cast<String&>(params) = config->getValue("router",params);
if (params.toBoolean(true))
SS7Layer3::attach(YOBJECT(SS7Router,engine()->build("SS7Router",params,true)));
}
return 0 != m_total;
}
// Detach all links and user. Destroys the object, disposes the memory
void SS7MTP3::destroyed()
{

View File

@ -29,10 +29,9 @@
using namespace TelEngine;
SS7Layer4::SS7Layer4()
: m_l3Mutex(true),
m_layer3(0)
: SignallingComponent("SS7Layer4"),
m_l3Mutex(true,"SS7Layer4::layer3"), m_layer3(0)
{
setName("ss7l4");
}
void SS7Layer4::attach(SS7Layer3* network)
@ -59,11 +58,11 @@ void SS7Layer4::attach(SS7Layer3* network)
Debug(this,DebugAll,"Attached network/router (%p,'%s') [%p]",
network,network->toString().safe(),this);
insert(network);
if (network->getObject("SS7Router"))
(static_cast<SS7Router*>(network))->attach(this);
SS7Router* router = YOBJECT(SS7Router,network);
if (router)
router->attach(this);
else
network->attach(this);
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -52,7 +52,7 @@ int main()
NamedList ifdefs("WpInterface");
ifdefs.addParam("card","wanpipe1");
ifdefs.addParam("device","w1g1");
SignallingInterface* iface = static_cast<SignallingInterface*>(SignallingFactory::build(ifdefs,&ifdefs));
SignallingInterface* iface = YSIGCREATE(SignallingInterface,&ifdefs);
if (iface) {
link->SignallingReceiver::attach(iface);
iface->control(SignallingInterface::Enable);

View File

@ -46,11 +46,19 @@ static const char* s_linkSideCpe = "CPE";
#define Q921_TEI_BROADCAST 127 // TEI value for broadcast and management procedures
#define Q921_SAPI_MANAGEMENT 63 // SAPI value for management procedures
inline const char* linkSide(bool net)
static inline const char* linkSide(bool net)
{
return net ? s_linkSideNet : s_linkSideCpe;
}
static inline void fixParams(NamedList& params, const NamedList& config)
{
params.copyParams(config);
int rx = params.getIntValue("rxunderrun");
if ((rx > 0) && (rx < 2500))
params.setParam("rxunderrun","2500");
}
// Drop frame reasons
static const char* s_noState = "Not allowed in this state";
@ -101,7 +109,7 @@ public:
// Constructor. Set data members. Print them
ISDNQ921::ISDNQ921(const NamedList& params, const char* name, ISDNQ921Management* mgmt, u_int8_t tei)
: SignallingComponent(name),
: SignallingComponent(name,&params),
ISDNLayer2(params,name,tei),
SignallingReceiver(name),
SignallingDumpable(SignallingDumper::Q921,network()),
@ -131,8 +139,6 @@ ISDNQ921::ISDNQ921(const NamedList& params, const char* name, ISDNQ921Management
{
if (mgmt && network())
autoRestart(false);
if (!mgmt)
setName(params.getValue("debugname",name));
m_retransTimer.interval(params,"t200",1000,1000,false);
m_idleTimer.interval(params,"t203",2000,10000,false);
// Adjust idle timeout to data link side
@ -145,6 +151,12 @@ ISDNQ921::ISDNQ921(const NamedList& params, const char* name, ISDNQ921Management
if (debugAt(DebugInfo)) {
String tmp;
#ifdef DEBUG
if (debugAt(DebugAll)) {
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"ISDNQ921::ISDNQ921(%p,'%s',%p,%u) [%p]%s",
&params,name,mgmt,tei,this,tmp.c_str());
tmp.clear();
}
tmp << " SAPI/TEI=" << (unsigned int)localSapi() << "/" << (unsigned int)localTei();
tmp << " auto-restart=" << String::boolText(autoRestart());
tmp << " max-user-data=" << (unsigned int)maxUserData();
@ -164,7 +176,7 @@ ISDNQ921::~ISDNQ921()
{
Lock lock(l2Mutex());
ISDNLayer2::attach((ISDNLayer3*)0);
SignallingReceiver::attach(0);
TelEngine::destruct(SignallingReceiver::attach(0));
cleanup();
DDebug(this,DebugAll,
"ISDN Data Link destroyed. Frames: sent=%u (failed=%u) recv=%u rejected=%u dropped=%u. HW errors=%u [%p]",
@ -173,6 +185,49 @@ ISDNQ921::~ISDNQ921()
(unsigned int)m_rxDroppedFrames,(unsigned int)m_hwErrors,this);
}
// Initialize layer, attach interface if not managed
bool ISDNQ921::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"ISDNQ921::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config) {
debugLevel(config->getIntValue("debuglevel_q921",
config->getIntValue("debuglevel",-1)));
setDebug(config->getBoolValue("print-frames",false),
config->getBoolValue("extended-debug",false));
}
if (config && !m_management && !iface()) {
NamedString* name = config->getParam("sig");
if (!name)
name = config->getParam("basename");
if (name) {
NamedPointer* ptr = YOBJECT(NamedPointer,name);
NamedList* ifConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(*name + "/D");
params.addParam("basename",*name);
if (ifConfig)
fixParams(params,*ifConfig);
else
ifConfig = &params;
SignallingInterface* ifc = YSIGCREATE(SignallingInterface,&params);
if (!ifc)
return false;
SignallingReceiver::attach(ifc);
if (ifc->initialize(ifConfig)) {
SignallingReceiver::control(SignallingInterface::Enable);
multipleFrame(0,true,false);
}
else
TelEngine::destruct(SignallingReceiver::attach(0));
}
}
return m_management || iface();
}
// Set or release 'multiple frame acknowledged' mode
bool ISDNQ921::multipleFrame(u_int8_t tei, bool establish, bool force)
{
@ -256,8 +311,6 @@ void ISDNQ921::cleanup()
changeState(Released,"cleanup");
}
YCLASSIMP2(ISDNQ921,ISDNLayer2,SignallingReceiver)
// Method called periodically to check timeouts
// Re-sync with remote peer if necessary
void ISDNQ921::timerTick(const Time& when)
@ -766,7 +819,7 @@ bool ISDNQ921::acceptFrame(ISDNFrame* frame, bool& reject)
!frame->command()) ||
((frame->type() == ISDNFrame::UA || frame->type() == ISDNFrame::DM) &&
frame->command())) {
Debug(this,DebugGoOn,
Debug(this,DebugMild,
"Received '%s': The remote peer has the same data link side type",
frame->name());
frame->m_error = ISDNFrame::ErrInvalidCR;
@ -970,13 +1023,21 @@ void ISDNQ921::timer(bool start, bool t203, u_int64_t time)
*/
// Constructor
ISDNQ921Management::ISDNQ921Management(const NamedList& params, const char* name, bool net)
: ISDNLayer2(params,name),
: SignallingComponent(name,&params),
ISDNLayer2(params,name),
SignallingReceiver(name),
SignallingDumpable(SignallingDumper::Q921,network()),
m_teiManTimer(0), m_teiTimer(0)
{
String baseName = params.getValue("debugname",name);
setName(baseName);
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"ISDNQ921Management::ISDNQ921Management(%p,'%s',%s) [%p]%s",
&params,name,String::boolText(net),this,tmp.c_str());
}
#endif
String baseName = toString();
m_network = net;
m_teiManTimer.interval(params,"t202",2500,2600,false);
m_teiTimer.interval(params,"t201",1000,5000,false);
@ -990,7 +1051,9 @@ ISDNQ921Management::ISDNQ921Management(const NamedList& params, const char* name
for (int i = 0; i < 127; i++) {
if (network() || (i == 0)) {
String qName = baseName;
if (set0 || (i != 0))
if (!network())
qName << "-CPE";
else if (set0 || (i != 0))
qName << "-" << i;
m_layer2[i] = new ISDNQ921(params,qName,this,i);
m_layer2[i]->ISDNLayer2::attach(this);
@ -1008,12 +1071,47 @@ ISDNQ921Management::~ISDNQ921Management()
{
Lock lock(l2Mutex());
ISDNLayer2::attach((ISDNLayer3*)0);
SignallingReceiver::attach(0);
TelEngine::destruct(SignallingReceiver::attach(0));
for (int i = 0; i < 127; i++)
TelEngine::destruct(m_layer2[i]);
}
YCLASSIMP3(ISDNQ921Management,ISDNLayer2,ISDNLayer3,SignallingReceiver)
bool ISDNQ921Management::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"ISDNQ921Management::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config)
debugLevel(config->getIntValue("debuglevel_q921mgmt",
config->getIntValue("debuglevel",-1)));
if (config && !iface()) {
NamedString* name = config->getParam("sig");
if (!name)
name = config->getParam("basename");
if (name) {
NamedPointer* ptr = YOBJECT(NamedPointer,name);
NamedList* ifConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(*name + "/D");
params.addParam("basename",*name);
if (ifConfig)
fixParams(params,*ifConfig);
else
ifConfig = &params;
SignallingInterface* ifc = YSIGCREATE(SignallingInterface,&params);
if (!ifc)
return false;
SignallingReceiver::attach(ifc);
if (ifc->initialize(ifConfig))
SignallingReceiver::control(SignallingInterface::Enable);
else
TelEngine::destruct(SignallingReceiver::attach(0));
}
}
return 0 != iface();
}
void ISDNQ921Management::engine(SignallingEngine* eng)
{
@ -1387,7 +1485,8 @@ void ISDNQ921Management::processTeiVerify(u_int8_t ai, bool pf)
*/
// Constructor. Set data members. Print them
ISDNQ921Passive::ISDNQ921Passive(const NamedList& params, const char* name)
: ISDNLayer2(params,name),
: SignallingComponent(name,&params),
ISDNLayer2(params,name),
SignallingReceiver(name),
SignallingDumpable(SignallingDumper::Q921,network()),
m_checkLinkSide(false),
@ -1401,7 +1500,14 @@ ISDNQ921Passive::ISDNQ921Passive(const NamedList& params, const char* name)
m_extendedDebug(false),
m_errorReceive(false)
{
setName(params.getValue("debugname",name));
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"ISDNQ921Passive::ISDNQ921Passive(%p,'%s') [%p]%s",
&params,name,this,tmp.c_str());
}
#endif
m_idleTimer.interval(params,"idletimeout",4000,30000,false);
m_checkLinkSide = detectType();
setDebug(params.getBoolValue("print-frames",false),
@ -1421,7 +1527,7 @@ ISDNQ921Passive::~ISDNQ921Passive()
{
Lock lock(l2Mutex());
ISDNLayer2::attach(0);
SignallingReceiver::attach(0);
TelEngine::destruct(SignallingReceiver::attach(0));
cleanup();
DDebug(this,DebugAll,
"ISDN Passive Data Link destroyed. Frames: recv=%u rejected=%u dropped=%u. HW errors=%u [%p]",
@ -1429,6 +1535,47 @@ ISDNQ921Passive::~ISDNQ921Passive()
(unsigned int)m_rxDroppedFrames,(unsigned int)m_hwErrors,this);
}
bool ISDNQ921Passive::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"ISDNQ921Passive::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config) {
debugLevel(config->getIntValue("debuglevel_q921",
config->getIntValue("debuglevel",-1)));
setDebug(config->getBoolValue("print-frames",false),
config->getBoolValue("extended-debug",false));
}
if (config && !iface()) {
NamedString* name = config->getParam("sig");
if (!name)
name = config->getParam("basename");
if (name) {
NamedPointer* ptr = YOBJECT(NamedPointer,name);
NamedList* ifConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(*name + "/D");
params.addParam("basename",*name);
params.addParam("readonly",String::boolText(true));
if (ifConfig)
fixParams(params,*ifConfig);
else
ifConfig = &params;
SignallingInterface* ifc = YSIGCREATE(SignallingInterface,&params);
if (!ifc)
return false;
SignallingReceiver::attach(ifc);
if (ifc->initialize(ifConfig))
SignallingReceiver::control(SignallingInterface::Enable);
else
TelEngine::destruct(SignallingReceiver::attach(0));
}
}
return 0 != iface();
}
// Reset data
void ISDNQ921Passive::cleanup()
{
@ -1436,8 +1583,6 @@ void ISDNQ921Passive::cleanup()
m_idleTimer.start();
}
YCLASSIMP2(ISDNQ921Passive,ISDNLayer2,SignallingReceiver)
// Called periodically by the engine to check timeouts
// Check idle timer. Notify upper layer on timeout
void ISDNQ921Passive::timerTick(const Time& when)
@ -1546,7 +1691,7 @@ bool ISDNQ921Passive::acceptFrame(ISDNFrame* frame, bool& cmd, bool& value)
changeType();
}
else {
Debug(this,DebugGoOn,
Debug(this,DebugMild,
"Received '%s': The remote peer has the same data link side type",
frame->name());
return dropFrame(frame,ISDNFrame::typeName(ISDNFrame::ErrInvalidCR));
@ -1595,10 +1740,10 @@ TokenDict ISDNLayer2::m_states[] = {
};
ISDNLayer2::ISDNLayer2(const NamedList& params, const char* name, u_int8_t tei)
: SignallingComponent(name),
: SignallingComponent(name,&params),
m_layer3(0),
m_layerMutex(true),
m_layer3Mutex(true),
m_layerMutex(true,"ISDNLayer2::layer"),
m_layer3Mutex(true,"ISDNLayer2::layer3"),
m_state(Released),
m_network(false),
m_detectType(false),
@ -1643,16 +1788,14 @@ void ISDNLayer2::attach(ISDNLayer3* layer3)
m_layer3 = layer3;
lock.drop();
if (tmp) {
const char* name = 0;
if (engine() && engine()->find(tmp)) {
name = tmp->toString().safe();
if (engine() && engine()->find(tmp))
tmp->attach(0);
}
DDebug(this,DebugAll,"Detached L3 (%p,'%s') [%p]",tmp,name,this);
Debug(this,DebugAll,"Detached L3 (%p,'%s') [%p]",
tmp,tmp->toString().safe(),this);
}
if (!layer3)
return;
DDebug(this,DebugAll,"Attached L3 (%p,'%s') [%p]",layer3,layer3->toString().safe(),this);
Debug(this,DebugAll,"Attached L3 (%p,'%s') [%p]",layer3,layer3->toString().safe(),this);
insert(layer3);
layer3->attach(this);
}

View File

@ -735,7 +735,7 @@ ISDNQ931Call::ISDNQ931Call(ISDNQ931* controller, bool outgoing,
m_data.m_reason = "temporary-failure";
return;
}
m_net = q931() && q931()->m_q921 && q931()->m_q921->network();
m_net = q931() && q931()->network();
// Init timers
q931()->setInterval(m_discTimer,305);
q931()->setInterval(m_relTimer,308);
@ -759,7 +759,7 @@ ISDNQ931Call::~ISDNQ931Call()
// Set terminate flags and reason
void ISDNQ931Call::setTerminate(bool destroy, const char* reason)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (m_destroyed)
return;
if (state() == CallAbort)
@ -780,7 +780,7 @@ bool ISDNQ931Call::sendEvent(SignallingEvent* event)
{
if (!event)
return false;
Lock lock(m_callMutex);
Lock mylock(this);
DDebug(q931(),DebugAll,"Call(%u,%u). sendEvent(%s) state=%s [%p]",
Q931_CALL_ID,event->name(),stateName(state()),this);
if (m_terminate || state() == CallAbort) {
@ -855,7 +855,7 @@ bool ISDNQ931Call::sendEvent(SignallingEvent* event)
// Get events from reserved circuit when no call event
SignallingEvent* ISDNQ931Call::getEvent(const Time& when)
{
Lock lock(m_callMutex);
Lock mylock(this);
// Check for last event or destroyed/aborting
if (m_lastEvent || m_destroyed || state() == CallAbort)
return 0;
@ -951,7 +951,7 @@ void* ISDNQ931Call::getObject(const String& name) const
// Set termination flag. Send status if link is up
void ISDNQ931Call::dataLinkState(bool up)
{
Lock lock(m_callMutex);
Lock mylock(this);
// Q.931 5.8.9. Terminate if not up and not in the active state
if (!up) {
if (state() != ISDNQ931Call::Active)
@ -1736,7 +1736,7 @@ bool ISDNQ931Call::sendSetupAck()
SignallingEvent* ISDNQ931Call::releaseComplete(const char* reason, const char* diag)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (m_destroyed)
return 0;
if (reason)
@ -1930,7 +1930,7 @@ ISDNQ931CallMonitor::~ISDNQ931CallMonitor()
// Get an event from this monitor
SignallingEvent* ISDNQ931CallMonitor::getEvent(const Time& when)
{
Lock lock(m_callMutex);
Lock mylock(this);
// Check for last event or aborting
if (m_lastEvent || state() == CallAbort)
return 0;
@ -1982,7 +1982,7 @@ SignallingEvent* ISDNQ931CallMonitor::getEvent(const Time& when)
// Set termination flag
void ISDNQ931CallMonitor::setTerminate(const char* reason)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (state() == CallAbort)
changeState(Null);
// Check terminate & destroy flags
@ -2136,7 +2136,7 @@ SignallingEvent* ISDNQ931CallMonitor::processMsgInfo(ISDNQ931Message* msg)
// Release monitor
SignallingEvent* ISDNQ931CallMonitor::releaseComplete(const char* reason)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (state() == Null)
return 0;
if (reason)
@ -2316,15 +2316,14 @@ TokenDict ISDNQ931::s_swType[] = {
{0,0}
};
YCLASSIMP(ISDNQ931,ISDNLayer3)
ISDNQ931::ISDNQ931(const NamedList& params, const char* name)
: SignallingComponent(name),
: SignallingComponent(name,&params),
SignallingCallControl(params,"isdn."),
SignallingDumpable(SignallingDumper::Q931),
ISDNLayer3(name),
m_q921(0),
m_q921Up(false),
m_networkHint(true),
m_primaryRate(true),
m_transferModeCircuit(true),
m_callRef(1),
@ -2348,9 +2347,18 @@ ISDNQ931::ISDNQ931(const NamedList& params, const char* name)
m_flagQ921Down(false),
m_flagQ921Invalid(false)
{
setName(params.getValue("debugname",name));
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"ISDNQ931::ISDNQ931(%p,'%s') [%p]%s",
&params,name,this,tmp.c_str());
}
#endif
m_parserData.m_dbg = this;
m_callRefLen = params.getIntValue("callreflen",2);
m_networkHint = params.getBoolValue("network",m_networkHint);
m_data.m_bri = !(m_primaryRate = params.getBoolValue("primary",m_primaryRate));
m_callRefLen = params.getIntValue("callreflen",m_primaryRate ? 2 : 1);
if (m_callRefLen < 1 || m_callRefLen > 4)
m_callRefLen = 2;
// Set mask. Bit 7 of the first byte of the message header it's used for initiator flag
@ -2383,9 +2391,9 @@ ISDNQ931::ISDNQ931(const NamedList& params, const char* name)
setDebug(params.getBoolValue("print-messages",false),
params.getBoolValue("extended-debug",false));
if (debugAt(DebugInfo)) {
String s;
String s(network() ? "NET" : "CPE");
#ifdef DEBUG
s << "type=" << lookup(m_parserData.m_flags,s_swType,"Custom");
s << " type=" << lookup(m_parserData.m_flags,s_swType,"Custom");
String t;
for (TokenDict* p = s_flags; p->token; p++)
if (m_parserData.flag(p->value))
@ -2406,7 +2414,7 @@ ISDNQ931::ISDNQ931(const NamedList& params, const char* name)
s << " segmentation=" << String::boolText(m_parserData.m_allowSegment);
s << " max-segments=" << (unsigned int)m_parserData.m_maxSegments;
#else
s << "type=" << params.getValue("switchtype");
s << " type=" << params.getValue("switchtype");
s << " pri=" << String::boolText(m_primaryRate);
s << " format=" << m_format;
s << " channelsync=" << String::boolText(0 != m_syncGroupTimer.interval());
@ -2423,10 +2431,54 @@ ISDNQ931::~ISDNQ931()
cleanup();
m_calls.clear();
}
attach((ISDNLayer2*)0);
TelEngine::destruct(attach((ISDNLayer2*)0));
TelEngine::destruct(SignallingCallControl::attach(0));
DDebug(this,DebugAll,"ISDN Call Controller destroyed [%p]",this);
}
// Initialize Q.931 and attach a layer 2
bool ISDNQ931::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"ISDNQ931::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config) {
debugLevel(config->getIntValue("debuglevel_q931",
config->getIntValue("debuglevel",-1)));
setDebug(config->getBoolValue("print-messages",false),
config->getBoolValue("extended-debug",false));
}
if (config && !layer2()) {
const String* name = config->getParam("sig");
if (!name)
name = config;
if (!TelEngine::null(name)) {
NamedPointer* ptr = YOBJECT(NamedPointer,name);
NamedList* linkConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(*name + "/Q921");
params.addParam("basename",*name);
params.addParam("primary",String::boolText(primaryRate()));
params.addParam("network",String::boolText(network()));
if (linkConfig)
params.copyParams(*linkConfig);
else
linkConfig = &params;
ISDNLayer2* l2 = YSIGCREATE(ISDNLayer2,&params);
if (!l2) {
Debug(this,DebugWarn,"Could not create ISDN Layer 2 '%s' [%p]",name->c_str(),this);
return false;
}
attach(l2);
if (!l2->initialize(linkConfig))
TelEngine::destruct(attach((ISDNLayer2*)0));
}
}
return 0 != layer2();
}
// Check if layer 2 may be up
bool ISDNQ931::q921Up() const
{
@ -2435,7 +2487,7 @@ bool ISDNQ931::q921Up() const
if (m_q921Up)
return true;
// Assume BRI NET is always up
return !primaryRate() && m_q921->network();
return !primaryRate() && network();
}
// Send a message to layer 2
@ -2620,7 +2672,7 @@ void ISDNQ931::receiveData(const DataBlock& data, u_int8_t tei, ISDNLayer2* laye
}
// Check if it is a new incoming call
if (msg->initiator() && msg->type() == ISDNQ931Message::Setup) {
if (!primaryRate() && m_cpeNumber && m_q921 && !m_q921->network()) {
if (!primaryRate() && m_cpeNumber && !network()) {
// We are a BRI CPE with a number - check the called party field
ISDNQ931IE* ie = msg->getIE(ISDNQ931IE::CalledNo);
if (ie) {
@ -2654,11 +2706,11 @@ void ISDNQ931::receiveData(const DataBlock& data, u_int8_t tei, ISDNLayer2* laye
// Attach layer 2
// Update some data from the attached object
void ISDNQ931::attach(ISDNLayer2* q921)
ISDNLayer2* ISDNQ931::attach(ISDNLayer2* q921)
{
Lock lock(l3Mutex());
if (m_q921 == q921)
return;
return 0;
cleanup(q921 ? "layer 2 attach" : "layer 2 detach");
ISDNLayer2* tmp = m_q921;
m_q921 = q921;
@ -2704,20 +2756,25 @@ void ISDNQ931::attach(ISDNLayer2* q921)
}
lock.drop();
if (tmp) {
const char* name = 0;
if (engine() && engine()->find(tmp)) {
name = tmp->toString().safe();
if (tmp->layer3() == this) {
Debug(this,DebugAll,"Detaching L2 (%p,'%s') [%p]",
tmp,tmp->toString().safe(),this);
tmp->attach(0);
}
Debug(this,DebugAll,"Detached L2 (%p,'%s') [%p]",tmp,name,this);
else {
Debug(this,DebugNote,"Layer 2 (%p,'%s') was not attached to us [%p]",
tmp,tmp->toString().safe(),this);
tmp = 0;
}
}
if (!q921)
return;
return tmp;
Debug(this,DebugAll,"Attached L2 '%s' (%p,'%s') [%p]",
(q921->network() ? "NET" : "CPE"),
q921,q921->toString().safe(),this);
insert(q921);
q921->attach(this);
return tmp;
}
// Make an outgoing call from a given message
@ -3332,37 +3389,82 @@ bool ISDNQ931::sendRelease(bool release, u_int8_t callRefLen, u_int32_t callRef,
* ISDNQ931Monitor
*/
ISDNQ931Monitor::ISDNQ931Monitor(const NamedList& params, const char* name)
: SignallingCallControl(params,"isdn."),
ISDNLayer3(name),
m_q921Net(0),
m_q921Cpe(0),
m_cicNet(0),
m_cicCpe(0),
m_parserData(params),
m_printMsg(true),
m_extendedDebug(false)
: SignallingComponent(name,&params),
SignallingCallControl(params,"isdn."),
ISDNLayer3(name),
m_q921Net(0), m_q921Cpe(0), m_cicNet(0), m_cicCpe(0),
m_parserData(params),
m_printMsg(true), m_extendedDebug(false)
{
setName(params.getValue("debugname",name));
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"ISDNQ931Monitor::ISDNQ931Monitor(%p,'%s') [%p]%s",
&params,name,this,tmp.c_str());
}
#endif
// Set parser data. Accept maximum data length
m_parserData.m_maxMsgLen = 0xffffffff;
m_parserData.m_dbg = this;
// Debug
setDebug(params.getBoolValue("print-messages",true),
params.getBoolValue("extended-debug",false));
Debug(this,DebugAll,"ISDN Monitor created [%p]",this);
}
ISDNQ931Monitor::~ISDNQ931Monitor()
{
terminateMonitor(0,0);
attach((ISDNQ921Passive*)0,true);
attach((ISDNQ921Passive*)0,false);
attach((SignallingCircuitGroup*)0,true);
attach((SignallingCircuitGroup*)0,false);
TelEngine::destruct(attach((ISDNQ921Passive*)0,true));
TelEngine::destruct(attach((ISDNQ921Passive*)0,false));
TelEngine::destruct(attach((SignallingCircuitGroup*)0,true));
TelEngine::destruct(attach((SignallingCircuitGroup*)0,false));
m_calls.clear();
DDebug(this,DebugAll,"ISDN Monitor destroyed [%p]",this);
}
// Initialize the monitor and attach both passive layer 2
bool ISDNQ931Monitor::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"ISDNQ931Monitor::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config) {
debugLevel(config->getIntValue("debuglevel_q931",
config->getIntValue("debuglevel",-1)));
setDebug(config->getBoolValue("print-messages",false),
config->getBoolValue("extended-debug",false));
for (int i = 0; i <= 1; i++) {
bool net = (0 == i);
if (net && m_q921Net)
continue;
if (!net && m_q921Cpe)
continue;
NamedString* name = config->getParam(net ? "sig-net" : "sig-cpe");
if (name) {
NamedPointer* ptr = YOBJECT(NamedPointer,name);
NamedList* linkConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(name->c_str());
params.addParam("basename",*name);
if (linkConfig)
params.copyParams(*linkConfig);
else
linkConfig = &params;
ISDNQ921Passive* l2 = YSIGCREATE(ISDNQ921Passive,&params);
if (!l2)
return false;
attach(l2,net);
if (!l2->initialize(linkConfig))
TelEngine::destruct(attach((ISDNQ921Passive*)0,net));
}
}
}
return m_q921Net && m_q921Cpe;
}
// Notification from layer 2 of data link set/release command or response
void ISDNQ931Monitor::dataLinkState(u_int8_t tei, bool cmd, bool value, ISDNLayer2* layer2)
{
@ -3446,64 +3548,64 @@ void ISDNQ931Monitor::receiveData(const DataBlock& data, u_int8_t tei, ISDNLayer
}
// Attach ISDN Q.921 pasive transport that monitors one side of the link
void ISDNQ931Monitor::attach(ISDNQ921Passive* q921, bool net)
ISDNQ921Passive* ISDNQ931Monitor::attach(ISDNQ921Passive* q921, bool net)
{
Lock lock(l3Mutex());
ISDNQ921Passive* which = net ? m_q921Net : m_q921Cpe;
// Yes, this is a reference to a pointer
ISDNQ921Passive*& which = net ? m_q921Net : m_q921Cpe;
// Make no change if same transport
if (which == q921)
return;
return 0;
terminateMonitor(0,q921 ? "layer 2 attach" : "layer 2 detach");
ISDNQ921Passive* tmp = which;
if (net)
m_q921Net = q921;
else
m_q921Cpe = q921;
which = q921;
lock.drop();
const char* type = net ? "NET" : "CPE";
if (tmp) {
const char* name = 0;
if (engine() && engine()->find(tmp)) {
name = tmp->toString().safe();
static_cast<ISDNLayer2*>(tmp)->attach((ISDNLayer3*)0);
if (tmp->layer3() == this) {
Debug(this,DebugAll,"Detaching L2 %s (%p,'%s') [%p]",
type,tmp,tmp->toString().safe(),this);
static_cast<ISDNLayer2*>(tmp)->attach(0);
}
else {
Debug(this,DebugNote,"Layer 2 %s (%p,'%s') was not attached to us [%p]",
type,tmp,tmp->toString().safe(),this);
tmp = 0;
}
Debug(this,DebugAll,"Detached L2 %s (%p,'%s') [%p]",net?"NET":"CPE",tmp,name,this);
}
if (!q921)
return;
return tmp;
Debug(this,DebugAll,"Attached L2 %s (%p,'%s') [%p]",
net?"NET":"CPE",q921,q921->toString().safe(),this);
type,q921,q921->toString().safe(),this);
insert(q921);
q921->ISDNLayer2::attach(this);
return tmp;
}
// Attach a circuit group to this call controller
void ISDNQ931Monitor::attach(SignallingCircuitGroup* circuits, bool net)
SignallingCircuitGroup* ISDNQ931Monitor::attach(SignallingCircuitGroup* circuits, bool net)
{
Lock lock(l3Mutex());
// Yes, this is a reference to a pointer
SignallingCircuitGroup*& which = net ? m_cicNet : m_cicCpe;
SignallingCircuitGroup* tmp = which;
// Don't attach if it's the same object
SignallingCircuitGroup* tmp = net ? m_cicNet : m_cicCpe;
if (tmp == circuits)
return;
return 0;
terminateMonitor(0,circuits ? "circuit group attach" : "circuit group detach");
if (tmp && circuits)
if (tmp && circuits) {
Debug(this,DebugNote,
"Attached circuit group (%p) '%s' while we already have one (%p) '%s'",
circuits,circuits->debugName(),tmp,tmp->debugName());
else if (circuits && !tmp)
DDebug(this,DebugAll,"Circuit group (%p) '%s' attached",circuits,circuits->debugName());
else if (tmp && !circuits)
DDebug(this,DebugAll,"Circuit group (%p) '%s' detached",tmp,tmp->debugName());
if (net)
m_cicNet = circuits;
}
#ifdef DEBUG
else if (circuits)
Debug(this,DebugAll,"Circuit group (%p) '%s' attached",circuits,circuits->debugName());
else
m_cicCpe = circuits;
}
// Get a pointer to this call controller
void* ISDNQ931Monitor::getObject(const String& name) const
{
if (name == "ISDNQ931Monitor")
return (void*)this;
return SignallingComponent::getObject(name);
Debug(this,DebugAll,"Circuit group (%p) '%s' detached",tmp,tmp->debugName());
#endif
which = circuits;
return tmp;
}
// Method called periodically to check timeouts

View File

@ -115,9 +115,66 @@ int SS7Route::transmitMSU(const SS7Router* router, const SS7MSU& msu,
* SS7Router
*/
SS7Router::SS7Router(const NamedList& params)
: Mutex(true), m_changes(0)
: SignallingComponent(params.safe("SS7Router"),&params),
Mutex(true,"SS7Router"), m_changes(0)
{
setName("ss7router");
#ifdef DEBUG
if (debugAt(DebugAll)) {
String tmp;
params.dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugAll,"SS7Router::SS7Router(%p) [%p]%s",
&params,this,tmp.c_str());
}
#endif
}
bool SS7Router::initialize(const NamedList* config)
{
#ifdef DEBUG
String tmp;
if (config && debugAt(DebugAll))
config->dump(tmp,"\r\n ",'\'',true);
Debug(this,DebugInfo,"SS7Router::initialize(%p) [%p]%s",config,this,tmp.c_str());
#endif
if (config) {
debugLevel(config->getIntValue("debuglevel_router",
config->getIntValue("debuglevel",-1)));
const String* param = config->getParam("management");
const char* name = "ss7snm";
if (param)
name = param->c_str();
else
param = config;
if (param->toBoolean(true)) {
NamedPointer* ptr = YOBJECT(NamedPointer,param);
NamedList* mConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(name);
params.addParam("basename",name);
if (mConfig)
params.copyParams(*mConfig);
else
mConfig = &params;
attach(YSIGCREATE(SS7Management,&params));
}
param = config->getParam("maintenance");
name = "ss7mtn";
if (param)
name = param->c_str();
else
param = config;
if (param->toBoolean(true)) {
NamedPointer* ptr = YOBJECT(NamedPointer,param);
NamedList* mConfig = ptr ? YOBJECT(NamedList,ptr->userData()) : 0;
NamedList params(name);
params.addParam("basename",name);
if (mConfig)
params.copyParams(*mConfig);
else
mConfig = &params;
attach(YSIGCREATE(SS7Maintenance,&params));
}
}
return true;
}
bool SS7Router::operational(int sls) const
@ -224,14 +281,6 @@ void SS7Router::detach(SS7Layer4* service)
}
}
void* SS7Router::getObject(const String& name) const
{
if (name == "SS7Router")
return (void*)this;
void* p = SS7L3User::getObject(name);
return p ? p : SS7Layer3::getObject(name);
}
int SS7Router::transmitMSU(const SS7MSU& msu, const SS7Label& label, int sls)
{
XDebug(this,DebugStub,"Possibly incomplete SS7Router::transmitMSU(%p,%p,%d)",

View File

@ -48,12 +48,12 @@ TokenDict SignallingCircuit::s_lockNames[] = {
*/
SignallingCallControl::SignallingCallControl(const NamedList& params,
const char* msgPrefix)
: Mutex(true),
m_verifyEvent(false),
m_verifyTimer(0),
m_circuits(0),
m_strategy(SignallingCircuitGroup::Increment),
m_exiting(false)
: Mutex(true,"SignallingCallControl"),
m_verifyEvent(false),
m_verifyTimer(0),
m_circuits(0),
m_strategy(SignallingCircuitGroup::Increment),
m_exiting(false)
{
// Strategy
const char* strategy = params.getValue("strategy","increment");
@ -86,29 +86,31 @@ SignallingCallControl::~SignallingCallControl()
}
// Attach a signalling circuit group. Set its strategy
void SignallingCallControl::attach(SignallingCircuitGroup* circuits)
SignallingCircuitGroup* SignallingCallControl::attach(SignallingCircuitGroup* circuits)
{
Lock lock(this);
Lock mylock(this);
// Don't attach if it's the same object
if (m_circuits == circuits)
return;
return 0;
cleanup(circuits ? "circuit group attach" : "circuit group detach");
if (m_circuits && circuits)
Debug(DebugNote,
"SignallingCallControl. Replaced circuit group (%p) with (%p) [%p]",
"SignallingCallControl. Replacing circuit group (%p) with (%p) [%p]",
m_circuits,circuits,this);
SignallingCircuitGroup* tmp = m_circuits;
m_circuits = circuits;
if (m_circuits) {
Lock lock(m_circuits);
m_circuits->setStrategy(m_strategy);
}
return tmp;
}
// Reserve a circuit from a given list in attached group
bool SignallingCallControl::reserveCircuit(SignallingCircuit*& cic, const char* range,
int checkLock, const String* list, bool mandatory, bool reverseRestrict)
{
Lock lock(this);
Lock mylock(this);
releaseCircuit(cic);
if (!m_circuits)
return false;
@ -143,7 +145,7 @@ bool SignallingCallControl::releaseCircuit(SignallingCircuit*& cic, bool sync)
bool SignallingCallControl::releaseCircuit(unsigned int code, bool sync)
{
Lock lock(this);
Lock mylock(this);
SignallingCircuit* cic = m_circuits ? m_circuits->find(code) : 0;
if (!cic)
return false;
@ -232,29 +234,29 @@ void SignallingCallControl::removeCall(SignallingCall* call, bool del)
* SignallingCall
*/
SignallingCall::SignallingCall(SignallingCallControl* controller, bool outgoing, bool signalOnly)
: m_callMutex(true),
: Mutex(true,"SignallingCall"),
m_lastEvent(0),
m_controller(controller),
m_outgoing(outgoing),
m_signalOnly(signalOnly),
m_inMsgMutex(true),
m_inMsgMutex(true,"SignallingCall::inMsg"),
m_private(0)
{
}
SignallingCall::~SignallingCall()
{
m_callMutex.lock();
lock();
m_inMsg.clear();
if (m_controller)
m_controller->removeCall(this,false);
m_callMutex.unlock();
unlock();
}
// Event termination notification
void SignallingCall::eventTerminated(SignallingEvent* event)
{
Lock lock(m_callMutex);
Lock mylock(this);
if (!m_lastEvent || !event || m_lastEvent != event)
return;
XDebug(DebugAll,"SignallingCall. Event (%p,'%s') terminated [%p]",event,event->name(),this);
@ -401,28 +403,22 @@ static TokenDict s_cicStatusDict[] = {
SignallingCircuit::SignallingCircuit(Type type, unsigned int code,
SignallingCircuitGroup* group, SignallingCircuitSpan* span)
: m_mutex(true),
m_group(group),
m_span(span),
m_code(code),
m_type(type),
m_status(Disabled),
m_lock(0),
m_lastEvent(0)
: m_mutex(true,"SignallingCircuit::operations"),
m_group(group), m_span(span),
m_code(code), m_type(type),
m_status(Disabled),
m_lock(0), m_lastEvent(0)
{
XDebug(m_group,DebugAll,"SignallingCircuit::SignallingCircuit [%p]",this);
}
SignallingCircuit::SignallingCircuit(Type type, unsigned int code, Status status,
SignallingCircuitGroup* group, SignallingCircuitSpan* span)
: m_mutex(true),
m_group(group),
m_span(span),
m_code(code),
m_type(type),
m_status(status),
m_lock(0),
m_lastEvent(0)
: m_mutex(true,"SignallingCircuit::operations"),
m_group(group), m_span(span),
m_code(code), m_type(type),
m_status(status),
m_lock(0), m_lastEvent(0)
{
XDebug(m_group,DebugAll,"SignallingCircuit::SignallingCircuit [%p]",this);
}
@ -530,13 +526,12 @@ const char* SignallingCircuit::lookupStatus(int status)
/**
* SignallingCircuitRange
*/
SignallingCircuitRange::SignallingCircuitRange(const String& rangeStr, const char* name,
int strategy)
SignallingCircuitRange::SignallingCircuitRange(const String& rangeStr,
const char* name, int strategy)
: String(name),
m_count(0),
m_last(0),
m_strategy(strategy),
m_used(0)
m_count(0), m_last(0),
m_strategy(strategy),
m_used(0)
{
add(rangeStr);
}
@ -607,13 +602,11 @@ TokenDict SignallingCircuitGroup::s_strategy[] = {
{0,0}
};
YCLASSIMP(SignallingCircuitGroup,SignallingComponent)
SignallingCircuitGroup::SignallingCircuitGroup(unsigned int base, int strategy, const char* name)
: SignallingComponent(name),
Mutex(true),
m_range(String::empty(),name,strategy),
m_base(base)
Mutex(true,"SignallingCircuitGroup"),
m_range(String::empty(),name,strategy),
m_base(base)
{
setName(name);
XDebug(this,DebugAll,"SignallingCircuitGroup::SignallingCircuitGroup() [%p]",this);
@ -635,7 +628,7 @@ SignallingCircuit* SignallingCircuitGroup::find(unsigned int cic, bool local)
return 0;
cic -= m_base;
}
Lock lock(this);
Lock mylock(this);
if (cic >= m_range.m_last)
return 0;
ObjList* l = m_circuits.skipNull();
@ -650,7 +643,7 @@ SignallingCircuit* SignallingCircuitGroup::find(unsigned int cic, bool local)
// Find a range of circuits owned by this group
SignallingCircuitRange* SignallingCircuitGroup::findRange(const char* name)
{
Lock lock(this);
Lock mylock(this);
ObjList* obj = m_ranges.find(name);
return obj ? static_cast<SignallingCircuitRange*>(obj->get()) : 0;
}
@ -658,7 +651,7 @@ SignallingCircuitRange* SignallingCircuitGroup::findRange(const char* name)
void SignallingCircuitGroup::getCicList(String& dest)
{
dest = "";
Lock lock(this);
Lock mylock(this);
for (ObjList* l = m_circuits.skipNull(); l; l = l->skipNext()) {
SignallingCircuit* c = static_cast<SignallingCircuit*>(l->get());
dest.append(String(c->code()),",");
@ -670,7 +663,7 @@ bool SignallingCircuitGroup::insert(SignallingCircuit* circuit)
{
if (!circuit)
return false;
Lock lock(this);
Lock mylock(this);
if (m_circuits.find(circuit) || find(circuit->code(),true))
return false;
circuit->m_group = this;
@ -684,7 +677,7 @@ void SignallingCircuitGroup::remove(SignallingCircuit* circuit)
{
if (!circuit)
return;
Lock lock(this);
Lock mylock(this);
if (!m_circuits.remove(circuit,false))
return;
circuit->m_group = 0;
@ -697,12 +690,34 @@ bool SignallingCircuitGroup::insertSpan(SignallingCircuitSpan* span)
{
if (!span)
return false;
Lock lock(this);
Lock mylock(this);
if (!m_spans.find(span))
m_spans.append(span);
return true;
}
SignallingCircuitSpan* SignallingCircuitGroup::buildSpan(const String& name, unsigned int start)
{
// Local class used to pass the circuit group pointer to the span
class VoiceParams : public NamedList
{
public:
inline VoiceParams(const char* name, SignallingCircuitGroup* group)
: NamedList(name), m_group(group)
{ }
virtual void* getObject(const String& name) const
{ return (name == "SignallingCircuitGroup") ? m_group : NamedList::getObject(name); }
SignallingCircuitGroup* m_group;
};
VoiceParams params(debugName(),this);
params << "/" << name;
params.addParam("voice",name);
if (start)
params.addParam("start",String(start));
return YSIGCREATE(SignallingCircuitSpan,&params);
}
// Build and insert a range from circuits belonging to a given span
void SignallingCircuitGroup::insertRange(SignallingCircuitSpan* span, const char* name,
int strategy)
@ -711,14 +726,14 @@ void SignallingCircuitGroup::insertRange(SignallingCircuitSpan* span, const char
return;
if (!name)
name = span->id();
Lock lock(this);
Lock mylock(this);
String tmp;
for (ObjList* o = m_circuits.skipNull(); o; o = o->skipNext()) {
SignallingCircuit* c = static_cast<SignallingCircuit*>(o->get());
if (span == c->span())
tmp.append(String(c->code()),",");
}
lock.drop();
mylock.drop();
insertRange(tmp,name,strategy);
}
@ -726,7 +741,7 @@ void SignallingCircuitGroup::insertRange(SignallingCircuitSpan* span, const char
void SignallingCircuitGroup::insertRange(const String& range, const char* name,
int strategy)
{
Lock lock(this);
Lock mylock(this);
if (findRange(name))
return;
if (strategy < 0)
@ -740,7 +755,7 @@ void SignallingCircuitGroup::removeSpan(SignallingCircuitSpan* span, bool delCic
{
if (!span)
return;
Lock lock(this);
Lock mylock(this);
if (delCics)
removeSpanCircuits(span);
m_spans.remove(span,delSpan);
@ -751,7 +766,7 @@ void SignallingCircuitGroup::removeSpanCircuits(SignallingCircuitSpan* span)
{
if (!span)
return;
Lock lock(this);
Lock mylock(this);
ListIterator iter(m_circuits);
for (GenObject* obj = 0; (obj = iter.get());) {
SignallingCircuit* c = static_cast<SignallingCircuit*>(obj);
@ -765,7 +780,7 @@ void SignallingCircuitGroup::removeSpanCircuits(SignallingCircuitSpan* span)
// Get the status of a circuit given by its code
SignallingCircuit::Status SignallingCircuitGroup::status(unsigned int cic)
{
Lock lock(this);
Lock mylock(this);
SignallingCircuit* circuit = find(cic);
return circuit ? circuit->status() : SignallingCircuit::Missing;
}
@ -774,7 +789,7 @@ SignallingCircuit::Status SignallingCircuitGroup::status(unsigned int cic)
bool SignallingCircuitGroup::status(unsigned int cic, SignallingCircuit::Status newStat,
bool sync)
{
Lock lock(this);
Lock mylock(this);
SignallingCircuit* circuit = find(cic);
return circuit && circuit->status(newStat,sync);
}
@ -820,7 +835,7 @@ unsigned int SignallingCircuitGroup::advance(unsigned int n, int strategy,
SignallingCircuit* SignallingCircuitGroup::reserve(int checkLock, int strategy,
SignallingCircuitRange* range)
{
Lock lock(this);
Lock mylock(this);
if (!range)
range = &m_range;
if (range->m_last < 1)
@ -875,7 +890,7 @@ SignallingCircuit* SignallingCircuitGroup::reserve(int checkLock, int strategy,
if (n == start)
break;
}
lock.drop();
mylock.drop();
if (strategy & Fallback) {
if (strategy & OnlyEven) {
Debug(this,DebugNote,"No even circuits available, falling back to odd [%p]",this);
@ -894,7 +909,7 @@ SignallingCircuit* SignallingCircuitGroup::reserve(int checkLock, int strategy,
SignallingCircuit* SignallingCircuitGroup::reserve(const String& list, bool mandatory,
int checkLock, int strategy, SignallingCircuitRange* range)
{
Lock lock(this);
Lock mylock(this);
if (!range)
range = &m_range;
// Check if any of the given circuits are free
@ -932,7 +947,7 @@ SignallingCircuit* SignallingCircuitGroup::reserve(const String& list, bool mand
// Clear data
void SignallingCircuitGroup::clearAll()
{
Lock lock(this);
Lock mylock(this);
// Remove spans and their circuits
ListIterator iter(m_spans);
for (GenObject* obj = 0; (obj = iter.get());)
@ -953,8 +968,8 @@ void SignallingCircuitGroup::clearAll()
* SignallingCircuitSpan
*/
SignallingCircuitSpan::SignallingCircuitSpan(const char* id, SignallingCircuitGroup* group)
: m_group(group),
m_id(id)
: SignallingComponent(id),
m_group(group), m_increment(0), m_id(id)
{
if (m_group)
m_group->insertSpan(this);
@ -1018,7 +1033,7 @@ inline u_int64_t getValidInt(const NamedList& params, const char* param, int def
// Reserve the line's circuit
AnalogLine::AnalogLine(AnalogLineGroup* grp, unsigned int cic, const NamedList& params)
: Mutex(true),
: Mutex(true,"AnalogLine"),
m_type(Unknown),
m_state(Idle),
m_inband(false),
@ -1095,7 +1110,7 @@ AnalogLine::~AnalogLine()
// Remove old peer's peer. Set this line's peer
void AnalogLine::setPeer(AnalogLine* line, bool sync)
{
Lock lock(this);
Lock mylock(this);
if (line == this) {
Debug(m_group,DebugNote,"%s: Attempt to set peer to itself [%p]",
address(),this);
@ -1140,7 +1155,7 @@ void AnalogLine::resetEcho(bool train)
// Connect the line's circuit. Reset line echo canceller
bool AnalogLine::connect(bool sync)
{
Lock lock(this);
Lock mylock(this);
bool ok = m_circuit && m_circuit->connect();
resetEcho(true);
if (sync && ok && m_peer)
@ -1151,7 +1166,7 @@ bool AnalogLine::connect(bool sync)
// Disconnect the line's circuit. Reset line echo canceller
bool AnalogLine::disconnect(bool sync)
{
Lock lock(this);
Lock mylock(this);
bool ok = m_circuit && m_circuit->disconnect();
resetEcho(false);
if (sync && ok && m_peer)
@ -1162,7 +1177,7 @@ bool AnalogLine::disconnect(bool sync)
// Send an event through this line
bool AnalogLine::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
{
Lock lock(this);
Lock mylock(this);
if (state() == OutOfService)
return false;
if (m_inband &&
@ -1174,7 +1189,7 @@ bool AnalogLine::sendEvent(SignallingCircuitEvent::Type type, NamedList* params)
// Get events from the line's circuit if not out of service
AnalogLineEvent* AnalogLine::getEvent(const Time& when)
{
Lock lock(this);
Lock mylock(this);
if (state() == OutOfService) {
checkTimeouts(when);
return 0;
@ -1201,7 +1216,7 @@ AnalogLineEvent* AnalogLine::getEvent(const Time& when)
// Alternate get events from this line or peer
AnalogLineEvent* AnalogLine::getMonitorEvent(const Time& when)
{
Lock lock(this);
Lock mylock(this);
m_getPeerEvent = !m_getPeerEvent;
AnalogLineEvent* event = 0;
if (m_getPeerEvent) {
@ -1221,7 +1236,7 @@ AnalogLineEvent* AnalogLine::getMonitorEvent(const Time& when)
// Change the line state if neither current or new state are OutOfService
bool AnalogLine::changeState(State newState, bool sync)
{
Lock lock(this);
Lock mylock(this);
bool ok = false;
while (true) {
if (m_state == newState || m_state == OutOfService || newState == OutOfService)
@ -1244,7 +1259,7 @@ bool AnalogLine::changeState(State newState, bool sync)
// entering/exiting the OutOfService state
bool AnalogLine::enable(bool ok, bool sync, bool connectNow)
{
Lock lock(this);
Lock mylock(this);
while (true) {
if (ok) {
if (m_state != OutOfService)
@ -1293,8 +1308,6 @@ void AnalogLine::destroyed()
* AnalogLineGroup
*/
YCLASSIMP(AnalogLineGroup,SignallingCircuitGroup)
// Construct an analog line group owning single lines
AnalogLineGroup::AnalogLineGroup(AnalogLine::Type type, const char* name, bool slave)
: SignallingCircuitGroup(0,SignallingCircuitGroup::Increment,name),
@ -1338,7 +1351,7 @@ bool AnalogLineGroup::appendLine(AnalogLine* line, bool destructOnFail)
TelEngine::destruct(line);
return false;
}
Lock lock(this);
Lock mylock(this);
m_lines.append(line);
DDebug(this,DebugAll,"Added line (%p) %s [%p]",line,line->address(),this);
return true;
@ -1347,7 +1360,7 @@ bool AnalogLineGroup::appendLine(AnalogLine* line, bool destructOnFail)
// Remove a line from the list and destruct it
void AnalogLineGroup::removeLine(unsigned int cic)
{
Lock lock(this);
Lock mylock(this);
AnalogLine* line = findLine(cic);
if (!line)
return;
@ -1360,7 +1373,7 @@ void AnalogLineGroup::removeLine(AnalogLine* line)
{
if (!line)
return;
Lock lock(this);
Lock mylock(this);
if (m_lines.remove(line,false))
DDebug(this,DebugAll,"Removed line %p %s [%p]",line,line->address(),this);
}
@ -1368,7 +1381,7 @@ void AnalogLineGroup::removeLine(AnalogLine* line)
// Find a line by its circuit
AnalogLine* AnalogLineGroup::findLine(unsigned int cic)
{
Lock lock(this);
Lock mylock(this);
for (ObjList* o = m_lines.skipNull(); o; o = o->skipNext()) {
AnalogLine* line = static_cast<AnalogLine*>(o->get());
if (line->circuit() && line->circuit()->code() == cic)
@ -1380,7 +1393,7 @@ AnalogLine* AnalogLineGroup::findLine(unsigned int cic)
// Find a line by its address
AnalogLine* AnalogLineGroup::findLine(const String& address)
{
Lock lock(this);
Lock mylock(this);
ObjList* tmp = m_lines.find(address);
return tmp ? static_cast<AnalogLine*>(tmp->get()) : 0;
}

View File

@ -52,7 +52,7 @@ const TokenDict* SIGTRAN::classNames()
}
SIGTRAN::SIGTRAN()
: m_trans(0)
: m_trans(0), m_transMutex(false,"SIGTRAN::transport")
{
}

View File

@ -1,5 +1,5 @@
/**
* tcap.cpp
* tup.cpp
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Signalling Stack - implements the support for SS7, ISDN and PSTN
@ -28,7 +28,8 @@
using namespace TelEngine;
SS7TUP::SS7TUP(const NamedList& params)
: SignallingCallControl(params,"tup.")
: SignallingComponent("SS7TUP",&params),
SignallingCallControl(params,"tup.")
{
}

File diff suppressed because it is too large Load Diff

View File

@ -31,9 +31,6 @@ namespace { // anonymous
class ModuleLine; // Module's interface to an analog line or recorder
// Manages the call setup detector and sends call setup info
class ModuleGroup; // Module's interface to a group of lines
class AnalogParams; // Named list containing creator data (pointers)
// Used to pass parameters to objects that need to obtain some
// pointers from the creator
class AnalogChannel; // Channel associated with an analog line
class AnalogCallRec; // Recorder call endpoint associated with an analog line monitor
class AnalogDriver; // Analog driver
@ -186,23 +183,6 @@ private:
ObjList m_endpoints; // Record data endpoints
};
// Named list containing creator data (pointers)
// Used to pass parameters to objects that need to obtain some pointers
class AnalogParams : public NamedList
{
public:
inline AnalogParams(const char* name, SignallingCircuitGroup* group)
: NamedList(name), m_cicGroup(group)
{}
virtual void* getObject(const String& name) const {
if (name == "SignallingCircuitGroup")
return m_cicGroup;
return NamedList::getObject(name);
}
private:
SignallingCircuitGroup* m_cicGroup;
};
// Channel associated with an analog line
class AnalogChannel : public Channel
{
@ -991,7 +971,7 @@ bool ModuleGroup::initialize(const NamedList& params, const NamedList& defaults,
if (!m_init)
debugChain(&plugin);
int level = params.getIntValue("debuglevel",m_init ? debugLevel() : plugin.debugLevel());
int level = params.getIntValue("debuglevel",m_init ? DebugEnabler::debugLevel() : plugin.debugLevel());
if (level >= 0) {
debugEnabled(0 != level);
debugLevel(level);
@ -1306,26 +1286,17 @@ void ModuleGroup::buildGroup(ModuleGroup* group, ObjList& spanList, String& erro
{
if (!group)
return;
int start = 0;
unsigned int start = 0;
for (ObjList* o = spanList.skipNull(); o; o = o->skipNext()) {
String* s = static_cast<String*>(o->get());
if (!s)
if (s->null())
continue;
AnalogParams spanParams("voice",group);
String tmp;
tmp << group->debugName() << "/" << *s;
spanParams.addParam("debugname",tmp);
spanParams.addParam("voice",*s);
if (start)
spanParams.addParam("start",String(start));
SignallingCircuitSpan* span = static_cast<SignallingCircuitSpan*>(
SignallingFactory::build(spanParams,&spanParams));
SignallingCircuitSpan* span = buildSpan(*s,start);
if (!span) {
error << "Failed to build span '" << *s << "'";
break;
}
int chans = spanParams.getIntValue("chans");
start += chans;
start += span->increment();
}
}

View File

@ -228,7 +228,7 @@ public:
// Handle the data received from Rudp
void handleData(DataBlock& data);
// Send start stop messages
void initSesion();
void initSession();
bool sendData(DataBlock& data, bool connectR = false);
// Find a specific user
bool insert(SessionUser* user);
@ -275,6 +275,7 @@ protected:
class SLT : public SS7Layer2, public SessionUser
{
YCLASS(SLT,SS7Layer2)
public:
enum Messages {
Connect_R = 0x06, // Connect Request message
@ -417,7 +418,7 @@ public:
{return lookup((int)state, s_linkCongestion);}
static inline const char* sprotocolError(protocolError state)
{return lookup((int)state, s_protocolError);}
static void* create(const String& type,const NamedList& params);
static SignallingComponent* create(const String& type,const NamedList& params);
protected:
unsigned int m_status; // Layer status
unsigned int m_lStatus; // Local layer status
@ -559,10 +560,10 @@ bool RudpSocket::initialize(const NamedList& params)
m_sequence = 0;
}
m_cumAckTimer.interval(params,"rudp_cumulative",100,300,false);
m_nullTimer.interval(params,"rudp_nulltimer",1900,2000,false);
m_retransTimer.interval(params,"rudp_retransmissiontimer",400,600,false);
m_nullTimer.interval(params,"rudp_nulltimer",1500,2000,false);
m_retransTimer.interval(params,"rudp_retransmission",400,600,false);
m_synTimer.interval(params,"rudp_syntimer",900,1000,false);
m_retransCounter = params.getIntValue("rudp_maxretransmission",2);
m_retransCounter = params.getIntValue("rudp_maxretrans",2);
m_maxCumAck = params.getIntValue("rudp_maxcumulative",3);
m_haveChecksum = params.getBoolValue("rudp_checksum",false);
m_sendSyn = params.getBoolValue("rudp_sendsyn",false);
@ -581,7 +582,7 @@ bool RudpSocket::initSocket(const NamedList& params)
{
m_socket = new Socket(AF_INET,SOCK_DGRAM);
String rhost = params.getValue("remote_host");
unsigned int rport = params.getIntValue("remote_port");
unsigned int rport = params.getIntValue("remote_port",8060);
if (!rhost || !rport) {
Debug(m_sm,DebugStub, "Unable to initialize socket, remote%s%s%s is missing",
rhost ? "" : " host",
@ -1192,7 +1193,7 @@ void SessionManager::notify(bool down)
informUser(false);
} else {
changeState(Operational);
initSesion();
initSession();
informUser(true);
}
}
@ -1215,7 +1216,7 @@ void SessionManager::handleData(DataBlock& data)
}
// Session Initialization send standby and active messages
void SessionManager::initSesion()
void SessionManager::initSession()
{
if (!m_socket)
return;
@ -1264,8 +1265,10 @@ bool SessionManager::sendData(DataBlock& data, bool connectR)
if (!m_socket || m_state != Operational)
return false;
// Send Standby and Active messages if we have an connect request message and all users are down
if (connectR && m_upUsers == 0)
initSesion();
if (connectR && m_upUsers == 0) {
initSession();
DDebug(this,DebugAll,"Sending init delayed PDU data: %u bytes",data.length());
}
m_socket->sendMSG(data);
return true;
}
@ -1318,7 +1321,7 @@ void SessionManager::changeState(State newState)
m_state = newState;
}
// As far as we know these messages should be send by us
// As far as we know these messages should be sent by us
void SessionManager::handleSmMessage(u_int32_t smMessageType)
{
switch (smMessageType) {
@ -1463,7 +1466,7 @@ const TokenDict SLT::s_protocolError[] = {
};
SLT::SLT(const String& name, const NamedList& param)
: SessionUser(1),
: SignallingComponent(param.safe("CiscoSLT")), SessionUser(1),
m_status(Unconfigured), m_lStatus(NormalAlignment), m_rStatus(OutOfAlignment),
m_reqStatus(NormalAlignment), m_messageId(1), m_channelId(0), m_bearerId(0),
m_confReqTimer(0), m_printMsg(false)
@ -1476,7 +1479,7 @@ SLT::SLT(const String& name, const NamedList& param)
m_session->insert(this);
m_session->deref();
}
m_confReqTimer.interval(param,"configuration",59,60,true);
m_confReqTimer.interval(param,"configuration",250,5000,true);
m_printMsg = param.getBoolValue("printslt",false);
}
@ -1909,24 +1912,23 @@ bool SLT::operational() const
return aligned();
}
void* SLT::create(const String& type, const NamedList& name)
SignallingComponent* SLT::create(const String& type, const NamedList& name)
{
if (type != "SS7l2")
if (type != "SS7Layer2")
return 0;
Configuration cfg(Engine::configFile("ciscosm"));
const char* sectName = name.getValue("name");
const char* sectName = name.getValue("link",name);
NamedList* layer = cfg.getSection(sectName);
if (!layer)
return 0;
String confSec = layer->getValue("session","default");
NamedList* section = cfg.getSection(confSec);
if (!section) {
Debug(DebugWarn,"Section '%s' does not exist in configuration",confSec.c_str());
Debug(DebugWarn,"Session '%s' does not exist in configuration",confSec.c_str());
return 0;
}
layer->copyParams(*section);
SLT* slt = new SLT(name,*layer);
return slt;
return new SLT(name,*layer);
}
/**

View File

@ -110,7 +110,7 @@ public:
inline bool fxs() const
{ return m_fxs; }
bool ownsId(const String& rqId) const;
static void* create(const String& type, const NamedList& name);
static SignallingComponent* create(const String& type, const NamedList& name);
static MGCPSpan* findNotify(const String& id);
bool matchEndpoint(const MGCPEndpointId& ep);
bool processEvent(MGCPTransaction* tr, MGCPMessage* mm);
@ -251,7 +251,7 @@ static bool copyRename(NamedList& dest, const char* dname, const NamedList& src,
}
// Increment the number at the end of a name by an offset
static bool increment(String& name, unsigned int offs)
static bool tailIncrement(String& name, unsigned int offs)
{
Regexp r("\\([0-9]\\+\\)@");
if (name.matches(r)) {
@ -674,17 +674,21 @@ bool MGCPWrapper::nativeConnect(DataEndpoint* peer)
// Called by the factory to create MGCP spans
void* MGCPSpan::create(const String& type, const NamedList& name)
SignallingComponent* MGCPSpan::create(const String& type, const NamedList& name)
{
if (type != "voice")
if (type != "SignallingCircuitSpan")
return 0;
const String* spanName = name.getParam(type);
const String* spanName = name.getParam("voice");
if (!spanName)
spanName = &name;
if (null(spanName) || !s_endpoint)
return 0;
MGCPEpInfo* ep = s_endpoint->findAlias(*spanName);
if (!ep)
if (!ep) {
DDebug(&splugin,DebugAll,"No endpoint info for span '%s'",spanName->c_str());
return 0;
MGCPSpan* span = new MGCPSpan(name,spanName->c_str(),*ep);
}
MGCPSpan* span = new MGCPSpan(name,spanName->safe("MGCPSpan"),*ep);
if (span->init(name))
return span;
TelEngine::destruct(span);
@ -761,6 +765,10 @@ bool MGCPSpan::init(const NamedList& params)
{
clearCircuits();
const String* sect = params.getParam("voice");
if (!sect)
sect = params.getParam("basename");
if (!sect)
sect = &params;
int cicStart = params.getIntValue("start");
if ((cicStart < 0) || !sect)
return false;
@ -776,6 +784,10 @@ bool MGCPSpan::init(const NamedList& params)
if (!m_count)
return false;
m_increment = m_count;
// assume 31 circuits means E1
if (m_increment == 31)
m_increment = 32;
m_circuits = new MGCPCircuit*[m_count];
unsigned int i;
for (i = 0; i < m_count; i++)
@ -783,7 +795,7 @@ bool MGCPSpan::init(const NamedList& params)
bool ok = true;
for (i = 0; i < m_count; i++) {
String name = epId().id();
if (!increment(name,i)) {
if (!tailIncrement(name,i)) {
Debug(m_group,DebugWarn,"MGCPSpan('%s'). Failed to increment name by %u. Rollback [%p]",
id().safe(),i,this);
clearCircuits();
@ -801,8 +813,6 @@ bool MGCPSpan::init(const NamedList& params)
}
circuit->ref();
}
if (ok)
const_cast<NamedList&>(params).setParam("chans",String(m_count));
return ok;
}

View File

@ -224,7 +224,7 @@ public:
// Process incoming data
virtual bool process();
// Called by the factory to create TDM interfaces or spans
static void* create(const String& type, const NamedList& name);
static SignallingComponent* create(const String& type, const NamedList& name);
protected:
// Check if received any data in the last interval. Notify receiver
virtual void timerTick(const Time& when);
@ -1106,17 +1106,20 @@ bool TdmSpan::init(TdmDevice::Type type,
if (!voice)
voice = "1-15.17-31";
chans = 31;
m_increment = 32;
break;
case TdmDevice::T1:
if (!voice)
voice = "1-23";
chans = 24;
m_increment = 24;
break;
case TdmDevice::NET:
case TdmDevice::CPE:
if (!voice)
voice = "1.2";
chans = 3;
m_increment = 3;
break;
case TdmDevice::FXO:
case TdmDevice::FXS:
@ -1142,12 +1145,11 @@ bool TdmSpan::init(TdmDevice::Type type,
}
if (!digital)
chans = count;
((NamedList*)&params)->setParam("chans",String(chans));
m_increment = chans = count;
unsigned int start = params.getIntValue("start",0);
// Create and insert circuits
unsigned int added = 0;
DDebug(m_group,DebugGoOn,
DDebug(m_group,DebugNote,
"TdmSpan('%s'). Creating circuits starting with %u [%p]",
id().safe(),start,this);
for (unsigned int i = 0; i < count; i++) {
@ -1166,7 +1168,7 @@ bool TdmSpan::init(TdmDevice::Type type,
continue;
}
TelEngine::destruct(cic);
Debug(m_group,DebugGoOn,
Debug(m_group,DebugWarn,
"TdmSpan('%s'). Duplicate circuit code=%u (channel=%u) [%p]",
id().safe(),code,channel,this);
}
@ -1638,25 +1640,31 @@ bool TdmAnalogCircuit::process()
}
// Interface
void* TdmInterface::create(const String& type, const NamedList& name)
SignallingComponent* TdmInterface::create(const String& type, const NamedList& name)
{
bool circuit = true;
if (type == "sig")
if (type == "SignallingInterface")
circuit = false;
else if (type == "voice")
else if (type == "SignallingCircuitSpan")
;
else
return 0;
Configuration cfg(Engine::configFile("tdmcard"));
cfg.load();
const char* sectName = name.getValue(type);
const char* sectName = name.getValue((circuit ? "voice" : "sig"),name.getValue("basename",name));
NamedList* config = cfg.getSection(sectName);
if (!config) {
DDebug(&plugin,DebugWarn,"No section '%s' in configuration",c_safe(sectName));
DDebug(&plugin,DebugAll,"No section '%s' in configuration",c_safe(sectName));
return 0;
}
#ifdef DEBUG
if (plugin.debugAt(DebugAll)) {
String tmp;
name.dump(tmp,"\r\n ",'\'',true);
Debug(&plugin,DebugAll,"TdmInterface::create %s%s",
(circuit ? "span" : "interface"),tmp.c_str());
}
#endif
NamedList dummy("general");
NamedList* general = cfg.getSection("general");
if (!general)
@ -1717,18 +1725,15 @@ void* TdmInterface::create(const String& type, const NamedList& name)
TdmInterface::TdmInterface(const NamedList& params)
: m_device(TdmDevice::DChan,this,0,0),
m_priority(Thread::Normal),
m_errorMask(255),
m_numbufs(16),
m_bufsize(1024),
m_buffer(0),
m_readOnly(false),
m_sendReadOnly(false),
m_notify(0),
m_timerRxUnder(0)
: SignallingComponent(params),
m_device(TdmDevice::DChan,this,0,0),
m_priority(Thread::Normal),
m_errorMask(255),
m_numbufs(16), m_bufsize(1024), m_buffer(0),
m_readOnly(false), m_sendReadOnly(false),
m_notify(0),
m_timerRxUnder(0)
{
setName(params.getValue("debugname","TdmInterface"));
m_buffer = new unsigned char[m_bufsize];
}
@ -1770,7 +1775,7 @@ bool TdmInterface::init(TdmDevice::Type type, unsigned int code, unsigned int ch
{
m_readOnly = getBoolValue("readonly",config,defaults,params);
m_priority = Thread::priority(config.getValue("priority",defaults.getValue("priority")));
int rx = params.getIntValue("rxunderruninterval");
int rx = params.getIntValue("rxunderrun");
if (rx > 0)
m_timerRxUnder.interval(rx);
int i = params.getIntValue("errormask",config.getIntValue("errormask",255));

View File

@ -223,7 +223,7 @@ class WpInterface : public SignallingInterface
friend class WpSigThread;
public:
// Create an instance of WpInterface or WpSpan
static void* create(const String& type, const NamedList& name);
static SignallingComponent* create(const String& type, const NamedList& name);
WpInterface(const NamedList& params);
virtual ~WpInterface();
// Initialize interface. Return false on failure
@ -727,26 +727,32 @@ bool WpSocket::updateLinkStatus()
* WpInterface
*/
// Create WpInterface or WpSpan
void* WpInterface::create(const String& type, const NamedList& name)
SignallingComponent* WpInterface::create(const String& type, const NamedList& name)
{
bool interface = false;
if (type == "sig")
if (type == "SignallingInterface")
interface = true;
else if (type == "voice")
else if (type == "SignallingCircuitSpan")
;
else
return 0;
Configuration cfg(Engine::configFile("wpcard"));
cfg.load();
const char* sectName = name.getValue(type);
DDebug(&driver,DebugAll,"Factory trying to create %s='%s'",type.c_str(),sectName);
const char* sectName = name.getValue((interface ? "sig" : "voice"),name.getValue("basename",name));
NamedList* config = cfg.getSection(sectName);
if (!config) {
DDebug(&driver,DebugAll,"No section '%s' in configuration",c_safe(sectName));
return 0;
}
#ifdef DEBUG
if (driver.debugAt(DebugAll)) {
String tmp;
name.dump(tmp,"\r\n ",'\'',true);
Debug(&driver,DebugAll,"WpInterface::create %s%s",
(interface ? "interface" : "span"),tmp.c_str());
}
#endif
if (interface) {
WpInterface* iface = new WpInterface(name);
if (iface->init(*config,(NamedList&)name))
@ -764,17 +770,17 @@ void* WpInterface::create(const String& type, const NamedList& name)
}
WpInterface::WpInterface(const NamedList& params)
: m_socket(this),
m_thread(0),
m_readOnly(false),
m_notify(0),
m_overRead(0),
m_sendReadOnly(false),
m_timerRxUnder(0),
m_repeatCapable(s_repeatCapable),
m_repeatMutex(true,"WpInterface::repeat")
: SignallingComponent(params),
m_socket(this),
m_thread(0),
m_readOnly(false),
m_notify(0),
m_overRead(0),
m_sendReadOnly(false),
m_timerRxUnder(0),
m_repeatCapable(s_repeatCapable),
m_repeatMutex(true,"WpInterface::repeat")
{
setName(params.getValue("debugname","WpInterface"));
DDebug(this,DebugAll,"WpInterface::WpInterface() [%p]",this);
}
@ -802,7 +808,7 @@ bool WpInterface::init(const NamedList& config, NamedList& params)
int i = params.getIntValue("errormask",config.getIntValue("errormask",255));
m_errorMask = ((i >= 0 && i < 256) ? i : 255);
int rx = params.getIntValue("rxunderruninterval");
int rx = params.getIntValue("rxunderrun");
if (rx > 0)
m_timerRxUnder.interval(rx);
@ -1373,6 +1379,7 @@ bool WpSpan::init(const NamedList& config, const NamedList& defaults, NamedList&
type = "E1";
if (type == "E1") {
m_chans = 31;
m_increment = 32;
if (cics.null())
cics = "1-15,17-31";
if (!m_samples)
@ -1380,17 +1387,25 @@ bool WpSpan::init(const NamedList& config, const NamedList& defaults, NamedList&
}
else if (type == "T1") {
m_chans = 24;
m_increment = 24;
if (cics.null())
cics = "1-23";
if (!m_samples)
m_samples = 64;
}
else if (type == "BRI") {
m_chans = 3;
m_increment = 3;
if (cics.null())
cics = "1-2";
if (!m_samples)
m_samples = 80;
}
else {
Debug(m_group,DebugNote,"WpSpan('%s'). Invalid voice group type '%s' [%p]",
id().safe(),type.safe(),this);
return false;
}
params.setParam("chans",String(m_chans));
// Other data
m_swap = defaults.getBoolValue("bitswap",true);
m_noData = defaults.getIntValue("idlevalue",0xff);

File diff suppressed because it is too large Load Diff

View File

@ -381,7 +381,7 @@ public:
// Process incoming data
virtual bool process();
// Called by the factory to create Zaptel interfaces or spans
static void* create(const String& type, const NamedList& name);
static SignallingComponent* create(const String& type, const NamedList& name);
protected:
// Check if received any data in the last interval. Notify receiver
virtual void timerTick(const Time& when);
@ -1483,18 +1483,15 @@ bool ZapDevice::ioctl(IoctlRequest request, void* param, int level)
* ZapInterface
*/
ZapInterface::ZapInterface(const NamedList& params)
: m_device(ZapDevice::DChan,this,0,0),
m_priority(Thread::Normal),
m_errorMask(255),
m_numbufs(16),
m_bufsize(1024),
m_buffer(0),
m_readOnly(false),
m_sendReadOnly(false),
m_notify(0),
m_timerRxUnder(0)
: SignallingComponent(params),
m_device(ZapDevice::DChan,this,0,0),
m_priority(Thread::Normal),
m_errorMask(255),
m_numbufs(16), m_bufsize(1024), m_buffer(0),
m_readOnly(false), m_sendReadOnly(false),
m_notify(0),
m_timerRxUnder(0)
{
setName(params.getValue("debugname","ZapInterface"));
m_buffer = new unsigned char[m_bufsize + ZAP_CRC_LEN];
XDebug(this,DebugAll,"ZapInterface::ZapInterface() [%p]",this);
}
@ -1507,27 +1504,31 @@ ZapInterface::~ZapInterface()
}
// Called by the factory to create Zaptel interfaces or spans
void* ZapInterface::create(const String& type, const NamedList& name)
SignallingComponent* ZapInterface::create(const String& type, const NamedList& name)
{
bool circuit = true;
if (type == "sig")
if (type == "SignallingInterface")
circuit = false;
else if (type == "voice")
else if (type == "SignallingCircuitSpan")
;
else
return 0;
Configuration cfg(Engine::configFile("zapcard"));
cfg.load();
const char* sectName = name.getValue(type);
DDebug(&plugin,DebugAll,"Factory trying to create %s='%s'",type.c_str(),sectName);
const char* sectName = name.getValue((circuit ? "voice" : "sig"),name.getValue("basename",name));
NamedList* config = cfg.getSection(sectName);
if (!config) {
DDebug(&plugin,DebugAll,"No section '%s' in configuration",c_safe(sectName));
return 0;
}
#ifdef DEBUG
if (plugin.debugAt(DebugAll)) {
String tmp;
name.dump(tmp,"\r\n ",'\'',true);
Debug(&plugin,DebugAll,"ZapInterface::create %s%s",
(circuit ? "span" : "interface"),tmp.c_str());
}
#endif
String sDevType = config->getValue("type");
ZapDevice::Type devType = (ZapDevice::Type)lookup(sDevType,s_types,ZapDevice::E1);
@ -1601,7 +1602,7 @@ bool ZapInterface::init(ZapDevice::Type type, unsigned int code, unsigned int ch
m_device.channel(channel,code);
m_readOnly = getBoolValue("readonly",config,defaults,params);
m_priority = Thread::priority(config.getValue("priority",defaults.getValue("priority")));
int rx = params.getIntValue("rxunderruninterval");
int rx = params.getIntValue("rxunderrun");
if (rx > 0)
m_timerRxUnder.interval(rx);
int i = params.getIntValue("errormask",config.getIntValue("errormask",255));
@ -1814,16 +1815,19 @@ bool ZapSpan::init(ZapDevice::Type type, unsigned int offset,
if (!voice)
voice = "1-15.17-31";
chans = 31;
m_increment = 32;
break;
case ZapDevice::T1:
if (!voice)
voice = "1-23";
chans = 24;
m_increment = 24;
break;
case ZapDevice::BRI:
if (!voice)
voice = "1-2";
chans = 3;
m_increment = 3;
break;
case ZapDevice::FXO:
case ZapDevice::FXS:
@ -1848,8 +1852,7 @@ bool ZapSpan::init(ZapDevice::Type type, unsigned int offset,
}
if (!digital)
chans = count;
((NamedList*)&params)->setParam("chans",String(chans));
m_increment = chans = count;
unsigned int start = params.getIntValue("start",0);
// Create and insert circuits