Behavior of isConnected()

What is the expected behavior of isConnected?

The doc says: “Returns true if currently connected to the XMPP Server”.

So what does “connected to the XMPP Server” mean?

Seems like it return true even when the connection is dead, such as when the network is physically disconnected or when a laptop wakes up form sleep.

I want to correctly display the connection status to the user, so that he will know if a message can be sent immediately.

Is there any easy way to poll the real connection status of a XMPPConnection?

If I am missing something, please correct me.

Thanks for your support.

If isConnected() returns true when the connection is actually dead, that would be a bug. Is there a test case we can try to reproduce the behavior you’'re seeing?

Thanks,

Matt

I wrote a very simple test case and found out a bit more about the problem. isConnected works on my Windows machine (W2K, Java 1.4.2) but not on my G4 Laptop (OSX 10.3.1, Java 1.4.1).

Here is how I test:

Windows:

Run the test and disable the network connection. isConnected return false afterwards and connectionCloseOnError is invoked. Seems like everything works.

OSX:

Run the test and physically unplug the connection. isConnected still return true afterwards. I also waited for a few minutes to make sure that it isn’'t a timeout issue.

I don’‘t have a desktop OSX machine so I am not sure if it’'s machine dependent.

If it turns out to be a bug outside of smack and I can’'t fixed it, do you have a suggestion to work around this problem? Thanks.

Here is my simple test program (need to fill in the host, user, and password):

import org.jivesoftware.smack.*;

import org.jivesoftware.smack.packet.*;

public class SmackTest {

public SmackTest() {

}

public static void main(String[] args) throws Exception{

String host = “server”;

String user = “username”;

String pass = “password”;

XMPPConnection connection = new XMPPConnection(host);

connection.login(user, pass);

ConnectionListener listener = new ConnectionListener(){

public void connectionClosed(){

System.out.println(“Connection close notified.”);

System.exit(0);

}

public void connectionClosedOnError(Exception e){

System.out.println(“Connection close on error.”);

System.out.println(e);

System.exit(0);

}

};

connection.addConnectionListener(listener);

while(true){

System.out.println("Connected " + connection.isConnected());

Thread.sleep(2000);

}

}

}

Well, this seems more a problem of the OS that don’‘t detect the unplugged cable. If so, theres nothing to do! If the OS don’‘t detect the unplugged cable, he doesn’‘t shutdown the currently open network connections, and soon, smack can’‘t detect that the connection goes down, because for the virtual machine the connections don’'t goes down!!!

It’‘s possible that soome added checks like trying to send a " " character to the server every few minutes might be able to detect an issue like this. I’'ll file an issue so that we can look into it further.

Regards,

Matt

Two other possibilities: 1) if you’‘re connecting locally (server is on the same machine as the client), unplugging the connection won’'t bring down the tcp/ip stack, and the server will still be reachable. 2) if your pbook is like mine, it has airport in it. So unplugging may not break your connection - your mac will automatically reroute traffic over the airport connection.

Assuming that these are not the case (I assume it is not but thought we should be thorough) then it’‘s probably as matt says: the connection closing is not being detected in a timely manner. This can probably be detected earlier by sending data over the connection as Matt proposes. Many servers will also destroy idle connections that don’‘t send any data so it’'s common to send extra space characters to keep the connection open. Adding a ‘‘send keepalive’’ method may help in several ways.

-iain

I think this is a OS problem, so sending white spaces don’'t help.

If the OS detects the unplugged cable and close the connection, the api would notice because is always trying to read from it and will catch the closed socket.

If the OS don’'t close the connection we can send all the white spaces we want!!!

The OS will put them in is internal buffer and wait that they get send… It will stop only when the buffer get’'s filled and abort the connection, and then the program will detect the closed connection!

Two other possibilities: 1) if you’'re connecting

locally (server is on the same machine as the

client), unplugging the connection won’'t bring down

the tcp/ip stack, and the server will still be

reachable. 2) if your pbook is like mine, it has

airport in it. So unplugging may not break your

connection - your mac will automatically reroute

traffic over the airport connection.

My only connection is the ethernet and I unplug it, so there is no way to reach the remote server (amessage.info).

I want to try the keep-alive packet method. Can someone point me to the format of such a packet (if exist)? I suppose I can send a packet, and declare the connection is dead if I don’'t get a reply with in a few seconds.

Can someone tell me the function that is supposed to throw an exception in this situation? I suppose it’‘s one of the input stream read method? I can send the problem to the apple-java mailing list and see if it’'s a bug or there might be some way to correct the behavior.

Thanks!

I’'m not sure, but I think if you send a simple space through the socket, and the connections is closed it throws a IOException.

Note: Don’'t need to send a XMPP packet, just a single space…

I’'m not sure, but I think if you send a simple space

through the socket, and the connections is closed it

throws a IOException.

Note: Don’'t need to send a XMPP packet, just a single

space…

But like someone says, if the OSX store the bytes in a buffer, we will have to send enough bytes to overflow that buffer. I guess it’‘s still possible that the api don’'t throw an exception when reading a byte, but will throw an exception when sending a byte, and this might work.

Plus, there is no way that I can access the actual output stream, unless I modified the smack library by myself.

I am guessing that sending a byte won’'t work, because after the connection was dead, I can still send messages without getting an exception. I suspect the bytes are stored in a buffer. Perhaps the OS thinks the connection might come back alive soon and will be able to continue sending the stored bytes without interuppting the caller.

Anyone can run the test on a desktop OSX machine? I suspect it might behave differently on a desktop.

I also suspect that this problem come after Panther, but not on Jaguar.

There is something strange (magical) that I don’'t understand when I tested more.

Test:

  1. Login Account A on OSX

  2. Login Account B on Windows

  3. Send message M1, A->B

  4. B receive message M1

  5. Network A disconnected (physically unplug)

  6. Account A send messages M2, M3 (via Chat object)

  7. B receive no messages

  8. Network connected (replug), no re-login

  9. B receive no messages

  10. A send message M4

Magical Result:

  1. B receive M2, M3, and M4!

That’'s very magical to me. My guesses of what could have happened:

  1. Chat used another thread to send messages, and it’'s blocked when sending a byte on a disconnected network, and when the network is back on and another message is sent, the old messages are flushed and sent to the server.

  2. Smack knows the network is down, so it store the messages somewhere, and when the network is up and another message is sent, it reconnect to the server and deliver those messages.

Did I missed something here? It’'s magical.

Message was edited by: ptl74

I retest and reverse the roles of A and B (B is on Windows).

When B is disconnected, it throws an “XMPPException: Not connected” when B tried to send a message.

So it seems like the problem (or feature) is OSX related.

Message was edited by: ptl74

But like someone says, if the OSX store the bytes in a buffer, we will have to send enough bytes to overflow that buffer. I guess it’‘s still possible that the api don’'t throw an exception when reading a byte, but will throw an exception when sending a byte, and this might work.

Has I said… The point I want to reach is that sending a space to see if the connection is alive probably don’‘t result because it’'s a failure of the OS! Must remember that the buffer normally has a size of 64Kb(I think), and that is a lot of spaces until the exceptions is raised!

I am guessing that sending a byte won’'t work, because after the connection was dead, I can still send messages without getting an exception. I suspect the bytes are stored in a buffer. Perhaps the OS thinks the connection might come back alive soon and will be able to continue sending the stored bytes without interuppting the caller.

Maybe it’‘s a feature of the OS to prevent resets to connections in a ambient of network instability!!! I don’'t no…

The rigth persons to ask that is to a forum or mailing list about OSX