MUC rooms and carbon copies sending duplicate messages when connected with multiple sessions

Hi there,

We are running Openfire 4.7.1 (linux) and Spark 2.9.4 (windows)

I’ve been chasing an odd issue where, if a user is signed in from multiple PCs (with different resource names) and is a member of a private chat that has been opened from a MUC room they will receive a duplicate copy of a message for each location they are connected.

Using the debugger built into Spark I can see that every session receives a single <message> packet and as many carbon copy <message> packets as there are extra sessions connected. This is true for each connected session.

Looking through the codebase for openfire, this appears to be because in sendPrivatePacket in MUCRoom.java the message is sent directly to every occupant of the private chat, each occupant being each of the user’s sessions. The problem is, further downstream openfire sends the message directly to the occupant and then sends a carbon copy to each of that user’s other sessions. This means that each message is sent multiple times.

To fix this I have made the following change to the openfire code, but I am unsure if it is the best practice:

From this
(MUCRoom.java lines 1455-1462)

        // Forward it to each occupant.
        for (final MUCRole occupant : occupants) {
            occupant.send(stanza); // Use the stanza copy to send data. The 'to' address of this object will be changed by sending it.
            if (stanza instanceof Message) {
                // Use an unmodified copy of the stanza (with the original 'to' address) when invoking event listeners (OF-2163)
                MUCEventDispatcher.privateMessageRecieved(occupant.getUserAddress(), senderRole.getUserAddress(), (Message) immutable);
            }
        }

To this:

        //We don't want to send a "message" stanza to every instance of an occupant... this is handled by carbon copies...
        if (stanza instanceof Message) {
            final MUCRole occupant = occupants.get(0);
            occupant.send(stanza); // Use the stanza copy to send data. The 'to' address of this object will be changed by sending it.
            MUCEventDispatcher.privateMessageRecieved(occupant.getUserAddress(), senderRole.getUserAddress(), (Message) immutable);
        } else {
            //Not a "message" send to all occupants
            for (final MUCRole occupant : occupants) {
                occupant.send(stanza); // Use the stanza copy to send data. The 'to' address of this object will be changed by sending it.
            }
        }

Thanks,
Alex 2

1 Like