[gnome-keyring/gck-work] [gck] Remove session pooling, and add concept of module list.



commit 28b92ce9b020dc3e1bb58eb07669f83d753c18dd
Author: Stef Walter <stef memberwebs com>
Date:   Fri Jul 30 20:42:16 2010 +0200

    [gck] Remove session pooling, and add concept of module list.
    
     * Session pooling no langer necessary now that we track sessions
       properly in GckObject. This was of dubious value anyway.
     * Added concept of a module list.

 .gitignore                   |    2 +-
 gck/Makefile.am              |    1 +
 gck/gck-module.c             |  477 +++---------------------------------------
 gck/gck-modules.c            |  221 +++++++++++++++++++
 gck/gck-private.h            |    8 -
 gck/gck-session.c            |    2 +-
 gck/gck-slot.c               |   44 ++---
 gck/gck.h                    |   26 ++-
 gck/tests/test-gck-crypto.c  |    4 +-
 gck/tests/test-gck-module.c  |    9 +-
 gck/tests/test-gck-session.c |   72 +------
 11 files changed, 296 insertions(+), 570 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 1707eef..627c574 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,7 +13,7 @@
 .anjuta*
 *.tar.gz
 .*project
-.settings
+.*settings
 *.orig
 *.stamp
 .deps
diff --git a/gck/Makefile.am b/gck/Makefile.am
index 0173680..b6ed66d 100644
--- a/gck/Makefile.am
+++ b/gck/Makefile.am
@@ -21,6 +21,7 @@ libgck_la_SOURCES = \
 	gck-call.c \
 	gck-misc.c \
 	gck-module.c \
+	gck-modules.c \
 	gck-object.c \
 	gck-session.c \
 	gck-slot.c \
diff --git a/gck/gck-module.c b/gck/gck-module.c
index d194384..ef33b85 100644
--- a/gck/gck-module.c
+++ b/gck/gck-module.c
@@ -77,8 +77,7 @@ enum {
 	PROP_0,
 	PROP_PATH,
 	PROP_FUNCTIONS,
-	PROP_POOL_SESSIONS,
-	PROP_AUTO_AUTHENTICATE
+	PROP_OPTIONS
 };
 
 enum {
@@ -99,8 +98,7 @@ typedef struct _GckModulePrivate {
 	GckModuleData data;
 	GStaticMutex mutex;
 	gboolean finalized;
-	GHashTable *open_sessions;
-	gint auto_authenticate;
+	guint options;
 } GckModulePrivate;
 
 #define gck_module_GET_DATA(o) \
@@ -110,13 +108,6 @@ G_DEFINE_TYPE (GckModule, gck_module, G_TYPE_OBJECT);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-typedef struct _SessionPool {
-	CK_SLOT_ID slot;
-	CK_FUNCTION_LIST_PTR funcs;
-	GArray *ro_sessions; /* array of CK_SESSION_HANDLE */
-	GArray *rw_sessions; /* array of CK_SESSION_HANDLE */
-} SessionPool;
-
 /* ----------------------------------------------------------------------------
  * HELPERS
  */
@@ -164,20 +155,6 @@ unlock_mutex (void *mutex)
 	return CKR_OK;
 }
 
-static void
-close_session (CK_FUNCTION_LIST_PTR funcs, CK_SESSION_HANDLE handle)
-{
-	CK_RV rv;
-
-	g_return_if_fail (funcs);
-
-	rv = (funcs->C_CloseSession) (handle);
-	if (rv != CKR_OK) {
-		g_warning ("couldn't close session properly: %s",
-		           gck_message_from_rv (rv));
-	}
-}
-
 /* ----------------------------------------------------------------------------
  * INTERNAL
  */
@@ -215,166 +192,6 @@ unlock_private (gpointer obj, GckModulePrivate *pv)
 	g_object_unref (self);
 }
 
-static void
-free_session_pool (gpointer p)
-{
-	SessionPool *pool = p;
-	guint i;
-
-	if (pool->ro_sessions) {
-		for(i = 0; i < pool->ro_sessions->len; ++i)
-			close_session (pool->funcs, g_array_index (pool->ro_sessions, CK_SESSION_HANDLE, i));
-		g_array_free (pool->ro_sessions, TRUE);
-	}
-
-	if (pool->rw_sessions) {
-		for(i = 0; i < pool->rw_sessions->len; ++i)
-			close_session (pool->funcs, g_array_index (pool->rw_sessions, CK_SESSION_HANDLE, i));
-		g_array_free (pool->rw_sessions, TRUE);
-	}
-
-	g_free (pool);
-}
-
-static gboolean
-push_session_table (GckModulePrivate *pv, CK_SLOT_ID slot, gulong flags, CK_SESSION_HANDLE handle)
-{
-	SessionPool *pool;
-	GArray *array;
-
-	g_assert (handle);
-
-	if (pv->open_sessions == NULL)
-		return FALSE;
-
-	pool = g_hash_table_lookup (pv->open_sessions, &slot);
-	if (!pool) {
-		pool = g_new0 (SessionPool, 1);
-		pool->funcs = pv->data.funcs;
-		g_hash_table_insert (pv->open_sessions, g_memdup (&slot, sizeof (slot)), pool);
-	}
-
-	if (flags & CKF_RW_SESSION) {
-		if (!pool->rw_sessions)
-			pool->rw_sessions = g_array_new (FALSE, TRUE, sizeof (CK_SESSION_HANDLE));
-		array = pool->rw_sessions;
-	} else {
-		if (!pool->ro_sessions)
-			pool->ro_sessions = g_array_new (FALSE, TRUE, sizeof (CK_SESSION_HANDLE));
-		array = pool->ro_sessions;
-	}
-
-	g_array_append_val (array, handle);
-	return TRUE;
-}
-
-static CK_SESSION_HANDLE
-pop_session_table (GckModulePrivate *pv, CK_SLOT_ID slot, gulong flags)
-{
-	CK_SESSION_HANDLE result = 0;
-	SessionPool *pool;
-	GArray **array;
-
-	g_return_val_if_fail (pv, 0);
-
-	if (!pv->open_sessions)
-		return 0;
-
-	pool = g_hash_table_lookup (pv->open_sessions, &slot);
-	if (pool == NULL)
-		return 0;
-
-	if (flags & CKF_RW_SESSION)
-		array = &pool->rw_sessions;
-	else
-		array = &pool->ro_sessions;
-
-	if (*array == NULL)
-		return 0;
-
-	g_assert ((*array)->len > 0);
-	result = g_array_index (*array, CK_SESSION_HANDLE, (*array)->len - 1);
-	g_assert (result != 0);
-	g_array_remove_index_fast (*array, (*array)->len - 1);
-
-	if (!(*array)->len) {
-		g_array_free (*array, TRUE);
-		*array = NULL;
-		if (!pool->rw_sessions && !pool->ro_sessions)
-			g_hash_table_remove (pv->open_sessions, &slot);
-	}
-
-	return result;
-}
-
-static void
-destroy_session_table (GckModulePrivate *pv)
-{
-	if (pv->open_sessions)
-		g_hash_table_unref (pv->open_sessions);
-	pv->open_sessions = NULL;
-}
-
-static void
-create_session_table (GckModulePrivate *pv)
-{
-	if (!pv->open_sessions)
-		pv->open_sessions = g_hash_table_new_full (_gck_ulong_hash, _gck_ulong_equal, g_free, free_session_pool);
-}
-
-CK_SESSION_HANDLE
-_gck_module_pooled_session_handle (GckModule *self, CK_SLOT_ID slot, gulong flags)
-{
-	GckModulePrivate *pv = lock_private (self);
-	CK_SESSION_HANDLE handle;
-
-	g_return_val_if_fail (GCK_IS_MODULE (self), 0);
-
-	{
-		handle = pop_session_table (pv, slot, flags);
-	}
-
-	unlock_private (self, pv);
-
-	return handle;
-}
-
-gboolean
-_gck_module_pool_session_handle (GckSession *session, CK_SESSION_HANDLE handle, GckModule *self)
-{
-	GckModuleData *data = gck_module_GET_DATA (self);
-	GckModulePrivate *pv;
-	CK_SESSION_INFO info;
-	gboolean handled = FALSE;
-	CK_RV rv;
-
-	g_return_val_if_fail (GCK_IS_SESSION (session), FALSE);
-	g_return_val_if_fail (GCK_IS_MODULE (self), FALSE);
-
-	/* Get the session info so we know where to categorize this */
-	rv = (data->funcs->C_GetSessionInfo) (handle, &info);
-
-	if (rv == CKR_OK) {
-
-		pv = lock_private (self);
-
-		{
-			/* Keep this one around for later use */
-			handled = push_session_table (pv, info.slotID, info.flags, handle);
-		}
-
-		unlock_private (self, pv);
-
-	} else {
-
-		/* An already closed session, we don't want to bother with */
-		if (rv == CKR_SESSION_CLOSED || rv == CKR_SESSION_HANDLE_INVALID)
-			handled = TRUE;
-	}
-
-	return handled;
-}
-
 gboolean
 _gck_module_fire_authenticate_slot (GckModule *self, GckSlot *slot, gchar *label, gchar **password)
 {
@@ -477,11 +294,8 @@ gck_module_get_property (GObject *obj, guint prop_id, GValue *value,
 	case PROP_FUNCTIONS:
 		g_value_set_pointer (value, gck_module_get_functions (self));
 		break;
-	case PROP_AUTO_AUTHENTICATE:
-		g_value_set_int (value, gck_module_get_auto_authenticate (self));
-		break;
-	case PROP_POOL_SESSIONS:
-		g_value_set_boolean (value, gck_module_get_pool_sessions (self));
+	case PROP_OPTIONS:
+		g_value_set_uint (value, gck_module_get_options (self));
 		break;
 	}
 }
@@ -503,11 +317,8 @@ gck_module_set_property (GObject *obj, guint prop_id, const GValue *value,
 		g_return_if_fail (!data->funcs);
 		data->funcs = g_value_get_pointer (value);
 		break;
-	case PROP_AUTO_AUTHENTICATE:
-		gck_module_set_auto_authenticate (self, g_value_get_int (value));
-		break;
-	case PROP_POOL_SESSIONS:
-		gck_module_set_pool_sessions (self, g_value_get_boolean (value));
+	case PROP_OPTIONS:
+		gck_module_set_options (self, g_value_get_uint (value));
 		break;
 	}
 }
@@ -521,8 +332,6 @@ gck_module_dispose (GObject *obj)
 	CK_RV rv;
 
 	{
-		destroy_session_table (pv);
-
 		if (!pv->finalized && data->initialized && data->funcs) {
 			finalize = TRUE;
 			pv->finalized = TRUE;
@@ -549,8 +358,6 @@ gck_module_finalize (GObject *obj)
 	GckModulePrivate *pv = G_TYPE_INSTANCE_GET_PRIVATE (obj, GCK_TYPE_MODULE, GckModulePrivate);
 	GckModuleData *data = gck_module_GET_DATA (obj);
 
-	g_assert (!pv->open_sessions);
-
 	data->funcs = NULL;
 
 	if (data->module) {
@@ -607,28 +414,16 @@ gck_module_class_init (GckModuleClass *klass)
 		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	/**
-	 * GckModule:auto-authenticate:
+	 * GckModule:options:
 	 *
-	 * Whether or not to automatically authenticate token objects that need
-	 * a C_Login call before they can be used.
+	 * Various option flags related to authentication etc.
 	 *
 	 * The #GckModule::authenticate-object signal will be fired when an
 	 * object needs to be authenticated.
 	 */
-	g_object_class_install_property (gobject_class, PROP_AUTO_AUTHENTICATE,
-		g_param_spec_int ("auto-authenticate", "Auto Authenticate", "Auto Login to Token when necessary",
-		                  0, G_MAXINT, 0, G_PARAM_READWRITE));
-
-	/**
-	 * GckModule:pool-sessions:
-	 *
-	 * Whether or not to pool PKCS&num;11 sessions. When this is set, sessions
-	 * will be pooled and reused if their flags match when gck_slot_open_session()
-	 * is called.
-	 */
-	g_object_class_install_property (gobject_class, PROP_POOL_SESSIONS,
-		g_param_spec_boolean ("pool-sessions", "Pool Sessions", "Pool sessions?",
-		                      FALSE, G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class, PROP_OPTIONS,
+		g_param_spec_uint ("options", "Options", "Module options",
+		                  0, G_MAXUINT, 0, G_PARAM_READWRITE));
 
 	/**
 	 * GckModule::authenticate-slot:
@@ -952,25 +747,23 @@ gck_module_get_functions (GckModule *self)
 
 
 /**
- * gck_module_get_pool_sessions:
+ * gck_module_get_options:
  * @self: The module to get setting from.
  *
- * Get the reuse sessions setting. When this is set, sessions
- * will be pooled and reused if their flags match when
- * gck_slot_open_session() is called.
+ * Get the various module options, such as auto authenticate etc.
  *
- * Return value: Whether reusing sessions or not.
+ * Return value: The module options.
  **/
-gboolean
-gck_module_get_pool_sessions (GckModule *self)
+guint
+gck_module_get_options (GckModule *self)
 {
 	GckModulePrivate *pv = lock_private (self);
-	gboolean ret;
+	guint ret;
 
 	g_return_val_if_fail (pv, FALSE);
 
 	{
-		ret = pv->open_sessions != NULL;
+		ret = pv->options;
 	}
 
 	unlock_private (self, pv);
@@ -979,253 +772,41 @@ gck_module_get_pool_sessions (GckModule *self)
 }
 
 /**
- * gck_module_set_pool_sessions:
+ * gck_module_set_options:
  * @self: The module to set the setting on.
- * @pool: Whether to reuse sessions or not.
- *
- * When this is set, sessions will be pooled and reused
- * if their flags match when gck_slot_open_session() is called.
+ * @options: Authentication and other options..
  **/
 void
-gck_module_set_pool_sessions (GckModule *self, gboolean pool)
+gck_module_set_options (GckModule *self, guint options)
 {
 	GckModulePrivate *pv = lock_private (self);
 
 	g_return_if_fail (pv);
 
 	{
-		if (pool)
-			create_session_table (pv);
-		else
-			destroy_session_table (pv);
-	}
-
-	unlock_private (self, pv);
-	g_object_notify (G_OBJECT (self), "pool-sessions");
-}
-
-/**
- * gck_module_get_auto_authenticate:
- * @self: The module to get setting from.
- *
- * Get the auto login setting. When this is set, this slot
- * will emit the 'authenticate-slot' signal when a session
- * requires authentication, and the 'authenticate-object'
- * signal when an object requires authintication.
- *
- * Return value: Whether auto login or not.
- **/
-gint
-gck_module_get_auto_authenticate (GckModule *self)
-{
-	GckModulePrivate *pv = lock_private (self);
-	gint ret;
-
-	g_return_val_if_fail (pv, FALSE);
-
-	{
-		ret = pv->auto_authenticate;
+		pv->options = options;
 	}
 
 	unlock_private (self, pv);
-
-	return ret;
+	g_object_notify (G_OBJECT (self), "options");
 }
 
 /**
- * gck_module_set_auto_authenticate:
- * @self: The module to set the setting on.
- * @auto_authenticate: Whether auto login or not.
- *
- * When this is set, this slot
- * will emit the 'authenticate-slot' signal when a session
- * requires authentication, and the 'authenticate-object'
- * signal when an object requires authintication.
+ * gck_module_add_options:
+ * @self: The module to add the option on.
+ * @options: Authentication and other options..
  **/
 void
-gck_module_set_auto_authenticate (GckModule *self, gint auto_authenticate)
+gck_module_add_options (GckModule *self, guint options)
 {
 	GckModulePrivate *pv = lock_private (self);
 
-	/* HACK: Get needed fix around API freeze. */
-	if (auto_authenticate == 1)
-		auto_authenticate = GCK_AUTHENTICATE_TOKENS | GCK_AUTHENTICATE_OBJECTS;
-
 	g_return_if_fail (pv);
 
 	{
-		pv->auto_authenticate = auto_authenticate;
+		pv->options |= options;
 	}
 
 	unlock_private (self, pv);
-	g_object_notify (G_OBJECT (self), "auto-authenticate");
-}
-
-/**
- * gck_module_enumerate_objects:
- * @self: The module to enumerate objects.
- * @func: Function to call for each object.
- * @user_data: Data to pass to the function.
- * @...: The arguments must be triples of: attribute type, data type, value.
- *
- * Call a function for every matching object on the module. This call may
- * block for an indefinite period.
- *
- *
- * <para>The variable argument list should contain:
- * 	<variablelist>
- *		<varlistentry>
- * 			<term>a)</term>
- * 			<listitem><para>The gulong attribute type (ie: CKA_LABEL). </para></listitem>
- * 		</varlistentry>
- * 		<varlistentry>
- * 			<term>b)</term>
- * 			<listitem><para>The attribute data type (one of GCK_BOOLEAN, GCK_ULONG,
- * 				GCK_STRING, GCK_DATE) orthe raw attribute value length.</para></listitem>
- * 		</varlistentry>
- * 		<varlistentry>
- * 			<term>c)</term>
- * 			<listitem><para>The attribute value, either a gboolean, gulong, gchar*, GDate* or
- * 				a pointer to a raw attribute value.</para></listitem>
- * 		</varlistentry>
- * 	</variablelist>
- * The variable argument list should be terminated with GCK_INVALID.</para>
- *
- * This function will open a session per slot. It's recommended that you
- * set the 'reuse-sessions' property on each slot if you'll be calling
- * it a lot.
- *
- * You can access the session in which the object was found, by using the
- * gck_object_get_session() function on the resulting objects.
- *
- * This function skips tokens that are not initialize, and makes a best effort to
- * find objects on valid tokens.
- *
- * The function can return FALSE to stop the enumeration.
- *
- * Return value: If FALSE then an error prevented all matching objects from being enumerated.
- **/
-gboolean
-gck_module_enumerate_objects (GckModule *self, GckObjectForeachFunc func,
-                               gpointer user_data, ...)
-{
-	GckAttributes *attrs;
-	GError *error = NULL;
-	va_list va;
-
-	va_start (va, user_data);
-	attrs = gck_attributes_new_valist (g_realloc, va);
-	va_end (va);
-
-	gck_module_enumerate_objects_full (self, attrs, NULL, func, user_data, &error);
-	gck_attributes_unref (attrs);
-
-	if (error != NULL) {
-		g_warning ("enumerating objects failed: %s", error->message);
-		g_clear_error (&error);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-/**
- * gck_module_enumerate_objects_full:
- * @self: The module to enumerate objects.
- * @attrs: Attributes that the objects must have, or empty for all objects.
- * @cancellable: Optional cancellation object, or NULL.
- * @func: Function to call for each object.
- * @user_data: Data to pass to the function.
- * @error: Location to return error information.
- *
- * Call a function for every matching object on the module. This call may
- * block for an indefinite period.
- *
- * This function will open a session per slot. It's recommended that you
- * set the 'reuse-sessions' property on each slot if you'll be calling
- * it a lot.
- *
- * You can access the session in which the object was found, by using the
- * gck_object_get_session() function on the resulting objects.
- *
- * The function can return FALSE to stop the enumeration.
- *
- * Return value: If FALSE then an error prevented all matching objects from being enumerated.
- **/
-gboolean
-gck_module_enumerate_objects_full (GckModule *self, GckAttributes *attrs,
-                                    GCancellable *cancellable, GckObjectForeachFunc func,
-                                    gpointer user_data, GError **err)
-{
-	gboolean stop = FALSE;
-	gboolean ret = TRUE;
-	GList *objects, *o;
-	GList *slots, *l;
-	GError *error = NULL;
-	GckSession *session;
-
-	g_return_val_if_fail (GCK_IS_MODULE (self), FALSE);
-	g_return_val_if_fail (attrs, FALSE);
-	g_return_val_if_fail (func, FALSE);
-
-	gck_attributes_ref (attrs);
-	slots = gck_module_get_slots (self, TRUE);
-
-	for (l = slots; ret && !stop && l; l = g_list_next (l)) {
-
-		/* TODO: We really should allow the caller to specify the flags, at least read-write */
-		session = gck_slot_open_session (l->data, CKF_RW_SESSION | CKF_SERIAL_SESSION, &error);
-		if (!session) {
-			g_return_val_if_fail (error != NULL, FALSE);
-
-			/* Ignore these errors when enumerating */
-			if (g_error_matches (error, GCK_ERROR, CKR_USER_PIN_NOT_INITIALIZED)) {
-				g_clear_error (&error);
-
-			} else {
-				ret = FALSE;
-				g_propagate_error (err, error);
-				error = NULL;
-			}
-			continue;
-		}
-
-		objects = gck_session_find_objects_full (session, attrs, cancellable, &error);
-		if (error) {
-			ret = FALSE;
-			g_object_unref (session);
-			g_propagate_error (err, error);
-			error = NULL;
-			continue;
-		}
-
-		for (o = objects; !stop && o; o = g_list_next (o)) {
-			if (!(func)(o->data, user_data)) {
-				stop = TRUE;
-				break;
-			}
-		}
-
-		g_object_unref (session);
-		gck_list_unref_free (objects);
-	}
-
-	gck_list_unref_free (slots);
-	gck_attributes_unref (attrs);
-
-	return ret;
+	g_object_notify (G_OBJECT (self), "options");
 }
-
-/**
- * GckObjectForeachFunc:
- * @object: The enumerated object.
- * @user_data: Data passed to enumerate function.
- *
- * This function is passed to gck_module_enumerate_objects() or a similar function.
- * It is called once for each object matched.
- *
- * The GckSession through which the object is accessible can be retrieved by calling
- * gck_object_get_session() on object.
- *
- * Returns: TRUE to continue enumerating, FALSE to stop.
- */
diff --git a/gck/gck-modules.c b/gck/gck-modules.c
new file mode 100644
index 0000000..ae70d6f
--- /dev/null
+++ b/gck/gck-modules.c
@@ -0,0 +1,221 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-modules.c - the GObject PKCS#11 wrapper library
+
+   Copyright (C) 2008, Stefan Walter
+
+   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,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <nielsen memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck.h"
+#include "gck-private.h"
+#include "gck-marshal.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gck-modules
+ * @title: GckModule lists
+ * @short_description: Dealing with lists of PKCS#11 modules.
+ *
+ * Xxxxx
+ */
+
+GList*
+gck_modules_get_slots (GList *modules, gboolean token_present)
+{
+	GList *result = NULL;
+	GList *m;
+
+	for (m = modules; m; m = g_list_next (m)) {
+		result = g_list_concat (result, gck_module_get_slots (m->data, token_present));
+	}
+
+	return result;
+}
+
+/**
+ * gck_modules_enumerate_objects:
+ * @modules: The modules on which to enumerate objects.
+ * @func: Function to call for each object.
+ * @user_data: Data to pass to the function.
+ * @...: The arguments must be triples of: attribute type, data type, value.
+ *
+ * Call a function for every matching object on the module. This call may
+ * block for an indefinite period.
+ *
+ * <para>The variable argument list should contain:
+ * 	<variablelist>
+ *		<varlistentry>
+ * 			<term>a)</term>
+ * 			<listitem><para>The gulong attribute type (ie: CKA_LABEL). </para></listitem>
+ * 		</varlistentry>
+ * 		<varlistentry>
+ * 			<term>b)</term>
+ * 			<listitem><para>The attribute data type (one of GCK_BOOLEAN, GCK_ULONG,
+ * 				GCK_STRING, GCK_DATE) orthe raw attribute value length.</para></listitem>
+ * 		</varlistentry>
+ * 		<varlistentry>
+ * 			<term>c)</term>
+ * 			<listitem><para>The attribute value, either a gboolean, gulong, gchar*, GDate* or
+ * 				a pointer to a raw attribute value.</para></listitem>
+ * 		</varlistentry>
+ * 	</variablelist>
+ * The variable argument list should be terminated with GCK_INVALID.</para>
+ *
+ * This function will open a session per slot. It's recommended that you
+ * set the 'reuse-sessions' property on each slot if you'll be calling
+ * it a lot.
+ *
+ * You can access the session in which the object was found, by using the
+ * gck_object_get_session() function on the resulting objects.
+ *
+ * This function skips tokens that are not initialize, and makes a best effort to
+ * find objects on valid tokens.
+ *
+ * The function can return FALSE to stop the enumeration.
+ *
+ * Return value: If FALSE then an error prevented all matching objects from being enumerated.
+ **/
+gboolean
+gck_modules_enumerate_objects (GList *modules, GckObjectForeachFunc func,
+                               gpointer user_data, ...)
+{
+	GckAttributes *attrs;
+	GError *error = NULL;
+	va_list va;
+
+	va_start (va, user_data);
+	attrs = gck_attributes_new_valist (g_realloc, va);
+	va_end (va);
+
+	gck_modules_enumerate_objects_full (modules, attrs, CKF_RW_SESSION, NULL, func, user_data, &error);
+	gck_attributes_unref (attrs);
+
+	if (error != NULL) {
+		g_warning ("enumerating objects failed: %s", error->message);
+		g_clear_error (&error);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/**
+ * gck_module_enumerate_objects_full:
+ * @self: The module to enumerate objects.
+ * @attrs: Attributes that the objects must have, or empty for all objects.
+ * @cancellable: Optional cancellation object, or NULL.
+ * @func: Function to call for each object.
+ * @user_data: Data to pass to the function.
+ * @error: Location to return error information.
+ *
+ * Call a function for every matching object on the module. This call may
+ * block for an indefinite period.
+ *
+ * This function will open a session per slot. It's recommended that you
+ * set the 'reuse-sessions' property on each slot if you'll be calling
+ * it a lot.
+ *
+ * You can access the session in which the object was found, by using the
+ * gck_object_get_session() function on the resulting objects.
+ *
+ * The function can return FALSE to stop the enumeration.
+ *
+ * Return value: If FALSE then an error prevented all matching objects from being enumerated.
+ **/
+gboolean
+gck_modules_enumerate_objects_full (GList *modules, GckAttributes *attrs, guint session_flags,
+                                    GCancellable *cancellable, GckObjectForeachFunc func,
+                                    gpointer user_data, GError **err)
+{
+	gboolean stop = FALSE;
+	gboolean ret = TRUE;
+	GList *objects, *o;
+	GList *slots, *l, *m;
+	GError *error = NULL;
+	GckSession *session;
+
+	g_return_val_if_fail (attrs, FALSE);
+	g_return_val_if_fail (func, FALSE);
+
+	gck_attributes_ref (attrs);
+
+	for (m = modules; ret && !stop && m; m = g_list_next (m)) {
+		slots = gck_module_get_slots (m->data, TRUE);
+
+		for (l = slots; ret && !stop && l; l = g_list_next (l)) {
+
+			session = gck_slot_open_session (l->data, session_flags, &error);
+			if (!session) {
+				g_return_val_if_fail (error != NULL, FALSE);
+
+				/* Ignore these errors when enumerating */
+				if (g_error_matches (error, GCK_ERROR, CKR_USER_PIN_NOT_INITIALIZED)) {
+					g_clear_error (&error);
+
+				} else {
+					ret = FALSE;
+					g_propagate_error (err, error);
+					error = NULL;
+				}
+				continue;
+			}
+
+			objects = gck_session_find_objects_full (session, attrs, cancellable, &error);
+			if (error) {
+				ret = FALSE;
+				g_object_unref (session);
+				g_propagate_error (err, error);
+				error = NULL;
+				continue;
+			}
+
+			for (o = objects; !stop && o; o = g_list_next (o)) {
+				if (!(func)(o->data, user_data)) {
+					stop = TRUE;
+					break;
+				}
+			}
+
+			g_object_unref (session);
+			gck_list_unref_free (objects);
+		}
+
+		gck_list_unref_free (slots);
+	}
+
+	gck_attributes_unref (attrs);
+
+	return ret;
+}
+
+/**
+ * GckObjectForeachFunc:
+ * @object: The enumerated object.
+ * @user_data: Data passed to enumerate function.
+ *
+ * This function is passed to gck_module_enumerate_objects() or a similar function.
+ * It is called once for each object matched.
+ *
+ * The GckSession through which the object is accessible can be retrieved by calling
+ * gck_object_get_session() on object.
+ *
+ * Returns: TRUE to continue enumerating, FALSE to stop.
+ */
diff --git a/gck/gck-private.h b/gck/gck-private.h
index f30f21c..5a337cf 100644
--- a/gck/gck-private.h
+++ b/gck/gck-private.h
@@ -72,14 +72,6 @@ gboolean            _gck_module_fire_authenticate_object   (GckModule *module,
                                                              gchar *label,
                                                              gchar **password);
 
-gboolean            _gck_module_pool_session_handle        (GckSession *session,
-                                                             CK_SESSION_HANDLE handle,
-                                                             GckModule *self);
-
-CK_SESSION_HANDLE   _gck_module_pooled_session_handle      (GckModule *module,
-                                                             CK_SLOT_ID slot,
-                                                             gulong flags);
-
 /* ----------------------------------------------------------------------------
  * SLOT
  */
diff --git a/gck/gck-session.c b/gck/gck-session.c
index 064a52d..73de8c8 100644
--- a/gck/gck-session.c
+++ b/gck/gck-session.c
@@ -2163,7 +2163,7 @@ authenticate_init (Authenticate *auth, GckSlot *slot, GckObject *object)
 	g_assert (GCK_IS_OBJECT (object));
 
 	module = gck_slot_get_module (slot);
-	if (gck_module_get_auto_authenticate (module) & GCK_AUTHENTICATE_OBJECTS) {
+	if (gck_module_get_options (module) & GCK_AUTHENTICATE_OBJECTS) {
 		auth->state = AUTHENTICATE_CAN;
 		auth->protected_auth = gck_slot_has_flags (slot, CKF_PROTECTED_AUTHENTICATION_PATH);
 		auth->module = module;
diff --git a/gck/gck-slot.c b/gck/gck-slot.c
index e4092bf..6afe3f3 100644
--- a/gck/gck-slot.c
+++ b/gck/gck-slot.c
@@ -113,10 +113,6 @@ make_session_object (GckSlot *self, gulong flags, CK_SESSION_HANDLE handle)
 	session = gck_session_from_handle (self, handle);
 	g_return_val_if_fail (session != NULL, NULL);
 
-	/* Session keeps a reference to module so this is safe */
-	g_signal_connect (session, "discard-handle",
-	                  G_CALLBACK (_gck_module_pool_session_handle), module);
-
 	g_object_unref (module);
 
 	return session;
@@ -937,9 +933,9 @@ GckSession*
 gck_slot_open_session_full (GckSlot *self, gulong flags, gpointer app_data,
                              CK_NOTIFY notify, GCancellable *cancellable, GError **err)
 {
+	OpenSession args = { GCK_ARGUMENTS_INIT, 0,  };
 	GckSession *session = NULL;
 	GckModule *module = NULL;
-	CK_SESSION_HANDLE handle;
 	CK_SLOT_ID slot_id;
 
 	flags |= CKF_SERIAL_SESSION;
@@ -949,25 +945,18 @@ gck_slot_open_session_full (GckSlot *self, gulong flags, gpointer app_data,
 	/* Try to use a cached session */
 	module = gck_slot_get_module (self);
 	slot_id = gck_slot_get_handle (self);
-	handle = _gck_module_pooled_session_handle (module, slot_id, flags);
-	if (handle != 0)
-		session = make_session_object (self, flags, handle);
 
 	/* Open a new session */
-	if (session == NULL) {
-		OpenSession args = { GCK_ARGUMENTS_INIT, 0,  };
-
-		args.slot = self;
-		args.flags = flags;
-		args.app_data = app_data;
-		args.notify = notify;
-		args.password = NULL;
-		args.auto_login = (gck_module_get_auto_authenticate (module) & GCK_AUTHENTICATE_TOKENS) ? TRUE : FALSE;
-		args.session = 0;
-
-		if (_gck_call_sync (self, perform_open_session, complete_open_session, &args, cancellable, err))
-			session = make_session_object (self, flags, args.session);
-	}
+	args.slot = self;
+	args.flags = flags;
+	args.app_data = app_data;
+	args.notify = notify;
+	args.password = NULL;
+	args.auto_login = (gck_module_get_options (module) & GCK_AUTHENTICATE_TOKENS) ? TRUE : FALSE;
+	args.session = 0;
+
+	if (_gck_call_sync (self, perform_open_session, complete_open_session, &args, cancellable, err))
+		session = make_session_object (self, flags, args.session);
 
 	g_object_unref (module);
 	g_object_unref (self);
@@ -996,7 +985,6 @@ gck_slot_open_session_async (GckSlot *self, gulong flags, gpointer app_data,
                               GAsyncReadyCallback callback, gpointer user_data)
 {
 	GckModule *module = NULL;
-	GckCall *call;
 	OpenSession *args;
 	CK_SLOT_ID slot_id;
 
@@ -1015,16 +1003,10 @@ gck_slot_open_session_async (GckSlot *self, gulong flags, gpointer app_data,
 	/* Try to use a cached session */
 	module = gck_slot_get_module (self);
 	slot_id = gck_slot_get_handle (self);
-	args->session = _gck_module_pooled_session_handle (module, slot_id, flags);
-	args->auto_login = (gck_module_get_auto_authenticate (module) & GCK_AUTHENTICATE_TOKENS) ? TRUE : FALSE;
+	args->auto_login = (gck_module_get_options (module) & GCK_AUTHENTICATE_TOKENS) ? TRUE : FALSE;
 	g_object_unref (module);
 
-	call = _gck_call_async_ready (args, cancellable, callback, user_data);
-	if (args->session)
-		_gck_call_async_short (call, CKR_OK);
-	else
-		_gck_call_async_go (call);
-
+	_gck_call_async_ready_go (args, cancellable, callback, user_data);
 	g_object_unref (self);
 }
 
diff --git a/gck/gck.h b/gck/gck.h
index 76905eb..bc53667 100644
--- a/gck/gck.h
+++ b/gck/gck.h
@@ -304,40 +304,44 @@ GckModuleInfo*        gck_module_get_info                     (GckModule *self);
 GList*                gck_module_get_slots                    (GckModule *self,
                                                                gboolean token_present);
 
-gboolean              gck_module_get_pool_sessions            (GckModule *self);
+guint                 gck_module_get_options                  (GckModule *self);
 
-void                  gck_module_set_pool_sessions            (GckModule *self,
-                                                               gboolean pool);
+void                  gck_module_set_options                  (GckModule *self,
+                                                               guint options);
 
-gint                  gck_module_get_auto_authenticate        (GckModule *self);
+void                  gck_module_add_options                  (GckModule *self,
+                                                               guint options);
 
-void                  gck_module_set_auto_authenticate        (GckModule *self,
-                                                               gint auto_authenticate);
+GList*                gck_modules_get_slots                   (GList *modules,
+                                                               gboolean token_present);
 
-gboolean              gck_module_enumerate_objects            (GckModule *self,
+gboolean              gck_modules_enumerate_objects           (GList *modules,
                                                                GckObjectForeachFunc func,
                                                                gpointer user_data,
                                                                ...);
 
-gboolean              gck_module_enumerate_objects_full       (GckModule *self,
+gboolean              gck_modules_enumerate_objects_full      (GList *modules,
                                                                GckAttributes *attrs,
+                                                               guint session_flags,
                                                                GCancellable *cancellable,
                                                                GckObjectForeachFunc func,
                                                                gpointer user_data,
                                                                GError **error);
 
 #ifdef UNIMPLEMENTED
-void                  gck_module_enumerate_objects_async      (GckModule *self,
+void                  gck_modules_enumerate_objects_async     (GList *modules,
                                                                GckAttributes *attrs,
+                                                               guint session_flags,
+                                                               GckObjectForeachFunc func,
                                                                GCancellable *cancellable,
                                                                GAsyncReadyCallback callback,
                                                                gpointer user_data);
 
-GckObject*            gck_module_enumerate_objects_next       (GckModule *self,
+GckObject*            gck_modules_enumerate_objects_next      (GList *modules,
                                                                GAsyncResult *res,
                                                                GError **error);
 
-void                  gck_module_enumerate_objects_finish     (GckModule *self,
+void                  gck_modules_enumerate_objects_finish    (GList *modules,
                                                                GAsyncResult *res,
                                                                GError **error);
 #endif
diff --git a/gck/tests/test-gck-crypto.c b/gck/tests/test-gck-crypto.c
index 0bb5c9c..9e6018c 100644
--- a/gck/tests/test-gck-crypto.c
+++ b/gck/tests/test-gck-crypto.c
@@ -253,7 +253,7 @@ DEFINE_TEST(sign)
 	mech = gck_mechanism_new_with_param (CKM_PREFIX, "my-prefix:", 10);
 
 	/* Enable auto-login on this session, see previous test */
-	gck_module_set_auto_authenticate (module, TRUE);
+	gck_module_set_options (module, GCK_AUTHENTICATE_OBJECTS);
 	g_signal_connect (module, "authenticate-object", G_CALLBACK (authenticate_object), NULL);
 
 	/* Find the right key */
@@ -303,7 +303,7 @@ DEFINE_TEST(verify)
 	mech = gck_mechanism_new_with_param (CKM_PREFIX, "my-prefix:", 10);
 
 	/* Enable auto-login on this session, shouldn't be needed */
-	gck_module_set_auto_authenticate (module, TRUE);
+	gck_module_set_options (module, GCK_AUTHENTICATE_OBJECTS);
 	g_signal_connect (module, "authenticate-object", G_CALLBACK (authenticate_object), NULL);
 
 	/* Find the right key */
diff --git a/gck/tests/test-gck-module.c b/gck/tests/test-gck-module.c
index 122d2d6..6a3ebf9 100644
--- a/gck/tests/test-gck-module.c
+++ b/gck/tests/test-gck-module.c
@@ -126,9 +126,12 @@ DEFINE_TEST(module_enumerate)
 	GckSession *session;
 	GckAttributes *attrs;
 	gboolean ret;
+	GList *modules;
+
+	modules = g_list_prepend (NULL, g_object_ref (module));
 
 	attrs = gck_attributes_new ();
-	ret = gck_module_enumerate_objects_full (module, attrs, NULL, for_first_object, "first", NULL);
+	ret = gck_modules_enumerate_objects_full (modules, attrs, 0, NULL, for_first_object, "first", NULL);
 	g_assert (ret);
 	g_assert_cmpint (n_objects, ==, 1);
 	g_assert (GCK_IS_OBJECT (last_object));
@@ -142,7 +145,7 @@ DEFINE_TEST(module_enumerate)
 	last_object = NULL;
 	n_objects = 0;
 
-	ret = gck_module_enumerate_objects (module, for_each_object, "blah",
+	ret = gck_modules_enumerate_objects (modules, for_each_object, "blah",
 	                                     CKA_CLASS, GCK_ULONG, CKO_PRIVATE_KEY,
 	                                     GCK_INVALID);
 	g_assert (ret);
@@ -156,4 +159,6 @@ DEFINE_TEST(module_enumerate)
 	g_object_unref (last_object);
 	last_object = NULL;
 	n_objects = 0;
+
+	gck_list_unref_free (modules);
 }
diff --git a/gck/tests/test-gck-session.c b/gck/tests/test-gck-session.c
index ff98a0a..ed00f32 100644
--- a/gck/tests/test-gck-session.c
+++ b/gck/tests/test-gck-session.c
@@ -101,66 +101,6 @@ DEFINE_TEST(open_close_session)
 	g_object_unref (sess);
 }
 
-DEFINE_TEST(open_reused)
-{
-	CK_OBJECT_HANDLE handle;
-	GckSession *sess, *sess2;
-	GAsyncResult *result = NULL;
-	GError *err = NULL;
-	gboolean value;
-
-	g_assert (gck_module_get_pool_sessions (module) == FALSE);
-	gck_module_set_pool_sessions (module, TRUE);
-	g_assert (gck_module_get_pool_sessions (module) == TRUE);
-	g_object_get (module, "pool-sessions", &value, NULL);
-	g_assert (value == TRUE);
-
-	sess = gck_slot_open_session (slot, 0, &err);
-	SUCCESS_RES (sess, err);
-	if (!sess) return;
-
-	/* Make note of the handle we saw */
-	handle = gck_session_get_handle (sess);
-	g_object_unref (sess);
-
-	/* Open again, and see if the same handle */
-	sess = gck_slot_open_session (slot, 0, &err);
-	SUCCESS_RES (sess, err);
-	if (!sess) return;
-	g_assert (handle == gck_session_get_handle (sess));
-	g_object_unref (sess);
-
-	/* Test opening async */
-	gck_slot_open_session_async (slot, 0, NULL, NULL, NULL, fetch_async_result, &result);
-	testing_wait_until (500);
-	g_assert (result != NULL);
-	sess = gck_slot_open_session_finish (slot, result, &err);
-	SUCCESS_RES (sess, err);
-	if (!sess) return;
-	g_assert (handle == gck_session_get_handle (sess));
-	g_object_unref (result);
-	g_object_unref (sess);
-
-	/* Test opening with different flags, a different session should be returned */
-	sess = gck_slot_open_session (slot, CKF_RW_SESSION, &err);
-	SUCCESS_RES (sess, err);
-	if (!sess) return;
-	g_assert (handle != gck_session_get_handle (sess));
-
-	/* Now open a second session, with same flags, shouldn't return the same */
-	sess2 = gck_slot_open_session (slot, CKF_RW_SESSION, &err);
-	SUCCESS_RES (sess2, err);
-	if (!sess2) return;
-	g_assert (gck_session_get_handle (sess) != gck_session_get_handle (sess2));
-
-	g_object_set (module, "pool-sessions", FALSE, NULL);
-	g_assert (gck_module_get_pool_sessions (module) == FALSE);
-
-	g_object_unref (sess);
-	g_object_unref (sess2);
-}
-
-
 DEFINE_TEST(init_set_pin)
 {
 	GAsyncResult *result = NULL;
@@ -274,10 +214,10 @@ DEFINE_TEST(auto_login)
 	g_clear_error (&err);
 
 	/* Setup for auto login */
-	g_assert (gck_module_get_auto_authenticate (module) == 0);
-	gck_module_set_auto_authenticate (module, TRUE);
-	g_assert (gck_module_get_auto_authenticate (module) == (GCK_AUTHENTICATE_TOKENS | GCK_AUTHENTICATE_OBJECTS));
-	g_object_get (module, "auto-authenticate", &value, NULL);
+	g_assert (gck_module_get_options (module) == 0);
+	gck_module_set_options (module, GCK_AUTHENTICATE_TOKENS | GCK_AUTHENTICATE_OBJECTS);
+	g_assert (gck_module_get_options (module) == (GCK_AUTHENTICATE_TOKENS | GCK_AUTHENTICATE_OBJECTS));
+	g_object_get (module, "options", &value, NULL);
 	g_assert (value == (GCK_AUTHENTICATE_TOKENS | GCK_AUTHENTICATE_OBJECTS));
 
 	g_signal_connect (module, "authenticate-slot", G_CALLBACK (authenticate_token), GUINT_TO_POINTER (35));
@@ -318,6 +258,6 @@ DEFINE_TEST(auto_login)
 	ret = gck_session_logout (session, &err);
 	SUCCESS_RES (ret, err);
 
-	g_object_set (module, "auto-authenticate", FALSE, NULL);
-	g_assert (gck_module_get_auto_authenticate (module) == FALSE);
+	g_object_set (module, "options", 0, NULL);
+	g_assert_cmpuint (gck_module_get_options (module), ==, 0);
 }



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