diff options
Diffstat (limited to 'libnm-glib/nm-remote-settings.c')
| -rw-r--r-- | libnm-glib/nm-remote-settings.c | 138 |
1 files changed, 90 insertions, 48 deletions
diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c index 8f213f9e..19d865c0 100644 --- a/libnm-glib/nm-remote-settings.c +++ b/libnm-glib/nm-remote-settings.c @@ -61,8 +61,6 @@ typedef struct { DBusGProxy *dbus_proxy; guint fetch_id; - - gboolean disposed; } NMRemoteSettingsPrivate; enum { @@ -109,7 +107,7 @@ static void _nm_remote_settings_ensure_inited (NMRemoteSettings *self) { NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); - GError *error; + GError *error = NULL; if (!priv->inited) { if (!g_initable_init (G_INITABLE (self), NULL, &error)) { @@ -258,6 +256,43 @@ connection_removed_cb (NMRemoteConnection *remote, gpointer user_data) g_hash_table_remove (priv->pending, path); } +static void connection_visible_cb (NMRemoteConnection *remote, + gboolean visible, + gpointer user_data); + +/* Takes a reference to the connection when adding to 'to' */ +static void +move_connection (NMRemoteSettings *self, + NMRemoteConnection *remote, + GHashTable *from, + GHashTable *to) +{ + const char *path = nm_connection_get_path (NM_CONNECTION (remote)); + + g_hash_table_insert (to, g_strdup (path), g_object_ref (remote)); + if (from) + g_hash_table_remove (from, path); + + /* Setup connection signals since removing from 'from' clears them, but + * also the first time the connection is added to a hash if 'from' is NULL. + */ + if (!g_signal_handler_find (remote, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, connection_removed_cb, NULL)) { + g_signal_connect (remote, + NM_REMOTE_CONNECTION_REMOVED, + G_CALLBACK (connection_removed_cb), + self); + } + + if (!g_signal_handler_find (remote, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, connection_visible_cb, NULL)) { + g_signal_connect (remote, + "visible", + G_CALLBACK (connection_visible_cb), + self); + } +} + static void connection_visible_cb (NMRemoteConnection *remote, gboolean visible, @@ -278,16 +313,14 @@ connection_visible_cb (NMRemoteConnection *remote, /* Connection visible to this user again */ if (g_hash_table_lookup (priv->pending, path)) { /* Move connection from pending to visible hash; emit for clients */ - g_hash_table_insert (priv->connections, g_strdup (path), g_object_ref (remote)); - g_hash_table_remove (priv->pending, path); + move_connection (self, remote, priv->pending, priv->connections); g_signal_emit (self, signals[NEW_CONNECTION], 0, remote); } } else { /* Connection now invisible to this user */ if (g_hash_table_lookup (priv->connections, path)) { /* Move connection to pending hash and wait for it to become visible again */ - g_hash_table_insert (priv->pending, g_strdup (path), g_object_ref (remote)); - g_hash_table_remove (priv->connections, path); + move_connection (self, remote, priv->connections, priv->pending); /* Signal to clients that the connection is gone; but we have to * block our connection removed handler so we don't destroy @@ -308,17 +341,14 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data) NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); AddConnectionInfo *addinfo; const char *path; - GError *error = NULL; - gboolean remove_from_pending = TRUE; + GError *error = NULL, *local; path = nm_connection_get_path (NM_CONNECTION (remote)); addinfo = add_connection_info_find (self, remote); if (g_async_initable_init_finish (G_ASYNC_INITABLE (remote), result, &error)) { - /* 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)); + /* Connection is initialized and visible; expose it to clients */ + move_connection (self, remote, priv->pending, priv->connections); /* If there's a pending AddConnection request, complete that here before * signaling new-connection. @@ -331,23 +361,23 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data) */ g_signal_emit (self, signals[NEW_CONNECTION], 0, remote); } else { - if (dbus_g_error_has_name (error, "org.freedesktop.NetworkManager.Settings.PermissionDenied")) { - /* Connection doesn't exist, or isn't visible to this user */ - remove_from_pending = FALSE; - } - g_error_free (error); - if (addinfo) { - error = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR, + local = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR, NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE, "Connection not visible or not available"); - add_connection_info_complete (self, addinfo, error); - g_error_free (error); + add_connection_info_complete (self, addinfo, local); + g_error_free (local); } - } - if (remove_from_pending) - g_hash_table_remove (priv->pending, path); + /* PermissionDenied means the connection isn't visible to this user, so + * keep it in priv->pending to be notified later of visibility changes. + * Otherwise forget it. + */ + if (!dbus_g_error_has_name (error, "org.freedesktop.NetworkManager.Settings.PermissionDenied")) + g_hash_table_remove (priv->pending, path); + + g_error_free (error); + } /* Let listeners know that all connections have been found */ priv->init_left--; @@ -373,14 +403,6 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) /* Create a new connection object for it */ connection = nm_remote_connection_new (priv->bus, path); if (connection) { - g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED, - G_CALLBACK (connection_removed_cb), - self); - - g_signal_connect (connection, "visible", - G_CALLBACK (connection_visible_cb), - self); - g_async_initable_init_async (G_ASYNC_INITABLE (connection), G_PRIORITY_DEFAULT, NULL, connection_inited, self); @@ -389,7 +411,8 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) * 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); + move_connection (self, connection, NULL, priv->pending); + g_object_unref (connection); /* move_connection() takes a ref */ } return connection; } @@ -796,14 +819,25 @@ nm_remote_settings_new_finish (GAsyncResult *result, GError **error) return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)); } +static void +forget_connection (gpointer user_data) +{ + NMRemoteConnection *remote = NM_REMOTE_CONNECTION (user_data); + + g_signal_handlers_disconnect_matched (remote, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, connection_removed_cb, NULL); + g_signal_handlers_disconnect_matched (remote, G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, connection_visible_cb, NULL); + g_object_unref (remote); +} static void 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); + priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, forget_connection); + priv->pending = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, forget_connection); } static void @@ -1007,29 +1041,35 @@ dispose (GObject *object) NMRemoteSettings *self = NM_REMOTE_SETTINGS (object); NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); - if (priv->disposed) - return; - - priv->disposed = TRUE; - - if (priv->fetch_id) + if (priv->fetch_id) { g_source_remove (priv->fetch_id); + priv->fetch_id = 0; + } while (g_slist_length (priv->add_list)) add_connection_info_dispose (self, (AddConnectionInfo *) priv->add_list->data); - if (priv->connections) + if (priv->connections) { g_hash_table_destroy (priv->connections); + priv->connections = NULL; + } - if (priv->pending) + if (priv->pending) { g_hash_table_destroy (priv->pending); + priv->pending = NULL; + } g_free (priv->hostname); + priv->hostname = NULL; - g_object_unref (priv->dbus_proxy); - g_object_unref (priv->proxy); - g_object_unref (priv->props_proxy); - dbus_g_connection_unref (priv->bus); + g_clear_object (&priv->dbus_proxy); + g_clear_object (&priv->proxy); + g_clear_object (&priv->props_proxy); + + if (priv->bus) { + dbus_g_connection_unref (priv->bus); + priv->bus = NULL; + } G_OBJECT_CLASS (nm_remote_settings_parent_class)->dispose (object); } @@ -1061,6 +1101,8 @@ get_property (GObject *object, guint prop_id, { NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object); + _nm_remote_settings_ensure_inited (NM_REMOTE_SETTINGS (object)); + switch (prop_id) { case PROP_BUS: g_value_set_boxed (value, priv->bus); |