From 04bc9e1cd3544445d883ad29ea108c1645c8e7b7 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Mon, 4 Jun 2018 00:07:45 +0200 Subject: New upstream version 1.11.4 --- tools/create-exports-NetworkManager.sh | 2 +- tools/debug-helper.py | 10 +- tools/run-nm-test.sh | 44 +- tools/test-networkmanager-service.py | 1514 +++++++++++++++++--------------- 4 files changed, 869 insertions(+), 701 deletions(-) (limited to 'tools') diff --git a/tools/create-exports-NetworkManager.sh b/tools/create-exports-NetworkManager.sh index b44e44bf..68752c54 100755 --- a/tools/create-exports-NetworkManager.sh +++ b/tools/create-exports-NetworkManager.sh @@ -19,7 +19,7 @@ die() { _build() { git clean -fdx ./autogen.sh --enable-ld-gc --enable-ifcfg-rh --enable-ifupdown \ - --enable-ifnet --enable-ibft --enable-teamdctl --enable-wifi \ + --enable-ibft --enable-teamdctl --enable-wifi \ --with-modem-manager-1 --with-ofono --with-more-asserts \ --with-more-logging make -j20 diff --git a/tools/debug-helper.py b/tools/debug-helper.py index 07338242..b841c39c 100755 --- a/tools/debug-helper.py +++ b/tools/debug-helper.py @@ -30,27 +30,27 @@ if args.do_set_nm_logging: dom_msg = "" if args.log_domains: dom_msg = " for domains: " + ','.join(args.log_domains) - print "Setting NetworkManager log level to '" + args.do_set_nm_logging + "'" + dom_msg + print("Setting NetworkManager log level to '" + args.do_set_nm_logging + "'" + dom_msg) nm_bus = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager') nm = dbus.Interface(nm_bus, dbus_interface='org.freedesktop.NetworkManager') nm.SetLogging(args.do_set_nm_logging, ','.join(args.log_domains)) if args.do_set_mm_logging: - print "Setting ModemManager log level to '" + args.do_set_mm_logging + "'" + print("Setting ModemManager log level to '" + args.do_set_mm_logging + "'") mm_bus = bus.get_object('org.freedesktop.ModemManager', '/org/freedesktop/ModemManager') mm = dbus.Interface(mm_bus, dbus_interface='org.freedesktop.ModemManager') mm.SetLogging(args.do_set_mm_logging) if args.do_set_wpa_logging: - print "Setting wpa_supplicant log level to '" + args.do_set_wpa_logging + "'" + print("Setting wpa_supplicant log level to '" + args.do_set_wpa_logging + "'") if 'debug' in args.do_set_wpa_logging or 'msgdump' in args.do_set_wpa_logging: - print "Enabling timestamps for wpasupplicant debugging logs" + print("Enabling timestamps for wpasupplicant debugging logs") use_timestamps = dbus.Boolean(True, variant_level=1) else: - print "Disabling timestamps for wpasupplicant debugging logs" + print("Disabling timestamps for wpasupplicant debugging logs") use_timestamps = dbus.Boolean(False, variant_level=1) wpa_bus = bus.get_object('fi.w1.wpa_supplicant1', '/fi/w1/wpa_supplicant1') diff --git a/tools/run-nm-test.sh b/tools/run-nm-test.sh index 5848d0a0..29ac7cd3 100755 --- a/tools/run-nm-test.sh +++ b/tools/run-nm-test.sh @@ -34,8 +34,17 @@ else CALLED_FROM_MAKE=0 fi +BUILDDIR= + if [ "$CALLED_FROM_MAKE" == 1 ]; then - NMTST_LIBTOOL=($1 --mode=execute); shift + BUILDDIR="$1" + shift + if [ -n "$1" ]; then + NMTST_LIBTOOL=($1 --mode=execute); + else + NMTST_LIBTOOL=() + fi + shift NMTST_VALGRIND_ARG="$1"; shift if [[ "$NMTST_VALGRIND_ARG" == no ]]; then NMTST_VALGRIND_ARG= @@ -121,6 +130,10 @@ else NMTST_USE_VALGRIND=0 shift; ;; + "-d") + NMTST_SET_DEBUG=1 + shift; + ;; "--test"|-t) shift TEST="$1" @@ -135,6 +148,7 @@ else ;; esac done + # we support calling the script directly. In this case, # only pass the path to the test to run. if test -z "${TEST+x}"; then @@ -144,6 +158,24 @@ else NMTST_SUPPRESSIONS="$SCRIPT_PATH/../valgrind.suppressions" fi + if [[ -z "$NMTST_BUILDDIR" ]]; then + if [[ "${NMTST_BUILDDIR-x}" == x ]]; then + # autodetect + BUILDDIR="$(readlink -f "$TEST")" + while [[ -n "$BUILDDIR" ]]; do + BUILDDIR="$(dirname "$BUILDDIR")" + [[ "$BUILDDIR" == / ]] && BUILDDIR= + [[ -z "$BUILDDIR" ]] && break + [[ -e "$BUILDDIR/libnm/.libs/libnm.so" ]] && break + [[ -e "$BUILDDIR/libnm/libnm.so" ]] && break + done + fi + fi + +fi + +if [ "$NMTST_SET_DEBUG" == 1 -a -z "${NMTST_DEBUG+x}" ]; then + export NMTST_DEBUG=d fi if _is_true "$NMTST_MAKE_FIRST" 0; then @@ -185,6 +217,16 @@ fi [ -x "$TEST" ] || die "Cannot execute test \"$TEST\"" +if [[ -n "$BUILDDIR" ]]; then + if [[ -d "$BUILDDIR/libnm" ]]; then + export GI_TYPELIB_PATH="$BUILDDIR/libnm/${GI_TYPELIB_PATH:+:$GI_TYPELIB_PATH}" + if [[ -d "$BUILDDIR/libnm/.libs" ]]; then + export LD_LIBRARY_PATH="$BUILDDIR/libnm/.libs${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" + else + export LD_LIBRARY_PATH="$BUILDDIR/libnm${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" + fi + fi +fi if ! _is_true "$NMTST_USE_VALGRIND" 0; then "${NMTST_DBUS_RUN_SESSION[@]}" \ diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index 68097778..8563aa19 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -3,68 +3,46 @@ from __future__ import print_function -from gi.repository import GLib import sys + +import gi +from gi.repository import GLib + +try: + gi.require_version('NM', '1.0') + from gi.repository import NM +except Exception as e: + print("Cannot load gi.NM: %s" % (str(e))) + sys.exit(77) + import dbus import dbus.service import dbus.mainloop.glib import random import collections import uuid +import hashlib + +############################################################################### + +_DEFAULT_ARG = object() + +############################################################################### + +class Global: + pass + +gl = None + +############################################################################### + +class TestError(AssertionError): + def __init__(self, message = 'Unspecified error', errors = None): + AssertionError.__init__(self, message) + self.errors = errors + +############################################################################### -mainloop = GLib.MainLoop() - -# NM State -NM_STATE_UNKNOWN = 0 -NM_STATE_ASLEEP = 10 -NM_STATE_DISCONNECTED = 20 -NM_STATE_DISCONNECTING = 30 -NM_STATE_CONNECTING = 40 -NM_STATE_CONNECTED_LOCAL = 50 -NM_STATE_CONNECTED_SITE = 60 -NM_STATE_CONNECTED_GLOBAL = 70 - -# Device state -NM_DEVICE_STATE_UNKNOWN = 0 -NM_DEVICE_STATE_UNMANAGED = 10 -NM_DEVICE_STATE_UNAVAILABLE = 20 -NM_DEVICE_STATE_DISCONNECTED = 30 -NM_DEVICE_STATE_PREPARE = 40 -NM_DEVICE_STATE_CONFIG = 50 -NM_DEVICE_STATE_NEED_AUTH = 60 -NM_DEVICE_STATE_IP_CONFIG = 70 -NM_DEVICE_STATE_IP_CHECK = 80 -NM_DEVICE_STATE_SECONDARIES = 90 -NM_DEVICE_STATE_ACTIVATED = 100 -NM_DEVICE_STATE_DEACTIVATING = 110 -NM_DEVICE_STATE_FAILED = 120 - -# Device type -NM_DEVICE_TYPE_UNKNOWN = 0 -NM_DEVICE_TYPE_ETHERNET = 1 -NM_DEVICE_TYPE_WIFI = 2 -NM_DEVICE_TYPE_UNUSED1 = 3 -NM_DEVICE_TYPE_UNUSED2 = 4 -NM_DEVICE_TYPE_BT = 5 -NM_DEVICE_TYPE_OLPC_MESH = 6 -NM_DEVICE_TYPE_WIMAX = 7 -NM_DEVICE_TYPE_MODEM = 8 -NM_DEVICE_TYPE_INFINIBAND = 9 -NM_DEVICE_TYPE_BOND = 10 -NM_DEVICE_TYPE_VLAN = 11 -NM_DEVICE_TYPE_ADSL = 12 -NM_DEVICE_TYPE_BRIDGE = 13 -NM_DEVICE_TYPE_GENERIC = 14 -NM_DEVICE_TYPE_TEAM = 15 - -# AC state -NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0 -NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1 -NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2 -NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3 -NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4 - -######################################################### IFACE_DBUS = 'org.freedesktop.DBus' class UnknownInterfaceException(dbus.DBusException): @@ -73,53 +51,166 @@ class UnknownInterfaceException(dbus.DBusException): class UnknownPropertyException(dbus.DBusException): _dbus_error_name = IFACE_DBUS + '.UnknownProperty' -def to_path_array(src): - array = dbus.Array([], signature=dbus.Signature('o')) - for o in src: - array.append(to_path(o)) - return array +class Util: + + @staticmethod + def pseudorandom_stream(seed, length = None): + seed = str(seed) + v = None + i = 0 + while length is None or length > 0: + if not v: + s = seed + str(i) + s = s.encode('utf8') + v = hashlib.sha256(s).hexdigest() + i += 1 + yield int(v[0:2], 16) + v = v[2:] + if length is not None: + length -= 1 + + @staticmethod + def pseudorandom_num(seed, v_end, v_start = 0): + n = 0 + span = v_end - v_start + for r in Util.pseudorandom_stream(seed): + n = n * 256 + r + if n > span: + break + return v_start + (n % span) + + @staticmethod + def random_mac(seed = None): + if seed is None: + r = tuple([random.randint(0, 255) for x in range(6)]) + else: + r = tuple(Util.pseudorandom_stream(seed, 6)) + return '%02X:%02X:%02X:%02X:%02X:%02X' % r -def to_path(src): - if src: - return dbus.ObjectPath(src.path) - return dbus.ObjectPath("/") +############################################################################### class ExportedObj(dbus.service.Object): - DBusInterface = collections.namedtuple('DBusInterface', ['dbus_iface', 'get_props_func', 'prop_changed_func']) + DBusInterface = collections.namedtuple('DBusInterface', ['dbus_iface', 'props', 'legacy_prop_changed_func']) + + @staticmethod + def create_path(klass, path_prefix = None): + if path_prefix is None: + path_prefix = klass.path_prefix + path = path_prefix + str(klass.path_counter_next) + klass.path_counter_next += 1 + return path + + @staticmethod + def to_path_array(src): + array = dbus.Array([], signature=dbus.Signature('o')) + if src is not None: + for o in src: + array.append(ExportedObj.to_path(o)) + return array - def __init__(self, bus, object_path): - dbus.service.Object.__init__(self, bus, object_path) - self._bus = bus + @staticmethod + def to_path(src): + if src: + return dbus.ObjectPath(src.path) + return dbus.ObjectPath("/") + + def __init__(self, object_path, ident = None): + dbus.service.Object.__init__(self) + + self._dbus_ifaces = {} self.path = object_path - self.__ensure_dbus_ifaces() - object_manager.add_object(self) - def __ensure_dbus_ifaces(self): - if not hasattr(self, '_ExportedObj__dbus_ifaces'): - self.__dbus_ifaces = {} + # ident is an optional (unique) identifier for the instance. + # The test driver may set it to reference to the object by + # this identifier. For NetworkManager, the real ID of an + # object on D-Bus is the object_path. But that is generated + # by the stub server only after the test user created the + # object. The ident parameter may be specified by the user + # and thus can be hard-coded in the test. + if ident is None: + ident = object_path + self.ident = ident + + def export(self): + self.add_to_connection(gl.bus, self.path) + gl.object_manager.add_object(self) + + def unexport(self): + gl.object_manager.remove_object(self) + self.remove_from_connection() - def add_dbus_interface(self, dbus_iface, get_props_func, prop_changed_func): - self.__ensure_dbus_ifaces() - self.__dbus_ifaces[dbus_iface] = ExportedObj.DBusInterface(dbus_iface, get_props_func, prop_changed_func) + def dbus_interface_add(self, dbus_iface, props, legacy_prop_changed_func = None): + self._dbus_ifaces[dbus_iface] = ExportedObj.DBusInterface(dbus_iface, props, legacy_prop_changed_func) - def __dbus_interface_get(self, dbus_iface): - if dbus_iface not in self.__dbus_ifaces: + def _dbus_interface_get(self, dbus_iface): + if dbus_iface not in self._dbus_ifaces: raise UnknownInterfaceException() - return self.__dbus_ifaces[dbus_iface] + return self._dbus_ifaces[dbus_iface] - def _dbus_property_get(self, dbus_iface, propname = None): - props = self.__dbus_interface_get(dbus_iface).get_props_func() + def _dbus_interface_get_property(self, dbus_interface, propname = None): + props = dbus_interface.props if propname is None: return props if propname not in props: raise UnknownPropertyException() return props[propname] + def _dbus_property_get(self, dbus_iface, propname = None): + return self._dbus_interface_get_property(self._dbus_interface_get(dbus_iface), + propname) + + def _dbus_property_set(self, dbus_iface, propname, value, allow_detect_dbus_iface = False, dry_run = False): + if allow_detect_dbus_iface and not dbus_iface: + props = None + for p, dbus_interface in self._dbus_ifaces.items(): + if propname in dbus_interface.props: + if props is not None: + raise TestError("Cannot uniquely find the property '%s' on object '%s'" % (propname, self.path)) + props = dbus_interface.props + dbus_iface = p + if props is None: + raise TestError("Cannot find the property '%s' on object '%s'" % (propname, self.path)) + else: + try: + dbus_interface = self._dbus_interface_get(dbus_iface) + props = self._dbus_interface_get_property(dbus_interface) + except: + if dry_run: + raise TestError("No interface '%s' on '%s'" % (dbus_iface, self.path)) + raise + + if dry_run: + if propname not in props: + raise TestError("No property '%s' on '%s' on '%s'" % (propname, dbus_iface, self.path)) + + if isinstance(self, ActiveConnection) \ + and dbus_iface == 'org.freedesktop.NetworkManager.Connection.Active' \ + and propname == 'State': + return + else: + raise TestError("Cannot set property '%s' on '%s' on '%s' via D-Bus" % (propname, dbus_iface, self.path)) + + assert propname in props + + props[propname] = value + self._dbus_property_notify(dbus_iface, propname) + def _dbus_property_notify(self, dbus_iface, propname): - prop = self._dbus_property_get(dbus_iface, propname) - self.__dbus_interface_get(dbus_iface).prop_changed_func(self, { propname: prop }) - ExportedObj.PropertiesChanged(self, dbus_iface, { propname: prop }, []) + dbus_interface = self._dbus_interface_get(dbus_iface) + prop = self._dbus_interface_get_property(dbus_interface, propname) + if propname is not None: + prop = { propname: prop } + ExportedObj.PropertiesChanged(self, dbus_iface, prop, []) + + # the legacy_prop_changed_func signal is a legacy signal that got obsoleted by the standard + # PropertiesChanged signal. NetworkManager (and this stub) still emit it for backward + # compatibility reasons. Note that this stub server implementation gets this wrong, + # for example, it emits PropertiesChanged signal on org.freedesktop.NetworkManager.Device, + # which NetworkManager never did. + # See https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/nm-dbus-manager.c?id=db80d5f62a1edf39c5970887ef7b9ec62dd4163f#n1274 + if dbus_interface.legacy_prop_changed_func is not None: + dbus_interface.legacy_prop_changed_func(self, prop) @dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as') def PropertiesChanged(self, iface, changed, invalidated): @@ -135,74 +226,61 @@ class ExportedObj(dbus.service.Object): def get_managed_ifaces(self): my_ifaces = {} - for iface in self.__dbus_ifaces: - my_ifaces[iface] = self.__dbus_ifaces[iface].get_props_func() - return self.path, my_ifaces + for iface in self._dbus_ifaces: + my_ifaces[iface] = self._dbus_ifaces[iface].props + return my_ifaces - def remove_from_connection(self): - object_manager.remove_object(self) - dbus.service.Object.remove_from_connection(self) +############################################################################### -################################################################### IFACE_DEVICE = 'org.freedesktop.NetworkManager.Device' class NotSoftwareException(dbus.DBusException): _dbus_error_name = IFACE_DEVICE + '.NotSoftware' -PD_UDI = "Udi" -PD_IFACE = "Interface" -PD_DRIVER = "Driver" -PD_STATE = "State" -PD_ACTIVE_CONNECTION = "ActiveConnection" -PD_IP4_CONFIG = "Ip4Config" -PD_IP6_CONFIG = "Ip6Config" -PD_DHCP4_CONFIG = "Dhcp4Config" -PD_DHCP6_CONFIG = "Dhcp6Config" -PD_MANAGED = "Managed" -PD_AUTOCONNECT = "Autoconnect" -PD_DEVICE_TYPE = "DeviceType" -PD_AVAILABLE_CONNECTIONS = "AvailableConnections" +PRP_DEVICE_UDI = "Udi" +PRP_DEVICE_IFACE = "Interface" +PRP_DEVICE_DRIVER = "Driver" +PRP_DEVICE_STATE = "State" +PRP_DEVICE_ACTIVE_CONNECTION = "ActiveConnection" +PRP_DEVICE_IP4_CONFIG = "Ip4Config" +PRP_DEVICE_IP6_CONFIG = "Ip6Config" +PRP_DEVICE_DHCP4_CONFIG = "Dhcp4Config" +PRP_DEVICE_DHCP6_CONFIG = "Dhcp6Config" +PRP_DEVICE_MANAGED = "Managed" +PRP_DEVICE_AUTOCONNECT = "Autoconnect" +PRP_DEVICE_DEVICE_TYPE = "DeviceType" +PRP_DEVICE_AVAILABLE_CONNECTIONS = "AvailableConnections" class Device(ExportedObj): - counter = 1 - - def __init__(self, bus, iface, devtype): - object_path = "/org/freedesktop/NetworkManager/Devices/%d" % Device.counter - Device.counter = Device.counter + 1 - - self.iface = iface - self.udi = "/sys/devices/virtual/%s" % iface - self.devtype = devtype - self.active_connection = None - self.state = NM_DEVICE_STATE_UNAVAILABLE - self.ip4_config = None - self.ip6_config = None - self.dhcp4_config = None - self.dhcp6_config = None - self.available_connections = [] - - self.add_dbus_interface(IFACE_DEVICE, self.__get_props, Device.PropertiesChanged) - ExportedObj.__init__(self, bus, object_path) - - # Properties interface - def __get_props(self): - props = {} - props[PD_UDI] = self.udi - props[PD_IFACE] = self.iface - props[PD_DRIVER] = "virtual" - props[PD_STATE] = dbus.UInt32(self.state) - props[PD_ACTIVE_CONNECTION] = to_path(self.active_connection) - props[PD_IP4_CONFIG] = to_path(self.ip4_config) - props[PD_IP6_CONFIG] = to_path(self.ip6_config) - props[PD_DHCP4_CONFIG] = to_path(self.dhcp4_config) - props[PD_DHCP6_CONFIG] = to_path(self.dhcp6_config) - props[PD_MANAGED] = True - props[PD_AUTOCONNECT] = True - props[PD_DEVICE_TYPE] = dbus.UInt32(self.devtype) - props[PD_AVAILABLE_CONNECTIONS] = to_path_array(self.available_connections) - return props - - # methods + + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/Devices/" + + def __init__(self, iface, devtype, ident = None): + + if ident is None: + ident = iface + + ExportedObj.__init__(self, ExportedObj.create_path(Device), ident) + + props = { + PRP_DEVICE_UDI: "/sys/devices/virtual/%s" % (iface), + PRP_DEVICE_IFACE: iface, + PRP_DEVICE_DRIVER: "virtual", + PRP_DEVICE_STATE: dbus.UInt32(NM.DeviceState.UNAVAILABLE), + PRP_DEVICE_ACTIVE_CONNECTION: ExportedObj.to_path(None), + PRP_DEVICE_IP4_CONFIG: ExportedObj.to_path(None), + PRP_DEVICE_IP6_CONFIG: ExportedObj.to_path(None), + PRP_DEVICE_DHCP4_CONFIG: ExportedObj.to_path(None), + PRP_DEVICE_DHCP6_CONFIG: ExportedObj.to_path(None), + PRP_DEVICE_MANAGED: True, + PRP_DEVICE_AUTOCONNECT: True, + PRP_DEVICE_DEVICE_TYPE: dbus.UInt32(devtype), + PRP_DEVICE_AVAILABLE_CONNECTIONS: ExportedObj.to_path_array([]), + } + + self.dbus_interface_add(IFACE_DEVICE, props, Device.PropertiesChanged) + @dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='') def Disconnect(self): pass @@ -213,126 +291,123 @@ class Device(ExportedObj): raise NotSoftwareException() pass - def __notify(self, propname): - self._dbus_property_notify(IFACE_DEVICE, propname) - @dbus.service.signal(IFACE_DEVICE, signature='a{sv}') def PropertiesChanged(self, changed): pass def set_active_connection(self, ac): - self.active_connection = ac - self.__notify(PD_ACTIVE_CONNECTION) - -################################################################### + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_ACTIVE_CONNECTION, ac) -def random_mac(): - return '%02X:%02X:%02X:%02X:%02X:%02X' % ( - random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), - random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) - ) +############################################################################### -################################################################### IFACE_WIRED = 'org.freedesktop.NetworkManager.Device.Wired' -PE_HW_ADDRESS = "HwAddress" -PE_PERM_HW_ADDRESS = "PermHwAddress" -PE_SPEED = "Speed" -PE_CARRIER = "Carrier" -PE_S390_SUBCHANNELS = "S390Subchannels" +PRP_WIRED_HW_ADDRESS = "HwAddress" +PRP_WIRED_PERM_HW_ADDRESS = "PermHwAddress" +PRP_WIRED_SPEED = "Speed" +PRP_WIRED_CARRIER = "Carrier" +PRP_WIRED_S390_SUBCHANNELS = "S390Subchannels" class WiredDevice(Device): - def __init__(self, bus, iface, mac, subchannels): + def __init__(self, iface, mac = None, subchannels = None, ident = None): + Device.__init__(self, iface, NM.DeviceType.ETHERNET, ident) if mac is None: - self.mac = random_mac() - else: - self.mac = mac - self.carrier = False - self.s390_subchannels = subchannels - - self.add_dbus_interface(IFACE_WIRED, self.__get_props, WiredDevice.PropertiesChanged) - Device.__init__(self, bus, iface, NM_DEVICE_TYPE_ETHERNET) - - # Properties interface - def __get_props(self): - props = {} - props[PE_HW_ADDRESS] = self.mac - props[PE_PERM_HW_ADDRESS] = self.mac - props[PE_SPEED] = dbus.UInt32(100) - props[PE_CARRIER] = self.carrier - props[PE_S390_SUBCHANNELS] = self.s390_subchannels - return props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_WIRED, propname) + mac = Util.random_mac(self.ident) + if subchannels is None: + subchannels = dbus.Array(signature = 's') + + props = { + PRP_WIRED_HW_ADDRESS: mac, + PRP_WIRED_PERM_HW_ADDRESS: mac, + PRP_WIRED_SPEED: dbus.UInt32(100), + PRP_WIRED_CARRIER: False, + PRP_WIRED_S390_SUBCHANNELS: subchannels, + } + + self.dbus_interface_add(IFACE_WIRED, props, WiredDevice.PropertiesChanged) @dbus.service.signal(IFACE_WIRED, signature='a{sv}') def PropertiesChanged(self, changed): pass -################################################################### +############################################################################### + IFACE_VLAN = 'org.freedesktop.NetworkManager.Device.Vlan' -PV_HW_ADDRESS = "HwAddress" -PV_CARRIER = "Carrier" -PV_VLAN_ID = "VlanId" +PRP_VLAN_HW_ADDRESS = "HwAddress" +PRP_VLAN_CARRIER = "Carrier" +PRP_VLAN_VLAN_ID = "VlanId" class VlanDevice(Device): - def __init__(self, bus, iface): - self.mac = random_mac() - self.carrier = False - self.vlan_id = 1 - - self.add_dbus_interface(IFACE_VLAN, self.__get_props, VlanDevice.PropertiesChanged) - Device.__init__(self, bus, iface, NM_DEVICE_TYPE_VLAN) - - # Properties interface - def __get_props(self): - props = {} - props[PV_HW_ADDRESS] = self.mac - props[PV_CARRIER] = self.carrier - props[PV_VLAN_ID] = dbus.UInt32(self.vlan_id) - return props + def __init__(self, iface, ident = None): + Device.__init__(self, iface, NM.DeviceType.VLAN, ident) + + props = { + PRP_VLAN_HW_ADDRESS: Util.random_mac(self.ident), + PRP_VLAN_CARRIER: False, + PRP_VLAN_VLAN_ID: dbus.UInt32(1), + } + + self.dbus_interface_add(IFACE_VLAN, props, VlanDevice.PropertiesChanged) @dbus.service.signal(IFACE_VLAN, signature='a{sv}') def PropertiesChanged(self, changed): pass -################################################################### +############################################################################### + IFACE_WIFI_AP = 'org.freedesktop.NetworkManager.AccessPoint' -PP_FLAGS = "Flags" -PP_WPA_FLAGS = "WpaFlags" -PP_RSN_FLAGS = "RsnFlags" -PP_SSID = "Ssid" -PP_FREQUENCY = "Frequency" -PP_HW_ADDRESS = "HwAddress" -PP_MODE = "Mode" -PP_MAX_BITRATE = "MaxBitrate" -PP_STRENGTH = "Strength" +PRP_WIFI_AP_FLAGS = "Flags" +PRP_WIFI_AP_WPA_FLAGS = "WpaFlags" +PRP_WIFI_AP_RSN_FLAGS = "RsnFlags" +PRP_WIFI_AP_SSID = "Ssid" +PRP_WIFI_AP_FREQUENCY = "Frequency" +PRP_WIFI_AP_HW_ADDRESS = "HwAddress" +PRP_WIFI_AP_MODE = "Mode" +PRP_WIFI_AP_MAX_BITRATE = "MaxBitrate" +PRP_WIFI_AP_STRENGTH = "Strength" class WifiAp(ExportedObj): - counter = 0 - def __init__(self, bus, ssid, mac, flags, wpaf, rsnf, freq): - path = "/org/freedesktop/NetworkManager/AccessPoint/%d" % WifiAp.counter - WifiAp.counter = WifiAp.counter + 1 + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/AccessPoint/" + + def __init__(self, ssid, bssid = None, flags = None, wpaf = None, rsnf = None, freq = None, strength = None, ident = None): + + ExportedObj.__init__(self, ExportedObj.create_path(WifiAp), ident) + + if flags is None: + flags = 0x1 + if wpaf is None: + wpaf = 0x1cc + if rsnf is None: + rsnf = 0x1cc + if freq is None: + freq = 2412 + if bssid is None: + bssid = Util.random_mac(self.path) + if strength is None: + strength = Util.pseudorandom_num(self.path, 100) self.ssid = ssid - if mac: - self.bssid = mac - else: - self.bssid = random_mac() - self.flags = flags - self.wpaf = wpaf - self.rsnf = rsnf - self.freq = freq - self.strength = random.randint(0, 100) + self.strength_counter = 0 self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None) - self.add_dbus_interface(IFACE_WIFI_AP, self.__get_props, WifiAp.PropertiesChanged) - ExportedObj.__init__(self, bus, path) + props = { + PRP_WIFI_AP_FLAGS: dbus.UInt32(flags), + PRP_WIFI_AP_WPA_FLAGS: dbus.UInt32(wpaf), + PRP_WIFI_AP_RSN_FLAGS: dbus.UInt32(rsnf), + PRP_WIFI_AP_SSID: dbus.ByteArray(self.ssid.encode('utf-8')), + PRP_WIFI_AP_FREQUENCY: dbus.UInt32(freq), + PRP_WIFI_AP_HW_ADDRESS: bssid, + PRP_WIFI_AP_MODE: dbus.UInt32(getattr(NM,'80211Mode').INFRA), + PRP_WIFI_AP_MAX_BITRATE: dbus.UInt32(54000), + PRP_WIFI_AP_STRENGTH: dbus.Byte(strength), + } + + self.dbus_interface_add(IFACE_WIFI_AP, props, WifiAp.PropertiesChanged) def __del__(self): if self.strength_id > 0: @@ -340,64 +415,60 @@ class WifiAp(ExportedObj): self.strength_id = 0 def strength_cb(self, ignored): - self.strength = random.randint(0, 100) - self.__notify(PP_STRENGTH) + self.strength_counter += 1 + strength = Util.pseudorandom_num(self.path + str(self.strength_counter), 100) + self._dbus_property_set(IFACE_WIFI_AP, PRP_WIFI_AP_STRENGTH, strength) return True - # Properties interface - def __get_props(self): - props = {} - props[PP_FLAGS] = dbus.UInt32(self.flags) - props[PP_WPA_FLAGS] = dbus.UInt32(self.wpaf) - props[PP_RSN_FLAGS] = dbus.UInt32(self.rsnf) - props[PP_SSID] = dbus.ByteArray(self.ssid.encode('utf-8')) - props[PP_FREQUENCY] = dbus.UInt32(self.freq) - props[PP_HW_ADDRESS] = self.bssid - props[PP_MODE] = dbus.UInt32(2) # NM_802_11_MODE_INFRA - props[PP_MAX_BITRATE] = dbus.UInt32(54000) - props[PP_STRENGTH] = dbus.Byte(self.strength) - return props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_WIFI_AP, propname) - @dbus.service.signal(IFACE_WIFI_AP, signature='a{sv}') def PropertiesChanged(self, changed): pass -################################################################### +############################################################################### + IFACE_WIFI = 'org.freedesktop.NetworkManager.Device.Wireless' class ApNotFoundException(dbus.DBusException): _dbus_error_name = IFACE_WIFI + '.AccessPointNotFound' -PW_HW_ADDRESS = "HwAddress" -PW_PERM_HW_ADDRESS = "PermHwAddress" -PW_MODE = "Mode" -PW_BITRATE = "Bitrate" -PW_ACCESS_POINTS = "AccessPoints" -PW_ACTIVE_ACCESS_POINT = "ActiveAccessPoint" -PW_WIRELESS_CAPABILITIES = "WirelessCapabilities" +PRP_WIFI_HW_ADDRESS = "HwAddress" +PRP_WIFI_PERM_HW_ADDRESS = "PermHwAddress" +PRP_WIFI_MODE = "Mode" +PRP_WIFI_BITRATE = "Bitrate" +PRP_WIFI_ACCESS_POINTS = "AccessPoints" +PRP_WIFI_ACTIVE_ACCESS_POINT = "ActiveAccessPoint" +PRP_WIFI_WIRELESS_CAPABILITIES = "WirelessCapabilities" class WifiDevice(Device): - def __init__(self, bus, iface): - self.mac = random_mac() + def __init__(self, iface, mac = None, ident = None): + Device.__init__(self, iface, NM.DeviceType.WIFI, ident) + + if mac is None: + mac = Util.random_mac(self.ident) + self.aps = [] - self.active_ap = None - self.add_dbus_interface(IFACE_WIFI, self.__get_props, WifiDevice.PropertiesChanged) - Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIFI) + props = { + PRP_WIFI_HW_ADDRESS: mac, + PRP_WIFI_PERM_HW_ADDRESS: mac, + PRP_WIFI_MODE: dbus.UInt32(getattr(NM,'80211Mode').INFRA), + PRP_WIFI_BITRATE: dbus.UInt32(21000), + PRP_WIFI_WIRELESS_CAPABILITIES: dbus.UInt32(0xFF), + PRP_WIFI_ACCESS_POINTS: ExportedObj.to_path_array(self.aps), + PRP_WIFI_ACTIVE_ACCESS_POINT: ExportedObj.to_path(None), + } + + self.dbus_interface_add(IFACE_WIFI, props, WifiDevice.PropertiesChanged) - # methods @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao') def GetAccessPoints(self): # only include non-hidden APs - return to_path_array([a for a in self.aps if a.ssid]) + return ExportedObj.to_path_array([a for a in self.aps if a.ssid]) @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao') def GetAllAccessPoints(self): # include all APs including hidden ones - return to_path_array(self.aps) + return ExportedObj.to_path_array(self.aps) @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='a{sv}', out_signature='') def RequestScan(self, props): @@ -408,44 +479,26 @@ class WifiDevice(Device): pass def add_ap(self, ap): + ap.export() self.aps.append(ap) - self.__notify(PW_ACCESS_POINTS) - self.AccessPointAdded(to_path(ap)) + self._dbus_property_set(IFACE_WIFI, PRP_WIFI_ACCESS_POINTS, ExportedObj.to_path_array(self.aps)) + self.AccessPointAdded(ExportedObj.to_path(ap)) + return ap + + def remove_ap(self, ap): + self.aps.remove(ap) + self._dbus_property_set(IFACE_WIFI, PRP_WIFI_ACCESS_POINTS, ExportedObj.to_path_array(self.aps)) + self.AccessPointRemoved(ExportedObj.to_path(ap)) + ap.unexport() @dbus.service.signal(IFACE_WIFI, signature='o') def AccessPointRemoved(self, ap_path): pass - def remove_ap(self, ap): - self.aps.remove(ap) - self.__notify(PW_ACCESS_POINTS) - self.AccessPointRemoved(to_path(ap)) - - # Properties interface - def __get_props(self): - props = {} - props[PW_HW_ADDRESS] = self.mac - props[PW_PERM_HW_ADDRESS] = self.mac - props[PW_MODE] = dbus.UInt32(3) # NM_802_11_MODE_INFRA - props[PW_BITRATE] = dbus.UInt32(21000) - props[PW_WIRELESS_CAPABILITIES] = dbus.UInt32(0xFF) - props[PW_ACCESS_POINTS] = to_path_array(self.aps) - props[PW_ACTIVE_ACCESS_POINT] = to_path(self.active_ap) - return props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_WIFI, propname) - @dbus.service.signal(IFACE_WIFI, signature='a{sv}') def PropertiesChanged(self, changed): pass - # test functions - def add_test_ap(self, ssid, mac): - ap = WifiAp(self._bus, ssid, mac, 0x1, 0x1cc, 0x1cc, 2412) - self.add_ap(ap) - return ap - def remove_ap_by_path(self, path): for ap in self.aps: if ap.path == path: @@ -454,26 +507,32 @@ class WifiDevice(Device): raise ApNotFoundException("AP %s not found" % path) -################################################################### +############################################################################### + IFACE_WIMAX_NSP = 'org.freedesktop.NetworkManager.WiMax.Nsp' -PN_NAME = "Name" -PN_SIGNAL_QUALITY = "SignalQuality" -PN_NETWORK_TYPE = "NetworkType" +PRP_WIMAX_NSP_NAME = "Name" +PRP_WIMAX_NSP_SIGNAL_QUALITY = "SignalQuality" +PRP_WIMAX_NSP_NETWORK_TYPE = "NetworkType" class WimaxNsp(ExportedObj): - counter = 0 - def __init__(self, bus, name): - path = "/org/freedesktop/NetworkManager/Nsp/%d" % WimaxNsp.counter - WimaxNsp.counter = WimaxNsp.counter + 1 + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/Nsp/" + + def __init__(self, name): + + ExportedObj.__init__(self, ExportedObj.create_path(WimaxNsp)) - self.name = name - self.strength = random.randint(0, 100) self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None) - self.add_dbus_interface(IFACE_WIMAX_NSP, self.__get_props, WimaxNsp.PropertiesChanged) - ExportedObj.__init__(self, bus, path) + props = { + PRP_WIMAX_NSP_NAME: name, + PRP_WIMAX_NSP_SIGNAL_QUALITY: dbus.UInt32(random.randint(0, 100)), + PRP_WIMAX_NSP_NETWORK_TYPE: dbus.UInt32(NM.WimaxNspNetworkType.HOME), + } + + self.dbus_interface_add(IFACE_WIMAX_NSP, props, WimaxNsp.PropertiesChanged) def __del__(self): if self.strength_id > 0: @@ -481,97 +540,81 @@ class WimaxNsp(ExportedObj): self.strength_id = 0 def strength_cb(self, ignored): - self.strength = random.randint(0, 100) - self.__notify(PN_SIGNAL_QUALITY) + self._dbus_property_set(IFACE_WIMAX_NSP, PRP_WIMAX_NSP_SIGNAL_QUALITY, dbus.UInt32(random.randint(0, 100))) return True - # Properties interface - def __get_props(self): - props = {} - props[PN_NAME] = self.name - props[PN_SIGNAL_QUALITY] = dbus.UInt32(self.strength) - props[PN_NETWORK_TYPE] = dbus.UInt32(0x1) # NM_WIMAX_NSP_NETWORK_TYPE_HOME - return props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_WIMAX_NSP, propname) - @dbus.service.signal(IFACE_WIMAX_NSP, signature='a{sv}') def PropertiesChanged(self, changed): pass -################################################################### +############################################################################### + IFACE_WIMAX = 'org.freedesktop.NetworkManager.Device.WiMax' class NspNotFoundException(dbus.DBusException): _dbus_error_name = IFACE_WIMAX + '.NspNotFound' -PX_NSPS = "Nsps" -PX_HW_ADDRESS = "HwAddress" -PX_CENTER_FREQUENCY = "CenterFrequency" -PX_RSSI = "Rssi" -PX_CINR = "Cinr" -PX_TX_POWER = "TxPower" -PX_BSID = "Bsid" -PX_ACTIVE_NSP = "ActiveNsp" +PRP_WIMAX_NSPS = "Nsps" +PRP_WIMAX_HW_ADDRESS = "HwAddress" +PRP_WIMAX_CENTER_FREQUENCY = "CenterFrequency" +PRP_WIMAX_RSSI = "Rssi" +PRP_WIMAX_CINR = "Cinr" +PRP_WIMAX_TX_POWER = "TxPower" +PRP_WIMAX_BSID = "Bsid" +PRP_WIMAX_ACTIVE_NSP = "ActiveNsp" class WimaxDevice(Device): - def __init__(self, bus, iface): - self.mac = random_mac() - self.bsid = random_mac() + def __init__(self, iface, ident = None): + Device.__init__(self, iface, NM.DeviceType.WIMAX, ident) + + mac = Util.random_mac(self.ident) + bsid = Util.random_mac(self.ident + '.bsid') + self.nsps = [] - self.active_nsp = None - self.add_dbus_interface(IFACE_WIMAX, self.__get_props, WimaxDevice.PropertiesChanged) - Device.__init__(self, bus, iface, NM_DEVICE_TYPE_WIMAX) + props = { + PRP_WIMAX_HW_ADDRESS: mac, + PRP_WIMAX_CENTER_FREQUENCY: dbus.UInt32(2525), + PRP_WIMAX_RSSI: dbus.Int32(-48), + PRP_WIMAX_CINR: dbus.Int32(24), + PRP_WIMAX_TX_POWER: dbus.Int32(9), + PRP_WIMAX_BSID: bsid, + PRP_WIMAX_NSPS: ExportedObj.to_path_array(self.nsps), + PRP_WIMAX_ACTIVE_NSP: ExportedObj.to_path(None), + } + + self.dbus_interface_add(IFACE_WIMAX, props, WimaxDevice.PropertiesChanged) - # methods @dbus.service.method(dbus_interface=IFACE_WIMAX, in_signature='', out_signature='ao') def GetNspList(self): - # include all APs including hidden ones - return to_path_array(self.nsps) + return ExportedObj.to_path_array(self.nsps) @dbus.service.signal(IFACE_WIMAX, signature='o') def NspAdded(self, nsp_path): pass def add_nsp(self, nsp): + nsp.export() self.nsps.append(nsp) - self.__notify(PX_NSPS) - self.NspAdded(to_path(nsp)) + self._dbus_property_set(IFACE_WIMAX, PRP_WIMAX_NSPS, ExportedObj.to_path_array(self.nsps)) + self.NspAdded(ExportedObj.to_path(nsp)) + + def remove_nsp(self, nsp): + self.nsps.remove(nsp) + self._dbus_property_set(IFACE_WIMAX, PRP_WIMAX_NSPS, ExportedObj.to_path_array(self.nsps)) + self.NspRemoved(ExportedObj.to_path(nsp)) + nsp.unexport() @dbus.service.signal(IFACE_WIMAX, signature='o') def NspRemoved(self, nsp_path): pass - def remove_nsp(self, nsp): - self.nsps.remove(nsp) - self.__notify(PX_NSPS) - self.NspRemoved(to_path(nsp)) - - # Properties interface - def __get_props(self): - props = {} - props[PX_HW_ADDRESS] = self.mac - props[PX_CENTER_FREQUENCY] = dbus.UInt32(2525) - props[PX_RSSI] = dbus.Int32(-48) - props[PX_CINR] = dbus.Int32(24) - props[PX_TX_POWER] = dbus.Int32(9) - props[PX_BSID] = self.bsid - props[PX_NSPS] = to_path_array(self.nsps) - props[PX_ACTIVE_NSP] = to_path(self.active_nsp) - return props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_WIMAX, propname) - @dbus.service.signal(IFACE_WIMAX, signature='a{sv}') def PropertiesChanged(self, changed): pass - # test functions def add_test_nsp(self, name): - nsp = WimaxNsp(self._bus, name) + nsp = WimaxNsp(name) self.add_nsp(nsp) return nsp @@ -582,75 +625,102 @@ class WimaxDevice(Device): return raise NspNotFoundException("NSP %s not found" % path) -################################################################### +############################################################################### + IFACE_ACTIVE_CONNECTION = 'org.freedesktop.NetworkManager.Connection.Active' -PAC_CONNECTION = "Connection" -PAC_SPECIFIC_OBJECT = "SpecificObject" -PAC_ID = "Id" -PAC_UUID = "Uuid" -PAC_TYPE = "Type" -PAC_DEVICES = "Devices" -PAC_STATE = "State" -PAC_DEFAULT = "Default" -PAC_IP4CONFIG = "Ip4Config" -PAC_DHCP4CONFIG = "Dhcp4Config" -PAC_DEFAULT6 = "Default6" -PAC_IP6CONFIG = "Ip6Config" -PAC_DHCP6CONFIG = "Dhcp6Config" -PAC_VPN = "Vpn" -PAC_MASTER = "Master" +PRP_ACTIVE_CONNECTION_CONNECTION = "Connection" +PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT = "SpecificObject" +PRP_ACTIVE_CONNECTION_ID = "Id" +PRP_ACTIVE_CONNECTION_UUID = "Uuid" +PRP_ACTIVE_CONNECTION_TYPE = "Type" +PRP_ACTIVE_CONNECTION_DEVICES = "Devices" +PRP_ACTIVE_CONNECTION_STATE = "State" +PRP_ACTIVE_CONNECTION_DEFAULT = "Default" +PRP_ACTIVE_CONNECTION_IP4CONFIG = "Ip4Config" +PRP_ACTIVE_CONNECTION_DHCP4CONFIG = "Dhcp4Config" +PRP_ACTIVE_CONNECTION_DEFAULT6 = "Default6" +PRP_ACTIVE_CONNECTION_IP6CONFIG = "Ip6Config" +PRP_ACTIVE_CONNECTION_DHCP6CONFIG = "Dhcp6Config" +PRP_ACTIVE_CONNECTION_VPN = "Vpn" +PRP_ACTIVE_CONNECTION_MASTER = "Master" class ActiveConnection(ExportedObj): - counter = 1 - def __init__(self, bus, device, connection, specific_object): - object_path = "/org/freedesktop/NetworkManager/ActiveConnection/%d" % ActiveConnection.counter - ActiveConnection.counter = ActiveConnection.counter + 1 + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/ActiveConnection/" + + def __init__(self, device, connection, specific_object): + + ExportedObj.__init__(self, ExportedObj.create_path(ActiveConnection)) self.device = device self.conn = connection - self.specific_object = specific_object - self.state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN - self.default = False - self.ip4config = None - self.dhcp4config = None - self.default6 = False - self.ip6config = None - self.dhcp6config = None - self.vpn = False - self.master = None - - self.add_dbus_interface(IFACE_ACTIVE_CONNECTION, self.__get_props, ActiveConnection.PropertiesChanged) - ExportedObj.__init__(self, bus, object_path) - - # Properties interface - def __get_props(self): - props = {} - props[PAC_CONNECTION] = to_path(self.conn) - props[PAC_SPECIFIC_OBJECT] = to_path(self.specific_object) + + self._activation_id = None + conn_settings = self.conn.GetSettings() s_con = conn_settings['connection'] - props[PAC_ID] = s_con['id'] - props[PAC_UUID] = s_con['uuid'] - props[PAC_TYPE] = s_con['type'] - props[PAC_DEVICES] = to_path_array([self.device]) - props[PAC_STATE] = dbus.UInt32(self.state) - props[PAC_DEFAULT] = self.default - props[PAC_IP4CONFIG] = to_path(self.ip4config) - props[PAC_DHCP4CONFIG] = to_path(self.dhcp4config) - props[PAC_DEFAULT6] = self.default6 - props[PAC_IP6CONFIG] = to_path(self.ip6config) - props[PAC_DHCP6CONFIG] = to_path(self.dhcp6config) - props[PAC_VPN] = self.vpn - props[PAC_MASTER] = to_path(self.master) - return props + + props = { + PRP_ACTIVE_CONNECTION_CONNECTION: ExportedObj.to_path(self.conn), + PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT: ExportedObj.to_path(specific_object), + PRP_ACTIVE_CONNECTION_ID: s_con['id'], + PRP_ACTIVE_CONNECTION_UUID: s_con['uuid'], + PRP_ACTIVE_CONNECTION_TYPE: s_con['type'], + PRP_ACTIVE_CONNECTION_DEVICES: ExportedObj.to_path_array([self.device]), + PRP_ACTIVE_CONNECTION_STATE: dbus.UInt32(NM.ActiveConnectionState.UNKNOWN), + PRP_ACTIVE_CONNECTION_DEFAULT: False, + PRP_ACTIVE_CONNECTION_IP4CONFIG: ExportedObj.to_path(None), + PRP_ACTIVE_CONNECTION_DHCP4CONFIG: ExportedObj.to_path(None), + PRP_ACTIVE_CONNECTION_DEFAULT6: False, + PRP_ACTIVE_CONNECTION_IP6CONFIG: ExportedObj.to_path(None), + PRP_ACTIVE_CONNECTION_DHCP6CONFIG: ExportedObj.to_path(None), + PRP_ACTIVE_CONNECTION_VPN: False, + PRP_ACTIVE_CONNECTION_MASTER: ExportedObj.to_path(None), + } + + self.dbus_interface_add(IFACE_ACTIVE_CONNECTION, props, ActiveConnection.PropertiesChanged) + + def _set_state(self, state, reason): + state = dbus.UInt32(state) + self._dbus_property_set(IFACE_ACTIVE_CONNECTION, PRP_ACTIVE_CONNECTION_STATE, state) + self.StateChanged(state, dbus.UInt32(reason)) + + def activation_cancel(self): + if self._activation_id is None: + return False + GLib.source_remove(self._activation_id) + self._activation_id = None + return True + + def _activation_step2(self): + assert self._activation_id is not None + self._activation_id = None + self._set_state(NM.ActiveConnectionState.ACTIVATED, NM.ActiveConnectionStateReason.UNKNOWN) + return False + + def _activation_step1(self): + assert self._activation_id is not None + self._activation_id = GLib.timeout_add(50, self._activation_step2) + self.device.set_active_connection(self) + self._set_state(NM.ActiveConnectionState.ACTIVATING, NM.ActiveConnectionStateReason.UNKNOWN) + return False + + def start_activation(self): + assert self._activation_id is None + self._activation_id = GLib.timeout_add(50, self._activation_step1) @dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='a{sv}') def PropertiesChanged(self, changed): pass -################################################################### + @dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='uu') + def StateChanged(self, state, reason): + pass + +############################################################################### + IFACE_TEST = 'org.freedesktop.NetworkManager.LibnmGlibTest' IFACE_NM = 'org.freedesktop.NetworkManager' @@ -663,82 +733,86 @@ class UnknownDeviceException(dbus.DBusException): class UnknownConnectionException(dbus.DBusException): _dbus_error_name = IFACE_NM + '.UnknownConnection' -PM_DEVICES = 'Devices' -PM_ALL_DEVICES = 'AllDevices' -PM_NETWORKING_ENABLED = 'NetworkingEnabled' -PM_WWAN_ENABLED = 'WwanEnabled' -PM_WWAN_HARDWARE_ENABLED = 'WwanHardwareEnabled' -PM_WIRELESS_ENABLED = 'WirelessEnabled' -PM_WIRELESS_HARDWARE_ENABLED = 'WirelessHardwareEnabled' -PM_WIMAX_ENABLED = 'WimaxEnabled' -PM_WIMAX_HARDWARE_ENABLED = 'WimaxHardwareEnabled' -PM_ACTIVE_CONNECTIONS = 'ActiveConnections' -PM_PRIMARY_CONNECTION = 'PrimaryConnection' -PM_ACTIVATING_CONNECTION = 'ActivatingConnection' -PM_STARTUP = 'Startup' -PM_STATE = 'State' -PM_VERSION = 'Version' -PM_CONNECTIVITY = 'Connectivity' - -def set_device_ac_cb(device, ac): - device.set_active_connection(ac) +PRP_NM_DEVICES = 'Devices' +PRP_NM_ALL_DEVICES = 'AllDevices' +PRP_NM_NETWORKING_ENABLED = 'NetworkingEnabled' +PRP_NM_WWAN_ENABLED = 'WwanEnabled' +PRP_NM_WWAN_HARDWARE_ENABLED = 'WwanHardwareEnabled' +PRP_NM_WIRELESS_ENABLED = 'WirelessEnabled' +PRP_NM_WIRELESS_HARDWARE_ENABLED = 'WirelessHardwareEnabled' +PRP_NM_WIMAX_ENABLED = 'WimaxEnabled' +PRP_NM_WIMAX_HARDWARE_ENABLED = 'WimaxHardwareEnabled' +PRP_NM_ACTIVE_CONNECTIONS = 'ActiveConnections' +PRP_NM_PRIMARY_CONNECTION = 'PrimaryConnection' +PRP_NM_ACTIVATING_CONNECTION = 'ActivatingConnection' +PRP_NM_STARTUP = 'Startup' +PRP_NM_STATE = 'State' +PRP_NM_VERSION = 'Version' +PRP_NM_CONNECTIVITY = 'Connectivity' class NetworkManager(ExportedObj): - def __init__(self, bus, object_path): - self._bus = bus; + def __init__(self): + ExportedObj.__init__(self, "/org/freedesktop/NetworkManager") self.devices = [] self.active_connections = [] - self.primary_connection = None - self.activating_connection = None - self.state = NM_STATE_DISCONNECTED - self.connectivity = 1 - self.add_dbus_interface(IFACE_NM, self.__get_props, NetworkManager.PropertiesChanged) - ExportedObj.__init__(self, bus, object_path) + props = { + PRP_NM_DEVICES: ExportedObj.to_path_array(self.devices), + PRP_NM_ALL_DEVICES: ExportedObj.to_path_array(self.devices), + PRP_NM_NETWORKING_ENABLED: True, + PRP_NM_WWAN_ENABLED: True, + PRP_NM_WWAN_HARDWARE_ENABLED: True, + PRP_NM_WIRELESS_ENABLED: True, + PRP_NM_WIRELESS_HARDWARE_ENABLED: True, + PRP_NM_WIMAX_ENABLED: True, + PRP_NM_WIMAX_HARDWARE_ENABLED: True, + PRP_NM_ACTIVE_CONNECTIONS: ExportedObj.to_path_array(self.active_connections), + PRP_NM_PRIMARY_CONNECTION: ExportedObj.to_path(None), + PRP_NM_ACTIVATING_CONNECTION: ExportedObj.to_path(None), + PRP_NM_STARTUP: False, + PRP_NM_STATE: dbus.UInt32(NM.State.DISCONNECTED), + PRP_NM_VERSION: "0.9.9.0", + PRP_NM_CONNECTIVITY: dbus.UInt32(NM.ConnectivityState.NONE), + } + + self.dbus_interface_add(IFACE_NM, props, NetworkManager.PropertiesChanged) + self.export() @dbus.service.signal(IFACE_NM, signature='u') def StateChanged(self, new_state): pass def set_state(self, new_state): - self.state = new_state - self.__notify(PM_STATE) + self._dbus_property_set(IFACE_NM, PRP_NM_STATE, state) self.StateChanged(dbus.UInt32(self.state)) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao') def GetDevices(self): - return to_path_array(self.devices) + return ExportedObj.to_path_array(self.devices) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao') def GetAllDevices(self): - return to_path_array(self.devices) + return ExportedObj.to_path_array(self.devices) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o') def GetDeviceByIpIface(self, ip_iface): - for d in self.devices: - # ignore iface/ip_iface distinction for now - if d.iface == ip_iface: - return to_path(d) - raise UnknownDeviceException("No device found for the requested iface.") + d = self.find_device_first(ip_iface = ip_iface, require = UnknownDeviceException) + return ExportedObj.to_path(d) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o') def ActivateConnection(self, conpath, devpath, specific_object): try: - connection = settings.get_connection(conpath) + connection = gl.settings.get_connection(conpath) except Exception as e: raise UnknownConnectionException("Connection not found") hash = connection.GetSettings() s_con = hash['connection'] - device = None - for d in self.devices: - if d.path == devpath: - device = d - break + device = self.find_device_first(path = devpath) if not device and s_con['type'] == 'vlan': ifname = s_con['interface-name'] - device = VlanDevice(self._bus, ifname) + device = VlanDevice(ifname) self.add_device(device) if not device: raise UnknownDeviceException("No device found for the requested iface.") @@ -747,7 +821,7 @@ class NetworkManager(ExportedObj): if '802-11-wireless-security' in hash: s_wsec = hash['802-11-wireless-security'] if (s_wsec['key-mgmt'] == 'wpa-psk' and 'psk' not in s_wsec): - secrets = agent_manager.get_secrets(hash, conpath, '802-11-wireless-security') + secrets = gl.agent_manager.get_secrets(hash, conpath, '802-11-wireless-security') if secrets is None: raise NoSecretsException("No secret agent available") if '802-11-wireless-security' not in secrets: @@ -756,30 +830,34 @@ class NetworkManager(ExportedObj): if 'psk' not in s_wsec: raise NoSecretsException("No secrets provided") - ac = ActiveConnection(self._bus, device, connection, None) - self.active_connections.append(ac) - self.__notify(PM_ACTIVE_CONNECTIONS) + ac = ActiveConnection(device, connection, None) + self.active_connection_add(ac) if s_con['id'] == 'object-creation-failed-test': - self.active_connections.remove(ac) - self.__notify(PM_ACTIVE_CONNECTIONS) - ac.remove_from_connection() - else: - GLib.timeout_add(50, set_device_ac_cb, device, ac) + # FIXME: this is not the right test, to delete the active-connection + # before returning it. It's the wrong order of what NetworkManager + # would do. + self.active_connection_remove(ac) + return ExportedObj.to_path(ac) + + return ExportedObj.to_path(ac) + + def active_connection_add(self, ac): + ac.export() + self.active_connections.append(ac) + self._dbus_property_set(IFACE_NM, PRP_NM_ACTIVE_CONNECTIONS, ExportedObj.to_path_array(self.active_connections)) + ac.start_activation() - return to_path(ac) + def active_connection_remove(self, ac): + ac.activation_cancel() + self.active_connections.remove(ac) + self._dbus_property_set(IFACE_NM, PRP_NM_ACTIVE_CONNECTIONS, ExportedObj.to_path_array(self.active_connections)) + ac.unexport() @dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo') def AddAndActivateConnection(self, connection, devpath, specific_object): - device = None - for d in self.devices: - if d.path == devpath: - device = d - break - if not device: - raise UnknownDeviceException("No device found for the requested iface.") - - conpath = settings.AddConnection(connection) + device = self.find_device_first(path = devpath, require = UnknownDeviceException) + conpath = gl.settings.AddConnection(connection) return (conpath, self.ActivateConnection(conpath, devpath, specific_object)) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='o', out_signature='') @@ -789,10 +867,10 @@ class NetworkManager(ExportedObj): @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='') def Sleep(self, do_sleep): if do_sleep: - self.state = NM_STATE_ASLEEP + state = NM.State.ASLEEP else: - self.state = NM_STATE_DISCONNECTED - self.__notify(PM_STATE) + state = NM.State.DISCONNECTED + self.set_state(state) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='') def Enable(self, do_enable): @@ -831,139 +909,160 @@ class NetworkManager(ExportedObj): def DeviceAdded(self, devpath): pass + def find_devices(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG): + r = None + for d in self.devices: + if ident is not _DEFAULT_ARG: + if d.ident != ident: + continue + if path is not _DEFAULT_ARG: + if d.path != path: + continue + if iface is not _DEFAULT_ARG: + if d.iface != iface: + continue + if ip_iface is not _DEFAULT_ARG: + # ignore iface/ip_iface distinction for now + if d.iface != ip_iface: + continue + yield d + + def find_device_first(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, require = None): + r = None + for d in self.find_devices(ident = ident, path = path, iface = iface, ip_iface = ip_iface): + r = d + break + if r is None and require: + if require is TestError: + raise TestError('Device not found') + raise UnknownDeviceException('Device not found') + return r + def add_device(self, device): + if self.find_device_first(ident = device.ident, path = device.path) is not None: + raise TestError("Duplicate device ident=%s / path=%s" % (device.ident, device.path)) + device.export() self.devices.append(device) - self.__notify(PM_DEVICES) - self.__notify(PM_ALL_DEVICES) - self.DeviceAdded(to_path(device)) + self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices)) + self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices)) + self.DeviceAdded(ExportedObj.to_path(device)) + return device + + def remove_device(self, device): + self.devices.remove(device) + self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices)) + self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices)) + self.DeviceRemoved(ExportedObj.to_path(device)) + device.unexport() @dbus.service.signal(IFACE_NM, signature='o') def DeviceRemoved(self, devpath): pass - def remove_device(self, device): - self.devices.remove(device) - self.__notify(PM_DEVICES) - self.__notify(PM_ALL_DEVICES) - self.DeviceRemoved(to_path(device)) - - ################# D-Bus Properties interface - def __get_props(self): - props = {} - props[PM_DEVICES] = to_path_array(self.devices) - props[PM_ALL_DEVICES] = to_path_array(self.devices) - props[PM_NETWORKING_ENABLED] = True - props[PM_WWAN_ENABLED] = True - props[PM_WWAN_HARDWARE_ENABLED] = True - props[PM_WIRELESS_ENABLED] = True - props[PM_WIRELESS_HARDWARE_ENABLED] = True - props[PM_WIMAX_ENABLED] = True - props[PM_WIMAX_HARDWARE_ENABLED] = True - props[PM_ACTIVE_CONNECTIONS] = to_path_array(self.active_connections) - props[PM_PRIMARY_CONNECTION] = to_path(self.primary_connection) - props[PM_ACTIVATING_CONNECTION] = to_path(self.activating_connection) - props[PM_STARTUP] = False - props[PM_STATE] = dbus.UInt32(self.state) - props[PM_VERSION] = "0.9.9.0" - props[PM_CONNECTIVITY] = dbus.UInt32(self.connectivity) - return props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_NM, propname) - @dbus.service.signal(IFACE_NM, signature='a{sv}') def PropertiesChanged(self, changed): pass - ################# Testing methods @dbus.service.method(IFACE_TEST, in_signature='', out_signature='') def Quit(self): - mainloop.quit() + gl.mainloop.quit() + + @dbus.service.method(IFACE_TEST, in_signature='a{ss}', out_signature='a(sss)') + def FindConnections(self, args): + return [(c.path, c.get_uuid(), c.get_id()) for c in gl.settings.find_connections(**args)] + + @dbus.service.method(IFACE_TEST, in_signature='a(oa(sa(sv)))', out_signature='') + def SetProperties(self, all_args): + for i in [0, 1]: + for path, iface_args in all_args: + o = gl.object_manager.find_object(path) + if o is None: + raise TestError("Object %s does not exist" % (path)) + for iface_name, args in iface_args: + for propname, value in args: + o._dbus_property_set(iface_name, propname, value, + allow_detect_dbus_iface = True, + dry_run = (i == 0)) + + + @dbus.service.method(IFACE_TEST, in_signature='sa{sv}', out_signature='o') + def AddObj(self, class_name, args): + if class_name in ['WiredDevice', 'WifiDevice']: + py_class = globals()[class_name] + d = py_class(**args) + return ExportedObj.to_path(self.add_device(d)) + elif class_name in ['WifiAp']: + if 'device' not in args: + raise TestError('missing "device" paramter') + d = self.find_device_first(ident = args['device'], require = TestError) + del args['device'] + if 'ssid' not in args: + args['ssid'] = d.ident + '-ap-' + str(WifiAp.path_counter_next) + ap = WifiAp(**args) + return ExportedObj.to_path(d.add_ap(ap)) + raise TestError("Invalid python type \"%s\"" % (class_name)) @dbus.service.method(IFACE_TEST, in_signature='ssas', out_signature='o') def AddWiredDevice(self, ifname, mac, subchannels): - for d in self.devices: - if d.iface == ifname: - raise PermissionDeniedException("Device already added") - dev = WiredDevice(self._bus, ifname, mac, subchannels) - self.add_device(dev) - return to_path(dev) + dev = WiredDevice(ifname, mac, subchannels) + return ExportedObj.to_path(self.add_device(dev)) @dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o') def AddWifiDevice(self, ifname): - for d in self.devices: - if d.iface == ifname: - raise PermissionDeniedException("Device already added") - dev = WifiDevice(self._bus, ifname) - self.add_device(dev) - return to_path(dev) + dev = WifiDevice(ifname) + return ExportedObj.to_path(self.add_device(dev)) @dbus.service.method(IFACE_TEST, in_signature='s', out_signature='o') def AddWimaxDevice(self, ifname): - for d in self.devices: - if d.iface == ifname: - raise PermissionDeniedException("Device already added") - dev = WimaxDevice(self._bus, ifname) - self.add_device(dev) - return to_path(dev) + dev = WimaxDevice(ifname) + return ExportedObj.to_path(self.add_device(dev)) @dbus.service.method(IFACE_TEST, in_signature='o', out_signature='') def RemoveDevice(self, path): - for d in self.devices: - if d.path == path: - self.remove_device(d) - return - raise UnknownDeviceException("Device not found") + d = self.find_device_first(path = path, require = TestError) + self.remove_device(d) @dbus.service.method(IFACE_TEST, in_signature='sss', out_signature='o') - def AddWifiAp(self, ifname, ssid, mac): - for d in self.devices: - if d.iface == ifname: - return to_path(d.add_test_ap(ssid, mac)) - raise UnknownDeviceException("Device not found") + def AddWifiAp(self, ident, ssid, bssid): + d = self.find_device_first(ident = ident, require = TestError) + ap = WifiAp(ssid, bssid) + return ExportedObj.to_path(d.add_ap(ap)) @dbus.service.method(IFACE_TEST, in_signature='so', out_signature='') - def RemoveWifiAp(self, ifname, ap_path): - for d in self.devices: - if d.iface == ifname: - d.remove_ap_by_path(ap_path) - return - raise UnknownDeviceException("Device not found") + def RemoveWifiAp(self, ident, ap_path): + d = self.find_device_first(ident = ident, require = TestError) + d.remove_ap_by_path(ap_path) @dbus.service.method(IFACE_TEST, in_signature='ss', out_signature='o') - def AddWimaxNsp(self, ifname, name): - for d in self.devices: - if d.iface == ifname: - return to_path(d.add_test_nsp(name)) - raise UnknownDeviceException("Device not found") + def AddWimaxNsp(self, ident, name): + d = self.find_device_first(ident = ident, require = TestError) + return ExportedObj.to_path(d.add_test_nsp(name)) @dbus.service.method(IFACE_TEST, in_signature='so', out_signature='') - def RemoveWimaxNsp(self, ifname, nsp_path): - for d in self.devices: - if d.iface == ifname: - d.remove_nsp_by_path(nsp_path) - return - raise UnknownDeviceException("Device not found") + def RemoveWimaxNsp(self, ident, nsp_path): + d = self.find_device_first(ident = ident, require = TestError) + d.remove_nsp_by_path(nsp_path) @dbus.service.method(IFACE_TEST, in_signature='', out_signature='') def AutoRemoveNextConnection(self): - settings.auto_remove_next_connection() + gl.settings.auto_remove_next_connection() @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='a{sa{sv}}b', out_signature='o') def AddConnection(self, connection, verify_connection): - return settings.add_connection(connection, verify_connection) + return gl.settings.add_connection(connection, verify_connection) @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='sa{sa{sv}}b', out_signature='') def UpdateConnection(self, path, connection, verify_connection): - return settings.update_connection(connection, path, verify_connection) + return gl.settings.update_connection(connection, path, verify_connection) @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='', out_signature='') def Restart(self): - bus.release_name("org.freedesktop.NetworkManager") - bus.request_name("org.freedesktop.NetworkManager") + gl.bus.release_name("org.freedesktop.NetworkManager") + gl.bus.request_name("org.freedesktop.NetworkManager") + +############################################################################### -################################################################### IFACE_CONNECTION = 'org.freedesktop.NetworkManager.Settings.Connection' class InvalidPropertyException(dbus.DBusException): @@ -978,24 +1077,41 @@ class InvalidSettingException(dbus.DBusException): class MissingSettingException(dbus.DBusException): _dbus_error_name = IFACE_CONNECTION + '.MissingSetting' +PRP_CONNECTION_UNSAVED = 'Unsaved' + class Connection(ExportedObj): - def __init__(self, bus, object_path, settings, remove_func, verify_connection=True): + def __init__(self, path_counter, settings, verify_connection=True): + path = "/org/freedesktop/NetworkManager/Settings/Connection/%s" % (path_counter) + + ExportedObj.__init__(self, path) + + if 'connection' not in settings: + settings['connection'] = { } + if self.get_id(settings) is None: + settings['connection']['id'] = 'connection-%s' % (path_counter) if self.get_uuid(settings) is None: - if 'connection' not in settings: - settings['connection'] = { } - settings['connection']['uuid'] = uuid.uuid4() + settings['connection']['uuid'] = str(uuid.uuid3(uuid.NAMESPACE_URL, path)) self.verify(settings, verify_strict=verify_connection) - self.path = object_path + self.path = path self.settings = settings - self.remove_func = remove_func self.visible = True - self.props = {} - self.props['Unsaved'] = False - self.add_dbus_interface(IFACE_CONNECTION, self.__get_props, None) - ExportedObj.__init__(self, bus, object_path) + props = { + PRP_CONNECTION_UNSAVED: False, + } + + self.dbus_interface_add(IFACE_CONNECTION, props) + + def get_id(self, settings=None): + if settings is None: + settings = self.settings + if 'connection' in settings: + s_con = settings['connection'] + if 'id' in s_con: + return s_con['id'] + return None def get_uuid(self, settings=None): if settings is None: @@ -1036,13 +1152,6 @@ class Connection(ExportedObj): self.settings = settings; self.Updated() - def __get_props(self): - return self.props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_CONNECTION, propname) - - # Connection methods @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='a{sa{sv}}') def GetSettings(self): if not self.visible: @@ -1056,13 +1165,16 @@ class Connection(ExportedObj): @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='') def Delete(self): - self.remove_func(self) - self.Removed() - self.remove_from_connection() + gl.settings.delete_connection(self) @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='a{sa{sv}}', out_signature='') def Update(self, settings): - self.update_connection(settings, TRUE) + self.update_connection(settings, True) + + @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='a{sa{sv}}ua{sv}', out_signature='a{sv}') + def Update2(self, settings, flags, args): + self.update_connection(settings, True) + return [] @dbus.service.signal(IFACE_CONNECTION, signature='') def Removed(self): @@ -1072,25 +1184,33 @@ class Connection(ExportedObj): def Updated(self): pass -################################################################### +############################################################################### + IFACE_SETTINGS = 'org.freedesktop.NetworkManager.Settings' class InvalidHostnameException(dbus.DBusException): _dbus_error_name = IFACE_SETTINGS + '.InvalidHostname' +PRP_SETTINGS_HOSTNAME = 'Hostname' +PRP_SETTINGS_CAN_MODIFY = 'CanModify' +PRP_SETTINGS_CONNECTIONS = 'Connections' + class Settings(ExportedObj): - def __init__(self, bus, object_path): + def __init__(self): + ExportedObj.__init__(self, "/org/freedesktop/NetworkManager/Settings") + self.connections = {} - self.bus = bus - self.counter = 1 + self.c_counter = 0 self.remove_next_connection = False - self.props = {} - self.props['Hostname'] = "foobar.baz" - self.props['CanModify'] = True - self.props['Connections'] = dbus.Array([], 'o') - self.add_dbus_interface(IFACE_SETTINGS, self.__get_props, Settings.PropertiesChanged) - ExportedObj.__init__(self, bus, object_path) + props = { + PRP_SETTINGS_HOSTNAME: "foobar.baz", + PRP_SETTINGS_CAN_MODIFY: True, + PRP_SETTINGS_CONNECTIONS: dbus.Array([], 'o'), + } + + self.dbus_interface_add(IFACE_SETTINGS, props, Settings.PropertiesChanged) + self.export() def auto_remove_next_connection(self): self.remove_next_connection = True; @@ -1098,6 +1218,19 @@ class Settings(ExportedObj): def get_connection(self, path): return self.connections[path] + def find_connections(self, path = None, con_id = None, con_uuid = None): + for c in self.connections.values(): + if path is not None: + if c.path != path: + continue + if con_id is not None: + if c.get_id() != con_id: + continue + if con_uuid is not None: + if c.get_uuid() != con_uuid: + continue + yield c + @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='', out_signature='ao') def ListConnections(self): return self.connections.keys() @@ -1107,24 +1240,23 @@ class Settings(ExportedObj): return self.add_connection(settings) def add_connection(self, settings, verify_connection=True): - path = "/org/freedesktop/NetworkManager/Settings/Connection/{0}".format(self.counter) - con = Connection(self.bus, path, settings, self.delete_connection, verify_connection) + self.c_counter += 1 + con = Connection(self.c_counter, settings, verify_connection) uuid = con.get_uuid() if uuid in [c.get_uuid() for c in self.connections.values()]: raise InvalidSettingException('cannot add duplicate connection with uuid %s' % (uuid)) - self.counter = self.counter + 1 - self.connections[path] = con - self.props['Connections'] = dbus.Array(self.connections.keys(), 'o') - self.NewConnection(path) - self.__notify('Connections') + con.export() + self.connections[con.path] = con + self.NewConnection(con.path) + self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.connections.keys(), 'o')) if self.remove_next_connection: self.remove_next_connection = False - self.connections[path].Delete() + self.delete_connection(con) - return path + return con.path def update_connection(self, connection, path=None, verify_connection=True): if path is None: @@ -1136,22 +1268,16 @@ class Settings(ExportedObj): def delete_connection(self, connection): del self.connections[connection.path] - self.props['Connections'] = dbus.Array(self.connections.keys(), 'o') - self.__notify('Connections') + self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.connections.keys(), 'o')) + connection.Removed() + connection.unexport() @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='s', out_signature='') def SaveHostname(self, hostname): # Arbitrary requirement to test error handling if hostname.find('.') == -1: raise InvalidHostnameException() - self.props['Hostname'] = hostname - self.__notify('Hostname') - - def __get_props(self): - return self.props - - def __notify(self, propname): - self._dbus_property_notify(IFACE_SETTINGS, propname) + self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_HOSTNAME, hostname) @dbus.service.signal(IFACE_SETTINGS, signature='o') def NewConnection(self, path): @@ -1163,9 +1289,40 @@ class Settings(ExportedObj): @dbus.service.method(IFACE_SETTINGS, in_signature='', out_signature='') def Quit(self): - mainloop.quit() + gl.mainloop.quit() + +############################################################################### + +IFACE_DNS_MANAGER = 'org.freedesktop.NetworkManager.DnsManager' + +PRP_DNS_MANAGER_MODE = 'Mode' +PRP_DNS_MANAGER_RC_MANAGER = 'RcManager' +PRP_DNS_MANAGER_CONFIGURATION = 'Configuration' + +class DnsManager(ExportedObj): + def __init__(self): + ExportedObj.__init__(self, "/org/freedesktop/NetworkManager/DnsManager") + + props = { + PRP_DNS_MANAGER_MODE: "dnsmasq", + PRP_DNS_MANAGER_RC_MANAGER: "symlink", + PRP_DNS_MANAGER_CONFIGURATION: dbus.Array( + [ + dbus.Dictionary( + { + 'nameservers' : dbus.Array(['1.2.3.4', '5.6.7.8'], 's'), + 'priority' : dbus.Int32(100), + }, + 'sv') + ], + 'a{sv}'), + } + + self.dbus_interface_add(IFACE_DNS_MANAGER, props) + self.export() + +############################################################################### -################################################################### IFACE_AGENT_MANAGER = 'org.freedesktop.NetworkManager.AgentManager' IFACE_AGENT = 'org.freedesktop.NetworkManager.SecretAgent' @@ -1182,10 +1339,9 @@ class UserCanceledException(dbus.DBusException): _dbus_error_name = IFACE_AGENT_MANAGER + '.UserCanceled' class AgentManager(dbus.service.Object): - def __init__(self, bus, object_path): - dbus.service.Object.__init__(self, bus, object_path) + def __init__(self): + dbus.service.Object.__init__(self, gl.bus, "/org/freedesktop/NetworkManager/AgentManager") self.agents = {} - self.bus = bus @dbus.service.method(dbus_interface=IFACE_AGENT_MANAGER, in_signature='s', out_signature='', @@ -1197,7 +1353,7 @@ class AgentManager(dbus.service.Object): in_signature='su', out_signature='', sender_keyword='sender') def RegisterWithCapabilities(self, name, caps, sender=None): - self.agents[sender] = self.bus.get_object(sender, PATH_SECRET_AGENT) + self.agents[sender] = gl.bus.get_object(sender, PATH_SECRET_AGENT) @dbus.service.method(dbus_interface=IFACE_AGENT_MANAGER, in_signature='', out_signature='', @@ -1224,36 +1380,28 @@ class AgentManager(dbus.service.Object): continue return secrets -################################################################### -IFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager' +############################################################################### -PATH_OBJECT_MANAGER = '/org/freedesktop' +IFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager' class ObjectManager(dbus.service.Object): - def __init__(self, bus, object_path): - dbus.service.Object.__init__(self, bus, object_path) + def __init__(self, object_path): + dbus.service.Object.__init__(self, gl.bus, object_path) self.objs = [] - self.bus = bus - @dbus.service.method(dbus_interface=IFACE_OBJECT_MANAGER, - in_signature='', out_signature='a{oa{sa{sv}}}', - sender_keyword='sender') - def GetManagedObjects(self, sender=None): - managed_objects = {} - for obj in self.objs: - name, ifaces = obj.get_managed_ifaces() - managed_objects[name] = ifaces - return managed_objects + def find_object(self, path): + for o in self.objs: + if path == o.path: + return o + return None def add_object(self, obj): self.objs.append(obj) - name, ifaces = obj.get_managed_ifaces() - self.InterfacesAdded(name, ifaces) + self.InterfacesAdded(obj.path, obj.get_managed_ifaces()) def remove_object(self, obj): self.objs.remove(obj) - name, ifaces = obj.get_managed_ifaces() - self.InterfacesRemoved(name, ifaces.keys()) + self.InterfacesRemoved(obj.path, obj.get_managed_ifaces().keys()) @dbus.service.signal(IFACE_OBJECT_MANAGER, signature='oa{sa{sv}}') def InterfacesAdded(self, name, ifaces): @@ -1263,79 +1411,57 @@ class ObjectManager(dbus.service.Object): def InterfacesRemoved(self, name, ifaces): pass -################################################################### -IFACE_DNS_MANAGER = 'org.freedesktop.NetworkManager.DnsManager' - -class DnsManager(ExportedObj): - def __init__(self, bus, object_path): - self.props = {} - self.props['Mode'] = "dnsmasq" - self.props['RcManager'] = "symlink" - self.props['Configuration'] = dbus.Array([ - dbus.Dictionary( - { 'nameservers' : dbus.Array(['1.2.3.4', '5.6.7.8'], 's'), - 'priority' : dbus.Int32(100) }, - 'sv') ], - 'a{sv}') - - self.add_dbus_interface(IFACE_DNS_MANAGER, self.__get_props, None) - ExportedObj.__init__(self, bus, object_path) - - @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}') - def GetAll(self, iface): - if iface != IFACE_DNS_MANAGER: - raise UnknownInterfaceException() - return self.props - - @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v') - def Get(self, iface, name): - if iface != IFACE_DNS_MANAGER: - raise UnknownInterfaceException() - if not name in self.props.keys(): - raise UnknownPropertyException() - return self.props[name] - - def __get_props(self): - return self.props - -################################################################### -def stdin_cb(io, condition): - mainloop.quit() + @dbus.service.method(dbus_interface=IFACE_OBJECT_MANAGER, + in_signature='', out_signature='a{oa{sa{sv}}}', + sender_keyword='sender') + def GetManagedObjects(self, sender=None): + managed_objects = {} + for obj in self.objs: + managed_objects[obj.path] = obj.get_managed_ifaces() + return managed_objects -def quit_cb(user_data): - mainloop.quit() +############################################################################### def main(): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) random.seed() - global manager, settings, agent_manager, dns_manager, object_manager, bus + global gl + gl = Global() + + gl.mainloop = GLib.MainLoop() + gl.bus = dbus.SessionBus() - bus = dbus.SessionBus() - object_manager = ObjectManager(bus, "/org/freedesktop") - manager = NetworkManager(bus, "/org/freedesktop/NetworkManager") - settings = Settings(bus, "/org/freedesktop/NetworkManager/Settings") - agent_manager = AgentManager(bus, "/org/freedesktop/NetworkManager/AgentManager") - dns_manager = DnsManager(bus, "/org/freedesktop/NetworkManager/DnsManager") + gl.object_manager = ObjectManager('/org/freedesktop') + gl.manager = NetworkManager() + gl.settings = Settings() + gl.dns_manager = DnsManager() + gl.agent_manager = AgentManager() - if not bus.request_name("org.freedesktop.NetworkManager"): - sys.exit(1) + if not gl.bus.request_name("org.freedesktop.NetworkManager"): + raise AssertionError("Failure to request D-Bus name org.freedesktop.NetworkManager") # Watch stdin; if it closes, assume our parent has crashed, and exit - io = GLib.IOChannel(0) - io.add_watch(GLib.IOCondition.HUP, stdin_cb) + id1 = GLib.IOChannel(0).add_watch(GLib.IOCondition.HUP, + lambda io, condition: gl.mainloop.quit() or True) # also quit after inactivity to ensure we don't stick around if the above fails somehow - GLib.timeout_add_seconds(20, quit_cb, None) + id2 = GLib.timeout_add_seconds(20, + lambda: gl.mainloop.quit() or True) - try: - mainloop.run() - except Exception as e: - pass + gl.mainloop.run() + + GLib.source_remove(id1) + GLib.source_remove(id2) + + gl.agent_manager.remove_from_connection() + gl.dns_manager.unexport() + gl.settings.unexport() + gl.manager.unexport() + gl.object_manager.remove_from_connection() sys.exit(0) if __name__ == '__main__': main() - -- cgit 1.3.0-6-gf8a5 From 069cb5c3a525ebcc19cc2927964258acaca87b13 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Sun, 17 Jun 2018 14:54:10 +0200 Subject: New upstream version 1.11.90 --- tools/test-networkmanager-service.py | 1268 +++++++++++++++++++++++++++------- 1 file changed, 1034 insertions(+), 234 deletions(-) (limited to 'tools') diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index 8563aa19..ab63b60a 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -15,13 +15,15 @@ except Exception as e: print("Cannot load gi.NM: %s" % (str(e))) sys.exit(77) +import os import dbus import dbus.service import dbus.mainloop.glib import random -import collections import uuid import hashlib +import socket +import collections ############################################################################### @@ -43,49 +45,470 @@ class TestError(AssertionError): ############################################################################### -IFACE_DBUS = 'org.freedesktop.DBus' +class Util: -class UnknownInterfaceException(dbus.DBusException): - _dbus_error_name = IFACE_DBUS + '.UnknownInterface' + PY3 = (sys.version_info[0] == 3) -class UnknownPropertyException(dbus.DBusException): - _dbus_error_name = IFACE_DBUS + '.UnknownProperty' + @staticmethod + def addr_family_check(family, allow_af_unspec = False): + if family == socket.AF_INET: + return + if family == socket.AF_INET6: + return + if allow_af_unspec and family == socket.AF_UNSPEC: + return + raise TestError('invalid address family %s' % (family)) -class Util: + @staticmethod + def ip_addr_pton(addr, family=None): + if addr is None: + return (None, None) + if family is not None and family is not socket.AF_UNSPEC: + Util.addr_family_check(family) + a = socket.inet_pton(family, addr) + else: + a = None + family = None + try: + a = socket.inet_pton(socket.AF_INET, addr) + family = socket.AF_INET + except: + a = socket.inet_pton(socket.AF_INET6, addr) + family = socket.AF_INET6 + if Util.PY3: + a = tuple([int(c) for c in a]) + else: + a = tuple([ord(c) for c in a]) + return (a, family) + + @staticmethod + def ip_addr_ntop(addr, family = None): + if Util.PY3: + a = bytes(addr) + else: + a = ''.join([chr(c) for c in addr]) + if len(a) == 4: + f = socket.AF_INET + elif len(a) == 16: + f = socket.AF_INET6 + else: + raise TestError("Invalid binary IP address '%s'" % (repr(addr))) + if family is not None and f != family: + raise TestError("Unexpected address family. Expected %s but ip address was %s" % (family, repr(addr))) + return socket.inet_ntop(f, a) + + @staticmethod + def ip_addr_norm(addr, family = None): + a, family = Util.ip_addr_pton(addr, family) + return (Util.ip_addr_ntop(a, family), family) + + @staticmethod + def ip4_addr_ne32(addr): + a, family = Util.ip_addr_pton(addr, socket.AF_INET) + n = 0 + for i in range(4): + n = (n << 8) + a[i] + return socket.htonl(n) @staticmethod - def pseudorandom_stream(seed, length = None): - seed = str(seed) + def ip6_addr_ay(addr): + return Util.ip_addr_pton(addr, socket.AF_INET6)[0] + + @staticmethod + def ip_net_parse(net, family = None): + parts = net.split('/') + if len(parts) != 2: + raise TestError("Invalid IP network '%s' has not '/' for the prefix length" % (net)) + prefix = int(parts[1]) + addr, family = Util.ip_addr_norm(parts[0], family) + if family == socket.AF_INET: + if prefix < 0 or prefix > 32: + raise TestError("Invalid prefix length for IPv4 address '%s'" % (net)) + else: + if prefix < 0 or prefix > 128: + raise TestError("Invalid prefix length for IPv4 address '%s'" % (net)) + return (addr, prefix, family) + + class RandomSeed(): + def __init__(self, seed): + self.cnt = 0 + self.seed = str(seed) + def _next(self): + c = self.cnt + self.cnt += 1 + return self.seed + '-' + str(c) + @staticmethod + def wrap(seed): + if seed is None: + return None + if isinstance(seed, Util.RandomSeed): + return seed + return Util.RandomSeed(seed) + @staticmethod + def get(seed, extra_seed = None): + if seed is None: + return None + if isinstance(seed, Util.RandomSeed): + seed = seed._next() + else: + seed = str(seed) + if extra_seed is None: + try: + extra_seed = Util.RandomSeed._extra_seed + except: + extra_seed = os.environ.get('NM_TEST_NETWORKMANAGER_SERVICE_SEED', '') + Util.RandomSeed._extra_seed = extra_seed + return extra_seed + seed + + @staticmethod + def random_stream(seed, length = None): + seed = Util.RandomSeed.wrap(seed) + # generates a stream of integers, in the range [0..255] + if seed is None: + # without a seed, we generate new random numbers. + while length is None or length > 0: + yield random.randint(0, 255) + if length is not None: + length -= 1 + return v = None - i = 0 while length is None or length > 0: if not v: - s = seed + str(i) + s = Util.RandomSeed.get(seed) s = s.encode('utf8') v = hashlib.sha256(s).hexdigest() - i += 1 yield int(v[0:2], 16) v = v[2:] if length is not None: length -= 1 @staticmethod - def pseudorandom_num(seed, v_end, v_start = 0): + def random_int(seed, v_start = _DEFAULT_ARG, v_end = _DEFAULT_ARG): + # - if neither start not end is give, return a number in the range + # u32 range [0, 0xFFFFFFFF] + # - if only start is given (the first argument), interpret it as + # the range of the interval. That is, return random number in + # range [0, start-1] + # - if end and start is given, return a random number with this + # range (inclusive!): [start, end] + if v_end is _DEFAULT_ARG: + # if only one edge is provided (no v_end), then the range + # is [0, v_start[. That is, random_int(seed, 5), returns + # values from 0 to 4. + if v_start is _DEFAULT_ARG: + # by default, return a 32u integer. + v_end = 0x100000000 + else: + v_end = v_start + v_start = 0 + else: + if v_start is _DEFAULT_ARG: + raise TestError("Cannot specify end without start") + # if a full range is provided, v_end is included. + # random_int(seed, 0, 4) returns values from 0 to 4. + v_end += 1 n = 0 span = v_end - v_start - for r in Util.pseudorandom_stream(seed): + assert span > 0 + for r in Util.random_stream(seed): n = n * 256 + r if n > span: break return v_start + (n % span) @staticmethod - def random_mac(seed = None): - if seed is None: - r = tuple([random.randint(0, 255) for x in range(6)]) + def random_bool(seed): + return Util.random_int(seed, 0, 1) == 1 + + @staticmethod + def random_subset(seed, all_set): + all_set = list(all_set) + result = [] + seed = Util.RandomSeed.wrap(seed) + for i in list(range(Util.random_int(Util.RandomSeed.get(seed), len(all_set) + 1))): + idx = Util.random_int(Util.RandomSeed.get(seed), len(all_set)) + result.append(all_set[idx]) + del all_set[idx] + return result + + @staticmethod + def random_mac(seed): + return '%02X:%02X:%02X:%02X:%02X:%02X' % tuple(Util.random_stream(seed, 6)) + + @staticmethod + def random_ip(seed, net = None, family = None): + if net is not None: + mask, prefix, family = Util.ip_net_parse(net, family) + a_mask, unused = Util.ip_addr_pton(mask, family) + else: + prefix = None + Util.addr_family_check(family) + if family == socket.AF_INET: + l = 4 else: - r = tuple(Util.pseudorandom_stream(seed, 6)) - return '%02X:%02X:%02X:%02X:%02X:%02X' % r + l = 16 + a = tuple(Util.random_stream(seed, l)) + if prefix is not None: + a2 = [] + for i in range(l): + if prefix == 0: + c = a[i] + elif prefix >= 8: + c = a_mask[i] + prefix -= 8 + else: + c = 0xFF & (0xFF << (8 - prefix)) + c = (a[i] & ~c) | (a_mask[i] & c) + prefix = 0 + a2.append(c) + a = tuple(a2) + return (Util.ip_addr_ntop(a, family), family) + + @staticmethod + def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + + @staticmethod + def variant_from_dbus(val): + if isinstance(val, (dbus.String, str)): + return GLib.Variant('s', str(val)) + if isinstance(val, dbus.UInt32): + return GLib.Variant('u', int(val)) + if isinstance(val, dbus.Boolean): + return GLib.Variant('b', bool(val)) + if isinstance(val, dbus.Byte): + return GLib.Variant('y', int(val)) + if isinstance(val, dbus.Array): + try: + if val.signature == 's': + return GLib.Variant('as', [Util.variant_from_dbus(x) for x in val]) + if val.signature == 'b': + return GLib.Variant('ab', [Util.variant_from_dbus(x) for x in val]) + if val.signature == 'y': + return GLib.Variant('ay', [int(x) for x in val]) + if val.signature == 'u': + return GLib.Variant('au', [Util.variant_from_dbus(x) for x in val]) + if val.signature == 'ay': + return GLib.Variant('aay', [Util.variant_from_dbus(x) for x in val]) + if val.signature == 'au': + return GLib.Variant('aau', [Util.variant_from_dbus(x) for x in val]) + if val.signature == 'a{sv}': + return GLib.Variant('aa{sv}', [collections.OrderedDict([(str(k), Util.variant_from_dbus(v)) for k, v in addr.items()]) for addr in val]) + if val.signature == '(ayuay)': + return GLib.Variant('a(ayuay)', [Util.variant_from_dbus(x) for x in val]) + if val.signature == '(ayuayu)': + return GLib.Variant('a(ayuayu)', [Util.variant_from_dbus(x) for x in val]) + except Exception as e: + raise Exception("Cannot convert array element to type '%s': %s" % (val.signature, e.message)) + if isinstance(val, dbus.Dictionary): + if val.signature == 'ss': + return GLib.Variant('a{ss}', collections.OrderedDict([(str(k), str(v)) for k, v in val.items()])) + if val.signature == 'sv': + return GLib.Variant('a{sv}', collections.OrderedDict([(str(k), Util.variant_from_dbus(v)) for k, v in val.items()])) + if val.signature == 'sa{sv}': + c = collections.OrderedDict([ + (str(key1), + collections.OrderedDict([(str(key2), Util.variant_from_dbus(arr2)) for key2, arr2 in arr1.items()]) + ) for key1, arr1 in val.items() + ]) + return GLib.Variant('a{sa{sv}}', c) + + raise Exception("Unsupported type for value '%s'" % (repr(val))) + +############################################################################### + +IFACE_DBUS = 'org.freedesktop.DBus' +IFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager' +IFACE_CONNECTION = 'org.freedesktop.NetworkManager.Settings.Connection' +IFACE_DEVICE = 'org.freedesktop.NetworkManager.Device' +IFACE_WIFI = 'org.freedesktop.NetworkManager.Device.Wireless' +IFACE_WIMAX = 'org.freedesktop.NetworkManager.Device.WiMax' +IFACE_TEST = 'org.freedesktop.NetworkManager.LibnmGlibTest' +IFACE_NM = 'org.freedesktop.NetworkManager' +IFACE_SETTINGS = 'org.freedesktop.NetworkManager.Settings' +IFACE_AGENT_MANAGER = 'org.freedesktop.NetworkManager.AgentManager' +IFACE_AGENT = 'org.freedesktop.NetworkManager.SecretAgent' +IFACE_WIRED = 'org.freedesktop.NetworkManager.Device.Wired' +IFACE_VLAN = 'org.freedesktop.NetworkManager.Device.Vlan' +IFACE_WIFI_AP = 'org.freedesktop.NetworkManager.AccessPoint' +IFACE_WIMAX_NSP = 'org.freedesktop.NetworkManager.WiMax.Nsp' +IFACE_ACTIVE_CONNECTION = 'org.freedesktop.NetworkManager.Connection.Active' +IFACE_VPN_CONNECTION = 'org.freedesktop.NetworkManager.VPN.Connection' +IFACE_DNS_MANAGER = 'org.freedesktop.NetworkManager.DnsManager' +IFACE_IP4_CONFIG = 'org.freedesktop.NetworkManager.IP4Config' +IFACE_IP6_CONFIG = 'org.freedesktop.NetworkManager.IP6Config' +IFACE_DHCP4_CONFIG = 'org.freedesktop.NetworkManager.DHCP4Config' +IFACE_DHCP6_CONFIG = 'org.freedesktop.NetworkManager.DHCP6Config' + +############################################################################### + +class BusErr: + + class UnknownInterfaceException(dbus.DBusException): + _dbus_error_name = IFACE_DBUS + '.UnknownInterface' + + class UnknownPropertyException(dbus.DBusException): + _dbus_error_name = IFACE_DBUS + '.UnknownProperty' + + class InvalidPropertyException(dbus.DBusException): + _dbus_error_name = IFACE_CONNECTION + '.InvalidProperty' + + class MissingPropertyException(dbus.DBusException): + _dbus_error_name = IFACE_CONNECTION + '.MissingProperty' + + class InvalidSettingException(dbus.DBusException): + _dbus_error_name = IFACE_CONNECTION + '.InvalidSetting' + + class MissingSettingException(dbus.DBusException): + _dbus_error_name = IFACE_CONNECTION + '.MissingSetting' + + class NotSoftwareException(dbus.DBusException): + _dbus_error_name = IFACE_DEVICE + '.NotSoftware' + + class ApNotFoundException(dbus.DBusException): + _dbus_error_name = IFACE_WIFI + '.AccessPointNotFound' + + class NspNotFoundException(dbus.DBusException): + _dbus_error_name = IFACE_WIMAX + '.NspNotFound' + + class PermissionDeniedException(dbus.DBusException): + _dbus_error_name = IFACE_NM + '.PermissionDenied' + + class UnknownDeviceException(dbus.DBusException): + _dbus_error_name = IFACE_NM + '.UnknownDevice' + + class UnknownConnectionException(dbus.DBusException): + _dbus_error_name = IFACE_NM + '.UnknownConnection' + + class InvalidHostnameException(dbus.DBusException): + _dbus_error_name = IFACE_SETTINGS + '.InvalidHostname' + + class NoSecretsException(dbus.DBusException): + _dbus_error_name = IFACE_AGENT_MANAGER + '.NoSecrets' + + class UserCanceledException(dbus.DBusException): + _dbus_error_name = IFACE_AGENT_MANAGER + '.UserCanceled' + + @staticmethod + def from_nmerror(e): + try: + domain, code = (e.domain, e.code) + except: + return None + if domain == GLib.quark_to_string(NM.ConnectionError.quark()): + if code == NM.ConnectionError.MISSINGSETTING: + return BusErr.MissingSettingException(e.message) + if code == NM.ConnectionError.INVALIDPROPERTY: + return BusErr.InvalidPropertyException(e.message) + return None + + @staticmethod + def raise_nmerror(e): + e2 = BusErr.from_nmerror(e) + if e2 is not None: + raise e2 + raise e + +############################################################################### + +class NmUtil: + + @staticmethod + def con_hash_to_connection(con_hash, do_verify = False, do_normalize = False): + + x_con = [] + for v_setting_name, v_setting in list(con_hash.items()): + if isinstance(v_setting_name, (dbus.String, str)): + v_setting_name = str(v_setting_name) + else: + raise Exception("Expected string dict, but got '%s' key" % (v_setting_name)) + x_setting = [] + for v_property_name, v_value in list(v_setting.items()): + if isinstance(v_property_name, (dbus.String, str)): + v_property_name = str(v_property_name) + else: + raise Exception("Expected string dict, but got '%s' subkey under %s (%s)" % (v_property_name, v_setting_name, repr(con_hash))) + try: + v = Util.variant_from_dbus(v_value) + except Exception as e: + raise Exception("Unsupported value %s.%s = %s (%s)" % (v_setting_name, v_property_name, v_value, str(e))) + x_setting.append((v_property_name, v)) + + x_con.append((v_setting_name, collections.OrderedDict(x_setting))) + + x_con = GLib.Variant('a{sa{sv}}', collections.OrderedDict(x_con)) + + assert GLib.Variant.equal(x_con, Util.variant_from_dbus(con_hash)) + + try: + con = NM.SimpleConnection.new_from_dbus(x_con) + except: + if do_verify: + raise + return None + + if do_normalize: + try: + con.normalize() + except: + if do_verify: + raise + + if do_verify: + con.verify() + + return con + + @staticmethod + def con_hash_verify(con_hash, do_verify_strict = True): + if NM.SETTING_CONNECTION_SETTING_NAME not in con_hash: + raise BusErr.MissingSettingException('connection: setting is required') + s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME] + if NM.SETTING_CONNECTION_TYPE not in s_con: + raise BusErr.MissingPropertyException('connection.type: property is required') + if NM.SETTING_CONNECTION_UUID not in s_con: + raise BusErr.MissingPropertyException('connection.uuid: property is required') + if NM.SETTING_CONNECTION_ID not in s_con: + raise BusErr.MissingPropertyException('connection.id: property is required') + + if not do_verify_strict: + return; + t = s_con[NM.SETTING_CONNECTION_TYPE] + if t not in [ NM.SETTING_WIRED_SETTING_NAME, + NM.SETTING_WIRELESS_SETTING_NAME, + NM.SETTING_VLAN_SETTING_NAME, + NM.SETTING_WIMAX_SETTING_NAME, + NM.SETTING_VPN_SETTING_NAME ]: + raise BusErr.InvalidPropertyException('connection.type: unsupported connection type "%s"' % (t)) + + try: + con_nm = NmUtil.con_hash_to_connection(con_hash, do_verify = True, do_normalize = True) + except Exception as e: + BusErr.raise_nmerror(e) + + @staticmethod + def con_hash_get_id(con_hash): + if NM.SETTING_CONNECTION_SETTING_NAME in con_hash: + s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME] + if NM.SETTING_CONNECTION_ID in s_con: + return s_con[NM.SETTING_CONNECTION_ID] + return None + + @staticmethod + def con_hash_get_uuid(con_hash): + if NM.SETTING_CONNECTION_SETTING_NAME in con_hash: + s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME] + if NM.SETTING_CONNECTION_UUID in s_con: + return s_con[NM.SETTING_CONNECTION_UUID] + return None + + @staticmethod + def con_hash_get_type(con_hash): + if NM.SETTING_CONNECTION_SETTING_NAME in con_hash: + s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME] + if NM.SETTING_CONNECTION_TYPE in s_con: + return s_con[NM.SETTING_CONNECTION_TYPE] + return None ############################################################################### @@ -103,11 +526,8 @@ class ExportedObj(dbus.service.Object): @staticmethod def to_path_array(src): - array = dbus.Array([], signature=dbus.Signature('o')) - if src is not None: - for o in src: - array.append(ExportedObj.to_path(o)) - return array + return dbus.Array([ExportedObj.to_path(o) for o in src] if src else [], + signature=dbus.Signature('o')) @staticmethod def to_path(src): @@ -145,7 +565,7 @@ class ExportedObj(dbus.service.Object): def _dbus_interface_get(self, dbus_iface): if dbus_iface not in self._dbus_ifaces: - raise UnknownInterfaceException() + raise BusErr.UnknownInterfaceException() return self._dbus_ifaces[dbus_iface] def _dbus_interface_get_property(self, dbus_interface, propname = None): @@ -153,14 +573,14 @@ class ExportedObj(dbus.service.Object): if propname is None: return props if propname not in props: - raise UnknownPropertyException() + raise BusErr.UnknownPropertyException() return props[propname] def _dbus_property_get(self, dbus_iface, propname = None): return self._dbus_interface_get_property(self._dbus_interface_get(dbus_iface), propname) - def _dbus_property_set(self, dbus_iface, propname, value, allow_detect_dbus_iface = False, dry_run = False): + def _dbus_property_set(self, dbus_iface, propname, value, allow_detect_dbus_iface = False, dry_run = False, force_update = False): if allow_detect_dbus_iface and not dbus_iface: props = None for p, dbus_interface in self._dbus_ifaces.items(): @@ -184,15 +604,27 @@ class ExportedObj(dbus.service.Object): if propname not in props: raise TestError("No property '%s' on '%s' on '%s'" % (propname, dbus_iface, self.path)) - if isinstance(self, ActiveConnection) \ - and dbus_iface == 'org.freedesktop.NetworkManager.Connection.Active' \ - and propname == 'State': - return - else: + permission_granted = False + + if isinstance(self, ActiveConnection): + if dbus_iface == IFACE_ACTIVE_CONNECTION: + if propname == PRP_ACTIVE_CONNECTION_STATE: + permission_granted = True + elif dbus_iface == IFACE_VPN_CONNECTION: + if propname == PRP_VPN_CONNECTION_VPN_STATE: + permission_granted = True + + if not permission_granted: raise TestError("Cannot set property '%s' on '%s' on '%s' via D-Bus" % (propname, dbus_iface, self.path)) + return + assert propname in props + if not force_update: + if props[propname] == value: + return + props[propname] = value self._dbus_property_notify(dbus_iface, propname) @@ -232,11 +664,6 @@ class ExportedObj(dbus.service.Object): ############################################################################### -IFACE_DEVICE = 'org.freedesktop.NetworkManager.Device' - -class NotSoftwareException(dbus.DBusException): - _dbus_error_name = IFACE_DEVICE + '.NotSoftware' - PRP_DEVICE_UDI = "Udi" PRP_DEVICE_IFACE = "Interface" PRP_DEVICE_DRIVER = "Driver" @@ -263,16 +690,21 @@ class Device(ExportedObj): ExportedObj.__init__(self, ExportedObj.create_path(Device), ident) + self.ip4_config = None + self.ip6_config = None + self.dhcp4_config = None + self.dhcp6_config = None + props = { PRP_DEVICE_UDI: "/sys/devices/virtual/%s" % (iface), PRP_DEVICE_IFACE: iface, PRP_DEVICE_DRIVER: "virtual", PRP_DEVICE_STATE: dbus.UInt32(NM.DeviceState.UNAVAILABLE), PRP_DEVICE_ACTIVE_CONNECTION: ExportedObj.to_path(None), - PRP_DEVICE_IP4_CONFIG: ExportedObj.to_path(None), - PRP_DEVICE_IP6_CONFIG: ExportedObj.to_path(None), - PRP_DEVICE_DHCP4_CONFIG: ExportedObj.to_path(None), - PRP_DEVICE_DHCP6_CONFIG: ExportedObj.to_path(None), + PRP_DEVICE_IP4_CONFIG: ExportedObj.to_path(self.ip4_config), + PRP_DEVICE_IP6_CONFIG: ExportedObj.to_path(self.ip6_config), + PRP_DEVICE_DHCP4_CONFIG: ExportedObj.to_path(self.dhcp4_config), + PRP_DEVICE_DHCP6_CONFIG: ExportedObj.to_path(self.dhcp6_config), PRP_DEVICE_MANAGED: True, PRP_DEVICE_AUTOCONNECT: True, PRP_DEVICE_DEVICE_TYPE: dbus.UInt32(devtype), @@ -281,6 +713,34 @@ class Device(ExportedObj): self.dbus_interface_add(IFACE_DEVICE, props, Device.PropertiesChanged) + def start(self): + self.ip4_config = IP4Config() + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP4_CONFIG, ExportedObj.to_path(self.ip4_config)) + self.ip6_config = IP6Config() + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP6_CONFIG, ExportedObj.to_path(self.ip6_config)) + self.dhcp4_config = Dhcp4Config() + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP4_CONFIG, ExportedObj.to_path(self.dhcp4_config)) + self.dhcp6_config = Dhcp6Config() + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP6_CONFIG, ExportedObj.to_path(self.dhcp6_config)) + + def stop(self): + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP4_CONFIG, ExportedObj.to_path(None)) + if self.ip4_config is not None: + self.ip4_config.unexport() + self.ip4_config = None + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_IP6_CONFIG, ExportedObj.to_path(None)) + if self.ip6_config is not None: + self.ip6_config.unexport() + self.ip6_config = None + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP4_CONFIG, ExportedObj.to_path(None)) + if self.dhcp4_config is not None: + self.dhcp4_config.unexport() + self.dhcp4_config = None + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_DHCP6_CONFIG, ExportedObj.to_path(None)) + if self.dhcp6_config is not None: + self.dhcp6_config.unexport() + self.dhcp6_config = None + @dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='') def Disconnect(self): pass @@ -288,7 +748,7 @@ class Device(ExportedObj): @dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='') def Delete(self): # We don't currently support any software device types, so... - raise NotSoftwareException() + raise BusErr.NotSoftwareException() pass @dbus.service.signal(IFACE_DEVICE, signature='a{sv}') @@ -298,9 +758,25 @@ class Device(ExportedObj): def set_active_connection(self, ac): self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_ACTIVE_CONNECTION, ac) -############################################################################### + def connection_is_available(self, con_inst): + if con_inst.is_vpn(): + return False + if isinstance(self, WiredDevice): + if con_inst.get_type() == NM.SETTING_WIRED_SETTING_NAME: + return True + elif isinstance(self, WifiDevice): + if con_inst.get_type() == NM.SETTING_WIRELESS_SETTING_NAME: + return True + return False + + def available_connections_get(self): + return [c for c in gl.settings.get_connections() if self.connection_is_available(c)] -IFACE_WIRED = 'org.freedesktop.NetworkManager.Device.Wired' + def available_connections_update(self): + self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_AVAILABLE_CONNECTIONS, + ExportedObj.to_path_array(self.available_connections_get())) + +############################################################################### PRP_WIRED_HW_ADDRESS = "HwAddress" PRP_WIRED_PERM_HW_ADDRESS = "PermHwAddress" @@ -333,8 +809,6 @@ class WiredDevice(Device): ############################################################################### -IFACE_VLAN = 'org.freedesktop.NetworkManager.Device.Vlan' - PRP_VLAN_HW_ADDRESS = "HwAddress" PRP_VLAN_CARRIER = "Carrier" PRP_VLAN_VLAN_ID = "VlanId" @@ -357,8 +831,6 @@ class VlanDevice(Device): ############################################################################### -IFACE_WIFI_AP = 'org.freedesktop.NetworkManager.AccessPoint' - PRP_WIFI_AP_FLAGS = "Flags" PRP_WIFI_AP_WPA_FLAGS = "WpaFlags" PRP_WIFI_AP_RSN_FLAGS = "RsnFlags" @@ -389,7 +861,7 @@ class WifiAp(ExportedObj): if bssid is None: bssid = Util.random_mac(self.path) if strength is None: - strength = Util.pseudorandom_num(self.path, 100) + strength = Util.random_int(self.path, 100) self.ssid = ssid self.strength_counter = 0 @@ -416,7 +888,7 @@ class WifiAp(ExportedObj): def strength_cb(self, ignored): self.strength_counter += 1 - strength = Util.pseudorandom_num(self.path + str(self.strength_counter), 100) + strength = Util.random_int(self.path + str(self.strength_counter), 100) self._dbus_property_set(IFACE_WIFI_AP, PRP_WIFI_AP_STRENGTH, strength) return True @@ -426,11 +898,6 @@ class WifiAp(ExportedObj): ############################################################################### -IFACE_WIFI = 'org.freedesktop.NetworkManager.Device.Wireless' - -class ApNotFoundException(dbus.DBusException): - _dbus_error_name = IFACE_WIFI + '.AccessPointNotFound' - PRP_WIFI_HW_ADDRESS = "HwAddress" PRP_WIFI_PERM_HW_ADDRESS = "PermHwAddress" PRP_WIFI_MODE = "Mode" @@ -438,6 +905,7 @@ PRP_WIFI_BITRATE = "Bitrate" PRP_WIFI_ACCESS_POINTS = "AccessPoints" PRP_WIFI_ACTIVE_ACCESS_POINT = "ActiveAccessPoint" PRP_WIFI_WIRELESS_CAPABILITIES = "WirelessCapabilities" +PRP_WIFI_LAST_SCAN = "LastScan" class WifiDevice(Device): def __init__(self, iface, mac = None, ident = None): @@ -456,6 +924,7 @@ class WifiDevice(Device): PRP_WIFI_WIRELESS_CAPABILITIES: dbus.UInt32(0xFF), PRP_WIFI_ACCESS_POINTS: ExportedObj.to_path_array(self.aps), PRP_WIFI_ACTIVE_ACCESS_POINT: ExportedObj.to_path(None), + PRP_WIFI_LAST_SCAN: NM.utils_get_timestamp_msec(), } self.dbus_interface_add(IFACE_WIFI, props, WifiDevice.PropertiesChanged) @@ -504,13 +973,11 @@ class WifiDevice(Device): if ap.path == path: self.remove_ap(ap) return - raise ApNotFoundException("AP %s not found" % path) + raise BusErr.ApNotFoundException("AP %s not found" % path) ############################################################################### -IFACE_WIMAX_NSP = 'org.freedesktop.NetworkManager.WiMax.Nsp' - PRP_WIMAX_NSP_NAME = "Name" PRP_WIMAX_NSP_SIGNAL_QUALITY = "SignalQuality" PRP_WIMAX_NSP_NETWORK_TYPE = "NetworkType" @@ -549,11 +1016,6 @@ class WimaxNsp(ExportedObj): ############################################################################### -IFACE_WIMAX = 'org.freedesktop.NetworkManager.Device.WiMax' - -class NspNotFoundException(dbus.DBusException): - _dbus_error_name = IFACE_WIMAX + '.NspNotFound' - PRP_WIMAX_NSPS = "Nsps" PRP_WIMAX_HW_ADDRESS = "HwAddress" PRP_WIMAX_CENTER_FREQUENCY = "CenterFrequency" @@ -623,12 +1085,10 @@ class WimaxDevice(Device): if nsp.path == path: self.remove_nsp(nsp) return - raise NspNotFoundException("NSP %s not found" % path) + raise BusErr.NspNotFoundException("NSP %s not found" % path) ############################################################################### -IFACE_ACTIVE_CONNECTION = 'org.freedesktop.NetworkManager.Connection.Active' - PRP_ACTIVE_CONNECTION_CONNECTION = "Connection" PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT = "SpecificObject" PRP_ACTIVE_CONNECTION_ID = "Id" @@ -645,29 +1105,32 @@ PRP_ACTIVE_CONNECTION_DHCP6CONFIG = "Dhcp6Config" PRP_ACTIVE_CONNECTION_VPN = "Vpn" PRP_ACTIVE_CONNECTION_MASTER = "Master" +PRP_VPN_CONNECTION_VPN_STATE = 'VpnState' +PRP_VPN_CONNECTION_BANNER = 'Banner' + class ActiveConnection(ExportedObj): path_counter_next = 1 path_prefix = "/org/freedesktop/NetworkManager/ActiveConnection/" - def __init__(self, device, connection, specific_object): + def __init__(self, device, con_inst, specific_object): ExportedObj.__init__(self, ExportedObj.create_path(ActiveConnection)) self.device = device - self.conn = connection + self.con_inst = con_inst + self.is_vpn = con_inst.is_vpn() self._activation_id = None - conn_settings = self.conn.GetSettings() - s_con = conn_settings['connection'] + s_con = con_inst.con_hash[NM.SETTING_CONNECTION_SETTING_NAME] props = { - PRP_ACTIVE_CONNECTION_CONNECTION: ExportedObj.to_path(self.conn), + PRP_ACTIVE_CONNECTION_CONNECTION: ExportedObj.to_path(con_inst), PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT: ExportedObj.to_path(specific_object), - PRP_ACTIVE_CONNECTION_ID: s_con['id'], - PRP_ACTIVE_CONNECTION_UUID: s_con['uuid'], - PRP_ACTIVE_CONNECTION_TYPE: s_con['type'], + PRP_ACTIVE_CONNECTION_ID: s_con[NM.SETTING_CONNECTION_ID], + PRP_ACTIVE_CONNECTION_UUID: s_con[NM.SETTING_CONNECTION_UUID], + PRP_ACTIVE_CONNECTION_TYPE: s_con[NM.SETTING_CONNECTION_TYPE], PRP_ACTIVE_CONNECTION_DEVICES: ExportedObj.to_path_array([self.device]), PRP_ACTIVE_CONNECTION_STATE: dbus.UInt32(NM.ActiveConnectionState.UNKNOWN), PRP_ACTIVE_CONNECTION_DEFAULT: False, @@ -676,12 +1139,21 @@ class ActiveConnection(ExportedObj): PRP_ACTIVE_CONNECTION_DEFAULT6: False, PRP_ACTIVE_CONNECTION_IP6CONFIG: ExportedObj.to_path(None), PRP_ACTIVE_CONNECTION_DHCP6CONFIG: ExportedObj.to_path(None), - PRP_ACTIVE_CONNECTION_VPN: False, + PRP_ACTIVE_CONNECTION_VPN: self.is_vpn, PRP_ACTIVE_CONNECTION_MASTER: ExportedObj.to_path(None), } self.dbus_interface_add(IFACE_ACTIVE_CONNECTION, props, ActiveConnection.PropertiesChanged) + if self.is_vpn: + props = { + PRP_VPN_CONNECTION_VPN_STATE: dbus.UInt32(NM.VpnConnectionState.UNKNOWN), + PRP_VPN_CONNECTION_BANNER: '*** VPN connection %s ***' % (con_inst.get_id()), + } + + self.dbus_interface_add(IFACE_VPN_CONNECTION, props, ActiveConnection.VpnPropertiesChanged) + + def _set_state(self, state, reason): state = dbus.UInt32(state) self._dbus_property_set(IFACE_ACTIVE_CONNECTION, PRP_ACTIVE_CONNECTION_STATE, state) @@ -711,6 +1183,11 @@ class ActiveConnection(ExportedObj): assert self._activation_id is None self._activation_id = GLib.timeout_add(50, self._activation_step1) + @dbus.service.signal(IFACE_VPN_CONNECTION, signature='a{sv}') + def PropertiesChanged(self, changed): + pass + VpnPropertiesChanged = PropertiesChanged + @dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='a{sv}') def PropertiesChanged(self, changed): pass @@ -719,19 +1196,11 @@ class ActiveConnection(ExportedObj): def StateChanged(self, state, reason): pass -############################################################################### - -IFACE_TEST = 'org.freedesktop.NetworkManager.LibnmGlibTest' -IFACE_NM = 'org.freedesktop.NetworkManager' - -class PermissionDeniedException(dbus.DBusException): - _dbus_error_name = IFACE_NM + '.PermissionDenied' - -class UnknownDeviceException(dbus.DBusException): - _dbus_error_name = IFACE_NM + '.UnknownDevice' + @dbus.service.signal(IFACE_VPN_CONNECTION, signature='uu') + def VpnStateChanged(self, state, reason): + pass -class UnknownConnectionException(dbus.DBusException): - _dbus_error_name = IFACE_NM + '.UnknownConnection' +############################################################################### PRP_NM_DEVICES = 'Devices' PRP_NM_ALL_DEVICES = 'AllDevices' @@ -796,44 +1265,57 @@ class NetworkManager(ExportedObj): @dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o') def GetDeviceByIpIface(self, ip_iface): - d = self.find_device_first(ip_iface = ip_iface, require = UnknownDeviceException) + d = self.find_device_first(ip_iface = ip_iface, require = BusErr.UnknownDeviceException) return ExportedObj.to_path(d) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o') def ActivateConnection(self, conpath, devpath, specific_object): try: - connection = gl.settings.get_connection(conpath) + con_inst = gl.settings.get_connection(conpath) except Exception as e: - raise UnknownConnectionException("Connection not found") + raise BusErr.UnknownConnectionException("Connection not found") - hash = connection.GetSettings() - s_con = hash['connection'] + con_hash = con_inst.con_hash + con_type = NmUtil.con_hash_get_type(con_hash) device = self.find_device_first(path = devpath) - if not device and s_con['type'] == 'vlan': - ifname = s_con['interface-name'] - device = VlanDevice(ifname) - self.add_device(device) if not device: - raise UnknownDeviceException("No device found for the requested iface.") + if con_type == NM.SETTING_WIRED_SETTING_NAME: + device = self.find_device_first(dev_type = WiredDevice) + elif con_type == NM.SETTING_WIRELESS_SETTING_NAME: + device = self.find_device_first(dev_type = WifiDevice) + elif con_type == NM.SETTING_VLAN_SETTING_NAME: + ifname = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]['interface-name'] + device = VlanDevice(ifname) + self.add_device(device) + elif con_type == NM.SETTING_VPN_SETTING_NAME: + for ac in self.active_connections: + if ac.is_vpn: + continue + if ac.device: + device = ac.device + break + + if not device: + raise BusErr.UnknownDeviceException("No device found for the requested iface.") # See if we need secrets. For the moment, we only support WPA - if '802-11-wireless-security' in hash: - s_wsec = hash['802-11-wireless-security'] + if '802-11-wireless-security' in con_hash: + s_wsec = con_hash['802-11-wireless-security'] if (s_wsec['key-mgmt'] == 'wpa-psk' and 'psk' not in s_wsec): - secrets = gl.agent_manager.get_secrets(hash, conpath, '802-11-wireless-security') + secrets = gl.agent_manager.get_secrets(con_hash, conpath, '802-11-wireless-security') if secrets is None: - raise NoSecretsException("No secret agent available") + raise BusErr.NoSecretsException("No secret agent available") if '802-11-wireless-security' not in secrets: - raise NoSecretsException("No secrets provided") + raise BusErr.NoSecretsException("No secrets provided") s_wsec = secrets['802-11-wireless-security'] if 'psk' not in s_wsec: - raise NoSecretsException("No secrets provided") + raise BusErr.NoSecretsException("No secrets provided") - ac = ActiveConnection(device, connection, None) + ac = ActiveConnection(device, con_inst, None) self.active_connection_add(ac) - if s_con['id'] == 'object-creation-failed-test': + if NmUtil.con_hash_get_id(con_hash) == 'object-creation-failed-test': # FIXME: this is not the right test, to delete the active-connection # before returning it. It's the wrong order of what NetworkManager # would do. @@ -855,9 +1337,9 @@ class NetworkManager(ExportedObj): ac.unexport() @dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo') - def AddAndActivateConnection(self, connection, devpath, specific_object): - device = self.find_device_first(path = devpath, require = UnknownDeviceException) - conpath = gl.settings.AddConnection(connection) + def AddAndActivateConnection(self, con_hash, devpath, specific_object): + device = self.find_device_first(path = devpath, require = BusErr.UnknownDeviceException) + conpath = gl.settings.AddConnection(con_hash) return (conpath, self.ActivateConnection(conpath, devpath, specific_object)) @dbus.service.method(dbus_interface=IFACE_NM, in_signature='o', out_signature='') @@ -903,13 +1385,13 @@ class NetworkManager(ExportedObj): @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='u') def CheckConnectivity(self): - raise PermissionDeniedException("You fail") + raise BusErr.PermissionDeniedException("You fail") @dbus.service.signal(IFACE_NM, signature='o') def DeviceAdded(self, devpath): pass - def find_devices(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG): + def find_devices(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, dev_type = _DEFAULT_ARG): r = None for d in self.devices: if ident is not _DEFAULT_ARG: @@ -925,17 +1407,20 @@ class NetworkManager(ExportedObj): # ignore iface/ip_iface distinction for now if d.iface != ip_iface: continue + if dev_type is not _DEFAULT_ARG: + if not isinstance(d, dev_type): + continue yield d - def find_device_first(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, require = None): + def find_device_first(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, dev_type = _DEFAULT_ARG, require = None): r = None - for d in self.find_devices(ident = ident, path = path, iface = iface, ip_iface = ip_iface): + for d in self.find_devices(ident = ident, path = path, iface = iface, ip_iface = ip_iface, dev_type = dev_type): r = d break if r is None and require: if require is TestError: raise TestError('Device not found') - raise UnknownDeviceException('Device not found') + raise BusErr.UnknownDeviceException('Device not found') return r def add_device(self, device): @@ -946,15 +1431,21 @@ class NetworkManager(ExportedObj): self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices)) self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices)) self.DeviceAdded(ExportedObj.to_path(device)) + device.start() return device def remove_device(self, device): + device.stop() self.devices.remove(device) self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices)) self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices)) self.DeviceRemoved(ExportedObj.to_path(device)) device.unexport() + def devices_available_connections_update(self): + for d in self.devices: + d.available_connections_update() + @dbus.service.signal(IFACE_NM, signature='o') def DeviceRemoved(self, devpath): pass @@ -968,8 +1459,8 @@ class NetworkManager(ExportedObj): gl.mainloop.quit() @dbus.service.method(IFACE_TEST, in_signature='a{ss}', out_signature='a(sss)') - def FindConnections(self, args): - return [(c.path, c.get_uuid(), c.get_id()) for c in gl.settings.find_connections(**args)] + def FindConnections(self, selector_args): + return [(c.path, c.get_uuid(), c.get_id()) for c in gl.settings.find_connections(**selector_args)] @dbus.service.method(IFACE_TEST, in_signature='a(oa(sa(sv)))', out_signature='') def SetProperties(self, all_args): @@ -1048,12 +1539,18 @@ class NetworkManager(ExportedObj): gl.settings.auto_remove_next_connection() @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='a{sa{sv}}b', out_signature='o') - def AddConnection(self, connection, verify_connection): - return gl.settings.add_connection(connection, verify_connection) + def AddConnection(self, con_hash, do_verify_strict): + return gl.settings.add_connection(con_hash, do_verify_strict) @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='sa{sa{sv}}b', out_signature='') - def UpdateConnection(self, path, connection, verify_connection): - return gl.settings.update_connection(connection, path, verify_connection) + def UpdateConnection(self, path, con_hash, do_verify_strict): + return gl.settings.update_connection(con_hash, path, do_verify_strict) + + @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='ba{ss}', out_signature='') + def ConnectionSetVisible(self, vis, selector_args): + cons = list(gl.settings.find_connections(**selector_args)) + assert(len(cons) == 1) + cons[0].SetVisible(vis) @dbus.service.method(dbus_interface=IFACE_TEST, in_signature='', out_signature='') def Restart(self): @@ -1063,100 +1560,67 @@ class NetworkManager(ExportedObj): ############################################################################### -IFACE_CONNECTION = 'org.freedesktop.NetworkManager.Settings.Connection' - -class InvalidPropertyException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + '.InvalidProperty' - -class MissingPropertyException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + '.MissingProperty' - -class InvalidSettingException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + '.InvalidSetting' - -class MissingSettingException(dbus.DBusException): - _dbus_error_name = IFACE_CONNECTION + '.MissingSetting' - PRP_CONNECTION_UNSAVED = 'Unsaved' +PRP_CONNECTION_FILENAME = 'Filename' class Connection(ExportedObj): - def __init__(self, path_counter, settings, verify_connection=True): + def __init__(self, path_counter, con_hash, do_verify_strict=True): path = "/org/freedesktop/NetworkManager/Settings/Connection/%s" % (path_counter) ExportedObj.__init__(self, path) - if 'connection' not in settings: - settings['connection'] = { } - if self.get_id(settings) is None: - settings['connection']['id'] = 'connection-%s' % (path_counter) - if self.get_uuid(settings) is None: - settings['connection']['uuid'] = str(uuid.uuid3(uuid.NAMESPACE_URL, path)) - self.verify(settings, verify_strict=verify_connection) + s_con = con_hash.get(NM.SETTING_CONNECTION_SETTING_NAME) + if s_con is None: + s_con = {} + con_hash[NM.SETTING_CONNECTION_SETTING_NAME] = s_con + if NmUtil.con_hash_get_id(con_hash) is None: + s_con[NM.SETTING_CONNECTION_ID] = 'connection-%s' % (path_counter) + if NmUtil.con_hash_get_uuid(con_hash) is None: + s_con[NM.SETTING_CONNECTION_UUID] = str(uuid.uuid3(uuid.NAMESPACE_URL, path)) + + NmUtil.con_hash_verify(con_hash, do_verify_strict=do_verify_strict) self.path = path - self.settings = settings + self.con_hash = con_hash self.visible = True props = { PRP_CONNECTION_UNSAVED: False, + PRP_CONNECTION_FILENAME: "/etc/NetworkManager/system-connections/" + self.get_id(), } self.dbus_interface_add(IFACE_CONNECTION, props) - def get_id(self, settings=None): - if settings is None: - settings = self.settings - if 'connection' in settings: - s_con = settings['connection'] - if 'id' in s_con: - return s_con['id'] - return None + def get_id(self): + return NmUtil.con_hash_get_id(self.con_hash) - def get_uuid(self, settings=None): - if settings is None: - settings = self.settings - if 'connection' in settings: - s_con = settings['connection'] - if 'uuid' in s_con: - return s_con['uuid'] - return None + def get_uuid(self): + return NmUtil.con_hash_get_uuid(self.con_hash) - def verify(self, settings=None, verify_strict=True): - if settings is None: - settings = self.settings; - if 'connection' not in settings: - raise MissingSettingException('connection: setting is required') - s_con = settings['connection'] - if 'type' not in s_con: - raise MissingPropertyException('connection.type: property is required') - if 'uuid' not in s_con: - raise MissingPropertyException('connection.uuid: property is required') - if 'id' not in s_con: - raise MissingPropertyException('connection.id: property is required') - - if not verify_strict: - return; - t = s_con['type'] - if t not in ['802-3-ethernet', '802-11-wireless', 'vlan', 'wimax']: - raise InvalidPropertyException('connection.type: unsupported connection type "%s"' % (t)) + def get_type(self): + return NmUtil.con_hash_get_type(self.con_hash) + + def is_vpn(self): + return self.get_type() == NM.SETTING_VPN_SETTING_NAME - def update_connection(self, settings, verify_connection): - self.verify(settings, verify_strict=verify_connection) + def update_connection(self, con_hash, do_verify_strict): + + NmUtil.con_hash_verify(con_hash, do_verify_strict = do_verify_strict) old_uuid = self.get_uuid() - new_uuid = self.get_uuid(settings) + new_uuid = NmUtil.con_hash_get_uuid(con_hash) if old_uuid != new_uuid: - raise InvalidPropertyException('connection.uuid: cannot change the uuid from %s to %s' % (old_uuid, new_uuid)) + raise BusErr.InvalidPropertyException('connection.uuid: cannot change the uuid from %s to %s' % (old_uuid, new_uuid)) - self.settings = settings; + self.con_hash = con_hash; self.Updated() @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='', out_signature='a{sa{sv}}') def GetSettings(self): if not self.visible: - raise PermissionDeniedException() - return self.settings + raise BusErr.PermissionDeniedException() + return self.con_hash @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='b', out_signature='') def SetVisible(self, vis): @@ -1168,12 +1632,12 @@ class Connection(ExportedObj): gl.settings.delete_connection(self) @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='a{sa{sv}}', out_signature='') - def Update(self, settings): - self.update_connection(settings, True) + def Update(self, con_hash): + self.update_connection(con_hash, True) @dbus.service.method(dbus_interface=IFACE_CONNECTION, in_signature='a{sa{sv}}ua{sv}', out_signature='a{sv}') - def Update2(self, settings, flags, args): - self.update_connection(settings, True) + def Update2(self, con_hash, flags, args): + self.update_connection(con_hash, True) return [] @dbus.service.signal(IFACE_CONNECTION, signature='') @@ -1186,11 +1650,6 @@ class Connection(ExportedObj): ############################################################################### -IFACE_SETTINGS = 'org.freedesktop.NetworkManager.Settings' - -class InvalidHostnameException(dbus.DBusException): - _dbus_error_name = IFACE_SETTINGS + '.InvalidHostname' - PRP_SETTINGS_HOSTNAME = 'Hostname' PRP_SETTINGS_CAN_MODIFY = 'CanModify' PRP_SETTINGS_CONNECTIONS = 'Connections' @@ -1218,8 +1677,17 @@ class Settings(ExportedObj): def get_connection(self, path): return self.connections[path] + def get_connections(self, stable_order = True): + cons = list(self.connections.values()) + if stable_order: + cons.sort(key = lambda c: (Util.random_int(c.get_id()), Util.random_int(c.path))) + return cons + + def get_connection_paths(self, stable_order = True): + return [c.path for c in self.get_connections(stable_order = stable_order)] + def find_connections(self, path = None, con_id = None, con_uuid = None): - for c in self.connections.values(): + for c in self.get_connections(): if path is not None: if c.path != path: continue @@ -1233,50 +1701,51 @@ class Settings(ExportedObj): @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='', out_signature='ao') def ListConnections(self): - return self.connections.keys() + return self.get_connection_paths() @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='a{sa{sv}}', out_signature='o') - def AddConnection(self, settings): - return self.add_connection(settings) + def AddConnection(self, con_hash): + return self.add_connection(con_hash) - def add_connection(self, settings, verify_connection=True): + def add_connection(self, con_hash, do_verify_strict=True): self.c_counter += 1 - con = Connection(self.c_counter, settings, verify_connection) + con_inst = Connection(self.c_counter, con_hash, do_verify_strict) - uuid = con.get_uuid() - if uuid in [c.get_uuid() for c in self.connections.values()]: - raise InvalidSettingException('cannot add duplicate connection with uuid %s' % (uuid)) + uuid = con_inst.get_uuid() + if uuid in [c.get_uuid() for c in self.get_connections(stable_order = False)]: + raise BusErr.InvalidSettingException('cannot add duplicate connection with uuid %s' % (uuid)) - con.export() - self.connections[con.path] = con - self.NewConnection(con.path) - self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.connections.keys(), 'o')) + con_inst.export() + self.connections[con_inst.path] = con_inst + self.NewConnection(con_inst.path) + self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.get_connection_paths(), 'o')) if self.remove_next_connection: self.remove_next_connection = False - self.delete_connection(con) + self.delete_connection(con_inst) - return con.path + gl.manager.devices_available_connections_update() - def update_connection(self, connection, path=None, verify_connection=True): - if path is None: - path = connection.path + return con_inst.path + + def update_connection(self, con_hash, path=None, do_verify_strict=True): if path not in self.connections: - raise UnknownConnectionException('Connection not found') - con = self.connections[path] - con.update_connection(connection, verify_connection) + raise BusErr.UnknownConnectionException('Connection not found') + self.connections[path].update_connection(con_hash, do_verify_strict) + + def delete_connection(self, con_inst): + del self.connections[con_inst.path] + self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.get_connection_paths(), 'o')) + con_inst.Removed() + con_inst.unexport() - def delete_connection(self, connection): - del self.connections[connection.path] - self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_CONNECTIONS, dbus.Array(self.connections.keys(), 'o')) - connection.Removed() - connection.unexport() + gl.manager.devices_available_connections_update() @dbus.service.method(dbus_interface=IFACE_SETTINGS, in_signature='s', out_signature='') def SaveHostname(self, hostname): # Arbitrary requirement to test error handling if hostname.find('.') == -1: - raise InvalidHostnameException() + raise BusErr.InvalidHostnameException() self._dbus_property_set(IFACE_SETTINGS, PRP_SETTINGS_HOSTNAME, hostname) @dbus.service.signal(IFACE_SETTINGS, signature='o') @@ -1293,7 +1762,349 @@ class Settings(ExportedObj): ############################################################################### -IFACE_DNS_MANAGER = 'org.freedesktop.NetworkManager.DnsManager' +PRP_IP4_CONFIG_ADDRESSES = 'Addresses' +PRP_IP4_CONFIG_ADDRESSDATA = 'AddressData' +PRP_IP4_CONFIG_GATEWAY = 'Gateway' +PRP_IP4_CONFIG_ROUTES = 'Routes' +PRP_IP4_CONFIG_ROUTEDATA = 'RouteData' +PRP_IP4_CONFIG_NAMESERVERS = 'Nameservers' +PRP_IP4_CONFIG_DOMAINS = 'Domains' +PRP_IP4_CONFIG_SEARCHES = 'Searches' +PRP_IP4_CONFIG_DNSOPTIONS = 'DnsOptions' +PRP_IP4_CONFIG_DNSPRIORITY = 'DnsPriority' +PRP_IP4_CONFIG_WINSSERVERS = 'WinsServers' + +class IP4Config(ExportedObj): + + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/IP4Config/" + + def __init__(self, generate_seed = _DEFAULT_ARG): + ExportedObj.__init__(self, ExportedObj.create_path(IP4Config)) + + if generate_seed == _DEFAULT_ARG: + generate_seed = self.path + + props = self._props_generate(generate_seed) + self.dbus_interface_add(IFACE_IP4_CONFIG, props, IP4Config.PropertiesChanged) + self.export() + + def _props_generate(self, generate_seed): + seed = Util.RandomSeed.wrap(generate_seed) + + gateway = None + if seed: + if Util.random_bool(seed): + gateway = Util.random_ip(seed, net = '192.168.0.0/16')[0] + + addrs = [] + if seed: + for n in range(0, Util.random_int(seed, 4)): + a = { + 'addr': Util.random_ip(seed, net = '192.168.0.0/16')[0], + 'prefix': Util.random_int(seed, 17, 32), + 'gateway': gateway if n == 0 else None, + } + addrs.append(a) + + routes = [] + if seed: + for n in range(0, Util.random_int(seed, 4)): + a = { + 'dest': Util.random_ip(seed, net = '192.168.0.0/16')[0], + 'prefix': Util.random_int(seed, 17, 32), + 'next-hop': None if (Util.random_int(seed) % 3 == 0) else Util.random_ip(seed, net = '192.168.0.0/16')[0], + 'metric': -1 if (Util.random_int(seed) % 3 == 0) else Util.random_int(seed, 0, 0xFFFFFFFF), + } + routes.append(a) + + nameservers = [] + if seed: + nameservers = list([Util.random_ip(seed, net = '192.168.0.0/16')[0] for x in range(Util.random_int(seed, 4))]) + + names_selection = ['foo1.bar', 'foo2.bar', 'foo3.bar', 'foo4.bar', 'fo.o.bar', 'fo.x.y']; + + domains = [] + if seed: + domains = Util.random_subset(seed, ['dom4.' + s for s in names_selection]) + + searches = [] + if seed: + domains = Util.random_subset(seed, ['sear4.' + s for s in names_selection]) + + dnsoptions = [] + if seed: + dnsoptions = Util.random_subset(seed, ['dns4-opt1', 'dns4-opt2', 'dns4-opt3', 'dns4-opt4']) + + dnspriority = 0 + if seed: + dnspriority = Util.random_int(seed, -10000, 10000) + + winsservers = [] + if seed: + winsservers = list([Util.random_ip(seed, net = '192.168.0.0/16')[0] for x in range(Util.random_int(seed, 4))]) + + return { + PRP_IP4_CONFIG_ADDRESSES: dbus.Array([ + [ Util.ip4_addr_ne32(a['addr']), + a['prefix'], + Util.ip4_addr_ne32(a['gateway']) if a['gateway'] else 0 + ] for a in addrs + ], + 'au'), + PRP_IP4_CONFIG_ADDRESSDATA: dbus.Array([ + dbus.Dictionary(collections.OrderedDict( [ ('address', dbus.String(a['addr'])), + ('prefix', dbus.UInt32(a['prefix']))] + \ + ([ ('gateway', dbus.String(a['gateway'])) ] if a['gateway'] else [])), + 'sv') + for a in addrs + ], + 'a{sv}'), + PRP_IP4_CONFIG_GATEWAY: dbus.String(gateway) if gateway else "", + PRP_IP4_CONFIG_ROUTES: dbus.Array([ + [ Util.ip4_addr_ne32(a['dest']), + a['prefix'], + Util.ip4_addr_ne32(a['next-hop'] or '0.0.0.0'), + max(a['metric'], 0) + ] for a in routes + ], + 'au'), + PRP_IP4_CONFIG_ROUTEDATA: dbus.Array([ + dbus.Dictionary(collections.OrderedDict( [ ('dest', dbus.String(a['dest'])), + ('prefix', dbus.UInt32(a['prefix']))] + \ + ([ ('next-hop', dbus.String(a['next-hop'])) ] if a['next-hop'] else []) + \ + ([ ('metric', dbus.UInt32(a['metric'])) ] if a['metric'] != -1 else [])), + 'sv') + for a in routes + ], + 'a{sv}'), + PRP_IP4_CONFIG_NAMESERVERS: dbus.Array([dbus.UInt32(Util.ip4_addr_ne32(n)) for n in nameservers], 'u'), + PRP_IP4_CONFIG_DOMAINS: dbus.Array(domains, 's'), + PRP_IP4_CONFIG_SEARCHES: dbus.Array(searches, 's'), + PRP_IP4_CONFIG_DNSOPTIONS: dbus.Array(dnsoptions, 's'), + PRP_IP4_CONFIG_DNSPRIORITY: dbus.Int32(dnspriority), + PRP_IP4_CONFIG_WINSSERVERS: dbus.Array([dbus.UInt32(Util.ip4_addr_ne32(n)) for n in winsservers], 'u'), + } + + def props_regenerate(self, generate_seed): + props = self.generate_props(generate_seed) + for k,v in props.items(): + self._dbus_property_set(IFACE_IP4_CONFIG, k, v) + + @dbus.service.signal(IFACE_IP4_CONFIG, signature='a{sv}') + def PropertiesChanged(self, path): + pass + +############################################################################### + +PRP_IP6_CONFIG_ADDRESSES = "Addresses" +PRP_IP6_CONFIG_ADDRESSDATA = "AddressData" +PRP_IP6_CONFIG_GATEWAY = "Gateway" +PRP_IP6_CONFIG_ROUTES = "Routes" +PRP_IP6_CONFIG_ROUTEDATA = "RouteData" +PRP_IP6_CONFIG_NAMESERVERS = "Nameservers" +PRP_IP6_CONFIG_DOMAINS = "Domains" +PRP_IP6_CONFIG_SEARCHES = "Searches" +PRP_IP6_CONFIG_DNSOPTIONS = "DnsOptions" +PRP_IP6_CONFIG_DNSPRIORITY = "DnsPriority" + +class IP6Config(ExportedObj): + + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/IP6Config/" + + def __init__(self, generate_seed = _DEFAULT_ARG): + ExportedObj.__init__(self, ExportedObj.create_path(IP6Config)) + + if generate_seed == _DEFAULT_ARG: + generate_seed = self.path + + props = self._props_generate(generate_seed) + self.dbus_interface_add(IFACE_IP6_CONFIG, props, IP6Config.PropertiesChanged) + self.export() + + def _props_generate(self, generate_seed): + seed = Util.RandomSeed.wrap(generate_seed) + + gateway = None + if seed: + if Util.random_bool(seed): + gateway = Util.random_ip(seed, net = '2001:a::/64')[0] + + addrs = [] + if seed: + for n in range(0, Util.random_int(seed, 4)): + a = { + 'addr': Util.random_ip(seed, net = '2001:a::/64')[0], + 'prefix': Util.random_int(seed, 65, 128), + 'gateway': gateway if n == 0 else None, + } + addrs.append(a) + + routes = [] + if seed: + for n in range(0, Util.random_int(seed, 4)): + a = { + 'dest': Util.random_ip(seed, net = '2001:a::/64')[0], + 'prefix': Util.random_int(seed, 65, 128), + 'next-hop': None if (Util.random_int(seed) % 3 == 0) else Util.random_ip(seed, net = '2001:a::/64')[0], + 'metric': -1 if (Util.random_int(seed) % 3 == 0) else Util.random_int(seed, 0, 0xFFFFFFFF), + } + routes.append(a) + + nameservers = [] + if seed: + nameservers = list([Util.random_ip(seed, net = '2001:a::/64')[0] for x in range(Util.random_int(seed, 4))]) + + names_selection = ['foo1.bar', 'foo2.bar', 'foo3.bar', 'foo4.bar', 'fo.o.bar', 'fo.x.y']; + + domains = [] + if seed: + domains = Util.random_subset(seed, ['dom6.' + s for s in names_selection]) + + searches = [] + if seed: + domains = Util.random_subset(seed, ['sear6.' + s for s in names_selection]) + + dnsoptions = [] + if seed: + dnsoptions = Util.random_subset(seed, ['dns6-opt1', 'dns6-opt2', 'dns6-opt3', 'dns6-opt4']) + + dnspriority = 0 + if seed: + dnspriority = Util.random_int(seed, -10000, 10000) + + return { + PRP_IP6_CONFIG_ADDRESSES: dbus.Array([ + [ Util.ip6_addr_ay(a['addr']), + a['prefix'], + Util.ip6_addr_ay(a['gateway'] or '::') + ] for a in addrs + ], + '(ayuay)'), + PRP_IP6_CONFIG_ADDRESSDATA: dbus.Array([ + dbus.Dictionary(collections.OrderedDict( [ ('address', dbus.String(a['addr'])), + ('prefix', dbus.UInt32(a['prefix']))] + \ + ([ ('gateway', dbus.String(a['gateway'])) ] if a['gateway'] else [])), + 'sv') + for a in addrs + ], + 'a{sv}'), + PRP_IP6_CONFIG_GATEWAY: dbus.String(gateway) if gateway else "", + PRP_IP6_CONFIG_ROUTES: dbus.Array([ + [ Util.ip6_addr_ay(a['dest']), + a['prefix'], + Util.ip6_addr_ay(a['next-hop'] or '::'), + max(a['metric'], 0) + ] for a in routes + ], + '(ayuayu)'), + PRP_IP6_CONFIG_ROUTEDATA: dbus.Array([ + dbus.Dictionary(collections.OrderedDict( [ ('dest', dbus.String(a['dest'])), + ('prefix', dbus.UInt32(a['prefix']))] + \ + ([ ('next-hop', dbus.String(a['next-hop'])) ] if a['next-hop'] else []) + \ + ([ ('metric', dbus.UInt32(a['metric'])) ] if a['metric'] != -1 else [])), + 'sv') + for a in routes + ], + 'a{sv}'), + PRP_IP6_CONFIG_NAMESERVERS: dbus.Array([Util.ip6_addr_ay(n) for n in nameservers], 'ay'), + PRP_IP6_CONFIG_DOMAINS: dbus.Array(domains, 's'), + PRP_IP6_CONFIG_SEARCHES: dbus.Array(searches, 's'), + PRP_IP6_CONFIG_DNSOPTIONS: dbus.Array(dnsoptions, 's'), + PRP_IP6_CONFIG_DNSPRIORITY: dbus.Int32(dnspriority), + } + + def props_regenerate(self, generate_seed): + props = self.generate_props(generate_seed) + for k,v in props.items(): + self._dbus_property_set(IFACE_IP6_CONFIG, k, v) + + @dbus.service.signal(IFACE_IP6_CONFIG, signature='a{sv}') + def PropertiesChanged(self, path): + pass + +############################################################################### + +PRP_DHCP4_CONFIG_OPTIONS = 'Options' + +class Dhcp4Config(ExportedObj): + + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/DHCP4Config/" + + def __init__(self, generate_seed = _DEFAULT_ARG): + ExportedObj.__init__(self, ExportedObj.create_path(Dhcp4Config)) + + if generate_seed == _DEFAULT_ARG: + generate_seed = self.path + + props = self._props_generate(generate_seed) + self.dbus_interface_add(IFACE_DHCP4_CONFIG, props, Dhcp4Config.PropertiesChanged) + self.export() + + def _props_generate(self, generate_seed): + seed = Util.RandomSeed.wrap(generate_seed) + + options = [] + if seed: + options = Util.random_subset(seed, [('dhcp-4-opt-' + str(i), 'val-' + str(i)) for i in range(10)]) + + return { + PRP_DHCP4_CONFIG_OPTIONS: dbus.Dictionary(collections.OrderedDict(options), + 'sv') + } + + def props_regenerate(self, generate_seed): + props = self.generate_props(generate_seed) + for k,v in props.items(): + self._dbus_property_set(IFACE_DHCP4_CONFIG, k, v) + + @dbus.service.signal(IFACE_DHCP4_CONFIG, signature='a{sv}') + def PropertiesChanged(self, path): + pass + +############################################################################### + +PRP_DHCP6_CONFIG_OPTIONS = 'Options' + +class Dhcp6Config(ExportedObj): + + path_counter_next = 1 + path_prefix = "/org/freedesktop/NetworkManager/DHCP6Config/" + + def __init__(self, generate_seed = _DEFAULT_ARG): + ExportedObj.__init__(self, ExportedObj.create_path(Dhcp6Config)) + + if generate_seed == _DEFAULT_ARG: + generate_seed = self.path + + props = self._props_generate(generate_seed) + self.dbus_interface_add(IFACE_DHCP6_CONFIG, props, Dhcp6Config.PropertiesChanged) + self.export() + + def _props_generate(self, generate_seed): + seed = Util.RandomSeed.wrap(generate_seed) + + options = [] + if seed: + options = Util.random_subset(seed, [('dhcp-6-opt-' + str(i), 'val-' + str(i)) for i in range(10)]) + + return { + PRP_DHCP4_CONFIG_OPTIONS: dbus.Dictionary(collections.OrderedDict(options), + 'sv') + } + + def props_regenerate(self, generate_seed): + props = self.generate_props(generate_seed) + for k,v in props.items(): + self._dbus_property_set(IFACE_DHCP6_CONFIG, k, v) + + @dbus.service.signal(IFACE_DHCP6_CONFIG, signature='a{sv}') + def PropertiesChanged(self, path): + pass + +############################################################################### PRP_DNS_MANAGER_MODE = 'Mode' PRP_DNS_MANAGER_RC_MANAGER = 'RcManager' @@ -1323,21 +2134,12 @@ class DnsManager(ExportedObj): ############################################################################### -IFACE_AGENT_MANAGER = 'org.freedesktop.NetworkManager.AgentManager' -IFACE_AGENT = 'org.freedesktop.NetworkManager.SecretAgent' - PATH_SECRET_AGENT = '/org/freedesktop/NetworkManager/SecretAgent' FLAG_ALLOW_INTERACTION = 0x1 FLAG_REQUEST_NEW = 0x2 FLAG_USER_REQUESTED = 0x4 -class NoSecretsException(dbus.DBusException): - _dbus_error_name = IFACE_AGENT_MANAGER + '.NoSecrets' - -class UserCanceledException(dbus.DBusException): - _dbus_error_name = IFACE_AGENT_MANAGER + '.UserCanceled' - class AgentManager(dbus.service.Object): def __init__(self): dbus.service.Object.__init__(self, gl.bus, "/org/freedesktop/NetworkManager/AgentManager") @@ -1361,7 +2163,7 @@ class AgentManager(dbus.service.Object): def Unregister(self, sender=None): del self.agents[sender] - def get_secrets(self, connection, path, setting_name): + def get_secrets(self, con_hash, path, setting_name): if len(self.agents) == 0: return None @@ -1369,21 +2171,19 @@ class AgentManager(dbus.service.Object): for sender in self.agents: agent = self.agents[sender] try: - secrets = agent.GetSecrets(connection, path, setting_name, + secrets = agent.GetSecrets(con_hash, path, setting_name, dbus.Array([], 's'), FLAG_ALLOW_INTERACTION | FLAG_USER_REQUESTED, dbus_interface=IFACE_AGENT) break except dbus.DBusException as e: if e.get_dbus_name() == IFACE_AGENT + '.UserCanceled': - raise UserCanceledException('User canceled') + raise BusErr.UserCanceledException('User canceled') continue return secrets ############################################################################### -IFACE_OBJECT_MANAGER = 'org.freedesktop.DBus.ObjectManager' - class ObjectManager(dbus.service.Object): def __init__(self, object_path): dbus.service.Object.__init__(self, gl.bus, object_path) -- cgit 1.3.0-6-gf8a5 From 429393567647935d9123e21fd27a7529d50255eb Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Sun, 1 Jul 2018 20:58:23 +0200 Subject: New upstream version 1.12.0 --- tools/check-docs.sh | 22 +++++++++++ tools/test-networkmanager-service.py | 71 ++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 35 deletions(-) create mode 100755 tools/check-docs.sh (limited to 'tools') diff --git a/tools/check-docs.sh b/tools/check-docs.sh new file mode 100755 index 00000000..9dcdb1ef --- /dev/null +++ b/tools/check-docs.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +SOURCEDIR=$1 +[ -n "$SOURCEDIR" ] && SOURCEDIR="$SOURCEDIR/" + +# Check that the D-Bus API docs contain all known interfaces +if (sed -n 's/.*&2; then + echo "*** Error: D-Bus interfaces not included in docs/api/network-manager-docs.xml ***" >&2 + exit 1 +fi + +# Check that files that define types that are in public libnm API are included in libnm documentation. +# Don't complain about readability or I'll rewrite this in Perl. +if (sed -n 's/.*&2; then + echo "*** Error: libnm classes not included in docs/libnm/libnm-docs.xml ***" >&2 + exit 1 +fi + +exit 0 diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index ab63b60a..7fbed7ec 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -49,6 +49,11 @@ class Util: PY3 = (sys.version_info[0] == 3) + @staticmethod + def g_source_remove(source_id): + if source_id is not None: + GLib.source_remove(source_id) + @staticmethod def addr_family_check(family, allow_af_unspec = False): if family == socket.AF_INET: @@ -840,6 +845,7 @@ PRP_WIFI_AP_HW_ADDRESS = "HwAddress" PRP_WIFI_AP_MODE = "Mode" PRP_WIFI_AP_MAX_BITRATE = "MaxBitrate" PRP_WIFI_AP_STRENGTH = "Strength" +PRP_WIFI_AP_LAST_SEEN = "LastSeen" class WifiAp(ExportedObj): @@ -864,8 +870,6 @@ class WifiAp(ExportedObj): strength = Util.random_int(self.path, 100) self.ssid = ssid - self.strength_counter = 0 - self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None) props = { PRP_WIFI_AP_FLAGS: dbus.UInt32(flags), @@ -877,21 +881,11 @@ class WifiAp(ExportedObj): PRP_WIFI_AP_MODE: dbus.UInt32(getattr(NM,'80211Mode').INFRA), PRP_WIFI_AP_MAX_BITRATE: dbus.UInt32(54000), PRP_WIFI_AP_STRENGTH: dbus.Byte(strength), + PRP_WIFI_AP_LAST_SEEN: dbus.Int32(NM.utils_get_timestamp_msec() / 1000), } self.dbus_interface_add(IFACE_WIFI_AP, props, WifiAp.PropertiesChanged) - def __del__(self): - if self.strength_id > 0: - GLib.source_remove(self.strength_id) - self.strength_id = 0 - - def strength_cb(self, ignored): - self.strength_counter += 1 - strength = Util.random_int(self.path + str(self.strength_counter), 100) - self._dbus_property_set(IFACE_WIFI_AP, PRP_WIFI_AP_STRENGTH, strength) - return True - @dbus.service.signal(IFACE_WIFI_AP, signature='a{sv}') def PropertiesChanged(self, changed): pass @@ -915,6 +909,18 @@ class WifiDevice(Device): mac = Util.random_mac(self.ident) self.aps = [] + self.scan_cb_id = None + + # Note: we would like to simulate how nmcli calls RequestScan() and we could + # do so by using an older timestamp. However, that makes the client tests + # racy, because if a bunch of nmcli instances run in parallel against this + # service, earlier instances will issue a RequestScan(), while later instances + # won't do that (because the LastScan timestamp is already updated). That means, + # the later instances will print the scan result immediately, and in another sort + # order. That should be fixed, by nmcli not starting to print anything, before + # all RequestScan() requests complete, and thus, always print a consistent list + # of results. + ts = NM.utils_get_timestamp_msec() props = { PRP_WIFI_HW_ADDRESS: mac, @@ -924,7 +930,7 @@ class WifiDevice(Device): PRP_WIFI_WIRELESS_CAPABILITIES: dbus.UInt32(0xFF), PRP_WIFI_ACCESS_POINTS: ExportedObj.to_path_array(self.aps), PRP_WIFI_ACTIVE_ACCESS_POINT: ExportedObj.to_path(None), - PRP_WIFI_LAST_SCAN: NM.utils_get_timestamp_msec(), + PRP_WIFI_LAST_SCAN: dbus.Int64(ts), } self.dbus_interface_add(IFACE_WIFI, props, WifiDevice.PropertiesChanged) @@ -941,6 +947,15 @@ class WifiDevice(Device): @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='a{sv}', out_signature='') def RequestScan(self, props): + self.scan_cb_id = Util.g_source_remove(self.scan_cb_id) + def cb(): + ts = NM.utils_get_timestamp_msec() + for ap in self.aps: + ap._dbus_property_set(IFACE_WIFI_AP, PRP_WIFI_AP_LAST_SEEN, dbus.Int32(ts / 1000)) + self._dbus_property_set(IFACE_WIFI, PRP_WIFI_LAST_SCAN, dbus.Int64(ts)) + self.scan_cb_id = None + return False + self.scan_cb_id = GLib.idle_add(cb) pass @dbus.service.signal(IFACE_WIFI, signature='o') @@ -960,6 +975,10 @@ class WifiDevice(Device): self.AccessPointRemoved(ExportedObj.to_path(ap)) ap.unexport() + def stop(self): + self.scan_cb_id = Util.g_source_remove(self.scan_cb_id) + super(WifiDevice, self).stop() + @dbus.service.signal(IFACE_WIFI, signature='o') def AccessPointRemoved(self, ap_path): pass @@ -991,25 +1010,16 @@ class WimaxNsp(ExportedObj): ExportedObj.__init__(self, ExportedObj.create_path(WimaxNsp)) - self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None) + strength = Util.random_int(self.path, 100) props = { PRP_WIMAX_NSP_NAME: name, - PRP_WIMAX_NSP_SIGNAL_QUALITY: dbus.UInt32(random.randint(0, 100)), + PRP_WIMAX_NSP_SIGNAL_QUALITY: dbus.UInt32(strength), PRP_WIMAX_NSP_NETWORK_TYPE: dbus.UInt32(NM.WimaxNspNetworkType.HOME), } self.dbus_interface_add(IFACE_WIMAX_NSP, props, WimaxNsp.PropertiesChanged) - def __del__(self): - if self.strength_id > 0: - GLib.source_remove(self.strength_id) - self.strength_id = 0 - - def strength_cb(self, ignored): - self._dbus_property_set(IFACE_WIMAX_NSP, PRP_WIMAX_NSP_SIGNAL_QUALITY, dbus.UInt32(random.randint(0, 100))) - return True - @dbus.service.signal(IFACE_WIMAX_NSP, signature='a{sv}') def PropertiesChanged(self, changed): pass @@ -1160,11 +1170,7 @@ class ActiveConnection(ExportedObj): self.StateChanged(state, dbus.UInt32(reason)) def activation_cancel(self): - if self._activation_id is None: - return False - GLib.source_remove(self._activation_id) - self._activation_id = None - return True + self._activation_id = Util.g_source_remove(self._activation_id) def _activation_step2(self): assert self._activation_id is not None @@ -2246,14 +2252,9 @@ def main(): id1 = GLib.IOChannel(0).add_watch(GLib.IOCondition.HUP, lambda io, condition: gl.mainloop.quit() or True) - # also quit after inactivity to ensure we don't stick around if the above fails somehow - id2 = GLib.timeout_add_seconds(20, - lambda: gl.mainloop.quit() or True) - gl.mainloop.run() GLib.source_remove(id1) - GLib.source_remove(id2) gl.agent_manager.remove_from_connection() gl.dns_manager.unexport() -- cgit 1.3.0-6-gf8a5