diff options
-rw-r--r-- | src/nm-pacrunner-manager.c | 168 |
1 files changed, 95 insertions, 73 deletions
diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index 87e0a36437..31f83256f3 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -27,8 +27,7 @@ #include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" - -static void pacrunner_remove_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data); +#include "nm-utils/c-list.h" #define PACRUNNER_DBUS_SERVICE "org.pacrunner" #define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager" @@ -37,11 +36,15 @@ static void pacrunner_remove_done (GDBusProxy *proxy, GAsyncResult *res, gpointe /*****************************************************************************/ struct _NMPacrunnerCallId { - NMPacrunnerManager *manager; + CList lst; + + /* this might be a dangling pointer after the async operation + * is cancelled. */ + NMPacrunnerManager *manager_maybe_dangling; + GVariant *args; char *path; guint refcount; - bool removed; }; typedef struct _NMPacrunnerCallId Config; @@ -49,8 +52,8 @@ typedef struct _NMPacrunnerCallId Config; typedef struct { char *iface; GDBusProxy *pacrunner; - GCancellable *pacrunner_cancellable; - GList *configs; + GCancellable *cancellable; + CList configs; } NMPacrunnerManagerPrivate; struct _NMPacrunnerManager { @@ -80,49 +83,59 @@ NM_DEFINE_SINGLETON_GETTER (NMPacrunnerManager, nm_pacrunner_manager_get, NM_TYP G_STMT_START { \ nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ "%s%p]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - "pacrunner: call[", \ + _NMLOG2_PREFIX_NAME": call[", \ (config) \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } G_STMT_END /*****************************************************************************/ +static void pacrunner_remove_done (GObject *source, GAsyncResult *res, gpointer user_data); + +/*****************************************************************************/ + static Config * config_new (NMPacrunnerManager *manager, GVariant *args) { Config *config; config = g_slice_new0 (Config); - config->manager = manager; + config->manager_maybe_dangling = manager; config->args = g_variant_ref_sink (args); config->refcount = 1; + c_list_link_tail (&NM_PACRUNNER_MANAGER_GET_PRIVATE (manager)->configs, + &config->lst); return config; } -static void +static Config * config_ref (Config *config) { - g_assert (config); - g_assert (config->refcount > 0); + nm_assert (config); + nm_assert (config->refcount > 0); config->refcount++; + return config; } static void config_unref (Config *config) { - g_assert (config); - g_assert (config->refcount > 0); + nm_assert (config); + nm_assert (config->refcount > 0); if (config->refcount == 1) { g_variant_unref (config->args); g_free (config->path); + c_list_unlink (&config->lst); g_slice_free (Config, config); } else config->refcount--; } +/*****************************************************************************/ + static void add_proxy_config (GVariantBuilder *proxy_data, const NMProxyConfig *proxy_config) { @@ -220,8 +233,18 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) } } +/*****************************************************************************/ + +static GCancellable * +_ensure_cancellable (NMPacrunnerManagerPrivate *priv) +{ + if (G_UNLIKELY (!priv->cancellable)) + priv->cancellable = g_cancellable_new (); + return priv->cancellable; +} + static void -pacrunner_send_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) +pacrunner_send_done (GObject *source, GAsyncResult *res, gpointer user_data) { Config *config = user_data; NMPacrunnerManager *self; @@ -230,15 +253,13 @@ pacrunner_send_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) gs_unref_variant GVariant *variant = NULL; const char *path = NULL; - g_return_if_fail (!config->path); + nm_assert (!config->path); - variant = g_dbus_proxy_call_finish (proxy, res, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - config_unref (config); - return; - } + variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto out; - self = NM_PACRUNNER_MANAGER (config->manager); + self = NM_PACRUNNER_MANAGER (config->manager_maybe_dangling); priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); if (!variant) @@ -246,21 +267,23 @@ pacrunner_send_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) else { g_variant_get (variant, "(&o)", &path); - config->path = g_strdup (path); - _LOG2D (config, "sent"); - - if (config->removed) { - config_ref (config); + if (c_list_is_empty (&config->lst)) { + _LOG2D (config, "sent (%s), but destory it right away", path); g_dbus_proxy_call (priv->pacrunner, "DestroyProxyConfiguration", - g_variant_new ("(o)", config->path), + g_variant_new ("(o)", path), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, - priv->pacrunner_cancellable, - (GAsyncReadyCallback) pacrunner_remove_done, - config); + _ensure_cancellable (priv), + pacrunner_remove_done, + config_ref (config)); + } else { + _LOG2D (config, "sent (%s)", path); + config->path = g_strdup (path); } } + +out: config_unref (config); } @@ -272,17 +295,15 @@ pacrunner_send_config (NMPacrunnerManager *self, Config *config) if (priv->pacrunner) { _LOG2T (config, "sending..."); - config_ref (config); - g_clear_pointer (&config->path, g_free); - + nm_assert (!config->path); g_dbus_proxy_call (priv->pacrunner, "CreateProxyConfiguration", config->args, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, - priv->pacrunner_cancellable, - (GAsyncReadyCallback) pacrunner_send_done, - config); + _ensure_cancellable (priv), + pacrunner_send_done, + config_ref (config)); } } @@ -291,15 +312,18 @@ name_owner_changed (NMPacrunnerManager *self) { NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); gs_free char *owner = NULL; - GList *iter = NULL; + CList *iter; owner = g_dbus_proxy_get_name_owner (priv->pacrunner); if (owner) { _LOGD ("name owner appeared (%s)", owner); - for (iter = g_list_first (priv->configs); iter; iter = g_list_next (iter)) - pacrunner_send_config (self, iter->data); + c_list_for_each (iter, &priv->configs) + pacrunner_send_config (self, c_list_entry (iter, Config, lst)); } else { _LOGD ("name owner disappeared"); + nm_clear_g_cancellable (&priv->cancellable); + c_list_for_each (iter, &priv->configs) + nm_clear_g_free (&c_list_entry (iter, Config, lst)->path); } } @@ -316,21 +340,19 @@ pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NMPacrunnerManager *self = user_data; NMPacrunnerManagerPrivate *priv; - GError *error = NULL; + gs_free_error GError *error = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (!proxy) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - _LOGW ("failed to connect to pacrunner via DBus: %s", error->message); - g_error_free (error); + _LOGE ("failed to create D-Bus proxy for pacrunner: %s", error->message); return; } priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); priv->pacrunner = proxy; - g_signal_connect (priv->pacrunner, "notify::g-name-owner", G_CALLBACK (name_owner_changed_cb), self); name_owner_changed (self); @@ -420,7 +442,6 @@ nm_pacrunner_manager_send (NMPacrunnerManager *self, } config = config_new (self, g_variant_new ("(a{sv})", &proxy_data)); - priv->configs = g_list_append (priv->configs, config); { gs_free char *args_str = NULL; @@ -439,26 +460,24 @@ nm_pacrunner_manager_send (NMPacrunnerManager *self, } static void -pacrunner_remove_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) +pacrunner_remove_done (GObject *source, GAsyncResult *res, gpointer user_data) { Config *config = user_data; NMPacrunnerManager *self; gs_free_error GError *error = NULL; gs_unref_variant GVariant *ret = NULL; - ret = g_dbus_proxy_call_finish (proxy, res, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - config_unref (config); - return; - } - - self = NM_PACRUNNER_MANAGER (config->manager); + ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto out; + self = NM_PACRUNNER_MANAGER (config->manager_maybe_dangling); if (!ret) _LOG2D (config, "remove failed: %s", error->message); else _LOG2D (config, "removed"); +out: config_unref (config); } @@ -472,7 +491,6 @@ nm_pacrunner_manager_remove (NMPacrunnerManager *self, NMPacrunnerCallId *call_i { NMPacrunnerManagerPrivate *priv; Config *config; - GList *list; g_return_if_fail (NM_IS_PACRUNNER_MANAGER (self)); g_return_if_fail (call_id); @@ -482,31 +500,28 @@ nm_pacrunner_manager_remove (NMPacrunnerManager *self, NMPacrunnerCallId *call_i _LOG2T (config, "removing..."); - list = g_list_find (priv->configs, config); - if (!list) - g_return_if_reached (); + nm_assert (c_list_contains (&priv->configs, &config->lst)); if (priv->pacrunner) { if (!config->path) { - /* send() failed or is still pending. Mark the item as + /* send() failed or is still pending. The item is marked as * removed, so that we ask pacrunner to drop it when the * send() completes. */ - config->removed = TRUE; - config_unref (config); } else { g_dbus_proxy_call (priv->pacrunner, "DestroyProxyConfiguration", g_variant_new ("(o)", config->path), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, - priv->pacrunner_cancellable, - (GAsyncReadyCallback) pacrunner_remove_done, - config); + _ensure_cancellable (priv), + pacrunner_remove_done, + config_ref (config)); } - } else - config_unref (config); - priv->configs = g_list_delete_link (priv->configs, list); + } + + c_list_unlink_init (&config->lst); + config_unref (config); } gboolean @@ -532,16 +547,15 @@ nm_pacrunner_manager_init (NMPacrunnerManager *self) { NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - priv->pacrunner_cancellable = g_cancellable_new (); - + c_list_init (&priv->configs); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, PACRUNNER_DBUS_SERVICE, PACRUNNER_DBUS_PATH, PACRUNNER_DBUS_INTERFACE, - priv->pacrunner_cancellable, - (GAsyncReadyCallback) pacrunner_proxy_cb, + _ensure_cancellable (priv), + pacrunner_proxy_cb, self); } @@ -549,14 +563,22 @@ static void dispose (GObject *object) { NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE ((NMPacrunnerManager *) object); + CList *iter, *safe; + + c_list_for_each_safe (iter, safe, &priv->configs) { + c_list_unlink_init (iter); + config_unref (c_list_entry (iter, Config, lst)); + } + + /* we cancel all pending operations. Note that pacrunner automatically + * removes all configuration once NetworkManager disconnects from + * the bus -- which happens soon after we destroy the pacrunner manager. + */ + nm_clear_g_cancellable (&priv->cancellable); g_clear_pointer (&priv->iface, g_free); - nm_clear_g_cancellable (&priv->pacrunner_cancellable); g_clear_object (&priv->pacrunner); - g_list_free_full (priv->configs, (GDestroyNotify) config_unref); - priv->configs = NULL; - G_OBJECT_CLASS (nm_pacrunner_manager_parent_class)->dispose (object); } |