robbiehanson / XMPPFramework

An XMPP Framework in Objective-C for Mac and iOS
Other
5.91k stars 2.09k forks source link

XMPPReconnect doesn't always work correctly #101

Open sarsonj opened 12 years ago

sarsonj commented 12 years ago

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 commented 12 years ago

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?

bluemoon commented 12 years ago

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

YDing commented 12 years ago

I'd like to see the fix as well.

ghost commented 12 years ago

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

sarsonj commented 12 years ago

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.

YDing commented 12 years ago

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 commented 12 years ago

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.

YDing commented 12 years ago

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

jonasman commented 12 years ago

Can you provide the code you have implemented?

jonasman commented 11 years ago

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?

asendra commented 11 years ago

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 commented 11 years ago

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

misha2400 commented 11 years ago

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

misha2400 commented 11 years ago

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

basants commented 11 years ago

I have tested whats app for ios. Even that wont connect in background once the internet connectivity is gone and comes back. However KIK messenger does connect. Weird problem.

On Tue, Feb 5, 2013 at 7:07 PM, misha2400 notifications@github.com wrote:

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

— Reply to this email directly or view it on GitHubhttps://github.com/robbiehanson/XMPPFramework/issues/101#issuecomment-13129364.

paulmelnikow commented 11 years ago

What code do you run when you enter background?

misha2400 commented 11 years ago

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.

paulmelnikow commented 11 years ago

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 commented 11 years ago

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?

paulmelnikow commented 11 years ago

Just did some digging, and it looks like you might also have to enable VOIP for the socket. There's a method -[GCDAsyncSocket enableBackgroundingOnSocketWithCaveat:] which does this but it doesn't look like it's used by the framework. You could try modifying XMPPStream to invoke that method and seeing if that makes a difference.

misha2400 commented 11 years ago

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 commented 11 years ago

[GCDAsyncSocket enableBackgroundingOnSocketWithCaveat:] method is called by enableBackgroundingOnSocket which we are setting to true. Also i didn't find nay method with the name of beginBackgroundTaskWithExpirationHandler. setKeepAliveTimeout looks promising, will test tomorrow when i have a device.

Apple says the backgrounding of voip will work only when the socket is connected. Will dig the link and share.

On Wed, Feb 6, 2013 at 12:06 AM, misha2400 notifications@github.com wrote:

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

— Reply to this email directly or view it on GitHubhttps://github.com/robbiehanson/XMPPFramework/issues/101#issuecomment-13144113.

misha2400 commented 11 years ago

This is the most complete posting I found related to this.

http://stackoverflow.com/questions/5987495/how-to-maintain-voip-socket-connection-in-background

misha2400 commented 11 years ago

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 commented 11 years ago

Turn on location updates ? Like setting some property in plist or general location updates of iOS device from settings ?

I wonder when we are able to receive messages when the app is in background, why wont it reconnect automatically. I have tested my app, it was kept for almost 24 hours in background and there wasn't any internet disruption, it was working fine (able to receive messages). So the normal backgrounding is not an issue, the main issue is when the socket has been disconnected due to internet disconnection and the app is in background.

On Wed, Feb 6, 2013 at 12:27 AM, misha2400 notifications@github.com wrote:

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.

— Reply to this email directly or view it on GitHubhttps://github.com/robbiehanson/XMPPFramework/issues/101#issuecomment-13145218.

misha2400 commented 11 years ago

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 commented 11 years ago

Thats correct because I tried but calling a function using NSTimer when the app was in background, and it didn't work. Will try with beginBackgroundTaskWithExpirationHandler once I have the device tomorrow.

On Wed, Feb 6, 2013 at 12:56 AM, misha2400 notifications@github.com wrote:

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.

— Reply to this email directly or view it on GitHubhttps://github.com/robbiehanson/XMPPFramework/issues/101#issuecomment-13146803.

paulmelnikow commented 11 years ago

You know, another thing to try is to register for the connection-related notifications when entering background – the ones which XMPPReconnect needs.

misha2400 commented 11 years ago

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 commented 11 years ago

You wont get anything via rechability, because you loose the callbacks when the reconnect module asks for them.

The bug in in the cgd async socket. I tried to debug it but i couldnt find anything.

Enviado do meu iPhone

No dia 05/02/2013, às 21:54, "misha2400" notifications@github.com escreveu:

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.

— Reply to this email directly or view it on GitHub.

basants commented 11 years ago

Reachability doesn't work in background, so that cant be used.

On Wed, Feb 6, 2013 at 1:26 AM, jonasman notifications@github.com wrote:

You wont get anything via rechability, because you loose the callbacks when the reconnect module asks for them.

The bug in in the cgd async socket. I tried to debug it but i couldnt find anything.

Enviado do meu iPhone

No dia 05/02/2013, às 21:54, "misha2400" notifications@github.com escreveu:

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.

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHubhttps://github.com/robbiehanson/XMPPFramework/issues/101#issuecomment-13148481.

misha2400 commented 11 years ago

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.

bluemoon commented 11 years ago

What do you have your timeout set to?

misha2400 commented 11 years ago

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 commented 11 years ago

So if we set the setKeepAliveTimeout, our client will be connected as soon as the internet is back and our app is in the background ? (if network is up within 10 mins)

And yes skype does connect in background, so does KIK messenger, so there has to be a solution for that. Thanks for the update though.

bluemoon commented 11 years ago

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

basants commented 11 years ago

Just an update, Skype uses push notification, so does KIK messenger to reconnect in background.

How we tested it ? Log into KIK messenger, kill it and send messages, you will still receive them. Skype uses push only for incoming voice calls. This basically leaves us with integrating push notification with openfire server if we want the auto reconnect functionality in background.

On Thu, Feb 14, 2013 at 4:17 AM, Bradford Toney notifications@github.comwrote:

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

— Reply to this email directly or view it on GitHubhttps://github.com/robbiehanson/XMPPFramework/issues/101#issuecomment-13523036.

bluemoon commented 11 years ago

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

jonasman commented 11 years ago

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 commented 11 years ago

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 commented 11 years ago

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 commented 11 years ago

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.

chauhan1009 commented 10 years ago

I am working on chat app using xmpp framework. I am facing connection issue on 3G network when network goes off or i put the device on airplane mode the application does not connect again it try to reconnect but connection never goes successful. I had tried all the options mention in the post buy unfortunately none of them is working in my case.

the application is working fine on WiFi network automatically reconnect on network failure, when network come again.

Kindly help me out to fix the reconnection issue on 3G network. Looking for kind help

Regards, Chauhan

guptatarun84 commented 9 years ago

So any luck to make XMPP stream connected to server, while application is in background. I got the app disconnected after 3 mins and no mechanism helped that can make the application alive other then calling it to foreground.

Regards, Tarun