From 92ee635c59510d5c196fba3d611bcf1784ecbda9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 14 Sep 2007 19:43:28 +0000 Subject: [PATCH] 2007-09-14 Dan Williams Implement deferred activation handling in the NMActRequest class. When a client wants to activate a device but must create the NMConnection details on the fly, there likely hasn't been enough time yet for NM to receive the new connection signal and grab all the connection details. So the activation is deferred (and bounded by a timer) for a while, and if the connection appears within the window, it is activated. * src/nm-activation-request.c src/nm-activation-request.h - (nm_act_request_class_init): two new signals to support deferred activation, to allow the listener to handle both timeout and success - (nm_act_request_new_deferred): new function, starts the deferred activation timeout handler and listens to the NMManager for new-connection signals to notice when the connection comes in git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2811 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 17 ++++ src/nm-activation-request.c | 175 ++++++++++++++++++++++++++++++++++-- src/nm-activation-request.h | 19 ++-- 3 files changed, 199 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index a61c006111..89ab88779d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2007-09-14 Dan Williams + + Implement deferred activation handling in the NMActRequest class. When a + client wants to activate a device but must create the NMConnection details + on the fly, there likely hasn't been enough time yet for NM to receive the + new connection signal and grab all the connection details. So the + activation is deferred (and bounded by a timer) for a while, and if the + connection appears within the window, it is activated. + + * src/nm-activation-request.c + src/nm-activation-request.h + - (nm_act_request_class_init): two new signals to support deferred + activation, to allow the listener to handle both timeout and success + - (nm_act_request_new_deferred): new function, starts the deferred + activation timeout handler and listens to the NMManager for + new-connection signals to notice when the connection comes in + 2007-09-14 Dan Williams * src/nm-manager.h diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 81d3811b15..32794f7762 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -22,6 +22,8 @@ #include "nm-activation-request.h" #include "nm-marshal.h" +#include "nm-manager.h" +#include "nm-utils.h" G_DEFINE_TYPE (NMActRequest, nm_act_request, G_TYPE_OBJECT) @@ -29,6 +31,8 @@ G_DEFINE_TYPE (NMActRequest, nm_act_request, G_TYPE_OBJECT) enum { CONNECTION_SECRETS_UPDATED, + DEFERRED_ACTIVATION_TIMEOUT, + DEFERRED_ACTIVATION_START, LAST_SIGNAL }; @@ -41,6 +45,11 @@ static void connection_secrets_updated_cb (NMConnection *connection, NMActRequest *self); typedef struct { + char *deferred_service_name; + char *deferred_connection_path; + gulong deferred_connection_id; + guint32 deferred_timeout_id; + NMConnection *connection; char *specific_object; gboolean user_requested; @@ -53,15 +62,53 @@ nm_act_request_init (NMActRequest *req) { } +static void +clear_deferred_stuff (NMActRequest *req) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req); + + g_free (priv->deferred_service_name); + priv->deferred_service_name = NULL; + g_free (priv->deferred_connection_path); + priv->deferred_connection_path = NULL; + + if (priv->deferred_connection_id) { + NMManager *manager = nm_manager_get (); + g_signal_handler_disconnect (manager, priv->deferred_connection_id); + g_object_unref (manager); + priv->deferred_connection_id = 0; + } + + if (priv->deferred_timeout_id) { + g_source_remove (priv->deferred_timeout_id); + priv->deferred_timeout_id = 0; + } +} + +static void +dispose (GObject *object) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); + + clear_deferred_stuff (NM_ACT_REQUEST (object)); + + if (priv->secrets_updated_id) { + g_signal_handler_disconnect (priv->connection, + priv->secrets_updated_id); + priv->secrets_updated_id = 0; + } + + if (priv->connection) + g_object_unref (priv->connection); +} + static void finalize (GObject *object) { NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - g_signal_handler_disconnect (priv->connection, - priv->secrets_updated_id); - g_object_unref (priv->connection); - + g_free (priv->deferred_service_name); + g_free (priv->deferred_connection_path); g_free (priv->specific_object); G_OBJECT_CLASS (nm_act_request_parent_class)->finalize (object); @@ -74,6 +121,7 @@ nm_act_request_class_init (NMActRequestClass *req_class) g_type_class_add_private (req_class, sizeof (NMActRequestPrivate)); + object_class->dispose = dispose; object_class->finalize = finalize; /* Signals */ @@ -81,11 +129,31 @@ nm_act_request_class_init (NMActRequestClass *req_class) g_signal_new ("connection-secrets-updated", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMConnectionClass, secrets_updated), + G_STRUCT_OFFSET (NMActRequestClass, connection_secrets_updated), NULL, NULL, nm_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_STRING); + + signals[DEFERRED_ACTIVATION_TIMEOUT] = + g_signal_new ("deferred-activation-timeout", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMActRequestClass, deferred_activation_timeout), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, + G_TYPE_NONE); + + signals[DEFERRED_ACTIVATION_START] = + g_signal_new ("deferred-activation-start", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMActRequestClass, deferred_activation_start), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, + G_TYPE_NONE); } NMActRequest * @@ -97,7 +165,7 @@ nm_act_request_new (NMConnection *connection, NMActRequestPrivate *priv; gulong id; - g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); obj = g_object_new (NM_TYPE_ACT_REQUEST, NULL); if (!obj) @@ -119,6 +187,101 @@ nm_act_request_new (NMConnection *connection, return NM_ACT_REQUEST (obj); } +static gboolean +deferred_timeout_cb (gpointer data) +{ + NMActRequest *self = NM_ACT_REQUEST (data); + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); + + priv->deferred_timeout_id = 0; + clear_deferred_stuff (self); + + g_signal_emit (self, signals[DEFERRED_ACTIVATION_TIMEOUT], 0); + return FALSE; +} + +static void +connection_added_cb (NMManager *manager, + NMConnection *connection, + gpointer user_data) +{ + NMActRequest *self; + NMActRequestPrivate *priv; + const char *service_name; + const char *path; + gulong id; + + g_return_if_fail (NM_IS_ACT_REQUEST (user_data)); + g_return_if_fail (NM_IS_CONNECTION (connection)); + g_return_if_fail (NM_IS_MANAGER (manager)); + + self = NM_ACT_REQUEST (user_data); + + service_name = nm_manager_get_connection_service_name (manager, connection); + path = nm_manager_get_connection_dbus_path (manager, connection); + if (!service_name || !path) { + nm_warning ("Couldn't get connection service name or path (%s, %s)", + service_name, path); + return; + } + + priv = NM_ACT_REQUEST_GET_PRIVATE (self); + if ( strcmp (service_name, priv->deferred_service_name) + || strcmp (path, priv->deferred_connection_path)) + return; + + clear_deferred_stuff (self); + + priv->connection = g_object_ref (connection); + id = g_signal_connect (priv->connection, + "secrets-updated", + G_CALLBACK (connection_secrets_updated_cb), + self); + priv->secrets_updated_id = id; + + g_signal_emit (self, signals[DEFERRED_ACTIVATION_START], 0); +} + +NMActRequest * +nm_act_request_new_deferred (const char *service_name, + const char *connection_path, + const char *specific_object, + gboolean user_requested) +{ + GObject *obj; + NMManager *manager; + NMActRequestPrivate *priv; + gulong id; + + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (connection_path != NULL, NULL); + + obj = g_object_new (NM_TYPE_ACT_REQUEST, NULL); + if (!obj) + return NULL; + + priv = NM_ACT_REQUEST_GET_PRIVATE (obj); + + priv->deferred_service_name = g_strdup (service_name); + priv->deferred_connection_path = g_strdup (connection_path); + priv->user_requested = user_requested; + if (specific_object) + priv->specific_object = g_strdup (specific_object); + + id = g_timeout_add (5000, deferred_timeout_cb, NM_ACT_REQUEST (obj)); + priv->deferred_timeout_id = id; + + manager = nm_manager_get (); + id = g_signal_connect (manager, + "connection-added", + G_CALLBACK (connection_added_cb), + NM_ACT_REQUEST (obj)); + priv->deferred_connection_id = id; + g_object_unref (manager); + + return NM_ACT_REQUEST (obj); +} + static void connection_secrets_updated_cb (NMConnection *connection, const char *setting_name, diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index 443763c35a..627d9247ce 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -41,16 +41,23 @@ typedef struct { GObjectClass parent; /* Signals */ - void (*connection_secrets_updated) (NMActRequest *req, - NMConnection *connection, - const char * setting); + void (*connection_secrets_updated) (NMActRequest *req, + NMConnection *connection, + const char * setting); + void (*deferred_activation_timeout) (NMActRequest *req); + void (*deferred_activation_start) (NMActRequest *req); } NMActRequestClass; GType nm_act_request_get_type (void); -NMActRequest *nm_act_request_new (NMConnection *connection, - const char *specific_object, - gboolean user_requested); +NMActRequest *nm_act_request_new (NMConnection *connection, + const char *specific_object, + gboolean user_requested); + +NMActRequest *nm_act_request_new_deferred (const char *service_name, + const char *connection_path, + const char *specific_object, + gboolean user_requested); NMConnection *nm_act_request_get_connection (NMActRequest *req); const char * nm_act_request_get_specific_object(NMActRequest *req);