From 1043189ef6bd12475304bbe87f4f8daaf67402ec Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 31 Jan 2020 00:54:46 +0100 Subject: [PATCH 2/2] libnm: hide NMActiveConnection until NMRemoteConnection is ready Generally, libnm's NMClient cache only wants to expose NMObjects that are fully initalized. Most objects don't require anything special, except NMRemoteConnection waits for the GetSettings() call to complete. NMObjects reference each other. For example, NMActiveConnection references NMDevice and NMRemoteConnection. There is a desire that an object is only ready, if the objects that it references are ready too. In practice that is not done, because usually every objects references other objects, that means all objects would be declared as non-ready until they are all ready at the same time. Only NMRemoteConnection implements is_ready() function. All other objects are declared ready as they appear. This is also done this way, to cope with cycles where objects reference each other. In practice, such cycles should not be exposed by NetworkManager. However, libnm should be robust against that. This has the undesired effect that when you call AddAndActivate(), then the NMActiveConnection might already be ready while its NMRemoteConnection isn't. That means, ac.get_connection() will initially return NULL, until the remote connection becomes ready. Also add a special handling that NMActiveConnection waits for their NMRemoteConnection to be ready, before being ready itself. --- libnm/nm-active-connection.c | 29 +++++++++++++++++++++++++++++ libnm/nm-client.c | 8 ++++++++ libnm/nm-libnm-utils.h | 2 ++ 3 files changed, 39 insertions(+) diff --git a/libnm/nm-active-connection.c b/libnm/nm-active-connection.c index aa8504e61d..ade2edbe73 100644 --- a/libnm/nm-active-connection.c +++ b/libnm/nm-active-connection.c @@ -425,6 +425,33 @@ _nm_active_connection_state_changed_commit (NMActiveConnection *self, _notify_event_state_changed, g_object_ref (self)); } +/*****************************************************************************/ + +static gboolean +is_ready (NMObject *nmobj) +{ + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (nmobj); + + /* Usually, we don't want to expose our NMObject instances until they are fully initialized. + * For NMRemoteSetting this means to wait until GetSettings() returns. + * + * Note that most object types reference each other (directly or indirectly). E.g. the + * NMActiveConnection refers to the NMRemoteConnection and the NMDevice instance. So, + * we don't want to hide them too long, otherwise basically the entire set of objects + * will be hidden until they are all initialized. So, usually, when a NMObject references + * objects that are not yet initialized, that reference will just be NULL but the object + * will be considered ready already. + * + * For NMActiveConnection referencing a NMRemoteConnection don't do that. Here we wait for the + * NMRemoteConnection to be ready as well. This is somewhat arbitrary special casing, but + * the effect is that when nm_client_add_and_activate*() returns, the NMActiveConnection already + * references a initialized NMRemoteConnection. + */ + if (!nml_dbus_property_o_is_ready_fully (&priv->property_o[PROPERTY_O_IDX_CONNECTION])) + return FALSE; + + return NM_OBJECT_CLASS (nm_active_connection_parent_class)->is_ready (nmobj); +} /*****************************************************************************/ @@ -550,6 +577,8 @@ nm_active_connection_class_init (NMActiveConnectionClass *klass) object_class->get_property = get_property; object_class->finalize = finalize; + nm_object_class->is_ready = is_ready; + _NM_OBJECT_CLASS_INIT_PRIV_PTR_INDIRECT (nm_object_class, NMActiveConnection); _NM_OBJECT_CLASS_INIT_PROPERTY_O_FIELDS_N (nm_object_class, NMActiveConnectionPrivate, property_o); diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 154ad1c992..a93a81c353 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -1594,6 +1594,14 @@ nml_dbus_property_o_is_ready (const NMLDBusPropertyO *pr_o) || !pr_o->owner_dbobj; } +gboolean +nml_dbus_property_o_is_ready_fully (const NMLDBusPropertyO *pr_o) +{ + return !pr_o->owner_dbobj + || !pr_o->obj_watcher + || pr_o->nmobj; +} + static void nml_dbus_property_o_notify_changed (NMLDBusPropertyO *pr_o, NMClient *self) diff --git a/libnm/nm-libnm-utils.h b/libnm/nm-libnm-utils.h index f2affc5f62..28c9c1164c 100644 --- a/libnm/nm-libnm-utils.h +++ b/libnm/nm-libnm-utils.h @@ -260,6 +260,8 @@ gpointer nml_dbus_property_o_get_obj (NMLDBusPropertyO *pr_o); gboolean nml_dbus_property_o_is_ready (const NMLDBusPropertyO *pr_o); +gboolean nml_dbus_property_o_is_ready_fully (const NMLDBusPropertyO *pr_o); + void nml_dbus_property_o_clear (NMLDBusPropertyO *pr_o, NMClient *client); -- 2.24.1