def iface(self): if hasattr(self, "_iface"): iface = self._iface else: iface_methods = [] for method_name, (args_xform, returns_xform, fn) in self.methods.items(): iface_methods.append( Method( method_name, arguments=args_xform.signature(), returns=returns_xform.signature(), )) iface_properties = [] for prop_name, (xform, _, kwargs) in self.properties.items(): iface_properties.append( Property(prop_name, xform.signature(), **kwargs)) iface_signals = [] for signal_name, xform in self.signals.items(): iface_signals.append(Signal(signal_name, xform.signature())) iface = DBusInterface( f"{self.service.namespace}.{self.iface_name}", *(iface_methods + iface_properties + iface_signals), ) self._iface = iface return iface
class BlueZLEAdvertisement(DBusObject): """ org.bluez.LEAdvertisement1 interface implementation """ interface_name: str = "org.bluez.LEAdvertisement1" iface: DBusInterface = DBusInterface( interface_name, Method("Release"), Property("Type", "s"), Property("ServiceUUIDs", "as"), Property("ManufacturerData", "a{qay}"), Property("SolicitUUIDs", "as"), Property("ServiceData", "a{sv}"), Property("IncludeTxPower", "b")) dbusInterfaces: List[DBusInterface] = [iface] ad_type: DBusProperty = DBusProperty("Type") service_uuids: DBusProperty = DBusProperty("ServiceUUIDs") # manufacturer_data = DBusProperty("ManufacturerData") # solicit_uuids = DBusProperty("SolicitUUIDs") # service_data = DBusProperty("ServiceData") include_tx_power: DBusProperty = DBusProperty("IncludeTxPower") def __init__( self, advertising_type: Type, index: int, app: "BlueZGattApplication" # noqa: F821 ): """ New Low Energy Advertisement Parameters ---------- advertising_type : Type The type of advertisement index : int, The index of the advertisement app : BlueZGattApplication The Application that is responsible for this advertisement """ self.ad_type: str = advertising_type.value self.path = app.base_path + "/advertisement" + str(index) self.service_uuids: List[str] = [] self.manufacturer_data: Dict = {} self.solicit_uuids = [''] self.service_data = {'': 0} self.include_tx_power: bool = False self.data = None super(BlueZLEAdvertisement, self).__init__(self.path) @dbusMethod(interface_name, "Release") def Release(self): # noqa: N802 print("%s: Released!" % self.path)
class BlueZGattService(DBusObject): """ org.bluez.GattService1 interface implementation """ interface_name: str = defs.GATT_SERVICE_INTERFACE iface: DBusInterface = DBusInterface( interface_name, Property("UUID", "s"), Property("Primary", "b"), ) dbusInterfaces: List[DBusInterface] = [iface] uuid: DBusProperty = DBusProperty("UUID") primary: DBusProperty = DBusProperty("Primary") def __init__( self, uuid: str, primary: bool, index: int, app: 'BlueZGattApplication', # noqa: F821 ): """ Initialize the DBusObject Parameters ---------- uuid : str A string representation of the unique identifier primary : bool Whether the service is the primary service for the application it belongs to index : int The index of the service amongst the other service of the application app : BlueZApp A BlueZApp object that owns this service """ self.path: str = app.base_path + "/service" + str(index) self.bus: client = app.bus self.destination: str = app.destination self.uuid: str = uuid self.primary: bool = primary self.loop: asyncio.AbstractEventLoop = app.loop self.app: 'BlueZGattApplication' = app # noqa: F821 self.characteristics: List[BlueZGattCharacteristic] = [] super(BlueZGattService, self).__init__(self.path)
class Network(BaseIface): """Interface implemented by objects representing configured networks""" INTERFACE_PATH = 'fi.w1.wpa_supplicant1.Network' iface = DBusInterface( INTERFACE_PATH, Signal('PropertiesChanged', 'a{sv}') ) def __repr__(self): return str(self) def __str__(self): return "Network(Path: %s, Properties: %s)" % (self.get_path(), self.get_properties()) # # Properties # def get_properties(self): """Properties of the configured network Dictionary contains entries from "network" block of wpa_supplicant.conf. All values are string type, e.g., frequency is "2437", not 2437. """ network_properties = self.get('Properties') ssid = network_properties.get('ssid', '') if ssid: quote_chars = {'"', "'"} ssid = ssid[1:] if ssid[0] in quote_chars else ssid ssid = ssid[:-1] if ssid[-1] in quote_chars else ssid network_properties.update({ 'ssid': ssid }) return network_properties def get_enabled(self): """Determines if the configured network is enabled or not""" return self.get('Enabled')
to run on every PC but serves as a reference. """ from twisted.internet import reactor, defer from txdbus import client, error from txdbus.interface import DBusInterface, Method, Signal import time dbus_name = 'fi.w1.wpa_supplicant1' root_iface_str = 'fi.w1.wpa_supplicant1' root_iface_obj_path = "/" + root_iface_str.replace('.', '/') interface_iface_str = root_iface_str + ".Interface" interface_iface = DBusInterface( interface_iface_str, Signal('ScanDone', 'b'), Method('Scan', arguments='a{sv}'), Method('AddNetwork', arguments='a{sv}', returns='o'), Method('RemoveNetwork', arguments='o'), Method('SelectNetwork', arguments='o')) @defer.inlineCallbacks def set_mode_example(): cli = yield client.connect(reactor, busAddress='system') root_obj = yield cli.getRemoteObject(dbus_name, root_iface_obj_path) print "Root Object: %s" % root_obj wlan0_obj_path = yield root_obj.callRemote('GetInterface', 'wlan1') print "WLAN0 Object Path: %s" % wlan0_obj_path wlan0_obj = yield cli.getRemoteObject(dbus_name, wlan0_obj_path,
__all__ = [ 'BUS_NAME', 'OBJECT_PATH', 'si446x_dbus_interface', 'Si446xDbus', 'reactor_loop' ] BUS_NAME = 'org.tagnet.si446x' OBJECT_PATH = '/org/tagnet/si446x/0/0' # object name includes device id/port numbers si446x_dbus_interface = DBusInterface( BUS_NAME, Method('cca', returns='u'), Method('clear_status', returns='s'), Method('control', arguments='s', returns='s'), Method('dump_radio', arguments='s', returns='s'), Method('dump_trace', arguments='sissu', returns='a(dyssay)'), Method('send', arguments='ayu', returns='s'), Method('spi_send', arguments='ays', returns='s'), Method('spi_send_recv', arguments='ayuss', returns='ay'), Method('status', returns='s'), Signal('new_status', 's'), Signal('receive', 'ayu'), Signal('send_cmp', 's'), ) class Si446xDbus(objects.DBusObject): """ provides the interface for accessing the SI446x Radio Chip Driver """ dbusInterfaces = [si446x_dbus_interface]
class BlueZGattService(DBusObject): """ org.bluez.GattService1 interface implementation """ interface_name: str = defs.GATT_SERVICE_INTERFACE iface: DBusInterface = DBusInterface( interface_name, Property("UUID", "s"), Property("Primary", "b"), ) dbusInterfaces: List[DBusInterface] = [iface] uuid: DBusProperty = DBusProperty("UUID") primary: DBusProperty = DBusProperty("Primary") def __init__( self, uuid: str, primary: bool, index: int, app: "BlueZGattApplication", # noqa: F821 ): """ Initialize the DBusObject Parameters ---------- uuid : str A string representation of the unique identifier primary : bool Whether the service is the primary service for the application it belongs to index : int The index of the service amongst the other service of the application app : BlueZApp A BlueZApp object that owns this service """ hex_index: str = hex(index)[2:].rjust(4, "0") self.path: str = app.base_path + "/service" + hex_index self.bus: client = app.bus self.destination: str = app.destination self.uuid: str = uuid self.primary: bool = primary self.loop: asyncio.AbstractEventLoop = app.loop self.app: "BlueZGattApplication" = app # noqa: F821 self.characteristics: List[BlueZGattCharacteristic] = [] super(BlueZGattService, self).__init__(self.path) async def add_characteristic( self, uuid: str, flags: List[Flags], value: Any ) -> BlueZGattCharacteristic: """ Adds a BlueZGattCharacteristic to the service. Parameters ---------- uuid : str The string representation of the UUID for the characteristic flags : List[Flags], A list of flags to apply to the characteristic value : Any The characteristic's value """ index: int = len(self.characteristics) + 1 characteristic: BlueZGattCharacteristic = BlueZGattCharacteristic( uuid, flags, index, self ) characteristic.value = value self.characteristics.append(characteristic) await self.app._register_object(characteristic) return characteristic async def get_obj(self) -> Dict: """ Obtain the underlying dictionary within the BlueZ API that describes the service Returns ------- Dict The dictionary that describes the service """ dbus_obj: RemoteDBusObject = await self.app.bus.getRemoteObject( self.app.destination, self.path ).asFuture(self.app.loop) dict_obj: Dict = await dbus_obj.callRemote( "GetAll", defs.GATT_SERVICE_INTERFACE, interface=defs.PROPERTIES_INTERFACE, ).asFuture(self.app.loop) return dict_obj
class BSS(BaseIface): """Interface implemented by objects representing a scanned BSSs (scan results)""" INTERFACE_PATH = 'fi.w1.wpa_supplicant1.BSS' iface = DBusInterface( INTERFACE_PATH, Signal('PropertiesChanged', 'a{sv}') ) def __repr__(self): return str(self) def __str__(self): return "BSS(Path: %s, SSID: %s, BSSID: %s, Signal: %sdBm)" % (self.get_path(), self.get_ssid(), self.get_bssid(), self.get_signal_dbm()) def to_dict(self): """Dict representation of a BSS object""" elements = ( ('ssid', self.get_ssid), ('rsn', self.get_rsn), ('channel', self.get_channel), ('privacy', self.get_privacy), ('wpa', self.get_wpa), ('signal_dbm', self.get_signal_dbm), ('signal_quality', self.get_signal_quality), ('network_type', self.get_network_type), ('privacy', self.get_privacy), ) out = {} for k, v in elements: try: out[k] = v() except: logger.exception('Error while fetching BSS information') return out # # Properties # def get_channel(self): """Wi-Fi channel number (1-14)""" freq = self.get_frequency() if freq == 2484: # Handle channel 14 return 14 elif freq >= 2412 and freq <= 2472: return 1 + (freq - 2412) / 5 elif freq >= 5180 and freq <= 5905: return 36 + (freq - 5180) / 5 else: logger.warn('Unexpected frequency %s', freq) raise WpaSupplicantException('Unexpected frequency in WiFi connection.') def get_ssid(self): """SSID of the BSS in ASCII""" return "".join(chr(i) for i in self.get('SSID')) def get_bssid(self): """BSSID of the BSS as hex bytes delimited by a colon""" return ":".join(["{:02X}".format(i) for i in self.get('BSSID')]) def get_frequency(self): """Frequency of the BSS in MHz""" return self.get('Frequency') def get_wpa(self): """WPA information of the BSS, empty dictionary indicates no WPA support Dictionaries are:: { "KeyMgmt": <Possible array elements: "wpa-psk", "wpa-eap", "wpa-none">, "Pairwise": <Possible array elements: "ccmp", "tkip">, "Group": <Possible values are: "ccmp", "tkip", "wep104", "wep40">, "MgmtGroup": <Possible values are: "aes128cmac"> } """ return self.get('WPA') def get_rsn(self): """RSN/WPA2 information of the BSS, empty dictionary indicates no RSN support Dictionaries are:: { "KeyMgmt": <Possible array elements: "wpa-psk", "wpa-eap", "wpa-ft-psk", "wpa-ft-eap", "wpa-psk-sha256", "wpa-eap-sha256">, "Pairwise": <Possible array elements: "ccmp", "tkip">, "Group": <Possible values are: "ccmp", "tkip", "wep104", "wep40">, "MgmtGroup": <Possible values are: "aes128cmac">, } """ return self.get('RSN') def get_ies(self): """All IEs of the BSS as a chain of TLVs""" return self.get('IEs') def get_privacy(self): """Indicates if BSS supports privacy""" return self.get('Privacy') def get_mode(self): """Describes mode of the BSS Possible values are: "ad-hoc" "infrastructure" """ return self.get('Mode') def get_rates(self): """Descending ordered array of rates supported by the BSS in bits per second""" return self.get('Rates') def get_signal_dbm(self): """Signal strength of the BSS in dBm""" return self.get('Signal') def get_signal_quality(self): """Signal strength of the BSS as a percentage (0-100)""" dbm = self.get_signal_dbm() if dbm <= -100: return 0 elif dbm >= -50: return 100 else: return 2 * (dbm + 100) def get_network_type(self): """Return the network type as a string Possible values are: 'WPA' 'WPA2' 'WEP' 'OPEN' """ if self.get_privacy(): rsn_key_mgmt = self.get_rsn().get('KeyMgmt') if rsn_key_mgmt: return 'WPA2' wpa_key_mgmt = self.get_wpa().get('KeyMgmt') if wpa_key_mgmt: return 'WPA' return 'WEP' else: return 'OPEN'
class Interface(BaseIface): """Interface implemented by objects related to network interface added to wpa_supplicant""" INTERFACE_PATH = 'fi.w1.wpa_supplicant1.Interface' iface = DBusInterface( INTERFACE_PATH, Method('Scan', arguments='a{sv}'), Method('AddNetwork', arguments='a{sv}', returns='o'), Method('RemoveNetwork', arguments='o'), Method('SelectNetwork', arguments='o'), Method('Disconnect'), Signal('ScanDone', 'b'), Signal('PropertiesChanged', 'a{sv}') ) def __repr__(self): return str(self) def __str__(self): return "Interface(Path: %s, Name: %s, State: %s)" % (self.get_path(), self.get_ifname(), self.get_state()) # # Methods # def scan(self, type='active', ssids=None, ies=None, channels=None, block=False): """Triggers a scan :returns: List of `BSS` objects if block=True else None :raises InvalidArgs: Invalid argument format :raises MethodTimeout: Scan has timed out (only if block=True) :raises UnknownError: An unknown error occurred """ # TODO: Handle the other arguments scan_options = { 'Type': type } # If blocking, register for the ScanDone signal and return BSSs if block: deferred_queue = self.register_signal_once('ScanDone') self._call_remote('Scan', scan_options) # Trigger scan success = deferred_queue.get(timeout=10) if success: return [BSS(path, self._conn, self._reactor) for path in self.get_all_bss()] else: raise UnknownError('ScanDone signal received without success') else: self._call_remote('Scan', scan_options) # Trigger scan def add_network(self, network_cfg): """Adds a new network to the interface :param network_cfg: Dictionary of config, see wpa_supplicant.conf for k/v pairs :returns: `Network` object that was registered w/ wpa_supplicant :raises InvalidArgs: Invalid argument format :raises UnknownError: An unknown error occurred """ network_path = self._call_remote('AddNetwork', network_cfg) return Network(network_path, self._conn, self._reactor) def remove_network(self, network_path): """Removes a configured network from the interface :param network_path: D-Bus object path to the desired network :returns: None :raises NetworkUnknown: The specified `network_path` is invalid :raises InvalidArgs: Invalid argument format :raises UnknownError: An unknown error occurred """ self._call_remote('RemoveNetwork', network_path) def select_network(self, network_path): """Attempt association with a configured network :param network_path: D-Bus object path to the desired network :returns: None :raises NetworkUnknown: The specified `network_path` has not been added :raises InvalidArgs: Invalid argument format """ self._call_remote('SelectNetwork', network_path) def disconnect_network(self): """Disassociates the interface from current network :returns: None :raises NotConnected: The interface is not currently connected to a network """ self._call_remote('Disconnect') # # Properties # def get_ifname(self): """Name of network interface controlled by the interface, e.g., wlan0""" return self.get('Ifname') def get_current_bss(self): """BSS object path which wpa_supplicant is associated with Returns "/" if is not associated at all """ bss_path = self.get('CurrentBSS') if bss_path == '/' or bss_path is None: return None else: return BSS(bss_path, self._conn, self._reactor) def get_current_network(self): """The `Network` object which wpa_supplicant is associated with Returns `None` if is not associated at all """ network_path = self.get('CurrentNetwork') if network_path == '/' or network_path is None: return None else: return Network(network_path, self._conn, self._reactor) def get_networks(self): """List of `Network` objects representing configured networks""" networks = list() paths = self.get('Networks') for network_path in paths: if network_path == '/': networks.append(None) else: networks.append(Network(network_path, self._conn, self._reactor)) return networks def get_state(self): """A state of the interface. Possible values are: "disconnected" "inactive" "scanning" "authenticating" "associating" "associated" "4way_handshake" "group_handshake" "completed" "unknown" """ return self.get('State') def get_scanning(self): """Determines if the interface is already scanning or not""" return self.get('Scanning') def get_scan_interval(self): """Time (in seconds) between scans for a suitable AP. Must be >= 0""" return self.get('ScanInterval') def get_fast_reauth(self): """Identical to fast_reauth entry in wpa_supplicant.conf""" return self.get('FastReauth') def get_all_bss(self): """List of D-Bus objects paths representing BSSs known to the interface""" return self.get('BSSs') def get_driver(self): """Name of driver used by the interface, e.g., nl80211""" return self.get('Driver') def get_country(self): """Identical to country entry in wpa_supplicant.conf""" return self.get('Country') def get_bridge_ifname(self): """Name of bridge network interface controlled by the interface, e.g., br0""" return self.get('BridgeIfname') def get_bss_expire_age(self): """Identical to bss_expiration_age entry in wpa_supplicant.conf file""" return self.get('BSSExpireAge') def get_bss_expire_count(self): """Identical to bss_expiration_scan_count entry in wpa_supplicant.conf file""" return self.get('BSSExpireCount') def get_ap_scan(self): """Identical to ap_scan entry in wpa_supplicant configuration file. Possible values are 0, 1 or 2. """ return self.get('ApScan') def set_country(self, country_code): self.set('Country', country_code)
class WpaSupplicant(BaseIface): """Interface implemented by the main wpa_supplicant D-Bus object Registered in the bus as "fi.w1.wpa_supplicant1" """ INTERFACE_PATH = 'fi.w1.wpa_supplicant1' iface = DBusInterface( INTERFACE_PATH, Method('CreateInterface', arguments='a{sv}', returns='o'), Method('GetInterface', arguments='s', returns='o'), Method('RemoveInterface', arguments='o'), Signal('InterfaceAdded', 'o,a{sv}'), Signal('InterfaceRemoved', 'o'), Signal('PropertiesChanged', 'a{sv}') ) def __init__(self, *args, **kwargs): BaseIface.__init__(self, *args, **kwargs) self._interfaces_cache = dict() def __repr__(self): return str(self) def __str__(self): return "WpaSupplicant(Interfaces: %s)" % self.get_interfaces() # # Methods # def get_interface(self, interface_name): """Get D-Bus object related to an interface which wpa_supplicant already controls :returns: Interface object that implements the wpa_supplicant Interface API. :rtype: :class:`~Interface` :raises InterfaceUnknown: wpa_supplicant doesn't know anything about `interface_name` :raises UnknownError: An unknown error occurred """ interface_path = self._call_remote_without_introspection('GetInterface', interface_name) interface = self._interfaces_cache.get(interface_path, None) if interface is not None: return interface else: interface = Interface(interface_path, self._conn, self._reactor) self._interfaces_cache[interface_path] = interface return interface def create_interface(self, interface_name, driver=None): """Registers a wireless interface in wpa_supplicant :returns: Interface object that implements the wpa_supplicant Interface API :raises InterfaceExists: The `interface_name` specified is already registered :raises UnknownError: An unknown error occurred """ interface_path = self._call_remote_without_introspection('CreateInterface', {'Ifname': interface_name, 'Driver': driver}) return Interface(interface_path, self._conn, self._reactor) def remove_interface(self, interface_path): """Deregisters a wireless interface from wpa_supplicant :param interface_path: D-Bus object path to the interface to be removed :returns: None :raises InterfaceUnknown: wpa_supplicant doesn't know anything about `interface_name` :raises UnknownError: An unknown error occurred """ self._call_remote_without_introspection('RemoveInterface', interface_path) # # Properties # def get_debug_level(self): """Global wpa_supplicant debugging level :returns: Possible values: "msgdump" (verbose debugging) "debug" (debugging) "info" (informative) "warning" (warnings) "error" (errors) :rtype: str """ return self.get('DebugLevel') def get_debug_timestamp(self): """ Determines if timestamps are shown in debug logs""" return self.get('DebugTimestamp') def get_debug_showkeys(self): """Determines if secrets are shown in debug logs""" return self.get('DebugShowKeys') def get_interfaces(self): """An array with paths to D-Bus objects representing controlled interfaces""" return self.get('Interfaces') def get_eap_methods(self): """An array with supported EAP methods names""" return self.get('EapMethods')
class Bus(objects.DBusObject): """ DBus Bus implementation. @ivar stdIface: L{interface.DBusInterface} containing the standard bus interface @type stdIface: L{interface.DBusInterface} """ stdIface = DBusInterface( 'org.freedesktop.DBus', Method('Hello', arguments='', returns='s'), Method('GetId', arguments='', returns='s'), Method('RequestName', arguments='su', returns='u'), Method('ReleaseName', arguments='s', returns='u'), Method('ListQueuedOwners', arguments='s', returns='as'), Method('AddMatch', arguments='s', returns=''), Method('RemoveMatch', arguments='s', returns=''), Method('GetNameOwner', arguments='s', returns='s'), Method('GetConnectionUnixUser', arguments='s', returns='u'), #Not Implemented Methods Method('GetConnectionUnixProcessId', arguments='s', returns='u'), Method('ListActivatableNames', arguments='', returns='as'), Method('UpdateActivationEnvironment', arguments='a{ss}', returns=''), Method('StartServiceByName', arguments='su', returns='u'), Method('GetAdtAuditSessionData', arguments='s', returns='u'), Method('GetConnectionSELinuxSecurityContext', arguments='su', returns='ay'), Method('ReloadConfig'), Signal('NameAcquired', arguments='s'), Signal('NameLost', arguments='s'), Signal('NameOwnerChanged', arguments='sss')) dbusInterfaces = [stdIface] def __init__(self): objects.DBusObject.__init__(self, '/org/freedesktop/DBus') self.uuid = binascii.hexlify(os.urandom(16)) self.clients = dict() # maps unique_bus_id to client connection self.busNames = dict() # maps name to list of queued connections self.router = router.MessageRouter() self.next_id = 1 self.obj_handler = objects.DBusObjectHandler(self) self.obj_handler.exportObject(self) # returns the new unique bus name for the client connection def clientConnected(self, proto): """ Called when a client connects to the bus. This method assigns the new connection a unique bus name. """ proto.uniqueName = ':1.%d' % (self.next_id, ) self.next_id += 1 self.clients[proto.uniqueName] = proto def clientDisconnected(self, proto): """ Called when a client disconnects from the bus """ for rule_id in proto.matchRules: self.router.delMatch(rule_id) for busName in proto.busNames.iterkeys(): self.dbus_ReleaseName(busName, proto.uniqueName) if proto.uniqueName: del self.clients[proto.uniqueName] def sendMessage(self, msg): """ Sends the supplied message to the correct destination. The @type msg: L{message.DBusMessage} @param msg: The 'destination' field of the message must be set for method calls and returns """ if msg._messageType in (1, 2): assert msg.destination, 'Failed to specify a message destination' if msg.destination is not None: if msg.destination[0] == ':': p = self.clients.get(msg.destination, None) else: p = self.busNames.get(msg.destination, None) if p: p = p[0] #print 'SND: ', msg._messageType, ' to ', p.uniqueName, 'serial', msg.serial, if p: p.sendMessage(msg) else: log.msg('Invalid bus name in msg.destination: ' + msg.destination) else: self.router.routeMessage(msg) def messageReceived(self, p, msg): mt = msg._messageType #print 'MSG: ', mt, ' from ', p.uniqueName, ' to ', msg.destination try: if mt == 1: self.methodCallReceived(p, msg) elif mt == 2: self.methodReturnReceived(p, msg) elif mt == 3: self.errorReceived(p, msg) elif mt == 4: self.signalReceived(p, msg) if msg.destination and not msg.destination == 'org.freedesktop.DBus': self.sendMessage(msg) self.router.routeMessage(msg) except DError, e: sig = None body = None if e.errorMessage: sig = 's' body = [e.errorMessage] r = message.ErrorMessage(e.errorName, msg.serial, signature=sig, body=body) p.sendMessage(r)
class Bus(objects.DBusObject): """ DBus Bus implementation. @ivar stdIface: L{interface.DBusInterface} containing the standard bus interface @type stdIface: L{interface.DBusInterface} """ stdIface = DBusInterface( 'org.freedesktop.DBus', Method('Hello', arguments='', returns='s'), Method('GetId', arguments='', returns='s'), Method('RequestName', arguments='su', returns='u'), Method('ReleaseName', arguments='s', returns='u'), Method('ListQueuedOwners', arguments='s', returns='as'), Method('AddMatch', arguments='s', returns=''), Method('RemoveMatch', arguments='s', returns=''), Method('GetNameOwner', arguments='s', returns='s'), Method('GetConnectionUnixUser', arguments='s', returns='u'), #Not Implemented Methods Method('GetConnectionUnixProcessId', arguments='s', returns='u'), Method('ListActivatableNames', arguments='', returns='as'), Method('UpdateActivationEnvironment', arguments='a{ss}', returns=''), Method('StartServiceByName', arguments='su', returns='u'), Method('GetAdtAuditSessionData', arguments='s', returns='u'), Method('GetConnectionSELinuxSecurityContext', arguments='su', returns='ay'), Method('ReloadConfig'), Signal('NameAcquired', arguments='s'), Signal('NameLost', arguments='s'), Signal('NameOwnerChanged', arguments='sss')) dbusInterfaces = [stdIface] def __init__(self): objects.DBusObject.__init__(self, '/org/freedesktop/DBus') self.uuid = binascii.hexlify(os.urandom(16)) self.clients = dict() # maps unique_bus_id to client connection self.busNames = dict() # maps name to list of queued connections self.router = router.MessageRouter() self.next_id = 1 self.obj_handler = objects.DBusObjectHandler(self) self.obj_handler.exportObject(self) # returns the new unique bus name for the client connection def clientConnected(self, proto): """ Called when a client connects to the bus. This method assigns the new connection a unique bus name. """ proto.uniqueName = ':1.%d' % (self.next_id, ) self.next_id += 1 self.clients[proto.uniqueName] = proto def clientDisconnected(self, proto): """ Called when a client disconnects from the bus """ for rule_id in proto.matchRules: self.router.delMatch(rule_id) for busName in proto.busNames.iterkeys(): self.dbus_ReleaseName(busName, proto.uniqueName) if proto.uniqueName: del self.clients[proto.uniqueName] def sendMessage(self, msg): """ Sends the supplied message to the correct destination. The @type msg: L{message.DBusMessage} @param msg: The 'destination' field of the message must be set for method calls and returns """ if msg._messageType in (1, 2): assert msg.destination, 'Failed to specify a message destination' if msg.destination is not None: if msg.destination[0] == ':': p = self.clients.get(msg.destination, None) else: p = self.busNames.get(msg.destination, None) if p: p = p[0] #print 'SND: ', msg._messageType, ' to ', p.uniqueName, 'serial', msg.serial, if p: p.sendMessage(msg) else: log.msg('Invalid bus name in msg.destination: ' + msg.destination) else: self.router.routeMessage(msg) def messageReceived(self, p, msg): mt = msg._messageType #print 'MSG: ', mt, ' from ', p.uniqueName, ' to ', msg.destination try: if mt == 1: self.methodCallReceived(p, msg) elif mt == 2: self.methodReturnReceived(p, msg) elif mt == 3: self.errorReceived(p, msg) elif mt == 4: self.signalReceived(p, msg) if msg.destination and not msg.destination == 'org.freedesktop.DBus': self.sendMessage(msg) self.router.routeMessage(msg) except DError as e: sig = None body = None if e.errorMessage: sig = 's' body = [e.errorMessage] r = message.ErrorMessage(e.errorName, msg.serial, signature=sig, body=body) p.sendMessage(r) def methodCallReceived(self, p, msg): if msg.destination == 'org.freedesktop.DBus': self.obj_handler.handleMethodCallMessage(msg) def methodReturnReceived(self, p, msg): pass def errorReceived(self, p, msg): pass def signalReceived(self, p, msg): pass def sendSignal(self, p, member, signature=None, body=None, path='/org/freedesktop/DBus', interface='org.freedesktop.DBus'): """ Sends a signal to a specific connection @type p: L{BusProtocol} @param p: L{BusProtocol} instance to send a signal to @type member: C{string} @param member: Name of the signal to send @type path: C{string} @param path: Path of the object emitting the signal. Defaults to 'org/freedesktop/DBus' @type interface: C{string} @param interface: If specified, this specifies the interface containing the desired method. Defaults to 'org.freedesktop.DBus' @type body: None or C{list} @param body: If supplied, this is a list of signal arguments. The contents of the list must match the signature. @type signature: None or C{string} @param signature: If specified, this specifies the DBus signature of the body of the DBus Signal message. This string must be a valid Signature string as defined by the DBus specification. If the body argumnent is supplied ,\ this parameter must be provided. """ if not isinstance(body, (list, tuple)): body = [body] s = message.SignalMessage(path, member, interface, p.uniqueName, signature, body) p.sendMessage(s) def broadcastSignal(self, member, signature=None, body=None, path='/org/freedesktop/DBus', interface='org.freedesktop.DBus'): """ Sends a signal to all connections with registered interest @type member: C{string} @param member: Name of the signal to send @type path: C{string} @param path: Path of the object emitting the signal. Defaults to 'org/freedesktop/DBus' @type interface: C{string} @param interface: If specified, this specifies the interface containing the desired method. Defaults to 'org.freedesktop.DBus' @type body: None or C{list} @param body: If supplied, this is a list of signal arguments. The contents of the list must match the signature. @type signature: None or C{string} @param signature: If specified, this specifies the DBus signature of the body of the DBus Signal message. This string must be a valid Signature string as defined by the DBus specification. If the body argumnent is supplied ,\ this parameter must be provided. """ if not isinstance(body, (list, tuple)): body = [body] s = message.SignalMessage(path, member, interface, None, signature, body) self.router.routeMessage(s) #---------------------------------------------------------------- # DBus Object Interface # def dbus_Hello(self, dbusCaller=None): raise DError('org.freedesktop.DBus.Error.Failed', 'Already handled an Hello message') def dbus_GetId(self): return self.uuid def dbus_RequestName(self, name, flags, dbusCaller=None): caller = self.clients[dbusCaller] allow_replacement = bool(flags & 0x1) replace_existing = bool(flags & 0x2) do_not_queue = bool(flags & 0x4) if not name: raise DError('org.freedesktop.DBus.Error.InvalidArgs', 'Empty string is not a valid bus name') if name[0] == ':': raise DError( 'org.freedesktop.DBus.Error.InvalidArgs', 'Cannot acquire a service starting with \':\' such as "%s"' % (name, )) try: marshal.validateBusName(name) except error.MarshallingError as e: raise DError('org.freedesktop.DBus.Error.InvalidArgs', str(e)) def signalAcq(old_owner_name): self.sendSignal(caller, 'NameAcquired', 's', name) self.broadcastSignal('NameOwnerChanged', 'sss', [name, old_owner_name, caller.uniqueName]) if not name in self.busNames: self.busNames[name] = [ caller, ] caller.busNames[name] = allow_replacement signalAcq('') return client.NAME_ACQUIRED else: queue = self.busNames[name] owner = queue[0] if owner is caller: # Update the replacement flag owner.busNames[name] = allow_replacement return client.NAME_ALREADY_OWNER else: if not replace_existing: return client.NAME_IN_USE if owner.busNames[name]: del queue[0] queue.insert(0, caller) del owner.busNames[name] caller.busNames[name] = allow_replacement self.sendSignal(owner, 'NameLost', 's', name) signalAcq(owner.uniqueName) return client.NAME_ACQUIRED else: if do_not_queue: return client.NAME_IN_USE queue.append(caller) caller.busNames[name] = allow_replacement return client.NAME_IN_QUEUE def dbus_ReleaseName(self, name, dbusCaller=None): caller = self.clients[dbusCaller] queue = self.busNames.get(name, None) if queue is None: return client.NAME_NON_EXISTENT owner = queue[0] if not caller is owner: return client.NAME_NOT_OWNER del queue[0] if caller.isConnected: self.sendSignal(caller, 'NameLost', 's', name) if queue: self.sendSignal(queue[0], 'NameAcquired', 's', name) else: del self.busNames[name] return client.NAME_RELEASED def dbus_ListQueuedOwners(self, name): queue = self.busNames.get(name, None) if queue: return [p.uniqueName for p in queue] else: raise DError( 'org.freedesktop.DBus.Error.NameHasNoOwner', 'Could not get owners of name \'%s\': no such name' % (name, )) def dbus_AddMatch(self, rule, dbusCaller=None): caller = self.clients[dbusCaller] kwargs = dict(mtype=None, sender=None, interface=None, member=None, path=None, path_namespace=None, destination=None, args=None, arg_paths=None, arg0namespace=None) for item in rule.split(','): k, v = item.split('=') value = v[1:-1] if k == 'type': k = 'mtype' if k in kwargs: kwargs[k] = value elif k.startswith('arg'): if k.endswith('path'): if kwargs['arg_paths'] is None: kwargs['arg_paths'] = list() kwargs['arg_paths'].append((int(k[3:-4]), value)) else: if kwargs['args'] is None: kwargs['args'] = list() kwargs['args'].append((int(k[3:]), value)) self.router.addMatch(caller.sendMessage, **kwargs) def dbus_GetNameOwner(self, busName): if busName.startswith(':'): conn = self.clients.get(busName, None) else: conn = self.busNames.get(busName, None) if conn: conn = conn[0] if conn is None: raise DError( "org.freedesktop.DBus.Error.NameHasNoOwner", "Could not get UID of name '%s': no such name" % (busName, )) return conn.uniqueName def dbus_GetConnectionUnixUser(self, busName): if busName.startswith(':'): conn = self.clients.get(busName, None) else: conn = self.busNames.get(busName, None) if conn: conn = conn[0] if conn is None: raise DError( "org.freedesktop.DBus.Error.NameHasNoOwner", "Could not get UID of name '%s': no such name" % (busName, )) try: import pwd return pwd.getpwnam(conn.username).pw_uid except: raise DError( 'org.freedesktop.DBus.Error', "Unable to determine unix user for bus '%s'" % (busName, ))
class Rfm69DBusService(objects.DBusObject): class NotImplementedError(Exception): dbusErrorName = "org.agile-rfm69.NotImplemented" class IOError(Exception): dbusErrorName = "org.agile-rfm69.IOError" class ValueError(Exception): dbusErrorName = "org.agile-rfm69.ValueError" class TypeError(Exception): dbusErrorName = "org.agile-rfm69.TypeError" iface = DBusInterface("iot.agile.Protocol", Method("Connect"), Method("Connected", returns="b"), Method("Disconnect"), Method("Setup", arguments="a{sv}"), Method("Send", arguments="a{sv}"), Method("Receive", returns="a{sv}"), Method("Subscribe", arguments="a{sv}"), Method("StartDiscovery"), Method("StopDiscovery"), Property("Devices", "av", writeable=False), Property("Name", "s", writeable=False), Property("Driver", "s", writeable=False), Property("Data", "a{sv}", writeable=False), Property("Status", "n", writeable=False) ) _devices = DBusProperty("Devices") _name = DBusProperty("Name") _driver = DBusProperty("Driver") _lastRecord = DBusProperty("Data") _status = DBusProperty("Status") dbusInterfaces = [iface] def __init__(self, objectPath): super(Rfm69DBusService, self).__init__(objectPath) self._lastRecord = {"STATUS": "TIMEOUT"} self._status = 0 self._driver = "No driver" self._name = PROTOCOL_NAME self._devices = ["None"] self._logger = logging.getLogger() self._full_path = PROTOCOL_PATH self._connected = False self._setup = { "MODEM_CONFIG_TABLE": MODEM_CONFIG_TABLE, "MODEM_CONFIG": MODEM_CONFIG, "key": MODEM_KEY, "channel": CHANNEL } def _setModemConfig(self): # Set RFM69 registers as per config settings = MODEM_CONFIG_TABLE[self._setup["MODEM_CONFIG"]] addresses = [0x02, 0x03, 0x04, 0x05, 0x06, 0x19, 0x1a, 0x37] for value, address in zip(settings, addresses): self._rfm69.spi_write(address, value) def _setModemKey(self): self._logger.debug("enabling ecryption") self._rfm69.set_encryption(self._setup["key"]) def _getConnected(self): return self._connected def _setConnected(self, status): if status: self._connected = True else: self._connected = False def dbus_Connect(self): self._logger.debug( "%s@Connect: Connect INIT", self._full_path) if self._getConnected(): self._logger.debug( "%s@Connect: Module is already connected", self._full_path) raise self.IOError("Module is already connected.") self._logger.debug( "%s@Connect: MODE=%s", self._full_path, self._setup["MODEM_CONFIG"]) self._rfm69 = rfm69.RFM69(25, 24, 0, rfm69.RFM69Configuration(), True) self._rfm69.set_channel(self._setup["channel"]) self._rfm69.set_address(1) self._logger.debug("Class initialized") self._logger.debug("Calibrating RSSI") # self._rfm69.calibrate_rssi_threshold() self._logger.debug("Checking temperature") self._logger.debug(self._rfm69.read_temperature()) # Make sure settings are correct to talk to other radios self._setModemConfig() self._setModemKey() self._logger.debug("reading all registers") for result in self._rfm69.read_registers(): self._logger.debug(result) # Won't get here if something went wrong reading temps etc. self._setConnected(True) self._logger.debug("%s@Connect: Connect OK", self._full_path) def dbus_Connected(self): return self._connected def dbus_Disconnect(self): self._logger.debug( "%s@Disconnect: Disconnect INIT", self._full_path) self._setConnected(False) self._rfm69.disconnect() self._logger.debug("%s@Disconnect: Disconnect OK", self._full_path) def dbus_Setup(self, args): self._logger.debug("%s@Setup: Setup INIT", self._full_path) self._setup.clear() self._setup = {} modemConfigTable = args.pop("MODEM_CONFIG_TABLE", MODEM_CONFIG_TABLE) self._setup["MODEM_CONFIG_TABLE"] = modemConfigTable modemConfig = args.pop("MODEM_CONFIG", MODEM_CONFIG) self._setup["MODEM_CONFIG"] = modemConfig modemKey = args.pop("key", MODEM_KEY) self._setup["key"] = modemKey channel = args.pop("channel", CHANNEL) self._setup["channel"] = channel self._logger.debug( "%s@Setup: Parameters=%s", self._full_path, self._setup) self._logger.debug( "%s@Setup: Setup OK", self._full_path) def dbus_Send(self, args): self._logger.debug( "%s@Send: Send INIT", self._full_path) if not self._getConnected(): self._logger.debug( "%s@Send: Module is not connected", self._full_path) raise self.IOError("Module is not connected.") sendData = args.pop("DATA", "") if not sendData: self._logger.debug( "%s@Send/Rfm69: No data provided", self._full_path) raise self.ValueError("You must provide the data.") if not type(sendData) is list: self._logger.debug( "%s@Send/Rfm69: Data in wrong format", self._full_path) raise self.TypeError("You must provide the data as a list of values.") # Turn it back into bytes again, since D-Bus turns it into a list sendData = struct.pack("B"*len(sendData), *sendData) self._rfm69.send_packet(sendData) def dbus_Receive(self): self._logger.debug("%s@Receive: Receive INIT", self._full_path) if not self._getConnected(): self._logger.debug( "%s@Receive: Module is not connected", self._full_path) raise self.IOError("Module is not connected.") response = self._rfm69.wait_for_packet(timeout=60) if response: (data, rssi) = response self._logger.debug("%s@Receive: receiveDone()", self._full_path) self._lastRecord = {"DATA": data, "RSSI": rssi, "STATUS": "OK"} else: self._lastRecord = {"STATUS": "TIMEOUT"} return self._lastRecord def dbus_Subscribe(self, args): raise self.NotImplementedError("Function not supported.") def dbus_StartDiscovery(self): pass def dbus_StopDiscovery(self): pass
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # global list of tag devices that are currently within radio range # taglist = dict() #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ TAGNET_BUS_NAME = 'org.tagnet.tagmaster' # bus name for tagnet forwarder TAGNET_OBJECT_PATH = '/org/tagnet/tagmaster' tagmaster_dbus_interface = DBusInterface( TAGNET_BUS_NAME, Method('tag_list', arguments='s', returns='ay'), Signal('tag_found', 'ay'), # report new tag Signal('tag_lost', 'ay'), # report tag out of range Signal('tag_events', 'ay'), # report new tag events Signal('tagnet_status', 'ay'), ) class TagNetDbus(objects.DBusObject): """ provides the interface for accessing the tagnet port """ dbusInterfaces = [tagmaster_dbus_interface] def __init__(self, object_path): super(TagNetDbus, self).__init__(object_path) self.object_path = object_path self.obj_handler = objects.DBusObjectHandler(self)
class BlueZGattCharacteristic(DBusObject): """ org.bluez.GattCharacteristic1 interface implementation """ interface_name: str = defs.GATT_CHARACTERISTIC_INTERFACE iface: DBusInterface = DBusInterface( interface_name, Method("ReadValue", arguments="a{sv}", returns="ay"), Method("WriteValue", arguments="aya{sv}"), Method("StartNotify"), Method("StopNotify"), Property("UUID", "s"), Property("Service", "o"), Property("Value", "ay"), Property("Notifying", "b"), Property("Flags", "as"), ) dbusInterfaces: List[DBusInterface] = [iface] uuid: DBusProperty = DBusProperty("UUID") service: DBusProperty = DBusProperty("Service") flags: DBusProperty = DBusProperty("Flags") value: DBusProperty = DBusProperty("Value") notifying: DBusProperty = DBusProperty("Notifying") def __init__( self, uuid: str, flags: List[Flags], index: int, service: "BlueZGattService", # noqa: F821 ): """ Create a BlueZ Gatt Characteristic Parameters ---------- uuid : str The unique identifier for the characteristic flags : List[Flags] A list of strings that represent the properties of the characteristic index : int The index number for this characteristic in the service service : BlueZService The Gatt Service that owns this characteristic """ self.path: str = service.path + "/char" + f"{index:04d}" self.uuid: str = uuid self.flags: List[str] = [x.value for x in flags] self.service: str = service.path # noqa: F821 self._service: "BlueZGattService" = service # noqa: F821 self.value: bytes = b"" self.notifying: bool = False self.descriptors: List["BlueZGattDescriptor"] = [] # noqa: F821 super(BlueZGattCharacteristic, self).__init__(self.path) @dbusMethod(interface_name, "ReadValue") def ReadValue(self, options: Dict) -> bytearray: # noqa: N802 """ Read the value of the characteristic. This is to be fully implemented at the application level Parameters ---------- options : Dict A list of options Returns ------- bytearray The bytearray that is the value of the characteristic """ f = self._service.app.Read if f is None: raise NotImplementedError() return f(self) @dbusMethod(interface_name, "WriteValue") def WriteValue(self, value: bytearray, options: Dict): # noqa: N802 """ Write a value to the characteristic This is to be fully implemented at the application level Parameters ---------- value : bytearray The value to set options : Dict Some options for you to select from """ f = self._service.app.Write if f is None: raise NotImplementedError() f(self, value) @dbusMethod(interface_name, "StartNotify") def StartNotify(self): # noqa: N802 """ Begin a subscription to the characteristic """ f = self._service.app.StartNotify if f is None: raise NotImplementedError() f(None) self._service.app.subscribed_characteristics.append(self.uuid) @dbusMethod(interface_name, "StopNotify") def StopNotify(self): # noqa: N802 """ Stop a subscription to the characteristic """ f = self._service.app.StopNotify if f is None: raise NotImplementedError() f(None) self._service.app.subscribed_characteristics.remove(self.uuid) async def get_obj(self) -> Dict: """ Obtain the underlying dictionary within the BlueZ API that describes the characteristic Returns ------- Dict The dictionary that describes the characteristic """ dbus_obj: RemoteDBusObject = await self._service.app.bus.getRemoteObject( self._service.app.destination, self.path).asFuture(self._service.app.loop) dict_obj: Dict = await dbus_obj.callRemote( "GetAll", defs.GATT_CHARACTERISTIC_INTERFACE, interface=defs.PROPERTIES_INTERFACE, ).asFuture(self._service.app.loop) return dict_obj
from dockcomact import DockcomFsmActionHandlers from dockcomserial import DockcomSerial from dockcomdef import * import dockcomtrace __all__ = ['BUS_NAME', 'OBJECT_PATH', 'dockcom_dbus_interface', 'DockcomDbus', 'reactor_loop'] BUS_NAME = 'org.tagnet.dockcom' OBJECT_PATH = '/org/tagnet/dockcom/0/0' # object name includes device id/port numbers dockcom_dbus_interface = DBusInterface( BUS_NAME, Method('clear_status', returns='s'), Method('control', arguments='s', returns='s'), Method('dump', arguments='s', returns='s'), Method('dump_trace', arguments='s', returns='a(dyssay)'), Method('send', arguments='ayu', returns='s'), Method('status', returns='s'), Signal('new_status', 's'), Signal('receive', 'ayu'), Signal('send_cmp', 's'), ) class DockcomDbus(objects.DBusObject): """ provides the interface for accessing the Dockcom Serial Chip Driver """ dbusInterfaces = [dockcom_dbus_interface] def __init__(self, objectPath, trace=None): super(DockcomDbus,self).__init__(objectPath) self.uuid = binascii.hexlify(os.urandom(16))