From 54cbd9a50aca424484de0ad7fd129df2368cdd19 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 29 Mar 2015 12:26:36 +0200 Subject: [PATCH 1/9] Smack 4.1.1-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 60a8f510b..e880afb5f 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { - shortVersion = '4.1.0' - isSnapshot = false + shortVersion = '4.1.1' + isSnapshot = true jxmppVersion = '0.4.2-beta1' smackMinAndroidSdk = 8 } From 5597b1ffc0271ec0d78bed1b0199b04bcfbab726 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 31 Mar 2015 10:04:53 +0200 Subject: [PATCH 2/9] Handle preceding whitespace in DIGEST-MD5 implementation from smack-sasl-provided. Fixes SMACK-649. --- .../smack/sasl/provided/SASLDigestMD5Mechanism.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java b/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java index 309c25527..1c0a8370a 100644 --- a/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java +++ b/smack-sasl-provided/src/main/java/org/jivesoftware/smack/sasl/provided/SASLDigestMD5Mechanism.java @@ -104,6 +104,13 @@ public class SASLDigestMD5Mechanism extends SASLMechanism { String[] keyValue = part.split("="); assert (keyValue.length == 2); String key = keyValue[0]; + // RFC 2831 § 7.1 about the formating of the digest-challenge: + // "The full form is "#element" indicating at least and + // at most elements, each separated by one or more commas + // (",") and OPTIONAL linear white space (LWS)." + // Which means the key value may be preceded by whitespace, + // which is what we remove: *Only the preceding whitespace*. + key = key.replaceFirst("^\\s+", ""); String value = keyValue[1]; if ("nonce".equals(key)) { if (nonce != null) { From 57fa631480fa865439407cc54271c9cadcba5eca Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 6 Apr 2015 17:37:45 +0200 Subject: [PATCH 3/9] Add javadoc to SynchronizationPoint --- .../smack/SynchronizationPoint.java | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java index 9a4614b59..73d4e8b4e 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java @@ -1,6 +1,6 @@ /** * - * Copyright © 2014 Florian Schmaus + * Copyright © 2014-2015 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,11 @@ public class SynchronizationPoint { private State state; private E failureException; + /** + * Construct a new synchronization point for the given connection. + * + * @param connection the connection of this synchronization point. + */ public SynchronizationPoint(AbstractXMPPConnection connection) { this.connection = connection; this.connectionLock = connection.getConnectionLock(); @@ -48,6 +53,9 @@ public class SynchronizationPoint { init(); } + /** + * Initialize (or reset) this synchronization point. + */ public void init() { connectionLock.lock(); state = State.Initial; @@ -55,6 +63,13 @@ public class SynchronizationPoint { connectionLock.unlock(); } + /** + * Send the given top level stream element and wait for a response. + * + * @param request the plain stream element to send. + * @throws NoResponseException if no response was received. + * @throws NotConnectedException if the connection is not connected. + */ public void sendAndWaitForResponse(TopLevelStreamElement request) throws NoResponseException, NotConnectedException { assert (state == State.Initial); @@ -79,6 +94,14 @@ public class SynchronizationPoint { checkForResponse(); } + /** + * Send the given plain stream element and wait for a response. + * + * @param request the plain stream element to send. + * @throws E if an failure was reported. + * @throws NoResponseException if no response was received. + * @throws NotConnectedException if the connection is not connected. + */ public void sendAndWaitForResponseOrThrow(PlainStreamElement request) throws E, NoResponseException, NotConnectedException { sendAndWaitForResponse(request); @@ -93,6 +116,11 @@ public class SynchronizationPoint { } } + /** + * Check if this synchronization point is successful or wait the connections reply timeout. + * @throws NoResponseException if there was no response marking the synchronization point as success or failed. + * @throws E if there was a failure + */ public void checkIfSuccessOrWaitOrThrow() throws NoResponseException, E { checkIfSuccessOrWait(); if (state == State.Failure) { @@ -100,6 +128,10 @@ public class SynchronizationPoint { } } + /** + * Check if this synchronization point is successful or wait the connections reply timeout. + * @throws NoResponseException if there was no response marking the synchronization point as success or failed. + */ public void checkIfSuccessOrWait() throws NoResponseException { connectionLock.lock(); try { @@ -114,6 +146,9 @@ public class SynchronizationPoint { checkForResponse(); } + /** + * Report this synchronization point as successful. + */ public void reportSuccess() { connectionLock.lock(); try { @@ -129,6 +164,11 @@ public class SynchronizationPoint { reportFailure(null); } + /** + * Report this synchronization point as failed because of the given exception. + * + * @param failureException the exception causing this synchronization point to fail. + */ public void reportFailure(E failureException) { connectionLock.lock(); try { @@ -141,6 +181,11 @@ public class SynchronizationPoint { } } + /** + * Check if this synchronization point was successful. + * + * @return true if the synchronization point was successful, false otherwise. + */ public boolean wasSuccessful() { connectionLock.lock(); try { @@ -151,6 +196,11 @@ public class SynchronizationPoint { } } + /** + * Check if this synchronization point has its request already sent. + * + * @return true if the request was already sent, false otherwise. + */ public boolean requestSent() { connectionLock.lock(); try { @@ -161,6 +211,12 @@ public class SynchronizationPoint { } } + /** + * Wait for the condition to become something else as {@link State#RequestSent} or {@link State#Initial}. + * {@link #reportSuccess()}, {@link #reportFailure()} and {@link #reportFailure(Exception)} will either set this + * synchronization point to {@link State#Success} or {@link State#Failure}. If none of them is set after the + * connections reply timeout, this method will set the state of {@link State#NoResponse}. + */ private void waitForConditionOrTimeout() { long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getPacketReplyTimeout()); while (state == State.RequestSent || state == State.Initial) { From 83aa6838d93eb9baeea36f229c95d4a3665c7667 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 6 Apr 2015 17:38:51 +0200 Subject: [PATCH 4/9] Use signalAll in SynchronizationPoint to prevent a thread from not being notified about a change of the state of the SynchronizationPoint. If two threads are waiting for a change, which could happen e.g. because of a connectivity change and one thread does instantShutdown() while the other handles connectionClosedOnError(), then only one thread, usually the one handling connectionClosedOnError(), would be notified and resumed. Fixes SMACK-652. --- .../java/org/jivesoftware/smack/SynchronizationPoint.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java index 73d4e8b4e..78918a06a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java @@ -153,7 +153,7 @@ public class SynchronizationPoint { connectionLock.lock(); try { state = State.Success; - condition.signal(); + condition.signalAll(); } finally { connectionLock.unlock(); @@ -174,7 +174,7 @@ public class SynchronizationPoint { try { state = State.Failure; this.failureException = failureException; - condition.signal(); + condition.signalAll(); } finally { connectionLock.unlock(); From cca34fd872dd08ae306ae7a6d00355d2b5167ed1 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 6 Apr 2015 21:18:59 +0200 Subject: [PATCH 5/9] First check condition, then remaining wait in SynchronizationPoint as otherwhise SynchronizationPoint may report NoResponseException when there was in fact a success or failure reported in case there are multiple threads waiting for the condition. --- .../main/java/org/jivesoftware/smack/SynchronizationPoint.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java index 78918a06a..c52242350 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java @@ -221,12 +221,11 @@ public class SynchronizationPoint { long remainingWait = TimeUnit.MILLISECONDS.toNanos(connection.getPacketReplyTimeout()); while (state == State.RequestSent || state == State.Initial) { try { - remainingWait = condition.awaitNanos( - remainingWait); if (remainingWait <= 0) { state = State.NoResponse; break; } + remainingWait = condition.awaitNanos(remainingWait); } catch (InterruptedException e) { LOGGER.log(Level.WARNING, "Thread interrupt while waiting for condition or timeout ignored", e); } From 3b6891b0d0b7a6b80e82aad03e615237165fd31a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 6 Apr 2015 21:55:20 +0200 Subject: [PATCH 6/9] Fix integer overflow if no max resumption time is specified by client and server. Fixes SMACK-653. --- .../org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 4f28dc633..86dea74da 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 @@ -1612,7 +1612,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { throw new StreamManagementException.StreamManagementNotEnabledException(); } // Remove the listener after max. 12 hours - final int removeAfterSeconds = Math.min(getMaxSmResumptionTime() + 60, 12 * 60 * 60); + final int removeAfterSeconds = Math.min(getMaxSmResumptionTime(), 12 * 60 * 60); schedule(new Runnable() { @Override public void run() { @@ -1703,8 +1703,13 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { /** * Get the maximum resumption time in seconds after which a managed stream can be resumed. + *

+ * This method will return {@link Integer#MAX_VALUE} if neither the client nor the server specify a maximum + * resumption time. Be aware of integer overflows when using this value, e.g. do not add arbitrary values to it + * without checking for overflows before. + *

* - * @return the maximum resumption time in seconds. + * @return the maximum resumption time in seconds or {@link Integer#MAX_VALUE} if none set. */ public int getMaxSmResumptionTime() { int clientResumptionTime = smClientMaxResumptionTime > 0 ? smClientMaxResumptionTime : Integer.MAX_VALUE; From dabbb40de602f411decb9311660a094bd7720969 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 6 Apr 2015 21:59:45 +0200 Subject: [PATCH 7/9] Fix isSmResumptionPossible() returning wrong values The cases where reversed. Change the condition for better readability. Also fix int and long handling in the computation of maxResumptionMillies. Fixes SMACK-654. --- .../java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 86dea74da..378f3299d 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 @@ -1693,8 +1693,10 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { // See if resumption time is over long current = System.currentTimeMillis(); - long maxResumptionMillies = getMaxSmResumptionTime() * 1000; - if (shutdownTimestamp + maxResumptionMillies > current) { + long maxResumptionMillies = ((long) getMaxSmResumptionTime()) * 1000; + if (current > shutdownTimestamp + maxResumptionMillies) { + // Stream resumption is *not* possible if the current timestamp is greater then the greatest timestamp where + // resumption is possible return false; } else { return true; From 9a69f992c42fa96fd82b79d5f45d4f9e472c4a32 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 7 Apr 2015 08:52:48 +0200 Subject: [PATCH 8/9] Deprecate SynchronizationPoint.reportFailure() assert and document that an exception must be set when calling reportFailure(E). --- .../java/org/jivesoftware/smack/SynchronizationPoint.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java index c52242350..fa87848a0 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java @@ -160,16 +160,22 @@ public class SynchronizationPoint { } } + /** + * Deprecated + * @deprecated use {@link #reportFailure(Exception)} instead. + */ + @Deprecated public void reportFailure() { reportFailure(null); } /** - * Report this synchronization point as failed because of the given exception. + * Report this synchronization point as failed because of the given exception. The {@code failureException} must be set. * * @param failureException the exception causing this synchronization point to fail. */ public void reportFailure(E failureException) { + assert failureException != null; connectionLock.lock(); try { state = State.Failure; From 062e9ee415eca1e65c8f9b2abb5a5ea51cdbe114 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 12 Apr 2015 18:13:19 +0200 Subject: [PATCH 9/9] Fix javadoc of pubsub.Item --- .../java/org/jivesoftware/smackx/pubsub/Item.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Item.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Item.java index 4e72b7a01..56a41cdc7 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Item.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Item.java @@ -24,21 +24,27 @@ import org.jivesoftware.smackx.pubsub.provider.ItemProvider; * pubsub node. An Item has several properties that are dependent * on the configuration of the node to which it has been or will be published. * - *

An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)} + *

An Item received from a node (via {@link LeafNode#getItems()} or {@link LeafNode#addItemEventListener(org.jivesoftware.smackx.pubsub.listener.ItemEventListener)}

+ *
    *
  • Will always have an id (either user or server generated) unless node configuration has both * {@link ConfigureForm#isPersistItems()} and {@link ConfigureForm#isDeliverPayloads()}set to false. *
  • Will have a payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set * to true, otherwise it will be null. + *
* - *

An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()} + *

An Item created to send to a node (via {@link LeafNode#send()} or {@link LeafNode#publish()}

+ *
    *
  • The id is optional, since the server will generate one if necessary, but should be used if it is * meaningful in the context of the node. This value must be unique within the node that it is sent to, since * resending an item with the same id will overwrite the one that already exists if the items are persisted. *
  • Will require payload if the node configuration has {@link ConfigureForm#isDeliverPayloads()} set - * to true. + * to true. + *
* - *

To customise the payload object being returned from the {@link PayloadItem#getPayload()} method, you can + *

+ * To customise the payload object being returned from the {@link PayloadItem#getPayload()} method, you can * add a custom parser as explained in {@link ItemProvider}. + *

* * @author Robin Collier */