diff --git a/src/nm-policy.c b/src/nm-policy.c index e3c899f5e3..44f5e1f930 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -76,6 +76,7 @@ struct NMPolicy { #define RETRIES_DEFAULT 4 #define RESET_RETRIES_TIMESTAMP_TAG "reset-retries-timestamp-tag" #define RESET_RETRIES_TIMER 300 +#define FAILURE_REASON_TAG "failure-reason" static NMDevice * get_best_ip4_device (NMManager *manager, NMActRequest **out_req) @@ -837,6 +838,23 @@ reset_retries_all (NMSettings *settings, NMDevice *device) g_slist_free (connections); } +static void +reset_retries_for_failed_secrets (NMSettings *settings) +{ + GSList *connections, *iter; + + connections = nm_settings_get_connections (settings); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMDeviceStateReason reason = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (iter->data), FAILURE_REASON_TAG)); + + if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) { + set_connection_auto_retries (NM_CONNECTION (iter->data), RETRIES_DEFAULT); + g_object_set_data (G_OBJECT (iter->data), FAILURE_REASON_TAG, GUINT_TO_POINTER (0)); + } + } + g_slist_free (connections); +} + static void sleeping_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) { @@ -927,6 +945,9 @@ device_state_changed (NMDevice *device, NMPolicy *policy = (NMPolicy *) user_data; NMConnection *connection = get_device_connection (device); + if (connection) + g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (0)); + switch (new_state) { case NM_DEVICE_STATE_FAILED: /* Mark the connection invalid if it failed during activation so that @@ -941,6 +962,11 @@ device_state_changed (NMDevice *device, * automatically retrying because it's just going to fail anyway. */ set_connection_auto_retries (connection, 0); + + /* Mark the connection as failed due to missing secrets so that we can reset + * RETRIES_TAG and automatically re-try when an secret agent registers. + */ + g_object_set_data (G_OBJECT (connection), FAILURE_REASON_TAG, GUINT_TO_POINTER (NM_DEVICE_STATE_REASON_NO_SECRETS)); } else if (tries > 0) { /* Otherwise if it's a random failure, just decrease the number * of automatic retries so that the connection gets tried again @@ -1172,6 +1198,19 @@ connection_visibility_changed (NMSettings *settings, _deactivate_if_active (policy->manager, NM_CONNECTION (connection)); } +static void +secret_agent_registered (NMSettings *settings, + NMSecretAgent *agent, + gpointer user_data) +{ + /* The registered secret agent may provide some missing secrets. Thus we + * reset retries count here and schedule activation, so that the + * connections failed due to missing secrets may re-try auto-connection. + */ + reset_retries_for_failed_secrets (settings); + schedule_activate_all ((NMPolicy *) user_data); +} + static void _connect_manager_signal (NMPolicy *policy, const char *name, gpointer callback) { @@ -1240,6 +1279,7 @@ nm_policy_new (NMManager *manager, _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, connection_removed); _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, connection_visibility_changed); + _connect_settings_signal (policy, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, secret_agent_registered); /* Initialize connections' auto-retries */ reset_retries_all (policy->settings, NULL); diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 9b9e1897b5..1693ae25b3 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -57,6 +57,14 @@ typedef struct { GHashTable *requests; } NMAgentManagerPrivate; +enum { + AGENT_REGISTERED, + + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + + typedef struct _Request Request; static void request_add_agent (Request *req, @@ -277,6 +285,9 @@ impl_agent_manager_register (NMAgentManager *self, nm_secret_agent_get_description (agent)); dbus_g_method_return (context); + /* Signal an agent was registered */ + g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent); + /* Add this agent to any in-progress secrets requests */ g_hash_table_iter_init (&iter, priv->requests); while (g_hash_table_iter_next (&iter, NULL, &data)) @@ -1363,6 +1374,17 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) /* virtual methods */ object_class->dispose = dispose; + /* Signals */ + signals[AGENT_REGISTERED] = + g_signal_new ("agent-registered", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMAgentManagerClass, agent_registered), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + G_TYPE_OBJECT); + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (agent_manager_class), &dbus_glib_nm_agent_manager_object_info); diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index 788a91758d..287413afce 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -25,6 +25,7 @@ #include #include #include "nm-settings-flags.h" +#include "nm-secret-agent.h" #define NM_TYPE_AGENT_MANAGER (nm_agent_manager_get_type ()) #define NM_AGENT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManager)) @@ -39,6 +40,9 @@ typedef struct { typedef struct { GObjectClass parent; + + /* Signals */ + void (*agent_registered) (NMAgentManager *agent_mgr, NMSecretAgent *agent); } NMAgentManagerClass; GType nm_agent_manager_get_type (void); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 83297809d0..733e9145bb 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -135,6 +135,7 @@ enum { CONNECTION_REMOVED, CONNECTION_VISIBILITY_CHANGED, CONNECTIONS_LOADED, + AGENT_REGISTERED, NEW_CONNECTION, /* exported, not used internally */ LAST_SIGNAL @@ -699,6 +700,18 @@ connection_visibility_changed (NMSettingsConnection *connection, connection); } +static void +secret_agent_registered (NMAgentManager *agent_mgr, + NMSecretAgent *agent, + gpointer user_data) +{ + /* Re-emit for listeners like NMPolicy */ + g_signal_emit (NM_SETTINGS (user_data), + signals[AGENT_REGISTERED], + 0, + agent); +} + #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" #define NM_OPENCONNECT_KEY_GATEWAY "gateway" #define NM_OPENCONNECT_KEY_COOKIE "cookie" @@ -1530,6 +1543,8 @@ nm_settings_init (NMSettings *self) * recreated often. */ priv->agent_mgr = nm_agent_manager_get (); + + g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self); } static void @@ -1693,6 +1708,16 @@ nm_settings_class_init (NMSettingsClass *class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + signals[AGENT_REGISTERED] = + g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsClass, agent_registered), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[NEW_CONNECTION] = g_signal_new ("new-connection", G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index a5cb4d7c88..66d41cce83 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -19,7 +19,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2010 Red Hat, Inc. + * (C) Copyright 2007 - 2011 Red Hat, Inc. * (C) Copyright 2008 Novell, Inc. */ @@ -31,6 +31,7 @@ #include "nm-settings-connection.h" #include "nm-system-config-interface.h" #include "nm-device.h" +#include "nm-secret-agent.h" #define NM_TYPE_SETTINGS (nm_settings_get_type ()) #define NM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS, NMSettings)) @@ -48,6 +49,7 @@ #define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED "connection-removed" #define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed" #define NM_SETTINGS_SIGNAL_CONNECTIONS_LOADED "connections-loaded" +#define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered" typedef struct { GObject parent_instance; @@ -68,6 +70,8 @@ typedef struct { void (*connection_visibility_changed) (NMSettings *self, NMSettingsConnection *connection); void (*connections_loaded) (NMSettings *self); + + void (*agent_registered) (NMSettings *self, NMSecretAgent *agent); } NMSettingsClass; GType nm_settings_get_type (void);