Skip to content
This repository

XMPPReconnect doesn't always work correctly #101

Open
sarsonj opened this Issue August 20, 2012 · 42 comments

9 participants

Jindrich Sarson jonasman Bradford Toney Yuhao Ding mschnall Alberto Sendra misha2400 basants Paul Melnikow
Jindrich Sarson

Hi,

I have issues with XMPPReconnect - sometimes, when going from 3G to no-signal and back, XMPP didn't reconnect. I tried to simulate this using flight mode and I realized, that XMPPReconnect doesn't handle "no network reachable" event. Because XMPPStream doesn't use timeouts, it can happen, that this "no-signal" state is not detected and when network goes back to 3G, same socket is used. But at least our 3G network doesn't guarantee same IP address, so that socket is not working again. But because of no timeout, application is in state, that it looks like that is connected, but it is not.

I tried to implement experiment, using Apple reachability example and simply disconnect xmppSteam socket when reachability changed and both WLAN and WAN are not available. It fixes this issue and now XMPPReconnect works correctly.

Before I start to change XMPPReconnect I want to discuss, how this should be handled correctly. For example - should be also socket closed and created again with every reachability change? How is this handled now? Is socket closed automaitcally, when for example already connected on WiFi and new WiFi is connected?

Thanks,

Jindrich

jonasman

Hello,

I also have this problem. Some times the Framework doesnt even connect to the server. I didnt make any investigation on that.

Could you share your fix so I can test it in my implementation?

Bradford Toney

Yeah I am having the same issue, is there a fix?

Yuhao Ding

I'd like to see the fix as well.

mschnall

I'm having the same exact problem- does anyone know of a solution?

Jindrich Sarson

Currently, I implemented "hacky" solution using Rechability example from Apple - http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html

Simply when I detect no network, I close XMPP socket using [asyncSocket disconnect];

The XMPPReconnect plugin then handles connecting correctly.

However, this is quick hack, It should be implemented in XMPPReconnect. Now when it is confirmed as problem of more people, I will look to XMPPReconnect to fix it here.

Yuhao Ding

sarsonj, I tried your solution, but it doesn't seem to fix my problem. Here's how I'm reproducing the issue:

  1. Start with app open, XMPP is connected.
  2. Background the app
  3. Turn on airplane mode (or turn off the AirPort if you're running on the simulator)
  4. Turn off airplane mode (or turn the AirPort back on)
  5. Bring app back to foreground.
  6. Look for the reconnection...

2012-08-29 01:54:47.540 medigram[48306:c07] -[MGXMPPManager xmppStream:socketDidConnect:] [Line 243] XMPP Stream Socket did connect
2012-08-29 01:54:47.768 medigram[48306:c07] -[MGXMPPManager xmppStream:willSecureWithSettings:] [Line 250] XMPP Stream willSecureWithSettings:{
}
2012-08-29 01:54:48.109 medigram[48306:c07] -[MGXMPPManager xmppStreamDidSecure:] [Line 302] XMPPStream Did secure
2012-08-29 01:54:48.186 medigram[48306:c07] -[MGXMPPManager xmppStreamDidConnect:] [Line 307] XMPP Stream Did Connect
2012-08-29 01:54:48.186 medigram[48306:c07] -[MGXMPPManager xmppStreamDidConnect:] [Line 315] Error authenticating with password: xxxxxx : Error Domain=XMPPStreamErrorDomain Code=1 "Please wait until the stream is connected." UserInfo=0x8514d70 {NSLocalizedDescription=Please wait until the stream is connected.}

The interesting thing is that xmppstream thinks it's not connected, even though the authenticatewithpassword function is being called from the xmppStreamDidConnect delegate function.

jonasman

yding did you try without using the secure method?

It could be a bug with the secure feature that is not setting all the variables correctly.

Yuhao Ding

jonasman, we ended up fixing it with sarsonj's method. Changing the security didn't seem to help.

jonasman

Can you provide the code you have implemented?

jonasman

any news in this topic?

It seems that the rechability is the way to go, what about the integration with that class and XMPPStream/reconnect or even in the async socket?

Alberto Sendra

I'm having the same problems. When leaving the app for a long time, or even in the background, It sometimes randomly loses the connection and can't reconnect. What's the best way to force a reconnection?

jonasman

I think the problem is with the async socket that doesn't care about the reachability at all.

misha2400

so, was there any development in this case or should I use sarsonj's workaround?

misha2400

Ok, the workaround does help when app is activated, but when it's in background it still doesn't reconnect.

basants
Paul Melnikow

What code do you run when you enter background?

misha2400

No code at all in AppDelegate's applicationDidEnterBackground, should I have something specific there?
I just keep being connected to xmpp server and listening for messages.

Paul Melnikow

I think you need to request permission to keep running while in the background, or else your app is suspended shortly after. This is Apple's documentation on background execution.

misha2400

I have "Location" and "VoIP" in required background modes in Info.plist, I thought this is enough.
Application runs for hours in background without any problem when there's uninterrupted access to data network. It's only when the network is temporary unavailable that it has problem reconnecting in background.
Is it possible that once app is disconnected, it automatically stops to qualify being "VoIP" and is suspended by iOS?

Paul Melnikow
misha2400

I'll try that, thanks. I also found that I may need to implement setKeepAliveTimeout and, possibly, use beginBackgroundTaskWithExpirationHandler. Will try all that later.

basants
misha2400

The other observation that I have is that when I turn on location updates, application seems to recover nicely from airplane mode, so I guess the problem is indeed related to app being suspended by OS.

basants
misha2400

Here's how I understand it: when your app is in background mode, there's only certain events that can "wake it up" to do some processing - for VoIP this event would be some incoming traffic on the socket, for location app - some update in location. But when VoIP socket is closed, there's no way it can receive incoming traffic, so there's nothing that can "wake up" your app. If location update comes and wakes it up, it has a chance to restore the socket, that's why it recovers.
Now, setKeepAliveTimeout supposedly also can wake up your app for, like, 10 sec, so if you manage to connect to server during that time and return from the handler - you're ok, if not - your app is suspended until you bring it to front manually. However beginBackgroundTaskWithExpirationHandler can, supposedly, increase that time interval to 10 minutes.

basants
Paul Melnikow
misha2400

Do you mean Reachability? Did that, don't get notified.
I do get notified when data connection is lost, but never when it's restored, unless I bring the app back into foreground mode. I guess it's not meant for background mode at all.

jonasman
basants
misha2400

Update: setKeepAliveTimeout helped, it connects me back to the server within 10 minutes. This is ok for me, if you want to connect immediately once data network is available, you will need to find another solution. That solution definitely exists, because I can see VoIP programs restore their connection in background within seconds after device comes back from Airplane Mode.

Bradford Toney

What do you have your timeout set to?

misha2400

600.
Actually I just looked at my logs and I see the interval between keepAlive handler calls varies and sometimes it's less than 10 minutes and sometimes it's several hours. So, I guess I still have no idea how it actually works, but it definitely keeps my client connected to server, which is all I care about.

basants
Bradford Toney

We had our QA firm look at the issue, it appears that when the user is changing connections we have the most issues.

basants
Bradford Toney

After a significant amount of digging, I think i've narrowed it down to a specific issue in CocoaAsyncSocket. robbiehanson/CocoaAsyncSocket#131

jonasman

yeah, i have been telling that the bug is for sure in the Asyncsocket.
Now to find the solution it is not that easy

jonasman

In my case i remade the module and adjusted it to my case.
In short:

I added the rechability code from apple. And keep it running all the time instead of when there is a disconnect.

My logic:
Try reconnect with timer when connection fails. After authenticated stop timer.
When stream error, start reconnect.
If wlan/3g changes, disconnect and reconnect.
if no iternet, stop the reconnect timer until the internet comes back, when it comes back start the reconnect again.

With this logic change i was able to cover all of the reconnect problems and internet problems.

misha2400

jonasman, how do you keep reachability running when the program is in the background mode? In my tests reachability doesn't wake your program up when network status changes.

jonasman

I dont use background mode.
I only use the background task ( beginBackgroundTaskWithExpirationHandler ). In this case it works.
But I dont keep my app running forever, I just use it to complete tasks or other small things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.