Handle jingle session redirect. Don't check the called party jid if requested in call.execute message.

git-svn-id: http://voip.null.ro/svn/yate@4000 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2010-12-21 13:58:55 +00:00
parent 0408bb83d5
commit 555a8262f6
2 changed files with 134 additions and 5 deletions

View File

@ -95,6 +95,17 @@
; resource.notify: integer: Override the priority of module's resource.notify message handler
;resource.notify=
; redirectcount: integer: Default value for outgoing calls redirect counter
; This parameter controls the behaviour of an outgoing call terminated
; with 'redirect' reason containing a non empty target
; If non 0 the counter is decreased. If the target is an XMPP uri the call will
; be re-executed internally.
; If the counter is 0 when terminated, the call parameters list will be filled with
; session parameters to let the PBX deal with it.
; This parameter can be overridden from routing
;redirectcount=0
[codecs]
; This section allows to individually enable or disable the codecs

View File

@ -285,6 +285,8 @@ private:
void handleAudioInfoEvent(JGEvent* event);
// Check jingle version override from call.execute or resource caps
void overrideJingleVersion(const NamedList& list, bool caps);
// Copy chan/session parameters to a destination list
void copySessionParams(NamedList& list, bool redirect = true);
Mutex m_mutex; // Lock transport and session
State m_state; // Connection state
@ -303,6 +305,7 @@ private:
String m_localip; // Local address
bool m_offerRawTransport; // Offer RAW transport on outgoing session
bool m_offerIceTransport; // Offer ICE transport on outgoing session
unsigned int m_redirectCount; // Redirect counter
// Crypto (for contents created by us)
bool m_secure; // The channel is using crypto
bool m_secureRequired; // Crypto is mandatory
@ -506,6 +509,7 @@ static bool s_acceptRelay = false;
static bool s_offerRawTransport = true; // Offer RAW UDP transport on outgoing sessions
static bool s_offerIceTransport = true; // Offer ICE UDP transport on outgoing sessions
static int s_priority = 0; // Resource priority for presence generated by this module
static unsigned int s_redirectCount = 0; // Redirect counter
static JGSession::Version s_sessVersion = JGSession::VersionUnknown; // Default jingle session version for outgoing calls
static String s_capsNode = "http://yate.null.ro/yate/jingle/caps"; // node for entity capabilities
static bool s_serverMode = true; // Server/client mode
@ -572,6 +576,18 @@ static inline void addValidParam(Message& m, const char* param, const char* valu
m.addParam(param,value);
}
// Add a parameter to a list.
// Optionally add it to a copy params string
static inline void jingleAddParam(NamedList& list, const char* param, const char* value,
String* copy, bool emptyOk = true)
{
if (TelEngine::null(param))
return;
list.addParam(param,value,emptyOk);
if (copy)
copy->append(param,",");
}
// Add formats to a list of jingle payloads
static void setMedia(JGRtpMediaList& dest, const String& formats,
const JGRtpMediaList& src)
@ -636,10 +652,15 @@ void YJGEngine::processEvent(JGEvent* event)
delete event;
return;
}
plugin.lock();
YJGConnection* conn = static_cast<YJGConnection*>(session->userData());
if (conn)
conn->ref();
plugin.unlock();
if (conn) {
if (!conn->handleEvent(event) || event->final())
conn->disconnect(event->reason());
TelEngine::destruct(conn);
}
else {
if (event->type() == JGEvent::Jingle &&
@ -700,11 +721,14 @@ YJGConnection::YJGConnection(Message& msg, const char* caller, const char* calle
m_callerPrompt(msg.getValue("callerprompt")),
m_localip(localip),
m_offerRawTransport(true), m_offerIceTransport(true),
m_redirectCount(s_redirectCount),
m_secure(s_useCrypto), m_secureRequired(s_cryptoMandatory),
m_hangup(false), m_timeout(0), m_transferring(false), m_recvTransferStanza(0),
m_dataFlags(0), m_ftStatus(FTNone), m_ftHostDirection(FTHostNone),
m_connSocksServer(msg.getBoolValue("socksserver",true))
{
int redir = msg.getIntValue("redirectcount",m_redirectCount);
m_redirectCount = (redir >= 0) ? redir : 0;
m_secure = msg.getBoolValue("secure",m_secure);
m_secureRequired = msg.getBoolValue("secure_required",m_secureRequired);
overrideJingleVersion(msg,false);
@ -790,7 +814,7 @@ YJGConnection::YJGConnection(JGEvent* event)
m_sessVersion(event->session()->version()),
m_local(event->session()->local()), m_remote(event->session()->remote()),
m_audioContent(0),
m_offerRawTransport(true), m_offerIceTransport(true),
m_offerRawTransport(true), m_offerIceTransport(true), m_redirectCount(0),
m_secure(s_useCrypto), m_secureRequired(s_cryptoMandatory),
m_hangup(false), m_timeout(0), m_transferring(false), m_recvTransferStanza(0),
m_dataFlags(0), m_ftStatus(FTNone), m_ftHostDirection(FTHostNone),
@ -1323,6 +1347,51 @@ bool YJGConnection::handleEvent(JGEvent* event)
}
if (event->type() == JGEvent::Terminated) {
// Handle redirect
if (isOutgoing() && event->reason() == "redirect" && event->text()) {
bool validCounter = false;
if (m_redirectCount) {
m_redirectCount--;
validCounter = true;
}
// Handle here XMPP targets
// Let the pbx deal with other targets
if (validCounter && event->text().startsWith("xmpp:",false)) {
JabberID callto(event->text().substr(5));
if (callto.bare()) {
if (callto == m_remote) {
Debug(this,DebugNote,"Got redirect to the same remote party! [%p]",this);
callto.clear();
}
}
else {
Debug(this,DebugNote,"Got redirect to incomplete jid=%s [%p]",
event->text().c_str(),this);
callto.clear();
}
String id;
if (callto && getPeerId(id)) {
Message m("chan.masquerade");
m.addParam("message","call.execute");
m.addParam("id",id);
m.addParam("callto",plugin.prefix() + callto);
m.addParam("caller",m_local,false);
copySessionParams(m);
Debug(this,DebugCall,"Redirecting to '%s' [%p]",callto.c_str(),this);
lock.drop();
Engine::dispatch(m);
}
}
else {
parameters().clearParams();
URI uri(event->text());
parameters().addParam("called",uri.getUser());
parameters().addParam("calledname",uri.getDescription(),false);
parameters().addParam("calleduri",event->text());
parameters().addParam("copyparams","");
copySessionParams(parameters());
}
}
const char* reason = event->reason();
Debug(this,DebugInfo,
"Session terminated with reason='%s' text='%s' [%p]",
@ -2906,6 +2975,52 @@ void YJGConnection::overrideJingleVersion(const NamedList& list, bool caps)
}
}
// Copy chan/session params to a destination list
void YJGConnection::copySessionParams(NamedList& list, bool redirect)
{
String* copy = list.getParam("copyparams");
if (redirect) {
list.addParam("redirect",String::boolText(true));
jingleAddParam(list,"redirectcount",String(m_redirectCount),copy);
list.addParam("diverter",m_remote,false);
}
if (m_ftStatus == FTNone)
jingleAddParam(list,"formats",m_formats,copy,false);
else
jingleAddParam(list,"format","data",copy);
// Jingle session params
jingleAddParam(list,"line",m_line,copy,false);
jingleAddParam(list,"ojingle_version",
JGSession::lookupVersion(m_sessVersion,""),copy,false);
jingleAddParam(list,"callerprompt",m_callerPrompt,copy,false);
jingleAddParam(list,"subject",m_subject,copy,false);
jingleAddParam(list,"secure",String::boolText(m_secure),copy);
jingleAddParam(list,"secure_required",String::boolText(m_secureRequired),copy);
jingleAddParam(list,"offerrawudp",String::boolText(m_offerRawTransport),copy);
jingleAddParam(list,"offericeudp",String::boolText(m_offerIceTransport),copy);
// File transfer
JGSessionContent* c = firstFTContent();
if (!c)
return;
const char* oper = 0;
if (c->type() == JGSessionContent::FileBSBOffer)
oper = "send";
else if (c->type() == JGSessionContent::FileBSBRequest)
oper = "receive";
else
return;
const String& file = c->m_fileTransfer["name"];
if (!file)
return;
jingleAddParam(list,"operation",oper,copy);
jingleAddParam(list,"file_name",file,copy);
jingleAddParam(list,"file_size",c->m_fileTransfer.getValue("size"),copy,false);
jingleAddParam(list,"file_md5",c->m_fileTransfer.getValue("hash"),copy,false);
unsigned int t = XMPPUtils::decodeDateTimeSec(c->m_fileTransfer["date"]);
if (t != (unsigned int)-1)
jingleAddParam(list,"file_time",String(t),copy);
}
/*
* Transfer thread (route and execute)
@ -3183,6 +3298,8 @@ void YJGDriver::initialize()
m_localAddress = sect->getValue("localip");
s_offerRawTransport = sect->getBoolValue("offerrawudp",true);
s_offerIceTransport = sect->getBoolValue("offericeudp",true);
int redir = sect->getIntValue("redirectcount");
s_redirectCount = (redir >= 0) ? redir : 0;
int prio = sect->getIntValue("resource_priority");
if (prio < -128)
@ -3271,6 +3388,7 @@ bool YJGDriver::msgExecute(Message& msg, String& dest)
msg.setParam("error","failure");
return false;
}
bool checkCalled = msg.getBoolValue("checkcalled",true);
const char* line = msg.getValue("line");
String localip;
// Set caller
@ -3322,11 +3440,11 @@ bool YJGDriver::msgExecute(Message& msg, String& dest)
else {
// Get line data
if (!TelEngine::null(line)) {
Message* m = plugin.checkAccount(line,true,&called);
Message* m = plugin.checkAccount(line,true,checkCalled ? &called : 0);
if (m) {
caller.set(m->getValue("jid"));
if (caller.isFull()) {
if (called && !called.resource())
if (checkCalled && called && !called.resource())
called.resource(m->getValue("instance"));
// Copy resource caps
unsigned int n = m->length();
@ -3354,7 +3472,7 @@ bool YJGDriver::msgExecute(Message& msg, String& dest)
return false;
}
// Called party must always be full in client mode
if (!(s_serverMode || called.isFull())) {
if (checkCalled && !(s_serverMode || called.isFull())) {
Debug(this,DebugNote,"Jingle call failed. Incomplete called '%s'",
called.c_str());
msg.setParam("error","failure");
@ -3379,7 +3497,7 @@ bool YJGDriver::msgExecute(Message& msg, String& dest)
}
}
bool online = !called.resource().null();
bool online = !(checkCalled && called.resource().null());
bool local = (caller.domain() == called.domain());
if (!online) {
bool reqSub = false;