Accept a comma separated list of links to try to send the call.

Detect early a congestion or network failure and attempt next link.


git-svn-id: http://voip.null.ro/svn/yate@2368 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2008-11-26 15:20:15 +00:00
parent 96c30c706c
commit 501f0bef0e
3 changed files with 109 additions and 59 deletions

View File

@ -2142,8 +2142,9 @@ SignallingCall* SS7ISUP::call(SignallingMessage* msg, String& reason)
reason = "noconn";
return 0;
}
if (!m_l3LinkUp) {
Debug(this,DebugNote,"L3 network is down");
if (exiting() || !m_l3LinkUp) {
Debug(this,DebugInfo,"Denying outgoing call request, reason: %s.",
exiting() ? "exiting" : "L3 down");
TelEngine::destruct(msg);
reason = "net-out-of-order";
return 0;
@ -2157,6 +2158,7 @@ SignallingCall* SS7ISUP::call(SignallingMessage* msg, String& reason)
SS7PointCode dest;
SignallingCircuit* cic = 0;
const char* range = msg->params().getValue("circuits");
reason.clear();
Lock lock(this);
// Check
while (true) {

View File

@ -720,6 +720,8 @@ ISDNQ931Call::ISDNQ931Call(ISDNQ931* controller, bool outgoing,
q931()->setInterval(m_discTimer,305);
q931()->setInterval(m_relTimer,308);
q931()->setInterval(m_conTimer,313);
if (outgoing)
reserveCircuit();
}
ISDNQ931Call::~ISDNQ931Call()
@ -1571,7 +1573,7 @@ bool ISDNQ931Call::sendSetup(SignallingMessage* sigMsg)
m_data.m_format = "alaw";
m_data.processBearerCaps(msg,true);
// ChannelID
if (!reserveCircuit())
if (!m_circuit)
break;
m_circuit->updateFormat(m_data.m_format,0);
m_data.m_bri = false;
@ -2532,6 +2534,11 @@ SignallingCall* ISDNQ931::call(SignallingMessage* msg, String& reason)
return 0;
}
ISDNQ931Call* call = new ISDNQ931Call(this,true,m_callRef,m_callRefLen);
if (!call->circuit()) {
reason = "congestion";
TelEngine::destruct(call);
return 0;
}
call->ref();
// Adjust m_callRef. Avoid to use 0
m_callRef = (m_callRef + 1) & m_callRefMask;
@ -2678,12 +2685,14 @@ void ISDNQ931::terminateCalls(ObjList* list, const char* reason)
// Check if new calls are acceptable
bool ISDNQ931::acceptNewCall(bool outgoing, String& reason)
{
if (!exiting())
return true;
Debug(this,DebugNote,"Denying %s call request. We are exiting",
outgoing ? "outgoing" : "incoming");
reason = "net-out-of-order";
return false;
if (exiting() || !m_q921 || !m_q921Up) {
Debug(this,DebugInfo,"Denying %s call request, reason: %s.",
outgoing ? "outgoing" : "incoming",
exiting() ? "exiting" : "link down");
reason = "net-out-of-order";
return false;
}
return true;
}
// Helper function called in ISDNQ931::receive()

View File

@ -54,8 +54,9 @@ public:
// Incoming
SigChannel(SignallingEvent* event);
// Outgoing
SigChannel(Message& msg, const char* caller, const char* called, SigLink* link);
SigChannel(const char* caller, const char* called);
virtual ~SigChannel();
bool startCall(Message& msg, String& links);
inline SignallingCall* call() const
{ return m_call; }
inline SigLink* link() const
@ -81,6 +82,7 @@ public:
void handleEvent(SignallingEvent* event);
void hangup(const char* reason = 0, SignallingEvent* event = 0);
private:
bool startCall(Message& msg, SigLink* link);
virtual void statusParams(String& str);
// Set call status. Print debug message
void setState(const char* state, bool updateStatus = true, bool showReason = false);
@ -516,7 +518,7 @@ SigChannel::SigChannel(SignallingEvent* event)
: Channel(&plugin,0,false),
m_call(event->call()),
m_link(0),
m_hungup(false),
m_hungup(true),
m_inband(false)
{
if (!(m_call && m_call->ref())) {
@ -532,6 +534,7 @@ SigChannel::SigChannel(SignallingEvent* event)
if (m_link)
m_inband = m_link->inband();
// Startup
m_hungup = false;
setState(0);
SignallingCircuit* cic = getCircuit();
if (m_link && cic)
@ -546,27 +549,87 @@ SigChannel::SigChannel(SignallingEvent* event)
Engine::enqueue(m);
}
// Construct an outgoing channel
SigChannel::SigChannel(Message& msg, const char* caller, const char* called, SigLink* link)
// Construct an unstarted outgoing channel
SigChannel::SigChannel(const char* caller, const char* called)
: Channel(&plugin,0,true),
m_caller(caller),
m_called(called),
m_call(0),
m_link(link),
m_hungup(false),
m_link(0),
m_hungup(true),
m_reason("noconn"),
m_inband(false)
{
if (!(m_link && m_link->controller())) {
msg.setParam("error","noconn");
m_hungup = true;
return;
}
SigChannel::~SigChannel()
{
hangup();
setState("destroyed",true,true);
}
// Start outgoing call by name of a link or list of links
bool SigChannel::startCall(Message& msg, String& links)
{
ObjList* linkList = links.split(',',false);
unsigned int n = linkList->length();
for (unsigned int i = 0; i < n; i++) {
const String* linkName = static_cast<const String*>((*linkList)[i]);
if (!linkName)
continue;
SigLink* link = plugin.findLink(*linkName,true);
if (link && startCall(msg,link)) {
// success - update link parameter in message
links = *linkName;
break;
}
}
delete linkList;
setState(0);
if (!m_call) {
msg.setParam("error",m_reason);
return false;
}
// Since the channel started the call remember to hang up as well
m_hungup = false;
SignallingCircuit* cic = getCircuit();
if (cic) {
m_address << m_link->name() << "/" << cic->code();
// Set echo cancel
const String* echo = msg.getParam("cancelecho");
if (echo && *echo) {
int taps = echo->toInteger(-1);
if (taps > 0) {
cic->setParam("echotaps",*echo);
cic->setParam("echocancel",String::boolText(true));
}
else
cic->setParam("echocancel",String::boolText(echo->toBoolean(true)));
}
}
setMaxcall(msg);
Message* m = message("chan.startup",msg);
m->setParam("direction",status());
m_targetid = msg.getValue("id");
m->setParam("caller",m_caller);
m->setParam("called",m_called);
m->setParam("billid",msg.getValue("billid"));
// TODO: Add call control parameter ?
Engine::enqueue(m);
return true;
}
bool SigChannel::startCall(Message& msg, SigLink* link)
{
if (!(link && link->controller()))
return false;
// Data
m_inband = msg.getBoolValue("dtmfinband",link->inband());
// Make the call
SignallingMessage* sigMsg = new SignallingMessage;
sigMsg->params().addParam("caller",caller);
sigMsg->params().addParam("called",called);
sigMsg->params().addParam("caller",m_caller);
sigMsg->params().addParam("called",m_called);
sigMsg->params().addParam("callername",msg.getValue("callername"));
sigMsg->params().copyParam(msg,"circuits");
sigMsg->params().copyParam(msg,"format");
@ -587,38 +650,15 @@ SigChannel::SigChannel(Message& msg, const char* caller, const char* called, Sig
sigMsg->params().addParam(ns->name().substr(prefix.length()),*ns);
}
m_call = link->controller()->call(sigMsg,m_reason);
setState(0);
if (m_call) {
m_call->userdata(this);
SignallingCircuit* cic = getCircuit();
if (cic) {
m_address << m_link->name() << "/" << cic->code();
// Set echo cancel
const char* echo = msg.getValue("cancelecho");
if (echo) {
String value = echo;
cic->setParam("echotaps",value);
cic->setParam("echocancel",String::boolText(0 != value.toInteger()));
}
}
setMaxcall(msg);
m_link = link;
m_reason.clear();
return true;
}
else
msg.setParam("error",m_reason);
Message* m = message("chan.startup",msg);
m->setParam("direction",status());
m_targetid = msg.getValue("id");
m->setParam("caller",caller);
m->setParam("called",called);
m->setParam("billid",msg.getValue("billid"));
// TODO: Add call control parameter ?
Engine::enqueue(m);
}
SigChannel::~SigChannel()
{
hangup();
setState("destroyed",true,true);
DDebug(this,DebugNote,"Failed to call on link '%s' reason: '%s' [%p]",
link->name().safe(),m_reason.c_str(),this);
return false;
}
void SigChannel::handleEvent(SignallingEvent* event)
@ -825,9 +865,9 @@ void SigChannel::hangup(const char* reason, SignallingEvent* event)
Lock lock(m_mutex);
if (m_hungup)
return;
m_hungup = true;
setSource();
setConsumer();
m_hungup = true;
if (m_reason.null())
m_reason = reason ? reason : (Engine::exiting() ? "net-out-of-order" : "normal-clearing");
setState("hangup",true,true);
@ -1043,20 +1083,19 @@ bool SigDriver::msgExecute(Message& msg, String& dest)
msg.setParam("error","failure");
return false;
}
// Identify the call controller before create channel
const char* tmp = msg.getValue("link");
SigLink* link = findLink(tmp,true);
if (!link) {
// Locate and check the link parameter
String* link = msg.getParam("link");
if (!link || link->null()) {
Debug(this,DebugNote,
"Signalling call failed. No call controller named '%s'",tmp);
msg.setParam("error","noroute");
"Signalling call failed. No link specified");
msg.setParam("error","noconn");
return false;
}
// Create channel
lock();
SigChannel* sigCh = new SigChannel(msg,msg.getValue("caller"),dest,link);
SigChannel* sigCh = new SigChannel(msg.getValue("caller"),dest);
unlock();
bool ok = sigCh->call() != 0;
bool ok = sigCh->startCall(msg,*link);
if (ok) {
if (sigCh->connect(peer,msg.getValue("reason"))) {
msg.setParam("peerid",sigCh->id());