Fix Bluetooth errors and improve store-and-forward

- Add peripheral state checks before all write operations
- Fix 'can only accept commands while connected' errors
- Check characteristic write properties to avoid ATT errors
- Preserve original timestamps in store-and-forward messages
- Only log crypto errors once per peer to reduce noise
- Store-and-forward now correctly maintains message ordering

The timestamp preservation ensures messages appear in the correct
chronological order even when delivered later via store-and-forward.
This commit is contained in:
jack
2025-07-04 14:30:00 +02:00
parent 3f882eec0f
commit 7b3cfb6227
3 changed files with 38 additions and 22 deletions
+12 -4
View File
@@ -255,6 +255,7 @@
DEVELOPMENT_TEAM = L3N5LHJD5Y; DEVELOPMENT_TEAM = L3N5LHJD5Y;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = bitchat/Info.plist; INFOPLIST_FILE = bitchat/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 16.0; IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@@ -264,9 +265,12 @@
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
PRODUCT_NAME = bitchat; PRODUCT_NAME = bitchat;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = 1;
}; };
name = Debug; name = Debug;
}; };
@@ -282,6 +286,7 @@
DEVELOPMENT_TEAM = L3N5LHJD5Y; DEVELOPMENT_TEAM = L3N5LHJD5Y;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = bitchat/Info.plist; INFOPLIST_FILE = bitchat/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 16.0; IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@@ -291,9 +296,12 @@
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat; PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
PRODUCT_NAME = bitchat; PRODUCT_NAME = bitchat;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = 1;
}; };
name = Release; name = Release;
}; };
+5 -1
View File
@@ -41,9 +41,13 @@
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string> </array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array> </array>
</dict> </dict>
</plist> </plist>
+21 -17
View File
@@ -35,6 +35,7 @@ class BluetoothMeshService: NSObject {
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
private var loggedCryptoErrors = Set<String>() // Track which peers we've logged crypto errors for
weak var delegate: BitchatDelegate? weak var delegate: BitchatDelegate?
private let encryptionService = EncryptionService() private let encryptionService = EncryptionService()
@@ -210,6 +211,7 @@ class BluetoothMeshService: NSObject {
self.broadcastPacket(messages[0]) self.broadcastPacket(messages[0])
} else if let dest = destination, } else if let dest = destination,
let peripheral = self.connectedPeripherals[dest], let peripheral = self.connectedPeripherals[dest],
peripheral.state == .connected,
let characteristic = self.peripheralCharacteristics[peripheral] { let characteristic = self.peripheralCharacteristics[peripheral] {
if let data = messages[0].toBinaryData() { if let data = messages[0].toBinaryData() {
peripheral.writeValue(data, for: characteristic, type: .withoutResponse) peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
@@ -225,6 +227,7 @@ class BluetoothMeshService: NSObject {
self?.broadcastPacket(message) self?.broadcastPacket(message)
} else if let dest = destination, } else if let dest = destination,
let peripheral = self?.connectedPeripherals[dest], let peripheral = self?.connectedPeripherals[dest],
peripheral.state == .connected,
let characteristic = self?.peripheralCharacteristics[peripheral] { let characteristic = self?.peripheralCharacteristics[peripheral] {
if let data = message.toBinaryData() { if let data = message.toBinaryData() {
peripheral.writeValue(data, for: characteristic, type: .withoutResponse) peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
@@ -627,9 +630,11 @@ class BluetoothMeshService: NSObject {
// Also try targeted send if we have the peripheral // Also try targeted send if we have the peripheral
if let peripheral = connectedPeripherals[peerID], if let peripheral = connectedPeripherals[peerID],
peripheral.state == .connected,
let characteristic = peripheral.services?.first(where: { $0.uuid == BluetoothMeshService.serviceUUID })?.characteristics?.first(where: { $0.uuid == BluetoothMeshService.characteristicUUID }) { let characteristic = peripheral.services?.first(where: { $0.uuid == BluetoothMeshService.serviceUUID })?.characteristics?.first(where: { $0.uuid == BluetoothMeshService.characteristicUUID }) {
// Also sending targeted announce // Also sending targeted announce
peripheral.writeValue(data, for: characteristic, type: .withResponse) let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.write) ? .withResponse : .withoutResponse
peripheral.writeValue(data, for: characteristic, type: writeType)
} else { } else {
// No peripheral found for targeted send // No peripheral found for targeted send
} }
@@ -768,10 +773,10 @@ class BluetoothMeshService: NSObject {
} }
} }
// Create stored message // Create stored message with original packet timestamp preserved
let storedMessage = StoredMessage( let storedMessage = StoredMessage(
packet: packet, packet: packet,
timestamp: Date(), timestamp: Date(timeIntervalSince1970: TimeInterval(packet.timestamp)),
messageID: messageID, messageID: messageID,
isForFavorite: isForFavorite isForFavorite: isForFavorite
) )
@@ -850,21 +855,14 @@ class BluetoothMeshService: NSObject {
guard let peripheral = peripheral, guard let peripheral = peripheral,
peripheral.state == .connected else { return } peripheral.state == .connected else { return }
// Create a new packet with fresh timestamp // Send the original packet with preserved timestamp
let updatedPacket = BitchatPacket( // This maintains message ordering for store-and-forward
type: storedMessage.packet.type, let packetToSend = storedMessage.packet
senderID: storedMessage.packet.senderID,
recipientID: storedMessage.packet.recipientID,
timestamp: UInt64(Date().timeIntervalSince1970),
payload: storedMessage.packet.payload,
signature: storedMessage.packet.signature,
ttl: storedMessage.packet.ttl
)
if let data = updatedPacket.toBinaryData(), if let data = packetToSend.toBinaryData(),
characteristic.properties.contains(.writeWithoutResponse) { characteristic.properties.contains(.writeWithoutResponse) {
peripheral.writeValue(data, for: characteristic, type: .withoutResponse) peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
// Sent cached message // Sent cached message with original timestamp
} }
} }
} }
@@ -1020,7 +1018,10 @@ class BluetoothMeshService: NSObject {
return return
} }
} catch { } catch {
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)") if !loggedCryptoErrors.contains(senderID) {
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)")
loggedCryptoErrors.insert(senderID)
}
} }
} }
@@ -1084,7 +1085,10 @@ class BluetoothMeshService: NSObject {
return return
} }
} catch { } catch {
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)") if !loggedCryptoErrors.contains(senderID) {
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)")
loggedCryptoErrors.insert(senderID)
}
} }
} }