[gnome-keyring] gck: Add async initialization functions.



commit 25b32cc25c7bf5a2707204743c04fed63c7e2e18
Author: Stef Walter <stefw collabora co uk>
Date:   Thu Aug 25 11:21:24 2011 +0200

    gck: Add async initialization functions.
    
     * PKCS#11 modules can take indeterminate time to initialize
     * Allow initialization in a separate thread

 docs/reference/gck/gck-sections.txt |    8 ++-
 gck/gck-call.c                      |    7 +-
 gck/gck-module.c                    |  150 +++++++++++++++++++++++++++--------
 gck/gck-modules.c                   |  108 +++++++++++++++++++++----
 gck/gck.h                           |   17 ++++-
 gck/tests/Makefile.am               |    2 +-
 gck/tests/test-gck-module.c         |   51 ++++++++++--
 po/POTFILES.in                      |    2 +
 8 files changed, 281 insertions(+), 64 deletions(-)
---
diff --git a/docs/reference/gck/gck-sections.txt b/docs/reference/gck/gck-sections.txt
index ed878b7..56e05c2 100644
--- a/docs/reference/gck/gck-sections.txt
+++ b/docs/reference/gck/gck-sections.txt
@@ -62,8 +62,10 @@ GckAllocator
 <SECTION>
 <FILE>gck-module</FILE>
 GckModule
-gck_module_new
 gck_module_initialize
+gck_module_initialize_async
+gck_module_initialize_finish
+gck_module_new
 gck_module_equal
 gck_module_hash
 gck_module_get_path
@@ -86,10 +88,12 @@ GckModulePrivate
 
 <SECTION>
 <FILE>gck-modules</FILE>
+gck_modules_initialize_registered
+gck_modules_initialize_registered_async
+gck_modules_initialize_registered_finish
 gck_modules_enumerate_objects
 gck_modules_enumerate_uri
 gck_modules_get_slots
-gck_modules_initialize_registered
 gck_modules_object_for_uri
 gck_modules_objects_for_uri
 gck_modules_token_for_uri
diff --git a/gck/gck-call.c b/gck/gck-call.c
index 6e46632..f839330 100644
--- a/gck/gck-call.c
+++ b/gck/gck-call.c
@@ -149,8 +149,7 @@ process_result (GckCall *call, gpointer unused)
 
 	/* All done, finish processing */
 	} else if (call->callback) {
-		g_assert (G_IS_OBJECT (call->object));
-		(call->callback) (G_OBJECT (call->object), G_ASYNC_RESULT (call),
+		(call->callback) (call->object, G_ASYNC_RESULT (call),
 				  call->user_data);
 	}
 }
@@ -423,6 +422,7 @@ _gck_call_async_prep (gpointer object, gpointer cb_object, gpointer perform,
 	GckCall *call;
 
 	g_assert (!object || G_IS_OBJECT (object));
+	g_assert (!cb_object || G_IS_OBJECT (cb_object));
 	g_assert (perform);
 
 	if (!destroy)
@@ -437,8 +437,7 @@ _gck_call_async_prep (gpointer object, gpointer cb_object, gpointer perform,
 	call->destroy = (GDestroyNotify)destroy;
 	call->perform = (GckPerformFunc)perform;
 	call->complete = (GckCompleteFunc)complete;
-	call->object = cb_object;
-	g_object_ref (cb_object);
+	call->object = cb_object ? g_object_ref (cb_object) : NULL;
 
 	/* Hook the two together */
 	call->args = args;
diff --git a/gck/gck-module.c b/gck/gck-module.c
index c7e7646..fa2fd84 100644
--- a/gck/gck-module.c
+++ b/gck/gck-module.c
@@ -27,6 +27,8 @@
 #include "gck-private.h"
 #include "gck-marshal.h"
 
+#include <glib/gi18n.h>
+
 #include <p11-kit/p11-kit.h>
 
 #include <string.h>
@@ -371,66 +373,150 @@ gck_module_info_free (GckModuleInfo *module_info)
 	g_free (module_info);
 }
 
-/**
- * gck_module_initialize:
- * @path: The file system path to the PKCS\#11 module to load.
- * @error: A location to store an error resulting from a failed load.
- *
- * Load and initialize a PKCS\#11 module represented by a GckModule object.
- *
- * Return value: The loaded PKCS\#11 module or NULL if failed.
- **/
-GckModule*
-gck_module_initialize (const gchar *path, GError **error)
+typedef struct {
+	GckArguments base;
+	gchar *path;
+	GckModule *result;
+	GError *error;
+} Initialize;
+
+static CK_RV
+perform_initialize (Initialize *args)
 {
 	CK_C_GetFunctionList get_function_list;
 	CK_FUNCTION_LIST_PTR funcs;
 	GModule *module;
-	GckModule *self;
+	GckModule *result;
 	CK_RV rv;
 
-	g_return_val_if_fail (path != NULL, NULL);
-	g_return_val_if_fail (!error || !*error, NULL);
-
 	/* Load the actual module */
-	module = g_module_open (path, 0);
+	module = g_module_open (args->path, 0);
 	if (!module) {
-		g_set_error (error, GCK_ERROR, (int)CKR_GCK_MODULE_PROBLEM,
-		             "Error loading pkcs11 module: %s", g_module_error ());
-		return NULL;
+		g_set_error (&args->error, GCK_ERROR, (int)CKR_GCK_MODULE_PROBLEM,
+		             _("Error loading PKCS#11 module: %s"), g_module_error ());
+		return CKR_GCK_MODULE_PROBLEM;
 	}
 
 	/* Get the entry point */
 	if (!g_module_symbol (module, "C_GetFunctionList", (void**)&get_function_list)) {
-		g_set_error (error, GCK_ERROR, (int)CKR_GCK_MODULE_PROBLEM,
-		             "Invalid pkcs11 module: %s", g_module_error ());
+		g_set_error (&args->error, GCK_ERROR, (int)CKR_GCK_MODULE_PROBLEM,
+		             _("Invalid PKCS#11 module: %s"), g_module_error ());
 		g_module_close (module);
-		return NULL;
+		return CKR_GCK_MODULE_PROBLEM;
 	}
 
 	/* Get the function list */
 	rv = (get_function_list) (&funcs);
 	if (rv != CKR_OK) {
-		g_set_error (error, GCK_ERROR, rv, "Couldn't get pkcs11 function list: %s",
+		g_set_error (&args->error, GCK_ERROR, rv,
+		             _("Couldn't setup PKCS#11 module: %s"),
 		             gck_message_from_rv (rv));
 		g_module_close (module);
-		return NULL;
+		return rv;
 	}
 
-	self = g_object_new (GCK_TYPE_MODULE, "functions", funcs, "path", path, NULL);
-	self->pv->module = module;
+	result = g_object_new (GCK_TYPE_MODULE,
+	                       "functions", funcs,
+	                       "path", args->path,
+	                       NULL);
+	result->pv->module = module;
 
 	/* Now initialize the module */
-	rv = p11_kit_initialize_module (self->pv->funcs);
+	rv = p11_kit_initialize_module (funcs);
 	if (rv != CKR_OK) {
-		g_set_error (error, GCK_ERROR, rv, "Couldn't initialize module: %s",
+		g_set_error (&args->error, GCK_ERROR, rv,
+		             _("Couldn't initialize PKCS#11 module: %s"),
 		             gck_message_from_rv (rv));
-		g_object_unref (self);
-		return NULL;
+		g_object_unref (result);
+		return rv;
+	}
+
+	result->pv->initialized = TRUE;
+	args->result = result;
+	return CKR_OK;
+}
+
+static void
+free_initialize (Initialize *args)
+{
+	g_free (args->path);
+	g_clear_error (&args->error);
+	g_clear_object (&args->result);
+	g_free (args);
+}
+
+/**
+ * gck_module_initialize:
+ * @path: The file system path to the PKCS\#11 module to load.
+ * @error: A location to store an error resulting from a failed load.
+ *
+ * Load and initialize a PKCS\#11 module represented by a GckModule object.
+ *
+ * Return value: The loaded PKCS\#11 module or NULL if failed.
+ **/
+GckModule*
+gck_module_initialize (const gchar *path,
+                       GError **error)
+{
+	Initialize args = { GCK_ARGUMENTS_INIT, 0,  };
+
+	g_return_val_if_fail (path != NULL, NULL);
+	g_return_val_if_fail (!error || !*error, NULL);
+
+	args.path = g_strdup (path);
+
+	if (!_gck_call_sync (NULL, perform_initialize, NULL, &args, NULL, error)) {
+
+		/* A custom error from perform_initialize */
+		if (args.error) {
+			g_clear_error (error);
+			g_propagate_error (error, args.error);
+			args.error = NULL;
+		}
 	}
 
-	self->pv->initialized = TRUE;
-	return self;
+	g_free (args.path);
+	g_clear_error (&args.error);
+	return args.result;
+}
+
+void
+gck_module_initialize_async (const gchar *path,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+	Initialize *args;
+
+	args =  _gck_call_async_prep (NULL, NULL, perform_initialize, NULL,
+	                              sizeof (*args), free_initialize);
+	args->path = g_strdup (path);
+
+	_gck_call_async_ready_go (args, cancellable, callback, user_data);
+}
+
+GckModule *
+gck_module_initialize_finish (GAsyncResult *result,
+                              GError **error)
+{
+	GckModule *module = NULL;
+	Initialize *args;
+
+	args = _gck_call_arguments (result, Initialize);
+	if (_gck_call_basic_finish (result, error)) {
+		module = args->result;
+		args->result = NULL;
+
+	} else {
+		/* A custom error from perform_initialize */
+		if (args->error) {
+			g_clear_error (error);
+			g_propagate_error (error, args->error);
+			args->error = NULL;
+		}
+	}
+
+	return module;
 }
 
 /**
diff --git a/gck/gck-modules.c b/gck/gck-modules.c
index 4782688..fd0d456 100644
--- a/gck/gck-modules.c
+++ b/gck/gck-modules.c
@@ -27,6 +27,9 @@
 #include "gck-private.h"
 #include "gck-marshal.h"
 
+#include <glib/gi18n.h>
+
+#define P11_KIT_FUTURE_UNSTABLE_API 1
 #include <p11-kit/p11-kit.h>
 
 #include <string.h>
@@ -41,39 +44,110 @@
  * operations on all of them.
  */
 
-/**
- * gck_modules_initialize_registered:
- *
- * Load and initialize all the registered modules.
- *
- * Returns: A newly allocated list of GckModule objects, which should
- * be released with gck_list_unref_free().
- */
-GList*
-gck_modules_initialize_registered (void)
+typedef struct {
+	GckArguments base;
+	GList *results;
+	GError *error;
+} InitializeRegistered;
+
+static CK_RV
+perform_initialize_registered (InitializeRegistered *args)
 {
 	GckModule *module;
-	GList *results = NULL;
 	CK_FUNCTION_LIST_PTR *modules, *funcs;
+	const gchar *message;
 	CK_RV rv;
 
 	rv = p11_kit_initialize_registered ();
 	if (rv != CKR_OK) {
-		g_warning ("couldn't initialize registered PKCS#11 modules: %s",
-		           gck_message_from_rv (rv));
-		return NULL;
+		message = p11_kit_message ();
+		if (message == NULL)
+			message = gck_message_from_rv (rv);
+		g_set_error (&args->error, GCK_ERROR, (int)CKR_GCK_MODULE_PROBLEM,
+		             _("Couldn't initialize registered PKCS#11 modules: %s"), message);
+		return rv;
 	}
 
 	modules = p11_kit_registered_modules ();
-
 	for (funcs = modules; *funcs; ++funcs) {
 		module = _gck_module_new_initialized (*funcs);
-		results = g_list_prepend (results, module);
+		args->results = g_list_prepend (args->results, module);
 	}
 
 	free (modules);
+	return CKR_OK;
+}
 
-	return results;
+static void
+free_initialize_registered (InitializeRegistered *args)
+{
+	g_clear_error (&args->error);
+	gck_list_unref_free (args->results);
+	g_free (args);
+}
+
+/**
+ * gck_modules_initialize_registered:
+ *
+ * Load and initialize all the registered modules.
+ *
+ * Returns: A newly allocated list of GckModule objects, which should
+ * be released with gck_list_unref_free().
+ */
+GList*
+gck_modules_initialize_registered (void)
+{
+	InitializeRegistered args = { GCK_ARGUMENTS_INIT, 0,  };
+	GError *error = NULL;
+
+	if (!_gck_call_sync (NULL, perform_initialize_registered, NULL, &args, NULL, &error)) {
+		if (args.error)
+			g_warning ("%s", args.error->message);
+		else
+			g_warning ("couldn't initialize registered PKCS#11 modules: %s",
+			           error->message);
+	}
+
+	g_clear_error (&args.error);
+	g_clear_error (&error);
+	return args.results;
+}
+
+void
+gck_modules_initialize_registered_async (GCancellable *cancellable,
+                                         GAsyncReadyCallback callback,
+                                         gpointer user_data)
+{
+	InitializeRegistered *args;
+
+	args =  _gck_call_async_prep (NULL, NULL, perform_initialize_registered, NULL,
+	                              sizeof (*args), free_initialize_registered);
+
+	_gck_call_async_ready_go (args, cancellable, callback, user_data);
+}
+
+GList *
+gck_modules_initialize_registered_finish (GAsyncResult *result,
+                                          GError **error)
+{
+	GList *modules = NULL;
+	InitializeRegistered *args;
+
+	args = _gck_call_arguments (result, InitializeRegistered);
+	if (_gck_call_basic_finish (result, error)) {
+		modules = args->results;
+		args->results = NULL;
+
+	} else {
+		/* A custom error from perform_initialize */
+		if (args->error) {
+			g_clear_error (error);
+			g_propagate_error (error, args->error);
+			args->error = NULL;
+		}
+	}
+
+	return modules;
 }
 
 /**
diff --git a/gck/gck.h b/gck/gck.h
index 4de88fd..cdf280f 100644
--- a/gck/gck.h
+++ b/gck/gck.h
@@ -301,6 +301,14 @@ GckModule*            gck_module_new                          (CK_FUNCTION_LIST_
 GckModule*            gck_module_initialize                   (const gchar *path,
                                                                GError **error);
 
+void                  gck_module_initialize_async             (const gchar *path,
+                                                               GCancellable *cancellable,
+                                                               GAsyncReadyCallback callback,
+                                                               gpointer user_data);
+
+GckModule *           gck_module_initialize_finish            (GAsyncResult *result,
+                                                               GError **error);
+
 gboolean              gck_module_equal                        (gconstpointer module1,
                                                                gconstpointer module2);
 
@@ -315,7 +323,14 @@ GckModuleInfo*        gck_module_get_info                     (GckModule *self);
 GList*                gck_module_get_slots                    (GckModule *self,
                                                                gboolean token_present);
 
-GList*                gck_modules_initialize_registered       (void);
+GList*                gck_modules_initialize_registered        (void);
+
+void                  gck_modules_initialize_registered_async  (GCancellable *cancellable,
+                                                                GAsyncReadyCallback callback,
+                                                                gpointer user_data);
+
+GList *               gck_modules_initialize_registered_finish (GAsyncResult *result,
+                                                                GError **error);
 
 GList*                gck_modules_get_slots                   (GList *modules,
                                                                gboolean token_present);
diff --git a/gck/tests/Makefile.am b/gck/tests/Makefile.am
index e43f2e6..4864fb8 100644
--- a/gck/tests/Makefile.am
+++ b/gck/tests/Makefile.am
@@ -30,7 +30,7 @@ TEST_PROGS = \
 check_PROGRAMS = $(TEST_PROGS)
 
 test: $(TEST_PROGS)
-	gtester -k --verbose -m $(TEST_MODE) --g-fatal-warnings $(TEST_PROGS)
+	gtester --verbose -m $(TEST_MODE) --g-fatal-warnings $(TEST_PROGS)
 
 check-local: test
 
diff --git a/gck/tests/test-gck-module.c b/gck/tests/test-gck-module.c
index 7e1b92a..72df360 100644
--- a/gck/tests/test-gck-module.c
+++ b/gck/tests/test-gck-module.c
@@ -27,6 +27,8 @@
 #include <glib.h>
 #include <string.h>
 
+#include "egg/egg-testing.h"
+
 #include "gck/gck.h"
 #include "gck/gck-test.h"
 
@@ -52,22 +54,56 @@ teardown (Test *test, gconstpointer unused)
 }
 
 static void
+fetch_async_result (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+	*((GAsyncResult**)user_data) = result;
+	g_object_ref (result);
+	egg_test_wait_stop ();
+}
+
+static void
+test_initialize_async (void)
+{
+	GckModule *module;
+	GAsyncResult *result;
+	GError *error = NULL;
+
+	/* Shouldn't be able to load modules */
+	gck_module_initialize_async (BUILDDIR "/.libs/libmock-test-module.so",
+	                             NULL, fetch_async_result, &result);
+
+	egg_test_wait_until (500);
+	g_assert (result != NULL);
+
+	/* Get the result */
+	module = gck_module_initialize_finish (result, &error);
+	g_assert_no_error (error);
+	g_assert (GCK_IS_MODULE (module));
+
+	g_object_unref (result);
+	g_object_unref (module);
+}
+
+
+static void
 test_invalid_modules (Test *test, gconstpointer unused)
 {
 	GckModule *invalid;
-	GError *err = NULL;
+	GError *error = NULL;
 
 	/* Shouldn't be able to load modules */
-	invalid = gck_module_initialize ("blah-blah-non-existant", &err);
+	invalid = gck_module_initialize ("blah-blah-non-existant", &error);
+	g_assert_error (error, GCK_ERROR, (int)CKR_GCK_MODULE_PROBLEM);
 	g_assert (invalid == NULL);
-	g_assert_error (err, GCK_ERROR, CKR_GCK_MODULE_PROBLEM);
 
-	g_clear_error (&err);
+	g_clear_error (&error);
 
 	/* Shouldn't be able to load any file successfully */
-	invalid = gck_module_initialize ("/usr/lib/libm.so", &err);
+	invalid = gck_module_initialize ("/usr/lib/libm.so", &error);
+	g_assert_error (error, GCK_ERROR, (int)CKR_GCK_MODULE_PROBLEM);
 	g_assert (invalid == NULL);
-	g_assert_error (err, GCK_ERROR, CKR_GCK_MODULE_PROBLEM);
+
+	g_clear_error (&error);
 }
 
 static void
@@ -130,10 +166,11 @@ main (int argc, char **argv)
 	g_type_init ();
 	g_test_init (&argc, &argv, NULL);
 
+	g_test_add_func ("/gck/module/initialize_async", test_initialize_async);
 	g_test_add ("/gck/module/invalid_modules", Test, NULL, setup, test_invalid_modules, teardown);
 	g_test_add ("/gck/module/module_equals_hash", Test, NULL, setup, test_module_equals_hash, teardown);
 	g_test_add ("/gck/module/module_props", Test, NULL, setup, test_module_props, teardown);
 	g_test_add ("/gck/module/module_info", Test, NULL, setup, test_module_info, teardown);
 
-	return g_test_run ();
+	return egg_tests_run_in_thread_with_loop ();
 }
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3b11f52..efe4a52 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,6 +12,8 @@ daemon/login/gkd-login.c
 daemon/org.gnome.keyring.service.in
 egg/egg-oid.c
 egg/egg-spawn.c
+gck/gck-module.c
+gck/gck-modules.c
 gcr/gcr-certificate.c
 gcr/gcr-certificate-exporter.c
 gcr/gcr-certificate-extensions.c



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