@@ -55,14 +55,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelCredentialsManaging {
5555 // Check if tunnel was force disconnected (e.g., due to session invalidation)
5656 // This mirrors WireGuard's credential check but uses a flag since OpenVPN
5757 // credentials are embedded in tunnel config and can't be deleted
58- if preferences. getDisconnectReason ( ) != DisconnectReason . unknown {
59- consoleLogger. debug ( " Tunnel start blocked - force disconnect flag is set " )
60- logger. logI ( " PacketTunnelProvider " , " Blocked tunnel start - force disconnect active " , flushImmediately: true )
61- let error = NSError ( domain: " com.windscribe " , code: 50 , userInfo: [
62- NSLocalizedDescriptionKey: " Session is invalid "
63- ] )
64- completionHandler ( error)
65- }
6658
6759 guard
6860 let protocolConfiguration = protocolConfiguration as? NETunnelProviderProtocol ,
@@ -190,25 +182,35 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelCredentialsManaging {
190182 }
191183
192184 override func sleep( completionHandler: @escaping ( ) -> Void ) {
185+ logger. logI ( " PacketTunnelProvider " , " Device going to sleep. " , flushImmediately: true )
193186 completionHandler ( )
194187 }
195188
196189 override func wake( ) {
197- consoleLogger. debug ( " Device wake up. " )
198- controlPlane? . checkTunnelHealth ( )
190+ let currentTime = Date ( ) . timeIntervalSince1970
191+ let lastWakeTime = preferences. getWireguardWakeupTime ( )
192+ logger. logI ( " PacketTunnelProvider " , " Device wakeup. " , flushImmediately: true )
193+ if lastWakeTime == 0 || currentTime - lastWakeTime >= 600 {
194+ UserDefaults . standard. set ( currentTime, forKey: " lastWakeTime " )
195+ preferences. saveWireguardWakeupTime ( value: currentTime)
196+ if preferences. getDisconnectReason ( ) == DisconnectReason . unknown {
197+ controlPlane? . checkTunnelHealth ( )
198+ }
199+ }
199200 }
200201
201202 // MARK: - TunnelCredentialsManaging
202203
204+ @MainActor
203205 func deleteCredentials( error: NSError ) {
204206 guard !isCancelling else {
205207 logger. logI ( " PacketTunnelProvider " , " Already cancelling tunnel, ignoring duplicate call. " , flushImmediately: true )
206208 return
207209 }
210+ controlPlane = nil
208211 isCancelling = true
209212 // OpenVPN credentials are passed per-connection, not stored persistently
210213 // Log the action for visibility
211- consoleLogger. debug ( " Credentials invalidated for OpenVPN tunnel. " )
212214 logger. logI ( " PacketTunnelProvider " , " OpenVPN credentials invalidated. " , flushImmediately: true )
213215 if vpnReachability. isTracking {
214216 vpnReachability. stopTracking ( )
@@ -245,10 +247,22 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
245247 self . startHandler = nil
246248 // Initialize control plane when tunnel is ready
247249 if controlPlane == nil {
248- controlPlane = ControlPlane ( apiUtil: apiUtil, api: api, preferences: preferences, credentialsManager: self , tunnelProvider: self , consoleLogger: self . consoleLogger)
250+ controlPlane = ControlPlane (
251+ apiUtil: apiUtil,
252+ api: api,
253+ preferences: preferences,
254+ consoleLogger: self . consoleLogger,
255+ onTunnelShouldStop: { @MainActor [ weak self] reason, error in
256+ guard let self = self else { return }
257+ self . logger. logI ( " PacketTunnelProvider " , " Control plane requested tunnel stop for reason: \( reason. rawValue) " , flushImmediately: true )
258+ self . deleteCredentials ( error: error)
259+ }
260+ )
261+ }
262+ if preferences. getDisconnectReason ( ) == DisconnectReason . unknown {
263+ consoleLogger. debug ( " Tunnel connected, checking tunnel health. " )
264+ controlPlane? . checkTunnelHealth ( )
249265 }
250- consoleLogger. debug ( " Tunnel connected, checking tunnel health. " )
251- controlPlane? . checkTunnelHealth ( )
252266 case . disconnected:
253267 guard let stopHandler = stopHandler else { return }
254268 if vpnReachability. isTracking {
@@ -258,8 +272,10 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
258272 self . stopHandler = nil
259273 case . reconnecting:
260274 reasserting = true
261- consoleLogger. debug ( " Reconnecting, checking tunnel health. " )
262- controlPlane? . checkTunnelHealth ( )
275+ if preferences. getDisconnectReason ( ) == DisconnectReason . unknown {
276+ logger. logI ( " PacketTunnelProvider " , " Reconnecting, checking tunnel health. " , flushImmediately: true )
277+ controlPlane? . checkTunnelHealth ( )
278+ }
263279 default :
264280 break
265281 }
@@ -277,12 +293,15 @@ extension PacketTunnelProvider: OpenVPNAdapterDelegate {
277293 startHandler ( error)
278294 self . startHandler = nil
279295 } else {
280- guard !isCancelling else {
281- logger. logI ( " PacketTunnelProvider " , " Already cancelling tunnel, ignoring error handler call. " , flushImmediately: true )
282- return
296+ DispatchQueue . main. async { [ weak self] in
297+ guard let self = self else { return }
298+ guard !self . isCancelling else {
299+ self . logger. logI ( " PacketTunnelProvider " , " Already cancelling tunnel, ignoring error handler call. " , flushImmediately: true )
300+ return
301+ }
302+ self . isCancelling = true
303+ self . cancelTunnelWithError ( error)
283304 }
284- isCancelling = true
285- cancelTunnelWithError ( error)
286305 }
287306 }
288307}
0 commit comments