Smack 4.2.0-rc2 AbstractXMPPConnection#connect() does not return "policy-violation" to the calling application.

When making an xmpp connection to a xmpp server, if the server returns a , this is not propagated to the calling application. Instead it is returned as:

{SmackException$NoResponseException@22122} “org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). While waiting for SASL mechanisms stream feature from server”

For application implementation, it may be important to inform the user if there is an and the connection is only unblocked at xx.xx.xx. Otherwise use may continuously attempt to login without knowing he has been blocked until xx.xx.xx.

============ Smack log showing the <policy violation =========================

01-06 12:07:03.695 8509-9341/org.atalk.android D/SMACK: SENT (0): <stream:stream xmlns=‘jabber:client’ to=‘jabbim.com’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

01-06 12:07:04.085 8509-9342/org.atalk.android D/SMACK: RECV (0): <?xml version='1.0'?><stream:stream xmlns=‘jabber:client’ xmlns:stream=‘http://etherx.jabber.org/streams’ id=‘6785787028201586334’ from=‘jabbim.com’ version=‘1.0’ xml:lang=‘en’>stream:errorToo 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</stream:error></stream:stream>

01-06 12:07:08.695 8509-9342/org.atalk.android W/αTalk: [4] org.jivesoftware.smack.AbstractXMPPConnection.callConnectionClosedOnErrorListen er() 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:errorToo 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</stream:error>

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPC onnection.java:1028)

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPCon nection.java:969)

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnecti on.java:984)

at java.lang.Thread.run(Thread.java:818)

01-06 12:07:08.695 8509-9342/org.atalk.android E/αTalk: [4] impl.protocol.jabber.ProtocolProviderServiceJabberImpl.connectionClosedOnError( ).2203 connectionClosedOnError policy-violation You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions

stream:errorToo 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</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:errorToo 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</stream:error>

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPC onnection.java:1028)

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPCon nection.java:969)

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnecti on.java:984)

at java.lang.Thread.run(Thread.java:818)

**================Variables of Exception returns to calling application ========================== **

Exception e = {SmackException$NoResponseException@22122} “org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). While waiting for SASL mechanisms stream feature from server”

filter = null

cause = {SmackException$NoResponseException@22122} “org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). While waiting for SASL mechanisms stream feature from server”

detailMessage = “No response received within reply timeout. Timeout was 5000ms (~5s). While waiting for SASL mechanisms stream feature from server”

stackState = {Object[10]@22132}

stackTrace = {StackTraceElement[0]@22133}

suppressedExceptions = {Collections$EmptyList@22134} size = 0

shadow$klass = {Class@20719} “class org.jivesoftware.smack.SmackException$NoResponseException”

shadow$monitor = -1541682932

mConnection = {XMPPTCPConnection@22098} “XMPPTCPConnection[not-authenticated] (0)”

Can you provide more of the debug output? You just show the send/receive pair of the stream open. What happened before?

I’ve made some changes, could you verify if you now receive a StreamErrorException with the latest -rc2-SNAPSHOT.

I have tried the latest rc2-snapshot, the problem remains. I did a quick trace of the actual execution sequence and following is my observation starting with method XMPPTCPConnection#connect()

connect() -> connectInternal() -> initConnection()

at which any reply packet is now handled via packetReader.init(); as async task by XMPPTCPConnection#parsePacket()

The reply packet from opening the stream:


01-06 12:07:04.085 8509-9342/org.atalk.android D/SMACK: RECV (0): <?xml version='1.0'?><stream:stream xmlns=‘jabber:client’ xmlns:stream=‘http://etherx.jabber.org/streams’ id=‘6785787028201586334’ from=‘jabbim.com’ version=‘1.0’ xml:lang=‘en’>stream:errorToo 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</stream:error></stream:stream>


trigger a case “error” and StreamErrorException(streamError) is thrown in parsePackets() as shown below.

As the StreamErrorException() is thrown from a separate async thread, hence it is not captured in initConnection() nor return to the calling application.

Not sure if a callback implementation can help resolve the problem. I am interested what is your final solution, hopefully can be adopt for aTalk which I face similar problem.

============ Method XMPPTCPConnection#parsePackets() ==========

private void parsePackets() {

case “error”:
StreamError streamError = PacketParserUtils.parseStreamError(parser);
saslFeatureReceived.reportFailure(new StreamErrorException(streamError));
throw new StreamErrorException(streamError);

}

============ Method XMPPTCPConnection#initConnection() ==========

private void initConnection() throws IOException {
boolean isFirstInitialization = packetReader == null || packetWriter == null;
compressionHandler = null;

// Set the reader and writer instance variables
initReaderAndWriter();

if (isFirstInitialization) {
packetWriter = new PacketWriter();
packetReader = new PacketReader();

// If debugging is enabled, we should start the thread that will listen for
// all packets and then log them.
if (config.isDebuggerEnabled()) {
addAsyncStanzaListener(debugger.getReaderListener(), null);
if (debugger.getWriterListener() != null) {
addPacketSendingListener(debugger.getWriterListener(), null);
}
}
}
// Start the packet writer. This will open an XMPP stream to the server
packetWriter.init();
// Start the packet reader. The startup() method will block until we
// get an opening stream packet back from server
packetReader.init();
}

===================================

By the way how you get build.gradle to refresh the library with the latest 4.2.0-rc2. I struggle for almost 3 hours with all suggestions I can get online, finally resort to clearing the .gradle/.cache that works.

I’ve made adjustments on the code based on your information. Smack uses SynchronizationPoints to synchronize the different states of XMPP connection establishment. The saslFeatureReceived sync point should now be reported as failed with StreamErrorException containing the policy-violation stream error. Please try the latest snapshot and report back.

You can follow my development at GitHub - Flowdalic/Smack at 4.2 which should usually reflect the latest snapshot of the 4.2 branch.

By the way how you get build.gradle to refresh the library with the latest 4.2.0-rc2. I struggle for almost 3 hours with all suggestions I can get online, finally resort to clearing the .gradle/.cache that works.
It appears that gradle is unable to reliable check for new snapshot versions if instructed so in certain situations. I’ve asked something related on the gradle forums: --refresh-dependencies should use cacheChangingModulesFor=0s - Old Forum - Gradle Forums

Deleting the gradle cache is the most reliable solution so far, that I also use. Maybe this will improve (or has already) with newer gradle versions.

The policy-violation exception is working now. Following shows what is being feedback. Quite a mouth full for user to read.

Thanks for the effort.

01-08 16:08:24.235 org.atalk.android D/SMACK: SENT (1): <stream:stream xmlns=‘jabber:client’ to=‘jab.com’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

01-08 16:08:24.665 org.atalk.android D/SMACK: RECV (1): <?xml version='1.0'?><stream:stream xmlns=‘jabber:client’ xmlns:stream=‘http://etherx.jabber.org/streams’ id=‘11641259353516965609’ from=‘jab.com’ version=‘1.0’ xml:lang=‘en’>stream:errorToo many (2) failed authentications from this IP address (xxx.xx.84.204). The address will be unblocked at 08:27:22 08.01.2017 UTC</stream:error></stream:stream>

01-08 16:08:24.675 org.atalk.android W/αTalk: [5] org.jivesoftware.smack.AbstractXMPPConnection.callConnectionClosedOnErrorListen er() Connection XMPPTCPConnection[not-authenticated] (1) 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:errorToo many (2) failed authentications from this IP address (115.66.84.204). The address will be unblocked at 08:27:22 08.01.2017 UTC</stream:error>

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPC onnection.java:1044)

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPCon nection.java:979)

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnecti on.java:994)

at java.lang.Thread.run(Thread.java:818)

Quite a mouth full for user to read.
Consider not exposing the user to such low level protocol details. Experience shows that users don’t want to deal with the protocol. They want to use it.

Or at least strip the technical details in order to not distract the users with the noise. In this particular case, it may be sufficient to just display as message like:

Could not login. Server returned ‘policy-violation’: Too many (2) failed authentications from this IP address (xxx.xx.84.204). The address will be unblocked at 08:27:22 08.01.2017 UTC.

Thanks, you read my mind. This is what I would like to have the low level Smack library to remove all the protocol <tag?> information. I am OK with other description text information.

No, that’s up to you to process the StreamError and to display it they way you want. Simply use the API provided by StreamError, e.g. getDescriptiveText().

Following is what aTalk source looks like to try & capture the exceptions return from mConnect.connect() method; it then checks for "policy-violation. The SmackException | IOException | XMPPException | InterruptedException are the only exceptions thrown by smack from connect(). At which point the only public method to get to the error string is ex.getMessage() and the errMsg is what you see in the Reason descriptive text above. There is no post-processing done by aTalk.

The getDescriptiveText() is only available at case “error”: throw new StreamErrorException(streamError)

which actually contains the body which is exactly what I would like to have in == result return from server == i.e.

Too many (2) failed authentications from this IP address (115.66.84.204). The address will be unblocked at 15:32:03 08.01.2017 UTC

To get to the above text, I need to use ex.getStreamError().getDescriptiveText(). However the method .getStreamError() is not accessible to aTalk application.

Actually I am not expecting smack nor aTalk application to perform any text cleanup on the actual return from server, as the text returned may be different form different servers; Any post processing of the return may distort the actual meaning the server trying to convey.

My previous few message is hoping the smack development team to actual investigate the reason why there are other added text being propagated up to the application layer. Alternatively is to make getStreamError() available to the application.

================= aTalk Connect() source ====================

try {
mConnection.connect();
}
catch (SmackException | IOException | XMPPException | InterruptedException ex) {
String errMsg = ex.getMessage();
if (errMsg.contains(“policy-violation”))
{
XMPPError.Builder xmppErrorBuilder = XMPPError.from(
XMPPError.Condition.policy_violation, errMsg);
throw new XMPPException.XMPPErrorException(null, xmppErrorBuilder.build());
}

=========== XMPPTCPConnection#Case in parsePackets() ======================

case “error”:
StreamError streamError = PacketParserUtils.parseStreamError(parser);
saslFeatureReceived.reportFailure(new StreamErrorException(streamError));
// Mark the tlsHandled sync point as success, we will use the saslFeatureReceived sync
// point to report the error, which is checked immediately after tlsHandled in
// connectInternal().
tlsHandled.reportSuccess();
throw new StreamErrorException(streamError);

============== result return from server =====================

01-08 23:14:44.487 org.atalk.android D/SMACK: RECV (4): <?xml version='1.0'?><stream:stream xmlns=‘jabber:client’ xmlns:stream=‘http://etherx.jabber.org/streams’ id=‘18037858095225184259’ from=‘jabbim.com’ version=‘1.0’ xml:lang=‘en’>stream:errorToo many (2) failed authentications from this IP address (115.66.84.204). The address will be unblocked at 15:32:03 08.01.2017 UTC</stream:error></stream:stream>

After reviewing the smack code, I found that I can re-cast the ex to (StreamErrorException) to get to the descriptive text i.e.

StreamErrorException erSEE = (StreamErrorException) ex;
String errMsg = erSEE.getStreamError().getDescriptiveText();

then I can get the actual sent from the server.

But not sure if this is a good approach, as the developer needs to check through the smack code to get to the solution.

May be exceptions throw from connect() should include StreamErrorException. Alternatively is to declare getDescriptiveText() as abstract method in XMPPException i.e. the base class where both XMPPErrorException and StreamErrorException is sub-class from.

May be exceptions throw from connect() should include StreamErrorException.
It does include StreamErrorException, since its a subclass of XMPPException. Your problem is your usage of try/multi-catch. Most exception types needs different handling. So instead of

try {
mConnection.connect();
}
catch (SmackException | IOException | XMPPException | InterruptedException ex) {
String errMsg = ex.getMessage();
if (errMsg.contains(“policy-violation”))
{
XMPPError.Builder xmppErrorBuilder = XMPPError.from(
XMPPError.Condition.policy_violation, errMsg);
throw new XMPPException.XMPPErrorException(null, xmppErrorBuilder.build());

}

you could do something like

try {

mConnection.connect()

} catch (StreamErrorException e) {

// handle stream error

} catch ( SmackException | IOException | XMPPException | InterruptedException e) {

}

Thanks for pointing it out. I was not aware that I can add new catch for sub-class in try/catch. When coding, Android Studio will only suggest all exceptions that are directly thrown by the called method but not its sub-class.

By the way, the reason for the multi-catch design is partially in-build in the original forked source where aTalk is based on. During login process, the calling method further action is based on single except throws from the called methods. I am still trying to fine tune on the way the various thrown exceptions are being handled.

Thanks again for your help.

I have just released a aTalk version 0.7.2 based on the latest Smack version 0.4.2-rc (SNAPSHOT).

aTalk is now able to support XEP-0077:In-Band Registration and XEP-0158:CAPTCHA Forms for captcha protected online registration. If anybody of your is interested; the released android apk can be downloaded from

http://atalk.sytes.net/releases/atalk-android/aTalk-release.apk

Thank again for your team effort on the new smack library release.