From aa8daba1cfd3cfa95f01da611473ba0a16a6e00a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 18 Feb 2015 12:01:55 +0100 Subject: [PATCH] Add StreamManagemtCounterError to allow graceful connectionClosedOnError() disconnects, since we received a bunch of reports where the counter seems wrong, which is causing a NPE in a thread pool executor, causing the VM or Android App to terminate. Now we throw the StreamManagementCounterError instead. --- .../smack/sm/StreamManagementException.java | 58 +++++++++++++++++++ .../smack/tcp/XMPPTCPConnection.java | 8 ++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java b/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java index 95278f3af..43684e299 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java @@ -16,7 +16,11 @@ */ package org.jivesoftware.smack.sm; +import java.util.Collections; +import java.util.List; + import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.packet.Stanza; public abstract class StreamManagementException extends SmackException { @@ -52,5 +56,59 @@ public abstract class StreamManagementException extends SmackException { super("Stream IDs do not match. Expected '" + expected + "', but got '" + got + "'"); } } + + public static class StreamManagementCounterError extends StreamManagementException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private final long handledCount; + private final long previousServerHandledCount; + private final long ackedStanzaCount; + private final int outstandingStanzasCount; + private final List ackedStanzas; + + public StreamManagementCounterError(long handledCount, long previousServerHandlerCount, + long ackedStanzaCount, + List ackedStanzas) { + super( + "There was an error regarding the Stream Mangement counters. Server reported " + + handledCount + + " handled stanzas, which means that the " + + ackedStanzaCount + + " recently send stanzas by client are now acked by the server. But Smack had only " + + ackedStanzas.size() + + " to acknowledge. The stanza id of the last acked outstanding stanza is " + + (ackedStanzas.isEmpty() ? "" + : ackedStanzas.get(ackedStanzas.size() - 1).getStanzaId())); + this.handledCount = handledCount; + this.previousServerHandledCount = previousServerHandlerCount; + this.ackedStanzaCount = ackedStanzaCount; + this.outstandingStanzasCount = ackedStanzas.size(); + this.ackedStanzas = Collections.unmodifiableList(ackedStanzas); + } + + public long getHandledCount() { + return handledCount; + } + + public long getPreviousServerHandledCount() { + return previousServerHandledCount; + } + + public long getAckedStanzaCount() { + return ackedStanzaCount; + } + + public int getOutstandingStanzasCount() { + return outstandingStanzasCount; + } + + public List getAckedStanzas() { + return ackedStanzas; + } + } } diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index 71d84b3b1..ae9610d5b 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -54,6 +54,7 @@ import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Success; import org.jivesoftware.smack.sm.SMUtils; import org.jivesoftware.smack.sm.StreamManagementException; import org.jivesoftware.smack.sm.StreamManagementException.StreamIdDoesNotMatchException; +import org.jivesoftware.smack.sm.StreamManagementException.StreamManagementCounterError; import org.jivesoftware.smack.sm.StreamManagementException.StreamManagementNotEnabledException; import org.jivesoftware.smack.sm.packet.StreamManagement; import org.jivesoftware.smack.sm.packet.StreamManagement.AckAnswer; @@ -1642,7 +1643,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { return Math.min(clientResumptionTime, serverResumptionTime); } - private void processHandledCount(long handledCount) throws NotConnectedException { + private void processHandledCount(long handledCount) throws NotConnectedException, StreamManagementCounterError { long ackedStanzasCount = SMUtils.calculateDelta(handledCount, serverHandledStanzasCount); final List ackedStanzas = new ArrayList( handledCount <= Integer.MAX_VALUE ? (int) handledCount @@ -1651,7 +1652,10 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { Stanza ackedStanza = unacknowledgedStanzas.poll(); // If the server ack'ed a stanza, then it must be in the // unacknowledged stanza queue. There can be no exception. - assert(ackedStanza != null); + if (ackedStanza == null) { + throw new StreamManagementCounterError(handledCount, serverHandledStanzasCount, + ackedStanzasCount, ackedStanzas); + } ackedStanzas.add(ackedStanza); }