@@ -14,24 +14,12 @@ import WireGuardKit
14
14
15
15
public final class TunnelPinger : PingerProtocol {
16
16
private var sequenceNumber : UInt16 = 0
17
- private let stateLock = NSRecursiveLock ( )
17
+ private let stateLock = NSLock ( )
18
18
private let pingReceiveQueue : DispatchQueue
19
19
private let replyQueue : DispatchQueue
20
20
private var destAddress : IPv4Address ?
21
- private var _onReply : ( ( PingerReply ) -> Void ) ?
22
- public var onReply : ( ( PingerReply ) -> Void ) ? {
23
- get {
24
- stateLock. withLock {
25
- return _onReply
26
- }
27
- }
28
- set {
29
- stateLock. withLock {
30
- _onReply = newValue
31
- }
32
- }
33
- }
34
-
21
+ /// Always accessed from the `replyQueue` and is assigned once, on the main thread of the PacketTunnel. It is thread safe.
22
+ public var onReply : ( ( PingerReply ) -> Void ) ?
35
23
private var pingProvider : ICMPPingProvider
36
24
37
25
private let logger : Logger
@@ -49,18 +37,26 @@ public final class TunnelPinger: PingerProtocol {
49
37
50
38
public func openSocket( bindTo interfaceName: String ? , destAddress: IPv4Address ) throws {
51
39
try pingProvider. openICMP ( address: destAddress)
52
- self . destAddress = destAddress
40
+ stateLock. withLock {
41
+ self . destAddress = destAddress
42
+ }
53
43
pingReceiveQueue. async { [ weak self] in
54
44
while let self {
55
45
do {
56
46
let seq = try pingProvider. receiveICMP ( )
57
47
58
48
replyQueue. async { [ weak self] in
59
- self ? . onReply ? ( PingerReply . success ( destAddress, UInt16 ( seq) ) )
49
+ self ? . stateLock. withLock {
50
+ self ? . onReply ? ( PingerReply . success ( destAddress, UInt16 ( seq) ) )
51
+ }
60
52
}
61
53
} catch {
62
54
replyQueue. async { [ weak self] in
63
- self ? . onReply ? ( PingerReply . parseError ( error) )
55
+ self ? . stateLock. withLock {
56
+ if self ? . destAddress != nil {
57
+ self ? . onReply ? ( PingerReply . parseError ( error) )
58
+ }
59
+ }
64
60
}
65
61
return
66
62
}
@@ -69,14 +65,18 @@ public final class TunnelPinger: PingerProtocol {
69
65
}
70
66
71
67
public func closeSocket( ) {
72
- pingProvider. closeICMP ( )
73
- self . destAddress = nil
68
+ stateLock. withLock {
69
+ self . destAddress = nil
70
+ pingProvider. closeICMP ( )
71
+ }
74
72
}
75
73
76
74
public func send( ) throws -> PingerSendResult {
77
75
let sequenceNumber = nextSequenceNumber ( )
78
76
79
- guard let destAddress else { throw WireGuardAdapterError . invalidState }
77
+ stateLock. lock ( )
78
+ defer { stateLock. unlock ( ) }
79
+ guard destAddress != nil else { throw WireGuardAdapterError . invalidState }
80
80
// NOTE: we cheat here by returning the destination address we were passed, rather than parsing it from the packet on the other side of the FFI boundary.
81
81
try pingProvider. sendICMPPing ( seqNumber: sequenceNumber)
82
82
0 commit comments