Server Unreachable Errors with NSURLSession - ios

I have been using NSURLSession on my app since iOS 7 first came out. Recently some users started complaining that some features weren't working, after having a deep look at their logs I noticed that several network requests failed with error:
{NSLocalizedDescription=Server is unreachable. Check your network connection and try again., NSUnderlyingError=0x174c4c300 "The operation couldnât be completed. (NSURLErrorDomain error -1001.)"}
As I have no idea what the problem might be, I added some code to resolve the hostname when the requests failed:
NSString *urlString = [url host];
const char *hostUrl = [urlString UTF8String];
struct hostent *remote_entity = gethostbyname(host);
if (!remote_entity) {
DDLogWarn(#"DNS Lookup failed! Cant resolve Hostname: %# for request: %#", [url host], [url description]);
return nil;
}
else {
// Get address info from host entry
struct in_addr *remote_in_addr = (struct in_addr *) remote_entity->h_addr_list[0];
char *sremote_in_addr = inet_ntoa(*remote_in_addr);
NSString* hostIP = [NSString stringWithUTF8String:sremote_in_addr];
DDLogWarn(#"Hostname: %# IP: %# (original request: %#)", [url host], hostIP, [url description]);
return hostIP;
}
After deploying this change, I can see in my logs that even when the request fails ( with NSURLErrorDomain error -1001) I can still resolve the hostname.
I don't understand how this could happen, I can always resolve the hostname but the requests still fail somehow. Please note that I can't reproduce this and this bug only manifests from time to time with no predictable pattern.
Any ideas of how to proceed to fix this for good ? Should I implement a packet tracking mechanism in my apps (similar to traceroute on unix)? Could this be a misconfiguration on my servers since requests to other hosts (like Amazon S3) never fail? I'm using Heroku by the way.
Thanks in advance,
Ze

I recommend looking at Apple's Networking Overview Guide, specifically the Handling Network Problems Gracefully section.
When working with networking code, you have to account for the fact that sometimes things go wrong. This is especially true on mobile devices where cellular connections can come and go. In the above mentioned section on handling network problems, Apple makes recommendations for automatically retrying requests and detecting network changes using the SCNetworkReachability API. I recommend using that strategy in your networking code to give your users the best experience.
In your specific case, it appears the -1001 error is indicating a network timeout. The host lookup is succeeding, but for whatever reason, the network request did not make it to the server. In that case, a retry would make sense.

Related

HTTP::ConnectionError & Errno::EHOSTUNREACH Errors in Rails App

I'm working on a Rails app and here are two important pieces of the error message I get when I try to seed data in my database:
HTTP::ConnectionError: failed to connect: Operation timed out - SSL_connect
Errno::ETIMEDOUT: Operation timed out - SSL_connect
Here is my code, where I'm pulling data from a file, and creating Politician objects:
politician_data.each do |politician|
photo_from_congress = "https://theunitedstates.io/images/congress/original/" + politician["id"]["bioguide"] + ".jpg"
HTTP.get(photo_from_congress).code == 200 ? image = photo_from_congress : image = "noPoliticianImage.png"
Politician.create(
name: "#{politician["name"]["first"]} #{politician["name"]["last"]}",
image: image
)
end
I put in a pry, and the iteration works for the first loop, so the code is OK. After several seconds, the loop breaks, and I get that error, so I think it has something to do with the number of HTTP.get requests I'm making?
https://github.com/unitedstates/images is a Git repo. Perhaps that repo can't handle that many get requests?
I did some Google'ing and saw it may have something to do with "Request timed out" error? My having to set up a proxy servers? I'm a junior programmer so please be very specific when responding.
*EDIT TO ADD THIS:
I found this blurb on the site where I'm making get requests to cull photos (https://github.com/unitedstates/images), that may help?
Note: Our HTTPS permalinks are provided through CloudFlare's Universal SSL, which also uses "Flexible SSL" to talk to GitHub Pages' unencrypted endpoints. So, you should know that it's not an end-to-end encrypted channel, but is encrypted between your client use and CloudFlare's servers (which at least should dissociate your requests from client IP addresses).
by the way, using "Net::HTTP" instead of the "HTTP" Ruby gem worked. Instead of checking the status code, i just checked to see if the body contained key text:
photo_from_congress = "https://theunitedstates.io/images/congress/original/" + politician["id"]["bioguide"] + ".jpg"
photo_as_URI = URI(photo_from_congress)
Net::HTTP.get_response(photo_as_URI ).body.include?("File not found") ? image = "noPoliticianImage.png" : image = photo_from_congress

SocketRocket not throwing error on connecting invalid host

I am developing an iPhone App (using iOS 9 beta). I am using Socket connections for which I am using SocketRocket client library. But when I try to establish a wss connection with some invalid host name, I don't get any error on opening socket, connection or even on sending data, so whenever I try to run program it seems like information about host is correct and data is being sent.
I am using current version of SocketRocket library, I have added SRWebSocket.h, SRWebSocket.m and SocketRocket-Prefix.pch files in my project. Following is the part of code I have:
NSString* url = [NSString stringWithFormat:#"wss://%#/myproject/stream?data=%d", webSocketHost, dummyData];
SRWebSocket *webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
webSocket.delegate = self;
// open websocket
[webSocket open];
// send message to websocket
[webSocket send:[self getJSONString:parameters]];
// close websocket
[webSocket close];
webSocket = nil;
If I pass some random host name like "abc.def" for the variable webSocketHost, it will still run smoothly (I have try-catch blocks surrounding above code, and I also tried to put break points in between and debugged it line by line).
And even when I don't have any internet connection to my phone, there aren't any errors thrown.
Does anyone know what could be the problem?
Thanks!
Are you implementing this delegate method? The library won't throw an error when you call [webSocket open], it will call this method if it can't connect to the endpoint sometime in the future since establishing a connection is an asynchronous operation.
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;

Creating sockaddr_in for CocoaAsyncSocket Getting Invalid IPv4 address

I'm having trouble connecting to a Java socket server. I know the server is working because I connect via a Java socket. I'm using the CocoaAsyncSocket library to make a client connection from an iOS device. I've tried the following,
[socket connectToHost:#"XXX.XXX.X.XXX" onPort:9090 error:&err]
method but the server never sees the client connect and the client (CocoaAsyncSocket) thinks its connected. So thats no good, then I realized there was another connection method available.
So I'm thinking I should be using the connectToAddress method instead. I've used this post as a reference for my current code but I'm still getting an error and I'm not sure why. The only difference from my version and the suggested version is for the length they use sa_len and I was getting a error and xCode wanted to switch it to sin_len, so I did. I'm really new to direct socket connections so bear with me.
GCDAsyncSocket *socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
struct sockaddr_in ip4addr;
ip4addr.sin_family = AF_INET;
ip4addr.sin_port = htons(9090);
inet_pton(AF_INET, "XXX.XXX.X.XXX", &ip4addr.sin_addr);
NSData *discoveryHost = [NSData dataWithBytes:&ip4addr length:ip4addr.sin_len];
NSError *err = nil;
if (![socket connectToAddress:discoveryHost error:&err])
{
NSLog(#"I CANNOT CONNECT!");
}
else
{
NSLog(#"IM CONNECTED!");
}
The connection fails and the error is,
Error Domain=GCDAsyncSocketErrorDomain Code=2 "A valid IPv4 or IPv6 address was not given" UserInfo=0x8bac880 {NSLocalizedDescription=A valid IPv4 or IPv6 address was not given}
I changed
NSData *discoveryHost = [NSData dataWithBytes:&ip4addr length:ip4addr.sin_len];
to
NSData *discoveryHost = [NSData dataWithBytes:&ip4addr length:sizeof(ip4addr)];
and it fixed that error I was getting. However, the reason I wasn't able to connect via the connectToHost method was due to my server socket code. I have two server sockets accepting connections. I commented out the second and it worked just fine. I'm guessing it was due to the thread being locked by the second socket or something.

initWithContentsOfURL returns nil only in iOS 5.x [duplicate]

I have been stuck with this for a while and don't seem to get around this.
I am trying to read the contents of an URL as a string from an URL, But i get a weird
Error -> Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)"
My code :
fetchedString = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"www.example.com/iphone"] encoding:NSUTF8StringEncoding error:&error];
NSLog(#"%#",fetchedString);
// if there is something wrong with the URL
if (error) {
NSLog(#"Error -> %#", error);
return ;
}
What am I doing wrong? I tried using getting as NSData as well, but I get null back.
Yes, the URL is missing the scheme: "http://".
"Error -> Error Domain=NSCocoaErrorDomain Code=256"
For the error code check the Apple documentation:
NSError codes in the Cocoa error domain.
NSFileReadUnknownError = 256,
NSFileReadUnknownError
"Read error, reason unknown"
Not that the error definition is very helpful. :-)
Also do not check if error is nil to determine if there is an error, check the return value for nil. error is not guaranteed to be nil on successful execution.
I had a similar problem accessing files located on my device. I followed NSURL isFileURL always returns NO
and used [NSURL fileURLWithPath] instead of [NSURL URLWithString] - this worked!
I got this error (Error Domain=NSCocoaErrorDomain Code=256) as soon as our ssl certificate expired. that may not help you but could help someone else.
Sandboxing
If you're using sandboxing in your app, you might want to check that com.apple.security.network.client is set to YES. It's in the the General tab of your Target in Xcode 5 under
Network: Outgoing Connections (Client)
Also be aware that if you see a code 257 when trying to reach a file:/// url, that's also probably because of sandboxing, but this time rather the File Access part. Because I didn't want to open it to anything else than `com.apple.security.files.user-selected.read-write'
User selected files
I preferred to use A Dead Simple Fileserver and use http://localhost:3000 when in Debug mode.
More reasons that might be causing this specific error:
SSL is misconfigured on the server
The server redirects (301) the http URL to https (see #1)
App transport security also uses this code for blocked requests.
I got the same error. The above marked answer is perfect. But in my case, I had the "http://" in the url but had to add the port number in the url request since there is a service running on a specific port that is actually responding to your request.
#"http://example.com:8084/yyy.zzz"
I got the same error, the above solution didn't work for me, in my case i was calling dataWithContentsOfURL from within a UNNotificationServiceExtension so i had to update the info.plist file of the UNNotificationServiceExtension with the app transport security entries.

NSData dataWithContentsOfURL:options:error: invalid server response

We've generally had success loading JSON-encoded data from our server using:
NSError* error;
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:path]
options:NSDataReadingUncached
error:&error];
(On a background thread to avoid blocking the main thread.) But, with increasing server load, we've recently seen an invalid but non-error (error == nil) server response of:
<html><body><script>document.cookie='ggggggg=00268082ggggggg_00268082;
path=/';window.location.href=window.location.href;</script></body></html>
A retry will often result in successful download of expected JSON-encoded data; the problem appears to be server-side. Three questions:
1) Does anyone recognize this server response?
2) Is our server attempting to create a cookie instead of returning our file/data!?
3) If so, where should we be looking to understand how to avoid this random cookie response from our server?
Based on message board traffic, we were able to confirm that the problem could be reproduced by a variety of means (app, browser, or command line) -- the issue had nothing to do with iOS or our application code. We were able to sporadically reproduce the problem from the command line with curl using the form:
curl -D - your-test-url-here -s
After further investigation by our ISP, they determined that the most likely cause of the invalid HTTP response was from their DDoS attack protection. After they reset the affected server(s), the problem was resolved.

Resources