Initial login presence being missed, Roster instantiation too late

Florian, all,

I’ve noticed during my debugging that the initial Presence updates sent by the server are being missed because the Roster is instantiated too late. Below is the output from the Smack debug mode. Grace has one user in her roster, Hubert. We can see that after the stream setup has completed, the user Grace is logged in and smack sends an empty presence. Right after this, the server sends the initial presence messages of the users on her roster. These are not captured by smack because the listeners haven’t been added by the Roster instantiation. I have debugged to make sure. After the presence messages, the roster request is sent (this is the point in time where the Roster is initialised). Note that subsequent presence notifications after this point are parsed correctly.

I seem to have this problem more when debugging (because the debugging process and println statements slow down the instantiation), but it does happen when not debugging too. I guess it depends how fast the server responds and how quick the connection is.

I’m not sure what the solution is here. Is there any way you could move the roster initialisation to before the final login message is received? Also, I can’t seem to find a way to re-request that the server sends those initial presences again, so I can’t provide a workaround either.

Update: it is possible to force the server to re-send the initial presence updates by simulating a log out and log in. I.e. send two presence packets, unavailable then available. This will trick the server into resending all the presences in your roster. Obviously, this is very hacky, but it works around the problems stated above.

Update 2: An even better solution is to force the instantiation of the roster after connection, but before login. Pseudocode: con.connect(); con.getRoster(); con.login(“myUser”,“host”, “resource”);. This way the roster can set up it’s listeners before the user is actually connected.

Ideas welcome.

Thanks,

Phil

Ps. Output from smack debug. The key here is that the presences packets are sent and received before smack has had time to instantiate the roster.

D/SMACK﹕ SENT (0):

D/SMACK﹕ RCV (0):

D/SMACK﹕ User logged (0): grace@localhost/localhost@localhost:5222

D/SMACK﹕ SENT (0):

D/SMACK﹕ RCV (0):

D/SMACK﹕ SENT (0):

D/SMACK﹕ RCV (0):

Why not simply request the roster before sending initial presence (as it is specified in RFC 6121)

a client SHOULD request the roster before sending initial presence

Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence

Hi CSH, Yes, you’re right. This is what update 2 is doing. The initial presence is controlled by smack, it occurs when you call the login method. The client doesn’t have control over that.

However, this isn’t clear. It isn’t well encapsulated from the client. You can’t instantiate the roster without having a connection object. And it doesn’t make sense to do a con.getRoster() until AFTER you are logged in. Why should the client have to call getRoster before login? The roster is empty until after log in.

Anyway, thanks for the response.

Phil

Yes, it’s a problem. That’s why we disabled sending initial Presence during login (in the connection config) and manually send initial presence.

An even better solution is to force the instantiation of the roster after connection, but before login. Pseudocode: con.connect(); con.getRoster(); con.login(“myUser”,“host”, “resource”);. This way the roster can set up it’s listeners before the user is actually connected.
Why not simply setup the roster just before the initial presence is send? Could you test and report back if Setup Roster before sending initial presence · 5ad4e85 · Flowdalic/Smack · GitHub fixes the issue?

Yes, that would fix it, but is a bit of a hack. This is part of a bigger problem where you generally need to instantiate all of the extensions before you log in. For example, if I want a CAPS hash to be sent with that initial presence message, I have to make sure CAPS is instantiated before login. Even something unrelated to presence, like Message Carbons, would make more sense if it was setup before login.

But you’re right, Roster is particularly scary, because Smack instantiates it, not the user. This is hidden from the user.

Thanks.

but is a bit of a hack.
Why is it a hack? The order is simply, install the packet listener, then send the request stanza. Like it should be.

instantiate all of the extensions before you log in.
I don’t know what you exactly mean with “instantiate”, but all of Smack should been initialized after the first AbstractXMPPConnection instance has been created.

For example, if I want a CAPS hash to be sent with that initial presence message, I have to make sure CAPS is instantiated before login.
That should be the case, EntityCapsManager registers a ConnectionCreationListener when it’s initialized, i.e. after the first AbstractXMPPConnection instance has been created. This ConnectionCreationListener will create a EntityCapsMaager for every XMPPTCPConnection by initConnection calling connectionCreated().

But you’re right, Roster is particularly scary, because Smack instantiates it, not the user. This is hidden from the user.

Not sure what’s scary about that. We just talked about that the Roster needs to be setup before the initial presence is send if you ever want to use the roster.

Understood. Thanks for your help.