core: connections failed due to missing secrets are re-tried when an secret agent registers (rh #706204)

Use case:
A user has an auto-activatable connection with secrets in a keyring. While
booting NM starts and tries to activate the connection, but it fails because of
missing secrets. Then the user logs in, but the connection is marked as invalid
and is not tried again.

This commit solves the issue by removing invalid flag and activating the
connection when a secret agent registers.

Signed-off-by: Jiří Klimeš <jklimes@redhat.com>
This commit is contained in:
Jiří Klimeš 2011-06-28 15:48:12 +02:00
parent 18b81930ce
commit 69b767bbf0
5 changed files with 96 additions and 1 deletions

View file

@ -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);

View file

@ -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);

View file

@ -25,6 +25,7 @@
#include <glib-object.h>
#include <nm-connection.h>
#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);

View file

@ -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),

View file

@ -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);