[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 <guus@goodbytes.nl>
This commit is contained in:
Florian Schmaus 2020-11-08 21:46:06 +01:00
parent f12fe2264a
commit 7e311ab9df
1 changed files with 24 additions and 6 deletions

View File

@ -149,6 +149,11 @@ public class MultiUserChat {
private EntityFullJid myRoomJid;
private StanzaCollector messageCollector;
/**
* Used to signal that the reflected self-presence was received <b>and</b> 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();