Allow trunking parameters set in 'user.login' to override configured. Allow trunking out to be enabled in 'user.login'.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5542 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2013-06-13 10:28:53 +00:00
parent 347829548c
commit b88be7a47e
7 changed files with 263 additions and 65 deletions

View File

@ -56,7 +56,19 @@
; IAX:
; server: Registrar address or domain. A port can be specified here (e.g. 1.2.3.4:7999)
; port: Registrar port if not specified in 'server' parameter
; If not set the port defaults to 4569
; If not set the port defaults to 4569
; trunking: Enable trunking for outgoing calls sent on this line
; The following parameters can also be set (see yiaxchan.conf.sample for more info):
; trunk_timestamps: Configure how trunked audio data is sent, enable it for
; trunked data with timestamps and disable it to send trunked data without timestamps
; trunk_sendinterval: integer: Interval, in milliseconds, to send trunked trunked audio
; data
; trunk_maxlen: integer: Maximum value for trunked data frames
; trunk_nominits_sync_use_ts: boolean: Configure how to re-build timestamps when
; processing incoming trunked audio without miniframe timestamps
; trunk_nominits_ts_diff_restart: integer: The difference (in milliseconds) between
; current timestamp and first timestamp of incoming trunked audio data without
; miniframe timestamps at which to restart timestamps build data
;
; H323:
; server: Registrar IP address

View File

@ -1,3 +1,21 @@
; Trunking notes:
; Trunking can be enabled when routing by a 'trunkout' parameter for outgoing calls
; and 'trunkin' parameter for incoming calls.
; When registering a line to a remote server trunking can be enabled using a 'trunking'
; parameter set in 'user.login' message
; The following parameters can be set in 'user.login' to override the defaults:
; trunk_timestamps, trunk_sendinterval, trunk_maxlen,
; trunk_nominits_sync_use_ts, trunk_nominits_ts_diff_restart
; When setting trunking parameters for a call the order is:
; - init with configured parameters value
; - override with parameters set for line (outgoing calls only)
; - override parameters set when routing
; IMPORTANT: When a call is set to send trunked data all parameters related to
; trunk (timestamps use, send interval, max packet length) are ignored if there
; is another call using trunking with the same remote ip/port.
; TAKE CARE WHEN SETTING TRUNKING PARAMETERS IN MORE THEN 1 PLACE FOR THE SAME
; REMOTE IP/PORT !!!
[general]
; This section sets global variables of the implementation

View File

@ -414,11 +414,15 @@ void IAXEngine::initialize(const NamedList& params)
IAX2_CHALLENGETOUT_DEF,IAX2_CHALLENGETOUT_MIN);
initOutDataAdjust(params);
IAXTrunkInfo* ti = new IAXTrunkInfo;
ti->initTrunking(params,"trunk_",0,true);
ti->initTrunking(params,"trunk_",0,false);
ti->initTrunking(params,"trunk_");
ti->init(params);
Lock lck(m_trunkInfoMutex);
m_trunkInfoDef = ti;
#ifdef XDEBUG
String tiS;
m_trunkInfoDef->dump(tiS,"\r\n");
Debug(this,DebugAll,"Initialized trunk info defaults:\r\n-----\r\n%s\r\n-----",tiS.c_str());
#endif
TelEngine::destruct(ti);
}
@ -807,7 +811,7 @@ static bool getTrunkingInfo(RefPointer<IAXTrunkInfo>& ti, IAXEngine* engine,
if (!params)
return true;
IAXTrunkInfo* tmp = new IAXTrunkInfo;
tmp->initTrunking(*params,prefix,ti,out);
tmp->initTrunking(*params,prefix,ti,out,!out);
ti = tmp;
TelEngine::destruct(tmp);
return true;
@ -846,6 +850,35 @@ void IAXEngine::enableTrunking(IAXTransaction* trans, const NamedList* params,
TelEngine::destruct(frame);
}
// Enable trunking for the given transaction. Allocate a trunk meta frame if needed.
void IAXEngine::enableTrunking(IAXTransaction* trans, IAXTrunkInfo& data)
{
if (!trans || trans->type() != IAXTransaction::New)
return;
Lock lock(m_mutexTrunk);
IAXMetaTrunkFrame* frame;
// Already enabled ?
for (ObjList* l = m_trunkList.skipNull(); l; l = l->skipNext()) {
frame = static_cast<IAXMetaTrunkFrame*>(l->get());
if (frame->addr() == trans->remoteAddr()) {
trans->enableTrunking(frame);
return;
}
}
frame = new IAXMetaTrunkFrame(this,trans->remoteAddr(),data.m_timestamps,
data.m_maxLen,data.m_sendInterval);
if (trans->enableTrunking(frame)) {
m_trunkList.append(frame);
Debug(this,DebugAll,
"Added trunk frame (%p) '%s:%d' timestamps=%s maxlen=%u interval=%ums",
frame,frame->addr().host().c_str(),frame->addr().port(),
String::boolText(frame->trunkTimestamps()),frame->maxLen(),
frame->sendInterval());
}
else
TelEngine::destruct(frame);
}
// Init incoming trunking data for a given transaction
void IAXEngine::initTrunkIn(IAXTransaction* trans, const NamedList* params,
const String& prefix)
@ -853,13 +886,26 @@ void IAXEngine::initTrunkIn(IAXTransaction* trans, const NamedList* params,
if (!trans)
return;
RefPointer<IAXTrunkInfo> ti;
if (!getTrunkingInfo(ti,this,params,prefix,false))
return;
trans->m_trunkInSyncUsingTs = ti->m_trunkInSyncUsingTs;
trans->m_trunkInTsDiffRestart = ti->m_trunkInTsDiffRestart;
if (getTrunkingInfo(ti,this,params,prefix,false))
initTrunkIn(trans,*ti);
ti = 0;
}
// Init incoming trunking data for a given transaction
void IAXEngine::initTrunkIn(IAXTransaction* trans, IAXTrunkInfo& data)
{
if (!trans)
return;
trans->m_trunkInSyncUsingTs = data.m_trunkInSyncUsingTs;
trans->m_trunkInTsDiffRestart = data.m_trunkInTsDiffRestart;
#ifdef XDEBUG
String tmp;
data.dump(tmp," ",false,true,false);
Debug(this,DebugAll,"initTrunkIn(%p) callno=%u set %s",
trans,trans->localCallNo(),tmp.c_str());
#endif
}
void IAXEngine::runProcessTrunkFrames()
{
while (1) {

View File

@ -1432,7 +1432,7 @@ void IAXTrunkInfo::init(const NamedList& params, const String& prefix,
// Init from parameters
void IAXTrunkInfo::initTrunking(const NamedList& params, const String& prefix,
const IAXTrunkInfo* def, bool out)
const IAXTrunkInfo* def, bool out, bool in)
{
if (out) {
m_timestamps = params.getBoolValue(prefix + "timestamps",
@ -1442,7 +1442,7 @@ void IAXTrunkInfo::initTrunking(const NamedList& params, const String& prefix,
m_maxLen = params.getIntValue(prefix + "maxlen",
def ? def->m_maxLen : IAX2_TRUNKFRAME_LEN_DEF,IAX2_TRUNKFRAME_LEN_MIN);
}
else {
if (in) {
m_trunkInSyncUsingTs = params.getBoolValue(prefix + "nominits_sync_use_ts",
!def || def->m_trunkInSyncUsingTs);
m_trunkInTsDiffRestart = params.getIntValue(prefix + "nominits_ts_diff_restart",
@ -1450,6 +1450,43 @@ void IAXTrunkInfo::initTrunking(const NamedList& params, const String& prefix,
}
}
// Update trunking from parameters. Don't change values not present in list
void IAXTrunkInfo::updateTrunking(const NamedList& params, const String& prefix,
bool out, bool in)
{
if (out) {
m_timestamps = params.getBoolValue(prefix + "timestamps",m_timestamps);
m_sendInterval = params.getIntValue(prefix + "sendinterval",
m_sendInterval,IAX2_TRUNKFRAME_SEND_MIN);
m_maxLen = params.getIntValue(prefix + "maxlen",m_maxLen,IAX2_TRUNKFRAME_LEN_MIN);
}
if (in) {
m_trunkInSyncUsingTs = params.getBoolValue(prefix + "nominits_sync_use_ts",
m_trunkInSyncUsingTs);
m_trunkInTsDiffRestart = params.getIntValue(prefix + "nominits_ts_diff_restart",
m_trunkInTsDiffRestart,1000);
}
}
// Dump info
void IAXTrunkInfo::dump(String& buf, const char* sep, bool out, bool in, bool other)
{
if (out) {
buf.append("timestamps=",sep) << String::boolText(m_timestamps);
buf << sep << "sendinterval=" << m_sendInterval;
buf << sep << "maxlen=" << m_maxLen;
}
if (in) {
buf.append("nominits_sync_use_ts=",sep) << String::boolText(m_trunkInSyncUsingTs);
buf << sep << "nominits_ts_diff_restart=" << m_trunkInTsDiffRestart;
}
if (other) {
buf.append("retrans_count=",sep) << m_retransCount;
buf << sep << "retrans_interval=" << m_retransInterval;
buf << sep << "ping_interval=" << m_pingInterval;
}
}
/*
* IAXMetaTrunkFrame

View File

@ -67,6 +67,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t
m_localReqEnd(false),
m_type(Incorrect),
m_state(Unknown),
m_destroy(false),
m_timeStamp(Time::msecNow() - 1),
m_timeout(0),
m_addr(addr),
@ -136,6 +137,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
m_localReqEnd(false),
m_type(type),
m_state(Unknown),
m_destroy(false),
m_timeStamp(Time::msecNow() - 1),
m_timeout(0),
m_addr(addr),
@ -603,6 +605,11 @@ IAXEvent* IAXTransaction::getEvent(const Time& now)
Lock lock(this);
if (state() == Terminated)
return 0;
if (m_destroy) {
if (m_currentEvent)
return 0;
return keepEvent(terminate(IAXEvent::Terminated,true));
}
// Send ack for received frames
ackInFrames();
// Do we have a generated event ?

View File

@ -1496,10 +1496,32 @@ public:
* @param params Parameter list
* @param prefix Parameter prefix
* @param def Optional defaults
* @param out True to init outgoing trunk data, false to init incoming trunk info
* @param out True to init outgoing trunk data
* @param in True to init incoming trunk data
*/
void initTrunking(const NamedList& params, const String& prefix,
const IAXTrunkInfo* def = 0, bool out = true);
void initTrunking(const NamedList& params, const String& prefix = String::empty(),
const IAXTrunkInfo* def = 0, bool out = true, bool in = true);
/**
* Update trunking from parameters. Don't change values not present in list
* @param params Parameter list
* @param prefix Parameter prefix
* @param out True to update outgoing trunk data
* @param in True to update incoming trunk data
*/
void updateTrunking(const NamedList& params, const String& prefix = String::empty(),
bool out = true, bool in = true);
/**
* Dump info
* @param buf Destination buffer
* @param sep Parameters separator
* @param out True to dump outgoing trunking info
* @param in True to dump incoming trunking info
* @param other True to dump non trunking info
*/
void dump(String& buf, const char* sep = " ", bool out = true, bool in = true,
bool other = true);
bool m_timestamps; // Trunk type: with(out) timestamps
unsigned int m_sendInterval; // Send interval
@ -1955,6 +1977,12 @@ public:
inline const String& authdata()
{ return m_authdata; }
/**
* Set the destroy flag
*/
inline void setDestroy()
{ m_destroy = true; }
/**
* Process a frame from remote peer
* This method is thread safe.
@ -2533,6 +2561,7 @@ private:
bool m_localReqEnd; // Local client requested terminate
Type m_type; // Transaction type
State m_state; // Transaction state
bool m_destroy; // Destroy flag
u_int64_t m_timeStamp; // Transaction creation timestamp
u_int64_t m_timeout; // Transaction timeout in Terminating state
SocketAddr m_addr; // Socket
@ -2981,20 +3010,35 @@ public:
* Enable trunking for the given transaction. Allocate a trunk meta frame if needed.
* Trunk data is ignored if a trunk object for transaction remote address already exists
* @param trans Transaction to enable trunking for
* @param params Optional trunk parameters list
* @param params Trunk parameters list, may be 0
* @param prefix Trunk parameters name prefix
*/
void enableTrunking(IAXTransaction* trans, const NamedList* params = 0,
void enableTrunking(IAXTransaction* trans, const NamedList* params,
const String& prefix = String::empty());
/**
* Enable trunking for the given transaction. Allocate a trunk meta frame if needed.
* Trunk data is ignored if a trunk object for transaction remote address already exists
* @param trans Transaction to enable trunking for
* @param data Trunk info to use
*/
void enableTrunking(IAXTransaction* trans, IAXTrunkInfo& data);
/**
* Init incoming trunking data for a given transaction
* @param trans Transaction to init
* @param params Trunk parameters list, may be 0
* @param prefix Trunk parameters name prefix
*/
void initTrunkIn(IAXTransaction* trans, const NamedList* params,
const String& prefix = String::empty());
/**
* Init incoming trunking data for a given transaction
* @param trans Transaction to init
* @param params Optional trunk parameters list
* @param prefix Trunk parameters name prefix
* @param data Trunk info to use
*/
void initTrunkIn(IAXTransaction* trans, const NamedList* params = 0,
const String& prefix = String::empty());
void initTrunkIn(IAXTransaction* trans, IAXTrunkInfo& data);
/**
* Retrieve the default trunk info data

View File

@ -110,6 +110,10 @@ public:
{ return m_remote; }
inline bool callToken() const
{ return m_callToken; }
inline bool trunking() const
{ return m_trunking; }
inline const NamedList& trunkInfo() const
{ return m_trunkInfo; }
private:
void setRegistered(bool registered, const char* reason = 0, const char* error = 0);
String m_name;
@ -130,6 +134,8 @@ private:
bool m_registered; // Registered flag. If true the line is registered
bool m_register; // Operation flag: True - register
RefPointer<IAXTransaction> m_transaction;
NamedList m_trunkInfo; // Trunk info parameters
bool m_trunking; // Enable trunking
};
/*
@ -182,12 +188,15 @@ public:
*/
void evTimer(Time& time);
/*
* Fill a named list from a line
* This method is thread safe
*/
bool fillList(String& name, NamedList& dest, SocketAddr& addr, bool& registered);
// Fill parameters with information taken from line
void fillList(YIAXLine& line, NamedList& dest, SocketAddr& addr);
// Find a line by name
inline bool findLine(RefPointer<YIAXLine>& line, const String& name) {
Lock lck(this);
line = findLine(name);
return line != 0;
}
/*
* Check if a line exists
*/
@ -289,7 +298,7 @@ public:
{}
// Setup a given transaction from parameters
void initTransaction(IAXTransaction* tr, const NamedList& params);
void initTransaction(IAXTransaction* tr, const NamedList& params, YIAXLine* line = 0);
/*
* Process media from remote peer.
@ -627,7 +636,9 @@ YIAXLine::YIAXLine(const String& name)
m_keepAliveInterval(0),
m_registered(false),
m_register(true),
m_transaction(0)
m_transaction(0),
m_trunkInfo(""),
m_trunking(false)
{
DDebug(&iplugin,DebugAll,"YIAXLine(%s) [%p]",m_name.c_str(),this);
}
@ -748,6 +759,9 @@ bool YIAXLineContainer::updateLine(Message& msg)
interval = 60;
changed = changeLine(line,line->m_expire,interval) || changed;
line->m_callToken = msg.getBoolValue("calltoken",s_callTokenOut);
line->m_trunking = msg.getBoolValue("trunking");
line->m_trunkInfo.clearParams();
line->m_trunkInfo.copySubParams(msg,"trunk_");
if (changed || op == "login") {
line->m_nextReg = Time::secNow() + (line->m_expire * 3 / 4);
line->m_nextKeepAlive = 0;
@ -918,29 +932,20 @@ void YIAXLineContainer::evTimer(Time& time)
}
// Fill parameters with information taken from line
bool YIAXLineContainer::fillList(String& name, NamedList& dest, SocketAddr& addr, bool& registered)
void YIAXLineContainer::fillList(YIAXLine& line, NamedList& dest, SocketAddr& addr)
{
registered = false;
Lock lck(this);
RefPointer<YIAXLine> line = findLine(name);
if (!line)
return false;
lck.drop();
line->lock();
dest.setParam("username",line->username());
dest.setParam("password",line->password());
if (line->callingNo())
dest.setParam("caller",line->callingNo());
if (line->callingName())
dest.setParam("callername",line->callingName());
String a = line->remoteAddr();
int p = line->remotePort();
registered = line->registered();
line->unlock();
line = 0;
line.lock();
dest.setParam("username",line.username());
dest.setParam("password",line.password());
if (line.callingNo())
dest.setParam("caller",line.callingNo());
if (line.callingName())
dest.setParam("callername",line.callingName());
String a = line.remoteAddr();
int p = line.remotePort();
line.unlock();
addr.host(a);
addr.port(p);
return true;
}
// Find line from event. Clear event transaction if line is not found
@ -1034,15 +1039,35 @@ YIAXEngine::YIAXEngine(const char* iface, int port, u_int16_t transListCount,
}
// Setup a given transaction from parameters
void YIAXEngine::initTransaction(IAXTransaction* tr, const NamedList& params)
void YIAXEngine::initTransaction(IAXTransaction* tr, const NamedList& params, YIAXLine* line)
{
if (!tr)
return;
String prefix = tr->outgoing() ? "trunkout" : "trunkin";
String pref = prefix + "_";
if (params.getBoolValue(prefix))
enableTrunking(tr,&params,pref);
initTrunkIn(tr,&params,pref);
IAXTrunkInfo* trunk = 0;
Lock lckLine(line);
bool trunkOut = params.getBoolValue(prefix,line && line->trunking());
if (line && line->trunkInfo().getParam(0)) {
RefPointer<IAXTrunkInfo> def;
tr->getEngine()->trunkInfo(def);
trunk = new IAXTrunkInfo;
trunk->initTrunking(line->trunkInfo(),String::empty(),def,trunkOut,true);
trunk->updateTrunking(params,pref,trunkOut,true);
}
lckLine.drop();
tr->getEngine()->initOutDataAdjust(params,tr);
if (trunkOut) {
if (trunk)
enableTrunking(tr,*trunk);
else
enableTrunking(tr,&params,pref);
}
if (trunk)
initTrunkIn(tr,*trunk);
else
initTrunkIn(tr,&params,pref);
TelEngine::destruct(trunk);
}
// Handle received voice data, forward it to connection's source
@ -1490,25 +1515,33 @@ bool YIAXDriver::msgRoute(Message& msg)
bool YIAXDriver::msgExecute(Message& msg, String& dest)
{
if (!msg.userData()) {
Debug(this,DebugAll,"No data channel for this IAX call!");
CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData());
if (!ch) {
Debug(this,DebugAll,"IAX call failed: no endpoint");
return false;
}
NamedList params(msg);
SocketAddr addr(AF_INET);
RefPointer<YIAXLine> line;
if (isE164(dest)) {
String* line = params.getParam("line");
bool lineReg = (line == 0);
if (line && !s_lines.fillList(*line,params,addr,lineReg)) {
Debug(this,DebugNote,"IAX call failed: no line '%s'",line->c_str());
const String& lName = params["line"];
if (!lName) {
Debug(this,DebugNote,"IAX call to '%s' failed: no line",dest.c_str());
msg.setParam("error","failure");
return false;
}
if (!s_lines.findLine(line,lName)) {
Debug(this,DebugNote,"IAX call failed: no line '%s'",lName.c_str());
msg.setParam("error","offline");
return false;
}
if (!lineReg) {
Debug(this,DebugNote,"IAX call failed: line '%s' is not registered!",line->c_str());
if (!line->registered()) {
Debug(this,DebugNote,"IAX call failed: line '%s' is not registered",
lName.c_str());
msg.setParam("error","offline");
return false;
}
s_lines.fillList(*line,params,addr);
params.setParam("called",dest);
}
else {
@ -1519,7 +1552,8 @@ bool YIAXDriver::msgExecute(Message& msg, String& dest)
uri.setAddr(addr);
}
if (!addr.host().length()) {
Debug(this,DebugAll,"Missing host name in this IAX call");
Debug(this,DebugNote,"IAX call failed: no remote address");
msg.setParam("error","failure");
return false;
}
IAXTransaction* tr = m_iaxEngine->call(addr,params);
@ -1527,19 +1561,20 @@ bool YIAXDriver::msgExecute(Message& msg, String& dest)
msg.copyParams(params,"error");
return false;
}
tr->getEngine()->initOutDataAdjust(msg,tr);
YIAXConnection* conn = new YIAXConnection(m_iaxEngine,tr,&msg,&params);
conn->initChan();
tr->setUserData(conn);
CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData());
if (ch && conn->connect(ch,msg.getValue("reason"))) {
m_iaxEngine->initTransaction(tr,msg,line);
if (conn->connect(ch,msg.getValue("reason"))) {
conn->callConnect(msg);
msg.setParam("peerid",conn->id());
msg.setParam("targetid",conn->id());
(static_cast<YIAXEngine*>(tr->getEngine()))->initTransaction(tr,msg);
}
else
else {
tr->setUserData(0);
tr->setDestroy();
}
line = 0;
conn->deref();
return true;
}
@ -1793,7 +1828,6 @@ void YIAXConnection::callAccept(Message& msg)
DDebug(this,DebugCall,"callAccept [%p]",this);
m_mutexTrans.lock();
if (m_transaction) {
m_transaction->getEngine()->initOutDataAdjust(msg,m_transaction);
u_int32_t codecs = iplugin.getEngine()->capability();
if (msg.getValue("formats")) {
u_int32_t ca = IAXFormat::mask(codecs,IAXFormat::Audio);