diff --git a/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClient.java b/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClient.java index cf41093..63bc20e 100644 --- a/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClient.java +++ b/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClient.java @@ -48,11 +48,15 @@ */ public class MucClient { + private static final int DEFAULT_PING_INTERVAL_SECONDS = 30; + + private static final long HALF_OPEN_CONNECTION_CHECK_PERIOD_MS = 2 * 1000 * DEFAULT_PING_INTERVAL_SECONDS; + static { XMPPTCPConnection.setUseStreamManagementDefault(false); XMPPTCPConnection.setUseStreamManagementResumptionDefault(false); - PingManager.setDefaultPingInterval(30); + PingManager.setDefaultPingInterval(DEFAULT_PING_INTERVAL_SECONDS); } /** @@ -795,7 +799,7 @@ private void removePresenceExtension(String elementName, String namespace) { return; } - + if (lastPresenceSent.removeExtension(elementName, namespace) != null) { updatedPresence = lastPresenceSent.build(); @@ -853,4 +857,51 @@ public void pingFailed() } } } + + private final PeriodicRunnable halfOpenConnectionPeriodicCheck = new HalfOpenConnectionPeriodicCheck(); + + /** + * @return the {@link PeriodicRunnable} that checks the XMPP connection state and triggers a disconnect if a + * half-open connection is detected. + */ + public PeriodicRunnable getHalfOpenConnectionPeriodicCheck() + { + return halfOpenConnectionPeriodicCheck; + } + + /** + * Periodically checks the connection state and triggers a disconnect if a half-open connection is detected. + */ + class HalfOpenConnectionPeriodicCheck + extends PeriodicRunnable + { + public HalfOpenConnectionPeriodicCheck() + { + super(HALF_OPEN_CONNECTION_CHECK_PERIOD_MS); + } + + /** + * Triggers a disconnect if a half-open connection is detected. + */ + @Override + public void run() + { + super.run(); + + AbstractXMPPConnection con = xmppConnection; + if (con != null && con.isConnected() && con.isAuthenticated()) + { + long lastStanzaReceivedMs = con.getLastStanzaReceived(); + if (lastStanzaReceivedMs > 0) + { + long nowMs = System.currentTimeMillis(); + if (nowMs - lastStanzaReceivedMs > HALF_OPEN_CONNECTION_CHECK_PERIOD_MS) + { + logger.warn("Half-open XMPP connection detected, will trigger a disconnect."); + con.disconnect(); + } + } + } + } + } } diff --git a/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClientManager.java b/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClientManager.java index 4c5953b..9df607b 100644 --- a/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClientManager.java +++ b/jicoco/src/main/java/org/jitsi/xmpp/mucclient/MucClientManager.java @@ -17,6 +17,7 @@ package org.jitsi.xmpp.mucclient; import org.jitsi.service.configuration.*; +import org.jitsi.utils.concurrent.*; import org.jitsi.utils.logging2.*; import org.jitsi.utils.logging2.Logger; import org.jivesoftware.smack.*; @@ -79,6 +80,11 @@ public class MucClientManager */ private final Object syncRoot = new Object(); + /** + * The {@link RecurringRunnableExecutor} to be utilized by the {@link MucClientManager} class and its instances. + */ + private final RecurringRunnableExecutor recurringRunnableExecutor = new RecurringRunnableExecutor(); + /** * Initializes a new {@link MucClientManager} instance. * @@ -126,6 +132,7 @@ public boolean addMucClient(MucClientConfiguration config) mucClient = new MucClient(config, MucClientManager.this); mucClients.put(config.getId(), mucClient); + recurringRunnableExecutor.registerRecurringRunnable(mucClient.getHalfOpenConnectionPeriodicCheck()); } mucClient.start(); @@ -325,7 +332,8 @@ public boolean removeMucClient(String id) logger.info("Can not find MucClient to remove."); return false; } - mucClient.stop(); + recurringRunnableExecutor.deRegisterRecurringRunnable(mucClient.getHalfOpenConnectionPeriodicCheck()); + mucClient.stop(); return true; }