Reachability lying about disconnected wifi network - ios

I use Stackmob SDK (which will end soon) and I assume they use AFNetworking for reachability. If a device is connected to a wifi network which is disconnected from the Internet, the reachability check will be positive and the following statement will be true:
if ([self.appDelegate.client.networkMonitor currentNetworkStatus] == SMNetworkStatusReachable) {
// reachable
}
How can I fine tune this check to overcome the present limitation? How can I check for real network reachability within this if statement, or is there any better Reachability check out there?

If your question is "can I send data to that host and receive a response", then Reachability can only answer "no" or "maybe". It cannot answer "yes" because there are many connectivity factors that Reachability does not check.
Reachability only checks the first hop. It defines reachability as the ability for packets to leave the device in the direction of that host. If the device is connected to a network that claims to be able to route to that host then Reachability is satisfied. If the router is lying or the host is down or there are unfriendly backhoes in Kansas then Reachability's result will be optimistic.
The only sure way to answer the question "can I send data to that host and receive a response" is to actually attempt to send data to that host and receive a response. Reachability can help you give up when connectivity is definitely not available. If you try and fail, Reachability's network-change notifications can help you decide when to try again without wasting power.

Related

Make an API call even if internet is not available

So I'm working on an IoT app, where I need to configure the hardware by connecting to its WiFi. If I use AFNetworking or URLSession to make the call, they fail with this error message.
"The Internet connection appears to be offline."
I need a way to make the API call to the local Wifi of the hardware by overriding the Reachability check. I'm sure there must be a way to do so, but I can't seem to come across something like that.
Reachability tells you if a certain host is reachable via Wifi. reachability.connection == .wifi test should be enough for that.
However, to know the reachability via that utility, you must know your host's IP within the wifi network, not internet.
What are all IP addresses that your host exposes? They will each belong to a network - internet, wifi, LAN and such.
What you probably need is the correct network utility to tell you that, for example, arp.

Why Apple is not bringing support to check whether a connection has active internet connection?

When I checked the apple Reachability class, it does return true even though the connected network doesn't have an active internet connection. So I'm having few doubts here -
Why is Reachability class made to throw YES if the packet can leave the local device even though it doesn't ensure it is delivered at the endpoint? Are there any special reasons to limit the ability?
Reachability has reachabilityWithHostName method still, YES will be thrown by class even if we add familiar hostname in the same network. If it doesn't ensure endpoint packet delivery why they provided this method?
Is there any other way to check whether there is an active internet connection in the connected network other than Reachability? Do we need to add our custom APIs or logic to tackle this thing?
I did connect an android phone to the same network, it instantaneously notified me the connection has no internet connection.

Is there an event for disconnecting from the internet on iOS?

I have an application that requires an internet connection for a certain library I use (XIMSS for Communigate). It receives status updates from a server and I can't alter the source of the lib. Is there a way to detect that the device disconnected from the internet? I'd like to avoid having to ping a server every x seconds to see if there is still a connection.
Apple's Reachability does this for you. Notifies you as your connectivity changes.
In iOS you can check like that :-
-(BOOL)returnInternetConnectionStatus{
ReachabilityLattest *reach = [ReachabilityLattest reachabilityForInternetConnection];
NetworkStatus internetStatus = [reach currentReachabilityStatus];
if ((internetStatus != NotReachable)) {
return TRUE;
} else {
return FALSE;
}
}
For more detail you can download from here Reachability Sample Code
Hope this helps you !
Note that all the pointers to Reachability are a good start, and you definitely need Reachability, but for a messaging app it is generally not sufficient. Reachability never sends packets. It just tells you whether the device could even try to send a packet if you asked it to. So it basically tells you that you have an IP address and know a gateway. It does not tell you that you could reach the server you care about, and it absolutely does not tell you whether that server can reach you (which is a very important question for messaging apps).
In most cases, if Reachability were sufficient, you wouldn't need Reachability. Apple strongly recommends (and for good reason) that you not check Reachability before sending packets. Just send the packets and deal with the error if it comes. But that doesn't help for apps that have to receive data at random times.
If connectivity is poor (particularly due to poor cell coverage), or if there is a firewall between you and the server, you can easily get positive results from Reachability even though you are no longer getting messages from the server. The only way to detect this situation is to send a packet and receive a packet (i.e. "ping").
Reachability is also not sufficient to notice when your connection changes. For instance, if you change IP addresses (pretty common when you're driving around town), Reachability won't always tell you (it may if you use SCNetworkReachabilityCreateWithAddressPair(); it's been awhile since I've worked on this problem; but the Reachability example code doesn't work this way in any case).
So Reachability is a good first start, but at the end of the day you still require a heartbeat if you want to detect that the server is no longer talking to you. The key thing to remember is that in IP, there is no such thing as "a connection." There are just packets. You can send them and you can receive them. But if you aren't receiving them, there's no way to distinguish "no one is sending them" from "they are not arriving." The illusion TCP gives of "connections" only exists when packets are being exchanged.
(BTW, dealing with network connectivity in a messaging app is probably the hardest iOS code I've ever worked on. Testing is a nightmare. I used to stick my phone in the fridge to cut off its network access. At least now there is the network conditioner…)
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(ReachablilityChange:) name:kReachabilityChangedNotification object:nil];
Add notifier for Reachability Change Notification.This will call the reachabilityChange when the network change occur, In ReachablilityChange function detect
NetworkStatus hostStatus = [hostReachable currentReachabilityStatus];
Get status in hostStatus
if(hostStatus == NotReachable)
{Do your code here;}

How do I force an iOS app to use 3G instead of WiFi?

I want to use a messaging protocol that works fine over 3G, but not over some corporate firewalls. How can my app force the use of the cellular network when it fails to connect over WiFi even in the case that the WiFi network is reachable?
EDIT: After reading through the implementation of the Reachability class I remain unsure whether the two are indeed mutually exclusive. It could well be possible to discover both interfaces via gethostbyname(), which I might try just to see what comes out.
Use getifaddrs to enumerate the network interfaces. Look for ifa_name that starts with "pdp." This will be the cellular interface (e.g., pdp_ip0). Test (ifa_flags & IFF_UP) to make sure the interface is up, and get the IP address from ifa_addr. Then use bind() to bind your socket to that address.
Not sure how you activate the cellular interface if it is not already up. Normally, I just make a high level http call to get iOS to wake up the network, but not sure under what conditions the cellular service becomes active when wifi is also available. I suspect it is usually there as a fallback to the wifi.
http://iphonedevsdk.com/discussion/comment/120957
From the looks of that thread, it seems like its impossible. Your best bet may be to try using the protocol, and saying something like "please disconnect from wifi and retry" if it doesn't work.
This thread says just about the same thing:
how to programatically start 3g connection on iphone?
You can use the Reachability class which apple wrote in order to test whether the network connection is currently over 3G or WiFi, and even to check if a specific resource is available on the network.
You can use any of the socket library to force to use cellular. Find the cellular interface from getifaddrs, pass the interface to the socket function, socket bind will happen with cellular. e.g. CocoaAsyncSocket

Detecting Whether an iPhone has roamed from wifi to 3G or vice versa

G'day Guys,
I've been using the reachability API with reachability status callbacks to determine whether an application is connected over 3G or wifi. It's an application that acts as a voice extension for an existing piece of hardware and as such we're using the VoIP APIs to run in the background and accept calls etc.
Is there a definitive way other than using reachability status callbacks to determine whether you can access a particular IP endpoint or not? I could use an ASIHTTPRequest and then check if it timed out but that may cause potential problems for me in the long run.
I'm not looking for a programmatical answer but more any insights other developers would have on how to manage a roaming between the two in the background if you have a persistent connection. Basically if the device roams over to 3G I need to destroy the session on the device and if it roams back over to Wifi I need to recreate the session.
Any feedback or advice would be welcome.
The Reachability APIs will provide the connection change notifications to your app so that you can know when the connectivity changed from WWAN to wifi. It will not tell you if you've changed from Edge to 3G or LTE unfortunately. The Reachability API also has methods to test reachability to a specific host. So, in your app you can listen for the notifications that the connection method has changed, then when it does change test reachability to your target host and at that time make the decision whether to rebuild the session or leave it intact.

Resources