Loading floss/pandora/server/hid.py +6 −4 Original line number Diff line number Diff line Loading @@ -54,8 +54,9 @@ class HIDService(hid_grpc_aio.HIDServicer): future = self.task['set_hid_report'] future.get_loop().call_soon_threadsafe(future.set_result, None) if request.address is None: raise ValueError('Request address field must be set.') if not request.address: await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') address = utils.address_from(request.address) try: Loading @@ -64,9 +65,10 @@ class HIDService(hid_grpc_aio.HIDServicer): name = utils.create_observer_name(observer) self.bluetooth.qa_client.register_callback_observer(name, observer) if request.report_type not in iter(floss_enums.BthhReportType): raise ValueError('Invalid report type.') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Invalid report type.') if not self.bluetooth.set_hid_report(address, request.report_type, request.report): raise RuntimeError('Failed to call set_hid_report.') await context.abort(grpc.StatusCode.UNKNOWN, 'Failed to call set_hid_report.') await asyncio.wait_for(set_hid_report, timeout=5) Loading floss/pandora/server/host.py +29 −26 Original line number Diff line number Diff line Loading @@ -21,8 +21,8 @@ import uuid as uuid_module from floss.pandora.floss import adapter_client from floss.pandora.floss import advertising_client from floss.pandora.floss import floss_enums from floss.pandora.floss import scanner_client from floss.pandora.floss import gatt_client from floss.pandora.floss import scanner_client from floss.pandora.floss import utils from floss.pandora.server import bluetooth as bluetooth_module from google.protobuf import empty_pb2 Loading Loading @@ -165,7 +165,8 @@ class HostService(host_grpc_aio.HostServicer): success, reason = await connect_device if not success: raise RuntimeError(f'Failed to connect to the {address}. Reason: {reason}') await context.abort(grpc.StatusCode.UNKNOWN, f'Failed to connect to the {address}. Reason: {reason}.') else: if not self.security.manually_confirm: create_bond = asyncio.get_running_loop().create_future() Loading @@ -181,13 +182,14 @@ class HostService(host_grpc_aio.HostServicer): self.bluetooth.adapter_client.register_callback_observer(name, observer) if not self.bluetooth.create_bond(address, floss_enums.BtTransport.BREDR): raise RuntimeError('Failed to call create_bond.') await context.abort(grpc.StatusCode.UNKNOWN, 'Failed to call create_bond.') if not self.security.manually_confirm: success, reason = await create_bond if not success: raise RuntimeError(f'Failed to connect to the {address}. Reason: {reason}') await context.abort(grpc.StatusCode.UNKNOWN, f'Failed to connect to the {address}. Reason: {reason}.') if self.bluetooth.is_bonded(address) and self.bluetooth.is_connected(address): self.bluetooth.connect_device(address) Loading Loading @@ -215,8 +217,9 @@ class HostService(host_grpc_aio.HostServicer): future = self.task['wait_connection'] future.get_loop().call_soon_threadsafe(future.set_result, address) if request.address is None: raise ValueError('Request address field must be set.') if not request.address: await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') address = utils.address_from(request.address) if not self.bluetooth.is_connected(address) or address not in self.waited_connections: Loading Loading @@ -257,11 +260,11 @@ class HostService(host_grpc_aio.HostServicer): future.get_loop().call_soon_threadsafe(future.set_result, (connected, None)) if not request.address: raise ValueError('Connect LE: Request address field must be set') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') own_address_type = request.own_address_type if own_address_type not in (host_pb2.RANDOM, host_pb2.RESOLVABLE_OR_RANDOM): raise RuntimeError(f'ConnectLE: Unsupported OwnAddressType: {own_address_type}.') await context.abort(grpc.StatusCode.UNIMPLEMENTED, f'Unsupported OwnAddressType: {own_address_type}.') address = utils.address_from(request.address) self.initiated_le_connection.add(address) Loading @@ -273,7 +276,8 @@ class HostService(host_grpc_aio.HostServicer): self.bluetooth.gatt_connect(address, True, floss_enums.BtTransport.LE) connected, reason = await connect_le_device if not connected: raise RuntimeError(f'Failed to connect to the address: {address}. Reason: {reason}') await context.abort(grpc.StatusCode.UNKNOWN, f'Failed to connect to the address: {address}. Reason: {reason}.') finally: self.bluetooth.gatt_client.unregister_callback_observer(name, observer) Loading Loading @@ -305,8 +309,9 @@ class HostService(host_grpc_aio.HostServicer): future = self.task['wait_disconnection'] future.get_loop().call_soon_threadsafe(future.set_result, address) if request.address is None: raise ValueError('Request address field must be set') if not request.address: await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') address = utils.address_from(request.address) if self.bluetooth.is_connected(address): Loading Loading @@ -401,22 +406,21 @@ class HostService(host_grpc_aio.HostServicer): self.bluetooth.adapter_client.register_callback_observer(name, observer) observers.append((name, observer)) while True: if not self.bluetooth.advertising_client.active_advs: reg_id = self.bluetooth.start_advertising_set(parameters, advertise_data, None, None, None, 0, 0) advertising_request = { 'start_advertising': asyncio.get_running_loop().create_future(), 'reg_id': reg_id } advertising_request = {'start_advertising': asyncio.get_running_loop().create_future(), 'reg_id': reg_id} observer = AdvertisingObserver(advertising_request) name = utils.create_observer_name(observer) self.bluetooth.advertising_client.register_callback_observer(name, observer) observers.append((name, observer)) advertiser_id = await asyncio.wait_for(advertising_request['start_advertising'], timeout=5) if advertiser_id is None: await context.abort(grpc.StatusCode.UNKNOWN, 'Failed to start advertising.') started_ids.append(advertiser_id) while True: if not request.connectable: await asyncio.sleep(1) continue Loading @@ -428,7 +432,6 @@ class HostService(host_grpc_aio.HostServicer): yield host_pb2.AdvertiseResponse( connection=utils.connection_to(utils.Connection(address, floss_enums.BtTransport.LE))) # Wait a small delay before restarting the advertisement. await asyncio.sleep(1) finally: for name, observer in observers: Loading floss/pandora/server/security.py +16 −15 Original line number Diff line number Diff line Loading @@ -101,7 +101,8 @@ class SecurityService(security_grpc_aio.SecurityServicer): if level == security_pb2.LE_LEVEL1: return True if level == security_pb2.LE_LEVEL4: raise RuntimeError(f'wait_le_security_level: Low-energy level 4 not supported') logging.error('wait_le_security_level: Low-energy level 4 not supported.') return False if self.bluetooth.is_bonded(address): is_bonded = True Loading @@ -122,7 +123,9 @@ class SecurityService(security_grpc_aio.SecurityServicer): return is_encrypted if level == security_pb2.LE_LEVEL3: return is_encrypted and is_bonded raise ValueError(f'wait_le_security_level: Invalid security level {level}') logging.error('wait_le_security_level: Invalid security level %s.', level) return False async def wait_classic_security_level(self, level, address): Loading Loading @@ -151,7 +154,8 @@ class SecurityService(security_grpc_aio.SecurityServicer): if level == security_pb2.LEVEL0: return True if level == security_pb2.LEVEL3: raise RuntimeError('wait_classic_security_level: Classic level 3 not supported') logging.error('wait_classic_security_level: Classic level 3 not supported') return False if self.bluetooth.is_bonded(address): is_bonded = True Loading Loading @@ -311,28 +315,29 @@ class SecurityService(security_grpc_aio.SecurityServicer): if transport == floss_enums.BtTransport.LE: if not request.HasField('le'): raise RuntimeError('Secure: Request le field must be set.') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request le field must be set.') if request.le == security_pb2.LE_LEVEL1: security_level_reached = True elif request.le == security_pb2.LE_LEVEL4: raise RuntimeError('Secure: Low-energy security level 4 not supported') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Low-energy security level 4 is not supported.') else: if not self.bluetooth.is_bonded(address): self.bluetooth.create_bond(address, transport) security_level_reached = await self.wait_le_security_level(request.le, address) elif transport == floss_enums.BtTransport.BREDR: if not request.HasField('classic'): raise RuntimeError('Secure: Request classic field must be set.') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request classic field must be set.') if request.classic == security_pb2.LEVEL0: security_level_reached = True elif request.classic >= security_pb2.LEVEL3: raise RuntimeError('Secure: Classic security level up to 3 not supported') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Classic security level up to 3 is not supported.') else: if not self.bluetooth.is_bonded(address): self.bluetooth.create_bond(address, transport) security_level_reached = await self.wait_classic_security_level(request.classic, address) else: raise RuntimeError(f'Secure: Invalid bluetooth transport type: {transport}') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f'Invalid bluetooth transport type: {transport}.') secure_response = security_pb2.SecureResponse() if security_level_reached: Loading @@ -351,7 +356,7 @@ class SecurityService(security_grpc_aio.SecurityServicer): elif transport == floss_enums.BtTransport.BREDR: security_level_reached = await self.wait_classic_security_level(request.classic, address) else: raise RuntimeError(f'WaitSecurity: Invalid bluetooth transport type: {transport}') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f'Invalid bluetooth transport type: {transport}.') wait_security_response = security_pb2.WaitSecurityResponse() if security_level_reached: Loading @@ -376,8 +381,6 @@ class SecurityStorageService(security_grpc_aio.SecurityStorageServicer): async def IsBonded(self, request: security_pb2.IsBondedRequest, context: grpc.ServicerContext) -> wrappers_pb2.BoolValue: if not (request.HasField('public') or request.HasField('random')): raise ValueError('Invalid request address field.') address = utils.address_from(request.address) is_bonded = self.bluetooth.is_bonded(address) Loading Loading @@ -411,9 +414,6 @@ class SecurityStorageService(security_grpc_aio.SecurityStorageServicer): future.set_result, (False, f'{address} failed on remove_bond, got bond state {state},' f' want {floss_enums.BondState.NOT_BONDED}')) if not (request.HasField('public') or request.HasField('random')): raise ValueError('Invalid request address field.') address = utils.address_from(request.address) if not self.bluetooth.is_bonded(address): return empty_pb2.Empty() Loading @@ -425,7 +425,8 @@ class SecurityStorageService(security_grpc_aio.SecurityStorageServicer): self.bluetooth.remove_bond(address) success, reason = await remove_bond if not success: raise RuntimeError(f'Failed to remove bond of address: {address}. Reason: {reason}') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f'Failed to remove bond of address: {address}. Reason: {reason}.') finally: self.bluetooth.adapter_client.unregister_callback_observer(name, observer) return empty_pb2.Empty() Loading
floss/pandora/server/hid.py +6 −4 Original line number Diff line number Diff line Loading @@ -54,8 +54,9 @@ class HIDService(hid_grpc_aio.HIDServicer): future = self.task['set_hid_report'] future.get_loop().call_soon_threadsafe(future.set_result, None) if request.address is None: raise ValueError('Request address field must be set.') if not request.address: await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') address = utils.address_from(request.address) try: Loading @@ -64,9 +65,10 @@ class HIDService(hid_grpc_aio.HIDServicer): name = utils.create_observer_name(observer) self.bluetooth.qa_client.register_callback_observer(name, observer) if request.report_type not in iter(floss_enums.BthhReportType): raise ValueError('Invalid report type.') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Invalid report type.') if not self.bluetooth.set_hid_report(address, request.report_type, request.report): raise RuntimeError('Failed to call set_hid_report.') await context.abort(grpc.StatusCode.UNKNOWN, 'Failed to call set_hid_report.') await asyncio.wait_for(set_hid_report, timeout=5) Loading
floss/pandora/server/host.py +29 −26 Original line number Diff line number Diff line Loading @@ -21,8 +21,8 @@ import uuid as uuid_module from floss.pandora.floss import adapter_client from floss.pandora.floss import advertising_client from floss.pandora.floss import floss_enums from floss.pandora.floss import scanner_client from floss.pandora.floss import gatt_client from floss.pandora.floss import scanner_client from floss.pandora.floss import utils from floss.pandora.server import bluetooth as bluetooth_module from google.protobuf import empty_pb2 Loading Loading @@ -165,7 +165,8 @@ class HostService(host_grpc_aio.HostServicer): success, reason = await connect_device if not success: raise RuntimeError(f'Failed to connect to the {address}. Reason: {reason}') await context.abort(grpc.StatusCode.UNKNOWN, f'Failed to connect to the {address}. Reason: {reason}.') else: if not self.security.manually_confirm: create_bond = asyncio.get_running_loop().create_future() Loading @@ -181,13 +182,14 @@ class HostService(host_grpc_aio.HostServicer): self.bluetooth.adapter_client.register_callback_observer(name, observer) if not self.bluetooth.create_bond(address, floss_enums.BtTransport.BREDR): raise RuntimeError('Failed to call create_bond.') await context.abort(grpc.StatusCode.UNKNOWN, 'Failed to call create_bond.') if not self.security.manually_confirm: success, reason = await create_bond if not success: raise RuntimeError(f'Failed to connect to the {address}. Reason: {reason}') await context.abort(grpc.StatusCode.UNKNOWN, f'Failed to connect to the {address}. Reason: {reason}.') if self.bluetooth.is_bonded(address) and self.bluetooth.is_connected(address): self.bluetooth.connect_device(address) Loading Loading @@ -215,8 +217,9 @@ class HostService(host_grpc_aio.HostServicer): future = self.task['wait_connection'] future.get_loop().call_soon_threadsafe(future.set_result, address) if request.address is None: raise ValueError('Request address field must be set.') if not request.address: await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') address = utils.address_from(request.address) if not self.bluetooth.is_connected(address) or address not in self.waited_connections: Loading Loading @@ -257,11 +260,11 @@ class HostService(host_grpc_aio.HostServicer): future.get_loop().call_soon_threadsafe(future.set_result, (connected, None)) if not request.address: raise ValueError('Connect LE: Request address field must be set') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') own_address_type = request.own_address_type if own_address_type not in (host_pb2.RANDOM, host_pb2.RESOLVABLE_OR_RANDOM): raise RuntimeError(f'ConnectLE: Unsupported OwnAddressType: {own_address_type}.') await context.abort(grpc.StatusCode.UNIMPLEMENTED, f'Unsupported OwnAddressType: {own_address_type}.') address = utils.address_from(request.address) self.initiated_le_connection.add(address) Loading @@ -273,7 +276,8 @@ class HostService(host_grpc_aio.HostServicer): self.bluetooth.gatt_connect(address, True, floss_enums.BtTransport.LE) connected, reason = await connect_le_device if not connected: raise RuntimeError(f'Failed to connect to the address: {address}. Reason: {reason}') await context.abort(grpc.StatusCode.UNKNOWN, f'Failed to connect to the address: {address}. Reason: {reason}.') finally: self.bluetooth.gatt_client.unregister_callback_observer(name, observer) Loading Loading @@ -305,8 +309,9 @@ class HostService(host_grpc_aio.HostServicer): future = self.task['wait_disconnection'] future.get_loop().call_soon_threadsafe(future.set_result, address) if request.address is None: raise ValueError('Request address field must be set') if not request.address: await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request address field must be set.') address = utils.address_from(request.address) if self.bluetooth.is_connected(address): Loading Loading @@ -401,22 +406,21 @@ class HostService(host_grpc_aio.HostServicer): self.bluetooth.adapter_client.register_callback_observer(name, observer) observers.append((name, observer)) while True: if not self.bluetooth.advertising_client.active_advs: reg_id = self.bluetooth.start_advertising_set(parameters, advertise_data, None, None, None, 0, 0) advertising_request = { 'start_advertising': asyncio.get_running_loop().create_future(), 'reg_id': reg_id } advertising_request = {'start_advertising': asyncio.get_running_loop().create_future(), 'reg_id': reg_id} observer = AdvertisingObserver(advertising_request) name = utils.create_observer_name(observer) self.bluetooth.advertising_client.register_callback_observer(name, observer) observers.append((name, observer)) advertiser_id = await asyncio.wait_for(advertising_request['start_advertising'], timeout=5) if advertiser_id is None: await context.abort(grpc.StatusCode.UNKNOWN, 'Failed to start advertising.') started_ids.append(advertiser_id) while True: if not request.connectable: await asyncio.sleep(1) continue Loading @@ -428,7 +432,6 @@ class HostService(host_grpc_aio.HostServicer): yield host_pb2.AdvertiseResponse( connection=utils.connection_to(utils.Connection(address, floss_enums.BtTransport.LE))) # Wait a small delay before restarting the advertisement. await asyncio.sleep(1) finally: for name, observer in observers: Loading
floss/pandora/server/security.py +16 −15 Original line number Diff line number Diff line Loading @@ -101,7 +101,8 @@ class SecurityService(security_grpc_aio.SecurityServicer): if level == security_pb2.LE_LEVEL1: return True if level == security_pb2.LE_LEVEL4: raise RuntimeError(f'wait_le_security_level: Low-energy level 4 not supported') logging.error('wait_le_security_level: Low-energy level 4 not supported.') return False if self.bluetooth.is_bonded(address): is_bonded = True Loading @@ -122,7 +123,9 @@ class SecurityService(security_grpc_aio.SecurityServicer): return is_encrypted if level == security_pb2.LE_LEVEL3: return is_encrypted and is_bonded raise ValueError(f'wait_le_security_level: Invalid security level {level}') logging.error('wait_le_security_level: Invalid security level %s.', level) return False async def wait_classic_security_level(self, level, address): Loading Loading @@ -151,7 +154,8 @@ class SecurityService(security_grpc_aio.SecurityServicer): if level == security_pb2.LEVEL0: return True if level == security_pb2.LEVEL3: raise RuntimeError('wait_classic_security_level: Classic level 3 not supported') logging.error('wait_classic_security_level: Classic level 3 not supported') return False if self.bluetooth.is_bonded(address): is_bonded = True Loading Loading @@ -311,28 +315,29 @@ class SecurityService(security_grpc_aio.SecurityServicer): if transport == floss_enums.BtTransport.LE: if not request.HasField('le'): raise RuntimeError('Secure: Request le field must be set.') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request le field must be set.') if request.le == security_pb2.LE_LEVEL1: security_level_reached = True elif request.le == security_pb2.LE_LEVEL4: raise RuntimeError('Secure: Low-energy security level 4 not supported') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Low-energy security level 4 is not supported.') else: if not self.bluetooth.is_bonded(address): self.bluetooth.create_bond(address, transport) security_level_reached = await self.wait_le_security_level(request.le, address) elif transport == floss_enums.BtTransport.BREDR: if not request.HasField('classic'): raise RuntimeError('Secure: Request classic field must be set.') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Request classic field must be set.') if request.classic == security_pb2.LEVEL0: security_level_reached = True elif request.classic >= security_pb2.LEVEL3: raise RuntimeError('Secure: Classic security level up to 3 not supported') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, 'Classic security level up to 3 is not supported.') else: if not self.bluetooth.is_bonded(address): self.bluetooth.create_bond(address, transport) security_level_reached = await self.wait_classic_security_level(request.classic, address) else: raise RuntimeError(f'Secure: Invalid bluetooth transport type: {transport}') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f'Invalid bluetooth transport type: {transport}.') secure_response = security_pb2.SecureResponse() if security_level_reached: Loading @@ -351,7 +356,7 @@ class SecurityService(security_grpc_aio.SecurityServicer): elif transport == floss_enums.BtTransport.BREDR: security_level_reached = await self.wait_classic_security_level(request.classic, address) else: raise RuntimeError(f'WaitSecurity: Invalid bluetooth transport type: {transport}') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f'Invalid bluetooth transport type: {transport}.') wait_security_response = security_pb2.WaitSecurityResponse() if security_level_reached: Loading @@ -376,8 +381,6 @@ class SecurityStorageService(security_grpc_aio.SecurityStorageServicer): async def IsBonded(self, request: security_pb2.IsBondedRequest, context: grpc.ServicerContext) -> wrappers_pb2.BoolValue: if not (request.HasField('public') or request.HasField('random')): raise ValueError('Invalid request address field.') address = utils.address_from(request.address) is_bonded = self.bluetooth.is_bonded(address) Loading Loading @@ -411,9 +414,6 @@ class SecurityStorageService(security_grpc_aio.SecurityStorageServicer): future.set_result, (False, f'{address} failed on remove_bond, got bond state {state},' f' want {floss_enums.BondState.NOT_BONDED}')) if not (request.HasField('public') or request.HasField('random')): raise ValueError('Invalid request address field.') address = utils.address_from(request.address) if not self.bluetooth.is_bonded(address): return empty_pb2.Empty() Loading @@ -425,7 +425,8 @@ class SecurityStorageService(security_grpc_aio.SecurityStorageServicer): self.bluetooth.remove_bond(address) success, reason = await remove_bond if not success: raise RuntimeError(f'Failed to remove bond of address: {address}. Reason: {reason}') await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f'Failed to remove bond of address: {address}. Reason: {reason}.') finally: self.bluetooth.adapter_client.unregister_callback_observer(name, observer) return empty_pb2.Empty()