[gnome-remote-desktop] session: Stop trying to stop the session, when it is already destroyed



commit aed99b38dc6785eee3722d6523cbfe49a8684036
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Wed Nov 24 17:03:11 2021 +0100

    session: Stop trying to stop the session, when it is already destroyed
    
    In order to start a remote desktop session, gnome-remote-desktop calls
    several dbus methods on the remote desktop- and screencast interface of
    mutter.
    These calls use in glib internally GTasks and will always run their
    async-ready-callback, when the task is done, aborted, or cancelled.
    This also applies to situations, where the session is immediately
    stopped or destroyed.
    In such cases, the callback should not be handled any more, as parts of
    the session are already destroyed, due to the session already been
    stopped, or the complete session is already destroyed.
    The result is usually a crash, as gnome-remote-desktop tries to stop
    the session, although it is already stopped or destroyed.
    
    To prevent these situations, always cancel the cancellable, when
    stopping the session.
    When a async-ready-callback is called, don't directly derenference the
    user date.
    Instead, call the finish function first and check the error code.
    When the cancellable was cancelled, the finish function will not return
    successfully and set the error.
    The error code will in such cases be G_IO_ERROR_CANCELLED.
    If that is the case, just return, as the session is already stopped.

 src/grd-session.c | 149 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 91 insertions(+), 58 deletions(-)
---
diff --git a/src/grd-session.c b/src/grd-session.c
index 32fdc671..057bb03e 100644
--- a/src/grd-session.c
+++ b/src/grd-session.c
@@ -93,6 +93,9 @@ grd_session_stop (GrdSession *session)
 {
   GrdSessionPrivate *priv = grd_session_get_instance_private (session);
 
+  if (priv->cancellable && g_cancellable_is_cancelled (priv->cancellable))
+    return;
+
   GRD_SESSION_GET_CLASS (session)->stop (session);
 
   if (priv->remote_desktop_session && priv->started)
@@ -107,11 +110,17 @@ grd_session_stop (GrdSession *session)
         }
     }
 
+  if (priv->cancellable)
+    g_cancellable_cancel (priv->cancellable);
+
   g_clear_signal_handler (&priv->caps_lock_state_changed_id,
                           priv->remote_desktop_session);
   g_clear_signal_handler (&priv->num_lock_state_changed_id,
                           priv->remote_desktop_session);
 
+  if (priv->stream)
+    grd_stream_disconnect_proxy_signals (priv->stream);
+
   g_clear_object (&priv->remote_desktop_session);
   g_clear_object (&priv->screen_cast_session);
 
@@ -437,23 +446,27 @@ on_session_start_finished (GObject      *object,
                            GAsyncResult *result,
                            gpointer      user_data)
 {
-  GrdSession *session = user_data;
-  GrdSessionPrivate *priv = grd_session_get_instance_private (session);
-  GrdDBusRemoteDesktopSession *proxy = priv->remote_desktop_session;
-  GError *error = NULL;
+  GrdDBusRemoteDesktopSession *proxy;
+  GrdSession *session;
+  GrdSessionPrivate *priv;
+  g_autoptr (GError) error = NULL;
 
+  proxy = GRD_DBUS_REMOTE_DESKTOP_SESSION (object);
   if (!grd_dbus_remote_desktop_session_call_start_finish (proxy,
                                                           result,
                                                           &error))
     {
-      g_warning ("Failed to start session: %s", error->message);
-      g_error_free (error);
-
-      grd_session_stop (session);
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
 
+      g_warning ("Failed to start session: %s", error->message);
+      grd_session_stop (GRD_SESSION (user_data));
       return;
     }
 
+  session = GRD_SESSION (user_data);
+  priv = grd_session_get_instance_private (session);
+
   priv->started = TRUE;
 }
 
@@ -474,23 +487,26 @@ on_screen_cast_stream_proxy_acquired (GObject      *object,
                                       GAsyncResult *result,
                                       gpointer      user_data)
 {
-  GrdSession *session = user_data;
-  GrdSessionPrivate *priv = grd_session_get_instance_private (session);
   GrdDBusScreenCastStream *stream_proxy;
-  GError *error = NULL;
+  GrdSession *session;
+  GrdSessionPrivate *priv;
+  g_autoptr (GError) error = NULL;
   GrdStream *stream;
 
   stream_proxy = grd_dbus_screen_cast_stream_proxy_new_finish (result, &error);
   if (!stream_proxy)
     {
-      g_warning ("Failed to acquire stream proxy: %s", error->message);
-      g_error_free (error);
-
-      grd_session_stop (session);
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
 
+      g_warning ("Failed to acquire stream proxy: %s", error->message);
+      grd_session_stop (GRD_SESSION (user_data));
       return;
     }
 
+  session = GRD_SESSION (user_data);
+  priv = grd_session_get_instance_private (session);
+
   stream = grd_stream_new (priv->context, stream_proxy);
   g_signal_connect (stream, "ready", G_CALLBACK (on_stream_ready),
                     session);
@@ -506,26 +522,30 @@ on_record_monitor_finished (GObject      *object,
                             GAsyncResult *result,
                             gpointer      user_data)
 {
-  GrdSession *session = user_data;
-  GrdSessionPrivate *priv = grd_session_get_instance_private (session);
-  GrdDBusScreenCastSession *proxy = priv->screen_cast_session;
-  g_autofree char *stream_path = NULL;
-  GError *error = NULL;
+  GrdDBusScreenCastSession *proxy;
+  GrdSession *session;
+  GrdSessionPrivate *priv;
   GDBusConnection *connection;
+  g_autofree char *stream_path = NULL;
+  g_autoptr (GError) error = NULL;
 
+  proxy = GRD_DBUS_SCREEN_CAST_SESSION (object);
   if (!grd_dbus_screen_cast_session_call_record_monitor_finish (proxy,
                                                                 &stream_path,
                                                                 result,
                                                                 &error))
     {
-      g_warning ("Failed to record monitor: %s", error->message);
-      g_error_free (error);
-
-      grd_session_stop (session);
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
 
+      g_warning ("Failed to record monitor: %s", error->message);
+      grd_session_stop (GRD_SESSION (user_data));
       return;
     }
 
+  session = GRD_SESSION (user_data);
+  priv = grd_session_get_instance_private (session);
+
   connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (proxy));
   grd_dbus_screen_cast_stream_proxy_new (connection,
                                          G_DBUS_PROXY_FLAGS_NONE,
@@ -541,25 +561,28 @@ on_screen_cast_session_proxy_acquired (GObject      *object,
                                        GAsyncResult *result,
                                        gpointer      user_data)
 {
-  GrdSession *session = user_data;
-  GrdSessionPrivate *priv = grd_session_get_instance_private (session);
   GrdDBusScreenCastSession *session_proxy;
+  GrdSession *session;
+  GrdSessionPrivate *priv;
   GVariantBuilder properties_builder;
-  GError *error = NULL;
+  g_autoptr (GError) error = NULL;
 
   session_proxy =
     grd_dbus_screen_cast_session_proxy_new_finish (result, &error);
   if (!session_proxy)
     {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
+
       g_warning ("Failed to acquire screen cast session proxy: %s\n",
                  error->message);
-      g_error_free (error);
-
-      grd_session_stop (session);
-
+      grd_session_stop (GRD_SESSION (user_data));
       return;
     }
 
+  session = GRD_SESSION (user_data);
+  priv = grd_session_get_instance_private (session);
+
   priv->screen_cast_session = session_proxy;
 
   g_variant_builder_init (&properties_builder, G_VARIANT_TYPE ("a{sv}"));
@@ -581,28 +604,31 @@ on_screen_cast_session_created (GObject      *source_object,
                                 GAsyncResult *res,
                                 gpointer      user_data)
 {
-  GrdSession *session = user_data;
-  GrdSessionPrivate *priv = grd_session_get_instance_private (session);
   GrdDBusScreenCast *screen_cast_proxy;
-  g_autofree char *session_path = NULL;
-  GError *error = NULL;
+  GrdSession *session;
+  GrdSessionPrivate *priv;
   GDBusConnection *connection;
+  g_autofree char *session_path = NULL;
+  g_autoptr (GError) error = NULL;
 
-  screen_cast_proxy = grd_context_get_screen_cast_proxy (priv->context);
+  screen_cast_proxy = GRD_DBUS_SCREEN_CAST (source_object);
   if (!grd_dbus_screen_cast_call_create_session_finish (screen_cast_proxy,
                                                         &session_path,
                                                         res,
                                                         &error))
     {
-      g_warning ("Failed to start screen cast session: %s\n", error->message);
-      g_error_free (error);
-
-      grd_session_stop (session);
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
 
+      g_warning ("Failed to start screen cast session: %s\n", error->message);
+      grd_session_stop (GRD_SESSION (user_data));
       return;
     }
 
+  session = GRD_SESSION (user_data);
+  priv = grd_session_get_instance_private (session);
   connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (screen_cast_proxy));
+
   grd_dbus_screen_cast_session_proxy_new (connection,
                                           G_DBUS_PROXY_FLAGS_NONE,
                                           MUTTER_SCREEN_CAST_BUS_NAME,
@@ -730,11 +756,11 @@ on_remote_desktop_session_proxy_acquired (GObject      *object,
                                           GAsyncResult *result,
                                           gpointer      user_data)
 {
-  GrdSession *session = user_data;
-  GrdSessionPrivate *priv = grd_session_get_instance_private (session);
-  GrdSessionClass *klass = GRD_SESSION_GET_CLASS (session);
   GrdDBusRemoteDesktopSession *session_proxy;
-  GError *error = NULL;
+  GrdSession *session;
+  GrdSessionPrivate *priv;
+  GrdSessionClass *klass;
+  g_autoptr (GError) error = NULL;
   const char *remote_desktop_session_id;
   GrdDBusScreenCast *screen_cast_proxy;
   GVariantBuilder properties_builder;
@@ -744,15 +770,19 @@ on_remote_desktop_session_proxy_acquired (GObject      *object,
     grd_dbus_remote_desktop_session_proxy_new_finish (result, &error);
   if (!session_proxy)
     {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
+
       g_warning ("Failed to acquire remote desktop session proxy: %s\n",
                  error->message);
-      g_error_free (error);
-
-      grd_session_stop (session);
-
+      grd_session_stop (GRD_SESSION (user_data));
       return;
     }
 
+  session = GRD_SESSION (user_data);
+  priv = grd_session_get_instance_private (session);
+  klass = GRD_SESSION_GET_CLASS (session);
+
   g_signal_connect (session_proxy, "closed",
                     G_CALLBACK (on_remote_desktop_session_closed),
                     session);
@@ -805,28 +835,31 @@ on_remote_desktop_session_created (GObject      *source_object,
                                    GAsyncResult *res,
                                    gpointer      user_data)
 {
-  GrdSession *session = user_data;
-  GrdSessionPrivate *priv = grd_session_get_instance_private (session);
   GrdDBusRemoteDesktop *remote_desktop_proxy;
-  g_autofree char *session_path = NULL;
+  GrdSession *session;
+  GrdSessionPrivate *priv;
   GDBusConnection *connection;
-  GError *error = NULL;
+  g_autofree char *session_path = NULL;
+  g_autoptr (GError) error = NULL;
 
-  remote_desktop_proxy = grd_context_get_remote_desktop_proxy (priv->context);
+  remote_desktop_proxy = GRD_DBUS_REMOTE_DESKTOP (source_object);
   if (!grd_dbus_remote_desktop_call_create_session_finish (remote_desktop_proxy,
                                                            &session_path,
                                                            res,
                                                            &error))
     {
-      g_warning ("Failed to start remote desktop session: %s\n", error->message);
-      g_error_free (error);
-
-      grd_session_stop (session);
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
 
+      g_warning ("Failed to start remote desktop session: %s\n", error->message);
+      grd_session_stop (GRD_SESSION (user_data));
       return;
     }
 
+  session = GRD_SESSION (user_data);
+  priv = grd_session_get_instance_private (session);
   connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (remote_desktop_proxy));
+
   grd_dbus_remote_desktop_session_proxy_new (connection,
                                              G_DBUS_PROXY_FLAGS_NONE,
                                              MUTTER_REMOTE_DESKTOP_BUS_NAME,
@@ -871,7 +904,7 @@ grd_session_finalize (GObject *object)
   g_assert (!priv->remote_desktop_session);
 
   if (priv->cancellable)
-    g_cancellable_cancel (priv->cancellable);
+    g_assert (g_cancellable_is_cancelled (priv->cancellable));
   g_clear_object (&priv->cancellable);
 
   G_OBJECT_CLASS (grd_session_parent_class)->finalize (object);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]