diff options
author | Morgan Collett <morgan.collett@gmail.com> | 2008-11-19 14:56:25 (GMT) |
---|---|---|
committer | Morgan Collett <morgan.collett@gmail.com> | 2008-11-25 13:01:11 (GMT) |
commit | 4c1dd3b8f3cc430877b72062ae20928da7dcbee7 (patch) | |
tree | 08ccea2aa52eeaf0d5f2417c78170a621c77dd89 | |
parent | 29c07d9a113dafb4cba3665250f3cb3341393aa7 (diff) |
#6248: Port NetworkManager watcher code to NM 0.7's D-Bus API
-rw-r--r-- | src/psutils.py | 146 |
1 files changed, 82 insertions, 64 deletions
diff --git a/src/psutils.py b/src/psutils.py index 630d39c..feabefe 100644 --- a/src/psutils.py +++ b/src/psutils.py @@ -1,5 +1,6 @@ # Copyright (C) 2007, Red Hat, Inc. # Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/> +# Copyright 2008 One Laptop Per Child # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,6 +27,8 @@ except ImportError: import dbus from dbus.exceptions import DBusException import gobject +import socket +import struct _logger = logging.getLogger('s-p-s.psutils') @@ -117,15 +120,20 @@ def escape_identifier(identifier): return ''.join(ret) -NM_SERVICE = 'org.freedesktop.NetworkManager' -NM_IFACE = 'org.freedesktop.NetworkManager' -NM_IFACE_DEVICES = 'org.freedesktop.NetworkManager.Devices' -NM_PATH = '/org/freedesktop/NetworkManager' +_NM_SERVICE = 'org.freedesktop.NetworkManager' +_NM_IFACE = 'org.freedesktop.NetworkManager' +_NM_IFACE_DEVICE = 'org.freedesktop.NetworkManager.Device' +_NM_PATH = '/org/freedesktop/NetworkManager' +_NM_DEVICE_STATE_ACTIVATED = 8 +_NM_STATE_CONNECTED = 3 +_NM_STATE_DISCONNECTED = 4 +_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active' +_DBUS_PROPERTIES = 'org.freedesktop.DBus.Properties' _ip4am = None class IP4AddressMonitor(gobject.GObject): - """This class, and direct buddy IPv4 address access, will go away quite soon""" + """Monitor NetworkManager for IP4 address changes.""" __gsignals__ = { 'address-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, @@ -150,11 +158,11 @@ class IP4AddressMonitor(gobject.GObject): self._nm_has_been_present = False self._matches = [] self._addr = None - self._nm_obj = None - - sys_bus = dbus.SystemBus() - self._watch = sys_bus.watch_name_owner(NM_SERVICE, self._nm_owner_cb) - if not sys_bus.name_has_owner(NM_SERVICE): + self._nm_iface = None + self._sys_bus = dbus.SystemBus() + self._watch = self._sys_bus.watch_name_owner(_NM_SERVICE, + self._nm_owner_cb) + if not self._sys_bus.name_has_owner(_NM_SERVICE): addr, iface = self._get_address_fallback() self._update_address(addr, iface) @@ -173,82 +181,92 @@ class IP4AddressMonitor(gobject.GObject): self.emit('address-changed', new_addr, iface) def _connect_to_nm(self): - """Connect to NM device state signals to tell when the IPv4 address changes""" + """Connect to NM device state signals to watch IPv4 address changes""" try: - sys_bus = dbus.SystemBus() - proxy = sys_bus.get_object(NM_SERVICE, NM_PATH) - self._nm_obj = dbus.Interface(proxy, NM_IFACE) + nm_obj = self._sys_bus.get_object(_NM_SERVICE, _NM_PATH) + self._nm_iface = dbus.Interface(nm_obj, _NM_IFACE) except DBusException, err: _logger.debug("Error finding NetworkManager: %s" % err) self._nm_present = False + addr, iface = self._get_address_fallback() + self._update_address(addr, iface) + return + + # Detect NM 0.6 which is now unsupported, so we can use the fallback + try: + dummy = self._nm_iface.GetDevices() + except DBusException: + _logger.debug( + "Error NM 0.6 is now unsupported - we use the fallback.") + addr, iface = self._get_address_fallback() + self._update_address(addr, iface) return - sys_bus = dbus.SystemBus() - match = sys_bus.add_signal_receiver(self._nm_device_active_cb, - signal_name="DeviceNowActive", - dbus_interface=NM_IFACE) + match = self._sys_bus.add_signal_receiver( + self._nm_device_added_cb, signal_name="DeviceAdded", + dbus_interface=_NM_IFACE, bus_name=_NM_SERVICE) self._matches.append(match) - match = sys_bus.add_signal_receiver(self._nm_device_no_longer_active_cb, - signal_name="DeviceNoLongerActive", - dbus_interface=NM_IFACE, - bus_name=NM_SERVICE) + match = self._sys_bus.add_signal_receiver( + self._nm_device_removed_cb, + signal_name="DeviceRemoved", + dbus_interface=_NM_IFACE, bus_name=_NM_SERVICE) self._matches.append(match) - match = sys_bus.add_signal_receiver(self._nm_state_change_cb, - signal_name="StateChange", - dbus_interface=NM_IFACE, - bus_name=NM_SERVICE) + match = self._sys_bus.add_signal_receiver( + self._nm_state_change_cb, signal_name="StateChanged", + dbus_interface=_NM_IFACE, bus_name=_NM_SERVICE) self._matches.append(match) - state = self._nm_obj.state() - if state == 3: # NM_STATE_CONNECTED + nm_props = dbus.Interface(nm_obj, _DBUS_PROPERTIES) + state = nm_props.Get(_NM_IFACE, 'State') + if state == _NM_STATE_CONNECTED: self._query_devices() - def _device_properties_cb(self, *props): - active = props[4] - if not active: - return - act_stage = props[5] - # HACK: OLPC NM has an extra stage, so activated == 8 on OLPC - # but 7 everywhere else - if act_stage != 8 and act_stage != 7: - # not activated - return - self._update_address(props[6], props[1]) - - def _device_properties_error_cb(self, err): - _logger.debug("Error querying device properties: %s" % err) - - def _query_device_properties(self, device): - sys_bus = dbus.SystemBus() - proxy = sys_bus.get_object(NM_SERVICE, device) - dev = dbus.Interface(proxy, NM_IFACE_DEVICES) - dev.getProperties(reply_handler=self._device_properties_cb, - error_handler=self._device_properties_error_cb) - - def _get_devices_cb(self, ops): + def _query_device_properties(self, device_path): + """Query a device's properties to get IP address and interface.""" + device = self._sys_bus.get_object(_NM_SERVICE, device_path) + props = dbus.Interface(device, _DBUS_PROPERTIES) + state = props.Get(_NM_IFACE_DEVICE, 'State') + if state == _NM_DEVICE_STATE_ACTIVATED: + ip = props.Get(_NM_IFACE_DEVICE, 'Ip4Address') + ipaddr = socket.inet_ntoa(struct.pack('I', ip)) + iface = props.Get(_NM_IFACE_DEVICE, 'Interface') + self._update_address(ipaddr, iface) + + def _get_devices_cb(self, device_paths): """Query each device's properties""" - for op in ops: - self._query_device_properties(op) + for device_path in device_paths: + self._query_device_properties(device_path) def _get_devices_error_cb(self, err): _logger.debug("Error getting NetworkManager devices: %s" % err) def _query_devices(self): """Query NM for a list of network devices""" - self._nm_obj.getDevices(reply_handler=self._get_devices_cb, - error_handler=self._get_devices_error_cb) - - def _nm_device_active_cb(self, device, ssid=None): - self._query_device_properties(device) - - def _nm_device_no_longer_active_cb(self, device): + _nm_props = dbus.Interface(self._nm_iface, _DBUS_PROPERTIES) + active_connection_paths = _nm_props.Get(_NM_IFACE, 'ActiveConnections') + for conn_path in active_connection_paths: + conn = self._sys_bus.get_object(_NM_IFACE, conn_path) + conn_props = dbus.Interface(conn, _DBUS_PROPERTIES) + conn_props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices', + reply_handler=self._get_devices_cb, + error_handler=self._get_devices_error_cb) + + def _nm_device_added_cb(self, device_path): + """Handle NetworkManager DeviceAdded signal.""" + self._query_device_properties(device_path) + + def _nm_device_removed_cb(self, device_path): + """Handle NetworkManager DeviceRemoved signal.""" self._update_address(None, None) def _nm_state_change_cb(self, new_state): - if new_state == 4: # NM_STATE_DISCONNECTED + """Handle NetworkManager StateChanged signal.""" + if new_state == _NM_STATE_DISCONNECTED: self._update_address(None, None) + elif new_state == _NM_STATE_CONNECTED: + self._query_devices() def _nm_owner_cb(self, unique_name): """Clear state when NM goes away""" @@ -256,6 +274,7 @@ class IP4AddressMonitor(gobject.GObject): # NM went away, or isn't there at all self._nm_present = False for match in self._matches: + self._sys_bus.remove_signal_receiver(match) match.remove() self._matches = [] if self._nm_has_been_present: @@ -270,13 +289,12 @@ class IP4AddressMonitor(gobject.GObject): self._connect_to_nm() def _get_iface_address(self, iface): - import socket import fcntl - import struct s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) fd = s.fileno() SIOCGIFADDR = 0x8915 - addr = fcntl.ioctl(fd, SIOCGIFADDR, struct.pack('256s', iface[:15]))[20:24] + addr = fcntl.ioctl(fd, SIOCGIFADDR, + struct.pack('256s', iface[:15]))[20:24] s.close() return socket.inet_ntoa(addr), iface |