From cb0303180dfafa9f0cd41e0d7f1f5e4639bd30ed Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 11 Aug 2009 10:33:13 -0500 Subject: [PATCH] libnm-glib: don't expose NMRemoteConnetions until they are valid Give them time to get their settings from the remote settings service first, then let subclasses/users/whatever know about them. --- libnm-glib/Makefile.am | 1 + libnm-glib/nm-remote-connection.c | 24 +++++++++-- libnm-glib/nm-remote-settings.c | 71 +++++++++++++++++++++++++++++-- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am index 3e14bd750d..2b7dd016fc 100644 --- a/libnm-glib/Makefile.am +++ b/libnm-glib/Makefile.am @@ -84,6 +84,7 @@ libnm_glib_la_SOURCES = \ nm-active-connection.c \ nm-dhcp4-config.c \ nm-remote-connection.c \ + nm-remote-connection-private.h \ nm-settings-interface.c \ nm-settings-system-interface.c \ nm-remote-settings.c \ diff --git a/libnm-glib/nm-remote-connection.c b/libnm-glib/nm-remote-connection.c index 76fdcf0244..65edda1a01 100644 --- a/libnm-glib/nm-remote-connection.c +++ b/libnm-glib/nm-remote-connection.c @@ -27,6 +27,7 @@ #include #include #include "nm-remote-connection.h" +#include "nm-remote-connection-private.h" #include "nm-dbus-glib-types.h" #include "nm-exported-connection-bindings.h" #include "nm-settings-connection-interface.h" @@ -41,6 +42,7 @@ G_DEFINE_TYPE_EXTENDED (NMRemoteConnection, nm_remote_connection, NM_TYPE_CONNEC enum { PROP_0, PROP_BUS, + PROP_INIT_RESULT, LAST_PROP }; @@ -60,6 +62,7 @@ typedef struct { DBusGProxy *secrets_proxy; GSList *calls; + NMRemoteConnectionInitResult init_result; gboolean disposed; } NMRemoteConnectionPrivate; @@ -227,6 +230,7 @@ get_settings_cb (DBusGProxy *proxy, gpointer user_data) { NMRemoteConnection *self = user_data; + NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); if (error) { g_warning ("%s: error getting %s connection %s settings: (%d) %s", @@ -236,9 +240,13 @@ get_settings_cb (DBusGProxy *proxy, error ? error->code : -1, (error && error->message) ? error->message : "(unknown)"); g_error_free (error); + priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_ERROR; + g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_INIT_RESULT); } else { replace_settings (self, new_settings); g_hash_table_destroy (new_settings); + priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_SUCCESS; + g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_INIT_RESULT); } } @@ -365,8 +373,8 @@ get_property (GObject *object, guint prop_id, NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self); switch (prop_id) { - case PROP_BUS: - g_value_set_boxed (value, priv->bus); + case PROP_INIT_RESULT: + g_value_set_uint (value, priv->init_result); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -414,6 +422,16 @@ nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class) "DBusGConnection", "DBusGConnection", DBUS_TYPE_G_CONNECTION, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property + (object_class, PROP_INIT_RESULT, + g_param_spec_uint (NM_REMOTE_CONNECTION_INIT_RESULT, + "Initialization result (PRIVATE)", + "Initialization result (PRIVATE)", + NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN, + NM_REMOTE_CONNECTION_INIT_RESULT_ERROR, + NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN, + G_PARAM_READABLE)); } diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c index 6a261ace99..ea8fd2664a 100644 --- a/libnm-glib/nm-remote-settings.c +++ b/libnm-glib/nm-remote-settings.c @@ -29,6 +29,7 @@ #include "nm-remote-settings.h" #include "nm-settings-bindings.h" #include "nm-settings-interface.h" +#include "nm-remote-connection-private.h" static void settings_interface_init (NMSettingsInterface *class); @@ -43,6 +44,7 @@ typedef struct { DBusGProxy *proxy; GHashTable *connections; + GHashTable *pending; /* Connections we don't have settings for yet */ DBusGProxy *dbus_proxy; @@ -68,8 +70,58 @@ get_connection_by_path (NMSettingsInterface *settings, const char *path) static void connection_removed_cb (NMRemoteConnection *remote, gpointer user_data) { - g_hash_table_remove (NM_REMOTE_SETTINGS_GET_PRIVATE (user_data)->connections, - nm_connection_get_path (NM_CONNECTION (remote))); + NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + const char *path; + + path = nm_connection_get_path (NM_CONNECTION (remote)); + g_hash_table_remove (priv->connections, path); + g_hash_table_remove (priv->pending, path); +} + +static void +connection_init_result_cb (NMRemoteConnection *remote, + GParamSpec *pspec, + gpointer user_data) +{ + NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); + NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); + guint32 init_result = NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN; + const char *path; + + /* Disconnect from the init-result signal just to be safe */ + g_signal_handlers_disconnect_matched (remote, + G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, + 0, + 0, + NULL, + G_CALLBACK (connection_init_result_cb), + self); + + path = nm_connection_get_path (NM_CONNECTION (remote)); + + g_object_get (G_OBJECT (remote), + NM_REMOTE_CONNECTION_INIT_RESULT, &init_result, + NULL); + + switch (init_result) { + case NM_REMOTE_CONNECTION_INIT_RESULT_SUCCESS: + /* ref it when adding to ->connections, since removing it from ->pending + * will unref it. + */ + g_hash_table_insert (priv->connections, g_strdup (path), g_object_ref (remote)); + + /* Finally, let users know of the new connection now that it has all + * its settings and is valid. + */ + g_signal_emit_by_name (self, "new-connection", remote); + break; + case NM_REMOTE_CONNECTION_INIT_RESULT_ERROR: + default: + break; + } + + g_hash_table_remove (priv->pending, path); } static void @@ -85,8 +137,15 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) G_CALLBACK (connection_removed_cb), self); - g_hash_table_insert (priv->connections, g_strdup (path), connection); - g_signal_emit_by_name (self, "new-connection", connection); + g_signal_connect (connection, "notify::" NM_REMOTE_CONNECTION_INIT_RESULT, + G_CALLBACK (connection_init_result_cb), + self); + + /* Add the connection to the pending table to wait for it to retrieve + * it's settings asynchronously over D-Bus. The connection isn't + * really valid until it has all its settings, so hide it until it does. + */ + g_hash_table_insert (priv->pending, g_strdup (path), connection); } } @@ -269,6 +328,7 @@ nm_remote_settings_init (NMRemoteSettings *self) NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->pending = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } static GObject * @@ -344,6 +404,9 @@ dispose (GObject *object) if (priv->connections) g_hash_table_destroy (priv->connections); + if (priv->pending) + g_hash_table_destroy (priv->pending); + g_object_unref (priv->dbus_proxy); g_object_unref (priv->proxy); dbus_g_connection_unref (priv->bus);