NSURLConnection SendAsynchronousRequest not working without Wi-Fi - ios

Requests don't seem to be sent when in 3G. The code is called and it returns to the callback with a -1001 error and the following message: "(The request timed out.)"
Protocol is HTTP, not HTTPs.
Code works fine in Wi-Fi.
Wireshark on the server does not show any incoming data when app is in 3G (but data is received when in Wi-Fi).
After network inspection in Instruments: request is shown but no data / packets out.
Code Below:
self.request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.route]];
[self.request setHTTPMethod:self.httpMethod];
self.request.timeoutInterval = XX.f;
[NSURLConnection sendAsynchronousRequest:self.request
queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// Stuff actually getting called but with -1001 error code (only when NOT in Wi-Fi)
}

It seems that OSX 10.10 Beta can corrupt the network privileges of an app when installing from XCode.
The issue can be worked-around by completely uninstalling the app and rebooting the phone (pressing home and power button simultaneously).

The error code you get (-1001) resolves to NSURLErrorTimedOut, which means your request timed out. I recommend you check your firewall (at the server-end). Is your server accessible from your phone? Is port 80 accessible from your phone? Note that the IP address of your phone when you're using WiFi differs from the IP address you get using 3G.

Related

Check if Internet access is available

In my app I want to make a network call only if I can access the internet.
Note: I'm connected to a WiFi spot that doesn't have Internet
I want to test if Internet is available. I tried using Reachability as described here and I also tried a simpler solution as described here
The problem is that with Reachability is that it returns that the Internet is reachable when it's not. The other solution takes too much time to give a response. I tried to set timeout intervals for the request and the session, but it's getting ignored.
How can I test for internet reachability in case I'm connected to a wifi with no Internet?
Here some code that I use:
- (void) postAsyncTaskWithUrl:(NSString*)urlString
andType:(NSString*)requestType
andToken:(NSString*)token
andPropertiesObject:(id)propObject
urlEncoded:(BOOL)isUrlEncoded
withSuccess:(nullable void(^)(id _Nullable))success
andFailure:(nullable void(^)(id _Nullable))failure
{
internetReachableFoo = [Reachability reachabilityWithHostname:#"www.google.com"];
__weak typeof(self) weakSelf = self;
// Internet is reachable
internetReachableFoo.reachableBlock = ^(Reachability*reach)
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlSt];
[request setTimeoutInterval:20]; //Ignored ... WHY?
NSURLSessionConfiguration *sessionConfigurations = [NSURLSessionConfiguration defaultSessionConfiguration];
[sessionConfigurations setTimeoutIntervalForRequest:20]; //Ignored ... WHY?
[sessionConfigurations setTimeoutIntervalForResource:20]; //Ignored ... WHY?
// NSURLSession *session = [NSURLSession sharedSession];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfigurations];
[[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}
}
}
Despite this being something that was historically done in the past, I don't believe that it's worth trying to check if the network is reachable, as it isn't something that's reliable or something that should be done before making a request in almost all cases now.
According to Apple's official documentation:
Always attempt to make a connection. Do not attempt to guess whether
network service is available, and do not cache that determination
Similar blog post from Jared Sinclair on this topic, using SCNetworkReachability (which is what the Reachability library uses under the hood):
SCNetworkReachability should only be used to influence what you do about a network request that has already failed, not an initial request that has yet to be attempted. Use a negative status to determine whether or not you attempt an automatic retry, or to tweak the user-facing language of an alert. Use a positive status to consider retrying an earlier failed request. Never prevent a user-initiated request from being attempted just because SCNetworkReachability thinks there’s not a reachable network
Borrowing from a recent Reddit thread:
Reachability is one or "these topics" in iOS world. What does it mean
that the Internet is reachable? Even if you check network interfaces,
you may not be able to reach apple.com or google.com. Even if you
reach Google, you may not be able to reach your on-prem server or
cloud. If you check whether you can reach your server of interest, why
not to send a request straight away?
TL;DR: You probably want an NSTimer.
In my app I want to make a network call only if I can access the internet.
This is not a meaningful statement. There is no test you can perform that reliably means you can "access the internet" (despite the existence of NSURLErrorNotConnectedToInternet, which doesn't actually mean what it says). For example, your code is trying to treat "www.google.com" as "the internet." But it is completely possible to have a network that permits packets to go to www.google.com, but nowhere else. Or to permit ICMP packets, but not HTTP packets. Or to permit HTTP packets, but not on certain ports. Such network configurations are not just possible, they're common, and in various ways they all can look like "not on the internet."
The only thing you can answer is "can I send a packet to a specific host and receive a packet in return?" It's not even possible to know whether you can just send a packet. If you don't get something in return, you don't know if your packet was delivered or not.
Reachability answers the question "if I tried to send a packet, would my local network stack even try?" It is basically the question of whether there is a first-hop available in the routing table. It doesn't mean you can actually connect; it can only tell you that it absolutely won't.
The timeouts you're using are based on idle-time on a session. But you never start the session, so it never idles. The timeout you're looking for is the TCP timeout, which I expect to be 4 minutes. NSURLSession can't configure it.
If you want a wall-clock "start-to-finish" timeout, then you need to run it yourself with a Timer.
If you try to load http://captive.apple.com it will return hardcoded string “Success” as a body if internet works or will redirect / fail. You can check for response starts to be 200 and body to be “success”. That’s what Apple is using to automatically show the credentials window when connected to airport like WiFi’s
Saying that
a) there’s no foolproof solution
b) you will be wasting user’s data (might be ok in your use case?)

Network connection lost when uploading large videos

I am developing an video sharing app. When I am trying to upload videos larger than 10MB NSURLConnection get lost and I got error NSURLErrorDomain Code=-1005 "The network connection was lost." . Video, less than 10 MB are uploading.Can resolution of video be an issue here?? Resolution of my video is 1280*720 .
Can anyone help me to understand issue here. This is my code for connection
NSString *urlString = [[NSString alloc]initWithString:[NSString stringWithFormat:WEBSERVICE_URL]];
urlString=[urlString stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setHTTPShouldHandleCookies:NO];
[request setTimeoutInterval:100];
[request setHTTPMethod:#"POST"];
This is not duplicate of NSURLConnection GET request returns -1005, "the network connection was lost" because
I am not using third party library for connection and not using simulator. I had tried every thing from that answer.
You might be hitting various timeouts—either the NSURLConnection timeout or a timeout on the server side. iOS may ignore the timeout value you specify, BTW. Or you could just be losing the network connection because your device decided to power down the cellular or Wi-Fi hardware to conserve power. Hard to say which. Or your Wi-Fi connection could have dropped because it missed too many beacons from the access point for some reason. Or....
My advice would be to upload large files a piece at a time, and then assemble the pieces on the server. That way, when (not if) the connection fails, you can re-upload the chunk that only partially transferred, and then continue uploading additional chunks until you've uploaded the whole thing.
See also the Content-Range HTTP header. Obviously, this requires your server-side code to support that functionality, but it is worth the extra effort. :-)
BTW, you forgot to set the Content-Type header.

NSURLConnection randomly fails until device reboot

I have been struggling with an issue where NSURLConnection calls instantly fail. The device needs to be rebooted entirely or Flight Mode needs to be toggled on/off to resolve the problem. Restarting the app (swipe up) alone does not help.
Some facts:
-All URLs are HTTPS, TLS 1.2 compatible with Forward Secrecy. There are no issues with ATS and iOS 9. The error has been present since iOS 7 and remains on 9.2.
-No third party frameworks are used by the app. I use only native NSURLConnection calls that always work, except for when this odd situation occurs.
-No infrastructure/network issues - other devices on same networks (same WiFi for instance) work in the same app at the same time. Going to/from 3G/Wifi makes no difference.
-I always implement willCacheResponse to return nil.
-The service is hosted on AWS Elastic Beanstalk, so some suggested that it might be a DNS caching issue in case of IP address changes - this seems unlikely to me and should trigger multiple errors at once on different devices, which I have never seen.
-The method called is didFailWithError, instantaneously, as if there were no Internet connection on the device at all - all other apps work, however.
-The website that hosts the API used by the app can be browsed with no problems at all times. The website actually makes the same requests to fetch data.
The error code returned is -1003, kCFURLErrorCannotFindHost. I've been following a thread on Git dealing with the same issue to no avail. https://github.com/AFNetworking/AFNetworking/issues/967
I tried using NSURLRequestReloadIgnoringCacheData for all my requests, but that did not help.
With this information, will anyone care to venture a guess what I might be doing wrong? I added the bounty because I have no idea how to approach this problem - especially because it's so inconsistent. And it is definitely not a legitimate error (that is, that the domain could not be found), as the service is operating fine while this happens on random clients.
I create my request with a static method that looks like this. It's been stripped of some non-public info, but basically it just performs a POST request with JSON data. [Controller getSQLHost] just returns a URL - the base domain.
+(NSURLConnection*)initiatePOSTwithJSONDictionary:(NSDictionary*)dictionary toURL:(NSString*)urllocation withDelegate:delegate {
NSMutableDictionary *connectionDictionary = [[NSMutableDictionary alloc] init];
if (dictionary) {
[connectionDictionary setObject:dictionary forKey:#"input"];
}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:connectionDictionary options:kNilOptions error:nil];
NSURL *url = [NSURL URLWithString:[[Controller getSQLHost] stringByAppendingString:urllocation]];
NSString *postLength = [NSString stringWithFormat:#"%i", (int)[jsonData length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:jsonData];
return [[NSURLConnection alloc] initWithRequest:request delegate:delegate];
}
Does you delegate implement connectionShouldUseCredentialStorage ? (or respond with YES)
I think the device's keychain is used when this method returns yes which may explain the persisting failure beyond the life time of the running application and why rebooting or otherwise resetting network connectivity "fixes" it. If an authentication failure has been recognized once, it may linger in the key chain for a little while which would then respond immediately without actually going to the server.
What would cause the authentication to register as a failure in the keychain in the first place may depend on a variety of factors. It could be as simple as a typo in the saved password or more convoluted such as some certificate expiration preventing the SSL layer from establishing a secure link.
You're creating NSURLConnections on the current runloop. How many are active at any one time? Have you considered using an NSOperationQueue so that you don't get bitten by load bugs?
Is your delegate thread-safe? If not, that could explain the sporadic-ness of the bug.
You say you don't see the problem often, but others do. Can you borrow their devices and maybe even them and their usage patterns and thus get to see the problem more often?

Error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."

I am working on an application in Xcode 6.1, iOS 8.1; the application was working completely fine till 2 days before, but today as I executed it I got an error in the web service & the error is printed below.
Error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed
out." UserInfo=0x7c6899b0 {NSErrorFailingURLStringKey=,
NSErrorFailingURLKey=, NSLocalizedDescription=The request timed
out., NSUnderlyingError=0x7c688f60 "The request timed out."}
I had used AFNetworking 2.x and following code snippet to make network call:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes=[manager.responseSerializer.acceptableContentTypes setByAddingObject:#"text/html"];
[manager POST:<URL>
parameters:<parameters>
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
NSError *error = nil;
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(#"Error serializing %#", error);
}
NSLog(#"Dictionary %#", JSON);
NSLog(#"Success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
UPDATE: I had done quit/relaunched the iOS Simulator.app, reseted content & settings, but nothing worked.
There was no issue in the code. I guess the simulator internally was not able to connect to the internet, so that is why it was not able to connect to the server after providing various timeout intervals. But it worked completely fine when I executed another day. Thanks to #Andrew Jaffee for helping me to find this issue.
iOS Simulator -> Reset Content and Settings; worked for me
Had this problem and had a different resolution so I thought I'd add it here:
Basically, I was sending some parameters when it should have been a clean GET request. Deleted the parameters, GET request worked just fine.
I was calling local server connection and was getting this error. I was using different network in my device and phone. When I connected both to same wifi, it worked.
This can happen if your network configuration changes while the simulator is running. Please reboot the simulator runtime (eg: quit/relaunch the iOS Simulator.app) and that will likely fix your problem.
If the problem persists, please update your question to indicate that the issue you are experiencing is not this known problem. Thanks.
Ok, I lost a lot of time investigeting similar issue.
In my case the problem was strange (bad?) firewall on the server. It was banning device when there was many (not so many) requests in short period of time.
I believe you can do easy test if you are facing similar issue.
Send a lot of (depends of firewall settings) requests in loop (let's say 50 in 1 second).
Close/Kill app (this will close connections to server)
(OPTIONAL) Wait a while (lets say 60 seconds)
Start app again and try send request
If you now got timeout for all next requests, you probably have same issue and you should talk
with sever guys.
PS: if you don't have access to server you can give user info that he should restart wifi on device to quit that timeout loop. It could be last resort in some cases.
I am working for an enterprise company so we use VPN for connecting our web services.
My computer connected to VPN so my simulators (xcode simulator) could VPN but my own iPhone (real phone) was not connected to VPN so the issue occur for this reason your simulator should be connected to URLs
Kidly check your URL in the simulator.
You must close the firewall and it will work. I tried this solution and it worked for me.

IOS Checking Active internet connection even connected via WIFI without internet

Please help me out how to check internet connection in iPhone.
I tried by checking the Apple's reachability framework, but it is not returning if connected via WIFI without internet.
What I am getting is reachable via wifi.
The other option I tried is making a synchronous request with google.com etc and checking the response code.
Is there any other way to check so that I can avoid making a url request and checking the response code.
Thanks in advance.
Check if wifi reachable (using Apple's reachability), and then make request to ensure host is reachable.
// wifi checking code here
//...
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:#"http://yourServer.com/someLightFile.html"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (!error) {
// Your host is reachable
}
}] resume];

Resources