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 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')
Note: There are some hardcoded values in this example and should not be expected 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
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] def __init__(self, objectPath, trace=None): super(Si446xDbus, self).__init__(objectPath) self.uuid = binascii.hexlify(os.urandom(16)) self.status = 'OFF'
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')
Note: There are some hardcoded values in this example and should not be expected 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)
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, ))
#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ # 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