summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/vpn-manager/nm-vpn-connection.c177
-rw-r--r--src/vpn-manager/nm-vpn-connection.h5
-rw-r--r--src/vpn-manager/nm-vpn-manager.c128
-rw-r--r--src/vpn-manager/nm-vpn-service.c356
-rw-r--r--src/vpn-manager/nm-vpn-service.h60
6 files changed, 215 insertions, 513 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0a60fb9745..734f4d62b3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -297,8 +297,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/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 4016a493d3..47717fb679 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -42,6 +42,8 @@
#include "nm-default-route-manager.h"
#include "nm-route-manager.h"
#include "nm-firewall-manager.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 */
NMFirewallPendingCall fw_call;
@@ -276,6 +282,9 @@ vpn_cleanup (NMVpnConnection *connection, 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.
*/
@@ -1750,6 +1759,116 @@ 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;
+ nm_log_info (LOGD_VPN, "VPN connection '%s' saw the service appear; activating connection",
+ nm_connection_get_id (priv->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;
+ nm_log_info (LOGD_VPN, "VPN connection '%s' service disappeared",
+ nm_vpn_connection_get_connection_id (self));
+ 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);
+
+ nm_log_warn (LOGD_VPN, "VPN connection '%s' timed out waiting for the service to start",
+ nm_vpn_connection_get_connection_id (self));
+ 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) {
+ nm_log_info (LOGD_VPN, "VPN connection '%s' started the service, PID %ld",
+ nm_vpn_connection_get_connection_id (self),
+ (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;
@@ -1777,36 +1896,32 @@ 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)) {
+ nm_log_warn (LOGD_VPN, "VPN connection '%s': could not launch the VPN service. error: %s.",
+ nm_vpn_connection_get_connection_id (self),
+ error->message);
+
+ nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE);
+ }
}
-void
-nm_vpn_connection_activate (NMVpnConnection *self)
+gboolean
+nm_vpn_connection_activate (NMVpnConnection *self,
+ NMVpnPluginInfo *plugin_info,
+ GError **error)
{
NMVpnConnectionPrivate *priv;
NMSettingVpn *s_vpn;
- g_return_if_fail (NM_IS_VPN_CONNECTION (self));
+ g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), FALSE);
priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
@@ -1814,18 +1929,30 @@ nm_vpn_connection_activate (NMVpnConnection *self)
g_assert (s_vpn);
priv->connection_can_persist = nm_setting_vpn_get_persistent (s_vpn);
- _set_vpn_state (self, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
+ priv->plugin_info = g_object_ref (plugin_info);
+ if (nm_vpn_plugin_info_supports_multiple (priv->plugin_info)) {
+ priv->bus_name = g_strdup_printf ("%s.%s",
+ nm_vpn_connection_get_service (self),
+ nm_connection_get_uuid (priv->connection));
+ } else {
+ priv->bus_name = g_strdup (nm_vpn_connection_get_service (self));
+ }
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);
+
+ return TRUE;
}
NMConnection *
@@ -2250,6 +2377,7 @@ dispose (GObject *object)
g_clear_object (&priv->connection);
g_clear_object (&priv->default_route_manager);
g_clear_object (&priv->route_manager);
+ g_clear_object (&priv->plugin_info);
fw_call_cleanup (NM_VPN_CONNECTION (object));
@@ -2372,4 +2500,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 a41c2630f4..46e62c9727 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,9 @@ NMVpnConnection * nm_vpn_connection_new (NMConnection *connection,
const char *specific_object,
NMAuthSubject *subject);
-void nm_vpn_connection_activate (NMVpnConnection *connection);
+gboolean nm_vpn_connection_activate (NMVpnConnection *connection,
+ NMVpnPluginInfo *plugin_info,
+ GError **error);
NMConnection * nm_vpn_connection_get_connection (NMVpnConnection *connection);
const char* nm_vpn_connection_get_connection_id (NMVpnConnection *connection);
NMVpnConnectionState nm_vpn_connection_get_vpn_state (NMVpnConnection *connection);
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index d7947b4621..9b1db587f4 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,31 @@ 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;
-} 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;
-}
+ /* This is only used for services that don't support multiple
+ * connections, to guard access to them. */
+ GHashTable *active_services;
+} NMVpnManagerPrivate;
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,9 +69,7 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager,
NMVpnConnection *vpn,
GError **error)
{
- NMConnection *connection;
- NMSettingVpn *s_vpn;
- NMVpnService *service;
+ NMVpnManagerPrivate *priv;
NMVpnPluginInfo *plugin_info;
const char *service_name;
NMDevice *device;
@@ -76,6 +79,7 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager,
g_return_val_if_fail (error != NULL, FALSE);
g_return_val_if_fail (*error == NULL, 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,22 +89,36 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager,
return FALSE;
}
- connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn));
- g_assert (connection);
- s_vpn = nm_connection_get_setting_vpn (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_lookup (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;
+ }
+
+ if (!nm_vpn_connection_activate (vpn, plugin_info, error))
+ return FALSE;
+
+ if (!nm_vpn_plugin_info_supports_multiple (plugin_info)) {
+ /* Block activations of the connections of the same service type. */
+ g_hash_table_insert (priv->active_services, g_strdup (service_name), g_object_ref (vpn));
+ g_signal_connect (vpn, "notify::" NM_ACTIVE_CONNECTION_STATE,
+ G_CALLBACK (vpn_state_changed),
+ g_object_ref (manager));
+ }
+
+ return TRUE;
}
gboolean
@@ -112,34 +130,18 @@ nm_vpn_manager_deactivate_connection (NMVpnManager *self,
}
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;
/* 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
@@ -152,7 +154,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;
@@ -162,25 +163,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
@@ -203,7 +195,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:
@@ -248,13 +240,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, g_object_unref);
}
static void
@@ -276,17 +270,13 @@ 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);
-
- 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);
+ while (priv->plugins) {
+ NMVpnPluginInfo *plugin_info = priv->plugins->data;
+ nm_vpn_plugin_info_list_remove (&priv->plugins, 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-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 */