mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 15:05:20 +00:00
Fix thread safety crash with NSLock
- Replace problematic messageQueue.sync with NSLock for peerNicknames - Prevents deadlock when accessing from within messageQueue - Add thread-safe access to all peerNicknames read/write operations - Fixes EXC_BREAKPOINT crash from recursive queue access The previous approach using messageQueue.sync caused deadlock when getAllConnectedPeerIDs was called from within the messageQueue itself.
This commit is contained in:
@@ -30,15 +30,8 @@ class BluetoothMeshService: NSObject {
|
|||||||
private var peripheralCharacteristics: [CBPeripheral: CBCharacteristic] = [:]
|
private var peripheralCharacteristics: [CBPeripheral: CBCharacteristic] = [:]
|
||||||
private var characteristic: CBMutableCharacteristic!
|
private var characteristic: CBMutableCharacteristic!
|
||||||
private var subscribedCentrals: [CBCentral] = []
|
private var subscribedCentrals: [CBCentral] = []
|
||||||
private var _peerNicknames: [String: String] = [:]
|
private var peerNicknames: [String: String] = [:]
|
||||||
private var peerNicknames: [String: String] {
|
private let peerNicknamesLock = NSLock()
|
||||||
get {
|
|
||||||
messageQueue.sync { _peerNicknames }
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
messageQueue.async(flags: .barrier) { self._peerNicknames = newValue }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private var activePeers: Set<String> = [] // Track all active peers
|
private var activePeers: Set<String> = [] // Track all active peers
|
||||||
private var peerRSSI: [String: NSNumber] = [:] // Track RSSI values for peers
|
private var peerRSSI: [String: NSNumber] = [:] // Track RSSI values for peers
|
||||||
private var peripheralRSSI: [String: NSNumber] = [:] // Track RSSI by peripheral ID during discovery
|
private var peripheralRSSI: [String: NSNumber] = [:] // Track RSSI by peripheral ID during discovery
|
||||||
@@ -662,7 +655,10 @@ class BluetoothMeshService: NSObject {
|
|||||||
|
|
||||||
|
|
||||||
func getPeerNicknames() -> [String: String] {
|
func getPeerNicknames() -> [String: String] {
|
||||||
return peerNicknames
|
peerNicknamesLock.lock()
|
||||||
|
let copy = peerNicknames
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPeerRSSI() -> [String: NSNumber] {
|
func getPeerRSSI() -> [String: NSNumber] {
|
||||||
@@ -730,7 +726,10 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Safely check if peer has a nickname (thread-safe)
|
// Safely check if peer has a nickname (thread-safe)
|
||||||
let hasNickname = self._peerNicknames[peerID] != nil
|
peerNicknamesLock.lock()
|
||||||
|
let hasNickname = peerNicknames[peerID] != nil
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
|
|
||||||
if hasNickname {
|
if hasNickname {
|
||||||
return peerID
|
return peerID
|
||||||
}
|
}
|
||||||
@@ -1030,7 +1029,9 @@ class BluetoothMeshService: NSObject {
|
|||||||
// Received broadcast message
|
// Received broadcast message
|
||||||
|
|
||||||
// Store nickname mapping
|
// Store nickname mapping
|
||||||
|
peerNicknamesLock.lock()
|
||||||
peerNicknames[senderID] = message.sender
|
peerNicknames[senderID] = message.sender
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
|
|
||||||
let messageWithPeerID = BitchatMessage(
|
let messageWithPeerID = BitchatMessage(
|
||||||
sender: message.sender,
|
sender: message.sender,
|
||||||
@@ -1112,9 +1113,11 @@ class BluetoothMeshService: NSObject {
|
|||||||
// Received private message
|
// Received private message
|
||||||
|
|
||||||
// Store nickname mapping if we don't have it
|
// Store nickname mapping if we don't have it
|
||||||
|
peerNicknamesLock.lock()
|
||||||
if peerNicknames[senderID] == nil {
|
if peerNicknames[senderID] == nil {
|
||||||
peerNicknames[senderID] = message.sender
|
peerNicknames[senderID] = message.sender
|
||||||
}
|
}
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
|
|
||||||
let messageWithPeerID = BitchatMessage(
|
let messageWithPeerID = BitchatMessage(
|
||||||
sender: message.sender,
|
sender: message.sender,
|
||||||
@@ -1239,7 +1242,9 @@ class BluetoothMeshService: NSObject {
|
|||||||
let isFirstAnnounce = !announcedPeers.contains(senderID)
|
let isFirstAnnounce = !announcedPeers.contains(senderID)
|
||||||
|
|
||||||
// Store the nickname
|
// Store the nickname
|
||||||
|
peerNicknamesLock.lock()
|
||||||
peerNicknames[senderID] = nickname
|
peerNicknames[senderID] = nickname
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
// Stored nickname
|
// Stored nickname
|
||||||
// Updated nicknames
|
// Updated nicknames
|
||||||
|
|
||||||
@@ -1312,7 +1317,9 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clean up peer data
|
// Clean up peer data
|
||||||
|
peerNicknamesLock.lock()
|
||||||
peerNicknames.removeValue(forKey: senderID)
|
peerNicknames.removeValue(forKey: senderID)
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
} else {
|
} else {
|
||||||
// Failed to parse leave packet
|
// Failed to parse leave packet
|
||||||
}
|
}
|
||||||
@@ -1646,7 +1653,11 @@ extension BluetoothMeshService: CBCentralManagerDelegate {
|
|||||||
announcedToPeers.remove(peerID)
|
announcedToPeers.remove(peerID)
|
||||||
|
|
||||||
// Only show disconnect if we have a resolved nickname
|
// Only show disconnect if we have a resolved nickname
|
||||||
if let nickname = peerNicknames[peerID], nickname != peerID {
|
peerNicknamesLock.lock()
|
||||||
|
let nickname = peerNicknames[peerID]
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
|
|
||||||
|
if let nickname = nickname, nickname != peerID {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.delegate?.didDisconnectFromPeer(nickname)
|
self.delegate?.didDisconnectFromPeer(nickname)
|
||||||
self.delegate?.didUpdatePeerList(self.getAllConnectedPeerIDs())
|
self.delegate?.didUpdatePeerList(self.getAllConnectedPeerIDs())
|
||||||
@@ -1935,7 +1946,11 @@ extension BluetoothMeshService: CBPeripheralManagerDelegate {
|
|||||||
for peerID in peersToRemove {
|
for peerID in peersToRemove {
|
||||||
activePeers.remove(peerID)
|
activePeers.remove(peerID)
|
||||||
announcedToPeers.remove(peerID)
|
announcedToPeers.remove(peerID)
|
||||||
if let nickname = peerNicknames[peerID] {
|
peerNicknamesLock.lock()
|
||||||
|
let nickname = peerNicknames[peerID]
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
|
|
||||||
|
if let nickname = nickname {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.delegate?.didDisconnectFromPeer(nickname)
|
self.delegate?.didDisconnectFromPeer(nickname)
|
||||||
}
|
}
|
||||||
@@ -2085,7 +2100,11 @@ extension BluetoothMeshService: CBPeripheralManagerDelegate {
|
|||||||
// Sending cover traffic
|
// Sending cover traffic
|
||||||
|
|
||||||
// Send as a private message so it's encrypted
|
// Send as a private message so it's encrypted
|
||||||
sendPrivateMessage(dummyContent, to: randomPeer, recipientNickname: peerNicknames[randomPeer] ?? "unknown")
|
peerNicknamesLock.lock()
|
||||||
|
let recipientNickname = peerNicknames[randomPeer] ?? "unknown"
|
||||||
|
peerNicknamesLock.unlock()
|
||||||
|
|
||||||
|
sendPrivateMessage(dummyContent, to: randomPeer, recipientNickname: recipientNickname)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func generateDummyContent() -> String {
|
private func generateDummyContent() -> String {
|
||||||
|
|||||||
Reference in New Issue
Block a user