Projects tigase _server server-core Issues #458
Initial presence to bare JID (#458)
Won't Fix
Daniele Ricci opened 9 years ago
Due Date
2015-04-15

I'm receiving initial presence (only presence stanzas after initial roster presence) directed to my bare JID:

D / SMACK    ( 1566): RECV (21): <presence to="aaaaaaaa@prime.kontalk.net" from="xxxxxxx@prime.kontalk.net/fcdf4358747b37f7" id="FFD3R-164" xmlns="jabber:client">[...other elements...]</presence>

This makes some operations work unreliably (I implemented a Client State Indication plugin which uses a filter, however I can't filter based on full JID since it will filter out also presence data to other resources which are not inactive).

I don't know if it's correct behaviour or not, can you confirm please? RFC 6121 is a little bit confusing about this IMHO.

Using version 7.0.0.

Daniele Ricci commented 9 years ago

In Presence.java:930, initVars() is called with copyWithoutResource(), but then setPacketTo is used to deliver the stanza to the right connection, so I guess it's intended, but why?

Artur Hefczyc commented 9 years ago

This all works as intended. Please take a look at the RFC-6121 section 4.2.2

Initial presence is supposed to be sent to BareJID. Presence sent to a full JID is a special presence called Direct presence which is used in specific cases.

Daniele Ricci commented 9 years ago

Ok, so why roster initial presence is sent to full JID then?

D / SMACK    (10936): RECV (28): <presence from="39006031729e26ed52c32492820f8bcc7860a80a@beta.kontalk.net" xmlns="jabber:client" to="e73ea3be23d0449597a82c62ed981f584a5c181b@beta.kontalk.net/eb2e56271013472f" type="unavailable"><delay xmlns="urn:xmpp:delay" stamp="2015-04-16T17:20:39.129Z"/></presence>

I know that initial presence is sent to bare JIDs, and that is right, but in the end a bare JID will be splitted into multiple full JIDs right? Doesn't it mean that multiple packets will be sent if more than one resource is connected?

Artur Hefczyc commented 9 years ago

Daniele Ricci wrote:

Ok, so why roster initial presence is sent to full JID then?

This is unavailable presence. It should also be sent to a BareJID. I have to little information to tell why it is addressed to FullJID. Maybe it was a direct presence?

I know that initial presence is sent to bare JIDs, and that is right, but in the end a bare JID will be splitted into multiple full JIDs right? Doesn't it mean that multiple packets will be sent if more than one resource is connected?

Yes, if a user to whom an initial presence is sent, has many resources connected, the presence is sent to all the user's resources. So, yes, at some point there are multiple packets generated, one for each resource/connection. That does not mean, however, that the destination address is changed.

Daniele Ricci commented 9 years ago

This is unavailable presence. It should also be sent to a BareJID. I have to little information to tell why it is addressed to FullJID. Maybe it was a direct presence?

No, that was a presence received after requesting the roster (that is, after sending the first initial presence and having requested the roster before). Those are received correctly with the "to" attribute as full JID, because they come from presence probes probably.

Presence updates though (the first one I reported) are sent directly through Presence.updatePresenceChange() which calls that copyWithoutResource at line 930, resulting in the "to" attribute being a bare JID (of course it's delivered to all resources, but the "to" attribute a client will see will be a bare JID, that's what I'm seeing this as a bug, but maybe I'm wrong: I'm just looking at what it seems to be an inconsistent behaviour between presence updates and roster presence and I wanted to understand).

However I just tried another XMPP server and it seems to do the same thing.

But I don't understand: an initial presence doesn't have a "to" attribute. It is injected by the server when broadcasting the presence stanza, therefore it can put whatever it wants, including changing the "to" attribute for every destination, appending a different resource everytime.

Anyway, with this approach, how can I check if a presence update is directed to a specific resource when dealing with a Client State Indication implementation? Please note that CSI can be activated per-session.

Artur Hefczyc commented 9 years ago

Daniele Ricci wrote:

This is unavailable presence. It should also be sent to a BareJID. I have to little information to tell why it is addressed to FullJID. Maybe it was a direct presence?

No, that was a presence received after requesting the roster (that is, after sending the first initial presence and having requested the roster before). Those are received correctly with the "to" attribute as full JID, because they come from presence probes probably.

This is the packet you attached above:

<presence 
  xmlns="jabber:client" 
  from="39006031729e26ed52c32492820f8bcc7860a80a@beta.kontalk.net" 
  to="e73ea3be23d0449597a82c62ed981f584a5c181b@beta.kontalk.net/eb2e56271013472f" 
  type="unavailable">
  <delay xmlns="urn:xmpp:delay" stamp="2015-04-16T17:20:39.129Z"/>
</presence>

As you see this is unavailable presence. Where is it sent from, and why it has full JID in to is something that would need to be investigated.

Presence updates though (the first one I reported) are sent directly through Presence.updatePresenceChange() which calls that copyWithoutResource at line 930, resulting in the "to" attribute being a bare JID (of course it's delivered to all resources, but the "to" attribute a client will see will be a bare JID, that's what I'm seeing this as a bug, but maybe I'm wrong:

Well, you might be right but the server does what the RFC says.

I'm just looking at what it seems to be an inconsistent behaviour between presence updates and roster presence and I wanted to understand).

I am still not catching what kind of inconsistency you see? Could you please elaborate on this? I do not see any inconsistency. Presence about roster contact status should always be addressed to a BareJID.

However I just tried another XMPP server and it seems to do the same thing.

But I don't understand: an initial presence doesn't have a "to" attribute. It is injected by the server when broadcasting the presence stanza, therefore it can put whatever it wants, including changing the "to" attribute for every destination, appending a different resource everytime.

Yes, it can but the server just follows the spec. As I said, presences addressed to a full JID are different kinds of presence, called direct presence and serve different purpose.

In general I think the presence protocol is overloaded as the presence packets are used for many different things, too many. Which makes presence handling implementation complicated and hard to optimize.

Anyway, with this approach, how can I check if a presence update is directed to a specific resource when dealing with a Client State Indication implementation? Please note that CSI can be activated per-session.

What is Client State Indication? Do you have any spec for CSI?

Daniele Ricci commented 9 years ago

Of course, here is XEP-0352: http://xmpp.org/extensions/xep-0352.html

It's an extension to define an "inactive state" that a client can request to queue not urgent information (such as presence updates) to be delayed when going back to the "active state". This state is per-session (i.e. per-resource), meaning that when I filter presence updates, I need to know the final destination of the presence stanza.

But since presence updates have a bare JID in their "to" attribute (despite they are delivered directly using setPacketTo(session.getConnectionId()), I can't say to what resource will be delivered (I lookup the results queue and filter packets based on the "to" attribute). This is my filter() method:

    @Override
    public void filter(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results) {
        if ((session == null) || (!session.isAuthorized()) || (results == null) || (results.size() == 0)) {
            return;
        }

        final InternalQueue queue = (InternalQueue) session.getSessionData(SESSION_QUEUE);
        if (queue == null) {
            return;
        }

        for (Iterator<Packet> it = results.iterator(); it.hasNext(); ) {
            Packet res = it.next();
            try {
                synchronized (queue) {
                    if (res.getStanzaTo() != null && session.getJID().equals(res.getStanzaTo())) {
                        if (log.isLoggable(Level.FINEST)) {
                            log.log(Level.FINEST, "Checking packet {0} for session {1}",
                                    new Object[]{packet, session});
                        }
                        if (filterPacket(res, queue)) {
                            it.remove();
                        }
                    }
                }
            }
            catch (NotAuthorizedException ignored) {
                // ignore
            }
        }
    }
  1. InternalQueue is the queue where I put presence updates into

  2. The method iterates through the results queue, looking for packets intended to the current resource session

  3. The filterPacket method decides if the packet needs to be filtered out or not

If presence updates have a bare JID in the "to" attribute, this condition will never be true:

if (session.getStanzaTo() != null && session.getJID().equals(res.getStanzaTo())) {

Or maybe I'm simply not understanding how filtering works?

The whole class can be inspected here:

https://github.com/kontalk/tigase-extension/blob/master/src/main/java/org/kontalk/xmppserver/ClientStateIndication.java

By the way I will probably merge this XEP implementation into your codebase when it will be finished and tested :)

Thanks for the help.

Artur Hefczyc commented 9 years ago

Daniele Ricci wrote:

Of course, here is XEP-0352: http://xmpp.org/extensions/xep-0352.html

It's an extension to define an "inactive state" that a client can request to queue not urgent information (such as presence updates) to be delayed when going back to the "active state".

OK, so this is something similar to what we already have in Tigase and it is named: MobileV1, MobileV2 and MobileV3 extension. This is our custom solution which predates the XEP but the intentions and idea is the same.

This state is per-session (i.e. per-resource), meaning that when I filter presence updates, I need to know the final destination of the presence stanza.

In general a presence updates with BareJID is destined to all user's resources/connections.

But since presence updates have a bare JID in their "to" attribute (despite they are delivered directly using setPacketTo(session.getConnectionId()), I can't say to what resource will be delivered (I lookup the results queue and filter packets based on the "to" attribute). This is my filter() method:

I suggest you look at the MobileV3 code to see how it is done. This would be the best code example. Maybe the MobileV3 is good enough for your needs and you do not need to implement the XEP.

Daniele Ricci commented 9 years ago

Artur Hefczyc wrote:

I suggest you look at the MobileV3 code to see how it is done. This would be the best code example. Maybe the MobileV3 is good enough for your needs and you do not need to implement the XEP.

I saw the code, I understand now how it works: you use the connectionId in combination with the packetTo attribute to deliver stanzas to the right resource. I'll use that approach with my implementation and contribute the code to Tigase by sending a patch. Thanks for the help!

Referenced from commit 11 months ago
Referenced from commit 11 months ago
Referenced from commit 11 months ago
issue 1 of 1
Type
Bug
Priority
Major
Assignee
RedmineID
2990
Issue Votes (0)
Watchers (0)
Reference
tigase/_server/server-core#458
Please wait...
Page is in error, reload to recover