powered by Jive Software

eJabberd admin still sees user as ONLINE after .disconnect / Android XMPP Smack

I’m using eJabberd and Smack for Android (Native Java)
I’ve been trying to call .disconnect() in every imaginable way to disconnect and set the user as OFFLINE, but on eJabberd admin, it’s always ONLINE, even after a successful disconnect.
Some codes I used:

connection.disconnect();

Also used:

    try {
         connection.sendStanza(
               MessageBuilder.buildPresence()
               .ofType(Presence.Type.unavailable)
               .build()
         );
    } catch (SmackException.NotConnectedException | InterruptedException e) {
        e.printStackTrace();
    }

Also:

  PresenceBuilder presenceBuilder = connection.getStanzaFactory()
                                .buildPresenceStanza();
                        presenceBuilder.ofType(Presence.Type.unavailable);
                        Presence presence = presenceBuilder.build();
                        try {
                            connection.disconnect(presence);
                        } catch (SmackException.NotConnectedException e) {
                            e.printStackTrace();
                        }

All these attempts results in the ConnectionListener trigger the
public void connectionClosed() {}

Which means the connection was successfully closed.

SO WHY IS THIS STILL SHOWING AS ONLINE (Online Users) EVEN AFTER SUCCESSFULLY DISCONNECTED?

My iOS version, whenever I call [connection disconnect]; and go to my eJabberd admin, the user is shown as OFFLINE (not listed in the Online Users page).

Did I miss something here?

Enable SmackConfiguration.DEBUG by setting it to true. Check the XMPP trace if Smack sends a closing stream tag and waits for the closing stream tag for the server. If this is the case, then it is not an issue on Smack’s side.

D/SMACK: SENT (1): 
    <presence id='3HD1T-11' type='unavailable'/>
    <a xmlns='urn:xmpp:sm:3' h='16'/>
    </stream:stream>

D/SMACK: RECV (1): 
    </stream:stream>

D/SMACK: XMPPConnection closed (XMPPTCPConnection[myuser@ejabberd.mydomain.com/3432235344…3890484] (1))

D/SMACK: RECV (0): 
    <r xmlns='urn:xmpp:sm:3'/>

D/SMACK: SENT (0): 
    <a xmlns='urn:xmpp:sm:3' h='16'/>

Assuming that the trace you show is chronological, it is a little bit surprising that the server sends a stream management request after it has send the closing stream tag. That said, we see in the trace that Smack send the closing stream tag, hereby announcing that it wants to close the connection, and this appears to be acknowledged by the server, by also sending the closing stream tag. This suggests that the server is aware the the cilent disconnected. So it does not look lilke a Smack issue and you may want to look on the server side for the cause.

I don’t agree with that. If that’s a server issue, HOW COME the iOS version works perfectly?
And the iOS client is sending the same tags to the server </stream:stream>, etc.
And it becomes offline immediately.
It is a SMACK issue. In fact many people reported it in many websites for years.
But none with a real solution.

What’s in the server’s debug logs at the time of the disconnect?

Below the eJabberd server logs when a user/client connects then disconnects from Android vs iOS.

ANDROID:

2022-02-25 15:19:22.846 [info] <0.668.0>@ejabberd_listener:accept:333 (#Port<0.19686>) Accepted connection ::FFFF:186.220.196.48:27122 -> ::FFFF:162.243.151.243:5222
2022-02-25 15:19:22.847 [info] <0.668.0>@ejabberd_listener:accept:333 (#Port<0.19688>) Accepted connection ::FFFF:186.220.196.48:27121 -> ::FFFF:162.243.151.243:5222
2022-02-25 15:19:24.125 [info] <0.14809.30>@ejabberd_c2s:wait_for_sasl_response:918 ({socket_state,p1_tls,{tlssock,#Port<0.19688>,#Port<0.19690>},<0.14808.30>}) Accepted authentication for my_user by undefined from ::FFFF:186.220.196.48
2022-02-25 15:19:24.126 [info] <0.14807.30>@ejabberd_c2s:wait_for_sasl_response:918 ({socket_state,p1_tls,{tlssock,#Port<0.19686>,#Port<0.19689>},<0.14806.30>}) Accepted authentication for my_user by undefined from ::FFFF:186.220.196.48
2022-02-25 15:19:24.702 [info] <0.14807.30>@ejabberd_c2s:wait_for_session:1106 ({socket_state,p1_tls,{tlssock,#Port<0.19686>,#Port<0.19689>},<0.14806.30>}) Opened session for my_user@ejabberd.mydomain.com/5670218761405988119112104412454738128828605688534567723564
2022-02-25 15:19:24.707 [info] <0.14809.30>@ejabberd_c2s:wait_for_session:1106 ({socket_state,p1_tls,{tlssock,#Port<0.19688>,#Port<0.19690>},<0.14808.30>}) Opened session for my_user@ejabberd.mydomain.com/38934401518419626781047176254608564657013565449192582023620
2022-02-25 15:19:24.890 [info] <0.14807.30>@ejabberd_c2s:handle_enable:2653 Stream management with resumption enabled for my_user@ejabberd.mydomain.com/5670218761405988119112104412454738128828605688534567723564
2022-02-25 15:19:24.899 [info] <0.14809.30>@ejabberd_c2s:handle_enable:2653 Stream management with resumption enabled for my_user@ejabberd.mydomain.com/38934401518419626781047176254608564657013565449192582023620
2022-02-25 15:19:38.638 [info] <0.14807.30>@ejabberd_c2s:terminate:1788 ({socket_state,p1_tls,{tlssock,#Port<0.19686>,#Port<0.19689>},<0.14806.30>}) Close session for my_user@ejabberd.mydomain.com/5670218761405988119112104412454738128828605688534567723564

IOS:

2022-02-25 15:25:54.322 [info] <0.671.0>@ejabberd_listener:accept:333 (#Port<0.19699>) Accepted connection 186.220.196.48:26693 -> 162.243.151.243:5280
2022-02-25 15:25:54.323 [info] <0.14837.30>@ejabberd_http:init:158 started: {p1_tls,{tlssock,#Port<0.19699>,#Port<0.19700>}}
2022-02-25 15:26:00.780 [info] <0.668.0>@ejabberd_listener:accept:333 (#Port<0.19701>) Accepted connection ::FFFF:186.220.196.48:26695 -> ::FFFF:162.243.151.243:5222
2022-02-25 15:26:00.781 [info] <0.668.0>@ejabberd_listener:accept:333 (#Port<0.19702>) Accepted connection ::FFFF:186.220.196.48:26696 -> ::FFFF:162.243.151.243:5222
2022-02-25 15:26:01.987 [info] <0.14841.30>@ejabberd_c2s:wait_for_sasl_response:918 ({socket_state,gen_tcp,#Port<0.19702>,<0.14840.30>}) Accepted authentication for my_user_IOS by undefined from ::FFFF:186.220.196.48
2022-02-25 15:26:02.561 [info] <0.14841.30>@ejabberd_c2s:wait_for_session:1106 ({socket_state,gen_tcp,#Port<0.19702>,<0.14840.30>}) Opened session for my_user_IOS@ejabberd.mydomain.com/9871235474941515536153297189674046270385853083472448150030
2022-02-25 15:26:10.549 [info] <0.14841.30>@ejabberd_c2s:terminate:1788 ({socket_state,gen_tcp,#Port<0.19702>,<0.14840.30>}) Close session for my_user_IOS@ejabberd.mydomain.com/9871235474941515536153297189674046270385853083472448150030

@Flow am I wrong or there are two sessions (or connections?) for the same user? How is that possible?

And when I’m disconnecting, it’s terminating for only one of them.

Allowing multiple connections (and online sessions) for the same user is a core feature of XMPP. I guess you have a stale connection. I’d also guess that this is probably because Smack enables XMPP Stream Management (XEP-0198) and xmpp framework on iOS does not. You could disable Stream Management in Smack (if you do not need it) or lower the preferred resumption time (XMPPTCPConnection.setPreferredResumptionTime(int resumptionTime).

OH GOD I FIXED IT! lol
When I came here to explain my solution I saw you figured it out the same way at the same time.
Thanks anyway bro!
I had my own XMPP manager. I changed it to avoid multiple connections, since I don’t need it.

My Solution to make my XMPPManager a singleton with allowing only a single user connection at a time.
Since connection is async, if it called twice (for any crazy reason), it would still connect twice the same user.
So I added a static Boolean set to true right after my method connecting starts. This way I’d know if I already started a connection/login attempt, and not allow another connection while it’s busy connecting.

if(busyConnecting) {
       return;
}
busyConnecting = true;

Also as @Flow wisely mentioned, we can also use this:

XMPPTCPConnection.setUseStreamManagementDefault(false);
XMPPTCPConnection.setUseStreamManagementResumptionDefault(false);

Thanks for all your help @Flow .