How to cancel a persistent connection using NSURLConnection? - iphone

Is it possible to destroy a persistent connection that has been created with NSURLConnection? I need to be able to destroy the persistent connection and do another SSL handshake.
As it is now, calling [conn cancel] leaves a persistent connection behind that gets used with the next connection request to that host, which I don't want to happen.

As it turns out, I believe the Secure Transport TLS session cache is to blame.
I also asked the question on the apple developer forums, and got a response from an Apple person. He pointed me to this Apple sample code readme where it says:
At the bottom of the TLS stack on both iOS and Mac OS X is a component known as Secure Transport. Secure Transport maintains a per-process TLS session cache. When you connect via TLS, the cache stores information about the TLS negotiation so that subsequent connections can connect more quickly. The on-the-wire mechanism is described at the link below.
http://en.wikipedia.org/wiki/Transport_Layer_Security#Resumed_TLS_handshake
This presents some interesting gotchas, especially while you're debugging. For example, consider the following sequence:
You use the Debug tab to set the TLS Server Validation to Disabled.
You connect to a site with a self-signed identity. The connection succeeds because you've disabled TLS server trust validation. This adds an entry to the Secure Transport TLS session cache.
You use the Debug tab to set the TLS Server Validation to Default.
You immediately connect to the same site as you did in step 2. This should fail, because of the change in server trust validation policy, but it succeeds because you never receive an NSURLAuthenticationMethodServerTrust challenge. Under the covers, Secure Transport has resumed the TLS session, which means that the challenge never bubbles up to your level.
On the other hand, if you delay for 11 minutes between steps 3 and 4, things work as expected (well, fail as expected :-). This is because Secure Transport's TLS session cache has a timeout of 10 minutes.
In the real world this isn't a huge problem, but it can be very confusing during debugging. There's no programmatic way to clear the Secure Transport TLS session cache but, as the cache is per-process, you can avoid this problem during debugging by simply quitting and relaunching your application. Remember that, starting with iOS 4, pressing the Home button does not necessarily quit your application. Instead, you should use quit the application from the recent applications list.
So, based on that, a user would have to either kill their app and restart it or wait more than 10 minutes before sending another request.
I did another google search with this new information and found this Apple technical Q&A article that matches this problem exactly. Near the bottom, it mentions adding a trailing '.' to domain names (and hopefully IP addresses) for requests in order to force a TLS session cache miss (if you can't modify the server in some way, which I can't), so I am going to try this and hopefully it will work. I will post my findings after I test it.
### EDIT ###
I tested adding a '.' to the end of the ip address, and the request was still completed successfully.
But I was thinking about the problem in general, and there's really no reason to force another SSL handshake. In my case, the solution to this problem is to keep a copy of the last known SecCertificateRef that was returned from the server. When making another request to the server, if a cached TLS session is used (connection:didReceiveAuthenticationChallenge: was not called), we know that the saved SecCertificateRef is still valid. If connection:didReceiveAuthenticationChallenge: is called, we can get the new SecCertificateRef at that time.

Starting with OS X 10.9, NSURLSession is the solution.

First, you should use
[self.conn cancel]
and second, that does just what it says. It cancels itself. If you don't want to use an NSURLConnection after that anymore, it won't do anything and if you'll use it again, you can just set a different request, which will connect to the given server.
Hope that helps.

Related

Website loads inconsistently on mobile only

I have a website being served from a custom webserver, and it loads and works fine when loaded from a laptop/desktop browser, but loads inconsistently on mobile browsers. (In my case I tested specifically Samsung Internet and Chrome on Android)
(The exact behaviour is: load the web page, refresh, and then after a couple of refreshes it will sometimes not be able to load a background image, or any resource on the page at all - but only on mobile browsers)
In case this was just some cached data issue, I've cleared all browser data, restarted my phone, asked friends to try on their devices etc, but I've only been able to reproduce this on mobile devices.
My web server is written using liburing, nginx as a reverse proxy, though I doubt that would be the issue
I read Can Anyone Explain These Long Network Stalled Times? and it ocurred to me that an issue could be me using multiple different HTTP requests to get resources (I've not implemented Connection: Keep-Alive), but I also get this issue on WiFi, and I get the issue even when loading a single asset (such as a background image)
Additional possibly relevant info:
I was initially having a similar issue on desktop as well, and I fixed it by using shutdown() before calling close() on the HTTP requests
I'm using the following response headers:
Keep-Alive: timeout=0, max=0
Connection: close
Cache-Control: no-cache
I'm using the following socket options:
SO_REUSEADDR (mainly for debug convenience)
SO_REUSEPORT (sockets in multiple threads bind to and listen on the same port)
SO_KEEPALIVE, TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT (to kill off inactive clients)
Oddly enough though I think this disappears for a while after restarting my phone
I have tried not using nginx, instead using WolfSSL for TLS, and I get the same issue
I am inclined to think that this could be an issue with what headers I'm setting in responses (or possibly some HTTPS specific detail I'm missing?), but I'm not sure
And here's the actual site if anyone wants to verify the issue https://servertest.erewhon.xyz/
It looks to me like your server does not do a proper TLS shutdown, but is simply shutting down the underlying TCP connection. This causes your server to send a RST (packet 28) when the client is doing the proper TLS shutdown by sending the appropriate close notify TLS alert (packet 27).
This RST will result in a connection close on the client side. Depending on how fast the client has processed the incoming data this can result in abandoning still unread data in the TCP socket buffer, thus causing the problems you see.
The difference in behavior between mobile and desktop might just be caused by the performance of the systems and maybe by the underlying TCP stack. But no matter if the desktop works fine - your web server behaves wrong.
For details on how the connection close should happen at the HTTP level see RFC 7230 section 6.6. Note especially the following parts of this section:
If a server performs an immediate close of a TCP connection, there is
a significant risk that the client will not be able to read the last
HTTP response. If the server receives additional data from the
client on a fully closed connection, such as another request that was
sent by the client before receiving the server's response, the
server's TCP stack will send a reset packet to the client;
unfortunately, the reset packet might erase the client's
unacknowledged input buffers before they can be read and interpreted
by the client's HTTP parser.
To avoid the TCP reset problem, servers typically close a connection
in stages. First, the server performs a half-close by closing only
the write side of the read/write connection. The server then
continues to read from the connection until it receives a
corresponding close by the client, or until the server is reasonably
certain that its own TCP stack has received the client's
acknowledgement of the packet(s) containing the server's last
response. Finally, the server fully closes the connection.

Authenticating lots of clients for a REST API

We have a large number of small devices deployed in the wild that communicate with a central server via a REST API. It will send a status update on a regular basis with some sensor data and will also ask the server if there are any software updates that need to be applied. If there are, it will download it etc.
I'd like some way to prevent my server API from being used by unauthorised clients. Here are the solutions that I have and the issues which I anticipate. This question is somewhat open ended but it is mostly a question of best practices for, what I think is, a common situation.
Keep a single username/password on the server and then use basic auth over https. This is simple but if I change it, I'd have to somehow change the credentials on all of my devices (which number in the low thousands). This is hard to do reliably. There's also a problem with how the devices are going to get the update without first changing their creds.
The second is to create a username/password for every device. Then I can update individual ones and manage them but there's a lot of state on the server and I'm worried about having this much data on the server.
Some kind of automatic key based system whereby the devices can ask for an expirable key and then use that for all transactions. If the key expires or is invalidated, that device can't connect anymore. This would necessitate some kind of id for the device which I'm not sure how to handle.
So, how would I do this?
Update
In our setup, we have assigned hostnames for each of the devices we're going to deploy created beforehand. Once the devices switch on, they will contact the server with their hostnames and thereby register themselves. The MAC address and other information is passed as part of the initial registration handshake.
So, the "unique identifer" which was mentioned in the answer (and comment) by Noksi is the hostname. This can be easily spoofed (since the hostnames have a pattern). However, when the devices first come online, we can get the mac and, after that, only refresh the token if the request comes from the same mac. This opens up the possibility of a fake registration happening the first time though.
If there is some way to uniquely identify each device (similar to a MAC address) then that would be the key. Keep a registry of the devices and each device would register with the server. the server would provide the device with a token and associate it (the token) with the registered device. the device uses that token to make requests. tokens can be made to expire and renewed as needed or can be black listed if needed. This seems to be similar to option 3 in the proposed options.

Slow API calls after turning off sslV3 on server

First, I'm way over my head as I know just about nothing about managing a server, even less a server's security settings (I have been externally hosted for 20 years!).
My shared environment host (Newtek) has recently turned off sslV3, (I understand is a good thing -see poodle bug), but since then, some API calls that are being made are slow and some are not.
All API calls to UPS, CanadaPost and Paypal are slow (average of 20 sec per call ) while all calls to FB or Google map are fast (1 sec. per call).
All API calls use HTTPS.
My question to you is either:
-Does anybody have some clues has to what is going on? And if not, does anybody have any suggestions as to how to find out what is going on? Basically where and how to even look for the source of trouble!?! (As I don't know enough about what is going on behind the scene for any part of these connections to troubleshoot.)
A few notes:
After my host investigated various things, they have ruled out xmlParser as the cause,since the slowness can be observed even on dumping the cfhttp.filecontent.
My host installed a new version of my domain ssl which now uses SHA256.
My host server is running CF10 on IIS 7
I can't reproduce this on my local development server and of course don't have full access to the live server.
There is no CF error to report. Only very slow connection.
Thank you for any help you can provide!

programmatically, call forwarding in iphone

how can we programmatically implement, call forwarding?
I have done some google search, but have not found any good solution.
For reference, i have gone through this web page
CLick here
Suggestions are always appreciated.
I see this thread is a little old, but I’ll give you my 2 cents worth which might help you out when it comes to call forwarding.
I’ve recently released an app Ridlee+ on the Kuwait app store it has a call forwarding feature implemented and I faced the same issues you all are having.
So basically, the method described here using -[NSApplication openURL:] us correct, The problem is that apple will not allow you to pass * or # to the number programmatically, and as far as I know you need those in the dial number to interact with the call forwarding option on the telecom side. So the answer is “It’s not doable “
What I did is suggest to the telecom to create a link between the two, so I would pass call forwarding requests through TCP/IP or network connectivity to a webservice, and that system will take care of the internal config on the telecom side.
You will face issues requesting such a thing from the telecom since you get into User verification arguments, but if you implement your app correctly they would consider it. The way I did it, is have the User verified using a small reg process where the user will send a free SMS to the telecom, who will pass back to the webserver a verification code assigned to the user, the user will then enter this code in the app, which in turn verifies it with the web server, this 3 way handshake allows you to verify the user is the phone number owner. In turn allowing him to control his forwarding through the web service.
I hope this helps.
Have you tried sending the call forwarding character to the -[NSApplication openURL:] method?

SSL socket connection on iPhone

Is there a way to reuse SSL socket connections on the iPhone. I'm seeing an extra 3-4 second overhead in doing SSL handshaking. I'm using NSURLconnection currently to do the API calls and each one of them is taking 4-5 seconds on Wifi. Any suggestions would be greatly appreciated.
Are you asking how to "reuse" sockets for the same specific address and port? Or for different URLs?
If the former, just don't close the socket until you're absolutely sure you don't need it anymore.
If the latter, there's nothing you can do about that. The SSL certificate verification process is likely where you're getting the overhead from.
You'll need to add more context to your question if you want a more specific answer.
you might want to establish an SSL connection an keep reusing it. Rather than make a new connection each time. There is definitely an overhead to SSL connections as well as handshaking. You cant get rid of the overhead from the encryption but the handshaking can be reduced by using NSStreams and keeping the connection open as you use it.
I have posted code and instructions on how to do it here:
NSStream SSL on used socket