@@ -41,7 +41,6 @@ enum VPNServiceError: Error, Equatable {
41
41
final class CoderVPNService : NSObject , VPNService {
42
42
var logger = Logger ( subsystem: Bundle . main. bundleIdentifier!, category: " vpn " )
43
43
lazy var xpc : VPNXPCInterface = . init( vpn: self )
44
- var terminating = false
45
44
var workspaces : [ UUID : String ] = [ : ]
46
45
47
46
@Published var tunnelState : VPNServiceState = . disabled
@@ -68,8 +67,14 @@ final class CoderVPNService: NSObject, VPNService {
68
67
super. init ( )
69
68
installSystemExtension ( )
70
69
Task {
71
- await loadNetworkExtension ( )
70
+ neState = if await hasNetworkExtensionConfig ( ) {
71
+ . disabled
72
+ } else {
73
+ . unconfigured
74
+ }
72
75
}
76
+ xpc. connect ( )
77
+ xpc. getPeerState ( )
73
78
NotificationCenter . default. addObserver (
74
79
self ,
75
80
selector: #selector( vpnDidUpdate ( _: ) ) ,
@@ -82,6 +87,11 @@ final class CoderVPNService: NSObject, VPNService {
82
87
NotificationCenter . default. removeObserver ( self )
83
88
}
84
89
90
+ func clearPeers( ) {
91
+ agents = [ : ]
92
+ workspaces = [ : ]
93
+ }
94
+
85
95
func start( ) async {
86
96
switch tunnelState {
87
97
case . disabled, . failed:
@@ -90,31 +100,18 @@ final class CoderVPNService: NSObject, VPNService {
90
100
return
91
101
}
92
102
93
- await enableNetworkExtension ( )
94
- // this ping is somewhat load bearing since it causes xpc to init
103
+ await startTunnel ( )
104
+ xpc. connect ( )
95
105
xpc. ping ( )
96
106
logger. debug ( " network extension enabled " )
97
107
}
98
108
99
109
func stop( ) async {
100
110
guard tunnelState == . connected else { return }
101
- await disableNetworkExtension ( )
111
+ await stopTunnel ( )
102
112
logger. info ( " network extension stopped " )
103
113
}
104
114
105
- // Instructs the service to stop the VPN and then quit once the stop event
106
- // is read over XPC.
107
- // MUST only be called from `NSApplicationDelegate.applicationShouldTerminate`
108
- // MUST eventually call `NSApp.reply(toApplicationShouldTerminate: true)`
109
- func quit( ) async {
110
- guard tunnelState == . connected else {
111
- NSApp . reply ( toApplicationShouldTerminate: true )
112
- return
113
- }
114
- terminating = true
115
- await stop ( )
116
- }
117
-
118
115
func configureTunnelProviderProtocol( proto: NETunnelProviderProtocol ? ) {
119
116
Task {
120
117
if let proto {
@@ -145,6 +142,22 @@ final class CoderVPNService: NSObject, VPNService {
145
142
}
146
143
}
147
144
145
+ func onExtensionPeerState( _ data: Data ? ) {
146
+ guard let data else {
147
+ logger. error ( " could not retrieve peer state from network extension, it may not be running " )
148
+ return
149
+ }
150
+ logger. info ( " received network extension peer state " )
151
+ do {
152
+ let msg = try Vpn_PeerUpdate ( serializedBytes: data)
153
+ debugPrint ( msg)
154
+ clearPeers ( )
155
+ applyPeerUpdate ( with: msg)
156
+ } catch {
157
+ logger. error ( " failed to decode peer update \( error) " )
158
+ }
159
+ }
160
+
148
161
func applyPeerUpdate( with update: Vpn_PeerUpdate ) {
149
162
// Delete agents
150
163
update. deletedAgents
@@ -204,9 +217,6 @@ extension CoderVPNService {
204
217
}
205
218
switch connection. status {
206
219
case . disconnected:
207
- if terminating {
208
- NSApp . reply ( toApplicationShouldTerminate: true )
209
- }
210
220
connection. fetchLastDisconnectError { err in
211
221
self . tunnelState = if let err {
212
222
. failed( . internalError( err. localizedDescription) )
0 commit comments