From cfced599cab19bb929494f6f38712e3b08ce3d55 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 5 Dec 2017 13:55:25 +0100 Subject: [PATCH] settings: delete volatile connection and support setting the volatile flag Previously, we would only set a connection as volatile before adding it to manager. As we never would set it volatile last on, there was no need to handle deletion. Now support that. Watch the volatile flag, and if the connection has currently not active connection that keeps it alive, delete it in an idle handler. --- src/nm-manager.c | 125 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 15 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 941738939b..04d17f9b23 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -177,6 +177,9 @@ typedef struct { bool sleeping:1; bool net_enabled:1; + + guint delete_volatile_connection_idle_id; + CList delete_volatile_connection_lst_head; } NMManagerPrivate; struct _NMManager { @@ -309,6 +312,11 @@ static void active_connection_parent_active (NMActiveConnection *active, NMActiveConnection *parent_ac, NMManager *self); +static NMActiveConnection *active_connection_find_first (NMManager *self, + NMSettingsConnection *settings_connection, + const char *uuid, + NMActiveConnectionState max_state); + /*****************************************************************************/ static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark) @@ -317,12 +325,34 @@ static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark) /*****************************************************************************/ +static void +_delete_volatile_connection_do (NMManager *self, + NMSettingsConnection *connection) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) + return; + if (active_connection_find_first (self, + connection, + NULL, + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) + return; + if (!nm_settings_has_connection (priv->settings, connection)) + return; + + _LOGD (LOGD_DEVICE, "volatile connection disconnected. Deleting connection '%s' (%s)", + nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); + nm_settings_connection_delete (connection, NULL); +} + /* Returns: whether to notify D-Bus of the removal or not */ static gboolean active_connection_remove (NMManager *self, NMActiveConnection *active) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingsConnection *connection; + gs_unref_object NMSettingsConnection *connection = NULL; gboolean notify; nm_assert (NM_IS_ACTIVE_CONNECTION (active)); @@ -336,23 +366,12 @@ active_connection_remove (NMManager *self, NMActiveConnection *active) g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self); g_signal_handlers_disconnect_by_func (active, active_connection_parent_active, self); - if ( (connection = nm_active_connection_get_settings_connection (active)) - && NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), - NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) - g_object_ref (connection); - else - connection = NULL; + connection = nm_g_object_ref (nm_active_connection_get_settings_connection (active)); nm_exported_object_clear_and_unexport (&active); - if (connection) { - if (nm_settings_has_connection (priv->settings, connection)) { - _LOGD (LOGD_DEVICE, "assumed connection disconnected. Deleting generated connection '%s' (%s)", - nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); - nm_settings_connection_delete (connection, NULL); - } - g_object_unref (connection); - } + if (connection) + _delete_volatile_connection_do (self, connection); return notify; } @@ -1483,6 +1502,74 @@ connection_updated_cb (NMSettings *settings, connection_changed (self, connection); } +/*****************************************************************************/ + +typedef struct { + CList delete_volatile_connection_lst; + NMSettingsConnection *connection; +} DeleteVolatileConnectionData; + +static void +_delete_volatile_connection_all (NMManager *self, gboolean do_delete) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + CList *lst; + DeleteVolatileConnectionData *data; + + while ((lst = c_list_first (&priv->delete_volatile_connection_lst_head))) { + gs_unref_object NMSettingsConnection *connection = NULL; + + data = c_list_entry (lst, + DeleteVolatileConnectionData, + delete_volatile_connection_lst); + connection = data->connection; + c_list_unlink_stale (&data->delete_volatile_connection_lst); + g_slice_free (DeleteVolatileConnectionData, data); + + if (do_delete) + _delete_volatile_connection_do (self, connection); + } +} + +static gboolean +_delete_volatile_connection_cb (gpointer user_data) +{ + NMManager *self = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + priv->delete_volatile_connection_idle_id = 0; + _delete_volatile_connection_all (self, TRUE); + return G_SOURCE_REMOVE; +} + +static void +connection_flags_changed (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) +{ + NMManager *self = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + DeleteVolatileConnectionData *data; + + if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) + return; + + if (active_connection_find_first (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) { + /* the connection still have an active-connection. It will be purged + * when the active connection(s) get(s) removed. */ + return; + } + + data = g_slice_new (DeleteVolatileConnectionData); + data->connection = g_object_ref (connection); + c_list_link_tail (&priv->delete_volatile_connection_lst_head, &data->delete_volatile_connection_lst); + if (!priv->delete_volatile_connection_idle_id) + priv->delete_volatile_connection_idle_id = g_idle_add (_delete_volatile_connection_cb, self); +} + +/*****************************************************************************/ + static void system_unmanaged_devices_changed_cb (NMSettings *settings, GParamSpec *pspec, @@ -6102,6 +6189,7 @@ constructed (GObject *object) G_CALLBACK (connection_added_cb), self); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, G_CALLBACK (connection_updated_cb), self); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, G_CALLBACK (connection_flags_changed), self); priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); g_signal_connect (priv->hostname_manager, "notify::" NM_HOSTNAME_MANAGER_HOSTNAME, @@ -6160,6 +6248,7 @@ nm_manager_init (NMManager *self) c_list_init (&priv->link_cb_lst); c_list_init (&priv->active_connections_lst_head); + c_list_init (&priv->delete_volatile_connection_lst_head); priv->platform = g_object_ref (NM_PLATFORM_GET); @@ -6420,6 +6509,11 @@ dispose (GObject *object) CList *iter, *iter_safe; NMActiveConnection *ac, *ac_safe; + nm_clear_g_source (&priv->delete_volatile_connection_idle_id); + _delete_volatile_connection_all (self, FALSE); + nm_assert (!priv->delete_volatile_connection_idle_id); + nm_assert (c_list_is_empty (&priv->delete_volatile_connection_lst_head)); + g_signal_handlers_disconnect_by_func (priv->platform, G_CALLBACK (platform_link_cb), self); @@ -6474,6 +6568,7 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (priv->settings, system_unmanaged_devices_changed_cb, self); g_signal_handlers_disconnect_by_func (priv->settings, connection_added_cb, self); g_signal_handlers_disconnect_by_func (priv->settings, connection_updated_cb, self); + g_signal_handlers_disconnect_by_func (priv->settings, connection_flags_changed, self); g_clear_object (&priv->settings); }