diff --git a/libnm/nm-client.c b/libnm/nm-client.c index f727e8201..cae4c47d3 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -2554,25 +2554,6 @@ dns_notify (GObject *object, } } -static void -checkpoint_create_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *simple = user_data; - NMCheckpoint *checkpoint; - GError *error = NULL; - - checkpoint = nm_manager_checkpoint_create_finish (NM_MANAGER (object), result, &error); - if (checkpoint) - g_simple_async_result_set_op_res_gpointer (simple, checkpoint, g_object_unref); - else - g_simple_async_result_take_error (simple, error); - - g_simple_async_result_complete (simple); - g_object_unref (simple); -} - /** * nm_client_get_checkpoints: * @client: a #NMClient @@ -2596,6 +2577,35 @@ nm_client_get_checkpoints (NMClient *client) return nm_manager_get_checkpoints (NM_CLIENT_GET_PRIVATE (client)->manager); } +static void +checkpoint_create_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + NMClient *self; + gs_unref_object GTask *task = user_data; + gs_unref_variant GVariant *ret = NULL; + const char *checkpoint_path; + GError *error = NULL; + + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error); + if (!ret) { + g_dbus_error_strip_remote_error (error); + g_task_return_error (task, error); + return; + } + + g_variant_get (ret, + "(&o)", + &checkpoint_path); + + self = g_task_get_source_object (task); + + nm_manager_wait_for_checkpoint (NM_CLIENT_GET_PRIVATE (self)->manager, + checkpoint_path, + g_steal_pointer (&task)); +} + /** * nm_client_checkpoint_create: * @client: the %NMClient @@ -2623,23 +2633,35 @@ nm_client_checkpoint_create (NMClient *client, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *simple; - GError *error = NULL; + gs_free const char **paths = NULL; + guint i; g_return_if_fail (NM_IS_CLIENT (client)); - if (!_nm_client_check_nm_running (client, &error)) { - g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error); - return; + if ( devices + && devices->len > 0) { + paths = g_new (const char *, devices->len + 1); + for (i = 0; i < devices->len; i++) + paths[i] = nm_object_get_path (NM_OBJECT (devices->pdata[i])); + paths[i] = NULL; } - simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data, - nm_client_checkpoint_create); - if (cancellable) - g_simple_async_result_set_check_cancellable (simple, cancellable); - nm_manager_checkpoint_create (NM_CLIENT_GET_PRIVATE (client)->manager, - devices, rollback_timeout, flags, - cancellable, checkpoint_create_cb, simple); + _nm_object_dbus_call (client, + nm_client_checkpoint_create, + cancellable, + callback, + user_data, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + "CheckpointCreate", + g_variant_new ("(^aouu)", + paths ?: NM_PTRARRAY_EMPTY (const char *), + rollback_timeout, + flags), + G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NONE, + NM_DBUS_DEFAULT_TIMEOUT_MSEC, + checkpoint_create_cb); } /** @@ -2660,16 +2682,10 @@ nm_client_checkpoint_create_finish (NMClient *client, GAsyncResult *result, GError **error) { - GSimpleAsyncResult *simple; - g_return_val_if_fail (NM_IS_CLIENT (client), NULL); - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL); + g_return_val_if_fail (nm_g_task_is_valid (result, client, nm_client_checkpoint_create), NULL); - simple = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - else - return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)); + return g_task_propagate_pointer (G_TASK (result), error); } static void diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c index 17e1f7c2f..52aa588d0 100644 --- a/libnm/nm-manager.c +++ b/libnm/nm-manager.c @@ -46,7 +46,6 @@ typedef struct { GPtrArray *all_devices; GPtrArray *active_connections; GPtrArray *checkpoints; - GSList *added_checkpoints; NMConnectivityState connectivity; NMActiveConnection *primary_connection; NMActiveConnection *activating_connection; @@ -60,6 +59,8 @@ typedef struct { */ CList wait_for_active_connection_lst_head; + CList wait_for_checkpoint_lst_head; + gboolean networking_enabled; gboolean wireless_enabled; gboolean wireless_hw_enabled; @@ -119,21 +120,21 @@ static guint signals[LAST_SIGNAL] = { 0 }; /*****************************************************************************/ typedef struct { - NMManager *manager; - GSimpleAsyncResult *simple; - char *path; + CList lst; + NMManager *self; + char *checkpoint_path; + GTask *task; + gulong cancelled_id; } CheckpointInfo; static CheckpointInfo * -find_checkpoint_info (NMManager *manager, const char *path) +_wait_for_checkpoint_find_info (NMManager *manager, const char *path) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); CheckpointInfo *info; - GSList *iter; - for (iter = priv->added_checkpoints; iter; iter = g_slist_next (iter)) { - info = iter->data; - if (nm_streq0 (path, info->path)) + c_list_for_each_entry (info, &priv->wait_for_checkpoint_lst_head, lst) { + if (nm_streq (path, info->checkpoint_path)) return info; } @@ -141,28 +142,23 @@ find_checkpoint_info (NMManager *manager, const char *path) } static void -checkpoint_info_complete (NMManager *self, - CheckpointInfo *info, - NMCheckpoint *checkpoint, - GError *error) +_wait_for_checkpoint_complete (CheckpointInfo *info, + NMCheckpoint *checkpoint, + GError *error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + c_list_unlink_stale (&info->lst); - g_return_if_fail (info); + nm_clear_g_signal_handler (g_task_get_cancellable (info->task), &info->cancelled_id); - if (checkpoint) { - g_simple_async_result_set_op_res_gpointer (info->simple, - g_object_ref (checkpoint), - g_object_unref); - } else - g_simple_async_result_set_from_error (info->simple, error); - g_simple_async_result_complete (info->simple); + if (!checkpoint) + g_task_return_error (info->task, error); + else + g_task_return_pointer (info->task, g_object_ref (checkpoint), g_object_unref); - g_object_unref (info->simple); - priv->added_checkpoints = g_slist_remove (priv->added_checkpoints, info); - - g_free (info->path); - g_slice_free (CheckpointInfo, info); + g_object_unref (info->task); + g_object_unref (info->self); + g_free (info->checkpoint_path); + nm_g_slice_free (info); } static void @@ -171,6 +167,7 @@ nm_manager_init (NMManager *manager) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); c_list_init (&priv->wait_for_active_connection_lst_head); + c_list_init (&priv->wait_for_checkpoint_lst_head); priv->state = NM_STATE_UNKNOWN; priv->connectivity = NM_CONNECTIVITY_UNKNOWN; @@ -250,12 +247,12 @@ object_creation_failed (NMObject *object, const char *failed_path) CheckpointInfo *info; GError *add_error; - info = find_checkpoint_info (self, failed_path); + info = _wait_for_checkpoint_find_info (self, failed_path); if (info) { add_error = g_error_new_literal (NM_CLIENT_ERROR, NM_CLIENT_ERROR_OBJECT_CREATION_FAILED, _("Checkpoint was removed before it was initialized")); - checkpoint_info_complete (self, info, NULL, add_error); + _wait_for_checkpoint_complete (info, NULL, add_error); g_error_free (add_error); } } @@ -991,9 +988,9 @@ checkpoint_added (NMManager *manager, NMCheckpoint *checkpoint) { CheckpointInfo *info; - info = find_checkpoint_info (manager, nm_object_get_path (NM_OBJECT (checkpoint))); + info = _wait_for_checkpoint_find_info (manager, nm_object_get_path (NM_OBJECT (checkpoint))); if (info) - checkpoint_info_complete (manager, info, checkpoint, NULL); + _wait_for_checkpoint_complete (info, checkpoint, NULL); } /*****************************************************************************/ @@ -1016,21 +1013,6 @@ free_active_connections (NMManager *manager) /*****************************************************************************/ -static const char ** -get_device_paths (const GPtrArray *devices) -{ - const char **array; - guint i; - - array = g_new (const char *, devices->len + 1); - for (i = 0; i < devices->len; i++) - array[i] = nm_object_get_path (NM_OBJECT (devices->pdata[i])); - - array[i] = NULL; - - return array; -} - const GPtrArray * nm_manager_get_checkpoints (NMManager *manager) { @@ -1040,81 +1022,58 @@ nm_manager_get_checkpoints (NMManager *manager) } static void -checkpoint_created_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) +_wait_for_checkpoint_cancelled_cb (GCancellable *cancellable, + gpointer user_data) { CheckpointInfo *info = user_data; - NMManager *self = info->manager; gs_free_error GError *error = NULL; - NMCheckpoint *checkpoint; - nmdbus_manager_call_checkpoint_create_finish (NMDBUS_MANAGER (object), - &info->path, result, &error); - if (error) { - g_dbus_error_strip_remote_error (error); - checkpoint_info_complete (self, info, NULL, error); + if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) return; - } - checkpoint = get_checkpoint_by_path (self, info->path); - if (!checkpoint) { - /* this is really problematic. The async request returned, but - * we don't yet have a visible (fully initialized) NMCheckpoint instance - * to return. Wait longer for it to appear. However, it's ugly. */ - return; - } - - checkpoint_info_complete (self, info, checkpoint, NULL); + _wait_for_checkpoint_complete (info, NULL, g_steal_pointer (&error)); } void -nm_manager_checkpoint_create (NMManager *manager, - const GPtrArray *devices, - guint32 rollback_timeout, - NMCheckpointCreateFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +nm_manager_wait_for_checkpoint (NMManager *self, + const char *checkpoint_path, + GTask *task_take) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - gs_free const char **paths = NULL; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + gs_unref_object GTask *task = task_take; CheckpointInfo *info; + GCancellable *cancellable; + NMCheckpoint *checkpoint; - g_return_if_fail (NM_IS_MANAGER (manager)); + checkpoint = get_checkpoint_by_path (self, checkpoint_path); + if (checkpoint) { + g_task_return_pointer (task, g_object_ref (checkpoint), g_object_unref); + return; + } - info = g_slice_new0 (CheckpointInfo); - info->manager = manager; - info->simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data, - nm_manager_checkpoint_create); - if (cancellable) - g_simple_async_result_set_check_cancellable (info->simple, cancellable); - paths = get_device_paths (devices); - nmdbus_manager_call_checkpoint_create (NM_MANAGER_GET_PRIVATE (manager)->proxy, - paths, - rollback_timeout, - flags, - cancellable, - checkpoint_created_cb, - info); - priv->added_checkpoints = g_slist_append (priv->added_checkpoints, info); -} + /* FIXME: there is no timeout for how long we wait. But this entire + * code will be reworked, also that we have a suitable GMainContext + * where we can schedule the timeout (we shouldn't use g_main_context_default()). */ -NMCheckpoint * -nm_manager_checkpoint_create_finish (NMManager *manager, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; + info = g_slice_new (CheckpointInfo); + *info = (CheckpointInfo) { + .self = g_object_ref (self), + .task = g_steal_pointer (&task), + .checkpoint_path = g_strdup (checkpoint_path), + }; + c_list_link_tail (&priv->wait_for_checkpoint_lst_head, &info->lst); - g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - else - return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)); + cancellable = g_task_get_cancellable (info->task); + if (cancellable) { + info->cancelled_id = g_signal_connect (cancellable, + "cancelled", + G_CALLBACK (_wait_for_checkpoint_cancelled_cb), + info); + if (g_cancellable_is_cancelled (cancellable)) { + _wait_for_checkpoint_cancelled_cb (cancellable, info); + return; + } + } } static void @@ -1483,6 +1442,7 @@ dispose (GObject *object) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (object); nm_assert (c_list_is_empty (&priv->wait_for_active_connection_lst_head)); + nm_assert (c_list_is_empty (&priv->wait_for_checkpoint_lst_head)); nm_clear_g_cancellable (&priv->perm_call_cancellable); diff --git a/libnm/nm-manager.h b/libnm/nm-manager.h index 30e8ad2e0..e1bf09336 100644 --- a/libnm/nm-manager.h +++ b/libnm/nm-manager.h @@ -142,16 +142,11 @@ void nm_manager_wait_for_active_connection (NMManager *self, GTask *task_take); const GPtrArray *nm_manager_get_checkpoints (NMManager *manager); -void nm_manager_checkpoint_create (NMManager *manager, - const GPtrArray *devices, - guint32 rollback_timeout, - NMCheckpointCreateFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -NMCheckpoint *nm_manager_checkpoint_create_finish (NMManager *manager, - GAsyncResult *result, - GError **error); + +void nm_manager_wait_for_checkpoint (NMManager *self, + const char *checkpoint_path, + GTask *task_take); + void nm_manager_checkpoint_destroy (NMManager *manager, const char *checkpoint_path, GCancellable *cancellable,