summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2015-08-19 18:55:53 +0200
committerLubomir Rintel <lkundrak@v3.sk>2015-10-13 18:20:56 +0200
commit5b48befaad3281c479673aed7c4b831e6e0da694 (patch)
treee2c541ebe27d748de3bd672b46ace02a8c2ae27a
parent9bbf5e94c2ff676f685a7740713140026efbcb7c (diff)
downloadNetworkManager-lr/multiple-vpn.tar.gz
vpn-manager: support multiple VPN connections of the same typelr/multiple-vpn
A separate instance of the support plugin is spawned for each connection with a different bus name. The bus name is passed via --bus-name <name> argument. Plugins that support the feature indicate it with support-multiple-connections=true key in the [VPN Connection] section. The bus name is currently generated by adding a .<connection.uuid> to the VPN service name. It's guarranteed unique, but if it proves to be too long or ugly it can easily be replaced with something more meaningful (such as the same number as is used for connection's DBus name). NMVpnService has been removed and folded into NMVpnConnection. A NMVpnConnection will spawn a service plugin instance whenever it is activated and notices the bus name it needs is not provided. The NMVpnManager no longer needs to keep track of the connections in use apart for compatibility purposes with plugins that don't support the feature.
-rw-r--r--libnm-core/nm-vpn-plugin-info.c3
-rw-r--r--src/Makefile.am2
-rw-r--r--src/nm-manager.c3
-rw-r--r--src/vpn-manager/nm-vpn-connection.c178
-rw-r--r--src/vpn-manager/nm-vpn-connection.h4
-rw-r--r--src/vpn-manager/nm-vpn-manager.c140
-rw-r--r--src/vpn-manager/nm-vpn-manager.h4
-rw-r--r--src/vpn-manager/nm-vpn-service.c356
-rw-r--r--src/vpn-manager/nm-vpn-service.h60
9 files changed, 221 insertions, 529 deletions
diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c
index d8ead9a220..28f0f69279 100644
--- a/libnm-core/nm-vpn-plugin-info.c
+++ b/libnm-core/nm-vpn-plugin-info.c
@@ -449,9 +449,6 @@ nm_vpn_plugin_info_list_add (GSList **list, NMVpnPluginInfo *plugin_info, GError
gboolean
nm_vpn_plugin_info_list_remove (GSList **list, NMVpnPluginInfo *plugin_info)
{
- if (!plugin_info)
- return FALSE;
-
g_return_val_if_fail (list, FALSE);
g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info), FALSE);
diff --git a/src/Makefile.am b/src/Makefile.am
index b845958a6e..2cae35de1c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -324,8 +324,6 @@ libNetworkManager_la_SOURCES = \
vpn-manager/nm-vpn-connection.h \
vpn-manager/nm-vpn-manager.c \
vpn-manager/nm-vpn-manager.h \
- vpn-manager/nm-vpn-service.c \
- vpn-manager/nm-vpn-service.h \
\
nm-activation-request.c \
nm-activation-request.h \
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 1253f99188..67bb1fc015 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -3465,7 +3465,6 @@ nm_manager_deactivate_connection (NMManager *manager,
NMDeviceStateReason reason,
GError **error)
{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
NMActiveConnection *active;
gboolean success = FALSE;
@@ -3481,7 +3480,7 @@ nm_manager_deactivate_connection (NMManager *manager,
if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED)
vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED;
- if (nm_vpn_manager_deactivate_connection (priv->vpn_manager, NM_VPN_CONNECTION (active), vpn_reason))
+ if (nm_vpn_connection_deactivate (NM_VPN_CONNECTION (active), vpn_reason, FALSE))
success = TRUE;
else
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index d47e15398a..37815644e6 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -43,6 +43,8 @@
#include "nm-route-manager.h"
#include "nm-firewall-manager.h"
#include "nm-config.h"
+#include "nm-vpn-plugin-info.h"
+#include "nm-vpn-manager.h"
#include "nmdbus-vpn-connection.h"
@@ -89,6 +91,10 @@ typedef struct {
NMVpnConnectionStateReason failure_reason;
NMVpnServiceState service_state;
+ guint start_timeout;
+ gboolean service_running;
+ NMVpnPluginInfo *plugin_info;
+ char *bus_name;
/* Firewall */
NMFirewallManagerCallId fw_call;
@@ -383,6 +389,9 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev)
priv->ip_iface = NULL;
priv->ip_ifindex = 0;
+ g_free (priv->bus_name);
+ priv->bus_name = NULL;
+
/* Clear out connection secrets to ensure that the settings service
* gets asked for them next time the connection is activated.
*/
@@ -1858,6 +1867,111 @@ ip6_config_cb (GDBusProxy *proxy,
}
static void
+_name_owner_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ NMVpnConnection *self = NM_VPN_CONNECTION (user_data);
+ NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+ char *owner;
+
+ owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object));
+
+ if (owner && !priv->service_running) {
+ /* service appeared */
+ priv->service_running = TRUE;
+ _LOGI ("Saw the service appear; activating connection");
+
+ /* No need to wait for the timeout any longer */
+ nm_clear_g_source (&priv->start_timeout);
+
+ /* Expect success because the VPN service has already appeared */
+ _nm_dbus_signal_connect (priv->proxy, "Failure", G_VARIANT_TYPE ("(u)"),
+ G_CALLBACK (failure_cb), self);
+ _nm_dbus_signal_connect (priv->proxy, "StateChanged", G_VARIANT_TYPE ("(u)"),
+ G_CALLBACK (state_changed_cb), self);
+ _nm_dbus_signal_connect (priv->proxy, "SecretsRequired", G_VARIANT_TYPE ("(sas)"),
+ G_CALLBACK (secrets_required_cb), self);
+ _nm_dbus_signal_connect (priv->proxy, "Config", G_VARIANT_TYPE ("(a{sv})"),
+ G_CALLBACK (config_cb), self);
+ _nm_dbus_signal_connect (priv->proxy, "Ip4Config", G_VARIANT_TYPE ("(a{sv})"),
+ G_CALLBACK (ip4_config_cb), self);
+ _nm_dbus_signal_connect (priv->proxy, "Ip6Config", G_VARIANT_TYPE ("(a{sv})"),
+ G_CALLBACK (ip6_config_cb), self);
+
+ _set_vpn_state (self, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
+
+ /* Kick off the secrets requests; first we get existing system secrets
+ * and ask the plugin if these are sufficient, next we get all existing
+ * secrets from system and from user agents and ask the plugin again,
+ * and last we ask the user for new secrets if required.
+ */
+ get_secrets (self, SECRETS_REQ_SYSTEM, NULL);
+ } else if (!owner && priv->service_running) {
+ /* service went away */
+ priv->service_running = FALSE;
+ _LOGI ("VPN service disappeared");
+ nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED, FALSE);
+ }
+
+ g_free (owner);
+}
+
+
+static gboolean
+_daemon_exec_timeout (gpointer data)
+{
+ NMVpnConnection *self = NM_VPN_CONNECTION (data);
+ NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+
+ _LOGW ("Timed out waiting for the service to start");
+ priv->start_timeout = 0;
+ nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, FALSE);
+
+ g_object_unref (self);
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
+nm_vpn_service_daemon_exec (NMVpnConnection *self, GError **error)
+{
+ NMVpnConnectionPrivate *priv;
+ GPid pid;
+ char *vpn_argv[4];
+ gboolean success = FALSE;
+ GError *spawn_error = NULL;
+ int i = 0;
+
+ g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), FALSE);
+ priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+
+ vpn_argv[i++] = (char *) nm_vpn_plugin_info_get_program (priv->plugin_info);
+ if (nm_vpn_plugin_info_supports_multiple (priv->plugin_info)) {
+ vpn_argv[i++] = "--bus-name";
+ vpn_argv[i++] = priv->bus_name;
+ }
+ vpn_argv[i] = NULL;
+ g_assert (vpn_argv[0]);
+
+ success = g_spawn_async (NULL, vpn_argv, NULL, 0, nm_utils_setpgid, NULL, &pid, &spawn_error);
+
+ if (success) {
+ _LOGI ("Started the VPN service, PID %ld", (long int) pid);
+ priv->start_timeout = g_timeout_add_seconds (5, _daemon_exec_timeout, g_object_ref (self));
+ } else {
+ g_set_error (error,
+ NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
+ "%s", spawn_error ? spawn_error->message : "unknown g_spawn_async() error");
+
+ if (spawn_error)
+ g_error_free (spawn_error);
+ }
+
+ return success;
+}
+
+static void
on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data)
{
NMVpnConnection *self;
@@ -1883,55 +1997,69 @@ on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data)
}
priv->proxy = proxy;
- _nm_dbus_signal_connect (priv->proxy, "Failure", G_VARIANT_TYPE ("(u)"),
- G_CALLBACK (failure_cb), self);
- _nm_dbus_signal_connect (priv->proxy, "StateChanged", G_VARIANT_TYPE ("(u)"),
- G_CALLBACK (state_changed_cb), self);
- _nm_dbus_signal_connect (priv->proxy, "SecretsRequired", G_VARIANT_TYPE ("(sas)"),
- G_CALLBACK (secrets_required_cb), self);
- _nm_dbus_signal_connect (priv->proxy, "Config", G_VARIANT_TYPE ("(a{sv})"),
- G_CALLBACK (config_cb), self);
- _nm_dbus_signal_connect (priv->proxy, "Ip4Config", G_VARIANT_TYPE ("(a{sv})"),
- G_CALLBACK (ip4_config_cb), self);
- _nm_dbus_signal_connect (priv->proxy, "Ip6Config", G_VARIANT_TYPE ("(a{sv})"),
- G_CALLBACK (ip6_config_cb), self);
- _set_vpn_state (self, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
+ g_signal_connect (priv->proxy, "notify::g-name-owner",
+ G_CALLBACK (_name_owner_changed), self);
+ _name_owner_changed (G_OBJECT (priv->proxy), NULL, self);
- /* Kick off the secrets requests; first we get existing system secrets
- * and ask the plugin if these are sufficient, next we get all existing
- * secrets from system and from user agents and ask the plugin again,
- * and last we ask the user for new secrets if required.
- */
- get_secrets (self, SECRETS_REQ_SYSTEM, NULL);
+ if (priv->service_running)
+ return;
+
+ if (!nm_vpn_service_daemon_exec (self, &error)) {
+ _LOGW ("Could not launch the VPN service. error: %s.",
+ error->message);
+
+ nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE);
+ }
}
void
-nm_vpn_connection_activate (NMVpnConnection *self)
+nm_vpn_connection_activate (NMVpnConnection *self,
+ NMVpnPluginInfo *plugin_info)
{
NMVpnConnectionPrivate *priv;
NMSettingVpn *s_vpn;
+ const char *service;
g_return_if_fail (NM_IS_VPN_CONNECTION (self));
+ g_return_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info));
priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
+ g_return_if_fail (!priv->plugin_info);
s_vpn = nm_connection_get_setting_vpn (_get_applied_connection (self));
- g_assert (s_vpn);
- priv->connection_can_persist = nm_setting_vpn_get_persistent (s_vpn);
+ g_return_if_fail (s_vpn);
- _set_vpn_state (self, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
+ service = nm_setting_vpn_get_service_type (s_vpn);
+ g_return_if_fail (!g_strcmp0 (service, nm_vpn_plugin_info_get_service (plugin_info)));
+
+ if (nm_vpn_plugin_info_supports_multiple (plugin_info)) {
+ const char *path;
+
+ path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self));
+ if (path)
+ path = strrchr (path, '/');
+ g_return_if_fail (path);
+ priv->bus_name = g_strdup_printf ("%s.Connection_%s", service, &path[1]);
+ } else
+ priv->bus_name = g_strdup (service);
+
+ priv->connection_can_persist = nm_setting_vpn_get_persistent (s_vpn);
+ priv->plugin_info = g_object_ref (plugin_info);
priv->cancellable = g_cancellable_new ();
+
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
NULL,
- nm_vpn_connection_get_service (self),
+ priv->bus_name,
NM_VPN_DBUS_PLUGIN_PATH,
NM_VPN_DBUS_PLUGIN_INTERFACE,
priv->cancellable,
(GAsyncReadyCallback) on_proxy_acquired,
self);
+
+ _set_vpn_state (self, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
}
NMVpnConnectionState
@@ -2305,6 +2433,7 @@ dispose (GObject *object)
g_clear_object (&priv->ip4_config);
g_clear_object (&priv->ip6_config);
g_clear_object (&priv->proxy);
+ g_clear_object (&priv->plugin_info);
fw_call_cleanup (self);
@@ -2429,4 +2558,3 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class)
NMDBUS_TYPE_VPN_CONNECTION_SKELETON,
NULL);
}
-
diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h
index 3df324c55b..19b0eb3feb 100644
--- a/src/vpn-manager/nm-vpn-connection.h
+++ b/src/vpn-manager/nm-vpn-connection.h
@@ -26,6 +26,7 @@
#include "nm-device.h"
#include "nm-auth-subject.h"
#include "nm-active-connection.h"
+#include "nm-vpn-plugin-info.h"
#define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ())
#define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection))
@@ -75,7 +76,8 @@ NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connecti
const char *specific_object,
NMAuthSubject *subject);
-void nm_vpn_connection_activate (NMVpnConnection *self);
+void nm_vpn_connection_activate (NMVpnConnection *self,
+ NMVpnPluginInfo *plugin_info);
NMVpnConnectionState nm_vpn_connection_get_vpn_state (NMVpnConnection *self);
const char * nm_vpn_connection_get_banner (NMVpnConnection *self);
const gchar * nm_vpn_connection_get_service (NMVpnConnection *self);
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index 343997a250..f39ddf6c11 100644
--- a/src/vpn-manager/nm-vpn-manager.c
+++ b/src/vpn-manager/nm-vpn-manager.c
@@ -25,7 +25,7 @@
#include "nm-default.h"
#include "nm-vpn-manager.h"
-#include "nm-vpn-service.h"
+#include "nm-vpn-plugin-info.h"
#include "nm-vpn-connection.h"
#include "nm-setting-vpn.h"
#include "nm-vpn-dbus-interface.h"
@@ -37,26 +37,33 @@ G_DEFINE_TYPE (NMVpnManager, nm_vpn_manager, G_TYPE_OBJECT)
#define NM_VPN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_MANAGER, NMVpnManagerPrivate))
typedef struct {
- GSList *services;
+ GSList *plugins;
GFileMonitor *monitor_etc;
GFileMonitor *monitor_lib;
guint monitor_id_etc;
guint monitor_id_lib;
+
+ /* This is only used for services that don't support multiple
+ * connections, to guard access to them. */
+ GHashTable *active_services;
} NMVpnManagerPrivate;
-static NMVpnService *
-_plugin_info_get_service (NMVpnPluginInfo *plugin_info)
-{
- if (plugin_info)
- return NM_VPN_SERVICE (g_object_get_data (G_OBJECT (plugin_info), "service-instance"));
- return NULL;
-}
+/******************************************************************************/
static void
-_plugin_info_set_service (NMVpnPluginInfo *plugin_info, NMVpnService *service)
+vpn_state_changed (NMVpnConnection *vpn,
+ GParamSpec *pspec,
+ NMVpnManager *manager)
{
- g_object_set_data_full (G_OBJECT (plugin_info), "service-instance", service,
- (GDestroyNotify) g_object_unref);
+ NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
+ NMActiveConnectionState state = nm_active_connection_get_state (NM_ACTIVE_CONNECTION (vpn));
+ const char *service_name = nm_vpn_connection_get_service (vpn);
+
+ if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
+ g_hash_table_remove (priv->active_services, service_name);
+ g_signal_handlers_disconnect_by_func (vpn, vpn_state_changed, manager);
+ g_object_unref (manager);
+ }
}
gboolean
@@ -64,18 +71,16 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager,
NMVpnConnection *vpn,
GError **error)
{
- NMConnection *applied_connection;
- NMSettingVpn *s_vpn;
- NMVpnService *service;
+ NMVpnManagerPrivate *priv;
NMVpnPluginInfo *plugin_info;
const char *service_name;
NMDevice *device;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE);
g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE);
- g_return_val_if_fail (error != NULL, FALSE);
- g_return_val_if_fail (*error == NULL, FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+ priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
g_assert (device);
if ( nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED
@@ -85,60 +90,57 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager,
return FALSE;
}
- applied_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (vpn));
- s_vpn = nm_connection_get_setting_vpn (applied_connection);
- g_assert (s_vpn);
+ service_name = nm_vpn_connection_get_service (vpn);
- service_name = nm_setting_vpn_get_service_type (s_vpn);
- plugin_info = nm_vpn_plugin_info_list_find_by_service (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name);
- service = _plugin_info_get_service (plugin_info);
- if (!service) {
+ plugin_info = nm_vpn_plugin_info_list_find_by_service (priv->plugins, service_name);
+ if (!plugin_info) {
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
"The VPN service '%s' was not installed.",
service_name);
return FALSE;
}
- return nm_vpn_service_activate (service, vpn, error);
-}
+ if ( !nm_vpn_plugin_info_supports_multiple (plugin_info)
+ && g_hash_table_contains (priv->active_services, service_name)) {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
+ "The '%s' plugin only supports a single active connection.",
+ nm_vpn_plugin_info_get_name (plugin_info));
+ return FALSE;
+ }
-gboolean
-nm_vpn_manager_deactivate_connection (NMVpnManager *self,
- NMVpnConnection *connection,
- NMVpnConnectionStateReason reason)
-{
- return nm_vpn_connection_deactivate (connection, reason, FALSE);
+ nm_vpn_connection_activate (vpn, plugin_info);
+
+ if (!nm_vpn_plugin_info_supports_multiple (plugin_info)) {
+ /* Block activations of the connections of the same service type. */
+ g_hash_table_add (priv->active_services, g_strdup (service_name));
+ g_signal_connect (vpn, "notify::" NM_ACTIVE_CONNECTION_STATE,
+ G_CALLBACK (vpn_state_changed),
+ g_object_ref (manager));
+ }
+
+ return TRUE;
}
+/******************************************************************************/
+
static void
-try_add_service (NMVpnManager *self, NMVpnPluginInfo *plugin_info)
+try_add_plugin (NMVpnManager *self, NMVpnPluginInfo *plugin_info)
{
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
- NMVpnService *service = NULL;
- GError *error = NULL;
+ const char *program;
+
+ program = nm_vpn_plugin_info_get_program (plugin_info);
+ if (!program || !*program)
+ return;
/* Make sure we don't add dupes.
* We don't really allow reload of the same file. What we do allow is however to
* delete a file and re-add it. */
- if (nm_vpn_plugin_info_list_find_by_filename (priv->services,
+ if (nm_vpn_plugin_info_list_find_by_filename (priv->plugins,
nm_vpn_plugin_info_get_filename (plugin_info)))
return;
- if (!nm_vpn_plugin_info_list_add (&priv->services, plugin_info, NULL))
+ if (!nm_vpn_plugin_info_list_add (&priv->plugins, plugin_info, NULL))
return;
-
- /* New service */
- service = nm_vpn_service_new (plugin_info, &error);
- if (service) {
- _plugin_info_set_service (plugin_info, service);
- nm_log_info (LOGD_VPN, "VPN: loaded %s - %s",
- nm_vpn_plugin_info_get_name (plugin_info),
- nm_vpn_service_get_dbus_service (service));
- } else {
- nm_log_warn (LOGD_VPN, "failed to load VPN service file %s: %s",
- nm_vpn_plugin_info_get_filename (plugin_info),
- error && error->message ? error->message : "(unknown)");
- g_clear_error (&error);
- }
}
static void
@@ -151,7 +153,6 @@ vpn_dir_changed (GFileMonitor *monitor,
NMVpnManager *self = NM_VPN_MANAGER (user_data);
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
NMVpnPluginInfo *plugin_info;
- NMVpnService *service;
gs_free char *path = NULL;
GError *error = NULL;
@@ -161,25 +162,16 @@ vpn_dir_changed (GFileMonitor *monitor,
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
- plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->services, path);
+ plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->plugins, path);
if (!plugin_info)
break;
nm_log_dbg (LOGD_VPN, "vpn: service file %s deleted", path);
- service = _plugin_info_get_service (plugin_info);
- if (service) {
- /* Stop active VPN connections and destroy the service */
- nm_vpn_service_stop_connections (service, FALSE,
- NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
- nm_log_info (LOGD_VPN, "VPN: unloaded %s", nm_vpn_service_get_dbus_service (service));
-
- _plugin_info_set_service (plugin_info, NULL);
- }
- nm_vpn_plugin_info_list_remove (&priv->services, plugin_info);
+ nm_vpn_plugin_info_list_remove (&priv->plugins, plugin_info);
break;
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
- plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->services, path);
+ plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->plugins, path);
if (plugin_info) {
/* we don't support reloading an existing plugin. You can only remove the file
* and re-add it. By reloading we want to support the use case of installing
@@ -202,7 +194,7 @@ vpn_dir_changed (GFileMonitor *monitor,
}
nm_log_dbg (LOGD_VPN, "vpn: service file %s created or modified", path);
- try_add_service (self, plugin_info);
+ try_add_plugin (self, plugin_info);
g_object_unref (plugin_info);
break;
default:
@@ -247,13 +239,15 @@ nm_vpn_manager_init (NMVpnManager *self)
* In case of no-conflict, the order doesn't matter. */
infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_lib, TRUE, 0, NULL, NULL);
for (info = infos; info; info = info->next)
- try_add_service (self, info->data);
+ try_add_plugin (self, info->data);
g_slist_free_full (infos, g_object_unref);
infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_etc, TRUE, 0, NULL, NULL);
for (info = infos; info; info = info->next)
- try_add_service (self, info->data);
+ try_add_plugin (self, info->data);
g_slist_free_full (infos, g_object_unref);
+
+ priv->active_services = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
static void
@@ -275,16 +269,10 @@ dispose (GObject *object)
g_clear_object (&priv->monitor_lib);
}
- while (priv->services) {
- NMVpnPluginInfo *plugin_info = priv->services->data;
- NMVpnService *service = _plugin_info_get_service (plugin_info);
+ while (priv->plugins)
+ nm_vpn_plugin_info_list_remove (&priv->plugins, priv->plugins->data);
- if (service) {
- nm_vpn_service_stop_connections (service, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
- _plugin_info_set_service (plugin_info, NULL);
- }
- nm_vpn_plugin_info_list_remove (&priv->services, plugin_info);
- }
+ g_hash_table_unref (priv->active_services);
G_OBJECT_CLASS (nm_vpn_manager_parent_class)->dispose (object);
}
diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h
index 2034e077ad..f557e27acb 100644
--- a/src/vpn-manager/nm-vpn-manager.h
+++ b/src/vpn-manager/nm-vpn-manager.h
@@ -48,8 +48,4 @@ gboolean nm_vpn_manager_activate_connection (NMVpnManager *manager,
NMVpnConnection *vpn,
GError **error);
-gboolean nm_vpn_manager_deactivate_connection (NMVpnManager *manager,
- NMVpnConnection *connection,
- NMVpnConnectionStateReason reason);
-
#endif /* __NETWORKMANAGER_VPN_MANAGER_H__ */
diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c
deleted file mode 100644
index c96242c940..0000000000
--- a/src/vpn-manager/nm-vpn-service.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2005 - 2014 Red Hat, Inc.
- * Copyright (C) 2005 - 2008 Novell, Inc.
- */
-
-#include "config.h"
-
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <unistd.h>
-
-#include "nm-default.h"
-#include "nm-vpn-service.h"
-#include "nm-vpn-manager.h"
-
-G_DEFINE_TYPE (NMVpnService, nm_vpn_service, G_TYPE_OBJECT)
-
-typedef struct {
- NMVpnPluginInfo *plugin_info;
-
- NMVpnConnection *active;
- GSList *pending;
-
- guint start_timeout;
- GDBusProxy *proxy;
- gboolean service_running;
-} NMVpnServicePrivate;
-
-#define NM_VPN_SERVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_SERVICE, NMVpnServicePrivate))
-
-static gboolean start_pending_vpn (NMVpnService *self, GError **error);
-
-static void _name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
-
-NMVpnService *
-nm_vpn_service_new (NMVpnPluginInfo *plugin_info, GError **error)
-{
- NMVpnService *self;
- NMVpnServicePrivate *priv;
-
- g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info), NULL);
- g_return_val_if_fail (nm_vpn_plugin_info_get_filename (plugin_info), NULL);
-
- if (!nm_vpn_plugin_info_get_program (plugin_info)) {
- g_set_error (error,
- NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_FAILED,
- "missing \"program\" entry");
- return NULL;
- }
-
- self = (NMVpnService *) g_object_new (NM_TYPE_VPN_SERVICE, NULL);
- priv = NM_VPN_SERVICE_GET_PRIVATE (self);
- priv->plugin_info = g_object_ref (plugin_info);
-
- priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
- G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
- NULL,
- nm_vpn_plugin_info_get_service (plugin_info),
- NM_VPN_DBUS_PLUGIN_PATH,
- NM_VPN_DBUS_PLUGIN_INTERFACE,
- NULL, error);
- if (!priv->proxy) {
- g_object_unref (self);
- return NULL;
- }
-
- g_signal_connect (priv->proxy, "notify::g-name-owner",
- G_CALLBACK (_name_owner_changed), self);
- _name_owner_changed (G_OBJECT (priv->proxy), NULL, self);
-
- return self;
-}
-
-const char *
-nm_vpn_service_get_dbus_service (NMVpnService *service)
-{
- g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL);
-
- return nm_vpn_plugin_info_get_service (NM_VPN_SERVICE_GET_PRIVATE (service)->plugin_info);
-}
-
-static void
-connection_vpn_state_changed (NMVpnConnection *connection,
- NMVpnConnectionState new_state,
- NMVpnConnectionState old_state,
- NMVpnConnectionStateReason reason,
- gpointer user_data)
-{
- NMVpnService *self = NM_VPN_SERVICE (user_data);
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
-
- if (new_state == NM_VPN_CONNECTION_STATE_FAILED ||
- new_state == NM_VPN_CONNECTION_STATE_DISCONNECTED) {
- g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_vpn_state_changed), self);
- if (connection == priv->active) {
- priv->active = NULL;
- start_pending_vpn (self, NULL);
- } else
- priv->pending = g_slist_remove (priv->pending, connection);
- g_object_unref (connection);
- }
-}
-
-void
-nm_vpn_service_stop_connections (NMVpnService *service,
- gboolean quitting,
- NMVpnConnectionStateReason reason)
-{
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service);
- GSList *iter;
-
- /* Just add priv->active to the beginning of priv->pending,
- * since we're going to clear priv->pending immediately anyway.
- */
- if (priv->active) {
- priv->pending = g_slist_prepend (priv->pending, priv->active);
- priv->active = NULL;
- }
-
- for (iter = priv->pending; iter; iter = iter->next) {
- NMVpnConnection *vpn = NM_VPN_CONNECTION (iter->data);
-
- g_signal_handlers_disconnect_by_func (vpn, G_CALLBACK (connection_vpn_state_changed), service);
- if (quitting) {
- /* Deactivate to allow pre-down before disconnecting */
- nm_vpn_connection_deactivate (vpn, reason, quitting);
- }
- nm_vpn_connection_disconnect (vpn, reason, quitting);
- g_object_unref (vpn);
- }
- g_clear_pointer (&priv->pending, g_slist_free);
-}
-
-static gboolean
-_daemon_exec_timeout (gpointer data)
-{
- NMVpnService *self = NM_VPN_SERVICE (data);
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
-
- nm_log_warn (LOGD_VPN, "VPN service '%s' start timed out", nm_vpn_plugin_info_get_name (priv->plugin_info));
- priv->start_timeout = 0;
- nm_vpn_service_stop_connections (self, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT);
- return G_SOURCE_REMOVE;
-}
-
-static gboolean
-nm_vpn_service_daemon_exec (NMVpnService *service, GError **error)
-{
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service);
- GPid pid;
- char *vpn_argv[2];
- gboolean success = FALSE;
- GError *spawn_error = NULL;
-
- g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE);
-
- vpn_argv[0] = (char *) nm_vpn_plugin_info_get_program (priv->plugin_info);
- vpn_argv[1] = NULL;
-
- g_assert (vpn_argv[0]);
-
- success = g_spawn_async (NULL, vpn_argv, NULL, 0, nm_utils_setpgid, NULL, &pid, &spawn_error);
- if (success) {
- nm_log_info (LOGD_VPN, "VPN service '%s' started (%s), PID %ld",
- nm_vpn_plugin_info_get_name (priv->plugin_info),
- nm_vpn_service_get_dbus_service (service),
- (long int) pid);
- priv->start_timeout = g_timeout_add_seconds (5, _daemon_exec_timeout, service);
- } else {
- nm_log_warn (LOGD_VPN, "VPN service '%s': could not launch the VPN service. error: (%d) %s.",
- nm_vpn_plugin_info_get_name (priv->plugin_info),
- spawn_error ? spawn_error->code : -1,
- spawn_error && spawn_error->message ? spawn_error->message : "(unknown)");
-
- g_set_error (error,
- NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
- "%s", spawn_error ? spawn_error->message : "unknown g_spawn_async() error");
-
- nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED);
- if (spawn_error)
- g_error_free (spawn_error);
- }
-
- return success;
-}
-
-static gboolean
-start_active_vpn (NMVpnService *self, GError **error)
-{
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
-
- if (!priv->active)
- return TRUE;
-
- if (priv->service_running) {
- /* Just activate the VPN */
- nm_vpn_connection_activate (priv->active);
- return TRUE;
- } else if (priv->start_timeout == 0) {
- /* VPN service not running, start it */
- nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", nm_vpn_plugin_info_get_name (priv->plugin_info));
- return nm_vpn_service_daemon_exec (self, error);
- }
-
- /* Already started VPN service, waiting for it to appear on D-Bus */
- return TRUE;
-}
-
-static gboolean
-start_pending_vpn (NMVpnService *self, GError **error)
-{
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
-
- g_assert (priv->active == NULL);
-
- if (!priv->pending)
- return TRUE;
-
- /* Make next VPN active */
- priv->active = g_slist_nth_data (priv->pending, 0);
- priv->pending = g_slist_remove (priv->pending, priv->active);
-
- return start_active_vpn (self, error);
-}
-
-gboolean
-nm_vpn_service_activate (NMVpnService *service,
- NMVpnConnection *vpn,
- GError **error)
-{
- NMVpnServicePrivate *priv;
-
- g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE);
- g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE);
- g_return_val_if_fail (error != NULL, FALSE);
- g_return_val_if_fail (*error == NULL, FALSE);
-
- priv = NM_VPN_SERVICE_GET_PRIVATE (service);
-
- g_signal_connect (vpn, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
- G_CALLBACK (connection_vpn_state_changed),
- service);
-
- /* Queue up the new VPN connection */
- priv->pending = g_slist_append (priv->pending, g_object_ref (vpn));
-
- /* Tell the active VPN to deactivate and wait for it to quit before we
- * start the next VPN. The just-queued VPN will then be started from
- * connection_vpn_state_changed().
- */
- if (priv->active) {
- nm_vpn_connection_deactivate (priv->active, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED, FALSE);
- return TRUE;
- }
-
- /* Otherwise start the next VPN */
- return start_pending_vpn (service, error);
-}
-
-static void
-_name_owner_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- NMVpnService *service = NM_VPN_SERVICE (user_data);
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service);
- gboolean success;
- char *owner;
-
- owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object));
-
- /* Service changed, no need to wait for the timeout any longer */
- if (priv->start_timeout) {
- g_source_remove (priv->start_timeout);
- priv->start_timeout = 0;
- }
-
- if (owner && !priv->service_running) {
- /* service appeared */
- priv->service_running = TRUE;
- nm_log_info (LOGD_VPN, "VPN service '%s' appeared; activating connections", nm_vpn_plugin_info_get_name (priv->plugin_info));
- /* Expect success because the VPN service has already appeared */
- success = start_active_vpn (service, NULL);
- g_warn_if_fail (success);
- } else if (!owner && priv->service_running) {
- /* service went away */
- priv->service_running = FALSE;
- nm_log_info (LOGD_VPN, "VPN service '%s' disappeared", nm_vpn_plugin_info_get_name (priv->plugin_info));
- nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
- }
-
- g_free (owner);
-}
-
-/******************************************************************************/
-
-static void
-nm_vpn_service_init (NMVpnService *self)
-{
-}
-
-static void
-dispose (GObject *object)
-{
- NMVpnService *self = NM_VPN_SERVICE (object);
- NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
-
- nm_clear_g_source (&priv->start_timeout);
-
- g_clear_object (&priv->plugin_info);
-
- /* VPNService owner is required to stop connections before releasing */
- g_assert (priv->active == NULL);
- g_assert (priv->pending == NULL);
-
- if (priv->proxy) {
- g_signal_handlers_disconnect_by_func (priv->proxy,
- G_CALLBACK (_name_owner_changed),
- self);
- g_clear_object (&priv->proxy);
- }
-
- G_OBJECT_CLASS (nm_vpn_service_parent_class)->dispose (object);
-}
-
-static void
-nm_vpn_service_class_init (NMVpnServiceClass *service_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (service_class);
-
- g_type_class_add_private (service_class, sizeof (NMVpnServicePrivate));
-
- /* virtual methods */
- object_class->dispose = dispose;
-}
diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h
deleted file mode 100644
index c43d7cd428..0000000000
--- a/src/vpn-manager/nm-vpn-service.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2005 - 2011 Red Hat, Inc.
- * Copyright (C) 2005 - 2008 Novell, Inc.
- */
-
-#ifndef __NETWORKMANAGER_VPN_SERVICE_H__
-#define __NETWORKMANAGER_VPN_SERVICE_H__
-
-#include "nm-default.h"
-#include "nm-device.h"
-#include "nm-vpn-connection.h"
-#include "nm-vpn-plugin-info.h"
-
-#define NM_TYPE_VPN_SERVICE (nm_vpn_service_get_type ())
-#define NM_VPN_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_SERVICE, NMVpnService))
-#define NM_VPN_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_SERVICE, NMVpnServiceClass))
-#define NM_IS_VPN_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_SERVICE))
-#define NM_IS_VPN_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_SERVICE))
-#define NM_VPN_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_SERVICE, NMVpnServiceClass))
-
-typedef struct {
- GObject parent;
-} NMVpnService;
-
-typedef struct {
- GObjectClass parent;
-} NMVpnServiceClass;
-
-GType nm_vpn_service_get_type (void);
-
-NMVpnService * nm_vpn_service_new (NMVpnPluginInfo *plugin_info, GError **error);
-
-/* Returns the VPN service's D-Bus service name */
-const char *nm_vpn_service_get_dbus_service (NMVpnService *service);
-
-gboolean nm_vpn_service_activate (NMVpnService *service,
- NMVpnConnection *vpn,
- GError **error);
-
-void nm_vpn_service_stop_connections (NMVpnService *service,
- gboolean quitting,
- NMVpnConnectionStateReason reason);
-
-#endif /* NM_VPN_VPN_SERVICE_H */