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 which 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
as long as any of them is still initializing. That does not seem
desirable. Instead, most objects (except NMRemoteConnection and now
NMActiveConnection) are considered ready and visible, once their first
notification completes. In case the objects reference any object that is
not yet ready, the references is NULL (but the source object is visible
already). 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 visible 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.

Fixes: ce0e898fb4 ('libnm: refactor caching of D-Bus objects in NMClient')
This commit is contained in:
Thomas Haller 2020-01-31 00:54:46 +01:00
parent 6b745e0725
commit 425412a363
3 changed files with 39 additions and 0 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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);