summary refs log tree commit diff
path: root/libnm/nm-object.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2017-01-17 20:25:09 +0100
committerMichael Biebl <biebl@debian.org>2017-01-17 20:25:09 +0100
commit58f8be580039b0575b197b9573a1c92745d96d30 (patch)
tree2c226233f623a0dcb529be0eb8cdf97e4a2ae0c0 /libnm/nm-object.c
parent45cb5bb3c0e6edb887cf69b417fcaf7053814a9b (diff)
New upstream version 1.5.90 upstream/1.5.90
Diffstat (limited to 'libnm/nm-object.c')
-rw-r--r--libnm/nm-object.c878
1 files changed, 157 insertions, 721 deletions
diff --git a/libnm/nm-object.c b/libnm/nm-object.c
index 20395ce8..a5eccbdc 100644
--- a/libnm/nm-object.c
+++ b/libnm/nm-object.c
@@ -29,7 +29,6 @@
 
 #include "nm-utils.h"
 #include "nm-dbus-interface.h"
-#include "nm-object-cache.h"
 #include "nm-object-private.h"
 #include "nm-dbus-helpers.h"
 #include "nm-client.h"
@@ -38,25 +37,18 @@
 static gboolean debug = FALSE;
 #define dbgmsg(f,...) if (G_UNLIKELY (debug)) { g_message (f, ## __VA_ARGS__ ); }
 
+G_DEFINE_QUARK (nm-obj-nm, _nm_object_obj_nm);
+
 static void nm_object_initable_iface_init (GInitableIface *iface);
 static void nm_object_async_initable_iface_init (GAsyncInitableIface *iface);
 
 typedef struct {
-	NMObjectDecideTypeFunc type_func;
-	char *interface;
-	char *property;
-} NMObjectTypeFuncData;
-
-static GHashTable *type_funcs;
-
-typedef struct {
 	GSList *interfaces;
 } NMObjectClassPrivate;
 
 #define NM_OBJECT_CLASS_GET_PRIVATE(k) (G_TYPE_CLASS_GET_PRIVATE ((k), NM_TYPE_OBJECT, NMObjectClassPrivate))
 
 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (NMObject, nm_object, G_TYPE_OBJECT,
-                                  type_funcs = g_hash_table_new (NULL, NULL);
                                   g_type_add_class_private (g_define_type_id, sizeof (NMObjectClassPrivate));
                                   G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_object_initable_iface_init);
                                   G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, nm_object_async_initable_iface_init);
@@ -75,15 +67,11 @@ static void reload_complete (NMObject *object, gboolean emit_now);
 static gboolean demarshal_generic (NMObject *object, GParamSpec *pspec, GVariant *value, gpointer field);
 
 typedef struct {
-	GDBusConnection *connection;
-	gboolean nm_running;
+	GDBusObject *object;
+	GDBusObjectManager *object_manager;
 
-	char *path;
-	GHashTable *proxies;
-	GDBusProxy *properties_proxy;
 	GSList *property_tables;
 	NMObject *parent;
-	gboolean suppress_property_updates;
 
 	gboolean inited;        /* async init finished? */
 	GSList *waiters;        /* if async init did not finish, users of this object need
@@ -104,50 +92,27 @@ enum {
 	PROP_PATH,
 	PROP_DBUS_CONNECTION,
 	PROP_NM_RUNNING,
+	PROP_DBUS_OBJECT,
+	PROP_DBUS_OBJECT_MANAGER,
 
 	LAST_PROP
 };
 
 /**
- * _nm_object_class_add_interface:
- * @object_class: an #NMObjectClass
- * @interface: a D-Bus interface name
- *
- * Registers that @object_class implements @interface. A proxy for that
- * interface will automatically be created at construction time, and can
- * be retrieved with _nm_object_get_proxy().
- */
-void
-_nm_object_class_add_interface (NMObjectClass *object_class,
-                                const char    *interface)
-{
-	NMObjectClassPrivate *cpriv;
-
-	g_return_if_fail (NM_IS_OBJECT_CLASS (object_class));
-	g_return_if_fail (interface);
-
-	cpriv = NM_OBJECT_CLASS_GET_PRIVATE (object_class);
-
-	g_return_if_fail (g_slist_find_custom (cpriv->interfaces, interface, (GCompareFunc) g_strcmp0) == NULL);
-
-	cpriv->interfaces = g_slist_prepend (cpriv->interfaces, g_strdup (interface));
-}
-
-/**
  * nm_object_get_path:
  * @object: a #NMObject
  *
  * Gets the DBus path of the #NMObject.
  *
  * Returns: the object's path. This is the internal string used by the
- * device, and must not be modified.
+ * object, and must not be modified.
  **/
 const char *
 nm_object_get_path (NMObject *object)
 {
 	g_return_val_if_fail (NM_IS_OBJECT (object), NULL);
 
-	return NM_OBJECT_GET_PRIVATE (object)->path;
+	return g_dbus_object_get_object_path (NM_OBJECT_GET_PRIVATE (object)->object);
 }
 
 /**
@@ -163,13 +128,14 @@ GDBusProxy *
 _nm_object_get_proxy (NMObject   *object,
                       const char *interface)
 {
-	GDBusProxy *proxy;
+	GDBusInterface *proxy;
 
 	g_return_val_if_fail (NM_IS_OBJECT (object), NULL);
 
-	proxy = g_hash_table_lookup (NM_OBJECT_GET_PRIVATE (object)->proxies, interface);
+	proxy = g_dbus_object_get_interface (NM_OBJECT_GET_PRIVATE (object)->object, interface);
 	g_return_val_if_fail (proxy != NULL, NULL);
-	return proxy;
+
+	return G_DBUS_PROXY (proxy);
 }
 
 typedef enum {
@@ -351,97 +317,6 @@ _nm_object_queue_notify (NMObject *object, const char *property)
 	_nm_object_queue_notify_full (object, property, NULL, FALSE, NULL);
 }
 
-void
-_nm_object_register_type_func (GType base_type,
-                               NMObjectDecideTypeFunc type_func,
-                               const char *interface,
-                               const char *property)
-{
-	NMObjectTypeFuncData *type_data;
-
-	g_return_if_fail (type_func != NULL);
-	g_return_if_fail (interface != NULL);
-	g_return_if_fail (property != NULL);
-
-	type_data = g_slice_new (NMObjectTypeFuncData);
-	type_data->type_func = type_func;
-	type_data->interface = g_strdup (interface);
-	type_data->property = g_strdup (property);
-
-	g_hash_table_insert (type_funcs,
-	                     GSIZE_TO_POINTER (base_type),
-	                     type_data);
-}
-
-static GObject *
-_nm_object_create (GType type, GDBusConnection *connection, const char *path)
-{
-	NMObjectTypeFuncData *type_data;
-	GObject *object;
-	GError *error = NULL;
-
-	type_data = g_hash_table_lookup (type_funcs, GSIZE_TO_POINTER (type));
-	if (type_data) {
-		GDBusProxy *proxy;
-		GVariant *ret, *value;
-
-		proxy = _nm_dbus_new_proxy_for_connection (connection, path,
-		                                           DBUS_INTERFACE_PROPERTIES,
-		                                           NULL, &error);
-		if (!proxy) {
-			g_warning ("Could not create proxy for %s: %s.", path, error->message);
-			g_error_free (error);
-			return NULL;
-		}
-
-		ret = g_dbus_proxy_call_sync (proxy,
-		                              "Get",
-		                              g_variant_new ("(ss)",
-		                                             type_data->interface,
-		                                             type_data->property),
-		                              G_DBUS_CALL_FLAGS_NONE, -1,
-		                              NULL, &error);
-		g_object_unref (proxy);
-		if (!ret) {
-			dbgmsg ("Could not fetch property '%s' of interface '%s' on %s: %s\n",
-			           type_data->property, type_data->interface, path, error->message);
-			g_error_free (error);
-			return NULL;
-		}
-
-		g_variant_get (ret, "(v)", &value);
-		type = type_data->type_func (value);
-		g_variant_unref (value);
-		g_variant_unref (ret);
-	}
-
-	if (type == G_TYPE_INVALID) {
-		dbgmsg ("Could not create object for %s: unknown object type", path);
-		return NULL;
-	}
-
-	object = g_object_new (type,
-	                       NM_OBJECT_PATH, path,
-	                       NM_OBJECT_DBUS_CONNECTION, connection,
-	                       NULL);
-	/* Cache the object before initializing it (and in particular, loading its
-	 * property values); this is necessary to make circular references work (eg,
-	 * when creating an NMActiveConnection, it will create an NMDevice which
-	 * will in turn try to create the parent NMActiveConnection). Since we don't
-	 * support multi-threaded use, we know that we will have inited the object
-	 * before any external code sees it.
-	 */
-	_nm_object_cache_add (NM_OBJECT (object));
-	NM_OBJECT_GET_PRIVATE (object)->inited = TRUE;
-	if (!g_initable_init (G_INITABLE (object), NULL, &error)) {
-		dbgmsg ("Could not create object for %s: %s", path, error->message);
-		g_error_free (error);
-		g_clear_object (&object);
-	}
-
-	return object;
-}
-
 typedef struct {
 	NMObject *self;
 	PropertyInfo *pi;
@@ -465,176 +340,6 @@ odata_free (gpointer data)
 
 static void object_property_maybe_complete (NMObject *self);
 
-
-typedef void (*NMObjectCreateCallbackFunc) (GObject *, const char *, gpointer);
-typedef struct {
-	char *path;
-	NMObjectCreateCallbackFunc callback;
-	gpointer user_data;
-	NMObjectTypeFuncData *type_data;
-	GDBusConnection *connection;
-} NMObjectTypeAsyncData;
-
-static void
-create_async_complete (GObject *object, NMObjectTypeAsyncData *async_data)
-{
-	async_data->callback (object, async_data->path, async_data->user_data);
-
-	g_free (async_data->path);
-	g_object_unref (async_data->connection);
-	g_slice_free (NMObjectTypeAsyncData, async_data);
-}
-
-static void
-create_async_inited (GObject *object, GAsyncResult *result, gpointer user_data)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	NMObjectPrivate *odata_priv;
-	NMObjectTypeAsyncData *async_data = user_data;
-	GError *error = NULL;
-	ObjectCreatedData *odata;
-
-	priv->inited = TRUE;
-	if (!g_async_initable_init_finish (G_ASYNC_INITABLE (object), result, &error)) {
-		dbgmsg ("Could not create object for %s: %s",
-		        nm_object_get_path (NM_OBJECT (object)),
-		        error->message);
-
-		while (priv->waiters) {
-			odata = priv->waiters->data;
-			odata_priv = NM_OBJECT_GET_PRIVATE (odata->self);
-
-			priv->waiters = g_slist_remove (priv->waiters, odata);
-			if (!odata_priv->reload_error)
-				odata_priv->reload_error = g_error_copy (error);
-			odata_priv->reload_remaining--;
-			reload_complete (odata->self, FALSE);
-		}
-
-		g_error_free (error);
-		g_clear_object (&object);
-	}
-
-	create_async_complete (object, async_data);
-
-	if (object) {
-		/* There are some object properties whose creation couldn't proceed
-		 * because it depended on this object. */
-		while (priv->waiters) {
-			odata = priv->waiters->data;
-			priv->waiters = g_slist_remove (priv->waiters, odata);
-			object_property_maybe_complete (odata->self);
-		}
-	}
-}
-
-static void
-create_async_got_type (NMObjectTypeAsyncData *async_data, GType type)
-{
-	GObject *object;
-
-	/* Ensure we don't have the object already; we may get multiple type
-	 * requests for the same object if there are multiple properties on
-	 * other objects that refer to the object at this path.  One of those
-	 * other requests may have already completed.
-	 */
-	object = (GObject *) _nm_object_cache_get (async_data->path);
-	if (object) {
-		create_async_complete (object, async_data);
-		return;
-	}
-
-	if (type == G_TYPE_INVALID) {
-		/* Don't know how to create this object */
-		create_async_complete (NULL, async_data);
-		return;
-	}
-
-	object = g_object_new (type,
-	                       NM_OBJECT_PATH, async_data->path,
-	                       NM_OBJECT_DBUS_CONNECTION, async_data->connection,
-	                       NULL);
-	_nm_object_cache_add (NM_OBJECT (object));
-	g_async_initable_init_async (G_ASYNC_INITABLE (object), G_PRIORITY_DEFAULT,
-	                             NULL, create_async_inited, async_data);
-}
-
-static void
-create_async_got_property (GObject *proxy, GAsyncResult *result, gpointer user_data)
-{
-	NMObjectTypeAsyncData *async_data = user_data;
-	NMObjectTypeFuncData *type_data = async_data->type_data;
-	GVariant *ret, *value;
-	GError *error = NULL;
-	GType type;
-
-	ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
-	                                  G_VARIANT_TYPE ("(v)"), &error);
-	if (ret) {
-		g_variant_get (ret, "(v)", &value);
-		type = type_data->type_func (value);
-		g_variant_unref (value);
-		g_variant_unref (ret);
-	} else {
-		dbgmsg ("Could not fetch property '%s' of interface '%s' on %s: %s\n",
-		        type_data->property, type_data->interface, async_data->path,
-		        error->message);
-		g_clear_error (&error);
-		type = G_TYPE_INVALID;
-	}
-
-	create_async_got_type (async_data, type);
-}
-
-static void
-create_async_got_proxy (GObject *object, GAsyncResult *result, gpointer user_data)
-{
-	NMObjectTypeAsyncData *async_data = user_data;
-	GDBusProxy *proxy;
-	GError *error = NULL;
-
-	proxy = _nm_dbus_new_proxy_for_connection_finish (result, &error);
-	if (!proxy) {
-		g_warning ("Could not create proxy for %s: %s.", async_data->path, error->message);
-		g_error_free (error);
-		create_async_complete (NULL, async_data);
-		return;
-	}
-
-	g_dbus_proxy_call (proxy,
-	                   "Get",
-	                   g_variant_new ("(ss)",
-	                                  async_data->type_data->interface,
-	                                  async_data->type_data->property),
-	                   G_DBUS_CALL_FLAGS_NONE, -1,
-	                   NULL,
-	                   create_async_got_property, async_data);
-}
-
-static void
-_nm_object_create_async (GType type, GDBusConnection *connection, const char *path,
-                         NMObjectCreateCallbackFunc callback, gpointer user_data)
-{
-	NMObjectTypeAsyncData *async_data;
-
-	async_data = g_slice_new (NMObjectTypeAsyncData);
-	async_data->path = g_strdup (path);
-	async_data->callback = callback;
-	async_data->user_data = user_data;
-	async_data->connection = g_object_ref (connection);
-
-	async_data->type_data = g_hash_table_lookup (type_funcs, GSIZE_TO_POINTER (type));
-	if (async_data->type_data) {
-		_nm_dbus_new_proxy_for_connection_async (connection, path,
-		                                         DBUS_INTERFACE_PROPERTIES,
-		                                         NULL,
-		                                         create_async_got_proxy, async_data);
-		return;
-	}
-
-	create_async_got_type (async_data, type);
-}
-
 /* Stolen from dbus-glib */
 static char*
 wincaps_to_dash (const char *caps)
@@ -855,15 +560,16 @@ object_created (GObject *obj, const char *path, gpointer user_data)
 			object_class->object_creation_failed (odata->self, path);
 	}
 
-	odata->objects[--odata->remaining] = obj;
+	odata->objects[--odata->remaining] = obj ? g_object_ref (obj) : NULL;
 	object_property_maybe_complete (odata->self);
 }
 
 static gboolean
 handle_object_property (NMObject *self, const char *property_name, GVariant *value,
-                        PropertyInfo *pi, gboolean synchronously)
+                        PropertyInfo *pi)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
+	gs_unref_object GDBusObject *object = NULL;
 	GObject *obj;
 	const char *path;
 	ObjectCreatedData *odata;
@@ -871,7 +577,7 @@ handle_object_property (NMObject *self, const char *property_name, GVariant *val
 	odata = g_slice_new (ObjectCreatedData);
 	odata->self = g_object_ref (self);
 	odata->pi = pi;
-	odata->objects = g_new (GObject *, 1);
+	odata->objects = g_new0 (GObject *, 1);
 	odata->length = odata->remaining = 1;
 	odata->array = FALSE;
 	odata->property_name = property_name;
@@ -886,31 +592,28 @@ handle_object_property (NMObject *self, const char *property_name, GVariant *val
 		return TRUE;
 	}
 
-	obj = G_OBJECT (_nm_object_cache_get (path));
-	if (obj) {
-		object_created (obj, path, odata);
-		return TRUE;
-	} else if (synchronously) {
-		obj = _nm_object_create (pi->object_type, priv->connection, path);
-		object_created (obj, path, odata);
-		return obj != NULL;
-	} else {
-		_nm_object_create_async (pi->object_type, priv->connection, path,
-		                         object_created, odata);
-		/* Assume success */
-		return TRUE;
+	object = g_dbus_object_manager_get_object (priv->object_manager, path);
+	if (!object) {
+		/* This is a server bug -- a dangling object path for an object
+		 * that does not exist. */
+		g_warning ("No object known for %s", path);
+		return FALSE;
 	}
+
+	obj = g_object_get_qdata (G_OBJECT (object), _nm_object_obj_nm_quark ());
+	object_created (obj, path, odata);
+
+	return TRUE;
 }
 
 static gboolean
 handle_object_array_property (NMObject *self, const char *property_name, GVariant *value,
-                              PropertyInfo *pi, gboolean synchronously)
+                              PropertyInfo *pi)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
 	GObject *obj;
 	GVariantIter iter;
 	gsize npaths;
-	GPtrArray **array = pi->field;
 	const char *path;
 	ObjectCreatedData *odata;
 
@@ -934,34 +637,25 @@ handle_object_array_property (NMObject *self, const char *property_name, GVarian
 
 	g_variant_iter_init (&iter, value);
 	while (g_variant_iter_next (&iter, "&o", &path)) {
-		if (!strcmp (path, "/")) {
-			/* FIXME: can't happen? */
-			continue;
-		}
+		gs_unref_object GDBusObject *object = NULL;
 
-		obj = G_OBJECT (_nm_object_cache_get (path));
-		if (obj) {
-			object_created (obj, path, odata);
-		} else if (synchronously) {
-			obj = _nm_object_create (pi->object_type, priv->connection, path);
+		object = g_dbus_object_manager_get_object (priv->object_manager, path);
+		if (object) {
+			obj = g_object_get_qdata (G_OBJECT (object), _nm_object_obj_nm_quark ());
 			object_created (obj, path, odata);
 		} else {
-			_nm_object_create_async (pi->object_type, priv->connection, path,
-			                         object_created, odata);
+			g_warning ("no object known for %s\n", path);
+			odata->remaining--;
+			odata->length--;
+			object_property_maybe_complete (self);
 		}
 	}
 
-	if (!synchronously) {
-		/* Assume success */
-		return TRUE;
-	}
-
-	return *array && ((*array)->len == npaths);
+	return TRUE;
 }
 
 static void
-handle_property_changed (NMObject *self, const char *dbus_name,
-                         GVariant *value, gboolean synchronously)
+handle_property_changed (NMObject *self, const char *dbus_name, GVariant *value)
 {
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
 	char *prop_name;
@@ -1015,9 +709,9 @@ handle_property_changed (NMObject *self, const char *dbus_name,
 
 	if (pspec && pi->object_type) {
 		if (g_variant_is_of_type (value, G_VARIANT_TYPE_OBJECT_PATH))
-			success = handle_object_property (self, pspec->name, value, pi, synchronously);
+			success = handle_object_property (self, pspec->name, value, pi);
 		else if (g_variant_is_of_type (value, G_VARIANT_TYPE ("ao")))
-			success = handle_object_array_property (self, pspec->name, value, pi, synchronously);
+			success = handle_object_array_property (self, pspec->name, value, pi);
 		else {
 			g_warn_if_reached ();
 			goto out;
@@ -1037,31 +731,23 @@ out:
 }
 
 static void
-process_properties_changed (NMObject *self, GVariant *properties, gboolean synchronously)
+properties_changed (GDBusProxy *proxy,
+                    GVariant   *changed_properties,
+                    GStrv       invalidated_properties,
+                    gpointer    user_data)
 {
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
+	NMObject *self = NM_OBJECT (user_data);
 	GVariantIter iter;
 	const char *name;
 	GVariant *value;
 
-	if (priv->suppress_property_updates)
-		return;
-
-	g_variant_iter_init (&iter, properties);
+	g_variant_iter_init (&iter, changed_properties);
 	while (g_variant_iter_next (&iter, "{&sv}", &name, &value)) {
-		handle_property_changed (self, name, value, synchronously);
+		handle_property_changed (self, name, value);
 		g_variant_unref (value);
 	}
 }
 
-static void
-properties_changed (GDBusProxy *proxy,
-                    GVariant   *properties,
-                    gpointer    user_data)
-{
-	process_properties_changed (NM_OBJECT (user_data), properties, FALSE);
-}
-
 #define HANDLE_TYPE(vtype, ctype, getter) \
 	G_STMT_START { \
 		if (g_variant_is_of_type (value, vtype)) { \
@@ -1240,10 +926,9 @@ _nm_object_register_properties (NMObject *object,
 	}
 
 	proxy = _nm_object_get_proxy (object, interface);
-	g_return_if_fail (proxy != NULL);
-
-	_nm_dbus_signal_connect (proxy, "PropertiesChanged", G_VARIANT_TYPE ("(a{sv})"),
-	                         G_CALLBACK (properties_changed), object);
+	g_signal_connect (proxy, "g-properties-changed",
+		          G_CALLBACK (properties_changed), object);
+	g_object_unref (proxy);
 
 	instance = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 	priv->property_tables = g_slist_prepend (priv->property_tables, instance);
@@ -1265,92 +950,6 @@ _nm_object_register_properties (NMObject *object,
 	}
 }
 
-static gboolean
-_nm_object_reload_properties (NMObject *object, GError **error)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	GVariant *ret, *props;
-	GHashTableIter iter;
-	const char *interface;
-	GDBusProxy *proxy;
-
-	if (!g_hash_table_size (priv->proxies) || !priv->nm_running)
-		return TRUE;
-
-	priv->reload_remaining++;
-
-	g_hash_table_iter_init (&iter, priv->proxies);
-	while (g_hash_table_iter_next (&iter, (gpointer *) &interface, (gpointer *) &proxy)) {
-		ret = _nm_dbus_proxy_call_sync (priv->properties_proxy,
-		                                "GetAll",
-		                                g_variant_new ("(s)", interface),
-		                                G_VARIANT_TYPE ("(a{sv})"),
-		                                G_DBUS_CALL_FLAGS_NONE, -1,
-		                                NULL, error);
-		if (!ret) {
-			if (error && *error)
-				g_dbus_error_strip_remote_error (*error);
-			return FALSE;
-		}
-
-		g_variant_get (ret, "(@a{sv})", &props);
-		process_properties_changed (object, props, TRUE);
-		g_variant_unref (props);
-		g_variant_unref (ret);
-	}
-
-	if (--priv->reload_remaining == 0)
-		reload_complete (object, TRUE);
-
-	return TRUE;
-}
-
-void
-_nm_object_suppress_property_updates (NMObject *object, gboolean suppress)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-
-	priv->suppress_property_updates = suppress;
-}
-
-
-void
-_nm_object_reload_property (NMObject *object,
-                            const char *interface,
-                            const char *prop_name)
-{
-	GVariant *ret, *value;
-	GError *err = NULL;
-
-	g_return_if_fail (NM_IS_OBJECT (object));
-	g_return_if_fail (interface != NULL);
-	g_return_if_fail (prop_name != NULL);
-
-	if (!NM_OBJECT_GET_PRIVATE (object)->nm_running)
-		return;
-
-	ret = _nm_dbus_proxy_call_sync (NM_OBJECT_GET_PRIVATE (object)->properties_proxy,
-	                                "Get",
-	                                g_variant_new ("(ss)", interface, prop_name),
-	                                G_VARIANT_TYPE ("(v)"),
-	                                G_DBUS_CALL_FLAGS_NONE, 15000,
-	                                NULL, &err);
-	if (!ret) {
-		dbgmsg ("%s: Error getting '%s' for %s: %s\n",
-		        __func__,
-		        prop_name,
-		        nm_object_get_path (object),
-		        err->message);
-		g_clear_error (&err);
-		return;
-	}
-
-	g_variant_get (ret, "(v)", &value);
-	handle_property_changed (object, prop_name, value, TRUE);
-	g_variant_unref (value);
-	g_variant_unref (ret);
-}
-
 void
 _nm_object_set_property (NMObject *object,
                          const char *interface,
@@ -1359,6 +958,7 @@ _nm_object_set_property (NMObject *object,
                          ...)
 {
 	GVariant *val, *ret;
+	GDBusProxy *proxy;
 	va_list ap;
 
 	g_return_if_fail (NM_IS_OBJECT (object));
@@ -1366,22 +966,21 @@ _nm_object_set_property (NMObject *object,
 	g_return_if_fail (prop_name != NULL);
 	g_return_if_fail (format_string != NULL);
 
-	if (!NM_OBJECT_GET_PRIVATE (object)->nm_running)
-		return;
-
 	va_start (ap, format_string);
 	val = g_variant_new_va (format_string, NULL, &ap);
 	va_end (ap);
 	g_return_if_fail (val != NULL);
 
-	ret = g_dbus_proxy_call_sync (NM_OBJECT_GET_PRIVATE (object)->properties_proxy,
-	                              "Set",
+	proxy = _nm_object_get_proxy (object, interface);
+	ret = g_dbus_proxy_call_sync (proxy,
+	                              DBUS_INTERFACE_PROPERTIES ".Set",
 	                              g_variant_new ("(ssv)", interface, prop_name, val),
 	                              G_DBUS_CALL_FLAGS_NONE, 2000,
 	                              NULL, NULL);
 	/* Ignore errors. */
 	if (ret)
 		g_variant_unref (ret);
+	g_object_unref (proxy);
 }
 
 static void
@@ -1418,139 +1017,40 @@ reload_complete (NMObject *object, gboolean emit_now)
 	g_clear_error (&error);
 }
 
-static void
-reload_got_properties (GObject *proxy,
-                       GAsyncResult *result,
-                       gpointer user_data)
+GDBusObjectManager *
+_nm_object_get_dbus_object_manager (NMObject *self)
 {
-	NMObject *object = user_data;
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	GVariant *ret, *props;
-	GError *error = NULL;
-
-	ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
-	                                  G_VARIANT_TYPE ("(a{sv})"),
-	                                  &error);
-	if (ret) {
-		g_variant_get (ret, "(@a{sv})", &props);
-		process_properties_changed (object, props, FALSE);
-		g_variant_unref (props);
-		g_variant_unref (ret);
-	} else {
-		g_dbus_error_strip_remote_error (error);
-		if (priv->reload_error)
-			g_error_free (error);
-		else
-			priv->reload_error = error;
-	}
-
-	if (--priv->reload_remaining == 0)
-		reload_complete (object, FALSE);
+	return NM_OBJECT_GET_PRIVATE (self)->object_manager;
 }
 
-void
-_nm_object_reload_properties_async (NMObject *object,
-                                    GCancellable *cancellable,
-                                    GAsyncReadyCallback callback,
-                                    gpointer user_data)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	GSimpleAsyncResult *simple;
-	GHashTableIter iter;
-	const char *interface;
-	GDBusProxy *proxy;
+/*****************************************************************************/
 
-	simple = g_simple_async_result_new (G_OBJECT (object), callback,
-	                                    user_data, _nm_object_reload_properties_async);
-
-	if (!g_hash_table_size (priv->proxies) || !priv->nm_running) {
-		g_simple_async_result_complete_in_idle (simple);
-		g_object_unref (simple);
-		return;
-	}
-
-	priv->reload_results = g_slist_prepend (priv->reload_results, simple);
-
-	/* If there was already a reload happening, we don't need to
-	 * re-read the properties again, we just need to wait for the
-	 * existing reload to finish.
-	 */
-	if (priv->reload_results->next)
-		return;
-
-	g_hash_table_iter_init (&iter, priv->proxies);
-	while (g_hash_table_iter_next (&iter, (gpointer *) &interface, (gpointer *) &proxy)) {
-		priv->reload_remaining++;
-		g_dbus_proxy_call (priv->properties_proxy,
-		                   "GetAll",
-		                   g_variant_new ("(s)", interface),
-		                   G_DBUS_CALL_FLAGS_NONE, -1,
-		                   cancellable,
-		                   reload_got_properties, object);
-	}
-}
-
-gboolean
-_nm_object_reload_properties_finish (NMObject *object, GAsyncResult *result, GError **error)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	GSimpleAsyncResult *simple;
-
-	g_return_val_if_fail (NM_IS_OBJECT (object), FALSE);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (object), _nm_object_reload_properties_async), FALSE);
-
-	/* NM might have disappeared meanwhile. That would cause a NoReply error to be emitted,
-	 * but we don't care if property updates were disabled. */
-	if (priv->suppress_property_updates)
-		return TRUE;
-
-	simple = G_SIMPLE_ASYNC_RESULT (result);
-	if (g_simple_async_result_propagate_error (simple, error))
-		return FALSE;
-
-	return g_simple_async_result_get_op_res_gboolean (simple);
-}
-
-gboolean
-_nm_object_get_nm_running (NMObject *self)
+static void
+init_dbus (NMObject *object)
 {
-	return NM_OBJECT_GET_PRIVATE (self)->nm_running;
 }
 
-/**************************************************************/
-
 static void
-on_name_owner_changed (GObject    *proxy,
-                       GParamSpec *pspec,
-                       gpointer    user_data)
+init_if (GDBusInterface *interface, gpointer user_data)
 {
 	NMObject *self = NM_OBJECT (user_data);
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
-	gboolean now_running;
-	char *owner;
-
-	now_running = ((owner = g_dbus_proxy_get_name_owner (priv->properties_proxy)) != NULL);
-	g_free (owner);
-	if (now_running != priv->nm_running) {
-		priv->nm_running = now_running;
-		g_object_notify (G_OBJECT (self), NM_OBJECT_NM_RUNNING);
+	GDBusProxy *proxy = G_DBUS_PROXY (interface);
+	gchar **props;
+	char **prop;
+	GVariant *val;
+	gchar *str;
+
+	props = g_dbus_proxy_get_cached_property_names (proxy);
+
+	for (prop = props; *prop; prop++) {
+		val = g_dbus_proxy_get_cached_property (proxy, *prop);
+		str = g_variant_print (val, TRUE);
+		handle_property_changed (self, *prop, val);
+		g_variant_unref (val);
+		g_free (str);
 	}
-}
 
-static void
-init_dbus (NMObject *object)
-{
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-	char *owner;
-
-	if (_nm_dbus_is_connection_private (priv->connection))
-		priv->nm_running = TRUE;
-	else {
-		priv->nm_running = ((owner = g_dbus_proxy_get_name_owner (priv->properties_proxy)) != NULL);
-		g_free (owner);
-		g_signal_connect (priv->properties_proxy, "notify::g-name-owner",
-		                  G_CALLBACK (on_name_owner_changed), object);
-	}
+	g_strfreev (props);
 }
 
 static gboolean
@@ -1558,45 +1058,36 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
 {
 	NMObject *self = NM_OBJECT (initable);
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
-	NMObjectClassPrivate *cpriv = NM_OBJECT_CLASS_GET_PRIVATE (NM_OBJECT_GET_CLASS (self));
-	GSList *iter;
+        GList *interfaces;
 
-	if (!priv->path) {
-		g_set_error_literal (error, NM_CLIENT_ERROR, NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
-		                     _("Caller did not specify D-Bus path for object"));
-		return FALSE;
-	}
+	g_assert (priv->object && priv->object_manager);
 
-	if (!priv->connection)
-		priv->connection = _nm_dbus_new_connection (cancellable, error);
-	if (!priv->connection)
-		return FALSE;
+	NM_OBJECT_GET_CLASS (self)->init_dbus (self);
 
-	/* Create proxies */
-	for (iter = cpriv->interfaces; iter; iter = iter->next) {
-		const char *interface = iter->data;
-		GDBusProxy *proxy;
+	priv->reload_remaining++;
 
-		proxy = _nm_dbus_new_proxy_for_connection (priv->connection, priv->path, interface,
-		                                           cancellable, error);
-		if (!proxy)
-			return FALSE;
-		g_hash_table_insert (priv->proxies, (char *) interface, proxy);
-	}
+	interfaces = g_dbus_object_get_interfaces (priv->object);
+	g_list_foreach (interfaces, (GFunc) init_if, self);
+	g_list_free_full (interfaces, g_object_unref);
 
-	priv->properties_proxy = _nm_dbus_new_proxy_for_connection (priv->connection,
-	                                                            priv->path,
-	                                                            DBUS_INTERFACE_PROPERTIES,
-	                                                            cancellable, error);
-	if (!priv->properties_proxy)
-		return FALSE;
+	priv->inited = TRUE;
 
-	NM_OBJECT_GET_CLASS (self)->init_dbus (self);
+	if (--priv->reload_remaining == 0)
+		reload_complete (self, TRUE);
+
+	/* There are some object properties whose creation couldn't proceed
+	 * because it depended on this object. */
+	while (priv->waiters) {
+		ObjectCreatedData *odata = priv->waiters->data;
+
+		priv->waiters = g_slist_remove (priv->waiters, odata);
+		object_property_maybe_complete (odata->self);
+	}
 
-	return _nm_object_reload_properties (self, error);
+	return TRUE;
 }
 
-/**************************************************************/
+/*****************************************************************************/
 
 typedef struct {
 	NMObject *object;
@@ -1613,88 +1104,13 @@ init_async_complete (NMObjectInitData *init_data)
 		g_simple_async_result_take_error (init_data->simple, init_data->error);
 	else
 		g_simple_async_result_set_op_res_gboolean (init_data->simple, TRUE);
-	g_simple_async_result_complete (init_data->simple);
+	g_simple_async_result_complete_in_idle (init_data->simple);
 	g_object_unref (init_data->simple);
 	g_clear_object (&init_data->cancellable);
 	g_slice_free (NMObjectInitData, init_data);
 }
 
 static void
-init_async_got_properties (GObject *object, GAsyncResult *result, gpointer user_data)
-{
-	NMObjectInitData *init_data = user_data;
-
-	_nm_object_reload_properties_finish (NM_OBJECT (object), result, &init_data->error);
-	init_async_complete (init_data);
-}
-
-static void
-init_async_got_proxy (GObject *object, GAsyncResult *result, gpointer user_data)
-{
-	NMObjectInitData *init_data = user_data;
-	NMObject *self = init_data->object;
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
-	GDBusProxy *proxy;
-
-	if (!init_data->error) {
-		proxy = _nm_dbus_new_proxy_for_connection_finish (result, &init_data->error);
-		if (proxy) {
-			const char *interface = g_dbus_proxy_get_interface_name (proxy);
-
-			if (!strcmp (interface, DBUS_INTERFACE_PROPERTIES))
-				priv->properties_proxy = proxy;
-			else
-				g_hash_table_insert (priv->proxies, (char *) interface, proxy);
-		}
-	}
-
-	init_data->proxies_pending--;
-	if (init_data->proxies_pending)
-		return;
-
-	if (init_data->error) {
-		init_async_complete (init_data);
-		return;
-	}
-
-	NM_OBJECT_GET_CLASS (self)->init_dbus (self);
-
-	_nm_object_reload_properties_async (init_data->object, init_data->cancellable, init_async_got_properties, init_data);
-}
-
-static void
-init_async_got_bus (GObject *object, GAsyncResult *result, gpointer user_data)
-{
-	NMObjectInitData *init_data = user_data;
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (init_data->object);
-	NMObjectClassPrivate *cpriv = NM_OBJECT_CLASS_GET_PRIVATE (NM_OBJECT_GET_CLASS (init_data->object));
-	GSList *iter;
-
-	priv->connection = _nm_dbus_new_connection_finish (result, &init_data->error);
-	if (!priv->connection) {
-		init_async_complete (init_data);
-		return;
-	}
-
-	for (iter = cpriv->interfaces; iter; iter = iter->next) {
-		const char *interface = iter->data;
-
-		_nm_dbus_new_proxy_for_connection_async (priv->connection,
-		                                         priv->path, interface,
-		                                         init_data->cancellable,
-		                                         init_async_got_proxy, init_data);
-		init_data->proxies_pending++;
-	}
-
-	_nm_dbus_new_proxy_for_connection_async (priv->connection,
-	                                         priv->path,
-	                                         DBUS_INTERFACE_PROPERTIES,
-	                                         init_data->cancellable,
-	                                         init_async_got_proxy, init_data);
-	init_data->proxies_pending++;
-}
-
-static void
 init_async (GAsyncInitable *initable, int io_priority,
             GCancellable *cancellable, GAsyncReadyCallback callback,
             gpointer user_data)
@@ -1702,29 +1118,40 @@ init_async (GAsyncInitable *initable, int io_priority,
 	NMObject *self = NM_OBJECT (initable);
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self);
 	NMObjectInitData *init_data;
+        GList *interfaces;
 
-	if (!priv->path) {
-		g_simple_async_report_error_in_idle (G_OBJECT (initable),
-		                                     callback, user_data,
-		                                     NM_CLIENT_ERROR,
-		                                     NM_CLIENT_ERROR_OBJECT_CREATION_FAILED,
-		                                     "%s",
-		                                     _("Caller did not specify D-Bus path for object"));
-		return;
-	}
+	g_assert (priv->object && priv->object_manager);
+
+	NM_OBJECT_GET_CLASS (self)->init_dbus (self);
 
 	init_data = g_slice_new0 (NMObjectInitData);
 	init_data->object = self;
 	init_data->simple = g_simple_async_result_new (G_OBJECT (initable), callback, user_data, init_async);
 	init_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
 
-	_nm_dbus_new_connection_async (cancellable, init_async_got_bus, init_data);
+	interfaces = g_dbus_object_get_interfaces (priv->object);
+	g_list_foreach (interfaces, (GFunc) init_if, self);
+	g_list_free_full (interfaces, g_object_unref);
+
+	init_async_complete (init_data);
 }
 
 static gboolean
 init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error)
 {
 	GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (initable);
+
+	priv->inited = TRUE;
+
+	/* There are some object properties whose creation couldn't proceed
+	 * because it depended on this object. */
+	while (priv->waiters) {
+		ObjectCreatedData *odata = priv->waiters->data;
+
+		priv->waiters = g_slist_remove (priv->waiters, odata);
+		object_property_maybe_complete (odata->self);
+	}
 
 	if (g_simple_async_result_propagate_error (simple, error))
 		return FALSE;
@@ -1732,7 +1159,7 @@ init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error)
 		return TRUE;
 }
 
-/**************************************************************/
+/*****************************************************************************/
 
 static void
 nm_object_initable_iface_init (GInitableIface *iface)
@@ -1750,9 +1177,6 @@ nm_object_async_initable_iface_init (GAsyncInitableIface *iface)
 static void
 nm_object_init (NMObject *object)
 {
-	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
-
-	priv->proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
 }
 
 static void
@@ -1762,13 +1186,13 @@ set_property (GObject *object, guint prop_id,
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
 
 	switch (prop_id) {
-	case PROP_PATH:
+	case PROP_DBUS_OBJECT:
 		/* Construct only */
-		priv->path = g_value_dup_string (value);
+		priv->object = g_value_dup_object (value);
 		break;
-	case PROP_DBUS_CONNECTION:
+	case PROP_DBUS_OBJECT_MANAGER:
 		/* Construct only */
-		priv->connection = g_value_dup_object (value);
+		priv->object_manager = g_value_dup_object (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1784,13 +1208,16 @@ get_property (GObject *object, guint prop_id,
 
 	switch (prop_id) {
 	case PROP_PATH:
-		g_value_set_string (value, priv->path);
+		g_value_set_string (value, nm_object_get_path (NM_OBJECT (object)));
 		break;
 	case PROP_DBUS_CONNECTION:
-		g_value_set_object (value, priv->connection);
+		g_value_set_object (value, g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager)));
+		break;
+	case PROP_DBUS_OBJECT:
+		g_value_set_object (value, priv->object);
 		break;
-	case PROP_NM_RUNNING:
-		g_value_set_boolean (value, priv->nm_running);
+	case PROP_DBUS_OBJECT_MANAGER:
+		g_value_set_object (value, priv->object_manager);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1809,10 +1236,9 @@ dispose (GObject *object)
 	priv->notify_items = NULL;
 
 	g_slist_free_full (priv->waiters, odata_free);
-	g_clear_pointer (&priv->proxies, g_hash_table_unref);
-	g_clear_object (&priv->properties_proxy);
 
-	g_clear_object (&priv->connection);
+	g_clear_object (&priv->object);
+	g_clear_object (&priv->object_manager);
 
 	G_OBJECT_CLASS (nm_object_parent_class)->dispose (object);
 }
@@ -1823,7 +1249,6 @@ finalize (GObject *object)
 	NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (object);
 
 	g_slist_free_full (priv->property_tables, (GDestroyNotify) g_hash_table_destroy);
-	g_free (priv->path);
 
 	G_OBJECT_CLASS (nm_object_parent_class)->finalize (object);
 }
@@ -1846,7 +1271,7 @@ nm_object_class_init (NMObjectClass *nm_object_class)
 	/* Properties */
 
 	/**
-	 * NMObject:path:
+	 * NMObject:path: (skip)
 	 *
 	 * The D-Bus object path.
 	 **/
@@ -1854,8 +1279,7 @@ nm_object_class_init (NMObjectClass *nm_object_class)
 		(object_class, PROP_PATH,
 		 g_param_spec_string (NM_OBJECT_PATH, "", "",
 		                      NULL,
-		                      G_PARAM_READWRITE |
-		                      G_PARAM_CONSTRUCT_ONLY |
+		                      G_PARAM_READABLE |
 		                      G_PARAM_STATIC_STRINGS));
 
 	/**
@@ -1867,20 +1291,32 @@ nm_object_class_init (NMObjectClass *nm_object_class)
 	    (object_class, PROP_DBUS_CONNECTION,
 	     g_param_spec_object (NM_OBJECT_DBUS_CONNECTION, "", "",
 	                          G_TYPE_DBUS_CONNECTION,
+	                          G_PARAM_READABLE |
+	                          G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * NMObject:dbus-object: (skip)
+	 *
+	 * The #GDBusObject of the object.
+	 **/
+	g_object_class_install_property
+	    (object_class, PROP_DBUS_OBJECT,
+	     g_param_spec_object (NM_OBJECT_DBUS_OBJECT, "", "",
+	                          G_TYPE_DBUS_OBJECT,
 	                          G_PARAM_READWRITE |
 	                          G_PARAM_CONSTRUCT_ONLY |
 	                          G_PARAM_STATIC_STRINGS));
 
 	/**
-	 * NMObject:manager-running: (skip)
+	 * NMObject:dbus-object-manager: (skip)
 	 *
-	 * Internal use only.
-	 */
+	 * The #GDBusObjectManager of the object.
+	 **/
 	g_object_class_install_property
-		(object_class, PROP_NM_RUNNING,
-		 g_param_spec_boolean (NM_OBJECT_NM_RUNNING, "", "",
-		                       FALSE,
-		                       G_PARAM_READABLE |
-		                       G_PARAM_STATIC_STRINGS));
+	    (object_class, PROP_DBUS_OBJECT_MANAGER,
+	     g_param_spec_object (NM_OBJECT_DBUS_OBJECT_MANAGER, "", "",
+	                          G_TYPE_DBUS_OBJECT_MANAGER,
+	                          G_PARAM_READWRITE |
+	                          G_PARAM_CONSTRUCT_ONLY |
+	                          G_PARAM_STATIC_STRINGS));
 }
-