Force NSURLSession only over cellular network

I am looking all over documentation and different frameworks but it looks like I can't find a way for this.


Basically, I need to call the HTTPS route only on a cellular network. I've looked into NWConnection and the Network Framework which can setup requiredInterfaceType = .cellular but I am not sure I can call an https using NWConnection.


Is there any option on setting NSURLSession to be routed only through cellular or any way to combine it with NWConnection?


Any help would be appreciated.

Replies

Using NSURLSession on a cellular network only is not a preferred option in iOS. Wi-Fi is always the preferred option for dataTasks and that is why you see options for providing access to WWAN, but not using it as your required path. For NSURLSession you would have to gate your dataTask execution around the usesInterfaceType result from NWPathMonitor. Which is essentially a preflight-check, something I typically recommend against.

let pathMonitor = NWPathMonitor()
pathMonitor.pathUpdateHandler = { path in
    if path.usesInterfaceType(.wifi) {
        print("Path is Wi-Fi")
    } else if path.usesInterfaceType(.cellular) {
        print("Path is Cellular")
    } else if path.usesInterfaceType(.wiredEthernet) {
        print("Path is Wired Ethernet")
    } else if path.usesInterfaceType(.loopback) {
        print("Path is Loopback")
    } else if path.usesInterfaceType(.other) {
        print("Path is other")
    }
}
pathMonitor.start(queue: .main)


For Network Framework, when creating a NWConnection you can use NWParameters to specify the requiredInterfaceType of .cellular. As an example:

let params = NWParameters(tls: tlsOptions, tcp: tcpOptions)
params.requiredInterfaceType = .cellular

connection = NWConnection(to: connectionHostPort, using: params)


To test the failing case for the example above, make sure your Wi-Fi interface is on and WWAN is disabled.


Matt Eaton

DTS Engineering, CoreOS

meaton3 at apple.com

Thanks for the answer, I am aware of NWPathMonitor and as you mentioned this is only for observation.


My idea is to have two connections to two endpoints and one will always use Cellular Network.


Is there any way to do SSL connection only over cellular?


Thanks a lot for the help

Could there be an opportunity here to use Multipath TCP on your NSURLSessionConfiguration instead of managing two connections?

See Improving Network Reliability Using Multipath TCP.

| My idea is to have two connections to two endpoints and one will always use Cellular

| Network.


Yes, SSL connections are done the same way over cellular and Wi-Fi. There should be no difference.

| Is there any way to do SSL connection only over cellular?



Matt Eaton

DTS Engineering, CoreOS

meaton3 at apple.com

I'd like to know whether anything has changed regarding the original poster's situation.

While using NSURLSession on a cellular network only may not be a preferred option in iOS, in my case it's a necessity. I'm using an off-the-shelf WiFi-to-Automotive-Ethernet adapter to connect to a car's diagnostic services. The adapter hands out an 192.168.x.y address via DHCP. Unfortunately iOS does not recognize that there is no internet connectivity over this adapter, hence all my URLRequests fail immediately.

Coming back to the Network preflight check… how would I use that in practice? E.g., it's good that I can detect the outgoing route, but what can I do if that's not the route I want to use? Is there anything else I can do to fix this issue?

I'd like to know whether anything has changed regarding the original poster's situation.

No there is has not been any updates here on this situation.

Regarding:

Unfortunately iOS does not recognize that there is no internet connectivity over this adapter, hence all my URLRequests fail immediately.

Is there anything listening on the other end that seeing this address as a viable route?

Regarding:

Coming back to the Network preflight check… how would I use that in practice? E.g., it's good that I can detect the outgoing route, but what can I do if that's not the route I want to use?

It sounds like your path might come through as .wifi if I'm understanding you correctly, what does NWPathMonitor report?

Thanks for responding. Here are more details on my situation. I'm starting my app and everything is OK so far. Depending on where I am either my local WiFi is being used or cellular. Now I'm attaching the diagnostic WiFi adapter to the car, use Settings -> WiFi to connect to its network and now the following happens:

  • The iPhone gets an IP, a subnet mask, and ­– sadly ­– a router, e.g. 192.168.16.103 / 255.255.255.0 / 192.168.16.254. Interestingly, for a short time, iOS seems to detect that with these settings, there is no internet available, hence it ­– sometimes ­– shows the [No Internet Connectivity] subtitle.
  • Despite all that, the path stays the same as NWPathMonitor still reports 2022-06-03 08:51:42.503 [none:ObservableReachability] <2> (D) Network Path now satisfied (Path is satisfied), interface: en0, ipv4, dns

So at this point of time, I have no internet connectivity.

Now if I manually go into the WiFi settings, change it to 'custom' and set 192.168.16.103 / 255.255.255.0 / (empty router), everything immediately starts to work. In the statusbar, there is 'LTE' and I can connect both to the 192.168.16.x and to the internet.

Now really I can't put the burden to my end users to go in their network settings and do the same I did. That's why I'm begging for a better solution.

  • And let me note here that I have to use URLSession, I'm not feeling like implementing my own URLSession using NWNetwork…

Add a Comment

Thank you for the follow up details. Have you tried using NEHotspotConfiguration here to join the local access point that does not have a wider internet connection? This may provide an in-app alternative to going to the Settings and performing this entire setup by hand. The question will become, does this provide a means to send your HTTP request with URLSession. If it does not, then try to stagger this request after association for a few seconds and then send it.

If the above does not work, are you able to access anything else over the local Wi-Fi link, such as a Bonjour service name or straight TCP connection? What this should tell us is if your can reach the device at all and if this is a viable route.

NEHotspotConfiguration has two problems:

  1. As far as I can see, the API doesn't allow me to intercept or override the DHCP configuration that gets sent from the WiFi access point, so how could I configure the router IP programmatically?
  2. I don't know the SSID in advance. Usually those WiFi diagnostic adapters insert their (varying) serial number into the SSID, and ­– sometimes ­– the password.

I'm not sure I understand your second paragraph. Do you want to say that trying to access an internet resource via the WiFi link would tell the system that it has no WiFi connection? If so, that doesn't happen ­– at least not with URLSession, since I'm already doing that. I try to access resources, which ­­– due to the WIFi link being used ­– all fail.

I don't know the SSID in advance. Usually those WiFi diagnostic adapters insert their (varying) serial number into the SSID, and ­– sometimes – the password.

One technique to try and solve this is to prefix the SSID. For example:

  • netAdap123
  • netAdap456
  • netAdap789

Then using the initWithSSIDPrefix API, you could associate with netAdap if the device can be configured in such a manner.

I'm not sure I understand your second paragraph. Do you want to say that trying to access an internet resource via the WiFi link would tell the system that it has no WiFi connection? If so, that doesn't happen ­– at least not with URLSession, since I'm already doing that. I try to access resources, which ­­– due to the WIFi link being used ­– all fail.

My second paragraph was a means to determine if you could reach the device of the Wi-Fi link or not without use HTTP.

Thanks, interesting, initWithSSIDPrefix is news to me, that's pretty helpful. Still remaining is the problem w/ DHCP handing out a "router" IP, which it shouldn't as this confuses iOS.

I can definitely reach the device of the WiFi link without HTTP. The way it works is that I have to broadcast via UDP to find out who's listening on the other side and also to find out the right interface. Then, I open a TCP socket, configure it via IP_BOUND_IF to use the appropriate interface and continue via streams with CFStreamCreatePairWithSocket.

FWIW, I could work around my issue of the WiFi adapter handing out a route by (ab)using the TCP multipath configuration ˋinteractiveˋ. That way it looks like every request is sent out both via WiFi and Cellular and since there is never any reply coming in via WiFi, Cellular always wins. Unless we get programmatic ability to adjust the IP configuration, this is the best thing to solve my problem.