mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-21 22:02:06 +01:00
Smack 4.3.3
-----BEGIN PGP SIGNATURE----- iQGTBAABCgB9FiEEl3UFnzoh3OFr5PuuIjmn6PWFIFIFAlyKV9tfFIAAAAAALgAo aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDk3 NzUwNTlGM0EyMURDRTE2QkU0RkJBRTIyMzlBN0U4RjU4NTIwNTIACgkQIjmn6PWF IFL4vQf/Qfg3VzNEnmk0+KjOtuvfAbhMfzE92gfo15vE0PPEIe9VA0Pzkvqhva4k Efw7BhD2zx8hWvo0d5FfkdII89hSYnOCiSmhiX1Ln9q/gUqFW0TDAKpsMfAl7jAK Fap8M7uUStP9T6fF/gq01djYCYoWA/4v1lGKv4J4b9gWCqzGIF2sK0M7of7VERnr pEXJSUM228rk6EYjVmX/9Ujo1Y+xaNMFFZZSbKYrirAqjP540v0OPBCRQyB8qFaI NTcNJ+qESe6Q80mw5V+y/kD6kX0LERSDB+pigzOOOlmfMtD1uADR84tAynuTKNAU 7/5K/YSQxceRY6RTgD17Al5lHIH5nw== =ToR+ -----END PGP SIGNATURE----- Merge tag '4.3.3' Smack 4.3.3
This commit is contained in:
commit
daab6039a1
15 changed files with 250 additions and 63 deletions
|
@ -141,6 +141,24 @@ hr {
|
|||
|
||||
<div id="pageBody">
|
||||
|
||||
<h2>4.3.3 -- <span style="font-weight: normal;">2019-03-14</span></h2>
|
||||
|
||||
<h2> Bug
|
||||
</h2>
|
||||
<ul>
|
||||
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-856'>SMACK-856</a>] - Smack fails under JDK 11 because com.sun.jndi.dns.DnsContextFactory is not inaccessible
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2> Improvement
|
||||
</h2>
|
||||
<ul>
|
||||
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-858'>SMACK-858</a>] - Dependency version specifier of jxmpp and MiniDNS include alpha/beta/... versions of the follow up version when Maven is used
|
||||
</li>
|
||||
<li>[<a href='https://issues.igniterealtime.org/browse/SMACK-859'>SMACK-859</a>] - MultiUserChat enter() should reset the timeout of the collector waiting for the final self presence to prevent timeouts for large MUCs
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>4.3.2 -- <span style="font-weight: normal;">2019-02-22</span></h2>
|
||||
|
||||
<h2> Bug
|
||||
|
|
|
@ -266,6 +266,11 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
|||
client = null;
|
||||
}
|
||||
|
||||
instantShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void instantShutdown() {
|
||||
setWasAuthenticated();
|
||||
sessionID = null;
|
||||
done = true;
|
||||
|
|
|
@ -111,6 +111,7 @@ import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
|||
import org.jivesoftware.smack.provider.NonzaProvider;
|
||||
import org.jivesoftware.smack.provider.ProviderManager;
|
||||
import org.jivesoftware.smack.sasl.core.SASLAnonymous;
|
||||
import org.jivesoftware.smack.util.Async;
|
||||
import org.jivesoftware.smack.util.DNSUtil;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||
|
@ -357,6 +358,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).
|
||||
|
@ -449,6 +453,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.
|
||||
|
@ -467,12 +477,11 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
throwAlreadyConnectedExceptionIfAppropriate();
|
||||
|
||||
// Reset the connection state
|
||||
initState();
|
||||
saslAuthentication.init();
|
||||
saslFeatureReceived.init();
|
||||
lastFeaturesReceived.init();
|
||||
tlsHandled.init();
|
||||
streamId = null;
|
||||
|
||||
try {
|
||||
// Perform the actual connection to the XMPP service
|
||||
connectInternal();
|
||||
|
||||
|
@ -480,9 +489,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
// 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();
|
||||
}
|
||||
} catch (SmackException | IOException | XMPPException | InterruptedException e) {
|
||||
instantShutdown();
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Make note of the fact that we're now connected.
|
||||
connected = true;
|
||||
|
@ -652,6 +664,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;
|
||||
|
||||
|
@ -834,15 +849,18 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
*
|
||||
* @param exception the exception that causes the connection close event.
|
||||
*/
|
||||
protected final synchronized void notifyConnectionError(Exception exception) {
|
||||
protected final void notifyConnectionError(final Exception exception) {
|
||||
if (!isConnected()) {
|
||||
LOGGER.log(Level.INFO, "Connection was already disconnected when attempting to handle " + exception,
|
||||
exception);
|
||||
return;
|
||||
}
|
||||
|
||||
ASYNC_BUT_ORDERED.performAsyncButOrdered(this, () -> {
|
||||
currentConnectionException = exception;
|
||||
synchronized (AbstractXMPPConnection.this) {
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
for (StanzaCollector collector : collectors) {
|
||||
collector.notifyConnectionError(exception);
|
||||
|
@ -851,19 +869,26 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
|
|||
tlsHandled.reportGenericFailure(smackWrappedException);
|
||||
saslFeatureReceived.reportGenericFailure(smackWrappedException);
|
||||
lastFeaturesReceived.reportGenericFailure(smackWrappedException);
|
||||
// TODO From XMPPTCPConnection. Was called in Smack 4.3 where notifyConnectionError() was part of
|
||||
// XMPPTCPConnection. Create delegation method?
|
||||
// maybeCompressFeaturesReceived.reportGenericFailure(smackWrappedException);
|
||||
|
||||
// Closes the connection temporary. A if the connection supports stream management, then a reconnection is
|
||||
// possible. Note that a connection listener of e.g. XMPPTCPConnection will drop the SM state in
|
||||
// case the Exception is a StreamErrorException.
|
||||
instantShutdown();
|
||||
|
||||
Async.go(() -> {
|
||||
// Notify connection listeners of the error.
|
||||
callConnectionClosedOnErrorListener(exception);
|
||||
}, AbstractXMPPConnection.this + " callConnectionClosedOnErrorListener()");
|
||||
});
|
||||
}
|
||||
|
||||
protected void instantShutdown() {
|
||||
// Default implementation simply calls shutdown(), subclasses may override this.
|
||||
shutdown();
|
||||
}
|
||||
/**
|
||||
* Performs an unclean disconnect and shutdown of the connection. Does not send a closing stream stanza.
|
||||
*/
|
||||
public abstract void instantShutdown();
|
||||
|
||||
/**
|
||||
* Shuts the current connection down.
|
||||
|
@ -1811,6 +1836,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.
|
||||
|
|
|
@ -93,17 +93,24 @@ public abstract class SmackException extends Exception {
|
|||
return new NoResponseException(sb.toString());
|
||||
}
|
||||
|
||||
public static NoResponseException newWith(XMPPConnection connection,
|
||||
@Deprecated
|
||||
// TODO: Remove in Smack 4.4.
|
||||
public static NoResponseException newWith(long timeout,
|
||||
StanzaCollector collector) {
|
||||
return newWith(timeout, collector.getStanzaFilter(), false);
|
||||
}
|
||||
|
||||
public static NoResponseException newWith(long timeout,
|
||||
StanzaCollector collector, boolean stanzaCollectorCancelled) {
|
||||
return newWith(connection, collector.getStanzaFilter(), stanzaCollectorCancelled);
|
||||
return newWith(timeout, collector.getStanzaFilter(), stanzaCollectorCancelled);
|
||||
}
|
||||
|
||||
public static NoResponseException newWith(XMPPConnection connection, StanzaFilter filter) {
|
||||
return newWith(connection, filter, false);
|
||||
return newWith(connection.getReplyTimeout(), filter, false);
|
||||
}
|
||||
|
||||
public static NoResponseException newWith(XMPPConnection connection, StanzaFilter filter, boolean stanzaCollectorCancelled) {
|
||||
final StringBuilder sb = getWaitingFor(connection);
|
||||
public static NoResponseException newWith(long timeout, StanzaFilter filter, boolean stanzaCollectorCancelled) {
|
||||
final StringBuilder sb = getWaitingFor(timeout);
|
||||
if (stanzaCollectorCancelled) {
|
||||
sb.append(" StanzaCollector has been cancelled.");
|
||||
}
|
||||
|
@ -119,7 +126,10 @@ public abstract 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 (~"
|
||||
|
|
|
@ -290,7 +290,7 @@ public class StanzaCollector implements AutoCloseable {
|
|||
if (!connection.isConnected()) {
|
||||
throw new NotConnectedException(connection, packetFilter);
|
||||
}
|
||||
throw NoResponseException.newWith(connection, this, cancelled);
|
||||
throw NoResponseException.newWith(timeout, this, cancelled);
|
||||
}
|
||||
|
||||
XMPPErrorException.ifHasErrorThenThrow(result);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,13 +45,12 @@ 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() {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -95,7 +93,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,7 +101,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,11 @@ import org.xmlpull.v1.XmlPullParser;
|
|||
|
||||
public class OriginIdProvider extends ExtensionElementProvider<OriginIdElement> {
|
||||
|
||||
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, XmlEnvironment xmlEnvironment) {
|
||||
|
|
|
@ -24,7 +24,11 @@ import org.xmlpull.v1.XmlPullParser;
|
|||
|
||||
public class StanzaIdProvider extends ExtensionElementProvider<StanzaIdElement> {
|
||||
|
||||
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, XmlEnvironment xmlEnvironment) {
|
||||
|
|
|
@ -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;
|
||||
|
@ -42,7 +43,7 @@ public class StableUniqueStanzaIdTest extends SmackTestSuite {
|
|||
assertEquals("alice@wonderland.lit", element.getBy());
|
||||
assertXMLEqual(xml, element.toXML().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());
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ public class StableUniqueStanzaIdTest extends SmackTestSuite {
|
|||
assertEquals("de305d54-75b4-431b-adb2-eb6b9e546013", element.getId());
|
||||
assertXMLEqual(xml, element.toXML().toString());
|
||||
|
||||
OriginIdElement parsed = OriginIdProvider.TEST_INSTANCE.parse(TestUtils.getParser(xml));
|
||||
OriginIdElement parsed = OriginIdProvider.INSTANCE.parse(TestUtils.getParser(xml));
|
||||
assertEquals(element.getId(), parsed.getId());
|
||||
}
|
||||
|
||||
|
@ -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 = "<message xmlns='jabber:client' from='e4aec989-3e20-4846-83bf-f50df89b5d07@muclight.example.com/user1@example.com' to='user1@example.com' id='6b71fe3a-3cb2-489c-9c8e-b6879761d15e' type='groupchat'>" +
|
||||
"<body>Test message</body>" +
|
||||
"<markable xmlns='urn:xmpp:chat-markers:0'/>" +
|
||||
"<stanza-id by='e4aec989-3e20-4846-83bf-f50df89b5d07@muclight.example.com' id='B0KK24ETVC81' xmlns='urn:xmpp:sid:0'/>" +
|
||||
"<stanza-id by='user1@example.com' id='B0KK24EV89G1' xmlns='urn:xmpp:sid:0'/>" +
|
||||
"</message>";
|
||||
Message messageStanza = PacketParserUtils.parseStanza(message);
|
||||
|
||||
assertTrue(StanzaIdElement.hasStanzaId(messageStanza));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -341,9 +341,10 @@ public class MultiUserChat {
|
|||
|
||||
// Setup the messageListeners and presenceListeners *before* the join presence is send.
|
||||
connection.addSyncStanzaListener(messageListener, fromRoomGroupchatFilter);
|
||||
connection.addSyncStanzaListener(presenceListener, new AndFilter(fromRoomFilter,
|
||||
StanzaFilter presenceFromRoomFilter = new AndFilter(fromRoomFilter,
|
||||
StanzaTypeFilter.PRESENCE,
|
||||
PossibleFromTypeFilter.ENTITY_FULL_JID));
|
||||
PossibleFromTypeFilter.ENTITY_FULL_JID);
|
||||
connection.addSyncStanzaListener(presenceListener, presenceFromRoomFilter);
|
||||
// @formatter:off
|
||||
connection.addSyncStanzaListener(subjectListener,
|
||||
new AndFilter(fromRoomFilter,
|
||||
|
@ -372,15 +373,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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -40,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
|
||||
*
|
||||
|
@ -51,7 +53,9 @@ public class JavaxResolver extends DNSResolver implements SmackInitializer {
|
|||
|
||||
static {
|
||||
try {
|
||||
dirContext = new InitialDirContext();
|
||||
Hashtable<String, String> 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);
|
||||
}
|
||||
|
|
|
@ -257,6 +257,15 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
*/
|
||||
private final Collection<StanzaListener> stanzaAcknowledgedListeners = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/**
|
||||
* These listeners are invoked for every stanza that got dropped.
|
||||
* <p>
|
||||
* We use a {@link ConcurrentLinkedQueue} here in order to allow the listeners to remove
|
||||
* themselves after they have been invoked.
|
||||
* </p>
|
||||
*/
|
||||
private final Collection<StanzaListener> 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.
|
||||
|
@ -421,10 +430,25 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
}
|
||||
}
|
||||
}
|
||||
// (Re-)send the stanzas *after* we tried to enable SM
|
||||
// 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);
|
||||
}
|
||||
|
@ -452,9 +476,6 @@ 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);
|
||||
|
@ -492,6 +513,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;
|
||||
|
@ -499,6 +522,16 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
reader = null;
|
||||
writer = null;
|
||||
|
||||
initState();
|
||||
|
||||
// Wait for reader and writer threads to be terminated.
|
||||
readerWriterSemaphore.acquireUninterruptibly(2);
|
||||
readerWriterSemaphore.release(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initState() {
|
||||
super.initState();
|
||||
maybeCompressFeaturesReceived.init();
|
||||
compressSyncPoint.init();
|
||||
smResumedSyncPoint.init();
|
||||
|
@ -784,14 +817,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) {
|
||||
|
@ -1062,7 +1094,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
LOGGER.info(XMPPTCPConnection.this
|
||||
+ " received closing </stream> element."
|
||||
+ " Server wants to terminate the connection, calling disconnect()");
|
||||
ASYNC_BUT_ORDERED.performAsyncButOrdered(XMPPTCPConnection.this, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
disconnect();
|
||||
}});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1567,6 +1603,32 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
stanzaAcknowledgedListeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Stanza dropped listener.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @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.
|
||||
* <p>
|
||||
|
|
|
@ -2,6 +2,12 @@ allprojects {
|
|||
ext {
|
||||
shortVersion = '4.4.0-alpha2'
|
||||
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].
|
||||
// See also:
|
||||
// - https://issues.apache.org/jira/browse/MNG-6232
|
||||
// - https://issues.igniterealtime.org/browse/SMACK-858
|
||||
jxmppVersion = '0.7.0-alpha5'
|
||||
miniDnsVersion = '0.4.0-alpha3'
|
||||
smackMinAndroidSdk = 19
|
||||
|
|
Loading…
Reference in a new issue