<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 09/09/2013 10:23 AM, Vratislav
      Podzimek wrote:<br>
    </div>
    <blockquote cite="mid:1378715023.2119.12.camel@koki-desktop"
      type="cite">
      <pre wrap="">On Mon, 2013-09-09 at 09:41 +0200, Radek Vykydal wrote:
</pre>
      <blockquote type="cite">
        <pre wrap="">Device has to be in ACTIVATED state for IPXConfig to be valid.

1) use a recently added nm module function to get IP configuration, replacing
python-dbus with GDBus here. Python-dbus would give us stale value.

2) Don't use get_cached_property of GDBus as it would give us stale value too.
Instead use DBus.Properties interface call to get current values.
---
 pyanaconda/nm.py                    | 77 ++++++++++++++++++++-----------------
 pyanaconda/ui/gui/spokes/network.py | 64 +++++++++++-------------------
 2 files changed, 63 insertions(+), 78 deletions(-)

diff --git a/pyanaconda/nm.py b/pyanaconda/nm.py
index 1109d6e..4f0923d 100644
--- a/pyanaconda/nm.py
+++ b/pyanaconda/nm.py
@@ -73,10 +73,27 @@ def _get_proxy(bus_type=Gio.BusType.SYSTEM,
                                            cancellable)
     return proxy
 
+def _get_property(object_path, prop, interface_name_suffix=""):
+    interface_name = "org.freedesktop.NetworkManager" + interface_name_suffix
+    proxy = _get_proxy(object_path=object_path, interface_name="org.freedesktop.DBus.Properties")
+    args = GLib.Variant('(ss)', (interface_name, prop))
+    try:
+        prop = proxy.call_sync("Get",
+                                args,
+                                Gio.DBusCallFlags.NONE,
+                                DEFAULT_DBUS_TIMEOUT,
+                                None)
+    except GLib.GError as e:
+        if "org.freedesktop.DBus.Error.AccessDenied" in e.message:
+            return None
+        else:
+            raise
+
+    return prop.unpack()[0]
</pre>
      </blockquote>
      <pre wrap="">I'd suggest using dbus_get_property_safe_sync from
pyanaconda/safe_dbus.py. From what I recall using proxy.call_sync may
cause troubles if it was used in a non-main thread. The _get_property
function could stay almost the same, it should just handle exceptions
raised from the safe_dbus module.</pre>
    </blockquote>
    <br>
    <tt>For now I'd assume that calling a method on a proxy
      synchronously is</tt><tt><br>
    </tt><tt> safe, as the doc says:</tt><tt><br>
    </tt><tt> </tt><tt><br>
    </tt><tt> "A </tt><tt><a
        href="https://developer.gnome.org/gio/2.37/GDBusProxy.html"
        class="link" title="GDBusProxy"><span class="type">GDBusProxy</span></a></tt><tt>
      instance can be used from multiple threads but note that all
      signals (e.g. </tt><tt><a
href="https://developer.gnome.org/gio/2.37/GDBusProxy.html#GDBusProxy-g-signal"
        class="link" title="The &quot;g-signal&quot; signal"><span
          class="type">"g-signal"</span></a></tt><tt>, </tt><tt><a
href="https://developer.gnome.org/gio/2.37/GDBusProxy.html#GDBusProxy-g-properties-changed"
        class="link" title="The &quot;g-properties-changed&quot; signal"><span
          class="type">"g-properties-changed"</span></a></tt><tt> and </tt><tt><a
href="https://developer.gnome.org/gobject/unstable/gobject-The-Base-Object-Type.html#GObject-notify"><span
          class="type">"notify"</span></a></tt><tt>) are emitted in the
    </tt><tt><a
href="https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html#g-main-context-push-thread-default">thread-default

        main loop</a></tt><tt> of the thread where the instance was
      constructed.</tt><tt>"<br>
    </tt><tt> </tt><tt><br>
    </tt><tt> and I'll get back to dbus_get_property_safe_sync or to
      Glib guys if</tt><tt><br>
    </tt><tt> I hit similar issue. In this bz just calling
      DBus.Properties method instead</tt><tt><br>
    </tt><tt>using the properties cached by the proxy seems to fix the
      problem.</tt><tt><br>
    </tt><tt> </tt><tt><br>
    </tt><tt> (Checking the device state and then getting the config is
      racy anyway,</tt><tt><br>
    </tt><tt> but this is another story with the race condition being
      harder to hit.</tt><tt>)</tt><tt><br>
    </tt><tt> </tt><tt><br>
    </tt><tt>I've peeked into the gdbus code and gdbus_call_proxy_sync
      is calling</tt><tt><br>
    </tt><tt><a class="code"
href="http://fossies.org/dox/glib-2.36.4/gdbusconnection_8c.html#a0140b7433268c65bd4c812d112316a66">g_dbus_connection_call_sync</a></tt><tt>
      (called by safe_dbus) so the only</tt><tt><br>
    </tt><tt>difference seems to be the connection object being used.
      With proxy</tt><tt><br>
    </tt><tt>in nm.py the connection object seems to by created each
      time, while</tt><tt><br>
    </tt><tt>in keyboard.py you are re-using a connection created in
      __init__ of</tt><tt><br>
    </tt><tt>LocaledWrapper. Also as you said in your case the
      connection is</tt><tt><br>
    </tt><tt>autostarting its service which is not the case with NM so</tt><tt>
      perhaps<br>
      this might really be the problem I don't hit with NM service.</tt><br>
    <br>
    <blockquote cite="mid:1378715023.2119.12.camel@koki-desktop"
      type="cite">
      <pre wrap="">
</pre>
      <blockquote type="cite">
        <pre wrap=""> def nm_state():
     """Return state of NetworkManager"""
-    proxy = _get_proxy()
-    return proxy.get_cached_property("State").unpack()
+    return _get_property("/org/freedesktop/NetworkManager", "State")
 
 # FIXME - use just GLOBAL? There is some connectivity checking
 # for GLOBAL in NM (nm_connectivity_get_connected), not sure if
@@ -107,11 +124,11 @@ def nm_devices():
 
     devices = devices.unpack()[0]
     for device in devices:
-        proxy = _get_proxy(object_path=device, interface_name="org.freedesktop.NetworkManager.Device")
-        device_type = proxy.get_cached_property("DeviceType").unpack()
+        device_type = _get_property(device, "DeviceType", ".Device")
         if device_type not in supported_device_types:
             continue
-        interfaces.append(proxy.get_cached_property("Interface").unpack())
+        iface = _get_property(device, "Interface", ".Device")
+        interfaces.append(iface)
 
     return interfaces
 
@@ -120,19 +137,15 @@ def nm_activated_devices():
 
     interfaces = []
 
-    proxy = _get_proxy()
-    active_connections = proxy.get_cached_property("ActiveConnections").unpack()
+    active_connections = _get_property("/org/freedesktop/NetworkManager", "ActiveConnections")
     for ac in active_connections:
-        proxy = _get_proxy(object_path=ac, interface_name="org.freedesktop.NetworkManager.Connection.Active")
-        state = proxy.get_cached_property("State")
-        if not state or state.unpack() != NetworkManager.ActiveConnectionState.ACTIVATED:
-            continue
-        devices = proxy.get_cached_property("Devices")
-        if not devices:
+        state = _get_property(ac, "State", ".Connection.Active")
+        if state != NetworkManager.ActiveConnectionState.ACTIVATED:
             continue
-        for device in devices.unpack():
-            proxy = _get_proxy(object_path=device, interface_name="org.freedesktop.NetworkManager.Device")
-            interfaces.append(proxy.get_cached_property("Interface").unpack())
+        devices = _get_property(ac, "Devices", ".Connection.Active")
+        for device in devices:
+            iface = _get_property(device, "Interface", ".Device")
+            interfaces.append(iface)
 
     return interfaces
 
@@ -181,18 +194,14 @@ def nm_device_property(name, prop):
         raise
 
     device = device.unpack()[0]
-    proxy = _get_proxy(object_path=device, interface_name="org.freedesktop.NetworkManager.Device")
 
-    if prop in proxy.get_cached_property_names():
-        retval = proxy.get_cached_property(prop).unpack()
-    else:
+    retval = _get_property(device, prop, ".Device")
+    if not retval:
         # Look in device type based interface
         interface = _device_type_specific_interface(device)
         if interface:
-            proxy = _get_proxy(object_path=device, interface_name=interface)
-            if prop in proxy.get_cached_property_names():
-                retval = proxy.get_cached_property(prop).unpack()
-            else:
+            retval = _get_property(device, prop, interface[30:])
+            if not retval:
                 raise PropertyNotFoundError(prop)
         else:
             raise PropertyNotFoundError(prop)
@@ -284,10 +293,10 @@ def nm_device_ip_config(name, version=4):
         return []
 
     if version == 4:
-        dbus_iface = "org.freedesktop.NetworkManager.IP4Config"
+        dbus_iface = ".IP4Config"
         prop= "Ip4Config"
     elif version == 6:
-        dbus_iface = "org.freedesktop.NetworkManager.IP6Config"
+        dbus_iface = ".IP6Config"
         prop= "Ip6Config"
     else:
         return []
@@ -296,9 +305,7 @@ def nm_device_ip_config(name, version=4):
     if config == "/":
         return []
 
-    proxy = _get_proxy(object_path=config, interface_name=dbus_iface)
-
-    addresses = proxy.get_cached_property("Addresses").unpack()
+    addresses = _get_property(config, "Addresses", dbus_iface)
     addr_list = []
     for addr, prefix, gateway in addresses:
         # TODO - look for a library function (could have used IPy but byte order!)
@@ -310,7 +317,7 @@ def nm_device_ip_config(name, version=4):
             gateway_str = nm_dbus_ay_to_ipv6(gateway)
         addr_list.append([addr_str, prefix, gateway_str])
 
-    nameservers = proxy.get_cached_property("Nameservers").unpack()
+    nameservers = _get_property(config, "Nameservers", dbus_iface)
     ns_list = []
     for ns in nameservers:
         # TODO - look for a library function
@@ -322,7 +329,6 @@ def nm_device_ip_config(name, version=4):
 
     return [addr_list, ns_list]
 
-
 def nm_ntp_servers_from_dhcp():
     """Return a list of NTP servers that were specified the reply of the
        DHCP server or empty list if no NTP servers were returned.
@@ -335,16 +341,15 @@ def nm_ntp_servers_from_dhcp():
     for device in active_devices:
         # harvest NTP server addresses from DHCPv4
         dhcp4_path = nm_device_property(device, "Dhcp4Config")
-        dhcp4_proxy = _get_proxy(object_path=dhcp4_path,
-                interface_name="org.freedesktop.NetworkManager.DHCP4Config")
-        options = dhcp4_proxy.get_cached_property("Options")
-        if options and 'ntp_servers' in options.unpack():
+        options = _get_property(dhcp4_path, "Options", ".DHCP4Config")
+        if options and 'ntp_servers' in options:
             # NTP server addresses returned by DHCP are whitespace delimited
-            ntp_servers_string = options.unpack()["ntp_servers"] 
+            ntp_servers_string = options["ntp_servers"]
             for ip in ntp_servers_string.split(" "):
                 ntp_servers.append(ip)
 
         # NetworkManager does not request NTP/SNTP options for DHCP6
+    print ntp_servers
</pre>
      </blockquote>
      <pre wrap="">Debugging print?
</pre>
    </blockquote>
    <tt><br>
    </tt><tt> Yes, thanks</tt><tt><br>
    </tt><tt> </tt><tt><br>
    </tt><tt> Radek</tt><br>
  </body>
</html>