powered by Jive Software

Smack 4.4.0-alpha5 does not immediately throws StreamErrorException to the calling app for action

Following is a capture of the aTalk debug log on StreamErrorException condition.
It is found that smack-4.4.0-alpha5 does not immediately re-throw this StreamErrorException nor return via ConnectionListener#connectionClosedOnError() to the app for action. Instead it only returns the Exception on response timeout: i.e.

org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 30000ms (~30s). While waiting for establishing TLS [XMPPTCPConnection[not-authenticated] (4)]

Found that the problem is due to new notifyConnectionError() implementation:

    protected final void notifyConnectionError(final Exception exception) {
        synchronized (notifyConnectionErrorMonitor) {
            if (!isConnected()) {
                LOGGER.log(Level.INFO, "Connection was already disconnected when attempting to handle " + exception,
                                exception);
                return;
            }

            // Note that we first have to set the current connection exception and notify waiting threads, as one of them
            // could hold the instance lock, which we also need later when calling instantShutdown().
            setCurrentConnectionExceptionAndNotify(exception);

            // 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();

            for (StanzaCollector collector : collectors) {
                collector.notifyConnectionError(exception);
            }

            Async.go(() -> {
                // Notify connection listeners of the error.
                callConnectionClosedOnErrorListener(exception);
            }, AbstractXMPPConnection.this + " callConnectionClosedOnErrorListener()");
        }
    }
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)

Pending on when the StreamErrorException is being thrown, if after the connection is made etc, then the following can also happen.

2020-08-06 13:26:06.154 22680-22847/org.atalk.android W/g.atalk.androi: Long monitor contention with owner Thread-15 (22836) at void org.jivesoftware.smack.AbstractXMPPConnection.login(java.lang.CharSequence, java.lang.String, org.jxmpp.jid.parts.Resourcepart)(AbstractXMPPConnection.java:-1) waiters=0 in void org.jivesoftware.smack.tcp.XMPPTCPConnection.instantShutdown() for 29.122s
2020-08-06 13:26:06.167 22680-22867/org.atalk.android W/aTalk: [242028] org.jivesoftware.smack.AbstractXMPPConnection.callConnectionClosedOnErrorListener() Connection XMPPTCPConnection[not-authenticated] (0) closed with 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 06:25:35 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)

Could you elaborate your findings on the problem instead of just showing the problematic code part?

I think I understand now what the issue is: the stream error exception is ignored because the connection is not assumed to be connected when the notifyConnectionError() callback is invoked.

Suggested fix