diff options
| author | Michael Biebl <biebl@debian.org> | 2019-07-31 10:51:42 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2019-07-31 10:51:42 +0200 |
| commit | 2e5fa45ddfbb5cffa1e78221f1cea706e2f298af (patch) | |
| tree | 86f69d36c56de3074280456eddc854a780b8e04b /src/nm-pacrunner-manager.c | |
| parent | 85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (diff) | |
New upstream version 1.19.90 upstream/1.19.90
Diffstat (limited to 'src/nm-pacrunner-manager.c')
| -rw-r--r-- | src/nm-pacrunner-manager.c | 779 |
1 files changed, 417 insertions, 362 deletions
diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index b9881f76..38b53eab 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager * * This program is free software; you can redistribute it and/or modify @@ -23,11 +22,14 @@ #include "nm-pacrunner-manager.h" #include "nm-utils.h" +#include "NetworkManagerUtils.h" #include "platform/nm-platform.h" +#include "nm-dbus-manager.h" #include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "c-list/src/c-list.h" +#include "nm-glib-aux/nm-dbus-aux.h" #define PACRUNNER_DBUS_SERVICE "org.pacrunner" #define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager" @@ -35,25 +37,27 @@ /*****************************************************************************/ -struct _NMPacrunnerCallId { - CList lst; +struct _NMPacrunnerConfId { + CList conf_id_lst; - /* this might be a dangling pointer after the async operation - * is cancelled. */ - NMPacrunnerManager *manager_maybe_dangling; + NMPacrunnerManager *self; + + GVariant *parameters; - GVariant *args; char *path; + guint64 log_id; guint refcount; }; -typedef struct _NMPacrunnerCallId Config; - typedef struct { - char *iface; - GDBusProxy *pacrunner; + GDBusConnection *dbus_connection; GCancellable *cancellable; - CList configs; + CList conf_id_lst_head; + guint64 log_id_counter; + guint name_owner_changed_id; + bool dbus_initied:1; + bool has_name_owner:1; + bool try_start_blocked:1; } NMPacrunnerManagerPrivate; struct _NMPacrunnerManager { @@ -79,469 +83,511 @@ NM_DEFINE_SINGLETON_GETTER (NMPacrunnerManager, nm_pacrunner_manager_get, NM_TYP #define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "pacrunner", __VA_ARGS__) #define _NMLOG2_PREFIX_NAME "pacrunner" -#define _NMLOG2(level, config, ...) \ +#define _NMLOG2(level, conf_id, ...) \ G_STMT_START { \ nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ - "%s%p]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + "%s%"G_GUINT64_FORMAT"]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG2_PREFIX_NAME": call[", \ - (config) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + (conf_id)->log_id \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } G_STMT_END /*****************************************************************************/ -static void pacrunner_remove_done (GObject *source, GAsyncResult *res, gpointer user_data); +static void _call_destroy_proxy_configuration (NMPacrunnerManager *self, + NMPacrunnerConfId *conf_id, + const char *path, + gboolean verbose_log); /*****************************************************************************/ -static Config * -config_new (NMPacrunnerManager *manager, GVariant *args) +static NMPacrunnerConfId * +conf_id_ref (NMPacrunnerConfId *conf_id) { - Config *config; - - config = g_slice_new0 (Config); - 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); + nm_assert (conf_id); + nm_assert (conf_id->refcount > 0); - return config; -} - -static Config * -config_ref (Config *config) -{ - nm_assert (config); - nm_assert (config->refcount > 0); - - config->refcount++; - return config; + conf_id->refcount++; + return conf_id; } static void -config_unref (Config *config) +conf_id_unref (NMPacrunnerConfId *conf_id) { - nm_assert (config); - nm_assert (config->refcount > 0); - - if (config->refcount == 1) { - g_variant_unref (config->args); - g_free (config->path); - c_list_unlink_stale (&config->lst); - g_slice_free (Config, config); + nm_assert (conf_id); + nm_assert (conf_id->refcount > 0); + + if (conf_id->refcount == 1) { + g_variant_unref (conf_id->parameters); + g_free (conf_id->path); + c_list_unlink_stale (&conf_id->conf_id_lst); + g_object_unref (conf_id->self); + g_slice_free (NMPacrunnerConfId, conf_id); } else - config->refcount--; + conf_id->refcount--; } +NM_AUTO_DEFINE_FCN0 (NMPacrunnerConfId *, _nm_auto_unref_conf_id, conf_id_unref); +#define nm_auto_unref_conf_id nm_auto (_nm_auto_unref_conf_id) + /*****************************************************************************/ static void -add_proxy_config (GVariantBuilder *proxy_data, const NMProxyConfig *proxy_config) +get_ip_domains (GPtrArray *domains, NMIPConfig *ip_config) { - const char *pac_url, *pac_script; + NMDedupMultiIter ipconf_iter; + char *cidr; + guint i, num; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + int addr_family; + + if (!ip_config) + return; + + addr_family = nm_ip_config_get_addr_family (ip_config); + + num = nm_ip_config_get_num_searches (ip_config); + for (i = 0; i < num; i++) + g_ptr_array_add (domains, g_strdup (nm_ip_config_get_search (ip_config, i))); + + num = nm_ip_config_get_num_domains (ip_config); + for (i = 0; i < num; i++) + g_ptr_array_add (domains, g_strdup (nm_ip_config_get_domain (ip_config, i))); + + if (addr_family == AF_INET) { + const NMPlatformIP4Address *address; + + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, (NMIP4Config *) ip_config, &address) { + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet4_ntop (address->address, sbuf), + address->plen); + g_ptr_array_add (domains, cidr); + } + } else { + const NMPlatformIP6Address *address; + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, (NMIP6Config *) ip_config, &address) { + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet6_ntop (&address->address, sbuf), + address->plen); + g_ptr_array_add (domains, cidr); + } + } + + if (addr_family == AF_INET) { + const NMPlatformIP4Route *routes; + + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, (NMIP4Config *) ip_config, &routes) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) + continue; + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet4_ntop (routes->network, sbuf), + routes->plen); + g_ptr_array_add (domains, cidr); + } + } else { + const NMPlatformIP6Route *routes; + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, (NMIP6Config *) ip_config, &routes) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) + continue; + cidr = g_strdup_printf ("%s/%u", + nm_utils_inet6_ntop (&routes->network, sbuf), + routes->plen); + g_ptr_array_add (domains, cidr); + } + } +} + +static GVariant * +_make_request_create_proxy_configuration (NMProxyConfig *proxy_config, + const char *iface, + NMIP4Config *ip4_config, + NMIP6Config *ip6_config) +{ + GVariantBuilder builder; NMProxyConfigMethod method; + const char *pac_url; + const char *pac_script; + + nm_assert (NM_IS_PROXY_CONFIG (proxy_config)); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + + if (iface) { + g_variant_builder_add (&builder, "{sv}", + "Interface", + g_variant_new_string (iface)); + } method = nm_proxy_config_get_method (proxy_config); + switch (method) { + case NM_PROXY_CONFIG_METHOD_AUTO: + g_variant_builder_add (&builder, "{sv}", + "Method", + g_variant_new_string ("auto")); - if (method == NM_PROXY_CONFIG_METHOD_AUTO) { pac_url = nm_proxy_config_get_pac_url (proxy_config); if (pac_url) { - g_variant_builder_add (proxy_data, "{sv}", + g_variant_builder_add (&builder, "{sv}", "URL", g_variant_new_string (pac_url)); } pac_script = nm_proxy_config_get_pac_script (proxy_config); if (pac_script) { - g_variant_builder_add (proxy_data, "{sv}", + g_variant_builder_add (&builder, "{sv}", "Script", g_variant_new_string (pac_script)); } + break; + case NM_PROXY_CONFIG_METHOD_NONE: + g_variant_builder_add (&builder, "{sv}", + "Method", + g_variant_new_string ("direct")); + break; } - g_variant_builder_add (proxy_data, "{sv}", + g_variant_builder_add (&builder, "{sv}", "BrowserOnly", g_variant_new_boolean (nm_proxy_config_get_browser_only (proxy_config))); -} - -static void -get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4) -{ - NMDedupMultiIter ipconf_iter; - char *cidr; - const NMPlatformIP4Address *address; - const NMPlatformIP4Route *routes; - guint i; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - /* Extract searches */ - for (i = 0; i < nm_ip4_config_get_num_searches (ip4); i++) - g_ptr_array_add (domains, g_strdup (nm_ip4_config_get_search (ip4, i))); + if (ip4_config || ip6_config) { + gs_unref_ptrarray GPtrArray *domains = NULL; - /* Extract domains */ - for (i = 0; i < nm_ip4_config_get_num_domains (ip4); i++) - g_ptr_array_add (domains, g_strdup (nm_ip4_config_get_domain (ip4, i))); + domains = g_ptr_array_new_with_free_func (g_free); - /* Add addresses and routes in CIDR form */ + get_ip_domains (domains, NM_IP_CONFIG_CAST (ip4_config)); + get_ip_domains (domains, NM_IP_CONFIG_CAST (ip6_config)); - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) { - cidr = g_strdup_printf ("%s/%u", - nm_utils_inet4_ntop (address->address, sbuf), - address->plen); - g_ptr_array_add (domains, cidr); + if (domains->len > 0) { + g_variant_builder_add (&builder, "{sv}", + "Domains", + g_variant_new_strv ((const char *const*) domains->pdata, + domains->len)); + } } - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &routes) { - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) - continue; - cidr = g_strdup_printf ("%s/%u", - nm_utils_inet4_ntop (routes->network, sbuf), - routes->plen); - g_ptr_array_add (domains, cidr); - } + return g_variant_new ("(a{sv})", &builder); } +/*****************************************************************************/ + static void -get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) +_call_destroy_proxy_configuration_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) { - NMDedupMultiIter ipconf_iter; - char *cidr; - const NMPlatformIP6Address *address; - const NMPlatformIP6Route *routes; - guint i; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - /* Extract searches */ - for (i = 0; i < nm_ip6_config_get_num_searches (ip6); i++) - g_ptr_array_add (domains, g_strdup (nm_ip6_config_get_search (ip6, i))); - - /* Extract domains */ - for (i = 0; i < nm_ip6_config_get_num_domains (ip6); i++) - g_ptr_array_add (domains, g_strdup (nm_ip6_config_get_domain (ip6, i))); - - /* Add addresses and routes in CIDR form */ - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) { - cidr = g_strdup_printf ("%s/%u", - nm_utils_inet6_ntop (&address->address, sbuf), - address->plen); - g_ptr_array_add (domains, cidr); - } + nm_auto_unref_conf_id NMPacrunnerConfId *conf_id = user_data; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) { - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) - continue; - cidr = g_strdup_printf ("%s/%u", - nm_utils_inet6_ntop (&routes->network, sbuf), - routes->plen); - g_ptr_array_add (domains, cidr); + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + if (!ret) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + _LOG2T (conf_id, "destroy proxy configuration: failed with %s", error->message); + else + _LOG2T (conf_id, "destroy proxy configuration: cancelled"); + return; } -} - -/*****************************************************************************/ - -static GCancellable * -_ensure_cancellable (NMPacrunnerManagerPrivate *priv) -{ - if (G_UNLIKELY (!priv->cancellable)) - priv->cancellable = g_cancellable_new (); - return priv->cancellable; + _LOG2T (conf_id, "destroy proxy configuration: success"); } static void -pacrunner_send_done (GObject *source, GAsyncResult *res, gpointer user_data) +_call_create_proxy_configuration_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) { - Config *config = user_data; - NMPacrunnerManager *self; - NMPacrunnerManagerPrivate *priv; + nm_auto_unref_conf_id NMPacrunnerConfId *conf_id = user_data; + NMPacrunnerManager *self = NM_PACRUNNER_MANAGER (conf_id->self); gs_free_error GError *error = NULL; gs_unref_variant GVariant *variant = NULL; const char *path = NULL; - nm_assert (!config->path); + nm_assert (!conf_id->path); - 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; + variant = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); - self = NM_PACRUNNER_MANAGER (config->manager_maybe_dangling); - priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - - if (!variant) - _LOG2D (config, "sending failed: %s", error->message); - else { - g_variant_get (variant, "(&o)", &path); - - if (c_list_is_empty (&config->lst)) { - _LOG2D (config, "sent (%s), but destroy it right away", path); - g_dbus_proxy_call (priv->pacrunner, - "DestroyProxyConfiguration", - g_variant_new ("(o)", path), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - _ensure_cancellable (priv), - pacrunner_remove_done, - config_ref (config)); - } else { - _LOG2D (config, "sent (%s)", path); - config->path = g_strdup (path); - } + if (!variant) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + _LOG2T (conf_id, "create proxy configuration failed: %s", error->message); + else + _LOG2T (conf_id, "create proxy configuration cancelled"); + return; } -out: - config_unref (config); + g_variant_get (variant, "(&o)", &path); + + if (c_list_is_empty (&conf_id->conf_id_lst)) { + _LOG2T (conf_id, "create proxy configuration succeeded (%s), but destroy it right away", path); + _call_destroy_proxy_configuration (self, + conf_id, + path, + FALSE); + } else { + _LOG2T (conf_id, "create proxy configuration succeeded (%s)", path); + conf_id->path = g_strdup (path); + } } static void -pacrunner_send_config (NMPacrunnerManager *self, Config *config) +_call_destroy_proxy_configuration (NMPacrunnerManager *self, + NMPacrunnerConfId *conf_id, + const char *path, + gboolean verbose_log) { NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - if (priv->pacrunner) { - _LOG2T (config, "sending..."); - - nm_assert (!config->path); - g_dbus_proxy_call (priv->pacrunner, - "CreateProxyConfiguration", - config->args, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - _ensure_cancellable (priv), - pacrunner_send_done, - config_ref (config)); - } + if (verbose_log) + _LOG2T (conf_id, "destroy proxy configuration %s...", path); + + g_dbus_connection_call (priv->dbus_connection, + PACRUNNER_DBUS_SERVICE, + PACRUNNER_DBUS_PATH, + PACRUNNER_DBUS_INTERFACE, + "DestroyProxyConfiguration", + g_variant_new ("(o)", path), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + NM_SHUTDOWN_TIMEOUT_MS, + priv->cancellable, + _call_destroy_proxy_configuration_cb, + conf_id_ref (conf_id)); } static void -name_owner_changed (NMPacrunnerManager *self) +_call_create_proxy_configuration (NMPacrunnerManager *self, + NMPacrunnerConfId *conf_id, + gboolean verbose_log) { NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - gs_free char *owner = NULL; - CList *iter; - - owner = g_dbus_proxy_get_name_owner (priv->pacrunner); - if (owner) { - _LOGD ("name owner appeared (%s)", owner); - 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); - } -} -static void -name_owner_changed_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - name_owner_changed (user_data); + if (verbose_log) + _LOG2T (conf_id, "create proxy configuration..."); + + g_dbus_connection_call (priv->dbus_connection, + PACRUNNER_DBUS_SERVICE, + PACRUNNER_DBUS_PATH, + PACRUNNER_DBUS_INTERFACE, + "CreateProxyConfiguration", + conf_id->parameters, + G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + NM_SHUTDOWN_TIMEOUT_MS, + priv->cancellable, + _call_create_proxy_configuration_cb, + conf_id_ref (conf_id)); } -static void -pacrunner_proxy_cb (GObject *source, GAsyncResult *res, gpointer user_data) +static gboolean +_try_start_service_by_name (NMPacrunnerManager *self) { - NMPacrunnerManager *self = user_data; - NMPacrunnerManagerPrivate *priv; - 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)) - _LOGE ("failed to create D-Bus proxy for pacrunner: %s", error->message); - return; - } + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + if ( priv->try_start_blocked + || !priv->dbus_initied) + return FALSE; - priv->pacrunner = proxy; - g_signal_connect (priv->pacrunner, "notify::g-name-owner", - G_CALLBACK (name_owner_changed_cb), self); - name_owner_changed (self); + _LOGD ("try D-Bus activating pacrunner..."); + priv->try_start_blocked = TRUE; + nm_dbus_connection_call_start_service_by_name (priv->dbus_connection, + PACRUNNER_DBUS_SERVICE, + -1, + NULL, + NULL, + NULL); + return TRUE; } +/*****************************************************************************/ + /** - * nm_pacrunner_manager_send: + * nm_pacrunner_manager_add: * @self: the #NMPacrunnerManager - * @iface: the iface for the connection or %NULL * @proxy_config: proxy config of the connection + * @iface: the iface for the connection or %NULL * @ip4_config: IP4 config of the connection to extract domain info from * @ip6_config: IP6 config of the connection to extract domain info from * - * Returns: a #NMPacrunnerCallId call id. The function cannot - * fail and always returns a non NULL pointer. The call-id may + * Returns: a #NMPacrunnerConfId id. The function cannot + * fail and always returns a non NULL pointer. The conf-id may * be used to remove the configuration later via nm_pacrunner_manager_remove(). - * Note that the call-id does not keep the @self instance alive. - * If you plan to remove the configuration later, you must keep - * the instance alive long enough. You can remove the configuration - * at most once using this call call-id. + * Note that the conf-id keeps the @self instance alive. */ -NMPacrunnerCallId * -nm_pacrunner_manager_send (NMPacrunnerManager *self, - const char *iface, - NMProxyConfig *proxy_config, - NMIP4Config *ip4_config, - NMIP6Config *ip6_config) +NMPacrunnerConfId * +nm_pacrunner_manager_add (NMPacrunnerManager *self, + NMProxyConfig *proxy_config, + const char *iface, + NMIP4Config *ip4_config, + NMIP6Config *ip6_config) { - char **strv = NULL; - NMProxyConfigMethod method; NMPacrunnerManagerPrivate *priv; - GVariantBuilder proxy_data; - GPtrArray *domains; - Config *config; + NMPacrunnerConfId *conf_id; + gs_free char *log_msg = NULL; g_return_val_if_fail (NM_IS_PACRUNNER_MANAGER (self), NULL); g_return_val_if_fail (proxy_config, NULL); priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - g_free (priv->iface); - priv->iface = g_strdup (iface); - - g_variant_builder_init (&proxy_data, G_VARIANT_TYPE_VARDICT); - - if (iface) { - g_variant_builder_add (&proxy_data, "{sv}", - "Interface", - g_variant_new_string (iface)); + conf_id = g_slice_new (NMPacrunnerConfId); + *conf_id = (NMPacrunnerConfId) { + .log_id = ++priv->log_id_counter, + .refcount = 1, + .self = g_object_ref (self), + .parameters = g_variant_ref_sink (_make_request_create_proxy_configuration (proxy_config, + iface, + ip4_config, + ip6_config)), + }; + c_list_link_tail (&priv->conf_id_lst_head, + &conf_id->conf_id_lst); + + if (!priv->has_name_owner) { + _LOG2T (conf_id, "add config: %s (%s)", + (log_msg = g_variant_print (conf_id->parameters, FALSE)), + "pacrunner D-Bus service not running"); + _try_start_service_by_name (self); + } else { + _LOG2T (conf_id, "add config: %s (%s)", + (log_msg = g_variant_print (conf_id->parameters, FALSE)), + "create proxy configuration"); + _call_create_proxy_configuration (self, conf_id, FALSE); } - method = nm_proxy_config_get_method (proxy_config); - switch (method) { - case NM_PROXY_CONFIG_METHOD_AUTO: - g_variant_builder_add (&proxy_data, "{sv}", - "Method", - g_variant_new_string ("auto")); + return conf_id; +} - break; - case NM_PROXY_CONFIG_METHOD_NONE: - g_variant_builder_add (&proxy_data, "{sv}", - "Method", - g_variant_new_string ("direct")); - } +/** + * nm_pacrunner_manager_remove: + * @conf_id: the conf id obtained from nm_pacrunner_manager_add() + */ +void +nm_pacrunner_manager_remove (NMPacrunnerConfId *conf_id) +{ + _nm_unused nm_auto_unref_conf_id NMPacrunnerConfId *conf_id_free = conf_id; + NMPacrunnerManager *self; + NMPacrunnerManagerPrivate *priv; - /* Extract stuff from configs */ - add_proxy_config (&proxy_data, proxy_config); + g_return_if_fail (conf_id); - if (ip4_config || ip6_config) { - domains = g_ptr_array_new_with_free_func (g_free); + self = conf_id->self; - if (ip4_config) - get_ip4_domains (domains, ip4_config); - if (ip6_config) - get_ip6_domains (domains, ip6_config); + g_return_if_fail (NM_IS_PACRUNNER_MANAGER (self)); - g_ptr_array_add (domains, NULL); - strv = (char **) g_ptr_array_free (domains, (domains->len == 1)); + priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - if (strv) { - g_variant_builder_add (&proxy_data, "{sv}", - "Domains", - g_variant_new_strv ((const char *const *) strv, -1)); - g_strfreev (strv); - } + _LOG2T (conf_id, "removing..."); + + nm_assert (c_list_contains (&priv->conf_id_lst_head, &conf_id->conf_id_lst)); + + c_list_unlink (&conf_id->conf_id_lst); + + if (!conf_id->path) { + /* There is no ID to destroy the configuration. + * + * That can happen because: + * + * - pacrunner D-Bus service is not running (no name owner) and we didn't call CreateProxyConfiguration. + * - CreateProxyConfiguration failed. + * - CreateProxyConfiguration is in progress. + * + * In all cases there is nothing to do. Note that if CreateProxyConfiguration is in progress + * it has a reference on the conf-id and it will automatically destroy the configuration + * when it completes. + */ + return; } - config = config_new (self, g_variant_new ("(a{sv})", &proxy_data)); - - { - gs_free char *args_str = NULL; - - _LOG2D (config, "send: new config %s", - (args_str = g_variant_print (config->args, FALSE))); - } + _call_destroy_proxy_configuration (self, conf_id, conf_id->path, TRUE); +} - /* Send if pacrunner is available on bus, otherwise - * config has already been appended above to be - * sent when pacrunner appears. - */ - pacrunner_send_config (self, config); +gboolean +nm_pacrunner_manager_remove_clear (NMPacrunnerConfId **p_conf_id) +{ + g_return_val_if_fail (p_conf_id, FALSE); - return config; + if (!*p_conf_id) + return FALSE; + nm_pacrunner_manager_remove (g_steal_pointer (p_conf_id)); + return TRUE; } +/*****************************************************************************/ + static void -pacrunner_remove_done (GObject *source, GAsyncResult *res, gpointer user_data) +name_owner_changed (NMPacrunnerManager *self, + const char *name_owner) { - Config *config = user_data; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + NMPacrunnerConfId *conf_id; + gboolean has_name_owner; - ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); - if (!ret) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto out; - _LOG2D (config, "remove failed: %s", error->message); - goto out; - } + has_name_owner = (name_owner && name_owner[0]); + + if ( priv->dbus_initied + && priv->has_name_owner == has_name_owner) + return; + + priv->has_name_owner = has_name_owner; - _LOG2D (config, "removed"); + nm_clear_g_cancellable (&priv->cancellable); -out: - config_unref (config); + if (has_name_owner) { + priv->dbus_initied = TRUE; + priv->try_start_blocked = FALSE; + _LOGD ("pacrunner appeared on D-Bus (%s)", name_owner); + priv->cancellable = g_cancellable_new (); + c_list_for_each_entry (conf_id, &priv->conf_id_lst_head, conf_id_lst) + _call_create_proxy_configuration (self, conf_id, TRUE); + } else { + if (!priv->dbus_initied) { + priv->dbus_initied = TRUE; + nm_assert (!priv->try_start_blocked); + _LOGD ("pacrunner not on D-Bus"); + } else + _LOGD ("pacrunner disappeared from D-Bus"); + if (!c_list_is_empty (&priv->conf_id_lst_head)) { + c_list_for_each_entry (conf_id, &priv->conf_id_lst_head, conf_id_lst) + nm_clear_g_free (&conf_id->path); + _try_start_service_by_name (self); + } + } } -/** - * nm_pacrunner_manager_remove: - * @self: the #NMPacrunnerManager - * @call_id: the call-id obtained from nm_pacrunner_manager_send() - */ -void -nm_pacrunner_manager_remove (NMPacrunnerManager *self, NMPacrunnerCallId *call_id) +static void +name_owner_changed_cb (GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) { - NMPacrunnerManagerPrivate *priv; - Config *config; + const char *new_owner; - g_return_if_fail (NM_IS_PACRUNNER_MANAGER (self)); - g_return_if_fail (call_id); - - config = call_id; - priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) + return; - _LOG2T (config, "removing..."); - - nm_assert (c_list_contains (&priv->configs, &config->lst)); - - if (priv->pacrunner) { - if (!config->path) { - /* send() failed or is still pending. The item is unlinked from - * priv->configs, so pacrunner_send_done() knows to call - * DestroyProxyConfiguration right away. - */ - } else { - g_dbus_proxy_call (priv->pacrunner, - "DestroyProxyConfiguration", - g_variant_new ("(o)", config->path), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - _ensure_cancellable (priv), - pacrunner_remove_done, - config_ref (config)); - nm_clear_g_free (&config->path); - } - } + g_variant_get (parameters, + "(&s&s&s)", + NULL, + NULL, + &new_owner); - c_list_unlink (&config->lst); - config_unref (config); + name_owner_changed (user_data, new_owner); } -gboolean -nm_pacrunner_manager_remove_clear (NMPacrunnerManager *self, - NMPacrunnerCallId **p_call_id) +static void +get_name_owner_cb (const char *name_owner, + GError *error, + gpointer user_data) { - g_return_val_if_fail (p_call_id, FALSE); - - /* if we have no call-id, allow for %NULL */ - g_return_val_if_fail ((!self && !*p_call_id) || NM_IS_PACRUNNER_MANAGER (self), FALSE); + if ( !name_owner + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - if (!*p_call_id) - return FALSE; - nm_pacrunner_manager_remove (self, - g_steal_pointer (p_call_id)); - return TRUE; + name_owner_changed (user_data, name_owner); } /*****************************************************************************/ @@ -551,28 +597,36 @@ nm_pacrunner_manager_init (NMPacrunnerManager *self) { NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (self); - 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, - _ensure_cancellable (priv), - pacrunner_proxy_cb, - self); + c_list_init (&priv->conf_id_lst_head); + + priv->dbus_connection = nm_g_object_ref (NM_MAIN_DBUS_CONNECTION_GET); + + if (!priv->dbus_connection) { + _LOGD ("no D-Bus connection to talk to pacrunner"); + return; + } + + priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->dbus_connection, + PACRUNNER_DBUS_SERVICE, + name_owner_changed_cb, + self, + NULL); + priv->cancellable = g_cancellable_new (); + + nm_dbus_connection_call_get_name_owner (priv->dbus_connection, + PACRUNNER_DBUS_SERVICE, + -1, + priv->cancellable, + get_name_owner_cb, + self); } 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 (iter); - config_unref (c_list_entry (iter, Config, lst)); - } + nm_assert (c_list_is_empty (&priv->conf_id_lst_head)); /* we cancel all pending operations. Note that pacrunner automatically * removes all configuration once NetworkManager disconnects from @@ -580,8 +634,9 @@ dispose (GObject *object) */ nm_clear_g_cancellable (&priv->cancellable); - g_clear_pointer (&priv->iface, g_free); - g_clear_object (&priv->pacrunner); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, + &priv->name_owner_changed_id); + g_clear_object (&priv->dbus_connection); G_OBJECT_CLASS (nm_pacrunner_manager_parent_class)->dispose (object); } |