[gnome-keyring] daemon: Exit gnome-keyring-daemon when the DBus connection closes



commit 636113849f970af6819ef599d207419c4881f8fb
Author: Stef Walter <stefw gnome org>
Date:   Thu Mar 6 16:11:12 2014 +0100

    daemon: Exit gnome-keyring-daemon when the DBus connection closes
    
    We don't do this via the standard mechanism, as it means that libdbus
    just calls _exit() (not even exit()) when the connection goes away.
    
    This can lead to inconsistent state. Shutdown should be orderly.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=708765

 daemon/Makefile.am     |    7 +++-
 daemon/dbus/gkd-dbus.c |   10 ++++-
 daemon/gkd-main.c      |    4 +-
 daemon/test-shutdown.c |  115 ++++++++++++++++++++++++++++++++++++++++++++++++
 egg/egg-dbus.c         |   21 +++++++--
 egg/egg-dbus.h         |    4 +-
 6 files changed, 152 insertions(+), 9 deletions(-)
---
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index bcfff8c..e9c4a18 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -76,11 +76,16 @@ daemon_LIBS = \
        $(GLIB_LIBS)
 
 daemon_TESTS = \
-       test-startup
+       test-startup \
+       test-shutdown
 
 test_startup_SOURCES = daemon/test-startup.c
 test_startup_LDADD = $(daemon_LIBS)
 test_statrup_CFLAGS = $(daemon_CFLAGS)
 
+test_shutdown_SOURCES = daemon/test-shutdown.c
+test_shutdown_LDADD = $(daemon_LIBS)
+test_shutdown_CFLAGS = $(daemon_CFLAGS)
+
 check_PROGRAMS += $(daemon_TESTS)
 TESTS += $(daemon_TESTS)
diff --git a/daemon/dbus/gkd-dbus.c b/daemon/dbus/gkd-dbus.c
index b66af10..e13e88d 100644
--- a/daemon/dbus/gkd-dbus.c
+++ b/daemon/dbus/gkd-dbus.c
@@ -25,6 +25,7 @@
 #include "gkd-dbus.h"
 #include "gkd-dbus-private.h"
 
+#include "daemon/gkd-main.h"
 #include "daemon/gkd-util.h"
 
 #include "egg/egg-cleanup.h"
@@ -54,6 +55,13 @@ cleanup_session_bus (gpointer unused)
        dbus_conn = NULL;
 }
 
+static void
+on_connection_close (gpointer user_data)
+{
+       g_debug ("dbus connection closed, exiting");
+       gkd_main_quit ();
+}
+
 static gboolean
 connect_to_session_bus (void)
 {
@@ -72,7 +80,7 @@ connect_to_session_bus (void)
                return FALSE;
        }
 
-       egg_dbus_connect_with_mainloop (dbus_conn, NULL);
+       egg_dbus_connect_with_mainloop (dbus_conn, NULL, on_connection_close);
        dbus_connection_set_exit_on_disconnect (dbus_conn, FALSE);
        egg_cleanup_register (cleanup_session_bus, NULL);
        return TRUE;
diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c
index 731d205..6664c28 100644
--- a/daemon/gkd-main.c
+++ b/daemon/gkd-main.c
@@ -81,6 +81,8 @@ typedef int socklen_t;
 
 EGG_SECURE_DECLARE (daemon_main);
 
+static GMainLoop *loop = NULL;
+
 /* -----------------------------------------------------------------------------
  * COMMAND LINE
  */
@@ -902,8 +904,6 @@ on_idle_initialize (gpointer data)
 int
 main (int argc, char *argv[])
 {
-       GMainLoop *loop;
-
        /*
         * The gnome-keyring startup is not as simple as I wish it could be.
         *
diff --git a/daemon/test-shutdown.c b/daemon/test-shutdown.c
new file mode 100644
index 0000000..b2fdb0c
--- /dev/null
+++ b/daemon/test-shutdown.c
@@ -0,0 +1,115 @@
+/*
+   Copyright (C) 2014 Red Hat Inc
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   <http://www.gnu.org/licenses/>.
+
+   Author: Stef Walter <stefw gnome org>
+*/
+
+#include "config.h"
+
+#include "gkd-test.h"
+
+#include "daemon/control/gkd-control.h"
+
+#include "egg/egg-testing.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+
+typedef struct {
+       GTestDBus *dbus;
+       gchar *directory;
+       GPid pid;
+} Test;
+
+static void
+setup (Test *test,
+       gconstpointer unused)
+{
+       test->dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
+       g_test_dbus_up (test->dbus);
+
+       test->directory = egg_tests_create_scratch_directory (NULL, NULL);
+}
+
+static void
+teardown (Test *test,
+          gconstpointer unused)
+{
+       if (test->pid) {
+               if (waitpid (test->pid, NULL, WNOHANG) != test->pid) {
+                       kill (test->pid, SIGTERM);
+                       g_assert_cmpint (waitpid (test->pid, NULL, 0), ==, test->pid);
+               }
+               g_spawn_close_pid (test->pid);
+       }
+
+       egg_tests_remove_scratch_directory (test->directory);
+       g_free (test->directory);
+
+       if (test->dbus) {
+               g_test_dbus_down (test->dbus);
+               g_object_unref (test->dbus);
+       }
+}
+
+static void
+test_close_connection (Test *test,
+                       gconstpointer unused)
+{
+       const gchar *argv[] = {
+               BUILDDIR "/gnome-keyring-daemon", "--foreground",
+               "--components=secrets,pkcs11", NULL
+       };
+
+       const gchar *control;
+       gchar **output;
+       gint status;
+       GPid pid;
+
+       output = gkd_test_launch_daemon (test->directory, argv, &pid, NULL);
+
+       control = g_environ_getenv (output, "GNOME_KEYRING_CONTROL");
+       g_assert_cmpstr (control, !=, NULL);
+
+       g_assert (gkd_control_unlock (control, "booo"));
+       g_strfreev (output);
+
+       /* Now close the dbus connection */
+       g_test_dbus_down (test->dbus);
+       g_object_unref (test->dbus);
+       test->dbus = NULL;
+
+       /* Daemon should exit */
+       g_assert_cmpint (waitpid (pid, &status, 0), ==, pid);
+       g_assert_cmpint (status, ==, 0);
+}
+
+int
+main (int argc, char **argv)
+{
+       g_test_init (&argc, &argv, NULL);
+
+       g_test_add ("/daemon/shutdown/dbus-connection", Test, NULL,
+                   setup, test_close_connection, teardown);
+
+       return g_test_run ();
+}
diff --git a/egg/egg-dbus.c b/egg/egg-dbus.c
index dca3425..b3bfa9e 100644
--- a/egg/egg-dbus.c
+++ b/egg/egg-dbus.c
@@ -37,13 +37,21 @@
 typedef struct {
   GSource source;             /* the parent GSource */
   DBusConnection *connection; /* the connection to dispatch */
+  GDestroyNotify closed_cb;   /* Callback when closed */
 } DBusGMessageQueue;
 
 static gboolean
 message_queue_prepare (GSource *source, gint *timeout)
 {
-       DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;  
+       DBusGMessageQueue *queue = ((DBusGMessageQueue *)source);
+       DBusConnection *connection = queue->connection;
        *timeout = -1;
+       if (queue->closed_cb) {
+               if (!dbus_connection_get_is_connected (connection)) {
+                       (queue->closed_cb) (connection);
+                       queue->closed_cb = NULL;
+               }
+       }
        return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
 }
 
@@ -95,7 +103,9 @@ typedef struct {
 } TimeoutHandler;
 
 static ConnectionSetup*
-connection_setup_new (GMainContext *context, DBusConnection *connection)
+connection_setup_new (GMainContext *context,
+                      DBusConnection *connection,
+                      GDestroyNotify closed_cb)
 {
        ConnectionSetup *cs = g_new0 (ConnectionSetup, 1);
        g_assert (context != NULL);
@@ -108,6 +118,7 @@ connection_setup_new (GMainContext *context, DBusConnection *connection)
                cs->message_queue_source = g_source_new ((GSourceFuncs *) &message_queue_funcs,
                                                         sizeof (DBusGMessageQueue));
                ((DBusGMessageQueue*)cs->message_queue_source)->connection = connection;
+               ((DBusGMessageQueue*)cs->message_queue_source)->closed_cb = closed_cb;
                g_source_attach (cs->message_queue_source, cs->context);
        }
   
@@ -368,13 +379,15 @@ wakeup_main (void *data)
 }
 
 void
-egg_dbus_connect_with_mainloop (DBusConnection *connection, GMainContext *context)
+egg_dbus_connect_with_mainloop (DBusConnection *connection,
+                                GMainContext *context,
+                                GDestroyNotify close_callback)
 {
        ConnectionSetup *cs;
   
        if (context == NULL)
                context = g_main_context_default ();
-       cs = connection_setup_new (context, connection);
+       cs = connection_setup_new (context, connection, close_callback);
        the_setup = cs;
   
        if (!dbus_connection_set_watch_functions (connection, add_watch,
diff --git a/egg/egg-dbus.h b/egg/egg-dbus.h
index 81dc2e9..91b7ab3 100644
--- a/egg/egg-dbus.h
+++ b/egg/egg-dbus.h
@@ -27,7 +27,9 @@
 #include <glib.h>
 #include <dbus/dbus.h>
 
-void egg_dbus_connect_with_mainloop (DBusConnection *connection, GMainContext *context);
+void    egg_dbus_connect_with_mainloop     (DBusConnection *connection,
+                                            GMainContext *context,
+                                            GDestroyNotify close_callback);
 
 void egg_dbus_disconnect_from_mainloop (DBusConnection *connection, GMainContext *context);
 


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