Hi Wray,
With the implementation of a very basic demo client, running against a development build of Openfire (4.8.0-SNAPSHOT) running with the bin/openfire.sh -demoboot -debug
startup arguments, I had no trouble getting the PingFailedListener to fire.
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.ping.PingManager;
import java.time.Duration;
public class TestClient {
public static void main(String[] args) throws Exception {
XMPPTCPConnectionConfiguration configA = XMPPTCPConnectionConfiguration.builder()
.setUsernameAndPassword("jane", "secret")
.setXmppDomain("example.org")
.setResource("test")
.setHost("localhost")
.setPort(5222)
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
.build();
AbstractXMPPConnection connection = new XMPPTCPConnection(configA);
connection.connect();
connection.login();
PingManager pingManager = PingManager.getInstanceFor(connection);
pingManager.setPingInterval(5);
pingManager.registerPingFailedListener(() -> System.out.println("Ping failed!"));
Thread.sleep(Duration.ofMinutes(6).toMillis());
connection.disconnect();
}
}
After first observing a ping to be succesfull, I I placed a breakpoint in Openfireās IQPingHandler
, effectively pausing the processing of the client request indefinitely. The next ping that was fired caused the PingFailedListener
to be invoked after about 2 minutes, as expected.
Looking at Smackās PingManager
implementation, this caught my eye in the āno response receivedā handling of the ping request:
pingFuture.onError(new ExceptionCallback<Exception>() {
@Override
public void processException(Exception exception) {
long lastStanzaReceived = connection.getLastStanzaReceived();
if (lastStanzaReceived > 0) {
long now = System.currentTimeMillis();
// Delta since the last stanza was received
int deltaInSeconds = (int) ((now - lastStanzaReceived) / 1000);
// If the delta is smaller then the ping interval, we have got an valid stanza in time
// So not error notification needed
if (deltaInSeconds < pingInterval) {
maybeSchedulePingServerTask(deltaInSeconds);
return;
}
}
for (PingFailedListener l : pingFailedListeners) {
l.pingFailed();
}
}
});
}
It looks like the ping failure event listener does not fire, if between the time that the ping request was made, some other data was received by the server. The reasoning here probably is that such data can be considered āproof of lifeā.
If in your setup, you properly killed the network connection, I canāt see other data arrive at the client, but Iām not sure exactly how you did that. If you only prevented the ping response from arriving, that might account for something.
Otherwise, Iām not sure whatās going on. Maybe another part of the code already picked up the network disconnect, and put Smack in some kind of āIām no longer connectedā state? Without more debugging, itās hard to tell exactly.