[gnome-keyring] [daemon] Rework the startup again, singleton crontrolled via dbus.
- From: Stefan Walter <stefw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-keyring] [daemon] Rework the startup again, singleton crontrolled via dbus.
- Date: Sun, 14 Feb 2010 05:25:18 +0000 (UTC)
commit 43590189620c9dc5cda9854fef899fe89b24d308
Author: Stef Walter <stef memberwebs com>
Date: Sun Feb 14 05:15:10 2010 +0000
[daemon] Rework the startup again, singleton crontrolled via dbus.
Account for starting dbus via the autostart files (ie: various
components individually), but without a gnome-keyring-daemon running
from pam. This previously caused multiple processes. We use a dbus
singleton in this case.
daemon/control/gkd-control-client.c | 4 +-
daemon/dbus/Makefile.am | 1 -
daemon/dbus/gkd-dbus-service.c | 155 ---------------------
daemon/dbus/gkd-dbus.c | 252 +++++++++++++++++++++++++++++++----
daemon/dbus/gkd-dbus.h | 4 +
daemon/gkd-main.c | 66 +++++++---
6 files changed, 280 insertions(+), 202 deletions(-)
---
diff --git a/daemon/control/gkd-control-client.c b/daemon/control/gkd-control-client.c
index eaf9d6d..58d7d62 100644
--- a/daemon/control/gkd-control-client.c
+++ b/daemon/control/gkd-control-client.c
@@ -208,10 +208,8 @@ gkd_control_initialize (const gchar *directory, const gchar *components,
egg_buffer_uninit (&buffer);
- if (!ret || res != GKD_CONTROL_RESULT_OK) {
- g_message ("couldn't initialize running daemon");
+ if (!ret || res != GKD_CONTROL_RESULT_OK)
return NULL;
- }
return env;
}
diff --git a/daemon/dbus/Makefile.am b/daemon/dbus/Makefile.am
index 3ec7399..3a1a9ee 100644
--- a/daemon/dbus/Makefile.am
+++ b/daemon/dbus/Makefile.am
@@ -15,7 +15,6 @@ libgkd_dbus_la_SOURCES = \
gkd-dbus-environment.c \
gkd-dbus-private.h \
gkd-dbus-secrets.c \
- gkd-dbus-service.c \
gkd-dbus-session.c \
gkd-dbus-util.c gkd-dbus-util.h \
gkd-secret-change.c gkd-secret-change.h \
diff --git a/daemon/dbus/gkd-dbus.c b/daemon/dbus/gkd-dbus.c
index 6b469f8..4688d18 100644
--- a/daemon/dbus/gkd-dbus.c
+++ b/daemon/dbus/gkd-dbus.c
@@ -26,6 +26,8 @@
#include "gkd-dbus.h"
#include "gkd-dbus-private.h"
+#include "gkd-util.h"
+
#include "egg/egg-cleanup.h"
#include "egg/egg-dbus.h"
@@ -34,35 +36,32 @@
#include <dbus/dbus.h>
static DBusConnection *dbus_conn = NULL;
-static gboolean dbus_do_session = TRUE;
+static gboolean object_registered = FALSE;
+static gboolean acquired_asked = FALSE;
+static gboolean acquired_service = FALSE;
+
+#define GNOME_KEYRING_DAEMON_SERVICE "org.gnome.keyring"
+#define GNOME_KEYRING_DAEMON_PATH "/org/gnome/keyring/daemon"
+#define GNOME_KEYRING_DAEMON_INTERFACE "org.gnome.keyring.Daemon"
static void
-daemon_dbus_cleanup (gpointer unused)
+cleanup_session_bus (gpointer unused)
{
if (!dbus_conn)
return;
- gkd_dbus_secrets_cleanup (dbus_conn);
-
- if (dbus_do_session) {
- gkd_dbus_session_cleanup (dbus_conn);
- gkd_dbus_environment_cleanup (dbus_conn);
- }
-
- gkd_dbus_service_cleanup (dbus_conn);
-
egg_dbus_disconnect_from_mainloop (dbus_conn, NULL);
dbus_connection_unref (dbus_conn);
dbus_conn = NULL;
}
-void
-gkd_dbus_setup (void)
+static gboolean
+connect_to_session_bus (void)
{
DBusError derr = { 0 };
if (dbus_conn)
- return;
+ return TRUE;
dbus_error_init (&derr);
@@ -71,25 +70,228 @@ gkd_dbus_setup (void)
if (!dbus_conn) {
g_message ("couldn't connect to dbus session bus: %s", derr.message);
dbus_error_free (&derr);
- return;
+ return FALSE;
}
- egg_cleanup_register (daemon_dbus_cleanup, NULL);
-
egg_dbus_connect_with_mainloop (dbus_conn, NULL);
-
- /* Make sure dbus doesn't kill our app */
dbus_connection_set_exit_on_disconnect (dbus_conn, FALSE);
+ egg_cleanup_register (cleanup_session_bus, NULL);
+ return TRUE;
+}
- /* Gnome Keyring service */
- gkd_dbus_service_init (dbus_conn);
+static DBusHandlerResult
+message_handler_cb (DBusConnection *conn, DBusMessage *message, void *user_data)
+{
+ /*
+ * Here we handle the requests to our own gnome-keyring DBus interfaces
+ */
- /* Session stuff */
- if (dbus_do_session) {
- gkd_dbus_environment_init (dbus_conn);
- gkd_dbus_session_init (dbus_conn);
+ DBusMessageIter args;
+ DBusMessage *reply = NULL;
+
+ /* GetEnvironment */
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
+ dbus_message_is_method_call (message, GNOME_KEYRING_DAEMON_INTERFACE, "GetEnvironment") &&
+ g_str_equal (dbus_message_get_signature (message), "")) {
+
+ const gchar **env;
+ DBusMessageIter items, entry;
+ gchar **parts;
+
+ env = gkd_util_get_environment ();
+ g_return_val_if_fail (env, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+ /* Setup the result */
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &args);
+ if (!dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY, "{ss}", &items))
+ g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
+ while (*env) {
+ parts = g_strsplit (*env, "=", 2);
+ g_return_val_if_fail (parts && parts[0] && parts[1], DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+ if (!dbus_message_iter_open_container (&items, DBUS_TYPE_DICT_ENTRY, NULL, &entry) ||
+ !dbus_message_iter_append_basic (&entry, DBUS_TYPE_STRING, &parts[0]) ||
+ !dbus_message_iter_append_basic (&entry, DBUS_TYPE_STRING, &parts[1]) ||
+ !dbus_message_iter_close_container (&items, &entry))
+ g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
+ ++env;
+ }
+ if (!dbus_message_iter_close_container (&args, &items))
+ g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
+
+ /* GetControlDirectory */
+ } else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
+ dbus_message_is_method_call (message, GNOME_KEYRING_DAEMON_INTERFACE, "GetControlDirectory") &&
+ g_str_equal (dbus_message_get_signature (message), "")) {
+
+ /* Setup the result */
+ const gchar *directory = gkd_util_get_master_directory ();
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_STRING, &directory, DBUS_TYPE_INVALID);
+
+ /* Unknown call */
+ } else {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ /* Send the reply */
+ if (!dbus_connection_send (conn, reply, NULL))
+ g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
+ dbus_connection_flush (conn);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusObjectPathVTable object_vtable = {
+ NULL,
+ message_handler_cb,
+ NULL,
+};
+
+static void
+cleanup_singleton (gpointer unused)
+{
+ g_return_if_fail (dbus_conn);
+ if (object_registered)
+ dbus_connection_unregister_object_path (dbus_conn, GNOME_KEYRING_DAEMON_PATH);
+ object_registered = FALSE;
+}
+
+gboolean
+gkd_dbus_singleton_acquire (gboolean *acquired)
+{
+ DBusError derr = DBUS_ERROR_INIT;
+ dbus_uint32_t res = 0;
+ const gchar *service = NULL;
+ unsigned int flags;
+
+ g_assert (acquired);
+
+ if (!connect_to_session_bus ())
+ return FALSE;
+
+ /* First register the object */
+ if (!object_registered) {
+ if (dbus_connection_register_object_path (dbus_conn, GNOME_KEYRING_DAEMON_PATH,
+ &object_vtable, NULL)) {
+ object_registered = TRUE;
+ egg_cleanup_register (cleanup_singleton, NULL);
+ } else {
+ g_message ("couldn't register dbus object path");
+ }
}
+ /* Try and grab our name */
+ if (!acquired_asked) {
+
+#ifdef WITH_TESTS
+ service = g_getenv ("GNOME_KEYRING_TEST_SERVICE");
+ if (service && service[0])
+ flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT | DBUS_NAME_FLAG_REPLACE_EXISTING;
+ else
+#endif
+ service = GNOME_KEYRING_DAEMON_SERVICE;
+
+ res = dbus_bus_request_name (dbus_conn, service, 0, &derr);
+ if (dbus_error_is_set (&derr)) {
+ g_message ("couldn't request name '%s' on session bus: %s", service, derr.message);
+ dbus_error_free (&derr);
+ return FALSE;
+ }
+
+ acquired_asked = TRUE;
+ switch (res) {
+ /* We acquired the service name */
+ case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+ case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+ acquired_service = TRUE;
+ break;
+ /* Another daemon is running */
+ case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+ case DBUS_REQUEST_NAME_REPLY_EXISTS:
+ acquired_service = FALSE;
+ break;
+ default:
+ acquired_service = FALSE;
+ g_return_val_if_reached (FALSE);
+ break;
+ };
+ }
+
+ *acquired = acquired_service;
+ return TRUE;
+}
+
+gchar*
+gkd_dbus_singleton_control (void)
+{
+ DBusError derr = DBUS_ERROR_INIT;
+ DBusMessage *msg, *reply;
+ gchar *control = NULL;
+ const char *path;
+
+ /* Must have tried to aquire the service, and failed */
+ g_return_val_if_fail (acquired_asked, NULL);
+ g_return_val_if_fail (!acquired_service, NULL);
+
+ if (!connect_to_session_bus())
+ return NULL;
+
+ msg = dbus_message_new_method_call (GNOME_KEYRING_DAEMON_SERVICE,
+ GNOME_KEYRING_DAEMON_PATH,
+ GNOME_KEYRING_DAEMON_INTERFACE,
+ "GetControlDirectory");
+ g_return_val_if_fail (msg, NULL);
+
+ /* Send message and get a handle for a reply */
+ reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
+ dbus_message_unref (msg);
+
+ if (!reply) {
+ g_message ("couldn't communicate with already running daemon: %s", derr.message);
+ dbus_error_free (&derr);
+ return NULL;
+ }
+
+ /* Get out our client path */
+ if (!dbus_message_get_args (reply, &derr, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) {
+ g_message ("couldn't parse response from already running daemon: %s", derr.message);
+ dbus_error_free (&derr);
+ control = NULL;
+ } else {
+ control = g_strdup (path);
+ }
+
+ dbus_message_unref (reply);
+ return control;
+}
+
+static void
+dbus_cleanup (gpointer unused)
+{
+ g_return_if_fail (dbus_conn);
+ gkd_dbus_secrets_cleanup (dbus_conn);
+ gkd_dbus_session_cleanup (dbus_conn);
+ gkd_dbus_environment_cleanup (dbus_conn);
+}
+
+void
+gkd_dbus_setup (void)
+{
+ gboolean unused;
+
+ if (!connect_to_session_bus ())
+ return;
+
+ /* Our singleton, and internal service API */
+ gkd_dbus_singleton_acquire (&unused);
+
+ /* Session stuff */
+ gkd_dbus_environment_init (dbus_conn);
+ gkd_dbus_session_init (dbus_conn);
+
/* Secrets API */
gkd_dbus_secrets_init (dbus_conn);
+
+ egg_cleanup_register (dbus_cleanup, NULL);
}
diff --git a/daemon/dbus/gkd-dbus.h b/daemon/dbus/gkd-dbus.h
index ed20138..93cfe9a 100644
--- a/daemon/dbus/gkd-dbus.h
+++ b/daemon/dbus/gkd-dbus.h
@@ -30,4 +30,8 @@ void gkd_dbus_setup (void);
gboolean gkd_dbus_secrets_startup (void);
+gboolean gkd_dbus_singleton_acquire (gboolean *acquired);
+
+gchar* gkd_dbus_singleton_control (void);
+
#endif /* GKD_DBUS_H */
diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c
index e1455b4..dab83cc 100644
--- a/daemon/gkd-main.c
+++ b/daemon/gkd-main.c
@@ -453,15 +453,11 @@ print_environment (pid_t pid)
printf ("GNOME_KEYRING_PID=%d\n", (gint)pid);
}
-
static gboolean
-start_or_initialize_daemon (const gchar *directory)
+initialize_daemon_at (const gchar *directory)
{
gchar **ourenv, **daemonenv, **e;
- if (!directory)
- return FALSE;
-
/* Exchange environment variables, and try to initialize daemon */
ourenv = gkd_util_build_environment (GKD_UTIL_IN_ENVIRONMENT);
daemonenv = gkd_control_initialize (directory, run_components,
@@ -477,19 +473,47 @@ start_or_initialize_daemon (const gchar *directory)
gkd_util_push_environment_full (*e);
g_strfreev (daemonenv);
- /*
- * Now we've initialized the daemon, we need to print out
- * the daemon's environment for any callers, and possibly
- * block if we've been asked to remain in the foreground.
- */
- print_environment (0);
+ return TRUE;
+}
- /* TODO: Better way to sleep forever? */
- if (run_foreground) {
- while (sleep(0x08000000) == 0);
+static gboolean
+initialize_daemon (const gchar *directory)
+{
+ gchar *control = NULL;
+ gboolean acquired, ret;
+
+ /* A pre-specified directory to control at */
+ if (directory) {
+ if (initialize_daemon_at (directory))
+ return TRUE;
}
- return TRUE;
+ /* An environment variable from an already running daemon */
+ directory = g_getenv (GKD_UTIL_ENV_CONTROL);
+ if (directory && directory[0]) {
+ if (initialize_daemon_at (directory))
+ return TRUE;
+ }
+
+ /* See if we can contact a daemon running, that didn't set an env variable */
+ if (!gkd_dbus_singleton_acquire (&acquired))
+ return FALSE;
+
+ /* We're the main daemon */
+ if (acquired)
+ return FALSE;
+
+ /* Figure out the path to the other daemon's control directory */
+ directory = control = gkd_dbus_singleton_control ();
+ if (directory) {
+ ret = initialize_daemon_at (directory);
+ g_free (control);
+ if (ret == TRUE)
+ return TRUE;
+ }
+
+ g_message ("couldn't initialize running daemon");
+ return FALSE;
}
static void
@@ -720,10 +744,16 @@ main (int argc, char *argv[])
/* The --start option */
if (run_for_start) {
- if (!control_directory)
- control_directory = g_getenv (GKD_UTIL_ENV_CONTROL);
- if (start_or_initialize_daemon (control_directory))
+ if (initialize_daemon (control_directory)) {
+ /*
+ * Another daemon was initialized, print out environment
+ * for any callers, and quit or go comatose.
+ */
+ print_environment (0);
+ if (run_foreground)
+ while (sleep(0x08000000) == 0);
cleanup_and_exit (0);
+ }
}
/* Initialize the main directory */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]