Catch error from PacketTunnelProvider

For this example assume that


session = A working NETunnelProviderSession



I'm using the following code to catch errors from my PacketTunnelProvider

if (! [session startVPNTunnelWithOptions:myOptions andReturnError:&myError]) {
   NSLog(@"Error While Starting VPN Tunnel: %@", myError.description);
}


However, that only seems to catch low level errors. I'm trying to figure out how to catch errors in my primary application when I call `[self cancelTunnelWithError:someError];` or the `startTunnelWithOptions` completion handler both inside my PacketTunnelProvider.


I understand that the `startVPNTunnelWithOptions:andReturnError:` function returns immidiately. Since that is the case, how would I go about catching errors in my primary application when they are thrown while canceling the tunnel internally?


Also, I'm not sure if it matters, but my NSError objects always have a custom ErrorDomain and Code.

Accepted Reply

I couldn't find any way to do this with just the NetworkExtension APIs.


My solution was to override cancelTunnelWithError (remembering to call super.cancelTunnelWithError), and have it store the error details into shared UserDefaults as a dictionary. I do the same in stopTunnel to catch system-triggered stops as well. Then, in the app, I watch for NEVPNStatusDidChangeNotification and check for a stored error any time the status changes to NEVPNStatusDisconnected. It's a little clunky but it works.

Replies

I couldn't find any way to do this with just the NetworkExtension APIs.


My solution was to override cancelTunnelWithError (remembering to call super.cancelTunnelWithError), and have it store the error details into shared UserDefaults as a dictionary. I do the same in stopTunnel to catch system-triggered stops as well. Then, in the app, I watch for NEVPNStatusDidChangeNotification and check for a stored error any time the status changes to NEVPNStatusDisconnected. It's a little clunky but it works.

Well, this worked. It's kinda crazy that you have to be so hacky around it just to get errors returned.

It's kinda crazy that you have to be so hacky around it just to get errors returned.

You should definitely file an enhancement request for the features you’d like to see here. Please post your bug number, just for the record.

Have you thought about using app messaging for this? When the app starts the tunnel (or is launched with the tunnel already up) it could send an app message to the provider. The provider would then hold on to the completion handler, calling it with the error when the tunnel goes down.

I’ve not tried this myself but it seems like it would work.

Having said that there’s merit in mike.ly’s approach in that it persists the error. So if the tunnel goes down when the app isn’t running, and the user launches the app to see the error, the app can get the persistent error and display it.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Would the completion handler still fire if the app were closed after initiating the provider? Like for example:


App Launched -> Prider brought up -> Send app message with error completion handler -> Provider holds on to completion handler -> app is closed -> error occurs


What handles that error?

Would the completion handler still fire if the app were closed after initiating the provider?

No. iOS is not going to resume or relaunch the main app to handle this message. Which is why I suggested that mike.ly’s approach has merit.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"