diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2016-10-18 16:35:07 +0200 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2016-11-10 16:48:48 +0100 |
commit | 1f5b48a59eb46c40cb10bf4381b2b21a19a9f471 (patch) | |
tree | ff92cacbfccf0c1b1bb09ee397c515bcd6b90b5e /libnm/nm-object.c | |
parent | ff3eb24c15154d2fa7aec9cb1882c63e83a65e70 (diff) | |
download | NetworkManager-lr/object-manager.tar.gz |
libnm: use the o.fd.DBus.ObjectManager API for object managementlr/object-manager
This speeds up the initial object tree load significantly. Also, it
reduces the object management complexity by shifting the duties to
GDBusObjectManager.
The lifetime of all NMObjects is now managed by the NMClient via the
object manager. The NMClient creates the NMObjects for GDBus objects,
triggers the initialization and serves as an object registry (replaces
the nm-cache).
The ObjectManager uses the o.fd.DBus.ObjectManager API to learn of the
object creation, removal and property changes. It takes care of the
property changes so that we don't have to and lets us always see a
consistent object state. Thus at the time we learn of a new object we
already know its properties.
The NMObject unfortunately can't be made synchronously initializable as
the NMRemoteConnection's settings are not managed with standard
o.fd.DBus Properties and ObjectManager APIs and thus are not known to
the ObjectManager. Thus most of the asynchronous object property
changing code in nm-object.c is preserved. The objects notify the
properties that reference them of their initialization in from their
init_finish() methods, thus the asynchronously created objects are not
allowed to fail creation (or the dependees would wait forever). Not a
problem -- if a connection can't get its Settings, it's either invisible
or being removed (presumably we'd learn of the removal from the object
manager soon).
The NMObjects can't be created by the object manager itself, since we
can't determine the resulting object type in proxy_type() yet (we can't
tell from the name and can't access the interface list). Therefore the
GDBusObject is coupled with a NMObject later on.
Lastly, now that all the objects are managed by the object manager, the
NMRemoteSettings and NMManager go away when the daemon is stopped. The
complexity of dealing with calls to NMClient that would require any of
the resources that these objects manage (connection or device lists,
etc.) had to be moved to NMClient. The bright side is that his allows
for removal all of the daemon presence tracking from NMObject.
Diffstat (limited to 'libnm/nm-object.c')
-rw-r--r-- | libnm/nm-object.c | 865 |
1 files changed, 150 insertions, 715 deletions
diff --git a/libnm/nm-object.c b/libnm/nm-object.c index aa1c177b2f..abade94b8d 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; @@ -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,28 @@ 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)) { + gs_unref_object GDBusObject *object = NULL; + if (!strcmp (path, "/")) { /* FIXME: can't happen? */ continue; } - 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_created (obj, path, odata); - } else { - _nm_object_create_async (pi->object_type, priv->connection, path, - object_created, odata); + object = g_dbus_object_manager_get_object (priv->object_manager, path); + if (!object) { + g_warning ("no object known for %s\n", path); + return FALSE; } - } - if (!synchronously) { - /* Assume success */ - return TRUE; + obj = g_object_get_qdata (G_OBJECT (object), _nm_object_obj_nm_quark ()); + object_created (obj, path, odata); } - 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 +712,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 +734,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 +929,8 @@ _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); 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 +952,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, @@ -1366,16 +967,13 @@ _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", + ret = g_dbus_proxy_call_sync (_nm_object_get_proxy (object, interface), + DBUS_INTERFACE_PROPERTIES ".Set", g_variant_new ("(ssv)", interface, prop_name, val), G_DBUS_CALL_FLAGS_NONE, 2000, NULL, NULL); @@ -1418,139 +1016,40 @@ reload_complete (NMObject *object, gboolean emit_now) g_clear_error (&error); } -static void -reload_got_properties (GObject *proxy, - GAsyncResult *result, - gpointer user_data) -{ - 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); -} - -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) +GDBusObjectManager * +_nm_object_get_dbus_object_manager (NMObject *self) { - return NM_OBJECT_GET_PRIVATE (self)->nm_running; + return NM_OBJECT_GET_PRIVATE (self)->object_manager; } /*****************************************************************************/ static void -on_name_owner_changed (GObject *proxy, - GParamSpec *pspec, - gpointer user_data) +init_dbus (NMObject *object) { - 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); - } } static void -init_dbus (NMObject *object) +init_if (GDBusInterface *interface, gpointer user_data) { - 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); + NMObject *self = NM_OBJECT (user_data); + 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); } + + g_strfreev (props); } static gboolean @@ -1558,42 +1057,33 @@ 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; - return _nm_object_reload_properties (self, error); + priv->waiters = g_slist_remove (priv->waiters, odata); + object_property_maybe_complete (odata->self); + } + + return TRUE; } /*****************************************************************************/ @@ -1613,88 +1103,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 +1117,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; @@ -1750,9 +1176,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 +1185,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 +1207,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_NM_RUNNING: - g_value_set_boolean (value, priv->nm_running); + case PROP_DBUS_OBJECT: + g_value_set_object (value, priv->object); + break; + 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 +1235,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 +1248,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 +1270,7 @@ nm_object_class_init (NMObjectClass *nm_object_class) /* Properties */ /** - * NMObject:path: + * NMObject:path: (skip) * * The D-Bus object path. **/ @@ -1854,8 +1278,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 +1290,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)); } - |