Commit e1ec6a51 authored by Dan Williams's avatar Dan Williams

vpn: implement PRE_DOWN dispatcher actions (bgo #387832)

https://bugzilla.gnome.org/show_bug.cgi?id=387832
parent 27cb927d
......@@ -84,7 +84,7 @@ typedef struct {
char *username;
VpnState vpn_state;
guint deactivating_idle_id;
guint dispatcher_id;
NMVPNConnectionStateReason failure_reason;
DBusGProxy *proxy;
......@@ -137,7 +137,8 @@ static void plugin_interactive_secrets_required (DBusGProxy *proxy,
static void _set_vpn_state (NMVPNConnection *connection,
VpnState vpn_state,
NMVPNConnectionStateReason reason);
NMVPNConnectionStateReason reason,
gboolean quitting);
/*********************************************************************/
......@@ -245,32 +246,32 @@ vpn_cleanup (NMVPNConnection *connection, NMDevice *parent_dev)
nm_connection_clear_secrets (priv->connection);
}
static gboolean
deactivating_to_disconnected (gpointer user_data)
static void
dispatcher_pre_down_done (guint call_id, gpointer user_data)
{
NMVPNConnection *self = NM_VPN_CONNECTION (user_data);
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
priv->deactivating_idle_id = 0;
_set_vpn_state (self, STATE_DISCONNECTED, NM_VPN_CONNECTION_STATE_REASON_NONE);
return G_SOURCE_REMOVE;
priv->dispatcher_id = 0;
_set_vpn_state (self, STATE_DISCONNECTED, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
}
static void
clear_deactivating_idle (NMVPNConnection *self)
dispatcher_cleanup (NMVPNConnection *self)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
if (priv->deactivating_idle_id) {
g_source_remove (priv->deactivating_idle_id);
priv->deactivating_idle_id = 0;
if (priv->dispatcher_id) {
nm_dispatcher_call_cancel (priv->dispatcher_id);
priv->dispatcher_id = 0;
}
}
static void
_set_vpn_state (NMVPNConnection *connection,
VpnState vpn_state,
NMVPNConnectionStateReason reason)
NMVPNConnectionStateReason reason,
gboolean quitting)
{
NMVPNConnectionPrivate *priv;
VpnState old_vpn_state;
......@@ -303,7 +304,7 @@ _set_vpn_state (NMVPNConnection *connection,
priv->secrets_id = 0;
}
clear_deactivating_idle (connection);
dispatcher_cleanup (connection);
/* The connection gets destroyed by the VPN manager when it enters the
* disconnected/failed state, but we need to keep it around for a bit
......@@ -345,7 +346,27 @@ _set_vpn_state (NMVPNConnection *connection,
NULL);
break;
case STATE_DEACTIVATING:
priv->deactivating_idle_id = g_idle_add (deactivating_to_disconnected, connection);
if (quitting) {
nm_dispatcher_call_vpn_sync (DISPATCHER_ACTION_VPN_PRE_DOWN,
priv->connection,
parent_dev,
priv->ip_iface,
priv->ip4_config,
priv->ip6_config);
} else {
if (!nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_PRE_DOWN,
priv->connection,
parent_dev,
priv->ip_iface,
priv->ip4_config,
priv->ip6_config,
dispatcher_pre_down_done,
connection,
&priv->dispatcher_id)) {
/* Just proceed on errors */
dispatcher_pre_down_done (0, connection);
}
}
break;
case STATE_FAILED:
case STATE_DISCONNECTED:
......@@ -386,11 +407,13 @@ device_state_changed (NMActiveConnection *active,
if (new_state <= NM_DEVICE_STATE_DISCONNECTED) {
_set_vpn_state (NM_VPN_CONNECTION (active),
STATE_DISCONNECTED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED,
FALSE);
} else if (new_state == NM_DEVICE_STATE_FAILED) {
_set_vpn_state (NM_VPN_CONNECTION (active),
STATE_FAILED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED,
FALSE);
}
/* FIXME: map device DEACTIVATING state to VPN DEACTIVATING state and
......@@ -665,7 +688,7 @@ plugin_state_changed (DBusGProxy *proxy,
case STATE_ACTIVATED:
nm_log_info (LOGD_VPN, "VPN plugin state change reason: %s (%d)",
vpn_reason_to_string (priv->failure_reason), priv->failure_reason);
_set_vpn_state (connection, STATE_FAILED, priv->failure_reason);
_set_vpn_state (connection, STATE_FAILED, priv->failure_reason, FALSE);
/* Reset the failure reason */
priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_UNKNOWN;
......@@ -836,7 +859,7 @@ nm_vpn_connection_apply_config (NMVPNConnection *connection)
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
nm_connection_get_id (priv->connection));
_set_vpn_state (connection, STATE_ACTIVATED, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, STATE_ACTIVATED, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
return TRUE;
}
......@@ -876,7 +899,7 @@ nm_vpn_connection_config_maybe_complete (NMVPNConnection *connection,
nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.",
nm_connection_get_id (priv->connection));
_set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID);
_set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE);
}
#define LOG_INVALID_ARG(property) \
......@@ -971,7 +994,7 @@ nm_vpn_connection_config_get (DBusGProxy *proxy,
nm_connection_get_id (priv->connection));
if (priv->vpn_state == STATE_CONNECT)
_set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
if (!process_generic_config (connection, config_hash))
return;
......@@ -1025,7 +1048,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
int i;
if (priv->vpn_state == STATE_CONNECT)
_set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
if (priv->has_ip4) {
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received.",
......@@ -1181,7 +1204,7 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
nm_connection_get_id (priv->connection));
if (priv->vpn_state == STATE_CONNECT)
_set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
if (g_hash_table_size (config_hash) == 0) {
priv->has_ip6 = FALSE;
......@@ -1322,7 +1345,7 @@ connect_timeout_cb (gpointer user_data)
priv->vpn_state == STATE_IP_CONFIG_GET) {
nm_log_warn (LOGD_VPN, "VPN connection '%s' connect timeout exceeded.",
nm_connection_get_id (priv->connection));
_set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT);
_set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE);
}
return FALSE;
......@@ -1359,7 +1382,7 @@ connect_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect: '%s'.",
nm_connection_get_id (priv->connection), err->message);
g_error_free (err);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE);
}
static void
......@@ -1388,7 +1411,7 @@ connect_interactive_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data
nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect interactively: '%s'.",
nm_connection_get_id (priv->connection), err->message);
g_error_free (err);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE);
}
}
......@@ -1483,7 +1506,7 @@ really_activate (NMVPNConnection *connection, const char *username)
g_object_unref (agent_mgr);
g_hash_table_destroy (details);
_set_vpn_state (connection, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
}
void
......@@ -1496,7 +1519,7 @@ nm_vpn_connection_activate (NMVPNConnection *connection)
priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
_set_vpn_state (connection, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
bus = nm_dbus_manager_get_connection (nm_dbus_manager_get ());
priv->proxy = dbus_g_proxy_new_for_name (bus,
......@@ -1522,7 +1545,7 @@ nm_vpn_connection_activate (NMVPNConnection *connection)
G_CALLBACK (plugin_interactive_secrets_required),
connection, NULL);
_set_vpn_state (connection, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, 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
......@@ -1605,18 +1628,19 @@ nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection)
}
void
nm_vpn_connection_stop (NMVPNConnection *connection,
gboolean fail,
NMVPNConnectionStateReason reason)
nm_vpn_connection_disconnect (NMVPNConnection *connection,
NMVPNConnectionStateReason reason,
gboolean quitting)
{
g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
_set_vpn_state (connection, fail ? STATE_FAILED : STATE_DISCONNECTED, reason);
_set_vpn_state (connection, STATE_DISCONNECTED, reason, quitting);
}
gboolean
nm_vpn_connection_deactivate (NMVPNConnection *connection,
NMVPNConnectionStateReason reason)
NMVPNConnectionStateReason reason,
gboolean quitting)
{
NMVPNConnectionPrivate *priv;
gboolean success = FALSE;
......@@ -1625,7 +1649,7 @@ nm_vpn_connection_deactivate (NMVPNConnection *connection,
priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
if (priv->vpn_state > STATE_UNKNOWN && priv->vpn_state <= STATE_DEACTIVATING) {
_set_vpn_state (connection, STATE_DEACTIVATING, reason);
_set_vpn_state (connection, STATE_DEACTIVATING, reason, quitting);
success = TRUE;
}
return success;
......@@ -1651,7 +1675,7 @@ plugin_need_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_dat
priv->secrets_idx + 1,
g_quark_to_string (error->domain),
error->message);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE);
g_error_free (error);
return;
}
......@@ -1663,7 +1687,7 @@ plugin_need_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_dat
nm_log_err (LOGD_VPN, "(%s/%s) final secrets request failed to provide sufficient secrets",
nm_connection_get_uuid (priv->connection),
nm_connection_get_id (priv->connection));
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE);
} else {
nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional secrets required",
nm_connection_get_uuid (priv->connection),
......@@ -1695,7 +1719,7 @@ plugin_new_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data
nm_connection_get_id (priv->connection),
g_quark_to_string (error->domain),
error->message);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE);
g_error_free (error);
}
}
......@@ -1720,7 +1744,7 @@ get_secrets_cb (NMSettingsConnection *connection,
if (error) {
nm_log_err (LOGD_VPN, "Failed to request VPN secrets #%d: (%d) %s",
priv->secrets_idx + 1, error->code, error->message);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE);
} else {
/* Cache the username for later */
if (agent_username) {
......@@ -1804,7 +1828,7 @@ get_secrets (NMVPNConnection *self,
nm_log_err (LOGD_VPN, "failed to request VPN secrets #%d: (%d) %s",
priv->secrets_idx + 1, error->code, error->message);
}
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS);
_set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE);
g_clear_error (&error);
}
}
......@@ -1828,7 +1852,7 @@ plugin_interactive_secrets_required (DBusGProxy *proxy,
priv->vpn_state == STATE_NEED_AUTH);
priv->secrets_idx = SECRETS_REQ_INTERACTIVE;
_set_vpn_state (connection, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE);
_set_vpn_state (connection, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
/* Copy hints and add message to the end */
hints = g_malloc0 (sizeof (char *) * (secrets_len + 2));
......@@ -1878,7 +1902,7 @@ dispose (GObject *object)
priv->connect_timeout = 0;
}
clear_deactivating_idle (NM_VPN_CONNECTION (object));
dispatcher_cleanup (NM_VPN_CONNECTION (object));
if (priv->secrets_id) {
nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection),
......
......@@ -76,10 +76,11 @@ NMVPNConnectionState nm_vpn_connection_get_vpn_state (NMVPNConnection *connect
const char * nm_vpn_connection_get_banner (NMVPNConnection *connection);
gboolean nm_vpn_connection_deactivate (NMVPNConnection *connection,
NMVPNConnectionStateReason reason);
void nm_vpn_connection_stop (NMVPNConnection *connection,
gboolean fail,
NMVPNConnectionStateReason reason);
NMVPNConnectionStateReason reason,
gboolean quitting);
void nm_vpn_connection_disconnect (NMVPNConnection *connection,
NMVPNConnectionStateReason reason,
gboolean quitting);
NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connection);
NMIP6Config * nm_vpn_connection_get_ip6_config (NMVPNConnection *connection);
......
......@@ -123,7 +123,7 @@ nm_vpn_manager_deactivate_connection (NMVPNManager *self,
NMVPNConnection *connection,
NMVPNConnectionStateReason reason)
{
return nm_vpn_connection_deactivate (connection, reason);
return nm_vpn_connection_deactivate (connection, reason, FALSE);
}
static void
......
......@@ -157,8 +157,11 @@ nm_vpn_service_stop_connections (NMVPNService *service,
NMVPNConnection *vpn = NM_VPN_CONNECTION (iter->data);
g_signal_handlers_disconnect_by_func (vpn, G_CALLBACK (connection_vpn_state_changed), service);
/* Quitting terminates the VPN cleanly, otherwise failure is assumed */
nm_vpn_connection_stop (vpn, quitting ? FALSE : TRUE, reason);
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);
......@@ -292,7 +295,7 @@ nm_vpn_service_activate (NMVPNService *service,
* connection_vpn_state_changed().
*/
if (priv->active) {
nm_vpn_connection_deactivate (priv->active, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
nm_vpn_connection_deactivate (priv->active, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED, FALSE);
return TRUE;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment