diff options
author | Thomas Haller <thaller@redhat.com> | 2017-05-11 12:04:24 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-05-11 12:45:12 +0200 |
commit | 06f80388c375be63ac1048667d1ceb980d92f5af (patch) | |
tree | 60670a125c55c7dbb1afb87fff80a4f220afdb79 | |
parent | a80f31fd57852fc1ebca520c2e1583e6e8120c40 (diff) | |
download | NetworkManager-th/c-list.tar.gz |
proxy: use CList to track configs in NMPacrunnnerManagerth/c-list
- config->removed can be replaced by c_list_is_empty(&config->lst)
- downgrade some assertions to nm_assert(). Even without the
assert we crash a few lines later with a NULL pointer access.
That gives almost the same debuggability and discoverability
of the bug.
- use exected type signature for GAsyncReadyCallback and avoid
the cast.
- when the name owner disappears, cancel all asynchronous
operations. Note how the new pacrunner instance will anyway
start without configuration, so for all purpose, all pending
operations are at that moment obsolete.
-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); } |