[libsecret] Disconnect the cached default SecretService if service goes away



commit 175ae0898446de247530de47ae2a4edc0340e08e
Author: Stef Walter <stefw gnome org>
Date:   Fri Jul 6 10:08:27 2012 +0200

    Disconnect the cached default SecretService if service goes away
    
     * Because the session would no longer be valid if the service
       was autostarted for the same SecretService proxy

 docs/reference/libsecret/libsecret-sections.txt |    1 +
 library/secret-service.c                        |  116 +++++++++++++++++------
 library/tests/mock-service.c                    |    1 +
 library/tests/test-password.c                   |    1 -
 4 files changed, 88 insertions(+), 31 deletions(-)
---
diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt
index 3fbba6c..bd45c41 100644
--- a/docs/reference/libsecret/libsecret-sections.txt
+++ b/docs/reference/libsecret/libsecret-sections.txt
@@ -174,6 +174,7 @@ SecretServiceFlags
 secret_service_get
 secret_service_get_sync
 secret_service_get_finish
+secret_service_disconnect
 secret_service_new
 secret_service_new_finish
 secret_service_new_sync
diff --git a/library/secret-service.c b/library/secret-service.c
index b56c334..658b04d 100644
--- a/library/secret-service.c
+++ b/library/secret-service.c
@@ -124,6 +124,7 @@ struct _SecretServicePrivate {
 
 G_LOCK_DEFINE (service_instance);
 static gpointer service_instance = NULL;
+static guint service_watch = 0;
 
 static GInitableIface *secret_service_initable_parent_iface = NULL;
 
@@ -138,6 +139,84 @@ G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY,
                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface);
 );
 
+static SecretService *
+service_get_instance (void)
+{
+	SecretService *instance = NULL;
+
+	G_LOCK (service_instance);
+	if (service_instance != NULL)
+		instance = g_object_ref (service_instance);
+	G_UNLOCK (service_instance);
+
+	return instance;
+}
+
+static gboolean
+service_uncache_instance (SecretService *which)
+{
+	SecretService *instance = NULL;
+	guint watch = 0;
+	gboolean matched = FALSE;
+
+	G_LOCK (service_instance);
+	if (which == NULL || service_instance == which) {
+		instance = service_instance;
+		service_instance = NULL;
+		watch = service_watch;
+		service_watch = 0;
+		matched = TRUE;
+	}
+	G_UNLOCK (service_instance);
+
+	if (instance != NULL)
+		g_object_unref (instance);
+	if (watch != 0)
+		g_bus_unwatch_name (watch);
+
+	return matched;
+}
+
+static void
+on_service_instance_vanished (GDBusConnection *connection,
+                              const gchar *name,
+                              gpointer user_data)
+{
+	if (!service_uncache_instance (user_data)) {
+		g_warning ("Global default SecretService instance out of sync "
+		           "with the watch for its DBus name");
+	}
+}
+
+static void
+service_cache_instance (SecretService *instance)
+{
+	GDBusProxy *proxy;
+	guint watch;
+
+	g_object_ref (instance);
+	proxy = G_DBUS_PROXY (instance);
+	watch = g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (proxy),
+	                                        g_dbus_proxy_get_name (proxy),
+	                                        G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
+	                                        NULL, on_service_instance_vanished,
+	                                        instance, NULL);
+
+	G_LOCK (service_instance);
+	if (service_instance == NULL) {
+		service_instance = instance;
+		instance = NULL;
+		service_watch = watch;
+		watch = 0;
+	}
+	G_UNLOCK (service_instance);
+
+	if (instance != NULL)
+		g_object_unref (instance);
+	if (watch != 0)
+		g_bus_unwatch_name (watch);
+}
+
 static void
 secret_service_init (SecretService *self)
 {
@@ -678,10 +757,7 @@ secret_service_get (SecretServiceFlags flags,
 	GSimpleAsyncResult *res;
 	InitClosure *closure;
 
-	G_LOCK (service_instance);
-	if (service_instance != NULL)
-		service = g_object_ref (service_instance);
-	G_UNLOCK (service_instance);
+	service = service_get_instance ();
 
 	/* Create a whole new service */
 	if (service == NULL) {
@@ -743,13 +819,8 @@ secret_service_get_finish (GAsyncResult *result,
 	/* Creating a whole new service */
 	} else {
 		service = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
-
-		if (service) {
-			G_LOCK (service_instance);
-			if (service_instance == NULL)
-				service_instance = g_object_ref (service);
-			G_UNLOCK (service_instance);
-		}
+		if (service)
+			service_cache_instance (SECRET_SERVICE (service));
 	}
 
 	if (source_object)
@@ -786,10 +857,7 @@ secret_service_get_sync (SecretServiceFlags flags,
 {
 	SecretService *service = NULL;
 
-	G_LOCK (service_instance);
-	if (service_instance != NULL)
-		service = g_object_ref (service_instance);
-	G_UNLOCK (service_instance);
+	service = service_get_instance ();
 
 	if (service == NULL) {
 		service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error,
@@ -802,12 +870,8 @@ secret_service_get_sync (SecretServiceFlags flags,
 		                          "flags", flags,
 		                          NULL);
 
-		if (service != NULL) {
-			G_LOCK (service_instance);
-			if (service_instance == NULL)
-				service_instance = g_object_ref (service);
-			G_UNLOCK (service_instance);
-		}
+		if (service != NULL)
+			service_cache_instance (service);
 
 	} else {
 		if (!service_ensure_for_flags_sync (service, flags, cancellable, error)) {
@@ -835,15 +899,7 @@ secret_service_get_sync (SecretServiceFlags flags,
 void
 secret_service_disconnect (void)
 {
-	SecretService *instance;
-
-	G_LOCK (service_instance);
-	instance = service_instance;
-	service_instance = NULL;
-	G_UNLOCK (service_instance);
-
-	if (instance != NULL)
-		g_object_unref (instance);
+	service_uncache_instance (NULL);
 }
 
 /**
diff --git a/library/tests/mock-service.c b/library/tests/mock-service.c
index feb6690..6a5a0f6 100644
--- a/library/tests/mock-service.c
+++ b/library/tests/mock-service.c
@@ -88,5 +88,6 @@ mock_service_stop (void)
 	}
 
 	g_spawn_close_pid (pid);
+	secret_service_disconnect ();
 	pid = 0;
 }
diff --git a/library/tests/test-password.c b/library/tests/test-password.c
index d541daf..d5829df 100644
--- a/library/tests/test-password.c
+++ b/library/tests/test-password.c
@@ -74,7 +74,6 @@ static void
 teardown (Test *test,
           gconstpointer unused)
 {
-	secret_service_disconnect ();
 	mock_service_stop ();
 }
 



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