Fixed stream iq stanza decoding. Increased jingle stanza timeout. Changed debug and comments.
git-svn-id: http://yate.null.ro/svn/yate/trunk@1918 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
eaad179c28
commit
1b00fcf7f4
|
@ -1333,7 +1333,7 @@ XMPPUser::~XMPPUser()
|
|||
}
|
||||
|
||||
// Add a resource for the user
|
||||
bool XMPPUser::addLocalRes(JIDResource* resource)
|
||||
bool XMPPUser::addLocalRes(JIDResource* resource, bool send)
|
||||
{
|
||||
if (!resource)
|
||||
return false;
|
||||
|
@ -1341,11 +1341,11 @@ bool XMPPUser::addLocalRes(JIDResource* resource)
|
|||
if (!m_localRes.add(resource))
|
||||
return false;
|
||||
DDebug(m_local->engine(),DebugAll,
|
||||
"User(%s). Added resource name=%s audio=%s [%p]",
|
||||
"User(%s). Added local resource name=%s audio=%s avail=%s [%p]",
|
||||
m_local->jid().c_str(),resource->name().c_str(),
|
||||
String::boolText(resource->hasCap(JIDResource::CapAudio)),this);
|
||||
resource->setPresence(true);
|
||||
if (m_subscription.from())
|
||||
String::boolText(resource->hasCap(JIDResource::CapAudio)),
|
||||
String::boolText(resource->available()),this);
|
||||
if (send && m_subscription.from())
|
||||
sendPresence(resource,0,true);
|
||||
return true;
|
||||
}
|
||||
|
@ -1353,15 +1353,18 @@ bool XMPPUser::addLocalRes(JIDResource* resource)
|
|||
// Remove a resource of the user
|
||||
void XMPPUser::removeLocalRes(JIDResource* resource)
|
||||
{
|
||||
if (!(resource && m_localRes.get(resource->name())))
|
||||
if (!(resource && m_localRes.get(resource->name()))) {
|
||||
TelEngine::destruct(resource);
|
||||
return;
|
||||
}
|
||||
Lock lock(this);
|
||||
resource->setPresence(false);
|
||||
if (m_subscription.from())
|
||||
sendPresence(resource,0);
|
||||
m_localRes.remove(resource);
|
||||
DDebug(m_local->engine(),DebugAll,"User(%s). Removed resource name=%s [%p]",
|
||||
DDebug(m_local->engine(),DebugAll,
|
||||
"User(%s). Removing local resource name=%s [%p]",
|
||||
m_local->jid().c_str(),resource->name().c_str(),this);
|
||||
m_localRes.remove(resource);
|
||||
}
|
||||
|
||||
// Remove all user's resources
|
||||
|
|
|
@ -59,8 +59,8 @@ TokenDict JBStream::s_flagName[] = {
|
|||
static String s_version = "1.0"; // Protocol version
|
||||
static String s_declaration = "<?xml version='1.0' encoding='UTF-8'?>";
|
||||
|
||||
// Utility: append a param to a string
|
||||
inline void s_appendParam(String& dest, const char* name, const char* value,
|
||||
// Utility: append a quoted param to a string
|
||||
inline void appendQParam(String& dest, const char* name, const char* value,
|
||||
bool quotes, bool first = false)
|
||||
{
|
||||
if (!first)
|
||||
|
@ -72,6 +72,27 @@ inline void s_appendParam(String& dest, const char* name, const char* value,
|
|||
dest << value;
|
||||
}
|
||||
|
||||
// Check if an element exists and have an expected namespace
|
||||
inline bool checkValidXmlns(XMLElement* e, XMPPNamespace::Type ns,
|
||||
XMPPError::Type& error)
|
||||
{
|
||||
if (e && XMPPUtils::hasXmlns(*e,ns))
|
||||
return true;
|
||||
error = e ? XMPPError::SFeatureNotImpl : XMPPError::SBadRequest;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fix some element name conflicts: change type according to their namespace
|
||||
// Some elements may have the same name in different namespaces
|
||||
inline void fixXmlType(XMLElement* xml)
|
||||
{
|
||||
if (!xml)
|
||||
return;
|
||||
if (xml->type() == XMLElement::Session &&
|
||||
xml->hasAttribute("xmlns",s_ns[XMPPNamespace::Jingle]))
|
||||
xml->changeType(XMLElement::Jingle);
|
||||
}
|
||||
|
||||
#define DROP_AND_EXIT { dropXML(xml); return; }
|
||||
#define INVALIDXML_AND_EXIT(code,reason) { invalidStreamXML(xml,code,reason); return; }
|
||||
#define ERRORXML_AND_EXIT { errorStreamXML(xml); return; }
|
||||
|
@ -774,19 +795,6 @@ void JBStream::processRunning(XMLElement* xml)
|
|||
sendStanza(XMPPUtils::createError(xml,XMPPError::TypeModify,error));
|
||||
}
|
||||
|
||||
// Helper function to make the code simpler
|
||||
inline bool checkChild(XMLElement* e, XMPPNamespace::Type ns, XMPPError::Type& error)
|
||||
{
|
||||
if (!e) {
|
||||
error = XMPPError::SBadRequest;
|
||||
return false;
|
||||
}
|
||||
if (XMPPUtils::hasXmlns(*e,ns))
|
||||
return true;
|
||||
error = XMPPError::SFeatureNotImpl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Process a received element in Securing state
|
||||
void JBStream::processSecuring(XMLElement* xml)
|
||||
{
|
||||
|
@ -1060,121 +1068,102 @@ void JBStream::processStarted(XMLElement* xml)
|
|||
}
|
||||
|
||||
// Create an iq event from a received iq stanza
|
||||
// Filter iq stanzas to generate an appropriate event
|
||||
// Get iq type : set/get, error, result
|
||||
// result: MAY have a first child with a response
|
||||
// set/get: MUST have a first child
|
||||
// error: MAY have a first child with the sent stanza
|
||||
// MUST have an 'error' child
|
||||
// Check type and the first child's namespace
|
||||
JBEvent* JBStream::getIqEvent(XMLElement* xml, int iqType, XMPPError::Type& error)
|
||||
{
|
||||
// Filter iq stanzas to generate an appropriate event
|
||||
// Get iq type : set/get, error, result
|
||||
// result: MAY have a first child with a response
|
||||
// set/get: MUST have a first child
|
||||
// error: MAY have a first child with the sent stanza
|
||||
// MUST have an 'error' child
|
||||
// Check type and the first child's namespace
|
||||
XMLElement* child = xml->findFirstChild();
|
||||
#define IQEVENT_SET_REQ(get,set) evType = (iqType == XMPPUtils::IqGet) ? get : set
|
||||
#define IQEVENT_SET_RSP(res,err) evType = (iqType == XMPPUtils::IqResult) ? res : err
|
||||
JBEvent::Type evType;
|
||||
switch (iqType) {
|
||||
case XMPPUtils::IqGet:
|
||||
case XMPPUtils::IqSet:
|
||||
evType = JBEvent::Iq;
|
||||
break;
|
||||
case XMPPUtils::IqResult:
|
||||
evType = JBEvent::IqResult;
|
||||
break;
|
||||
case XMPPUtils::IqError:
|
||||
evType = JBEvent::IqError;
|
||||
break;
|
||||
default:
|
||||
error = XMPPError::SFeatureNotImpl;
|
||||
return 0;
|
||||
}
|
||||
error = XMPPError::NoError;
|
||||
XMLElement* child = 0;
|
||||
|
||||
// Fix some element name conflicts
|
||||
if (child && child->type() == XMLElement::Session &&
|
||||
child->hasAttribute("xmlns",s_ns[XMPPNamespace::Jingle]))
|
||||
child->changeType(XMLElement::Jingle);
|
||||
|
||||
// Create event
|
||||
if (iqType == XMPPUtils::IqResult || iqType == XMPPUtils::IqSet ||
|
||||
iqType == XMPPUtils::IqGet) {
|
||||
// Request (type is set or get): check the child (MUST exists)
|
||||
// Response (type is result or error). Check it only if it has an 'iq' child
|
||||
if (evType == JBEvent::Iq) {
|
||||
child = xml->findFirstChild();
|
||||
// No child: request what ???
|
||||
if (!child) {
|
||||
if (iqType == XMPPUtils::IqResult)
|
||||
return new JBEvent(JBEvent::IqResult,this,xml);
|
||||
return new JBEvent(JBEvent::Iq,this,xml);
|
||||
error = XMPPError::SBadRequest;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fixXmlType(child);
|
||||
switch (child->type()) {
|
||||
case XMLElement::Jingle:
|
||||
if (!checkChild(child,XMPPNamespace::Jingle,error))
|
||||
return 0;
|
||||
switch (iqType) {
|
||||
case XMPPUtils::IqGet:
|
||||
return new JBEvent(JBEvent::IqJingleGet,this,xml,child);
|
||||
case XMPPUtils::IqSet:
|
||||
return new JBEvent(JBEvent::IqJingleSet,this,xml,child);
|
||||
case XMPPUtils::IqResult:
|
||||
return new JBEvent(JBEvent::IqJingleRes,this,xml,child);
|
||||
}
|
||||
if (checkValidXmlns(child,XMPPNamespace::Jingle,error))
|
||||
IQEVENT_SET_REQ(JBEvent::IqJingleGet,JBEvent::IqJingleSet);
|
||||
break;
|
||||
case XMLElement::Query:
|
||||
if (checkChild(child,XMPPNamespace::DiscoInfo,error))
|
||||
switch (iqType) {
|
||||
case XMPPUtils::IqGet:
|
||||
return new JBEvent(JBEvent::IqDiscoInfoGet,this,xml,child);
|
||||
case XMPPUtils::IqSet:
|
||||
return new JBEvent(JBEvent::IqDiscoInfoSet,this,xml,child);
|
||||
case XMPPUtils::IqResult:
|
||||
return new JBEvent(JBEvent::IqDiscoInfoRes,this,xml,child);
|
||||
}
|
||||
else if (checkChild(child,XMPPNamespace::DiscoItems,error))
|
||||
switch (iqType) {
|
||||
case XMPPUtils::IqGet:
|
||||
return new JBEvent(JBEvent::IqDiscoItemsGet,this,xml,child);
|
||||
case XMPPUtils::IqSet:
|
||||
return new JBEvent(JBEvent::IqDiscoItemsSet,this,xml,child);
|
||||
case XMPPUtils::IqResult:
|
||||
return new JBEvent(JBEvent::IqDiscoItemsRes,this,xml,child);
|
||||
}
|
||||
else if (checkChild(child,XMPPNamespace::Roster,error))
|
||||
switch (iqType) {
|
||||
case XMPPUtils::IqGet:
|
||||
error = XMPPError::SBadRequest;
|
||||
break;
|
||||
case XMPPUtils::IqSet:
|
||||
return new JBEvent(JBEvent::IqRosterSet,this,xml,child);
|
||||
case XMPPUtils::IqResult:
|
||||
return new JBEvent(JBEvent::IqRosterRes,this,xml,child);
|
||||
}
|
||||
return 0;
|
||||
if (checkValidXmlns(child,XMPPNamespace::DiscoInfo,error))
|
||||
IQEVENT_SET_REQ(JBEvent::IqDiscoInfoGet,JBEvent::IqDiscoInfoSet);
|
||||
else if (checkValidXmlns(child,XMPPNamespace::DiscoItems,error))
|
||||
IQEVENT_SET_REQ(JBEvent::IqDiscoItemsGet,JBEvent::IqDiscoItemsSet);
|
||||
else if (checkValidXmlns(child,XMPPNamespace::Roster,error))
|
||||
if (iqType == XMPPUtils::IqGet)
|
||||
error = XMPPError::SBadRequest;
|
||||
else
|
||||
evType = JBEvent::IqRosterSet;
|
||||
break;
|
||||
case XMLElement::Command:
|
||||
if (!checkChild(child,XMPPNamespace::Command,error))
|
||||
return 0;
|
||||
switch (iqType) {
|
||||
case XMPPUtils::IqGet:
|
||||
return new JBEvent(JBEvent::IqCommandGet,this,xml,child);
|
||||
case XMPPUtils::IqSet:
|
||||
return new JBEvent(JBEvent::IqCommandSet,this,xml,child);
|
||||
case XMPPUtils::IqResult:
|
||||
return new JBEvent(JBEvent::IqCommandRes,this,xml,child);
|
||||
}
|
||||
if (checkValidXmlns(child,XMPPNamespace::Command,error))
|
||||
IQEVENT_SET_REQ(JBEvent::IqCommandGet,JBEvent::IqCommandSet);
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
// Unhandled child
|
||||
if (iqType != XMPPUtils::IqResult)
|
||||
return new JBEvent(JBEvent::Iq,this,xml,child);
|
||||
return new JBEvent(JBEvent::IqResult,this,xml,child);
|
||||
}
|
||||
else if (iqType == XMPPUtils::IqError) {
|
||||
JBEvent::Type evType = JBEvent::IqError;
|
||||
// First child may be a sent stanza
|
||||
if (child && child->type() != XMLElement::Error) {
|
||||
switch (child->type()) {
|
||||
else {
|
||||
child = xml->findFirstChild(XMLElement::Iq);
|
||||
XMLElement* c = child ? child->findFirstChild() : 0;
|
||||
// The child of this 'iq' sets the event's type
|
||||
if (c) {
|
||||
fixXmlType(c);
|
||||
switch (c->type()) {
|
||||
case XMLElement::Jingle:
|
||||
evType = JBEvent::IqJingleErr;
|
||||
if (XMPPUtils::hasXmlns(*c,XMPPNamespace::Jingle))
|
||||
IQEVENT_SET_RSP(JBEvent::IqJingleRes,JBEvent::IqJingleErr);
|
||||
break;
|
||||
case XMLElement::Query:
|
||||
if (XMPPUtils::hasXmlns(*xml,XMPPNamespace::DiscoInfo))
|
||||
evType = JBEvent::IqDiscoInfoErr;
|
||||
else if (XMPPUtils::hasXmlns(*xml,XMPPNamespace::DiscoItems))
|
||||
evType = JBEvent::IqDiscoItemsErr;
|
||||
else if (XMPPUtils::hasXmlns(*xml,XMPPNamespace::Roster))
|
||||
evType = JBEvent::IqRosterErr;
|
||||
if (XMPPUtils::hasXmlns(*c,XMPPNamespace::DiscoInfo))
|
||||
IQEVENT_SET_RSP(JBEvent::IqDiscoInfoRes,JBEvent::IqDiscoInfoErr);
|
||||
else if (XMPPUtils::hasXmlns(*c,XMPPNamespace::DiscoItems))
|
||||
IQEVENT_SET_RSP(JBEvent::IqDiscoItemsRes,JBEvent::IqDiscoItemsErr);
|
||||
else if (XMPPUtils::hasXmlns(*c,XMPPNamespace::Roster))
|
||||
IQEVENT_SET_RSP(JBEvent::IqRosterRes,JBEvent::IqRosterErr);
|
||||
break;
|
||||
case XMLElement::Command:
|
||||
evType = JBEvent::IqCommandErr;
|
||||
if (XMPPUtils::hasXmlns(*c,XMPPNamespace::Command))
|
||||
IQEVENT_SET_RSP(JBEvent::IqCommandRes,JBEvent::IqCommandErr);
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
child = xml->findNextChild(child);
|
||||
}
|
||||
if (!(child && child->type() == XMLElement::Error))
|
||||
child = 0;
|
||||
return new JBEvent(evType,this,xml,child);
|
||||
}
|
||||
error = XMPPError::SBadRequest;
|
||||
|
||||
if (error == XMPPError::NoError)
|
||||
return new JBEvent(evType,this,xml,child);
|
||||
return 0;
|
||||
#undef IQEVENT_SET_REQ
|
||||
#undef IQEVENT_SET_RSP
|
||||
}
|
||||
|
||||
// Send declaration and stream start
|
||||
|
@ -1453,28 +1442,28 @@ void JBStream::buildSaslResponse(String& response, String* realm, String* nonce)
|
|||
// Digest MD5. See RFC 2831 2.1.2.1
|
||||
MD5 md5(String((unsigned int)::random()));
|
||||
m_cnonce = md5.hexDigest();
|
||||
s_appendParam(response,"username",m_local.node(),true,true);
|
||||
appendQParam(response,"username",m_local.node(),true,true);
|
||||
if (realm) {
|
||||
m_realm = *realm;
|
||||
s_appendParam(response,"realm",m_realm,true);
|
||||
appendQParam(response,"realm",m_realm,true);
|
||||
if (nonce) {
|
||||
m_nonce = *nonce;
|
||||
s_appendParam(response,"nonce",m_nonce,true);
|
||||
appendQParam(response,"nonce",m_nonce,true);
|
||||
m_nonceCount++;
|
||||
char tmp[9];
|
||||
::sprintf(tmp,"%08x",m_nonceCount);
|
||||
m_nc = tmp;
|
||||
s_appendParam(response,"nc",m_nc,false);
|
||||
appendQParam(response,"nc",m_nc,false);
|
||||
}
|
||||
}
|
||||
s_appendParam(response,"cnonce",m_cnonce,true);
|
||||
s_appendParam(response,"digest-uri",String("xmpp/")+m_local.domain(),true);
|
||||
s_appendParam(response,"qop",s_qop,true);
|
||||
appendQParam(response,"cnonce",m_cnonce,true);
|
||||
appendQParam(response,"digest-uri",String("xmpp/")+m_local.domain(),true);
|
||||
appendQParam(response,"qop",s_qop,true);
|
||||
String rsp;
|
||||
buildDigestMD5Sasl(rsp,true);
|
||||
s_appendParam(response,"response",rsp,false);
|
||||
s_appendParam(response,"charset","utf-8",false);
|
||||
s_appendParam(response,"algorithm","md5-sess",false);
|
||||
appendQParam(response,"response",rsp,false);
|
||||
appendQParam(response,"charset","utf-8",false);
|
||||
appendQParam(response,"algorithm","md5-sess",false);
|
||||
Base64 base64((void*)response.c_str(),response.length());
|
||||
base64.encode(response);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ static XMPPError s_err;
|
|||
*/
|
||||
JGEngine::JGEngine(JBEngine* engine, const NamedList* params, int prio)
|
||||
: JBService(engine,"jgengine",params,prio), m_sessionIdMutex(true),
|
||||
m_sessionId(1), m_stanzaTimeout(10000), m_useSidAttr(false)
|
||||
m_sessionId(1), m_stanzaTimeout(20000), m_useSidAttr(false)
|
||||
{
|
||||
JBThreadList::setOwner(this);
|
||||
}
|
||||
|
|
|
@ -70,10 +70,9 @@ public:
|
|||
Presence = 20, // m_element is a 'presence' stanza
|
||||
Message = 30, // m_element is a 'message' stanza
|
||||
Iq = 50, // m_element is an 'iq' set/get, m_child is it's first child
|
||||
IqError = 51, // m_element is an 'iq' error, m_child is the 'error' child if any
|
||||
IqResult = 52, // m_element is an 'iq' result, m_child is it's first child
|
||||
IqError = 51, // m_element is an 'iq' error, m_child is the 'iq' child if any
|
||||
IqResult = 52, // m_element is an 'iq' result, m_child is it's first child if any
|
||||
// Disco: m_child is a 'query' element qualified by DiscoInfo/DiscoItems namespaces
|
||||
// IqDisco error: m_child is the 'error' child, m_element has a 'query' child
|
||||
IqDiscoInfoGet = 60,
|
||||
IqDiscoInfoSet = 61,
|
||||
IqDiscoInfoRes = 62,
|
||||
|
@ -83,13 +82,11 @@ public:
|
|||
IqDiscoItemsRes = 66,
|
||||
IqDiscoItemsErr = 67,
|
||||
// Command: m_child is a 'command' element qualified by Command namespace
|
||||
// IqCommandError: m_child is the 'error' child, m_element has a 'command' child
|
||||
IqCommandGet = 70,
|
||||
IqCommandSet = 71,
|
||||
IqCommandRes = 72,
|
||||
IqCommandErr = 73,
|
||||
// Jingle: m_child is a 'jingle' element qualified by Jingle namespace
|
||||
// IqJingleError: m_child is the 'error' child, m_element has a 'jingle' child
|
||||
IqJingleGet = 80,
|
||||
IqJingleSet = 81,
|
||||
IqJingleRes = 82,
|
||||
|
@ -2237,14 +2234,29 @@ public:
|
|||
inline XMPPDirVal& subscription()
|
||||
{ return m_subscription; }
|
||||
|
||||
/**
|
||||
* Get the local resource list
|
||||
* @return The local resource list
|
||||
*/
|
||||
inline JIDResourceList& localRes()
|
||||
{ return m_localRes; }
|
||||
|
||||
/**
|
||||
* Get the remote resource list
|
||||
* @return The remote resource list
|
||||
*/
|
||||
inline JIDResourceList& remoteRes()
|
||||
{ return m_remoteRes; }
|
||||
|
||||
/**
|
||||
* Add a local resource to the list.
|
||||
* Send presence if the remote peer is subscribed to the local one.
|
||||
* This method is thread safe.
|
||||
* @param resource The resource to add.
|
||||
* @param send True to send presence from the resource if it is a new one
|
||||
* @return False if the the resource already exists in the list.
|
||||
*/
|
||||
bool addLocalRes(JIDResource* resource);
|
||||
bool addLocalRes(JIDResource* resource, bool send = true);
|
||||
|
||||
/**
|
||||
* Remove a local resource from the list.
|
||||
|
|
Loading…
Reference in New Issue