From d1095e00cbc132dc4795eda73de1f87462b6b131 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 May 2014 18:38:04 -0500 Subject: [PATCH] vpn: stop all connections of a service outside of dispose Future patches will allow blocking dispatcher calls, which we don't want to happen when deactivating a VPN connection during normal operation. So move code that stops VPN connections outside of the VPNService object's dispose() function and require the object that owns the VPNService (the VPNManager) to stop connections at the right times. When quitting, blocking calls are acceptable (because NetworkManager's D-Bus interface is no longer useful, plus we can't easily schedule callbacks because no mainloop is running), so it's ok to stop connections from NMVPNManager:dispose. --- src/vpn-manager/nm-vpn-manager.c | 18 +++++++++++++++++- src/vpn-manager/nm-vpn-service.c | 19 ++++++++++--------- src/vpn-manager/nm-vpn-service.h | 4 ++-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index 276dd03658..00ce4e8f52 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -186,7 +186,7 @@ vpn_dir_changed (GFileMonitor *monitor, const char *service_name = nm_vpn_service_get_dbus_service (service); /* Stop active VPN connections and destroy the service */ - nm_vpn_service_connections_stop (service, TRUE, + nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); nm_log_info (LOGD_VPN, "VPN: unloaded %s", service_name); g_hash_table_remove (priv->services, service_name); @@ -257,6 +257,21 @@ nm_vpn_manager_init (NMVPNManager *self) } } +static void +stop_all_services (NMVPNManager *self) +{ + NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + NMVPNService *service; + + g_hash_table_iter_init (&iter, priv->services); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &service)) { + nm_vpn_service_stop_connections (service, + TRUE, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); + } +} + static void dispose (GObject *object) { @@ -270,6 +285,7 @@ dispose (GObject *object) } if (priv->services) { + stop_all_services (NM_VPN_MANAGER (object)); g_hash_table_destroy (priv->services); priv->services = NULL; } diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c index ac329422f4..3752797fb8 100644 --- a/src/vpn-manager/nm-vpn-service.c +++ b/src/vpn-manager/nm-vpn-service.c @@ -138,8 +138,8 @@ connection_vpn_state_changed (NMVPNConnection *connection, } void -nm_vpn_service_connections_stop (NMVPNService *service, - gboolean fail, +nm_vpn_service_stop_connections (NMVPNService *service, + gboolean quitting, NMVPNConnectionStateReason reason) { NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service); @@ -157,7 +157,8 @@ nm_vpn_service_connections_stop (NMVPNService *service, NMVPNConnection *vpn = NM_VPN_CONNECTION (iter->data); g_signal_handlers_disconnect_by_func (vpn, G_CALLBACK (connection_vpn_state_changed), service); - nm_vpn_connection_stop (vpn, fail, reason); + /* Quitting terminates the VPN cleanly, otherwise failure is assumed */ + nm_vpn_connection_stop (vpn, quitting ? FALSE : TRUE, reason); g_object_unref (vpn); } g_clear_pointer (&priv->pending, g_slist_free); @@ -185,7 +186,7 @@ _daemon_exec_timeout (gpointer data) nm_log_warn (LOGD_VPN, "VPN service '%s' start timed out", priv->name); priv->start_timeout = 0; - nm_vpn_service_connections_stop (self, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT); + nm_vpn_service_stop_connections (self, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT); return G_SOURCE_REMOVE; } @@ -218,7 +219,7 @@ nm_vpn_service_daemon_exec (NMVPNService *service, GError **error) NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_START_FAILED, "%s", spawn_error ? spawn_error->message : "unknown g_spawn_async() error"); - nm_vpn_service_connections_stop (service, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED); + nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED); if (spawn_error) g_error_free (spawn_error); } @@ -333,7 +334,7 @@ _name_owner_changed (NMDBusManager *mgr, /* service went away */ priv->service_running = FALSE; nm_log_info (LOGD_VPN, "VPN service '%s' disappeared", priv->name); - nm_vpn_service_connections_stop (service, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); + nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); } } @@ -359,9 +360,9 @@ dispose (GObject *object) priv->start_timeout = 0; } - nm_vpn_service_connections_stop (NM_VPN_SERVICE (object), - FALSE, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); + /* VPNService owner is required to stop connections before releasing */ + g_assert (priv->active == NULL); + g_assert (priv->pending == NULL); g_signal_handlers_disconnect_by_func (nm_dbus_manager_get (), G_CALLBACK (_name_owner_changed), diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h index 1edde7b526..4545d1f07d 100644 --- a/src/vpn-manager/nm-vpn-service.h +++ b/src/vpn-manager/nm-vpn-service.h @@ -56,8 +56,8 @@ gboolean nm_vpn_service_activate (NMVPNService *service, NMVPNConnection *vpn, GError **error); -void nm_vpn_service_connections_stop (NMVPNService *service, - gboolean fail, +void nm_vpn_service_stop_connections (NMVPNService *service, + gboolean quitting, NMVPNConnectionStateReason reason); #endif /* NM_VPN_VPN_SERVICE_H */