We previously only set 'connected' after connectInternal()
returned. This could lead to notifyConnectionError() ignoring stream
error exceptions, e.g. when establishing TLS which happens also in
connectInternal(), because 'connected' was still 'false'.
2020-08-06 13:08:06.265 19830-20423/org.atalk.android D/SMACK: SENT (0):
<stream:stream xmlns='jabber:client' to='atalk.sytes.net' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
2020-08-06 13:08:06.333 19830-20424/org.atalk.android D/SMACK: RECV (0): ?xml version='1.0'?>
<stream:stream id='16420577292739412012' version='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' from='atalk.sytes.net' xmlns='jabber:client'>
<stream:error>
<policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>
Too many (20) failed authentications from this IP address (::ffff:42.60.7.13). The address will be unblocked at 05:15:34 06.08.2020 UTC
</text>
</stream:error>
</stream:stream>
2020-08-06 13:08:06.346 19830-20424/org.atalk.android I/aTalk: [241896] org.jivesoftware.smack.AbstractXMPPConnection.notifyConnectionError() Connection was already disconnected when attempting to handle org.jivesoftware.smack.XMPPException$StreamErrorException: policy-violation You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions
<stream:error><policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xml:lang='en'>Too many (20) failed authentications from this IP address (::ffff:42.60.7.13). The address will be unblocked at 05:15:34 06.08.2020 UTC</text></stream:error>
org.jivesoftware.smack.XMPPException$StreamErrorException: policy-violation You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions
<stream:error><policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xml:lang='en'>Too many (20) failed authentications from this IP address (::ffff:42.60.7.13). The address will be unblocked at 05:15:34 06.08.2020 UTC</text></stream:error>
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:966)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$700(XMPPTCPConnection.java:898)
at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:921)
at java.lang.Thread.run(Thread.java:919)
Which eventually leads to a NoResponseException
org.jivesoftware.smack.SmackException$NoResponseException: No response
received within reply timeout. Timeout was 30000ms (~30s). While
waiting for establishing TLS
[XMPPTCPConnection[not-authenticated] (4)]
We now set 'connected' to 'true' as soon as the transport (e.g. TCP,
BOSH, …) is connected. While this is in other ways also sensible, it
also allows notifyConnectionError() to handle exceptions in the early
connection stage.
Thanks to Eng Chong Meng for reporting this.
We previously only looked in the registry for 'submit' type forms. But
also 'result' type forms may be send without field type
annotations. Same is true, but less likely, for 'form' type forms.
Instead of passing the passphrase back to the user via a
DisplayBackupCodeCallback, we directly return the passphrase
which is now represented by a class.
Also we now allow the user to provide the passphrase.
InBandBytestreamManager followed an unusual pattern: Within the
connectionTermianted() callback, it would remove itself from the
'managers' map. This allowed for multiple instances of an
InBandBytestreamManager to exist for the same connection, causing all
kinds of issues.
This fixes the issue by changing InBandBytestreamManager to use the
Smack-idiomatic pattern used by managers.
We also do no longer reset the listeners if the connection is
termianted, as listeners (and handlers) typically persist until they
are explicitly removed by the user.
As positive side-effect, the number of indeterministic unit-tests,
caused by using Thread.sleep(), is reduced. The executor service in
InitiationListener was also removed, because the IQ handler is already
called asynchronously to the connections main loop.
Thanks to Anno van Vliet for reporting this.
The current code would work just fine for a connection having
multiple endpoints. However, when there is only one endpoint
ConnectionAttemptState.nextAddress() would return null, since
connectionEndpointIterator has already iterated over the only
possible value in the contructor leading to a NullPointerException.
This means that during establishment of a connection having multiple
endpoints, the first value inside connectionEndpointIterator would
always be overlooked.
To ensure the thread starting the reader/writer threads sees them
running and eventually waits until the 'running' boolean is reset to
'false' upon connection termination.
Since the current variant of notifyConnectionError() does not execute
most of its work in a new thread, especially since instantShutdown()
is called in the invoking thread, we have to mark the connections
reader or writer threads as no longer running prior them invoking
notifyConnectionError(). Otherwise they will end up waiting for
themselves to terminate.