fix: resolve deadlock between interface online and Transport.identity loading

Move self.online = True BEFORE waiting for Transport.identity to break circular dependency. Reticulum loads Transport.identity only after interfaces are online, so blocking before self.online = True creates infinite wait.

New sequence:
1. Set self.online = True (unblocks Reticulum startup)
2. Reticulum loads Transport.identity from storage
3. Wait completes successfully
4. Identity set on GATT server
5. GATT server starts with valid 16-byte identity

Reduced timeout from 30s to 10s since identity should load within 1s once interface is online.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
torlando-tech 2025-10-30 21:15:42 -04:00
commit d4a07d48e8

View file

@ -488,22 +488,6 @@ class BLEInterface(Interface):
else:
RNS.log(f"{self} central mode disabled, skipping peer discovery", RNS.LOG_INFO)
# Protocol v2: Wait for Transport.identity BEFORE starting GATT server
# This ensures the Identity characteristic is created with a valid value,
# preventing BlueZ from rejecting/corrupting the advertisement
if self.gatt_server:
RNS.log(f"{self} Waiting for Transport.identity before starting GATT server...", RNS.LOG_DEBUG)
identity_hash = self._wait_for_transport_identity(timeout=30)
if identity_hash:
self.gatt_server.set_transport_identity(identity_hash)
RNS.log(f"{self} Transport.identity set on GATT server: {identity_hash.hex()}", RNS.LOG_INFO)
else:
RNS.log(f"{self} WARNING: Starting GATT server without identity (Protocol v1 mode)", RNS.LOG_WARNING)
# Start GATT server if peripheral mode is enabled
if self.gatt_server:
asyncio.run_coroutine_threadsafe(self._start_server(), self.loop)
# Start periodic cleanup task (CRITICAL #2: prevent unbounded reassembly buffer growth)
asyncio.run_coroutine_threadsafe(self._periodic_cleanup(), self.loop)
@ -514,7 +498,25 @@ class BLEInterface(Interface):
# TODO: Remove when upstream Transport.py is fixed (see session notes)
self._clear_stale_ble_paths()
# Set interface online FIRST to allow Reticulum to complete startup
# (Transport.identity is loaded after interfaces are online)
self.online = True
RNS.log(f"{self} interface online, waiting for Transport.identity...", RNS.LOG_INFO)
# Protocol v2: Wait for Transport.identity BEFORE starting GATT server
# This ensures the Identity characteristic is created with a valid value,
# preventing BlueZ from rejecting/corrupting the advertisement
if self.gatt_server:
identity_hash = self._wait_for_transport_identity(timeout=10)
if identity_hash:
self.gatt_server.set_transport_identity(identity_hash)
RNS.log(f"{self} Transport.identity set on GATT server: {identity_hash.hex()}", RNS.LOG_INFO)
else:
RNS.log(f"{self} WARNING: Starting GATT server without identity (Protocol v1 mode)", RNS.LOG_WARNING)
# Start GATT server AFTER identity is set
asyncio.run_coroutine_threadsafe(self._start_server(), self.loop)
RNS.log(f"{self} started successfully", RNS.LOG_INFO)
def _run_async_loop(self):