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.
This commit adds
- SmackReactor / NIO
- a framework for finite state machine connections
- support for Java 8
- pretty printed XML debug output
It also
- reworks the integration test framework
- raises the minimum Android API level to 19
- introduces XmppNioTcpConnection
Furthermore fixes SMACK-801 (at least partly). Java 8 language
features are available, but not all runtime library methods. For that
we would need to raise the Android API level to 24 or higher.
The inetAddressAndPort String is redundant since
a2743549b8, because we now construct the
InetSocketAddress earlier and can hence use it in the log statement.
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.
using the default algorithm. Instead continue with 'null' as value of
the KeyManager[] array (kms). This makes the SSLContext.init() methods
to search the default security providers for implementations, which is
also OK.
This change is needed because it appears that on Android
KeyManagerFactory.getDefaultAlgorithm returns 'SunX509', which
subsequently results in
W/AbstractXMPPConnection: Connection XMPPTCPConnection[not-authenticated] (0) closed with error
java.security.NoSuchAlgorithmException: KeyManagerFactory SunX509 implementation not found
at org.apache.harmony.security.fortress.Engine.notFound(Engine.java:190)
at org.apache.harmony.security.fortress.Engine.getInstance(Engine.java:139)
at javax.net.ssl.KeyManagerFactory.getInstance(KeyManagerFactory.java:77)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:747)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1200(XMPPTCPConnection.java:149)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1053)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:980)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:996)
at java.lang.Thread.run(Thread.java:818)
Note that this is possibly because the Secuurity Provider was
not (yet) intialized.
New stanzas sent directly after stream resumption might have been added
to unacknowledgedStanzas before the old unacknowledged stanzas
are resent. This caused new stanzas to be sent twice and later led
to a StreamManagementCounterError.
Fixes SMACK-786
by calling String.equals() on the constant string and not on the
return value of parser.getName().
Also perform the access to 'parser' on a different LOC than
equals(). This should help debugging things like
okt 25, 2017 2:02:54 PM org.jivesoftware.smack.AbstractXMPPConnection callConnectionClosedOnErrorListener
WARNING: Connection XMPPTCPConnection[***@***/***] (0) closed with error
java.lang.NullPointerException
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1194)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:982)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:998)
at java.lang.Thread.run(Thread.java:745)
which where recently reported on the forums.
This caused the WaitForClosingStreamElementTest integration test to
fail, because the last presences stanzas, which are send after done()
in the writer thread would return true, are not added to the
unacknowledgedStanzas queue.
The result was:
SEVERE: WaitForClosingStreamElementTest.waitForClosingStreamElementTest (LowLevel): Failed
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.igniterealtime.smack.inttest.SmackIntegrationTestFramework.invokeLowLevel(SmackIntegrationTestFramework.java:466)
at org.igniterealtime.smack.inttest.SmackIntegrationTestFramework.runTests(SmackIntegrationTestFramework.java:375)
at org.igniterealtime.smack.inttest.SmackIntegrationTestFramework.run(SmackIntegrationTestFramework.java:165)
at org.igniterealtime.smack.inttest.SmackIntegrationTestFramework.main(SmackIntegrationTestFramework.java:84)
Caused by: java.lang.AssertionError: Sync poing yielded failure exception
at org.jivesoftware.smack.WaitForClosingStreamElementTest.waitForClosingStreamElementTest(WaitForClosingStreamElementTest.java:46)
... 8 more
Caused by: org.jivesoftware.smack.sm.StreamManagementException$StreamManagementCounterError: There was an error regarding the Stream Mangement counters. Server reported 3 handled stanzas, which means that the 3 recently send stanzas by client are now acked by the server. But Smack had only 1 to acknowledge. The stanza id of the last acked outstanding stanza is FqL1X-144
at org.jivesoftware.smack.tcp.XMPPTCPConnection.processHandledCount(XMPPTCPConnection.java:1847)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$2600(XMPPTCPConnection.java:149)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1176)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:980)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:996)
at java.lang.Thread.run(Thread.java:745)
Before this, if there was a stream error response by the server to our
stream open, that error response would only be handled in the reader
thread, and the user would get a message like:
"org.jivesoftware.smack.SmackException$NoResponseException: No
response received within reply timeout. Timeout was
5000ms (~5s). While waiting for SASL mechanisms stream feature from
server"
while the server may actually sent something like
<stream:stream
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
id='6785787028201586334'
from='jabbim.com'
version='1.0'
xml:lang='en'>
<stream:error>
<policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'>
</policy-violation>
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>
Too many (2) failed authentications from this IP
address (1xx.66.xx.xxx). The address will be unblocked at 04:24:00
06.01.2017 UTC
</text>
</stream:error>
</stream:stream>
It was necessary to change saslFeatureReceived from SmackException to
XMPPException in order to return the StreamErrorException at this sync
point. But this change in return required the introduction of a
tlsHandled sync point for SmackException (which just acts as a wrapper
for the various exception types that could occurn when establishing
TLS). The tlsHandled sync point is marked successful even if no TLS
was established in case none was required and/or if not supported by
the server.
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.charAt(String.java:658)
at org.jivesoftware.smack.util.dns.HostAddress.<init>(HostAddress.java:48)
at org.jivesoftware.smack.util.dns.HostAddress.<init>(HostAddress.java:62)
It was a *very* bad idea to perform the SecurityMode.Required check in
the connection's reader thread and not at the end of
AbstractXMPPConnectin's connect(). :/
This behavior dates back to 8e750912a7
Fixes SMACK-739
as otherwhise the following could happen:
WARNING: Connection XMPPTCPConnection[not-authenticated] (0) closed with error
java.security.KeyStoreException: Uninitialized keystore
at java.security.KeyStore.aliases(KeyStore.java:1233)
at sun.security.ssl.SunX509KeyManagerImpl.<init>(SunX509KeyManagerImpl.java:127)
at sun.security.ssl.KeyManagerFactoryImpl$SunX509.engineInit(KeyManagerFactoryImpl.java:70)
at javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:256)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:739)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1000(XMPPTCPConnection.java:146)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1026)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:960)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:975)
at java.lang.Thread.run(Thread.java:745)
org.jivesoftware.smack.SmackException: java.security.KeyStoreException: Uninitialized keystore
org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1033)
org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:960)
org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:975)
java.lang.Thread.run(Thread.java:745)
java.security.KeyStoreException: Uninitialized keystore
java.security.KeyStore.aliases(KeyStore.java:1233)
sun.security.ssl.SunX509KeyManagerImpl.<init>(SunX509KeyManagerImpl.java:127)
sun.security.ssl.KeyManagerFactoryImpl$SunX509.engineInit(KeyManagerFactoryImpl.java:70)
javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:256)
org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:739)
org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1000(XMPPTCPConnection.java:146)
org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1026)
org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:960)
org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:975)
java.lang.Thread.run(Thread.java:745)