From 7e311ab9df129b843e4fbcf0905834673624f220 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 8 Nov 2020 21:46:06 +0100 Subject: [PATCH] [muc] Prevent race condition on enter() by waiting This prevents a race condition of enter() with the presence listern by waiting until all presences have been processed. Reported-by: Guus der Kinderen --- .../smackx/muc/MultiUserChat.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index b75f44d5e..51f267694 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -149,6 +149,11 @@ public class MultiUserChat { private EntityFullJid myRoomJid; private StanzaCollector messageCollector; + /** + * Used to signal that the reflected self-presence was received and processed by us. + */ + private volatile boolean processedReflectedSelfPresence; + MultiUserChat(XMPPConnection connection, EntityBareJid room, MultiUserChatManager multiUserChatManager) { this.connection = connection; this.room = room; @@ -216,13 +221,15 @@ public class MultiUserChat { newAffiliation, isUserStatusModification, from); - } - else { + } else if (mucUser.getStatus().contains(MUCUser.Status.PRESENCE_TO_SELF_110)) { + processedReflectedSelfPresence = true; + synchronized (this) { + notify(); + } + } else { // A new occupant has joined the room - if (!isUserStatusModification) { - for (ParticipantStatusListener listener : participantStatusListeners) { - listener.joined(from); - } + for (ParticipantStatusListener listener : participantStatusListeners) { + listener.joined(from); } } break; @@ -376,6 +383,7 @@ public class MultiUserChat { ) ); // @formatter:on + processedReflectedSelfPresence = false; StanzaCollector presenceStanzaCollector = null; final Presence reflectedSelfPresence; try { @@ -398,6 +406,16 @@ public class MultiUserChat { } } + synchronized (presenceListener) { + // Only continue after we have received *and* processed the reflected self-presence. Since presences are + // handled in an extra listener, we may return from enter() without having processed all presences of the + // participants, resulting in a e.g. to low participant counter after enter(). Hence we wait here until the + // processing is done. + while (!processedReflectedSelfPresence) { + presenceListener.wait(); + } + } + // This presence must be send from a full JID. We use the resourcepart of this JID as nick, since the room may // performed roomnick rewriting Resourcepart receivedNickname = reflectedSelfPresence.getFrom().getResourceOrThrow();