From 77baaa99bc6ad7eaca65268ef3d31b57e3731168 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 10 Sep 2018 21:00:49 +0200 Subject: [PATCH 01/72] Do not warn on presence from bare MUC JID in MultiUserChat as such presence messages became a thing in XMPP (e.g. for XEP-0153 avatars for MUC). --- .../src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java | 1 - 1 file changed, 1 deletion(-) 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 598fe68e4..3b2bcbc86 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 @@ -205,7 +205,6 @@ public class MultiUserChat { final Presence presence = (Presence) packet; final EntityFullJid from = presence.getFrom().asEntityFullJidIfPossible(); if (from == null) { - LOGGER.warning("Presence not from a full JID: " + presence.getFrom()); return; } final EntityFullJid myRoomJID = myRoomJid; From 87fac888c62de55a458eaf20f40dfe321dd5ee3a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 12 Sep 2018 19:56:46 +0200 Subject: [PATCH 02/72] Improve MultiUserChat's API to query hosted rooms Return a Map instead of a List. This makes it possible to check for the existence of MUC by looking up the MUC's address in the Map's key set. --- .../smackx/muc/MultiUserChatManager.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java index 8c5a98ccd..33e36e76b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java @@ -19,6 +19,7 @@ package org.jivesoftware.smackx.muc; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -392,19 +393,46 @@ public final class MultiUserChatManager extends Manager { * @throws NotConnectedException * @throws InterruptedException * @throws NotAMucServiceException + * @deprecated use {@link #getRoomsHostedBy(DomainBareJid)} instead. */ + @Deprecated + // TODO: Remove in Smack 4.4. public List getHostedRooms(DomainBareJid serviceName) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotAMucServiceException { + Map hostedRooms = getRoomsHostedBy(serviceName); + return new ArrayList<>(hostedRooms.values()); + } + + /** + * Returns a Map of HostedRooms where each HostedRoom has the XMPP address of the room and the room's name. + * Once discovered the rooms hosted by a chat service it is possible to discover more detailed room information or + * join the room. + * + * @param serviceName the service that is hosting the rooms to discover. + * @return a map from the room's address to its HostedRoom information. + * @throws XMPPErrorException + * @throws NoResponseException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotAMucServiceException + * @since 4.3.1 + */ + public Map getRoomsHostedBy(DomainBareJid serviceName) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotAMucServiceException { if (!providesMucService(serviceName)) { throw new NotAMucServiceException(serviceName); } ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection()); DiscoverItems discoverItems = discoManager.discoverItems(serviceName); List items = discoverItems.getItems(); - List answer = new ArrayList(items.size()); + + Map answer = new HashMap<>(items.size()); for (DiscoverItems.Item item : items) { - answer.add(new HostedRoom(item)); + HostedRoom hostedRoom = new HostedRoom(item); + HostedRoom previousRoom = answer.put(hostedRoom.getJid(), hostedRoom); + assert previousRoom == null; } + return answer; } From 1e21ab763cfbfdb1925408fd4b9112a65ff6ded7 Mon Sep 17 00:00:00 2001 From: spslinger <3893604+spslinger@users.noreply.github.com> Date: Thu, 11 Oct 2018 12:29:32 +0200 Subject: [PATCH 03/72] Fix getPresence ConcurrentModificationException Fix for SMACK-841 Since Smack 4.2.4, the getPresencesInternal method in the Roster class can return a LruCache object, which is a LinkedHashMap with access order. This means that any access using get or getOrDefault will be a modification of the Map. If you loop over the keySet of the Map and there are more than one, the second call to get will throw a ConcurrentModificationException! Since the keys are only used here to obtain the corresponding values, the simplest solution is to just loop over the values instead. --- .../src/main/java/org/jivesoftware/smack/roster/Roster.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index c4e7a0cf2..8e241151d 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -951,8 +951,7 @@ public final class Roster extends Manager { // This is used in case no available presence is found Presence unavailable = null; - for (Resourcepart resource : userPresences.keySet()) { - Presence p = userPresences.get(resource); + for (Presence p : userPresences.values()) { if (!p.isAvailable()) { unavailable = p; continue; From 89c9a418634dc0c9911b0645615c78f1a32ac793 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 14 Oct 2018 11:57:50 +0200 Subject: [PATCH 04/72] Bump MiniDNS to 0.3.3 --- version.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index 683627553..846567106 100644 --- a/version.gradle +++ b/version.gradle @@ -3,7 +3,7 @@ allprojects { shortVersion = '4.3.1' isSnapshot = true jxmppVersion = '0.6.3' - miniDnsVersion = '0.3.2' + miniDnsVersion = '0.3.3' smackMinAndroidSdk = 9 } } From ec982f65e23fcfd0d0b61d2909128ba1c2c792f5 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 14 Oct 2018 12:07:51 +0200 Subject: [PATCH 05/72] Fix IndexOutOfBoundsException in FormField.getFirstValue() Fixes SMACK-838. --- .../java/org/jivesoftware/smackx/xdata/FormField.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java index b45c139bc..5ecf7ab59 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java @@ -261,12 +261,14 @@ public class FormField implements NamedElement { */ public String getFirstValue() { CharSequence firstValue; + synchronized (values) { + if (values.isEmpty()) { + return null; + } firstValue = values.get(0); } - if (firstValue == null) { - return null; - } + return firstValue.toString(); } From cf22371d3e3cb36d84e03a09396df9e1c9c10c1a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 14 Oct 2018 12:10:50 +0200 Subject: [PATCH 06/72] Catch IllegalArgumentException in XmlUtil clinit Fixes SMACK-833. --- .../src/main/java/org/jivesoftware/smack/util/XmlUtil.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlUtil.java index 7fc081b43..b55297d6e 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlUtil.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlUtil.java @@ -35,7 +35,11 @@ public class XmlUtil { private static final TransformerFactory transformerFactory = TransformerFactory.newInstance(); static { - transformerFactory.setAttribute("indent-number", 2); + try { + transformerFactory.setAttribute("indent-number", 2); + } catch (IllegalArgumentException e) { + LOGGER.log(Level.INFO, "XML TransformerFactory does not support indent-number attribute", e); + } } public static String prettyFormatXml(CharSequence xml) { From 6a43481320fb34caeac023cbfe59a63ba0128cd7 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 14 Oct 2018 12:53:11 +0200 Subject: [PATCH 07/72] Smack 4.3.1 --- resources/releasedocs/changelog.html | 18 ++++++++++++++++++ version.gradle | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/resources/releasedocs/changelog.html b/resources/releasedocs/changelog.html index 4d51e4594..77450e326 100644 --- a/resources/releasedocs/changelog.html +++ b/resources/releasedocs/changelog.html @@ -141,6 +141,24 @@ hr {
+

4.3.1 -- 2018-10-14

+ +

Bug +

+
    +
  • [SMACK-833] - XMLUtil.prettyFormatXml() throws on some Android devices +
  • +
+ +

Improvement +

+
    +
  • [SMACK-829] - Disconnect BOSH client on shutdown +
  • +
  • [SMACK-838] - FormField.getFirstValue() throws IndexOutOfBoundsException if there are no values +
  • +
+

4.3.0 -- 2018-08-02

Bug diff --git a/version.gradle b/version.gradle index 846567106..62b47a3c8 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { shortVersion = '4.3.1' - isSnapshot = true + isSnapshot = false jxmppVersion = '0.6.3' miniDnsVersion = '0.3.3' smackMinAndroidSdk = 9 From 5f05da2f7770e10d3e8c6851a67f1f6c085a01ec Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 14 Oct 2018 14:22:00 +0200 Subject: [PATCH 08/72] Smack 4.3.2-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 62b47a3c8..74674db63 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { - shortVersion = '4.3.1' - isSnapshot = false + shortVersion = '4.3.2' + isSnapshot = true jxmppVersion = '0.6.3' miniDnsVersion = '0.3.3' smackMinAndroidSdk = 9 From 2900c5ae234345160e197835545c6cdfc3c4a215 Mon Sep 17 00:00:00 2001 From: asokolov Date: Wed, 14 Nov 2018 13:36:10 +0300 Subject: [PATCH 09/72] Move xml-not-well-formed (RFC 3920) condition handling to StreamError Fixes SMACK-842. --- .../jivesoftware/smack/packet/StanzaError.java | 5 ----- .../jivesoftware/smack/packet/StreamError.java | 5 +++++ .../smack/packet/StreamErrorTest.java | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java index 6ebd523ab..fad9f5253 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java @@ -385,11 +385,6 @@ public class StanzaError extends AbstractError implements ExtensionElement { } public static Condition fromString(String string) { - // Backwards compatibility for older implementations still using RFC 3920. RFC 6120 - // changed 'xml-not-well-formed' to 'not-well-formed'. - if ("xml-not-well-formed".equals(string)) { - string = "not-well-formed"; - } string = string.replace('-', '_'); Condition condition = null; try { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/StreamError.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/StreamError.java index def48dfbe..67ec3ec2a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/StreamError.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/StreamError.java @@ -186,6 +186,11 @@ public class StreamError extends AbstractError implements Nonza { } public static Condition fromString(String string) { + // Backwards compatibility for older implementations still using RFC 3920. RFC 6120 + // changed 'xml-not-well-formed' to 'not-well-formed'. + if ("xml-not-well-formed".equals(string)) { + string = "not-well-formed"; + } string = string.replace('-', '_'); Condition condition = null; try { diff --git a/smack-core/src/test/java/org/jivesoftware/smack/packet/StreamErrorTest.java b/smack-core/src/test/java/org/jivesoftware/smack/packet/StreamErrorTest.java index f390497f5..515053714 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/packet/StreamErrorTest.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/packet/StreamErrorTest.java @@ -104,4 +104,22 @@ public class StreamErrorTest { assertNotNull(appSpecificElement); } + @Test + public void testStreamErrorXmlNotWellFormed() { + StreamError error = null; + final String xml = + // Usually the stream:stream element has more attributes (to, version, ...) + // We omit those, since they are not relevant for testing + "" + + "" + + ""; + try { + XmlPullParser parser = PacketParserUtils.getParserFor(xml, "error"); + error = PacketParserUtils.parseStreamError(parser); + } catch (Exception e) { + fail(e.getMessage()); + } + assertNotNull(error); + assertEquals(Condition.not_well_formed, error.getCondition()); + } } From 229653af3017e32141dcbe0a53abe6573b0c2df9 Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Tue, 27 Nov 2018 18:27:10 +0100 Subject: [PATCH 10/72] ParserUtils: fix boolean parser How could this even happen? Signed-off-by: Georg Lukas --- .../src/main/java/org/jivesoftware/smack/util/ParserUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java index 28440bdbd..5c516f51a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java @@ -141,7 +141,7 @@ public class ParserUtils { if (valueString == null) return null; valueString = valueString.toLowerCase(Locale.US); - return valueString.equals("true") || valueString.equals("0"); + return valueString.equals("true") || valueString.equals("1"); } public static boolean getBooleanAttribute(XmlPullParser parser, String name, From 8b88f9cb20b86f302c91684d8cd73823599b703d Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Tue, 27 Nov 2018 18:33:39 +0100 Subject: [PATCH 11/72] Bookmarks: use proper boolean parser for `autojoin` Some clients (read: Gajim) store boolean values as `0` and `1` instead of `false` and `true`, which is legal for the XML boolean type. Signed-off-by: Georg Lukas --- .../java/org/jivesoftware/smackx/bookmarks/Bookmarks.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java index 322d0c8bb..f89e40f49 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java @@ -269,12 +269,12 @@ public class Bookmarks implements PrivateData { private static BookmarkedConference getConferenceStorage(XmlPullParser parser) throws XmlPullParserException, IOException { String name = parser.getAttributeValue("", "name"); - String autojoin = parser.getAttributeValue("", "autojoin"); + boolean autojoin = ParserUtils.getBooleanAttribute(parser, "autojoin", false); EntityBareJid jid = ParserUtils.getBareJidAttribute(parser); BookmarkedConference conf = new BookmarkedConference(jid); conf.setName(name); - conf.setAutoJoin(Boolean.valueOf(autojoin)); + conf.setAutoJoin(autojoin); // Check for nickname boolean done = false; From b8bd10b0562810b8abc14a92c8aa8cb01abc9dc7 Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Tue, 27 Nov 2018 18:33:39 +0100 Subject: [PATCH 12/72] RoomInfo: use proper boolean parser for `muc#roominfo_subjectmod` XML allows both false/true and 0/1 syntax for booleans. Signed-off-by: Georg Lukas --- .../src/main/java/org/jivesoftware/smackx/muc/RoomInfo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/RoomInfo.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/RoomInfo.java index b31f5bb4f..421f957f4 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/RoomInfo.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/RoomInfo.java @@ -207,7 +207,8 @@ public class RoomInfo { FormField subjectmodField = form.getField("muc#roominfo_subjectmod"); if (subjectmodField != null && !subjectmodField.getValues().isEmpty()) { - subjectmod = Boolean.valueOf(subjectmodField.getFirstValue()); + String firstValue = subjectmodField.getFirstValue(); + subjectmod = ("true".equals(firstValue) || "1".equals(firstValue)); } FormField urlField = form.getField("muc#roominfo_logs"); From 7ea7f9e2e9c8ff35e3bcc08d7f257386fac862d4 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 29 Nov 2018 08:55:10 +0100 Subject: [PATCH 13/72] Add ParserUtils.parseXmlBoolean(String) --- .../jivesoftware/smack/util/ParserUtils.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java index 5c516f51a..90f2b543c 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java @@ -129,6 +129,27 @@ public class ParserUtils { return Resourcepart.from(resourcepartString); } + /** + * Prase a string to a boolean value as per "xs:boolean". Valid input strings are "true", "1" for true, and "false", "0" for false. + * + * @param booleanString the input string. + * @return the boolean representation of the input string + * @throws IllegalArgumentException if the input string is not valid. + * @since 4.3.2 + */ + public static boolean parseXmlBoolean(String booleanString) { + switch (booleanString) { + case "true": + case "1": + return true; + case "false": + case "0": + return false; + default: + throw new IllegalArgumentException(booleanString + " is not a valid boolean string"); + } + } + /** * Get the boolean value of an argument. * @@ -141,7 +162,7 @@ public class ParserUtils { if (valueString == null) return null; valueString = valueString.toLowerCase(Locale.US); - return valueString.equals("true") || valueString.equals("1"); + return parseXmlBoolean(valueString); } public static boolean getBooleanAttribute(XmlPullParser parser, String name, From dbfc123e5e05d9c8f80dd907f02faa1e54ae116a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 29 Nov 2018 22:29:21 +0100 Subject: [PATCH 14/72] Use ParserUtils.parseXmlBoolean() where appropriate --- .../smackx/hoxt/provider/HttpOverXmppReqProvider.java | 8 +++++--- .../smackx/iot/control/element/SetBoolData.java | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/hoxt/provider/HttpOverXmppReqProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/hoxt/provider/HttpOverXmppReqProvider.java index 0a69ab4bd..6edf5ca0c 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/hoxt/provider/HttpOverXmppReqProvider.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/hoxt/provider/HttpOverXmppReqProvider.java @@ -16,6 +16,8 @@ */ package org.jivesoftware.smackx.hoxt.provider; +import org.jivesoftware.smack.util.ParserUtils; + import org.jivesoftware.smackx.hoxt.packet.HttpMethod; import org.jivesoftware.smackx.hoxt.packet.HttpOverXmppReq; @@ -47,13 +49,13 @@ public class HttpOverXmppReqProvider extends AbstractHttpOverXmppProvider Date: Thu, 29 Nov 2018 22:38:11 +0100 Subject: [PATCH 15/72] Add checkstyle rule for "Boolean.valueOf()" usages --- config/checkstyle.xml | 5 +++++ .../jivesoftware/smack/provider/IntrospectionProvider.java | 2 ++ .../provider/JivePropertiesExtensionProvider.java | 2 ++ .../smackx/workgroup/settings/WorkgroupProperties.java | 2 ++ 4 files changed, 11 insertions(+) diff --git a/config/checkstyle.xml b/config/checkstyle.xml index a05c12726..041e31ffb 100644 --- a/config/checkstyle.xml +++ b/config/checkstyle.xml @@ -89,6 +89,11 @@ + + + + + diff --git a/smack-core/src/main/java/org/jivesoftware/smack/provider/IntrospectionProvider.java b/smack-core/src/main/java/org/jivesoftware/smack/provider/IntrospectionProvider.java index 981b437a5..35dde99b4 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/provider/IntrospectionProvider.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/provider/IntrospectionProvider.java @@ -123,7 +123,9 @@ public class IntrospectionProvider{ case "java.lang.String": return value; case "boolean": + // CHECKSTYLE:OFF return Boolean.valueOf(value); + // CHECKSTYLE:ON case "int": return Integer.valueOf(value); case "long": diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jiveproperties/provider/JivePropertiesExtensionProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jiveproperties/provider/JivePropertiesExtensionProvider.java index b5719be65..178e4ad85 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jiveproperties/provider/JivePropertiesExtensionProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jiveproperties/provider/JivePropertiesExtensionProvider.java @@ -92,7 +92,9 @@ public class JivePropertiesExtensionProvider extends ExtensionElementProvider Date: Thu, 15 Nov 2018 15:18:17 +0200 Subject: [PATCH 16/72] Fix previous archive page requested incorrectly in MamManager Previous page should be before the first message in the previous result set, not the last. Fixes SMACK-843. --- .../src/main/java/org/jivesoftware/smackx/mam/MamManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java index 3b90d1cb5..61fd861df 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java @@ -995,7 +995,7 @@ public final class MamManager extends Manager { public List pagePrevious(int count) throws NoResponseException, XMPPErrorException, NotConnectedException, NotLoggedInException, InterruptedException { RSMSet previousResultRsmSet = getPreviousRsmSet(); - RSMSet requestRsmSet = new RSMSet(count, previousResultRsmSet.getLast(), RSMSet.PageDirection.before); + RSMSet requestRsmSet = new RSMSet(count, previousResultRsmSet.getFirst(), RSMSet.PageDirection.before); return page(requestRsmSet); } From 0c134db07202910389641964f7a341c0e649e0c1 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 4 Dec 2018 12:44:16 +0100 Subject: [PATCH 17/72] Add ConnectionConfiguration.setHostAddressByNameOrIp(CharSequence fqdnOrIp) --- .../smack/ConnectionConfiguration.java | 37 +++++++++ .../smack/ConnectionConfigurationTest.java | 79 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 smack-core/src/test/java/org/jivesoftware/smack/ConnectionConfigurationTest.java diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java index c16e5624c..7115a2bc3 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java @@ -18,6 +18,7 @@ package org.jivesoftware.smack; import java.net.InetAddress; +import java.net.UnknownHostException; import java.security.KeyStore; import java.util.Arrays; import java.util.Collection; @@ -45,6 +46,7 @@ import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; import org.minidns.dnsname.DnsName; +import org.minidns.util.InetAddressUtil; /** * Configuration to use while establishing the connection to the server. @@ -171,6 +173,14 @@ public abstract class ConnectionConfiguration { } + DnsName getHost() { + return host; + } + + InetAddress getHostAddress() { + return hostAddress; + } + /** * Returns the server name of the target server. * @@ -642,6 +652,33 @@ public abstract class ConnectionConfiguration { return getThis(); } + /** + * Set the host to connect to by either its fully qualified domain name (FQDN) or its IP. + * + * @param fqdnOrIp a CharSequence either representing the FQDN or the IP of the host. + * @return a reference to this builder. + * @see #setHost(DnsName) + * @see #setHostAddress(InetAddress) + * @since 4.3.2 + */ + public B setHostAddressByNameOrIp(CharSequence fqdnOrIp) { + String fqdnOrIpString = fqdnOrIp.toString(); + if (InetAddressUtil.isIpAddress(fqdnOrIp)) { + InetAddress hostInetAddress; + try { + hostInetAddress = InetAddress.getByName(fqdnOrIpString); + } + catch (UnknownHostException e) { + // Should never happen. + throw new AssertionError(e); + } + setHostAddress(hostInetAddress); + } else { + setHost(fqdnOrIpString); + } + return getThis(); + } + public B setPort(int port) { if (port < 0 || port > 65535) { throw new IllegalArgumentException( diff --git a/smack-core/src/test/java/org/jivesoftware/smack/ConnectionConfigurationTest.java b/smack-core/src/test/java/org/jivesoftware/smack/ConnectionConfigurationTest.java new file mode 100644 index 000000000..6637eae56 --- /dev/null +++ b/smack-core/src/test/java/org/jivesoftware/smack/ConnectionConfigurationTest.java @@ -0,0 +1,79 @@ +/** + * + * Copyright 2018 Florian Schmaus. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smack; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.jxmpp.jid.JidTestUtil; + +public class ConnectionConfigurationTest { + + @Test + public void setIp() { + DummyConnectionConfiguration.Builder builder = newUnitTestBuilder(); + + final String ip = "192.168.0.1"; + builder.setHostAddressByNameOrIp(ip); + + DummyConnectionConfiguration connectionConfiguration = builder.build(); + assertEquals('/' + ip, connectionConfiguration.getHostAddress().toString()); + } + + @Test + public void setFqdn() { + DummyConnectionConfiguration.Builder builder = newUnitTestBuilder(); + + final String fqdn = "foo.example.org"; + builder.setHostAddressByNameOrIp(fqdn); + + DummyConnectionConfiguration connectionConfiguration = builder.build(); + assertEquals(fqdn, connectionConfiguration.getHost().toString()); + } + + private static DummyConnectionConfiguration.Builder newUnitTestBuilder() { + DummyConnectionConfiguration.Builder builder = DummyConnectionConfiguration.builder(); + builder.setXmppDomain(JidTestUtil.DOMAIN_BARE_JID_1); + return builder; + } + + private static final class DummyConnectionConfiguration extends ConnectionConfiguration { + + protected DummyConnectionConfiguration(Builder builder) { + super(builder); + } + + public static Builder builder() { + return new Builder(); + } + + private static final class Builder + extends ConnectionConfiguration.Builder { + + @Override + public DummyConnectionConfiguration build() { + return new DummyConnectionConfiguration(this); + } + + @Override + protected Builder getThis() { + return this; + } + + } + } +} From 5ddaa623da266a3b3b1efa2ee03320184cd78149 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 8 Dec 2018 22:54:13 +0100 Subject: [PATCH 18/72] Check if unacknowledged stanzas queue is full before adding to it to avoid an IllegalStateException. Fixes SMACK-844. --- .../smack/sm/StreamManagementException.java | 54 +++++++++++++++++++ .../smack/tcp/XMPPTCPConnection.java | 11 +++- 2 files changed, 64 insertions(+), 1 deletion(-) 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 f5e30784d..553d9d702 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,10 +16,13 @@ */ package org.jivesoftware.smack.sm; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.BlockingQueue; import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.packet.Element; import org.jivesoftware.smack.packet.Stanza; public abstract class StreamManagementException extends SmackException { @@ -110,5 +113,56 @@ public abstract class StreamManagementException extends SmackException { return ackedStanzas; } } + + public static final class UnacknowledgedQueueFullException extends StreamManagementException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private final int overflowElementNum; + private final int droppedElements; + private final List elements; + private final List unacknowledgesStanzas; + + private UnacknowledgedQueueFullException(String message, int overflowElementNum, int droppedElements, List elements, + List unacknowledgesStanzas) { + super(message); + this.overflowElementNum = overflowElementNum; + this.droppedElements = droppedElements; + this.elements = elements; + this.unacknowledgesStanzas = unacknowledgesStanzas; + } + + public int getOverflowElementNum() { + return overflowElementNum; + } + + public int getDroppedElements() { + return droppedElements; + } + + public List getElements() { + return elements; + } + + public List getUnacknowledgesStanzas() { + return unacknowledgesStanzas; + } + + public static UnacknowledgedQueueFullException newWith(int overflowElementNum, List elements, + BlockingQueue unacknowledgedStanzas) { + final int unacknowledgesStanzasQueueSize = unacknowledgedStanzas.size(); + List localUnacknowledgesStanzas = new ArrayList<>(unacknowledgesStanzasQueueSize); + localUnacknowledgesStanzas.addAll(unacknowledgedStanzas); + int droppedElements = elements.size() - overflowElementNum - 1; + + String message = "The queue size " + unacknowledgesStanzasQueueSize + " is not able to fit another " + + droppedElements + " potential stanzas type top-level stream-elements."; + return new UnacknowledgedQueueFullException(message, overflowElementNum, droppedElements, elements, + localUnacknowledgesStanzas); + } + } } 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 b48e3cf4b..6ba5e64fd 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 @@ -1514,7 +1514,16 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { private void drainWriterQueueToUnacknowledgedStanzas() { List elements = new ArrayList<>(queue.size()); queue.drainTo(elements); - for (Element element : elements) { + for (int i = 0; i < elements.size(); i++) { + Element element = elements.get(i); + // If the unacknowledgedStanza queue is full, then bail out with a warning message. See SMACK-844. + if (unacknowledgedStanzas.remainingCapacity() == 0) { + StreamManagementException.UnacknowledgedQueueFullException exception = StreamManagementException.UnacknowledgedQueueFullException + .newWith(i, elements, unacknowledgedStanzas); + LOGGER.log(Level.WARNING, + "Some stanzas may be lost as not all could be drained to the unacknowledged stanzas queue", exception); + return; + } if (element instanceof Stanza) { unacknowledgedStanzas.add((Stanza) element); } From f6da386dea748fd1b82be4b337e267a9fa65cae0 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 14 Dec 2018 17:18:53 +0100 Subject: [PATCH 19/72] Ensure that IQ response 'to' address and ID are set correctly Fixes SMACK-845. --- .../java/org/jivesoftware/smack/AbstractXMPPConnection.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 6ab848c50..52fe2138e 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -1097,6 +1097,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { if (packet instanceof IQ) { final IQ iq = (IQ) packet; if (iq.isRequestIQ()) { + final IQ iqRequest = iq; final String key = XmppStringUtils.generateKey(iq.getChildElementName(), iq.getChildElementNamespace()); IQRequestHandler iqRequestHandler; final IQ.Type type = iq.getType(); @@ -1162,6 +1163,11 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // e.g. to avoid presence leaks. return; } + + assert (response.getType() == IQ.Type.result || response.getType() == IQ.Type.error); + + response.setTo(iqRequest.getFrom()); + response.setStanzaId(iqRequest.getStanzaId()); try { sendStanza(response); } From 48e31271720d65824e0ffff3f39abe9a2ef1980f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 20 Dec 2018 16:52:44 +0100 Subject: [PATCH 20/72] Always wait for stream features after authentication The purpose of the "maybeCompressFeaturesReceived" synchronization point is to wait for the stream features after authentication. This is not really reflected by its name and furthermore its checkIfSuccessOrWait() method was only invoked if compression was enabled, but we always want to wait for the stream features after authentication. Hence move the call before the isCompressionEnabled() check and one layer up in the call stack. Fixes SMACK-846. --- .../java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 6ba5e64fd..c5183fa70 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 @@ -387,6 +387,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { SSLSession sslSession = secureSocket != null ? secureSocket.getSession() : null; saslAuthentication.authenticate(username, password, config.getAuthzid(), sslSession); + // Wait for stream features after the authentication. + // TODO: The name of this synchronization point "maybeCompressFeaturesReceived" is not perfect. It should be + // renamed to "streamFeaturesAfterAuthenticationReceived". + maybeCompressFeaturesReceived.checkIfSuccessOrWait(); + // If compression is enabled then request the server to use stream compression. XEP-170 // recommends to perform stream compression before resource binding. maybeEnableCompression(); @@ -859,7 +864,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { if (!config.isCompressionEnabled()) { return; } - maybeCompressFeaturesReceived.checkIfSuccessOrWait(); + Compress.Feature compression = getFeature(Compress.Feature.ELEMENT, Compress.NAMESPACE); if (compression == null) { // Server does not support compression From d1c73eba8d4cdac363204a95da2d93905c0da6d0 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 20 Dec 2018 17:00:00 +0100 Subject: [PATCH 21/72] Fix MamManager javadoc of methods which have been renamed. --- .../src/main/java/org/jivesoftware/smackx/mam/MamManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java index 61fd861df..ba3af51aa 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java @@ -114,8 +114,8 @@ import org.jxmpp.jid.Jid; *
  * {@code
  * MamQueryArgs mamQueryArgs = MamQueryArgs.builder()
- *                                 .withJid(jid)
- *                                 .setResultPageSize(10)
+ *                                 .limitResultsToJid(jid)
+ *                                 .setResultPageSizeTo(10)
  *                                 .queryLastPage()
  *                                 .build();
  * MamQuery mamQuery = mamManager.queryArchive(mamQueryArgs);

From a2743549b8a4126e17f61adcb369f72d86ef58e1 Mon Sep 17 00:00:00 2001
From: Florian Schmaus 
Date: Mon, 17 Dec 2018 21:16:03 +0100
Subject: [PATCH 22/72] Make TCP socket connection attempt interruptable

by introducing SmackFuture.SocketFuture.

Fixes SMACK-847.
---
 .../org/jivesoftware/smack/SmackFuture.java   | 82 ++++++++++++++++++-
 .../smack/tcp/XMPPTCPConnection.java          | 12 ++-
 2 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackFuture.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackFuture.java
index 88a951677..9a6511d5f 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/SmackFuture.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackFuture.java
@@ -16,11 +16,18 @@
  */
 package org.jivesoftware.smack;
 
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketAddress;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.SocketFactory;
 
 import org.jivesoftware.smack.packet.Stanza;
 import org.jivesoftware.smack.util.CallbackRecipient;
@@ -29,6 +36,8 @@ import org.jivesoftware.smack.util.SuccessCallback;
 
 public abstract class SmackFuture implements Future, CallbackRecipient {
 
+    private static final Logger LOGGER = Logger.getLogger(SmackFuture.class.getName());
+
     private boolean cancelled;
 
     protected V result;
@@ -94,7 +103,7 @@ public abstract class SmackFuture implements Future,
     @Override
     public final synchronized V get() throws InterruptedException, ExecutionException {
         while (result == null && exception == null && !cancelled) {
-            wait();
+            futureWait();
         }
 
         return getOrThrowExecutionException();
@@ -102,7 +111,7 @@ public abstract class SmackFuture implements Future,
 
     public final synchronized V getOrThrow() throws E, InterruptedException {
         while (result == null && exception == null && !cancelled) {
-            wait();
+            futureWait();
         }
 
         if (exception != null) {
@@ -124,7 +133,7 @@ public abstract class SmackFuture implements Future,
         while (result != null && exception != null) {
             final long waitTimeRemaining = deadline - System.currentTimeMillis();
             if (waitTimeRemaining > 0) {
-                wait(waitTimeRemaining);
+                futureWait(waitTimeRemaining);
             }
         }
 
@@ -162,6 +171,15 @@ public abstract class SmackFuture implements Future,
         }
     }
 
+    protected final void futureWait() throws InterruptedException {
+        futureWait(0);
+    }
+
+    @SuppressWarnings("WaitNotInLoop")
+    protected void futureWait(long timeout) throws InterruptedException {
+        wait(timeout);
+    }
+
     public static class InternalSmackFuture extends SmackFuture {
         public final synchronized void setResult(V result) {
             this.result = result;
@@ -178,6 +196,64 @@ public abstract class SmackFuture implements Future,
         }
     }
 
+    public static class SocketFuture extends InternalSmackFuture {
+        private final Socket socket;
+
+        private final Object wasInterruptedLock = new Object();
+
+        private boolean wasInterrupted;
+
+        public SocketFuture(SocketFactory socketFactory) throws IOException {
+            socket = socketFactory.createSocket();
+        }
+
+        @Override
+        protected void futureWait(long timeout) throws InterruptedException {
+            try {
+                super.futureWait(timeout);
+            } catch (InterruptedException interruptedException) {
+                synchronized (wasInterruptedLock) {
+                    wasInterrupted = true;
+                    if (!socket.isClosed()) {
+                        closeSocket();
+                    }
+                }
+                throw interruptedException;
+            }
+        }
+
+        public void connectAsync(final SocketAddress socketAddress, final int timeout) {
+            AbstractXMPPConnection.asyncGo(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        socket.connect(socketAddress, timeout);
+                    }
+                    catch (IOException e) {
+                        setException(e);
+                        return;
+                    }
+                    synchronized (wasInterruptedLock) {
+                        if (wasInterrupted) {
+                            closeSocket();
+                            return;
+                        }
+                    }
+                    setResult(socket);
+                }
+            });
+        }
+
+        private void closeSocket() {
+            try {
+                socket.close();
+            }
+            catch (IOException ioException) {
+                LOGGER.log(Level.WARNING, "Could not close socket", ioException);
+            }
+        }
+    }
+
     public abstract static class InternalProcessStanzaSmackFuture extends InternalSmackFuture
                     implements StanzaListener, ExceptionCallback {
 
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 c5183fa70..5d940a679 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
@@ -83,6 +83,7 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
 import org.jivesoftware.smack.SmackException.NotConnectedException;
 import org.jivesoftware.smack.SmackException.NotLoggedInException;
 import org.jivesoftware.smack.SmackException.SecurityRequiredByServerException;
+import org.jivesoftware.smack.SmackFuture;
 import org.jivesoftware.smack.StanzaListener;
 import org.jivesoftware.smack.SynchronizationPoint;
 import org.jivesoftware.smack.XMPPConnection;
@@ -560,7 +561,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
         }
     }
 
-    private void connectUsingConfiguration() throws ConnectionException, IOException {
+    private void connectUsingConfiguration() throws ConnectionException, IOException, InterruptedException {
         List failedAddresses = populateHostAddresses();
         SocketFactory socketFactory = config.getSocketFactory();
         ProxyInfo proxyInfo = config.getProxyInfo();
@@ -579,14 +580,17 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
                 innerloop: while (inetAddresses.hasNext()) {
                     // Create a *new* Socket before every connection attempt, i.e. connect() call, since Sockets are not
                     // re-usable after a failed connection attempt. See also SMACK-724.
-                    socket = socketFactory.createSocket();
+                    SmackFuture.SocketFuture socketFuture = new SmackFuture.SocketFuture(socketFactory);
 
                     final InetAddress inetAddress = inetAddresses.next();
                     final String inetAddressAndPort = inetAddress + " at port " + port;
+                    final InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, port);
                     LOGGER.finer("Trying to establish TCP connection to " + inetAddressAndPort);
+                    socketFuture.connectAsync(inetSocketAddress, timeout);
+
                     try {
-                        socket.connect(new InetSocketAddress(inetAddress, port), timeout);
-                    } catch (Exception e) {
+                        socket = socketFuture.getOrThrow();
+                    } catch (IOException e) {
                         hostAddress.setException(inetAddress, e);
                         if (inetAddresses.hasNext()) {
                             continue innerloop;

From b9c12d44c3d8e5697d892c2938fe4e031c90a137 Mon Sep 17 00:00:00 2001
From: Florian Schmaus 
Date: Fri, 21 Dec 2018 12:05:14 +0100
Subject: [PATCH 23/72] Use InetSocketAddress in log message in
 XMPPTCPConnection

The inetAddressAndPort String is redundant since
a2743549b8a4126e17f61adcb369f72d86ef58e1, because we now construct the
InetSocketAddress earlier and can hence use it in the log statement.
---
 .../java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java   | 5 ++---
 1 file changed, 2 insertions(+), 3 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 5d940a679..24fcf37bc 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
@@ -583,9 +583,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
                     SmackFuture.SocketFuture socketFuture = new SmackFuture.SocketFuture(socketFactory);
 
                     final InetAddress inetAddress = inetAddresses.next();
-                    final String inetAddressAndPort = inetAddress + " at port " + port;
                     final InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, port);
-                    LOGGER.finer("Trying to establish TCP connection to " + inetAddressAndPort);
+                    LOGGER.finer("Trying to establish TCP connection to " + inetSocketAddress);
                     socketFuture.connectAsync(inetSocketAddress, timeout);
 
                     try {
@@ -598,7 +597,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
                             break innerloop;
                         }
                     }
-                    LOGGER.finer("Established TCP connection to " + inetAddressAndPort);
+                    LOGGER.finer("Established TCP connection to " + inetSocketAddress);
                     // We found a host to connect to, return here
                     this.host = host;
                     this.port = port;

From 4b21f003af8462cd7f05992568d80776bd291fa4 Mon Sep 17 00:00:00 2001
From: Florian Schmaus 
Date: Wed, 26 Dec 2018 21:39:25 +0100
Subject: [PATCH 24/72] Add MultiUserChat.leaveSync()

Fixes SMACK-848.
---
 .../smackx/muc/MultiUserChat.java             | 51 ++++++++++++++++++-
 .../muc/MultiUserChatIntegrationTest.java     | 26 ++++++++++
 2 files changed, 76 insertions(+), 1 deletion(-)

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 3b2bcbc86..77a859e09 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
@@ -734,7 +734,12 @@ public class MultiUserChat {
         // If we've already joined the room, leave it before joining under a new
         // nickname.
         if (joined) {
-            leave();
+            try {
+                leaveSync();
+            }
+            catch (XMPPErrorException | NoResponseException | MucNotJoinedException e) {
+                LOGGER.log(Level.WARNING, "Could not leave MUC prior joining, assuming we are not joined", e);
+            }
         }
         enter(mucEnterConfiguration);
     }
@@ -775,6 +780,50 @@ public class MultiUserChat {
         connection.sendStanza(leavePresence);
     }
 
+    /**
+     * Leave the chat room.
+     *
+     * @return the leave presence as reflected by the MUC.
+     * @throws NotConnectedException
+     * @throws InterruptedException
+     * @throws XMPPErrorException
+     * @throws NoResponseException
+     * @throws MucNotJoinedException
+     */
+    public synchronized Presence leaveSync()
+                    throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException, MucNotJoinedException {
+        //  Note that this method is intentionally not guarded by
+        // "if  (!joined) return" because it should be always be possible to leave the room in case the instance's
+        // state does not reflect the actual state.
+
+        // Reset occupant information first so that we are assume that we left the room even if sendStanza() would
+        // throw.
+        userHasLeft();
+
+        final EntityFullJid myRoomJid = this.myRoomJid;
+        if (myRoomJid == null) {
+            throw new MucNotJoinedException(this);
+        }
+
+        // We leave a room by sending a presence packet where the "to"
+        // field is in the form "roomName@service/nickname"
+        Presence leavePresence = new Presence(Presence.Type.unavailable);
+        leavePresence.setTo(myRoomJid);
+
+        StanzaFilter reflectedLeavePresenceFilter = new AndFilter(
+                        StanzaTypeFilter.PRESENCE,
+                        new StanzaIdFilter(leavePresence),
+                        new OrFilter(
+                                        new AndFilter(FromMatchesFilter.createFull(myRoomJid), PresenceTypeFilter.UNAVAILABLE, MUCUserStatusCodeFilter.STATUS_110_PRESENCE_TO_SELF),
+                                        new AndFilter(fromRoomFilter, PresenceTypeFilter.ERROR)
+                                    )
+                                );
+
+        Presence reflectedLeavePresence = connection.createStanzaCollectorAndSend(reflectedLeavePresenceFilter, leavePresence).nextResultOrThrow();
+
+        return reflectedLeavePresence;
+    }
+
     /**
      * Get a {@link MucConfigFormManager} to configure this room.
      * 

diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java index d4898bf16..d57f4467e 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java @@ -16,6 +16,9 @@ */ package org.jivesoftware.smackx.muc; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.util.List; import org.jivesoftware.smack.MessageListener; @@ -23,8 +26,12 @@ import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.muc.MultiUserChat.MucCreateConfigFormHandle; +import org.jivesoftware.smackx.muc.MultiUserChatException.MucNotJoinedException; +import org.jivesoftware.smackx.muc.MultiUserChatException.NotAMucServiceException; +import org.jivesoftware.smackx.muc.packet.MUCUser; import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest; import org.igniterealtime.smack.inttest.SmackIntegrationTest; @@ -36,6 +43,7 @@ import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Localpart; import org.jxmpp.jid.parts.Resourcepart; +import org.jxmpp.stringprep.XmppStringprepException; public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest { @@ -61,6 +69,24 @@ public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest { } } + @SmackIntegrationTest + public void mucJoinLeaveTest() throws XmppStringprepException, NotAMucServiceException, NoResponseException, + XMPPErrorException, NotConnectedException, InterruptedException, MucNotJoinedException { + EntityBareJid mucAddress = JidCreate.entityBareFrom(Localpart.from("smack-inttest-join-leave-" + randomString), + mucService.getDomain()); + + MultiUserChat muc = mucManagerOne.getMultiUserChat(mucAddress); + + muc.join(Resourcepart.from("nick-one")); + + Presence reflectedLeavePresence = muc.leaveSync(); + + MUCUser mucUser = MUCUser.from(reflectedLeavePresence); + assertNotNull(mucUser); + + assertTrue(mucUser.getStatus().contains(MUCUser.Status.PRESENCE_TO_SELF_110)); + } + @SmackIntegrationTest public void mucTest() throws Exception { EntityBareJid mucAddress = JidCreate.entityBareFrom(Localpart.from("smack-inttest-" + randomString), mucService.getDomain()); From 1a4ad7b8b50a54c086a65bbe02e30aa3dca01d96 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 27 Dec 2018 14:42:48 +0100 Subject: [PATCH 25/72] Mark Local SOCKS5 Proxy thread as daemon thread Fixes SMACK-849. --- .../org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java | 1 + 1 file changed, 1 insertion(+) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java index b39527ee3..da4dde16a 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5Proxy.java @@ -211,6 +211,7 @@ public final class Socks5Proxy { if (this.serverSocket != null) { this.serverThread = new Thread(this.serverProcess); this.serverThread.setName("Smack Local SOCKS5 Proxy"); + this.serverThread.setDaemon(true); this.serverThread.start(); } } From 5273402b878fdc74acbbd4497bf85b5ba7043200 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 30 Dec 2018 16:30:47 +0100 Subject: [PATCH 26/72] Use ranged versions for jXMPP and MiniDNS --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 74674db63..7348022bf 100644 --- a/version.gradle +++ b/version.gradle @@ -2,8 +2,8 @@ allprojects { ext { shortVersion = '4.3.2' isSnapshot = true - jxmppVersion = '0.6.3' - miniDnsVersion = '0.3.3' + jxmppVersion = '[0.6, 0.7)' + miniDnsVersion = '[0.3, 0.4)' smackMinAndroidSdk = 9 } } From 62cba0d96fdf9d2a307ae6c46571d351bd56448b Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 6 Feb 2019 21:49:58 +0100 Subject: [PATCH 27/72] XMPPTCPConnection: Ensure both writer/reader threads are terminated This should fix SMACK-855. --- .../smack/tcp/XMPPTCPConnection.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 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 24fcf37bc..ba71e69bf 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 @@ -51,6 +51,7 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -166,6 +167,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { private SSLSocket secureSocket; + private final Semaphore readerWriterSemaphore = new Semaphore(2); + /** * Protected access level because of unit test purposes */ @@ -635,8 +638,9 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { * @throws XMPPException if establishing a connection to the server fails. * @throws SmackException if the server fails to respond back or if there is anther error. * @throws IOException + * @throws InterruptedException */ - private void initConnection() throws IOException { + private void initConnection() throws IOException, InterruptedException { boolean isFirstInitialization = packetReader == null || packetWriter == null; compressionHandler = null; @@ -647,6 +651,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { packetWriter = new PacketWriter(); packetReader = new PacketReader(); } + + readerWriterSemaphore.acquire(2); // Start the writer thread. This will open an XMPP stream to the server packetWriter.init(); // Start the reader thread. The startup() method will block until we @@ -1014,7 +1020,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { Async.go(new Runnable() { @Override public void run() { - parsePackets(); + try { + parsePackets(); + } finally { + XMPPTCPConnection.this.readerWriterSemaphore.release(); + } } }, "Smack Reader (" + getConnectionCounter() + ")"); } @@ -1310,7 +1320,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { Async.go(new Runnable() { @Override public void run() { - writePackets(); + try { + writePackets(); + } finally { + XMPPTCPConnection.this.readerWriterSemaphore.release(); + } } }, "Smack Writer (" + getConnectionCounter() + ")"); } From 5c8e83015798ef8b897ea0c023355a4a0ed1ce39 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 8 Feb 2019 13:08:51 +0100 Subject: [PATCH 28/72] Log if not all reader/writer threads where terminated --- .../org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 ba71e69bf..4b44e61dd 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 @@ -652,6 +652,14 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { packetReader = new PacketReader(); } + int availableReaderWriterSemaphorePermits = readerWriterSemaphore.availablePermits(); + if (availableReaderWriterSemaphorePermits < 2) { + Object[] logObjects = new Object[] { + this, + availableReaderWriterSemaphorePermits, + }; + LOGGER.log(Level.FINE, "Not every reader/writer threads where terminated on connection re-initializtion of {0}. Available permits {1}", logObjects); + } readerWriterSemaphore.acquire(2); // Start the writer thread. This will open an XMPP stream to the server packetWriter.init(); From 09bffb8dca5d6850c022212b58310536978ce0a3 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 7 Feb 2019 20:43:45 +0100 Subject: [PATCH 29/72] Fail sync points on exception in XMPPTCPConnection --- .../smack/AbstractXMPPConnection.java | 4 +- .../jivesoftware/smack/SmackException.java | 12 ++++ .../smack/SynchronizationPoint.java | 59 +++++++++++++++---- .../smack/tcp/XMPPTCPConnection.java | 7 +++ 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 52fe2138e..7a9bf2ee1 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -235,7 +235,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { * stanza is send by the server. This is set to true once the last feature stanza has been * parsed. */ - protected final SynchronizationPoint lastFeaturesReceived = new SynchronizationPoint( + protected final SynchronizationPoint lastFeaturesReceived = new SynchronizationPoint<>( AbstractXMPPConnection.this, "last stream features received from server"); /** @@ -550,7 +550,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // - the servers last features stanza has been parsed // - the timeout occurs LOGGER.finer("Waiting for last features to be received before continuing with resource binding"); - lastFeaturesReceived.checkIfSuccessOrWait(); + lastFeaturesReceived.checkIfSuccessOrWaitOrThrow(); if (!hasFeature(Bind.ELEMENT, Bind.NAMESPACE)) { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java index 74d391539..a84b75211 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java @@ -334,4 +334,16 @@ public class SmackException extends Exception { super("Resource binding was not offered by server"); } } + + public static class SmackWrappedException extends SmackException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public SmackWrappedException(Exception exception) { + super(exception); + } + } } 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 54be30a36..a7113b284 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-2015 Florian Schmaus + * Copyright © 2014-2019 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.concurrent.locks.Lock; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.SmackException.SmackWrappedException; import org.jivesoftware.smack.packet.Nonza; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.TopLevelStreamElement; @@ -37,6 +38,7 @@ public class SynchronizationPoint { // same memory synchronization effects as synchronization block enter and leave. private State state; private E failureException; + private SmackWrappedException smackWrappedExcpetion; /** * Construct a new synchronization point for the given connection. @@ -59,6 +61,7 @@ public class SynchronizationPoint { connectionLock.lock(); state = State.Initial; failureException = null; + smackWrappedExcpetion = null; connectionLock.unlock(); } @@ -71,7 +74,7 @@ public class SynchronizationPoint { * @throws InterruptedException if the connection is interrupted. * @return null if synchronization point was successful, or the failure Exception. */ - public E sendAndWaitForResponse(TopLevelStreamElement request) throws NoResponseException, + public Exception sendAndWaitForResponse(TopLevelStreamElement request) throws NoResponseException, NotConnectedException, InterruptedException { assert (state == State.Initial); connectionLock.lock(); @@ -103,15 +106,14 @@ public class SynchronizationPoint { * @throws NoResponseException if no response was received. * @throws NotConnectedException if the connection is not connected. * @throws InterruptedException if the connection is interrupted. + * @throws SmackWrappedException in case of a wrapped exception; */ public void sendAndWaitForResponseOrThrow(Nonza request) throws E, NoResponseException, - NotConnectedException, InterruptedException { + NotConnectedException, InterruptedException, SmackWrappedException { sendAndWaitForResponse(request); switch (state) { case Failure: - if (failureException != null) { - throw failureException; - } + throwException(); break; default: // Success, do nothing @@ -123,11 +125,12 @@ public class SynchronizationPoint { * @throws NoResponseException if there was no response marking the synchronization point as success or failed. * @throws E if there was a failure * @throws InterruptedException if the connection is interrupted. + * @throws SmackWrappedException in case of a wrapped exception; */ - public void checkIfSuccessOrWaitOrThrow() throws NoResponseException, E, InterruptedException { + public void checkIfSuccessOrWaitOrThrow() throws NoResponseException, E, InterruptedException, SmackWrappedException { checkIfSuccessOrWait(); if (state == State.Failure) { - throw failureException; + throwException(); } } @@ -137,7 +140,7 @@ public class SynchronizationPoint { * @throws InterruptedException * @return null if synchronization point was successful, or the failure Exception. */ - public E checkIfSuccessOrWait() throws NoResponseException, InterruptedException { + public Exception checkIfSuccessOrWait() throws NoResponseException, InterruptedException { connectionLock.lock(); try { switch (state) { @@ -145,7 +148,7 @@ public class SynchronizationPoint { case Success: return null; case Failure: - return failureException; + return getException(); default: // Do nothing break; @@ -198,6 +201,24 @@ public class SynchronizationPoint { } } + /** + * Report this synchronization point as failed because of the given exception. The {@code failureException} must be set. + * + * @param exception the exception causing this synchronization point to fail. + */ + public void reportGenericFailure(SmackWrappedException exception) { + assert exception != null; + connectionLock.lock(); + try { + state = State.Failure; + this.smackWrappedExcpetion = exception; + condition.signalAll(); + } + finally { + connectionLock.unlock(); + } + } + /** * Check if this synchronization point was successful. * @@ -256,6 +277,20 @@ public class SynchronizationPoint { } } + private Exception getException() { + if (failureException != null) { + return failureException; + } + return smackWrappedExcpetion; + } + + private void throwException() throws E, SmackWrappedException { + if (failureException != null) { + throw failureException; + } + throw smackWrappedExcpetion; + } + /** * Check for a response and throw a {@link NoResponseException} if there was none. *

@@ -264,7 +299,7 @@ public class SynchronizationPoint { * @return true if synchronization point was successful, false on failure. * @throws NoResponseException */ - private E checkForResponse() throws NoResponseException { + private Exception checkForResponse() throws NoResponseException { switch (state) { case Initial: case NoResponse: @@ -273,7 +308,7 @@ public class SynchronizationPoint { case Success: return null; case Failure: - return failureException; + return getException(); default: throw new AssertionError("Unknown state " + state); } 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 4b44e61dd..0774e4375 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 @@ -84,6 +84,7 @@ import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotLoggedInException; import org.jivesoftware.smack.SmackException.SecurityRequiredByServerException; +import org.jivesoftware.smack.SmackException.SmackWrappedException; import org.jivesoftware.smack.SmackFuture; import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.SynchronizationPoint; @@ -937,6 +938,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { if ((packetReader == null || packetReader.done) && (packetWriter == null || packetWriter.done())) return; + SmackWrappedException smackWrappedException = new SmackWrappedException(e); + tlsHandled.reportGenericFailure(smackWrappedException); + saslFeatureReceived.reportGenericFailure(smackWrappedException); + maybeCompressFeaturesReceived.reportGenericFailure(smackWrappedException); + lastFeaturesReceived.reportGenericFailure(smackWrappedException); + // Closes the connection temporary. A reconnection is possible // Note that a connection listener of XMPPTCPConnection will drop the SM state in // case the Exception is a StreamErrorException. From 60f324eb1b8db2b910cc952ef6accdad22d45afc Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 9 Feb 2019 13:59:06 +0100 Subject: [PATCH 30/72] Make writer/reader fields final in XMPPTCPConnection --- .../org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 10 ++-------- .../org/jivesoftware/smack/tcp/PacketWriterTest.java | 8 +++----- 2 files changed, 5 insertions(+), 13 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 0774e4375..af7ffdeeb 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 @@ -173,12 +173,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { /** * Protected access level because of unit test purposes */ - protected PacketWriter packetWriter; + protected final PacketWriter packetWriter = new PacketWriter(); /** * Protected access level because of unit test purposes */ - protected PacketReader packetReader; + protected final PacketReader packetReader = new PacketReader(); private final SynchronizationPoint initialOpenStreamSend = new SynchronizationPoint<>( this, "initial open stream element send to server"); @@ -642,17 +642,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { * @throws InterruptedException */ private void initConnection() throws IOException, InterruptedException { - boolean isFirstInitialization = packetReader == null || packetWriter == null; compressionHandler = null; // Set the reader and writer instance variables initReaderAndWriter(); - if (isFirstInitialization) { - packetWriter = new PacketWriter(); - packetReader = new PacketReader(); - } - int availableReaderWriterSemaphorePermits = readerWriterSemaphore.availablePermits(); if (availableReaderWriterSemaphorePermits < 2) { Object[] logObjects = new Object[] { diff --git a/smack-tcp/src/test/java/org/jivesoftware/smack/tcp/PacketWriterTest.java b/smack-tcp/src/test/java/org/jivesoftware/smack/tcp/PacketWriterTest.java index c72996783..c28ec85e4 100644 --- a/smack-tcp/src/test/java/org/jivesoftware/smack/tcp/PacketWriterTest.java +++ b/smack-tcp/src/test/java/org/jivesoftware/smack/tcp/PacketWriterTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2014 Florian Schmaus + * Copyright 2014-2019 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,11 +49,9 @@ public class PacketWriterTest { @Test public void shouldBlockAndUnblockTest() throws InterruptedException, BrokenBarrierException, NotConnectedException, XmppStringprepException { XMPPTCPConnection connection = new XMPPTCPConnection("user", "pass", "example.org"); - final PacketWriter pw = connection.new PacketWriter(); - connection.packetWriter = pw; - connection.packetReader = connection.new PacketReader(); + final PacketWriter pw = connection.packetWriter; connection.setWriter(new BlockingStringWriter()); - pw.init(); + connection.packetWriter.init(); for (int i = 0; i < XMPPTCPConnection.PacketWriter.QUEUE_SIZE; i++) { pw.sendStreamElement(new Message()); From 78dcaec75bbd26f795e37776d3d8b8748a03226f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 9 Feb 2019 18:20:55 +0100 Subject: [PATCH 31/72] Remove null checks for writer/reader fields in XMPPTCPConnection as those are never null since 60f324eb1b8db2b910cc952ef6accdad22d45afc (the previous commit). --- .../smack/SynchronizationPoint.java | 10 +++++++ .../smack/tcp/XMPPTCPConnection.java | 26 ++++++++----------- 2 files changed, 21 insertions(+), 15 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 a7113b284..a40c3aeb5 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SynchronizationPoint.java @@ -234,6 +234,16 @@ public class SynchronizationPoint { } } + public boolean isNotInInitialState() { + connectionLock.lock(); + try { + return state != State.Initial; + } + finally { + connectionLock.unlock(); + } + } + /** * Check if this synchronization point has its request already sent. * 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 af7ffdeeb..8b1bdb70f 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 @@ -492,10 +492,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { // First shutdown the writer, this will result in a closing stream element getting send to // the server - if (packetWriter != null) { - LOGGER.finer("PacketWriter shutdown()"); - packetWriter.shutdown(instant); - } + LOGGER.finer("PacketWriter shutdown()"); + packetWriter.shutdown(instant); LOGGER.finer("PacketWriter has been shut down"); if (!instant) { @@ -510,10 +508,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } } - if (packetReader != null) { - LOGGER.finer("PacketReader shutdown()"); - packetReader.shutdown(); - } + LOGGER.finer("PacketReader shutdown()"); + packetReader.shutdown(); LOGGER.finer("PacketReader has been shut down"); try { @@ -929,8 +925,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { */ private synchronized void notifyConnectionError(Exception e) { // Listeners were already notified of the exception, return right here. - if ((packetReader == null || packetReader.done) && - (packetWriter == null || packetWriter.done())) return; + if (packetReader.done && packetWriter.done()) return; SmackWrappedException smackWrappedException = new SmackWrappedException(e); tlsHandled.reportGenericFailure(smackWrappedException); @@ -1386,11 +1381,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { instantShutdown = instant; queue.shutdown(); shutdownTimestamp = System.currentTimeMillis(); - try { - shutdownDone.checkIfSuccessOrWait(); - } - catch (NoResponseException | InterruptedException e) { - LOGGER.log(Level.WARNING, "shutdownDone was not marked as successful by the writer thread", e); + if (shutdownDone.isNotInInitialState()) { + try { + shutdownDone.checkIfSuccessOrWait(); + } catch (NoResponseException | InterruptedException e) { + LOGGER.log(Level.WARNING, "shutdownDone was not marked as successful by the writer thread", e); + } } } From ac9641f09187ae4a393c5f1acb1e94e66f24a64f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 16 Feb 2019 10:00:11 +0100 Subject: [PATCH 32/72] Do not set com.sun.jndi.dns.DnsContextFactory in JavaxResolver as this is not accessible in newer Java versions (at least 11). Fixes SMACK-856. --- .../jivesoftware/smack/util/dns/javax/JavaxResolver.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java index 12cc680fe..e91802e04 100644 --- a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java +++ b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2018 Florian Schmaus + * Copyright 2013-2019 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package org.jivesoftware.smack.util.dns.javax; import java.net.InetAddress; import java.util.ArrayList; -import java.util.Hashtable; import java.util.List; import java.util.logging.Level; @@ -52,9 +51,7 @@ public class JavaxResolver extends DNSResolver implements SmackInitializer { static { try { - Hashtable env = new Hashtable<>(); - env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); - dirContext = new InitialDirContext(env); + dirContext = new InitialDirContext(); } catch (Exception e) { // Ignore. } From eccaf58df1d95460b05de6c35e19b70dd498c189 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 16 Feb 2019 10:03:05 +0100 Subject: [PATCH 33/72] Add Logger to JavaxResolver --- .../org/jivesoftware/smack/util/dns/javax/JavaxResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java index e91802e04..0d4825bfa 100644 --- a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java +++ b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java @@ -53,7 +53,7 @@ public class JavaxResolver extends DNSResolver implements SmackInitializer { try { dirContext = new InitialDirContext(); } catch (Exception e) { - // Ignore. + LOGGER.log(Level.SEVERE, "Could not construct InitialDirContext", e); } // Try to set this DNS resolver as primary one From db8e37d75f374fad17c74ab9a45036a67dfd8b92 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 16 Feb 2019 10:03:32 +0100 Subject: [PATCH 34/72] Reduce scope of catched Exceptions in JavaxResolver --- .../org/jivesoftware/smack/util/dns/javax/JavaxResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java index 0d4825bfa..e83c588f6 100644 --- a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java +++ b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java @@ -52,7 +52,7 @@ public class JavaxResolver extends DNSResolver implements SmackInitializer { static { try { dirContext = new InitialDirContext(); - } catch (Exception e) { + } catch (NamingException e) { LOGGER.log(Level.SEVERE, "Could not construct InitialDirContext", e); } From e9b514548b54affed48522a2d61248bf7aee53e1 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 17 Feb 2019 21:54:38 +0100 Subject: [PATCH 35/72] Filter error messages in DeliveryReceiptManager --- .../smackx/receipts/DeliveryReceiptManager.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java index dbfd61436..c310ceb25 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2014 Georg Lukas, 2015 Florian Schmaus + * Copyright 2013-2014 Georg Lukas, 2015-2019 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,8 +74,16 @@ import org.jxmpp.jid.Jid; */ public final class DeliveryReceiptManager extends Manager { - private static final StanzaFilter MESSAGES_WITH_DELIVERY_RECEIPT_REQUEST = new AndFilter(StanzaTypeFilter.MESSAGE, - new StanzaExtensionFilter(new DeliveryReceiptRequest())); + /** + * Filters all non-error messages with receipt requests. + * See XEP-0184 § 5. "A sender could request receipts + * on any non-error content message (chat, groupchat, headline, or normal)…" + */ + private static final StanzaFilter NON_ERROR_GROUPCHAT_MESSAGES_WITH_DELIVERY_RECEIPT_REQUEST = new AndFilter( + StanzaTypeFilter.MESSAGE, + new StanzaExtensionFilter(new DeliveryReceiptRequest()), + new NotFilter(MessageTypeFilter.ERROR)); + private static final StanzaFilter MESSAGES_WITH_DELIVERY_RECEIPT = new AndFilter(StanzaTypeFilter.MESSAGE, new StanzaExtensionFilter(DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE)); @@ -175,7 +183,7 @@ public final class DeliveryReceiptManager extends Manager { } connection.sendStanza(ack); } - }, MESSAGES_WITH_DELIVERY_RECEIPT_REQUEST); + }, NON_ERROR_GROUPCHAT_MESSAGES_WITH_DELIVERY_RECEIPT_REQUEST); } /** From a8044f723a7dd35a30be8525df41399d982085e0 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 22 Feb 2019 09:22:23 +0100 Subject: [PATCH 36/72] Smack 4.3.2 --- resources/releasedocs/changelog.html | 32 ++++++++++++++++++++++++++++ version.gradle | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/resources/releasedocs/changelog.html b/resources/releasedocs/changelog.html index 77450e326..5d249c249 100644 --- a/resources/releasedocs/changelog.html +++ b/resources/releasedocs/changelog.html @@ -141,6 +141,38 @@ hr {

+

4.3.2 -- 2019-02-22

+ +

Bug +

+
    +
  • [SMACK-842] - The RFC 3920 xml-not-well-formed error condition should be handled in stream error not a stanza error +
  • +
  • [SMACK-843] - ManManager.pagePrevious() pages into the wrong direction +
  • +
  • [SMACK-844] - Check if bounded unacknowledged stanzas queue is full before adding to it to avoid IllegalStateException +
  • +
  • [SMACK-845] - Ensure that IQ response 'to' address and ID are set correctly +
  • +
  • [SMACK-846] - XMPPTCPConnection does not wait for stream features after authentication if compression is disabled +
  • +
  • [SMACK-848] - Make MultiUserChat.leave() wait for response +
  • +
  • [SMACK-850] - DeliveryReceiptManager should not send receipts with messages of type 'groupchat' +
  • +
  • [SMACK-855] - XMPPTCPConnection sometimes has two writer threads running +
  • +
+ +

Improvement +

+
    +
  • [SMACK-847] - Make TCP socket connection attempt interruptable +
  • +
  • [SMACK-849] - Smack Local SOCKS5 Proxy thread should be marked as daemon thread +
  • +
+

4.3.1 -- 2018-10-14

Bug diff --git a/version.gradle b/version.gradle index 7348022bf..3fc19bb3e 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { shortVersion = '4.3.2' - isSnapshot = true + isSnapshot = false jxmppVersion = '[0.6, 0.7)' miniDnsVersion = '[0.3, 0.4)' smackMinAndroidSdk = 9 From 47f76952e3da3901b43f68c1b39a8e89726ad727 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 22 Feb 2019 10:57:48 +0100 Subject: [PATCH 37/72] Smack 4.3.3-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 3fc19bb3e..ffd608d0c 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { - shortVersion = '4.3.2' - isSnapshot = false + shortVersion = '4.3.3' + isSnapshot = true jxmppVersion = '[0.6, 0.7)' miniDnsVersion = '[0.3, 0.4)' smackMinAndroidSdk = 9 From 27749b21376a34870986635df5c4619aec240e0b Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 23 Feb 2019 23:27:06 +0100 Subject: [PATCH 38/72] Remove unused filter in StableUniqueStanzaIdManager --- .../jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java index 677a38910..85c08c437 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java @@ -27,7 +27,6 @@ import org.jivesoftware.smack.XMPPConnectionRegistry; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.MessageTypeFilter; import org.jivesoftware.smack.filter.NotFilter; -import org.jivesoftware.smack.filter.StanzaExtensionFilter; import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.ToTypeFilter; import org.jivesoftware.smack.packet.Message; @@ -46,8 +45,6 @@ public final class StableUniqueStanzaIdManager extends Manager { MessageTypeFilter.NORMAL_OR_CHAT_OR_HEADLINE, ToTypeFilter.ENTITY_FULL_OR_BARE_JID); - private static final StanzaFilter ORIGIN_ID_FILTER = new StanzaExtensionFilter(OriginIdElement.ELEMENT, NAMESPACE); - // Listener for outgoing stanzas that adds origin-ids to outgoing stanzas. private final StanzaListener stanzaListener = new StanzaListener() { @Override From 4da4558b29857a02cdc32f09befd84295186d8ef Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 23 Feb 2019 23:39:58 +0100 Subject: [PATCH 39/72] Make origin-id interceptor static and rename it --- .../smackx/sid/StableUniqueStanzaIdManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java index 85c08c437..ec6523dff 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java @@ -46,7 +46,7 @@ public final class StableUniqueStanzaIdManager extends Manager { ToTypeFilter.ENTITY_FULL_OR_BARE_JID); // Listener for outgoing stanzas that adds origin-ids to outgoing stanzas. - private final StanzaListener stanzaListener = new StanzaListener() { + private static final StanzaListener ADD_ORIGIN_ID_INTERCEPTOR = new StanzaListener() { @Override public void processStanza(Stanza stanza) { OriginIdElement.addOriginId((Message) stanza); @@ -92,7 +92,7 @@ public final class StableUniqueStanzaIdManager extends Manager { public synchronized void enable() { ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(NAMESPACE); StanzaFilter filter = new AndFilter(OUTGOING_FILTER, new NotFilter(OUTGOING_FILTER)); - connection().addStanzaInterceptor(stanzaListener, filter); + connection().addStanzaInterceptor(ADD_ORIGIN_ID_INTERCEPTOR, filter); } /** @@ -100,7 +100,7 @@ public final class StableUniqueStanzaIdManager extends Manager { */ public synchronized void disable() { ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(NAMESPACE); - connection().removeStanzaInterceptor(stanzaListener); + connection().removeStanzaInterceptor(ADD_ORIGIN_ID_INTERCEPTOR); } /** From 5a2109e73fd346baa5aba2ff64e351b8a98e30d4 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 23 Feb 2019 23:40:27 +0100 Subject: [PATCH 40/72] Move cast in extra line in ADD_ORIGIN_ID_INTERCEPTOR --- .../jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java index ec6523dff..99ec03f5d 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java @@ -49,7 +49,8 @@ public final class StableUniqueStanzaIdManager extends Manager { private static final StanzaListener ADD_ORIGIN_ID_INTERCEPTOR = new StanzaListener() { @Override public void processStanza(Stanza stanza) { - OriginIdElement.addOriginId((Message) stanza); + Message message = (Message) stanza; + OriginIdElement.addOriginId(message); } }; From 5f7cfd04bdccb140383124235f7fea424dd566d6 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 23 Feb 2019 23:54:42 +0100 Subject: [PATCH 41/72] Add further unit test to StableUniqueStanzaIdTest --- .../smackx/sid/StableUniqueStanzaIdTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java index f6486ee43..95e42e962 100644 --- a/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java @@ -25,6 +25,7 @@ import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.test.util.SmackTestSuite; import org.jivesoftware.smack.test.util.TestUtils; +import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smackx.sid.element.OriginIdElement; import org.jivesoftware.smackx.sid.element.StanzaIdElement; import org.jivesoftware.smackx.sid.provider.OriginIdProvider; @@ -81,4 +82,17 @@ public class StableUniqueStanzaIdTest extends SmackTestSuite { assertTrue(StanzaIdElement.hasStanzaId(message)); assertEquals(stanzaId, StanzaIdElement.getStanzaId(message)); } + + @Test + public void testMultipleUssidExtensions() throws Exception { + String message = "" + + "Test message" + + "" + + "" + + "" + + ""; + Message messageStanza = PacketParserUtils.parseStanza(message); + + assertTrue(StanzaIdElement.hasStanzaId(messageStanza)); + } } From 3bdc1d30b11686ca50bd537663d9ea1b77bba9a1 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 23 Feb 2019 23:57:31 +0100 Subject: [PATCH 42/72] Correctly name provider INSTANCE fields and make them 'final' where possible. --- .../jivesoftware/smackx/sid/provider/OriginIdProvider.java | 6 +++++- .../jivesoftware/smackx/sid/provider/StanzaIdProvider.java | 6 +++++- .../jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/OriginIdProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/OriginIdProvider.java index 19ef6edd7..a84bf6266 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/OriginIdProvider.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/OriginIdProvider.java @@ -23,7 +23,11 @@ import org.xmlpull.v1.XmlPullParser; public class OriginIdProvider extends ExtensionElementProvider { - public static final OriginIdProvider TEST_INSTANCE = new OriginIdProvider(); + public static final OriginIdProvider INSTANCE = new OriginIdProvider(); + + // TODO: Remove in Smack 4.4. + @Deprecated + public static final OriginIdProvider TEST_INSTANCE = INSTANCE; @Override public OriginIdElement parse(XmlPullParser parser, int initialDepth) throws Exception { diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/StanzaIdProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/StanzaIdProvider.java index 2a3fcad28..a37aaf10f 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/StanzaIdProvider.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/provider/StanzaIdProvider.java @@ -23,7 +23,11 @@ import org.xmlpull.v1.XmlPullParser; public class StanzaIdProvider extends ExtensionElementProvider { - public static StanzaIdProvider TEST_INSTANCE = new StanzaIdProvider(); + public static final StanzaIdProvider INSTANCE = new StanzaIdProvider(); + + // TODO: Remove in Smack 4.4. + @Deprecated + public static final StanzaIdProvider TEST_INSTANCE = INSTANCE; @Override public StanzaIdElement parse(XmlPullParser parser, int initialDepth) throws Exception { diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java index 95e42e962..9b12fc0c3 100644 --- a/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdTest.java @@ -43,7 +43,7 @@ public class StableUniqueStanzaIdTest extends SmackTestSuite { assertEquals("alice@wonderland.lit", element.getBy()); assertXMLEqual(xml, element.toXML(null).toString()); - StanzaIdElement parsed = StanzaIdProvider.TEST_INSTANCE.parse(TestUtils.getParser(xml)); + StanzaIdElement parsed = StanzaIdProvider.INSTANCE.parse(TestUtils.getParser(xml)); assertEquals(element.getId(), parsed.getId()); assertEquals(element.getBy(), parsed.getBy()); } @@ -55,7 +55,7 @@ public class StableUniqueStanzaIdTest extends SmackTestSuite { assertEquals("de305d54-75b4-431b-adb2-eb6b9e546013", element.getId()); assertXMLEqual(xml, element.toXML(null).toString()); - OriginIdElement parsed = OriginIdProvider.TEST_INSTANCE.parse(TestUtils.getParser(xml)); + OriginIdElement parsed = OriginIdProvider.INSTANCE.parse(TestUtils.getParser(xml)); assertEquals(element.getId(), parsed.getId()); } From 456d645e275d3439c3a8369dbbc9238600b84167 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 24 Feb 2019 22:09:47 +0100 Subject: [PATCH 43/72] Use different version specifier for jxmpp and MiniDNS Fixes SMACK-858. --- version.gradle | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index ffd608d0c..a478e9a52 100644 --- a/version.gradle +++ b/version.gradle @@ -2,8 +2,12 @@ allprojects { ext { shortVersion = '4.3.3' isSnapshot = true - jxmppVersion = '[0.6, 0.7)' - miniDnsVersion = '[0.3, 0.4)' + // When using dynamic versions for those, do *not* use [1.0, + // 2.0), since this will also pull in 2.0-alpha1. Instead use + // [1.0, 1.0.99]. + // See also https://issues.apache.org/jira/browse/MNG-6232 + jxmppVersion = '[0.6, 0.6.999]' + miniDnsVersion = '[0.3, 0.3.999]' smackMinAndroidSdk = 9 } } From 78ee22c2611ee49c989092d9686d521b719df88a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 2 Mar 2019 14:42:19 +0100 Subject: [PATCH 44/72] Revert "Do not set com.sun.jndi.dns.DnsContextFactory in JavaxResolver" This reverts commit ac9641f09187ae4a393c5f1acb1e94e66f24a64f. Reverted because now an NoInitialContextException is now thrown. Related to SMACK-856. --- .../jivesoftware/smack/util/dns/javax/JavaxResolver.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java index e83c588f6..58da92432 100644 --- a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java +++ b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2019 Florian Schmaus + * Copyright 2013-2018 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.jivesoftware.smack.util.dns.javax; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; import java.util.logging.Level; @@ -51,7 +52,9 @@ public class JavaxResolver extends DNSResolver implements SmackInitializer { static { try { - dirContext = new InitialDirContext(); + Hashtable env = new Hashtable<>(); + env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); + dirContext = new InitialDirContext(env); } catch (NamingException e) { LOGGER.log(Level.SEVERE, "Could not construct InitialDirContext", e); } From f4ebd530e6de4cafad8fe6b12546fc1bd71b2754 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 2 Mar 2019 14:47:28 +0100 Subject: [PATCH 45/72] Add note about module dependencies to JavaxResolver Related to SMACK-856. --- .../org/jivesoftware/smack/util/dns/javax/JavaxResolver.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java index 58da92432..957d8006c 100644 --- a/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java +++ b/smack-resolver-javax/src/main/java/org/jivesoftware/smack/util/dns/javax/JavaxResolver.java @@ -1,6 +1,6 @@ /** * - * Copyright 2013-2018 Florian Schmaus + * Copyright 2013-2019 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,7 @@ import org.minidns.dnsname.DnsName; /** * A DNS resolver (mostly for SRV records), which makes use of the API provided in the javax.* namespace. + * Note that using JavaxResovler requires applications using newer Java versions (at least 11) to declare a dependency on the "sun.jdk" module. * * @author Florian Schmaus * From f602de8771db507f4538a60302a0f2d2bca218f6 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 4 Mar 2019 17:08:53 +0100 Subject: [PATCH 46/72] Call shutdown() in connect() on exception to clean up the state build up by connect(). Related to SMACK-855 there is the possiblitiy of a stray (writer) thread if, for example, tlsHandled.checkifSuccessOrWaitorThrow() in XMPPTCPConnection.connectInternal() throws. This commit should prevent that. --- .../smack/bosh/XMPPBOSHConnection.java | 5 ++++ .../smack/AbstractXMPPConnection.java | 25 +++++++++++++------ .../jivesoftware/smack/DummyConnection.java | 6 +++++ .../smack/tcp/XMPPTCPConnection.java | 4 +-- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index 8fba8051a..68dd48fcb 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -263,6 +263,11 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { client = null; } + instantShutdown(); + } + + @Override + public void instantShutdown() { setWasAuthenticated(); sessionID = null; done = true; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 7a9bf2ee1..697ebfc3b 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -405,15 +405,19 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { tlsHandled.init(); streamId = null; - // Perform the actual connection to the XMPP service - connectInternal(); + try { + // Perform the actual connection to the XMPP service + connectInternal(); - // If TLS is required but the server doesn't offer it, disconnect - // from the server and throw an error. First check if we've already negotiated TLS - // and are secure, however (features get parsed a second time after TLS is established). - if (!isSecureConnection() && getConfiguration().getSecurityMode() == SecurityMode.required) { - shutdown(); - throw new SecurityRequiredByClientException(); + // If TLS is required but the server doesn't offer it, disconnect + // from the server and throw an error. First check if we've already negotiated TLS + // and are secure, however (features get parsed a second time after TLS is established). + if (!isSecureConnection() && getConfiguration().getSecurityMode() == SecurityMode.required) { + throw new SecurityRequiredByClientException(); + } + } catch (SmackException | IOException | XMPPException | InterruptedException e) { + instantShutdown(); + throw e; } // Make note of the fact that we're now connected. @@ -763,6 +767,11 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { */ protected abstract void shutdown(); + /** + * Performs an unclean disconnect and shutdown of the connection. Does not send a closing stream stanza. + */ + public abstract void instantShutdown(); + @Override public void addConnectionListener(ConnectionListener connectionListener) { if (connectionListener == null) { diff --git a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java index a3ff3246f..ea39e1233 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java @@ -100,6 +100,11 @@ public class DummyConnection extends AbstractXMPPConnection { callConnectionClosedListener(); } + @Override + public void instantShutdown() { + shutdown(); + } + @Override public boolean isSecureConnection() { return false; @@ -226,4 +231,5 @@ public class DummyConnection extends AbstractXMPPConnection { } } } + } 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 8b1bdb70f..0d340cfcd 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 @@ -478,9 +478,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { shutdown(false); } - /** - * Performs an unclean disconnect and shutdown of the connection. Does not send a closing stream stanza. - */ + @Override public synchronized void instantShutdown() { shutdown(true); } From 7f0932a481016505d58daf6cc4dbcbd5991573e0 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 4 Mar 2019 23:00:45 +0100 Subject: [PATCH 47/72] Reset the MUC self-presence collector on presence stanzas on join To prevent timeouts when joining very large MUCs we now reset the self-presence collector's timeout for every other (occupant) presence we receive. Fixes SMACK-859. --- .../smackx/muc/MultiUserChat.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 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 77a859e09..ce00484a3 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 @@ -340,8 +340,9 @@ public class MultiUserChat { // Setup the messageListeners and presenceListeners *before* the join presence is send. connection.addSyncStanzaListener(messageListener, fromRoomGroupchatFilter); - connection.addSyncStanzaListener(presenceListener, new AndFilter(fromRoomFilter, - StanzaTypeFilter.PRESENCE)); + StanzaFilter presenceFromRoomFilter = new AndFilter(fromRoomFilter, + StanzaTypeFilter.PRESENCE); + connection.addSyncStanzaListener(presenceListener, presenceFromRoomFilter); // @formatter:off connection.addSyncStanzaListener(subjectListener, new AndFilter(fromRoomFilter, @@ -370,15 +371,27 @@ public class MultiUserChat { ) ); // @formatter:on + StanzaCollector presenceStanzaCollector = null; Presence presence; try { - presence = connection.createStanzaCollectorAndSend(responseFilter, joinPresence).nextResultOrThrow(conf.getTimeout()); + // This stanza collector will collect the final self presence from the MUC, which also signals that we have successful entered the MUC. + StanzaCollector selfPresenceCollector = connection.createStanzaCollectorAndSend(responseFilter, joinPresence); + StanzaCollector.Configuration presenceStanzaCollectorConfguration = StanzaCollector.newConfiguration().setCollectorToReset( + selfPresenceCollector).setStanzaFilter(presenceFromRoomFilter); + // This stanza collector is used to reset the timeout of the selfPresenceCollector. + presenceStanzaCollector = connection.createStanzaCollector(presenceStanzaCollectorConfguration); + presence = selfPresenceCollector.nextResultOrThrow(conf.getTimeout()); } catch (NotConnectedException | InterruptedException | NoResponseException | XMPPErrorException e) { // Ensure that all callbacks are removed if there is an exception removeConnectionCallbacks(); throw e; } + finally { + if (presenceStanzaCollector != null) { + presenceStanzaCollector.cancel(); + } + } // 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 From 3d1a781a2228d9d2fe31f6b8c96687ca3dc56eb5 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 5 Mar 2019 08:21:59 +0100 Subject: [PATCH 48/72] Show correct reply timeout value in StanzaCollector's NoResponseException --- .../org/jivesoftware/smack/SmackException.java | 18 ++++++++++++++++-- .../jivesoftware/smack/StanzaCollector.java | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java index a84b75211..3011a1288 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackException.java @@ -93,13 +93,24 @@ public class SmackException extends Exception { return new NoResponseException(sb.toString()); } + @Deprecated + // TODO: Remove in Smack 4.4. public static NoResponseException newWith(XMPPConnection connection, StanzaCollector collector) { return newWith(connection, collector.getStanzaFilter()); } + public static NoResponseException newWith(long timeout, + StanzaCollector collector) { + return newWith(timeout, collector.getStanzaFilter()); + } + public static NoResponseException newWith(XMPPConnection connection, StanzaFilter filter) { - final StringBuilder sb = getWaitingFor(connection); + return newWith(connection.getReplyTimeout(), filter); + } + + public static NoResponseException newWith(long timeout, StanzaFilter filter) { + final StringBuilder sb = getWaitingFor(timeout); sb.append(" Waited for response using: "); if (filter != null) { sb.append(filter.toString()); @@ -112,7 +123,10 @@ public class SmackException extends Exception { } private static StringBuilder getWaitingFor(XMPPConnection connection) { - final long replyTimeout = connection.getReplyTimeout(); + return getWaitingFor(connection.getReplyTimeout()); + } + + private static StringBuilder getWaitingFor(final long replyTimeout) { final StringBuilder sb = new StringBuilder(256); sb.append("No response received within reply timeout. Timeout was " + replyTimeout + "ms (~" diff --git a/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java b/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java index 0b933909e..f6aa5225c 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/StanzaCollector.java @@ -262,7 +262,7 @@ public class StanzaCollector { if (!connection.isConnected()) { throw new NotConnectedException(connection, packetFilter); } - throw NoResponseException.newWith(connection, this); + throw NoResponseException.newWith(timeout, this); } XMPPErrorException.ifHasErrorThenThrow(result); From 7d2c3ac9f9ca28b172b3acb41d95ba9aa2583a63 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 6 Mar 2019 22:11:45 +0100 Subject: [PATCH 49/72] Do not call synchronized methods in reader/writer thread This may cause deadlocks with a call to acquire(2) on the introduced readerWriterSemaphore in initConnection(), which is also synchronized. --- .../smack/AbstractXMPPConnection.java | 2 +- .../smack/tcp/XMPPTCPConnection.java | 57 ++++++++++++++----- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 697ebfc3b..d19b680ef 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -297,7 +297,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { } }); - private static final AsyncButOrdered ASYNC_BUT_ORDERED = new AsyncButOrdered<>(); + protected static final AsyncButOrdered ASYNC_BUT_ORDERED = new AsyncButOrdered<>(); /** * The used host to establish the connection to 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 0d340cfcd..77245f285 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 @@ -921,23 +921,46 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { * * @param e the exception that causes the connection close event. */ - private synchronized void notifyConnectionError(Exception e) { - // Listeners were already notified of the exception, return right here. - if (packetReader.done && packetWriter.done()) return; + private synchronized void notifyConnectionError(final Exception e) { + ASYNC_BUT_ORDERED.performAsyncButOrdered(this, new Runnable() { + @Override + public void run() { + // Listeners were already notified of the exception, return right here. + if (packetReader.done || packetWriter.done()) return; - SmackWrappedException smackWrappedException = new SmackWrappedException(e); - tlsHandled.reportGenericFailure(smackWrappedException); - saslFeatureReceived.reportGenericFailure(smackWrappedException); - maybeCompressFeaturesReceived.reportGenericFailure(smackWrappedException); - lastFeaturesReceived.reportGenericFailure(smackWrappedException); + // Report the failure outside the synchronized block, so that a thread waiting within a synchronized + // function like connect() throws the wrapped exception. + SmackWrappedException smackWrappedException = new SmackWrappedException(e); + tlsHandled.reportGenericFailure(smackWrappedException); + saslFeatureReceived.reportGenericFailure(smackWrappedException); + maybeCompressFeaturesReceived.reportGenericFailure(smackWrappedException); + lastFeaturesReceived.reportGenericFailure(smackWrappedException); - // Closes the connection temporary. A reconnection is possible - // Note that a connection listener of XMPPTCPConnection will drop the SM state in - // case the Exception is a StreamErrorException. - instantShutdown(); + synchronized (XMPPTCPConnection.this) { + // Within this synchronized block, either *both* reader and writer threads must be terminated, or + // none. + assert ((packetReader.done && packetWriter.done()) + || (!packetReader.done && !packetWriter.done())); - // Notify connection listeners of the error. - callConnectionClosedOnErrorListener(e); + // Closes the connection temporary. A reconnection is possible + // Note that a connection listener of XMPPTCPConnection will drop the SM state in + // case the Exception is a StreamErrorException. + instantShutdown(); + + // Wait for reader and writer threads to be terminated. + readerWriterSemaphore.acquireUninterruptibly(2); + readerWriterSemaphore.release(2); + } + + Async.go(new Runnable() { + @Override + public void run() { + // Notify connection listeners of the error. + callConnectionClosedOnErrorListener(e); + } + }, XMPPTCPConnection.this + " callConnectionClosedOnErrorListener()"); + } + }); } /** @@ -1248,7 +1271,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { LOGGER.info(XMPPTCPConnection.this + " received closing element." + " Server wants to terminate the connection, calling disconnect()"); - disconnect(); + ASYNC_BUT_ORDERED.performAsyncButOrdered(XMPPTCPConnection.this, new Runnable() { + @Override + public void run() { + disconnect(); + }}); } } break; From 5da6dea138cf57a96e6bd4d9298fdb497be5b64a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 7 Mar 2019 09:49:16 +0100 Subject: [PATCH 50/72] Throw exception to reduce call sites of notifyConnectionError() in XMPPTCPConnection. --- .../java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 7 +++---- 1 file changed, 3 insertions(+), 4 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 77245f285..8d53dc5e8 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 @@ -973,14 +973,13 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } @Override - protected void afterFeaturesReceived() throws NotConnectedException, InterruptedException { + protected void afterFeaturesReceived() throws NotConnectedException, InterruptedException, SecurityRequiredByServerException { StartTls startTlsFeature = getFeature(StartTls.ELEMENT, StartTls.NAMESPACE); if (startTlsFeature != null) { if (startTlsFeature.required() && config.getSecurityMode() == SecurityMode.disabled) { - SmackException smackException = new SecurityRequiredByServerException(); + SecurityRequiredByServerException smackException = new SecurityRequiredByServerException(); tlsHandled.reportFailure(smackException); - notifyConnectionError(smackException); - return; + throw smackException; } if (config.getSecurityMode() != ConnectionConfiguration.SecurityMode.disabled) { From 7518bf9a25a8c8ac7e25fa5daff9d50ab4801bd7 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 8 Mar 2019 13:50:54 +0100 Subject: [PATCH 51/72] Add descriptive text to StanzaError.toString() --- .../java/org/jivesoftware/smack/packet/StanzaError.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java index fad9f5253..d5a2dd890 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/StanzaError.java @@ -198,6 +198,12 @@ public class StanzaError extends AbstractError implements ExtensionElement { public String toString() { StringBuilder sb = new StringBuilder("XMPPError: "); sb.append(condition.toString()).append(" - ").append(type.toString()); + + String descriptiveText = getDescriptiveText(); + if (descriptiveText != null) { + sb.append(" [").append(descriptiveText).append(']'); + } + if (errorGenerator != null) { sb.append(". Generated by ").append(errorGenerator); } From c4289b2c1819bd7b62dca9ed7743410b19665296 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 9 Mar 2019 17:13:54 +0100 Subject: [PATCH 52/72] Add AbstractXMPPConnection.initState() and init/reset the sychronization points there. This method is called right at the beginning of connect() and at the end of shutdown(). --- .../org/jivesoftware/smack/AbstractXMPPConnection.java | 10 +++++++--- .../org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index d19b680ef..5800c6dd7 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -381,6 +381,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { @Override public abstract boolean isUsingCompression(); + protected void initState() { + saslFeatureReceived.init(); + lastFeaturesReceived.init(); + tlsHandled.init(); + } + /** * Establishes a connection to the XMPP server. It basically * creates and maintains a connection to the server. @@ -399,10 +405,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { throwAlreadyConnectedExceptionIfAppropriate(); // Reset the connection state + initState(); saslAuthentication.init(); - saslFeatureReceived.init(); - lastFeaturesReceived.init(); - tlsHandled.init(); streamId = null; try { 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 8d53dc5e8..713bf77bd 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 @@ -534,6 +534,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { reader = null; writer = null; + initState(); + } + + @Override + protected void initState() { + super.initState(); maybeCompressFeaturesReceived.init(); compressSyncPoint.init(); smResumedSyncPoint.init(); From 569f7417a8e2bc59462f0112334ae1cddab73dde Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 9 Mar 2019 19:19:20 +0100 Subject: [PATCH 53/72] Add AuthenticatedConnectionInitiallyEstablished timestamp --- .../smack/AbstractXMPPConnection.java | 18 ++++++++++++++++++ .../smack/tcp/XMPPTCPConnection.java | 2 ++ 2 files changed, 20 insertions(+) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 5800c6dd7..38e188ef9 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -314,6 +314,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { */ protected boolean authenticated = false; + // TODO: Migrate to ZonedDateTime once Smack's minimum required Android SDK level is 26 (8.0, Oreo) or higher. + protected long authenticatedConnectionInitiallyEstablishedTimestamp; + /** * Flag that indicates if the user was authenticated with the server when the connection * to the server was closed (abruptly or not). @@ -590,6 +593,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { } protected void afterSuccessfulLogin(final boolean resumed) throws NotConnectedException, InterruptedException { + if (!resumed) { + authenticatedConnectionInitiallyEstablishedTimestamp = System.currentTimeMillis(); + } // Indicate that we're now authenticated. this.authenticated = true; @@ -1729,6 +1735,18 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { return lastStanzaReceived; } + /** + * Get the timestamp when the connection was the first time authenticated, i.e., when the first successful login was + * performed. Note that this value is not reset on disconnect, so it represents the timestamp from the last + * authenticated connection. The value is also not reset on stream resumption. + * + * @return the timestamp or {@code null}. + * @since 4.3.3 + */ + public final long getAuthenticatedConnectionInitiallyEstablishedTimestamp() { + return authenticatedConnectionInitiallyEstablishedTimestamp; + } + /** * Install a parsing exception callback, which will be invoked once an exception is encountered while parsing a * stanza. 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 713bf77bd..9f2c2d048 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 @@ -527,6 +527,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { // Reset the stream management session id to null, since if the stream is cleanly closed, i.e. sending a closing // stream tag, there is no longer a stream to resume. smSessionId = null; + // Note that we deliberately do not reset authenticatedConnectionInitiallyEstablishedTimestamp here, so that the + // information is available in the connectionClosedOnError() listeners. } authenticated = false; connected = false; From e5bbd19ef11e4111d8927f44be5061e765975962 Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Wed, 28 Nov 2018 17:55:46 +0100 Subject: [PATCH 54/72] StanzaDroppedListener for XEP-0198 resumption failures If a stream resume fails, smack will re-send all queued stanzas after a reconnect. However, it does not make sense to re-send them: * IQs / IQ responses have probably timed out * MUC messages and PMs will be rejected as you haven't rejoined yet * regular messages should be amended with a element This patch adds a StanzaDroppedListener interface to the XMPPTCPConnection. If at least one StanzaDroppedListener is provided, all queued messages will be drained into the StanzaDroppedListener(s). Otherwise, the original behavior of attempting to transmit them will be followed. Discussion: https://discourse.igniterealtime.org/t/xep-0198-resume-failure-reconnect-resending-of-muc-messages/83510/3 Signed-off-by: Georg Lukas --- .../smack/tcp/XMPPTCPConnection.java | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 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 9f2c2d048..61de855d6 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 @@ -283,6 +283,15 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { */ private final Collection stanzaAcknowledgedListeners = new ConcurrentLinkedQueue<>(); + /** + * These listeners are invoked for every stanza that got dropped. + *

+ * We use a {@link ConcurrentLinkedQueue} here in order to allow the listeners to remove + * themselves after they have been invoked. + *

+ */ + private final Collection stanzaDroppedListeners = new ConcurrentLinkedQueue<>(); + /** * This listeners are invoked for a acknowledged stanza that has the given stanza ID. They will * only be invoked once and automatically removed after that. @@ -447,9 +456,24 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } } } - // (Re-)send the stanzas *after* we tried to enable SM - for (Stanza stanza : previouslyUnackedStanzas) { - sendStanzaInternal(stanza); + // Inform client about failed resumption if possible, resend stanzas otherwise + // Process the stanzas synchronously so a client can re-queue them for transmission + // before it is informed about connection success + if (!stanzaDroppedListeners.isEmpty()) { + for (Stanza stanza : previouslyUnackedStanzas) { + for (StanzaListener listener : stanzaDroppedListeners) { + try { + listener.processStanza(stanza); + } + catch (InterruptedException | NotConnectedException | NotLoggedInException e) { + LOGGER.log(Level.FINER, "StanzaDroppedListener received exception", e); + } + } + } + } else { + for (Stanza stanza : previouslyUnackedStanzas) { + sendStanzaInternal(stanza); + } } afterSuccessfulLogin(false); @@ -1787,6 +1811,32 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { stanzaAcknowledgedListeners.clear(); } + /** + * Add a Stanza dropped listener. + *

+ * Those listeners will be invoked every time a Stanza has been dropped due to a failed SM resume. They will not get + * automatically removed. If at least one StanzaDroppedListener is configured, no attempt will be made to retransmit + * the Stanzas. + *

+ * + * @param listener the listener to add. + * @since 4.3.3 + */ + public void addStanzaDroppedListener(StanzaListener listener) { + stanzaDroppedListeners.add(listener); + } + + /** + * Remove the given Stanza dropped listener. + * + * @param listener the listener. + * @return true if the listener was removed. + * @since 4.3.3 + */ + public boolean removeStanzaDroppedListener(StanzaListener listener) { + return stanzaDroppedListeners.remove(listener); + } + /** * Add a new Stanza ID acknowledged listener for the given ID. *

From 0de0873abb3b34618bb9b771800c505609a2113f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 14 Mar 2019 14:29:23 +0100 Subject: [PATCH 55/72] version.gradle: Add link to SMACK-858 --- version.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/version.gradle b/version.gradle index a478e9a52..4634e860a 100644 --- a/version.gradle +++ b/version.gradle @@ -5,7 +5,9 @@ allprojects { // When using dynamic versions for those, do *not* use [1.0, // 2.0), since this will also pull in 2.0-alpha1. Instead use // [1.0, 1.0.99]. - // See also https://issues.apache.org/jira/browse/MNG-6232 + // See also: + // - https://issues.apache.org/jira/browse/MNG-6232 + // - https://issues.igniterealtime.org/browse/SMACK-858 jxmppVersion = '[0.6, 0.6.999]' miniDnsVersion = '[0.3, 0.3.999]' smackMinAndroidSdk = 9 From b054c4fe77435cc9cdbdd2722e9bb923815acdc7 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 14 Mar 2019 14:31:09 +0100 Subject: [PATCH 56/72] Smack 4.3.3 --- resources/releasedocs/changelog.html | 18 ++++++++++++++++++ version.gradle | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/resources/releasedocs/changelog.html b/resources/releasedocs/changelog.html index 5d249c249..706a4e2c6 100644 --- a/resources/releasedocs/changelog.html +++ b/resources/releasedocs/changelog.html @@ -141,6 +141,24 @@ hr {

+

4.3.3 -- 2019-03-14

+ +

Bug +

+
    +
  • [SMACK-856] - Smack fails under JDK 11 because com.sun.jndi.dns.DnsContextFactory is not inaccessible +
  • +
+ +

Improvement +

+
    +
  • [SMACK-858] - Dependency version specifier of jxmpp and MiniDNS include alpha/beta/... versions of the follow up version when Maven is used +
  • +
  • [SMACK-859] - MultiUserChat enter() should reset the timeout of the collector waiting for the final self presence to prevent timeouts for large MUCs +
  • +
+

4.3.2 -- 2019-02-22

Bug diff --git a/version.gradle b/version.gradle index 4634e860a..85012ef33 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { shortVersion = '4.3.3' - isSnapshot = true + isSnapshot = false // When using dynamic versions for those, do *not* use [1.0, // 2.0), since this will also pull in 2.0-alpha1. Instead use // [1.0, 1.0.99]. From 29af92cbd1d691e76f5137fe2e4d7cfcf4545577 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 15 Mar 2019 09:43:09 +0100 Subject: [PATCH 57/72] Smack 4.3.4-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 85012ef33..82e39bdf3 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { - shortVersion = '4.3.3' - isSnapshot = false + shortVersion = '4.3.4' + isSnapshot = true // When using dynamic versions for those, do *not* use [1.0, // 2.0), since this will also pull in 2.0-alpha1. Instead use // [1.0, 1.0.99]. From 3ded023629e1d90365d95e2857230a8086d4e67a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 16 Mar 2019 10:27:18 +0100 Subject: [PATCH 58/72] Remove 'synchronized' from notifyConnectionError() as it is not neccessary and causes stalls and deadlocks with a concurrent connect()/login() (which could be resolved interrupting the connect()/login() calling thread): "Smack Reader (0)" daemon prio=5 tid=21 Blocked | group="main" sCount=1 dsCount=0 obj=0x12c84670 self=0x7e072ca200 | sysTid=14965 nice=0 cgrp=default sched=0/0 handle=0x7e06155450 | state=S schedstat=( 63430626 3034269 21 ) utm=5 stm=0 core=2 HZ=100 | stack=0x7e06053000-0x7e06055000 stackSize=1037KB | held mutexes= at org.jivesoftware.smack.tcp.XMPPTCPConnection.notifyConnectionError(XMPPTCPConnection.java:-1) - waiting to lock <0x0ec6e6bb> (a org.jivesoftware.smack.tcp.XMPPTCPConnection) held by thread 22 at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$3900(XMPPTCPConnection.java:154) at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1330) at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$900(XMPPTCPConnection.java:1064) at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:1081) at java.lang.Thread.run(Thread.java:761) "connect" prio=5 tid=22 Waiting | group="main" sCount=1 dsCount=0 obj=0x12c8e820 self=0x7e19bcd600 | sysTid=15047 nice=0 cgrp=default sched=0/0 handle=0x7e05ee4450 | state=S schedstat=( 14067083 7475835 14 ) utm=1 stm=0 core=0 HZ=100 | stack=0x7e05de2000-0x7e05de4000 stackSize=1037KB | held mutexes= at java.lang.Object.wait!(Native method) - waiting on <0x0c058b14> (a java.lang.Object) at java.lang.Thread.parkFor$(Thread.java:2127) - locked <0x0c058b14> (a java.lang.Object) at sun.misc.Unsafe.park(Unsafe.java:325) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:161) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:840) at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:994) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1303) at java.util.concurrent.Semaphore.acquire(Semaphore.java:446) at org.jivesoftware.smack.tcp.XMPPTCPConnection.initConnection(XMPPTCPConnection.java:685) at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:942) at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.java:417) - locked <0x0ec6e6bb> (a org.jivesoftware.smack.tcp.XMPPTCPConnection) at org.yaxim.androidclient.service.SmackableImp.connectAndLogin(SmackableImp.java:717) - locked <0x0ec6e6bb> (a org.jivesoftware.smack.tcp.XMPPTCPConnection) at org.yaxim.androidclient.service.SmackableImp.doConnect(SmackableImp.java:304) at org.yaxim.androidclient.service.SmackableImp$5.run(SmackableImp.java:391) --- .../main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 61de855d6..b0fcb8b7d 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 @@ -953,7 +953,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { * * @param e the exception that causes the connection close event. */ - private synchronized void notifyConnectionError(final Exception e) { + private void notifyConnectionError(final Exception e) { ASYNC_BUT_ORDERED.performAsyncButOrdered(this, new Runnable() { @Override public void run() { From 7059b60672628d1427776a794d396fb09b2ed42b Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 16 Mar 2019 11:11:58 +0100 Subject: [PATCH 59/72] Wait for reader/writer thread termination at the end of shutdown() This synchronizes the place with what the master branch currently does. --- .../org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 b0fcb8b7d..bf4409506 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 @@ -561,6 +561,10 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { writer = null; initState(); + + // Wait for reader and writer threads to be terminated. + readerWriterSemaphore.acquireUninterruptibly(2); + readerWriterSemaphore.release(2); } @Override @@ -978,10 +982,6 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { // Note that a connection listener of XMPPTCPConnection will drop the SM state in // case the Exception is a StreamErrorException. instantShutdown(); - - // Wait for reader and writer threads to be terminated. - readerWriterSemaphore.acquireUninterruptibly(2); - readerWriterSemaphore.release(2); } Async.go(new Runnable() { From c83d717a26544eb9c355a0ca932a3cca2867c88f Mon Sep 17 00:00:00 2001 From: Mohsen Hariri Date: Wed, 27 Jun 2018 11:18:50 +0200 Subject: [PATCH 60/72] Allow adding custom HTTP headers to bosh communications --- smack-bosh/build.gradle | 2 +- .../jivesoftware/smack/bosh/BOSHConfiguration.java | 14 ++++++++++++++ .../smack/bosh/XMPPBOSHConnection.java | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/smack-bosh/build.gradle b/smack-bosh/build.gradle index a3416325e..6a0e1c679 100644 --- a/smack-bosh/build.gradle +++ b/smack-bosh/build.gradle @@ -4,5 +4,5 @@ This API is considered beta quality.""" dependencies { compile project(':smack-core') - compile 'org.igniterealtime.jbosh:jbosh:[0.9,0.10)' + compile 'org.igniterealtime.jbosh:jbosh:[0.9.1,0.10)' } diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java index a83819ad2..8cf01fe85 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java @@ -19,6 +19,8 @@ package org.jivesoftware.smack.bosh; import java.net.URI; import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; import org.jivesoftware.smack.ConnectionConfiguration; import org.jivesoftware.smack.proxy.ProxyInfo; @@ -34,6 +36,7 @@ public final class BOSHConfiguration extends ConnectionConfiguration { private final boolean https; private final String file; + private Map httpHeaders; private BOSHConfiguration(Builder builder) { super(builder); @@ -49,6 +52,7 @@ public final class BOSHConfiguration extends ConnectionConfiguration { } else { file = builder.file; } + httpHeaders = builder.httpHeaders; } public boolean isProxyEnabled() { @@ -76,6 +80,10 @@ public final class BOSHConfiguration extends ConnectionConfiguration { return new URI((https ? "https://" : "http://") + this.host + ":" + this.port + file); } + public Map getHttpHeaders() { + return httpHeaders; + } + public static Builder builder() { return new Builder(); } @@ -83,6 +91,7 @@ public final class BOSHConfiguration extends ConnectionConfiguration { public static final class Builder extends ConnectionConfiguration.Builder { private boolean https; private String file; + private Map httpHeaders = new HashMap<>(); private Builder() { } @@ -101,6 +110,11 @@ public final class BOSHConfiguration extends ConnectionConfiguration { return this; } + public Builder addHttpHeader(String name, String value) { + httpHeaders.put(name, value); + return this; + } + @Override public BOSHConfiguration build() { return new BOSHConfiguration(this); diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index 68dd48fcb..3c8995b14 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -22,6 +22,7 @@ import java.io.PipedReader; import java.io.PipedWriter; import java.io.StringReader; import java.io.Writer; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -156,6 +157,9 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { if (config.isProxyEnabled()) { cfgBuilder.setProxy(config.getProxyAddress(), config.getProxyPort()); } + for (Map.Entry h : config.getHttpHeaders().entrySet()) { + cfgBuilder.addHttpHeader(h.getKey(), h.getValue()); + } client = BOSHClient.create(cfgBuilder.build()); client.addBOSHClientConnListener(new BOSHConnectionListener()); From 653d9dbba75826968f4f5bf648760edefa43e51f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 22 Mar 2019 21:53:53 +0100 Subject: [PATCH 61/72] smack-bosh: Limit jbosh to the 0.9 series akin to version.gradle --- smack-bosh/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/smack-bosh/build.gradle b/smack-bosh/build.gradle index 6a0e1c679..f686c8209 100644 --- a/smack-bosh/build.gradle +++ b/smack-bosh/build.gradle @@ -4,5 +4,7 @@ This API is considered beta quality.""" dependencies { compile project(':smack-core') - compile 'org.igniterealtime.jbosh:jbosh:[0.9.1,0.10)' + // See https://issues.igniterealtime.org/browse/SMACK-858 and + // comment in version.gradle why the specify the version this way. + compile 'org.igniterealtime.jbosh:jbosh:[0.9.1,0.9.999]' } From 3450ffad2b8ea4ae1015c81146f6efe23515852a Mon Sep 17 00:00:00 2001 From: Oliver Mihatsch Date: Mon, 18 Mar 2019 10:34:49 +0100 Subject: [PATCH 62/72] Do not use "CONNECT" in the Host header field. --- .../org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java index cd1000c15..6326cf1db 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java @@ -58,7 +58,7 @@ class HTTPProxySocketConnection implements ProxySocketConnection { proxyLine = "\r\nProxy-Authorization: Basic " + Base64.encode(username + ":" + password); } socket.getOutputStream().write((hostport + " HTTP/1.1\r\nHost: " - + hostport + proxyLine + "\r\n\r\n").getBytes("UTF-8")); + + host + ":" + port + proxyLine + "\r\n\r\n").getBytes("UTF-8")); InputStream in = socket.getInputStream(); StringBuilder got = new StringBuilder(100); From 8e88cd2e31a744bf9c5d8e599d38796b927c0413 Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Tue, 12 Mar 2019 11:33:38 +0100 Subject: [PATCH 63/72] Proxy mode: add failed address on error --- .../main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java | 1 + 1 file changed, 1 insertion(+) 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 bf4409506..97e0e2044 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 @@ -647,6 +647,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { proxyInfo.getProxySocketConnection().connect(socket, host, port, timeout); } catch (IOException e) { hostAddress.setException(e); + failedAddresses.add(hostAddress); continue; } LOGGER.finer("Established TCP connection to " + hostAndPort); From 007a04c4fe599bbea04fdd4bc6cf03e45ae8db36 Mon Sep 17 00:00:00 2001 From: Oliver Mihatsch Date: Mon, 18 Mar 2019 10:28:50 +0100 Subject: [PATCH 64/72] Better error messages when using a Proxy to connect to the XMPP server. --- .../jivesoftware/smack/proxy/HTTPProxySocketConnection.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java index 6326cf1db..549406423 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java @@ -115,7 +115,8 @@ class HTTPProxySocketConnection implements ProxySocketConnection { int code = Integer.parseInt(m.group(1)); if (code != HttpURLConnection.HTTP_OK) { - throw new ProxyException(ProxyInfo.ProxyType.HTTP); + throw new ProxyException(ProxyInfo.ProxyType.HTTP, + "Error code in proxy response: " + code); } } From 5d46e281fcbd60f34bd96ccbe36faa8072d39354 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 25 Mar 2019 13:06:12 +0100 Subject: [PATCH 65/72] XMPPTCPConnection log when reader/writer threads start and exit --- .../jivesoftware/smack/tcp/XMPPTCPConnection.java | 12 ++++++++++-- 1 file changed, 10 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 97e0e2044..2441845c6 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 @@ -1063,6 +1063,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { protected class PacketReader { + private final String threadName = "Smack Reader (" + getConnectionCounter() + ')'; + XmlPullParser parser; private volatile boolean done; @@ -1077,13 +1079,15 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { Async.go(new Runnable() { @Override public void run() { + LOGGER.finer(threadName + " start"); try { parsePackets(); } finally { + LOGGER.finer(threadName + " exit"); XMPPTCPConnection.this.readerWriterSemaphore.release(); } } - }, "Smack Reader (" + getConnectionCounter() + ")"); + }, threadName); } /** @@ -1336,6 +1340,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { protected class PacketWriter { public static final int QUEUE_SIZE = XMPPTCPConnection.QUEUE_SIZE; + private final String threadName = "Smack Writer (" + getConnectionCounter() + ')'; + private final ArrayBlockingQueueWithShutdown queue = new ArrayBlockingQueueWithShutdown<>( QUEUE_SIZE, true); @@ -1381,13 +1387,15 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { Async.go(new Runnable() { @Override public void run() { + LOGGER.finer(threadName + " start"); try { writePackets(); } finally { + LOGGER.finer(threadName + " exit"); XMPPTCPConnection.this.readerWriterSemaphore.release(); } } - }, "Smack Writer (" + getConnectionCounter() + ")"); + }, threadName); } private boolean done() { From 25b3f354216683e568a54b93be1c6a931cd79b26 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 28 Mar 2019 13:52:17 +0100 Subject: [PATCH 66/72] Ensure that shutdown() terminates reader/writer threads In case an exception happens in connect()/login() the 'disconnectedButResumable' boolean may (still) be set. Which causes only one of the reader and writer threads to exit, typically the reader thread, because shutdown() will bail out very early. This leaves a dangling (writer) thread causing memory leaks and deadlocks on a subsequent connect()/login(). --- .../smack/tcp/XMPPTCPConnection.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 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 2441845c6..a08221ddb 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 @@ -508,10 +508,6 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } private void shutdown(boolean instant) { - if (disconnectedButResumeable) { - return; - } - // First shutdown the writer, this will result in a closing stream element getting send to // the server LOGGER.finer("PacketWriter shutdown()"); @@ -534,13 +530,25 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { packetReader.shutdown(); LOGGER.finer("PacketReader has been shut down"); - try { + final Socket socket = this.socket; + if (socket != null && socket.isConnected()) { + try { socket.close(); - } catch (Exception e) { + } catch (Exception e) { LOGGER.log(Level.WARNING, "shutdown", e); + } } setWasAuthenticated(); + + // Wait for reader and writer threads to be terminated. + readerWriterSemaphore.acquireUninterruptibly(2); + readerWriterSemaphore.release(2); + + if (disconnectedButResumeable) { + return; + } + // If we are able to resume the stream, then don't set // connected/authenticated/usingTLS to false since we like behave like we are still // connected (e.g. sendStanza should not throw a NotConnectedException). @@ -561,10 +569,6 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { writer = null; initState(); - - // Wait for reader and writer threads to be terminated. - readerWriterSemaphore.acquireUninterruptibly(2); - readerWriterSemaphore.release(2); } @Override From 9be498c440e2b10cae4d01b4d0037bfdb90c85cf Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 1 Apr 2019 22:02:36 +0200 Subject: [PATCH 67/72] Fix NPE in Roster's presence listeners if 'from' is not set The NPE is caused by an inbound presence stanza without the 'from' attribute set. The stacktrace of the NPE is: FATAL EXCEPTION: Smack Cached Executor Process: de.fhg.ivi.senetz.mobile.android.mbk.debug, PID: 13365 java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:944) at org.jivesoftware.smack.roster.Roster.getPresencesInternal(Roster.java:374) at org.jivesoftware.smack.roster.Roster.getOrCreatePresencesInternal(Roster.java:388) at org.jivesoftware.smack.roster.Roster.access$1100(Roster.java:94) at org.jivesoftware.smack.roster.Roster$PresencePacketListener$1.run(Roster.java:1519) at org.jivesoftware.smack.AsyncButOrdered$Handler.run(AsyncButOrdered.java:121) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) at java.lang.Thread.run(Thread.java:764) Thanks to Marcel Heckel for reporting this. Fixes SMACK-861. --- .../org/jivesoftware/smack/roster/Roster.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index 8e241151d..73486cd12 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -1471,7 +1471,29 @@ public final class Roster extends Manager { final Presence presence = (Presence) packet; final Jid from = presence.getFrom(); - final BareJid key = from != null ? from.asBareJid() : null; + final BareJid key; + if (from != null) { + key = from.asBareJid(); + } else { + XMPPConnection connection = connection(); + if (connection == null) { + LOGGER.finest("Connection was null while trying to handle exotic presence stanza: " + presence); + return; + } + // Assume the presence come "from the users account on the server" since no from was set (RFC 6120 § + // 8.1.2.1 4.). Note that getUser() may return null, but should never return null in this case as where + // connected. + EntityFullJid myJid = connection.getUser(); + if (myJid == null) { + LOGGER.info( + "Connection had no local address in Roster's presence listener." + + " Possibly we received a presence without from before being authenticated." + + " Presence: " + presence); + return; + } + LOGGER.info("Exotic presence stanza without from received: " + presence); + key = myJid.asBareJid(); + } asyncButOrdered.performAsyncButOrdered(key, new Runnable() { @Override From 9ad162af6ee656d933c4766a7bf8ec34f83dc6d8 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 9 Apr 2019 12:14:12 +0200 Subject: [PATCH 68/72] Use correct field in ServiceDiscoveryManager.getIdentities() Fixes SMACK-863. --- .../jivesoftware/smackx/disco/ServiceDiscoveryManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java index eabc7773f..e2413b100 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software, 2018 Florian Schmaus. + * Copyright 2003-2007 Jive Software, 2018-2019 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -271,8 +271,8 @@ public final class ServiceDiscoveryManager extends Manager { */ public Set getIdentities() { Set res = new HashSet<>(identities); - // Add the default identity that must exist - res.add(defaultIdentity); + // Add the main identity that must exist + res.add(identity); return Collections.unmodifiableSet(res); } From 0ec7e84cbc80576013bb2cd0b48ea6e4f8880d33 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 9 Apr 2019 14:26:15 +0200 Subject: [PATCH 69/72] Update link to XMPP Registry for Service Discovery Identities --- .../jivesoftware/smackx/disco/ServiceDiscoveryManager.java | 2 +- .../org/jivesoftware/smackx/disco/packet/DiscoverInfo.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java index e2413b100..06099413d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/ServiceDiscoveryManager.java @@ -227,7 +227,7 @@ public final class ServiceDiscoveryManager extends Manager { /** * Returns the type of client that will be returned when asked for the client identity in a * disco request. The valid types are defined by the category client. Follow this link to learn - * the possible types: Jabber::Registrar. + * the possible types: XMPP Registry for Service Discovery Identities * * @return the type of client that will be returned when asked for the client identity in a * disco request. diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java index 2abda87fb..40cc92909 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java @@ -263,7 +263,7 @@ public class DiscoverInfo extends IQ implements TypedCloneable { * Represents the identity of a given XMPP entity. An entity may have many identities but all * the identities SHOULD have the same name.

* - * Refer to Jabber::Registrar + * Refer to XMPP Registry for Service Discovery Identities * in order to get the official registry of values for the category and type * attributes. * @@ -327,7 +327,7 @@ public class DiscoverInfo extends IQ implements TypedCloneable { /** * Returns the entity's category. To get the official registry of values for the - * 'category' attribute refer to Jabber::Registrar + * 'category' attribute refer to XMPP Registry for Service Discovery Identities. * * @return the entity's category. */ @@ -346,7 +346,7 @@ public class DiscoverInfo extends IQ implements TypedCloneable { /** * Returns the entity's type. To get the official registry of values for the - * 'type' attribute refer to Jabber::Registrar + * 'type' attribute refer to XMPP Registry for Service Discovery Identities. * * @return the entity's type. */ From 6076a9dfa54fdce20b82b8e55337341e148bb39c Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 10 Apr 2019 12:18:06 +0200 Subject: [PATCH 70/72] Introduce asyncGoLimited() which limits the number of threads created for asynchronous operations. Fixes SMACK-864. --- .../smack/AbstractXMPPConnection.java | 85 ++++++++++++++++++- .../jivesoftware/smack/AsyncButOrdered.java | 16 +++- .../smack/SmackConfiguration.java | 15 ++++ 3 files changed, 113 insertions(+), 3 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index 38e188ef9..fe82c07f6 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -26,6 +26,7 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArraySet; @@ -299,6 +300,17 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { protected static final AsyncButOrdered ASYNC_BUT_ORDERED = new AsyncButOrdered<>(); + /** + * An executor which uses {@link #asyncGoLimited(Runnable)} to limit the number of asynchronously processed runnables + * per connection. + */ + private final Executor limitedExcutor = new Executor() { + @Override + public void execute(Runnable runnable) { + asyncGoLimited(runnable); + } + }; + /** * The used host to establish the connection to */ @@ -1166,7 +1178,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { executorService = ASYNC_BUT_ORDERED.asExecutorFor(this); break; case async: - executorService = CACHED_EXECUTOR_SERVICE; + executorService = limitedExcutor; break; } final IQRequestHandler finalIqRequestHandler = iqRequestHandler; @@ -1216,7 +1228,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { } for (final StanzaListener listener : listenersToNotify) { - asyncGo(new Runnable() { + asyncGoLimited(new Runnable() { @Override public void run() { try { @@ -1773,6 +1785,75 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { return getClass().getSimpleName() + '[' + localEndpointString + "] (" + getConnectionCounter() + ')'; } + /** + * A queue of deferred runnables that where not executed immediately because {@link #currentAsyncRunnables} reached + * {@link #maxAsyncRunnables}. Note that we use a {@code LinkedList} in order to avoid space blowups in case the + * list ever becomes very big and shrinks again. + */ + private final Queue deferredAsyncRunnables = new LinkedList<>(); + + private int deferredAsyncRunnablesCount; + + private int deferredAsyncRunnablesCountPrevious; + + private int maxAsyncRunnables = SmackConfiguration.getDefaultConcurrencyLevelLimit(); + + private int currentAsyncRunnables; + + protected void asyncGoLimited(final Runnable runnable) { + Runnable wrappedRunnable = new Runnable() { + @Override + public void run() { + runnable.run(); + + synchronized (deferredAsyncRunnables) { + Runnable defferredRunnable = deferredAsyncRunnables.poll(); + if (defferredRunnable == null) { + currentAsyncRunnables--; + } else { + deferredAsyncRunnablesCount--; + asyncGo(defferredRunnable); + } + } + } + }; + + synchronized (deferredAsyncRunnables) { + if (currentAsyncRunnables < maxAsyncRunnables) { + currentAsyncRunnables++; + asyncGo(wrappedRunnable); + } else { + deferredAsyncRunnablesCount++; + deferredAsyncRunnables.add(wrappedRunnable); + } + + final int HIGH_WATERMARK = 100; + final int INFORM_WATERMARK = 20; + + final int deferredAsyncRunnablesCount = this.deferredAsyncRunnablesCount; + + if (deferredAsyncRunnablesCount >= HIGH_WATERMARK + && deferredAsyncRunnablesCountPrevious < HIGH_WATERMARK) { + LOGGER.log(Level.WARNING, "High watermark of " + HIGH_WATERMARK + " simultaneous executing runnables reached"); + } else if (deferredAsyncRunnablesCount >= INFORM_WATERMARK + && deferredAsyncRunnablesCountPrevious < INFORM_WATERMARK) { + LOGGER.log(Level.INFO, INFORM_WATERMARK + " simultaneous executing runnables reached"); + } + + deferredAsyncRunnablesCountPrevious = deferredAsyncRunnablesCount; + } + } + + public void setMaxAsyncOperations(int maxAsyncOperations) { + if (maxAsyncOperations < 1) { + throw new IllegalArgumentException("Max async operations must be greater than 0"); + } + + synchronized (deferredAsyncRunnables) { + maxAsyncRunnables = maxAsyncOperations; + } + } + protected static void asyncGo(Runnable runnable) { CACHED_EXECUTOR_SERVICE.execute(runnable); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AsyncButOrdered.java b/smack-core/src/main/java/org/jivesoftware/smack/AsyncButOrdered.java index 00fb94549..6fb6244ab 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AsyncButOrdered.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AsyncButOrdered.java @@ -55,6 +55,16 @@ public class AsyncButOrdered { private final Map threadActiveMap = new WeakHashMap<>(); + private final Executor executor; + + public AsyncButOrdered() { + this(null); + } + + public AsyncButOrdered(Executor executor) { + this.executor = executor; + } + /** * Invoke the given {@link Runnable} asynchronous but ordered in respect to the given key. * @@ -86,7 +96,11 @@ public class AsyncButOrdered { if (newHandler) { Handler handler = new Handler(keyQueue, key); threadActiveMap.put(key, true); - AbstractXMPPConnection.asyncGo(handler); + if (executor == null) { + AbstractXMPPConnection.asyncGo(handler); + } else { + executor.execute(handler); + } } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java index 01f2995a4..10695df47 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java @@ -365,4 +365,19 @@ public final class SmackConfiguration { public static void setUnknownIqRequestReplyMode(UnknownIqRequestReplyMode unknownIqRequestReplyMode) { SmackConfiguration.unknownIqRequestReplyMode = Objects.requireNonNull(unknownIqRequestReplyMode, "Must set mode"); } + + private static final int defaultConcurrencyLevelLimit; + + static { + int availableProcessors = Runtime.getRuntime().availableProcessors(); + if (availableProcessors < 8) { + defaultConcurrencyLevelLimit = 8; + } else { + defaultConcurrencyLevelLimit = (int) (availableProcessors * 1.1); + } + } + + public static int getDefaultConcurrencyLevelLimit() { + return defaultConcurrencyLevelLimit; + } } From 488055948d2a67a2b576630d3e51dda107e620a3 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 14 Apr 2019 21:41:59 +0200 Subject: [PATCH 71/72] Add missing 'synchronized' keywords to Manager.getInstanceFor() Fixes SMACK-865. --- .../smackx/jingle_filetransfer/JingleFileTransferManager.java | 2 +- .../org/jivesoftware/smackx/reference/ReferenceManager.java | 2 +- .../jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java | 2 +- .../java/org/jivesoftware/smackx/spoiler/SpoilerManager.java | 2 +- .../smackx/jingle/JingleTransportMethodManager.java | 2 +- .../jingle/transports/jingle_ibb/JingleIBBTransportManager.java | 2 +- .../jingle/transports/jingle_s5b/JingleS5BTransportManager.java | 2 +- .../java/org/jivesoftware/smackx/jingleold/JingleSession.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java index 7b96cdbd4..a50ea0519 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java @@ -32,7 +32,7 @@ public final class JingleFileTransferManager extends Manager { super(connection); } - public static JingleFileTransferManager getInstanceFor(XMPPConnection connection) { + public static synchronized JingleFileTransferManager getInstanceFor(XMPPConnection connection) { JingleFileTransferManager manager = INSTANCES.get(connection); if (manager == null) { manager = new JingleFileTransferManager(connection); diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/reference/ReferenceManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/reference/ReferenceManager.java index d3bdfce12..b588aa5e3 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/reference/ReferenceManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/reference/ReferenceManager.java @@ -51,7 +51,7 @@ public final class ReferenceManager extends Manager { * @param connection xmpp connection * @return reference manager instance */ - public static ReferenceManager getInstanceFor(XMPPConnection connection) { + public static synchronized ReferenceManager getInstanceFor(XMPPConnection connection) { ReferenceManager manager = INSTANCES.get(connection); if (manager == null) { manager = new ReferenceManager(connection); diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java index 99ec03f5d..a9fd4fcfa 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/sid/StableUniqueStanzaIdManager.java @@ -78,7 +78,7 @@ public final class StableUniqueStanzaIdManager extends Manager { * @param connection xmpp-connection * @return manager instance for the connection */ - public static StableUniqueStanzaIdManager getInstanceFor(XMPPConnection connection) { + public static synchronized StableUniqueStanzaIdManager getInstanceFor(XMPPConnection connection) { StableUniqueStanzaIdManager manager = INSTANCES.get(connection); if (manager == null) { manager = new StableUniqueStanzaIdManager(connection); diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/SpoilerManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/SpoilerManager.java index f3bb80c85..fa5c8680b 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/SpoilerManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/spoiler/SpoilerManager.java @@ -61,7 +61,7 @@ public final class SpoilerManager extends Manager { * @param connection xmpp connection * @return SpoilerManager */ - public static SpoilerManager getInstanceFor(XMPPConnection connection) { + public static synchronized SpoilerManager getInstanceFor(XMPPConnection connection) { SpoilerManager manager = INSTANCES.get(connection); if (manager == null) { manager = new SpoilerManager(connection); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java index 848dc1671..9a9941a07 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java @@ -48,7 +48,7 @@ public final class JingleTransportMethodManager extends Manager { super(connection); } - public static JingleTransportMethodManager getInstanceFor(XMPPConnection connection) { + public static synchronized JingleTransportMethodManager getInstanceFor(XMPPConnection connection) { JingleTransportMethodManager manager = INSTANCES.get(connection); if (manager == null) { manager = new JingleTransportMethodManager(connection); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java index 500a7b0a8..63dada1ae 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_ibb/JingleIBBTransportManager.java @@ -38,7 +38,7 @@ public final class JingleIBBTransportManager extends JingleTransportManager Date: Mon, 15 Apr 2019 09:46:43 +0200 Subject: [PATCH 72/72] Add checkstyle rule for 'synchronized' on Manager.getInstanceFor() --- config/checkstyle.xml | 13 +++++++++++++ .../org/jivesoftware/smackx/mam/MamManager.java | 2 ++ 2 files changed, 15 insertions(+) diff --git a/config/checkstyle.xml b/config/checkstyle.xml index 041e31ffb..d925f4909 100644 --- a/config/checkstyle.xml +++ b/config/checkstyle.xml @@ -6,6 +6,11 @@ + + + + + @@ -61,6 +66,14 @@ + + + + + diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java index ba3af51aa..2c72c8229 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java @@ -178,7 +178,9 @@ public final class MamManager extends Manager { * @param connection the XMPP connection to get the archive for. * @return the instance of MamManager. */ + // CHECKSTYLE:OFF:RegexpSingleline public static MamManager getInstanceFor(XMPPConnection connection) { + // CHECKSTYLE:ON:RegexpSingleline return getInstanceFor(connection, (Jid) null); }