Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: reachabilityWithHostname YES although it should be NO

I tested different frameworks, e.g.

  • https://github.com/tonymillion/Reachability
  • https://github.com/VerticodeLabs/VCLReachability
  • https://github.com/kstenerud/KSReachability

and I would like to know if a host is reachable. On my iPhone, I set my iMac as proxy (Charles) and block or don't block the connections, but the reachability is always YES. Only if I set a non-existing host, it returns NO. But if the host exists but I block the connection to it, I always get isReachable. Isn't there a way to check if the host is really reachable?

If I try with KSReachability, I'm doing the following:

self.reachability = [KSReachability reachabilityToHost:@"www.stackoverflow.com"];
self.reachability.notificationName = kDefaultNetworkReachabilityChangedNotification;
self.reachability.onReachabilityChanged = ^(KSReachability *reachability) {
    NSLog(@"isReachable: %i", reachability.reachable);
};

I always get isReachable: 1 there with the following configuration:

  • connected to Wifi
  • configured my iMac as HTTP-Proxy
  • blocking www.stackoverflow.com in my Charles Proxy

When I try to reach www.stackoverflow.com in Safari, the page can't be opened (as expected). I would expect the reachability to be false (isReachable: 0) in this case.

EDIT So the most important question for me is - how to achieve the behavior I'm expecting? I.e. that the app continuously checks if the given host is really reachable?

like image 933
swalkner Avatar asked Jun 17 '14 09:06

swalkner


People also ask

When should I show the iOS native permission prompt?

That means that they will need to only show the iOS native permission prompt when they are certain that the user will accept it. Amazon showcases that the notifications are important and time-sensitive.

Why are iOS notifications so hard to send?

Sending notifications to users iOS is tricky. Users are particularly sensitive to spam, which is completely understandable if you’ve ever spent time clearing out useless notifications. Because of this, opt-in rates are really low for iOS permission prompts with little or no context.

What are the best practices for app permissions notifications?

Users are sensitive to the term “notification,” particularly because it bring backs memories of Farmville-style notifications they’d received on their Facebook news feed. A best practice for app notifications is to be able to frame the permissions prompt as something more valuable, so that the user understands the value of granting permissions.


4 Answers

The code statement:

self.reachability = [KSReachability reachabilityToHost:@"www.stackoverflow.com"];

actually calls below method:

SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL,
                                                          [hostName UTF8String]);

SCNetworkReachability reference says:

The SCNetworkReachability programming interface allows an application to determine the status of a system's current network configuration and the reachability of a target host. A remote host is considered reachable when a data packet, sent by an application into the network stack, can leave the local device. Reachability does not guarantee that the data packet will actually be received by the host.

The explanation clears that iOS system doesn't send any request to outside world to check the reachability. It just tells that data packet can leave the device or not. If system were to send the request it automatically means that it is connected to network.

You can verify this by mentioning a valid host like "www.stackoverflow.com" and check in charles (first unblock it) that no request is sent.You can also check with other valid host names like "www.abcdefgh.com" (verify this by running it in Safari and see in charles) it also gives you the reachability but charles shows no request.Also if you put http:// before any valid host, something like "http://www.stackoverflow.com" it will also fails reachability. So it is clear that it is not an outgoing http request. If system has to send a request outside then what's the point of providing the class? A developer could have created a network connection and try to connect to a host and see if it passes or fails.

However it is interesting that if an invalid host like "www.hjjkhkhk.com" is provided iOS system gives reachability as false. Now the question is how iOS system finds a valid or invalid host without sending any query to outside world? May be it is periodically caching a list of DNS ranges??? Highly improbable to me.

like image 116
tarun_sharma Avatar answered Nov 19 '22 11:11

tarun_sharma


In your AppDelegate add this method:

#import "Reachability.h"

-(NSString *)checkNetworkConnectivity
{
    NSString *networkValue;

    Reachability *rc = [Reachability reachabilityWithHostName:@"www.stackoverflow.com"];
    NetworkStatus internetStatus = [rc currentReachabilityStatus];

    if(internetStatus==0)
    {
        networkValue = @"NoAccess";
    }
    else if(internetStatus==1)
    {
        networkValue = @"ReachableViaWiFi";

    } else if(internetStatus==2)
    {
        networkValue = @"ReachableViaWWAN";
    }
    else
    {
        networkValue = @"Reachable";
    }

    return networkValue;
}

Checking if the host is reachable

NSString *netStr = [appDelegate checkNetworkConnectivity];

if([netStr isEqualToString:@"NoAccess"])
{
     [appDelegate callNoNetworkAlert];
}
like image 22
Vinaykrishnan Avatar answered Nov 19 '22 10:11

Vinaykrishnan


Firstly, unless we see some code, we cannot make sure what you're doing, you're doing the right way. However I will assume you are doing it correctly.

Secondly, you should test what FreeNickname has suggested in his comment. Maybe it's not actually unreachable, and the reachability is acting correctly, when you expect a different response.

Last, but very important, from the Reachability docs :

Note: Reachability cannot tell your application if you can connect to a particular host, only that an interface is available that might allow a connection, and whether that interface is the WWAN.

What it means is that, even though your server might not be returning any responses, Reachability does NOT check that. It only checks if your server is available , such that a packet can be sent. What it does with that packet is of no concern to Reachability. If Reachability is able to transmit the entire packet, it assumes your host is reachable. It will return unreachable iff your server is down, disconnected, or does not exist.

like image 34
n00bProgrammer Avatar answered Nov 19 '22 10:11

n00bProgrammer


I would like to add that To listen the Network changes at Runtime, you need to listen to the Notifications that tell you that a Network state has been changed.

This is how you can do this :

  1. Implement a listener in AppDelegate file.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];

  • Now reachabilityChanged will be called when there is a change in Network status (perhaps connectivity of internet connection or it's disconnection). You can do appropriate handling in reachabilityChanged event

like:

- (void) reachabilityChanged:(NSNotification *)note
{
     Reachability* reachability = [note object];

     if (reachability == self.hostReachability)
     {
        isHostReachable = YES;  //A flag to keep track of connectivity
     }

     if (reachability == self.internetReachability)
     {
         isInternetAvailable = YES;  
     }

     if (reachability == self.wifiReachability)
     {
         isWifiAvailable = YES;  
     }

     //If all are true that means we have host and Internet available
     if (isHostReachable && isInternetAvailable && isWifiAvailable) 
     {
          isInternetAvailable = true;
     }
}

Hope this will help you.

like image 24
Jamal Zafar Avatar answered Nov 19 '22 09:11

Jamal Zafar