diff options
Diffstat (limited to 'src/vpn-manager/nm-vpn-manager.c')
-rw-r--r-- | src/vpn-manager/nm-vpn-manager.c | 128 |
1 files changed, 59 insertions, 69 deletions
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); } |