blob: 82f18461a1a4be0237abdf6ae132b39e44e87e98 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
//
// SimulatorVPNConnection.swift
// MullvadVPN
//
// Created by Jon Petersson on 2023-09-07.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
#if targetEnvironment(simulator)
import Foundation
import MullvadREST
import NetworkExtension
class SimulatorVPNConnection: NSObject, VPNConnectionProtocol, @unchecked Sendable {
// Protocol configuration is automatically synced by `SimulatorTunnelInfo`
var protocolConfiguration = NEVPNProtocol()
private let lock = NSRecursiveLock()
private var _status: NEVPNStatus = .disconnected
private var _reasserting = false
private var _connectedDate: Date?
private(set) var status: NEVPNStatus {
get {
lock.lock()
defer { lock.unlock() }
return _status
}
set {
lock.lock()
if _status != newValue {
_status = newValue
// Send notification while holding the lock. This should enable the receiver
// to fetch the `SimulatorVPNConnection.status` before the concurrent code gets
// opportunity to change it again.
postStatusDidChangeNotification()
}
lock.unlock()
}
}
var reasserting: Bool {
get {
lock.lock()
defer { lock.unlock() }
return _reasserting
}
set {
lock.lock()
if _reasserting != newValue {
_reasserting = newValue
if newValue {
status = .reasserting
} else {
status = .connected
}
}
lock.unlock()
}
}
private(set) var connectedDate: Date? {
get {
lock.lock()
defer { lock.unlock() }
return _connectedDate
}
set {
lock.lock()
_connectedDate = newValue
lock.unlock()
}
}
func startVPNTunnel() throws {
try startVPNTunnel(options: nil)
}
func startVPNTunnel(options: [String: NSObject]?) throws {
SimulatorTunnelProvider.shared.delegate.connection = self
status = .connecting
SimulatorTunnelProvider.shared.delegate.startTunnel(options: options) { error in
if error == nil {
self.status = .connected
self.connectedDate = Date()
} else if error is NoRelaysSatisfyingConstraintsError {
self.reasserting = true
self.connectedDate = nil
} else {
self.status = .disconnected
self.connectedDate = nil
}
}
}
func stopVPNTunnel() {
status = .disconnecting
SimulatorTunnelProvider.shared.delegate.stopTunnel(with: .userInitiated) {
self.status = .disconnected
self.connectedDate = nil
}
}
private func postStatusDidChangeNotification() {
NotificationCenter.default.post(name: .NEVPNStatusDidChange, object: self)
}
}
#endif
|