MUC ignored an update of presence, but resent an old presence

I am using Openfire 4.2.3 that a user “focus” created a conference room (“myroom@conference.mydomain”) and joined the room. Then it updated its presence with an extension element “jibri-recording-status”, but the updated presence never arrived, instead an older presence packet arrived. However, when I used the same client app with a different XMPP server (Prosody), the updated presence with extension element arrived correctly. Has anyone seen this problem? Does Openfire MUC have any special settings to aggregate extended elements in the presence packet?

Here is the client side log using Openfire (notice that the response had an older packet-ID):

Jicofo 2018-07-18 20:41:47.212 INFO: [56] org.jitsi.impl.protocol.xmpp.XmppProtocolProvider.sendStanza().758 <presence to='myroom@conference.mydomain.com/focus' id='gPE4g-216'><x xmlns='http://jabber.org/protocol/muc'></x><etherpad xmlns='http://jitsi.org/jitmeet/etherpad'>7f5c315bcb0746a380625c89798a599f</etherpad><versions xmlns='http://jitsi.org/jitmeet'><component xmlns='http://jitsi.org/jitmeet' name='focus'>JiCoFo(1.0.build.SVN,Linux)</component></versions><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.igniterealtime.org/projects/smack' ver='lWpWNgqtfynY+MxupmhOr2LZqOg='/><jibri-recording-status xmlns='http://jitsi.org/protocol/jibri' status='off'/></presence>
Jicofo 2018-07-18 20:41:47.216 FINER: [40] org.jitsi.impl.protocol.xmpp.ChatRoomImpl.processPresence().1228 Presence received <presence to='focus@mydomain/focus2245713712296611' from='myroom@conference.mydomain/focus' id='gPE4g-20
4'><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.igniterealtime.org/projects/smack' ver='lWpWNgqtfynY+MxupmhOr2LZqOg='/><x xmlns='http://jabber.org/protocol/muc#user'><item affiliation='owner' jid='focus@mydomain/focus2245713712296611' role='moderator'></item><status code='100'/><status code='110'/></x></presence>

Here is the client side log using Prosody XMPP server:

Jicofo 2018-07-19 20:36:07.204 INFO: [70] org.jitsi.impl.protocol.xmpp.XmppProtocolProvider.sendStanza().758 <presence to='myroom@conference.mydomain/focus' id='TaLo2-104'><x xmlns='http://jabber.org/protocol/muc'></x><etherpad xmlns='http://jitsi.org/jitmeet/etherpad'>c920df6ea849470aaa316e6f13d627ff</etherpad><versions xmlns='http://jitsi.org/jitmeet'><component xmlns='http://jitsi.org/jitmeet' name='xmpp'>Prosody(0.9.10,Linux)</component><component xmlns='http://jitsi.org/jitmeet' name='focus'>JiCoFo(1.0.build.SVN,Linux)</component></versions><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://jitsi.org' ver='lWpWNgqtfynY+MxupmhOr2LZqOg='/><jibri-recording-status xmlns='http://jitsi.org/protocol/jibri' status='off'/></presence>
Jicofo 2018-07-19 20:36:07.212 FINER: [37] org.jitsi.impl.protocol.xmpp.ChatRoomImpl.processPresence().1246 Presence received <presence to='focus@auth.mydomain/focus2331872029122373' from='myroom@conference.mydomain/focus' id='TaLo2-104'><etherpad xmlns='http://jitsi.org/jitmeet/etherpad' xmlns:stream='http://etherx.jabber.org/streams'>c920df6ea849470aaa316e6f13d627ff</etherpad><versions xmlns='http://jitsi.org/jitmeet' xmlns:stream='http://etherx.jabber.org/streams'><component xmlns:stream='http://etherx.jabber.org/streams' name='xmpp'>Prosody(0.9.10,Linux)</component><component xmlns:stream='http://etherx.jabber.org/streams' name='focus'>JiCoFo(1.0.build.SVN,Linux)</component></versions><jibri-recording-status xmlns='http://jitsi.org/protocol/jibri' xmlns:stream='http://etherx.jabber.org/streams' status='off'></jibri-recording-status><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://jitsi.org' ver='lWpWNgqtfynY+MxupmhOr2LZqOg='/><x xmlns='http://jabber.org/protocol/muc#user'><item affiliation='owner' jid='focus@auth.jitsi2.magnet.com/focus2331872029122373' role='moderator'></item><status code='110'/></x></presence>

After further investigation, it seems to be “bug” in …/openfire/muc/spi/LocalMUCUser#process(Presence packet). In my use case, the “focus” user has joined the “myroom@conference.mydomain”. Then it updates the presence with the x element and additional custom element
<presence ...> <x xmlns='http://jabber.org/protocol/muc'></x>... <jibri-recording-status xmlns="http://jitsi.org/protocol/jibri" status="off"></jibri-recording-status> </presence>
The code (see below) assumes that if there is no role or there is an muc info (x element), the client wants to join the room. It throws away the update and sends out the previous presence info. By removing the “|| mucInfo != null” from the if-statement, everything works as expected.

    MUCRole role = roles.get(group);
    Element mucInfo = packet.getChildElement("x",
            "http://jabber.org/protocol/muc");
    if (role == null || mucInfo != null ) {
        // If we're not already in a room (role == null), we either are joining it or it's not
        // properly addressed and we drop it silently
        // Alternative is that mucInfo is not null, in which case the client thinks it isn't in the room, so we should join anyway.

So, is this fix safe?

Thanks for diving into this!

I don’t think your suggested fix is the way to go. What you suggest to remove is a fail-safe that was added to work around an issue where a client would think it wasn’t in the room, but actually was.

This is the commit message that introduced that feature:

Based on this, I believe that the presence update (the second presence), should not include the <x xmlns='http://jabber.org/protocol/muc'> element - that should be present only when joining the room, not on subsequent presence updates. This is illustrated by the examples in XEP-0045: Multi-User Chat, which don’t show this element.

We might facilitate your scenario better by using the presence information in the latest “join” that is being received by the server (I have to consult smarter people than me to see if that’s feasible).

In any case, it’s likely a good idea for the client to stop including that x element in presence updates other than the initial join.

For posterity: the background to Vincent’s original issue is discussed here: https://github.com/jitsi/jibri/issues/116

Thanks for looking into this issue. I just notice a paragraph in section 7.2.2 Basic MUC Protocol of XEP-0045 that clearly supports what you said:

When a MUC service receives an <x/> tagged join stanza from an already-joined client (as identified by the client's full JID), the service should assume that the client lost its synchronization, and therefore it SHOULD send exactly the same stanzas to the client as if it actually just joined the MUC. The server MAY also send a presence update to the other participants according to the received join presence.

However, I am not sure how to interpret the last sentence. Does it imply that the updating presence info will also be broadcast to other participants?

Exactly. All other participants will also receive the presence update, as if the user just joined.

What Openfire does is send the original presence. What perhaps should be done to mitigate the problems that you’re having, is send the new presence. The text that you quote seems to call for that anyways.

I have created https://issues.igniterealtime.org/browse/OF-1581 to track this issue.

Thank you so much for creating a JIRA to track this issue. Looking forward to see any updates in OF.