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.