From 9f15abbda786c3db0431a3a5cb82baf5bea87660 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 23 Sep 2015 12:19:09 +0200 Subject: [PATCH] libnm/vpn-service-plugin: add watch-peer property Make it possible to construct the plugin instance in a way that disconnects the connection if the DBus client that activated it drops off the bus. This makes the plugins conveniently clean up when NetworkManager crashes. We need this, as with multiple VPN support we can loose track of the client bus names when the daemon crashes leaving to nice way to clean up on respawn. However, this behavior is not desired for debugging or hypotetical VPN plugin users other than NetworkManager (say; "gdbus call -m o.fd.NM.VPN.Plugin.Connect"). Let the plugin decide when to use it. --- libnm/nm-vpn-service-plugin.c | 65 +++++++++++++++++++++++++++++++++++ libnm/nm-vpn-service-plugin.h | 1 + 2 files changed, 66 insertions(+) diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c index 2644732d9..d9f669c9e 100644 --- a/libnm/nm-vpn-service-plugin.c +++ b/libnm/nm-vpn-service-plugin.c @@ -53,11 +53,13 @@ typedef struct { GDBusConnection *connection; NMDBusVpnPlugin *dbus_vpn_service_plugin; char *dbus_service_name; + gboolean dbus_watch_peer; /* Temporary stuff */ guint connect_timer; guint quit_timer; guint fail_stop_id; + guint peer_watch_id; gboolean interactive; gboolean got_config; @@ -88,6 +90,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, PROP_DBUS_SERVICE_NAME, + PROP_DBUS_WATCH_PEER, PROP_STATE, LAST_PROP @@ -184,11 +187,13 @@ nm_vpn_service_plugin_failure (NMVpnServicePlugin *plugin, gboolean nm_vpn_service_plugin_disconnect (NMVpnServicePlugin *plugin, GError **err) { + NMVpnServicePluginPrivate *priv; gboolean ret = FALSE; NMVpnServiceState state; g_return_val_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin), FALSE); + priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); state = nm_vpn_service_plugin_get_state (plugin); switch (state) { case NM_VPN_SERVICE_STATE_STOPPING: @@ -207,6 +212,11 @@ nm_vpn_service_plugin_disconnect (NMVpnServicePlugin *plugin, GError **err) break; case NM_VPN_SERVICE_STATE_STARTING: case NM_VPN_SERVICE_STATE_STARTED: + if (priv->peer_watch_id) { + g_dbus_connection_signal_unsubscribe (nm_vpn_service_plugin_get_connection (plugin), + priv->peer_watch_id); + priv->peer_watch_id = 0; + } nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPING); ret = NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin)->disconnect (plugin, err); nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPED); @@ -413,6 +423,37 @@ connect_timer_start (NMVpnServicePlugin *plugin) priv->connect_timer = g_timeout_add_seconds (60, connect_timer_expired, plugin); } +static void +peer_vanished (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + nm_vpn_service_plugin_disconnect (NM_VPN_SERVICE_PLUGIN (user_data), NULL); +} + +static guint +watch_peer (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context) +{ + GDBusConnection *connection = g_dbus_method_invocation_get_connection (context); + const gchar *peer = g_dbus_message_get_sender (g_dbus_method_invocation_get_message (context)); + + return g_dbus_connection_signal_subscribe (connection, + "org.freedesktop.DBus", + "org.freedesktop.DBus", + "NameOwnerChanged", + "/org/freedesktop/DBus", + peer, + G_DBUS_SIGNAL_FLAGS_NONE, + peer_vanished, + plugin, + NULL); +} + static void _connect_generic (NMVpnServicePlugin *plugin, GDBusMethodInvocation *context, @@ -457,6 +498,9 @@ _connect_generic (NMVpnServicePlugin *plugin, nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); + if (priv->dbus_watch_peer) + priv->peer_watch_id = watch_peer (plugin, context); + if (details) { priv->interactive = TRUE; success = vpn_class->connect_interactive (plugin, connection, details, &error); @@ -994,6 +1038,10 @@ set_property (GObject *object, guint prop_id, /* Construct-only */ priv->dbus_service_name = g_value_dup_string (value); break; + case PROP_DBUS_WATCH_PEER: + /* Construct-only */ + priv->dbus_watch_peer = g_value_get_boolean (value); + break; case PROP_STATE: nm_vpn_service_plugin_set_state (NM_VPN_SERVICE_PLUGIN (object), (NMVpnServiceState) g_value_get_enum (value)); @@ -1014,6 +1062,9 @@ get_property (GObject *object, guint prop_id, case PROP_DBUS_SERVICE_NAME: g_value_set_string (value, priv->dbus_service_name); break; + case PROP_DBUS_WATCH_PEER: + g_value_set_boolean (value, priv->dbus_watch_peer); + break; case PROP_STATE: g_value_set_enum (value, nm_vpn_service_plugin_get_state (NM_VPN_SERVICE_PLUGIN (object))); break; @@ -1120,6 +1171,20 @@ nm_vpn_service_plugin_class_init (NMVpnServicePluginClass *plugin_class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * NMVpnServicePlugin:service-name: + * + * The D-Bus service name of this plugin. + * + * Since: 1.2 + */ + g_object_class_install_property + (object_class, PROP_DBUS_WATCH_PEER, + g_param_spec_boolean (NM_VPN_SERVICE_PLUGIN_DBUS_WATCH_PEER, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + /** * NMVpnServicePlugin:state: * diff --git a/libnm/nm-vpn-service-plugin.h b/libnm/nm-vpn-service-plugin.h index 81ba40457..4fb0ed360 100644 --- a/libnm/nm-vpn-service-plugin.h +++ b/libnm/nm-vpn-service-plugin.h @@ -36,6 +36,7 @@ G_BEGIN_DECLS #define NM_VPN_SERVICE_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_SERVICE_PLUGIN, NMVpnServicePluginClass)) #define NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME "service-name" +#define NM_VPN_SERVICE_PLUGIN_DBUS_WATCH_PEER "watch-peer" #define NM_VPN_SERVICE_PLUGIN_STATE "state" typedef struct {