diff --git a/src/RNS/Interfaces/BLEInterface.py b/src/RNS/Interfaces/BLEInterface.py index e618f56..b073ecf 100644 --- a/src/RNS/Interfaces/BLEInterface.py +++ b/src/RNS/Interfaces/BLEInterface.py @@ -41,6 +41,7 @@ import threading import time import asyncio from collections import deque +from typing import Optional # Add interface directory to path for importing other BLE modules # This is needed when loaded as external interface @@ -647,54 +648,43 @@ class BLEInterface(Interface): except Exception as e: RNS.log(f"{self} failed to initiate connection to {device.name}: {e}", RNS.LOG_ERROR) - def _device_connected_callback(self, address: str): + def _device_connected_callback(self, address: str, peer_identity: Optional[bytes]): """ Driver callback: Handle successful device connection. - Called when driver has established a connection. We read the identity - characteristic and prepare to receive data. + Called when driver has established a connection. For central connections, + the peer_identity is provided. For peripheral connections, identity will + arrive later via handshake. + + Args: + address: MAC address of connected peer + peer_identity: 16-byte identity hash (None for peripheral connections) """ - # Check connection role to determine identity exchange method role = self.driver.get_peer_role(address) - if role == "central": - # We are the central, we must read the peer's identity - RNS.log(f"{self} connected to {address} as CENTRAL, reading identity...", RNS.LOG_INFO) - try: - identity_bytes = self.driver.read_characteristic( - address, - BLEInterface.CHARACTERISTIC_IDENTITY_UUID - ) + if peer_identity is not None: + # Central mode: identity provided by driver + if len(peer_identity) == 16: + identity_hash = self._compute_identity_hash(peer_identity) - if identity_bytes and len(identity_bytes) == 16: - peer_identity = bytes(identity_bytes) - identity_hash = self._compute_identity_hash(peer_identity) + # Store identity mappings + self.address_to_identity[address] = peer_identity + self.identity_to_address[identity_hash] = address - # Store identity mappings - self.address_to_identity[address] = peer_identity - self.identity_to_address[identity_hash] = address - - RNS.log(f"{self} received peer identity from {address}: {identity_hash}", RNS.LOG_INFO) - self._record_connection_success(address) - else: - RNS.log(f"{self} invalid identity from {address}, disconnecting", RNS.LOG_WARNING) - self.driver.disconnect(address) - self._record_connection_failure(address) - - except Exception as e: - RNS.log(f"{self} failed to read identity from {address}: {e}", RNS.LOG_ERROR) + RNS.log(f"{self} connected to {address} as CENTRAL, received identity: {identity_hash}", RNS.LOG_INFO) + self._record_connection_success(address) + else: + RNS.log(f"{self} invalid identity from {address} (wrong length), disconnecting", RNS.LOG_WARNING) self.driver.disconnect(address) self._record_connection_failure(address) elif role == "peripheral": - # We are the peripheral, we must wait for the central to send its identity + # Peripheral mode: identity will arrive via handshake RNS.log(f"{self} connected to {address} as PERIPHERAL, waiting for identity handshake...", RNS.LOG_INFO) - # The identity will be received in `handle_peripheral_data` or `_data_received_callback` - # No action is needed here. - pass + # The identity will be received in `_data_received_callback` else: - RNS.log(f"{self} connected to {address}, but role is unknown. Disconnecting.", RNS.LOG_WARNING) + RNS.log(f"{self} connected to {address}, but identity not provided and role is {role}. Disconnecting.", RNS.LOG_WARNING) self.driver.disconnect(address) def _mtu_negotiated_callback(self, address: str, mtu: int): diff --git a/src/RNS/Interfaces/bluetooth_driver.py b/src/RNS/Interfaces/bluetooth_driver.py index b39a8ba..2274025 100644 --- a/src/RNS/Interfaces/bluetooth_driver.py +++ b/src/RNS/Interfaces/bluetooth_driver.py @@ -44,7 +44,7 @@ class BLEDriverInterface(ABC): # implement and assign these callbacks to receive events from the driver. on_device_discovered: Optional[Callable[[BLEDevice], None]] = None - on_device_connected: Optional[Callable[[str], None]] = None # address (MTU reported separately) + on_device_connected: Optional[Callable[[str, Optional[bytes]], None]] = None # address, peer_identity (None for peripheral role) on_device_disconnected: Optional[Callable[[str], None]] = None # address on_data_received: Optional[Callable[[str, bytes], None]] = None # address, data on_mtu_negotiated: Optional[Callable[[str, int], None]] = None # address, mtu diff --git a/src/RNS/Interfaces/linux_bluetooth_driver.py b/src/RNS/Interfaces/linux_bluetooth_driver.py index 6029d27..c9275b3 100644 --- a/src/RNS/Interfaces/linux_bluetooth_driver.py +++ b/src/RNS/Interfaces/linux_bluetooth_driver.py @@ -254,6 +254,7 @@ class PeerConnection: mtu: int = 23 # Negotiated MTU connection_type: str = "unknown" # "central" or "peripheral" connected_at: float = 0.0 + peer_identity: Optional[bytes] = None # 16-byte identity hash class LinuxBluetoothDriver(BLEDriverInterface): @@ -822,7 +823,8 @@ class LinuxBluetoothDriver(BLEDriverInterface): client=client, mtu=mtu, connection_type="central", - connected_at=time.time() + connected_at=time.time(), + peer_identity=peer_identity ) with self._peers_lock: @@ -846,10 +848,10 @@ class LinuxBluetoothDriver(BLEDriverInterface): except Exception as e: self._log(f"Failed to send identity handshake: {e}", "WARNING") - # Notify callback + # Notify callback with peer identity if self.on_device_connected: try: - self.on_device_connected(address) + self.on_device_connected(address, peer_identity) except Exception as e: self._log(f"Error in device connected callback: {e}", "ERROR") @@ -1511,10 +1513,10 @@ class BluezeroGATTServer: self._log(f"Central connected: {central_address} (MTU: {effective_mtu})") - # Notify callback + # Notify callback (identity not available yet for peripheral connections) if self.driver.on_device_connected: try: - self.driver.on_device_connected(central_address) + self.driver.on_device_connected(central_address, None) except Exception as e: self._log(f"Error in device connected callback: {e}", "ERROR")