summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-05-05 09:51:09 +0200
committerThomas Haller <thaller@redhat.com>2019-05-13 09:24:02 +0200
commit83476a3fb64efa0b04630469aa901f99e4de121a (patch)
tree62449d2f501d7cbb041977c0a11d6c6db2fc37e1
parentcbdb4981973420c51144a637c0cdc97fc74e5167 (diff)
downloadNetworkManager-83476a3fb64efa0b04630469aa901f99e4de121a.tar.gz
pacrunner: refactor pacrunner to use GDBusConnection
- use GDBusConnection instead of GDBusProxy. - rename "call-id" to "conf-id". It's really not a "call" but configuration that gets added and NMPacrunnerManager ensures that the configuration is send to pacrunner. - let "conf-id" keep a reference to NMPacrunnerManager. For one, when we remove configurations we need to call DestroyProxyConfiguration to remove it again. We cannot just abort the requests but must linger around until our configuration is properly cleaned up. Hence, we anyway cannot destroy the NMPacrunnerManager earlier. With respect to fixing shutdown not to leak anything, this merely means that we must wait (and iterate the main loop) as long as NMPacrunnerManager singleton still exits (that is anyway the plan how to fix shutdown). With these considerations it's also clear that our D-Bus calls must have a stricter timeout: NM_SHUTDOWN_TIMEOUT_MS. This is also nice because nm_pacrunner_manager_remove() no longer needs a manager parameter, it can just rely on having a reference to the manager. - for logging the configuration IDs, don't log pointer values. Logging pointer values should be avoided as it defeats ASLR. Instead, give them a "log_id" number. - pacrunner is a D-Bus activatable service. D-Bus activatable services needs special care. We don't want to start it over and over again. Instead, we only try to "StartServiceByName" if - we have any configuration to add - if pacrunner is currently confirmed not to be running (by watching name owner changes) - we didn't try to start it already. That means, only start it at the beginning and afterwards set a flag to block it. When we see pacrunner appear on D-Bus we always clear that flag, that means if pacrunner drops of, we will try to restart it (once).
-rw-r--r--src/NetworkManagerUtils.h2
-rw-r--r--src/devices/nm-device.c34
-rw-r--r--src/nm-pacrunner-manager.c778
-rw-r--r--src/nm-pacrunner-manager.h18
-rw-r--r--src/vpn/nm-vpn-connection.c28
5 files changed, 448 insertions, 412 deletions
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 2b1f5ed891..4be5d462b3 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -78,7 +78,7 @@ NMPlatformRoutingRule *nm_ip_routing_rule_to_platform (const NMIPRoutingRule *ru
* SIGKILL.
*
* After NM_SHUTDOWN_TIMEOUT_MS, NetworkManager will however not yet terminate right
- * away. It iterates the mainloop for another NM_SHUTDOWN_TIMEOUT_MS_EXTRA. This
+ * away. It iterates the mainloop for another NM_SHUTDOWN_TIMEOUT_MS_WATCHDOG. This
* should give time to reap the child process (after SIGKILL).
*
* So, the maximum time we should wait before sending SIGKILL should be at most
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 89207586e7..38582937e4 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -397,8 +397,7 @@ typedef struct _NMDevicePrivate {
/* Proxy Configuration */
NMProxyConfig *proxy_config;
- NMPacrunnerManager *pacrunner_manager;
- NMPacrunnerCallId *pacrunner_call_id;
+ NMPacrunnerConfId *pacrunner_conf_id;
/* IP configuration info. Combined config from VPN, settings, and device */
union {
@@ -11128,21 +11127,17 @@ nm_device_reactivate_ip6_config (NMDevice *self,
}
static void
-_pacrunner_manager_send (NMDevice *self)
+_pacrunner_manager_add (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- nm_pacrunner_manager_remove_clear (priv->pacrunner_manager,
- &priv->pacrunner_call_id);
+ nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id);
- if (!priv->pacrunner_manager)
- priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ());
-
- priv->pacrunner_call_id = nm_pacrunner_manager_send (priv->pacrunner_manager,
- nm_device_get_ip_iface (self),
- priv->proxy_config,
- NULL,
- NULL);
+ priv->pacrunner_conf_id = nm_pacrunner_manager_add (nm_pacrunner_manager_get (),
+ priv->proxy_config,
+ nm_device_get_ip_iface (self),
+ NULL,
+ NULL);
}
static void
@@ -11150,10 +11145,10 @@ reactivate_proxy_config (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- if (!priv->pacrunner_call_id)
+ if (!priv->pacrunner_conf_id)
return;
nm_device_set_proxy_config (self, priv->dhcp4.pac_url);
- _pacrunner_manager_send (self);
+ _pacrunner_manager_add (self);
}
static gboolean
@@ -15081,8 +15076,7 @@ _set_state_full (NMDevice *self,
}
}
- nm_pacrunner_manager_remove_clear (priv->pacrunner_manager,
- &priv->pacrunner_call_id);
+ nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id);
break;
case NM_DEVICE_STATE_DISCONNECTED:
if ( priv->queued_act_request
@@ -15102,7 +15096,7 @@ _set_state_full (NMDevice *self,
NULL, NULL, NULL);
if (priv->proxy_config)
- _pacrunner_manager_send (self);
+ _pacrunner_manager_add (self);
break;
case NM_DEVICE_STATE_FAILED:
/* Usually upon failure the activation chain is interrupted in
@@ -16345,9 +16339,7 @@ dispose (GObject *object)
dispatcher_cleanup (self);
- nm_pacrunner_manager_remove_clear (priv->pacrunner_manager,
- &priv->pacrunner_call_id);
- g_clear_object (&priv->pacrunner_manager);
+ nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id);
_cleanup_generic_pre (self, CLEANUP_TYPE_KEEP);
diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c
index b9881f76f2..1ad9cb0f75 100644
--- a/src/nm-pacrunner-manager.c
+++ b/src/nm-pacrunner-manager.c
@@ -23,11 +23,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 +38,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 +84,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 +598,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 +635,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);
}
diff --git a/src/nm-pacrunner-manager.h b/src/nm-pacrunner-manager.h
index 3080c4f5fd..35ccb3c351 100644
--- a/src/nm-pacrunner-manager.h
+++ b/src/nm-pacrunner-manager.h
@@ -31,22 +31,20 @@
typedef struct _NMPacrunnerManagerClass NMPacrunnerManagerClass;
-typedef struct _NMPacrunnerCallId NMPacrunnerCallId;
+typedef struct _NMPacrunnerConfId NMPacrunnerConfId;
GType nm_pacrunner_manager_get_type (void);
NMPacrunnerManager *nm_pacrunner_manager_get (void);
-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);
-void nm_pacrunner_manager_remove (NMPacrunnerManager *self,
- NMPacrunnerCallId *call_id);
+void nm_pacrunner_manager_remove (NMPacrunnerConfId *conf_id);
-gboolean nm_pacrunner_manager_remove_clear (NMPacrunnerManager *self,
- NMPacrunnerCallId **p_call_id);
+gboolean nm_pacrunner_manager_remove_clear (NMPacrunnerConfId **p_conf_id);
#endif /* __NETWORKMANAGER_PACRUNNER_MANAGER_H__ */
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index 5acf491a2c..2c4f33359f 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -124,8 +124,7 @@ typedef struct {
GVariant *connect_hash;
guint connect_timeout;
NMProxyConfig *proxy_config;
- NMPacrunnerManager *pacrunner_manager;
- NMPacrunnerCallId *pacrunner_call_id;
+ NMPacrunnerConfId *pacrunner_conf_id;
gboolean has_ip4;
NMIP4Config *ip4_config;
guint32 ip4_internal_gw;
@@ -552,18 +551,12 @@ _set_vpn_state (NMVpnConnection *self,
NULL);
if (priv->proxy_config) {
- nm_pacrunner_manager_remove_clear (priv->pacrunner_manager,
- &priv->pacrunner_call_id);
- if (!priv->pacrunner_manager) {
- /* the pending call doesn't keep NMPacrunnerManager alive.
- * Take a reference to it. */
- priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ());
- }
- priv->pacrunner_call_id = nm_pacrunner_manager_send (priv->pacrunner_manager,
- priv->ip_iface,
- priv->proxy_config,
- priv->ip4_config,
- priv->ip6_config);
+ nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id);
+ priv->pacrunner_conf_id = nm_pacrunner_manager_add (nm_pacrunner_manager_get (),
+ priv->proxy_config,
+ priv->ip_iface,
+ priv->ip4_config,
+ priv->ip6_config);
}
break;
case STATE_DEACTIVATING:
@@ -594,8 +587,7 @@ _set_vpn_state (NMVpnConnection *self,
}
}
- nm_pacrunner_manager_remove_clear (priv->pacrunner_manager,
- &priv->pacrunner_call_id);
+ nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id);
break;
case STATE_FAILED:
case STATE_DISCONNECTED:
@@ -2801,9 +2793,7 @@ dispose (GObject *object)
fw_call_cleanup (self);
- nm_pacrunner_manager_remove_clear (priv->pacrunner_manager,
- &priv->pacrunner_call_id);
- g_clear_object (&priv->pacrunner_manager);
+ nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id);
G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object);
}