diff options
| author | Marcus Brinkmann <[email protected]> | 2003-04-24 15:40:49 +0000 | 
|---|---|---|
| committer | Marcus Brinkmann <[email protected]> | 2003-04-24 15:40:49 +0000 | 
| commit | 5375105fadf033a71e0d2fdf324cc44e417b4202 (patch) | |
| tree | af0069d9f590c2e494c552b9a71f15b1653ce48f | |
| parent | Pretty print. (diff) | |
| download | gpgme-5375105fadf033a71e0d2fdf324cc44e417b4202.tar.gz gpgme-5375105fadf033a71e0d2fdf324cc44e417b4202.zip | |
2003-04-24  Marcus Brinkmann  <[email protected]>
	* Makefile.am (libgpgme_la_SOURCES): Add key-cache.c.
	* key.c (key_cache_initialized, key_cache_size,
	key_cache_max_chain_length, ): Removed.
	(struct key_cache_item_s, key_cache_lock, key_cache,
	key_cache_unused_items, hash_key, _gpgme_key_cache_add,
	_gpgme_key_cache_get, gpgme_get_key): Moved to ...
	* key-cache.c: ... here.  New file.
	* key.h (_gpgme_key_cache_init): Remove prototypes.
	(_gpgme_key_cache_add,_gpgme_key_cache_get): Move to ...
	* ops.h: ... here.
	* version.c: Do not include "key.h".
	(do_subsystem_inits): Do not call _gpgme_key_cache_init.
| -rw-r--r-- | gpgme/ChangeLog | 13 | ||||
| -rw-r--r-- | gpgme/Makefile.am | 2 | ||||
| -rw-r--r-- | gpgme/key-cache.c | 250 | ||||
| -rw-r--r-- | gpgme/key.c | 261 | ||||
| -rw-r--r-- | gpgme/key.h | 5 | ||||
| -rw-r--r-- | gpgme/ops.h | 11 | ||||
| -rw-r--r-- | gpgme/version.c | 4 | 
7 files changed, 275 insertions, 271 deletions
| diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 59eed259..1b4d0b5f 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,5 +1,18 @@  2003-04-24  Marcus Brinkmann  <[email protected]> +	* Makefile.am (libgpgme_la_SOURCES): Add key-cache.c. +	* key.c (key_cache_initialized, key_cache_size, +	key_cache_max_chain_length, ): Removed. +	(struct key_cache_item_s, key_cache_lock, key_cache, +	key_cache_unused_items, hash_key, _gpgme_key_cache_add, +	_gpgme_key_cache_get, gpgme_get_key): Moved to ... +	* key-cache.c: ... here.  New file. +	* key.h (_gpgme_key_cache_init): Remove prototypes. +	(_gpgme_key_cache_add,_gpgme_key_cache_get): Move to ... +	* ops.h: ... here. +	* version.c: Do not include "key.h". +	(do_subsystem_inits): Do not call _gpgme_key_cache_init. +  	* mkstatus: Strip trailing comma.  	* gpgme.h (GpgmeStatus): Pretty print. diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index 364897f1..f36872e2 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -77,7 +77,7 @@ libgpgme_la_SOURCES =							\  	op-support.c							\  	encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c	\  	sign.c passphrase.c progress.c					\ -	key.h key.c keylist.c trustlist.c				\ +	key.h key.c key-cache.c keylist.c trustlist.c			\  	import.c export.c genkey.c delete.c edit.c			\  	engine.h engine-backend.h engine.c rungpg.c status-table.h	\  	${gpgsm_components} sema.h io.h ${system_components}		\ diff --git a/gpgme/key-cache.c b/gpgme/key-cache.c new file mode 100644 index 00000000..0322ef22 --- /dev/null +++ b/gpgme/key-cache.c @@ -0,0 +1,250 @@ +/* key-cache.c - Key cache routines. +   Copyright (C) 2000 Werner Koch (dd9jn) +   Copyright (C) 2001, 2002, 2003 g10 Code GmbH + +   This file is part of GPGME. +  +   GPGME is free software; you can redistribute it and/or modify it +   under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. +  +   GPGME 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 +   General Public License for more details. +  +   You should have received a copy of the GNU General Public License +   along with GPGME; if not, write to the Free Software Foundation, +   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> + +#include "gpgme.h" +#include "util.h" +#include "ops.h" +#include "sema.h" +#include "key.h" + +#if SIZEOF_UNSIGNED_INT < 4 +#error unsigned int too short to be used as a hash value +#endif + +#define KEY_CACHE_SIZE 503 +#define KEY_CACHE_MAX_CHAIN_LENGTH 10 + +struct key_cache_item_s +{ +  struct key_cache_item_s *next; +  GpgmeKey key; +}; + +/* Protects key_cache and key_cache_unused_items.  */ +DEFINE_STATIC_LOCK (key_cache_lock); +static struct key_cache_item_s *key_cache[KEY_CACHE_SIZE]; +static struct key_cache_item_s *key_cache_unused_items; + + +/* We use the first 4 digits to calculate the hash.  */ +static int +hash_key (const char *fpr, unsigned int *rhash) +{ +  unsigned int hash; +  int c; + +  if (!fpr) +    return -1; +  if ((c = _gpgme_hextobyte (fpr)) == -1) +    return -1; +  hash = c; +  if ((c = _gpgme_hextobyte (fpr+2)) == -1) +    return -1; +  hash |= c << 8; +  if ((c = _gpgme_hextobyte (fpr+4)) == -1) +    return -1; +  hash |= c << 16; +  if ((c = _gpgme_hextobyte (fpr+6)) == -1) +    return -1; +  hash |= c << 24; + +  *rhash = hash; +  return 0; +} + + +/* Acquire a reference to KEY and add it to the key cache.  */ +void +_gpgme_key_cache_add (GpgmeKey key) +{ +  struct subkey_s *k; + +  LOCK (key_cache_lock); +  /* Put the key under each fingerprint into the cache.  We use the +     first 4 digits to calculate the hash.  */ +  for (k = &key->keys; k; k = k->next) +    { +      size_t n; +      unsigned int hash; +      struct key_cache_item_s *item; + +      if (hash_key (k->fingerprint, &hash)) +	continue; + +      hash %= KEY_CACHE_SIZE; +      for (item = key_cache[hash], n=0; item; item = item->next, n++) +	{ +	  struct subkey_s *k2; +	  if (item->key == key)  +	    /* Already in cache.  */ +	    break; +	  /* Now do a deeper check.  */ +	  for (k2 = &item->key->keys; k2; k2 = k2->next) +	    { +	      if (k2->fingerprint && !strcmp (k->fingerprint, k2->fingerprint)) +		{ +		  /* Okay, replace it with the new copy.  */ +		  gpgme_key_unref (item->key); +		  item->key = key; +		  gpgme_key_ref (item->key); +		  UNLOCK (key_cache_lock); +		  return; +                } +            } +        } +      if (item) +	continue; +         +      if (n > KEY_CACHE_MAX_CHAIN_LENGTH) +	{ +	  /* Remove the last entries.  */ +	  struct key_cache_item_s *last = NULL; + +	  for (item = key_cache[hash]; +	       item && n < KEY_CACHE_MAX_CHAIN_LENGTH; +	       last = item, item = item->next, n++) +	    ; +	   +	  if (last) +	    { +	      struct key_cache_item_s *next; + +	      last->next = NULL; +	      for (; item; item = next) +		{ +		  next = item->next; +		  gpgme_key_unref (item->key); +		  item->key = NULL; +		  item->next = key_cache_unused_items; +		  key_cache_unused_items = item; +                } +            } +        } + +      item = key_cache_unused_items; +      if (item) +	{ +	  key_cache_unused_items = item->next; +	  item->next = NULL; +        } +      else +	{ +	  item = malloc (sizeof *item); +	  if (!item) +	    { +	      UNLOCK (key_cache_lock); +	      return; +	    } +        } + +      item->key = key; +      gpgme_key_ref (key); +      item->next = key_cache[hash]; +      key_cache[hash] = item; +    } +  UNLOCK (key_cache_lock); +} + + +GpgmeKey  +_gpgme_key_cache_get (const char *fpr) +{ +  struct key_cache_item_s *item; +  unsigned int hash; + +  LOCK (key_cache_lock); +  if (hash_key (fpr, &hash)) +    { +      UNLOCK (key_cache_lock); +      return NULL; +    } + +  hash %= KEY_CACHE_SIZE; +  for (item = key_cache[hash]; item; item = item->next) +    { +      struct subkey_s *k; + +      for (k = &item->key->keys; k; k = k->next) +	{ +	  if (k->fingerprint && !strcmp (k->fingerprint, fpr)) +	    { +	      gpgme_key_ref (item->key); +	      UNLOCK (key_cache_lock); +	      return item->key; +            } +        } +    } +  UNLOCK (key_cache_lock); +  return NULL; +} + + +/* Get the key with the fingerprint FPR from the key cache or from the +   crypto backend.  If FORCE_UPDATE is true, force a refresh of the +   key from the crypto backend and replace the key in the cache, if +   any.  If SECRET is true, get the secret key.  */ +GpgmeError +gpgme_get_key (GpgmeCtx ctx, const char *fpr, GpgmeKey *r_key, +	       int secret, int force_update) +{ +  GpgmeCtx listctx; +  GpgmeError err; + +  if (!ctx || !r_key) +    return GPGME_Invalid_Value; +   +  if (strlen (fpr) < 16)	/* We have at least a key ID.  */ +    return GPGME_Invalid_Key; + +  if (!force_update) +    { +      *r_key = _gpgme_key_cache_get (fpr); +      if (*r_key) +	{ +	  /* If the primary UID (if available) has no signatures, and +	     we are in the signature listing keylist mode, then try to +	     update the key below before returning.  */ +	  if (!((ctx->keylist_mode & GPGME_KEYLIST_MODE_SIGS) +		&& (*r_key)->uids && !(*r_key)->uids->certsigs)) +	    return 0; +	} +    } + +  /* We need our own context because we have to avoid the user's I/O +     callback handlers.  */ +  /* Fixme: This can be optimized by keeping an internal context +     used for such key listings.  */ +  err = gpgme_new (&listctx); +  if (err) +    return err; +  gpgme_set_protocol (listctx, gpgme_get_protocol (ctx)); +  gpgme_set_keylist_mode (listctx, ctx->keylist_mode); +  err = gpgme_op_keylist_start (listctx, fpr, secret); +  if (!err) +    err = gpgme_op_keylist_next (listctx, r_key); +  gpgme_release (listctx); +  return err; +} diff --git a/gpgme/key.c b/gpgme/key.c index 7a2b7544..af87ac95 100644 --- a/gpgme/key.c +++ b/gpgme/key.c @@ -32,225 +32,12 @@  #include "key.h"  #include "sema.h" -#if SIZEOF_UNSIGNED_INT < 4 -#error unsigned int too short to be used as a hash value -#endif - - -struct key_cache_item_s -{ -  struct key_cache_item_s *next; -  GpgmeKey key; -}; - -/* Protects all key_cache_* variables.  */ -DEFINE_STATIC_LOCK (key_cache_lock); -static int key_cache_initialized; -static struct key_cache_item_s **key_cache; -static size_t key_cache_size; -static size_t key_cache_max_chain_length; -static struct key_cache_item_s *key_cache_unused_items;  /* Protects all reference counters in keys.  All other accesses to a     key are either read only or happen before the key is entered into     the cache.  */  DEFINE_STATIC_LOCK (key_ref_lock); -static int -hash_key (const char *fpr, unsigned int *rhash) -{ -  unsigned int hash; -  int c; - -  if (!fpr) -    return -1; -  if ((c = _gpgme_hextobyte (fpr)) == -1) -    return -1; -  hash = c; -  if ((c = _gpgme_hextobyte (fpr+2)) == -1) -    return -1; -  hash |= c << 8; -  if ((c = _gpgme_hextobyte (fpr+4)) == -1) -    return -1; -  hash |= c << 16; -  if ((c = _gpgme_hextobyte (fpr+6)) == -1) -    return -1; -  hash |= c << 24; - -  *rhash = hash; -  return 0; -} - - -void -_gpgme_key_cache_init (void) -{ -  LOCK (key_cache_lock); -  if (!key_cache_initialized) -    { -      key_cache_size = 503; -      key_cache = calloc (key_cache_size, sizeof *key_cache); -      if (!key_cache) -	{ -	  key_cache_size = 0; -	  key_cache_initialized = 1; -	} -      else -	{ -	  /* The upper bound for our cache size is -	     key_cache_max_chain_length * key_cache_size.  */ -	  key_cache_max_chain_length = 10; -	  key_cache_initialized = 1; -	} -    } -  UNLOCK (key_cache_lock); -} - - -void -_gpgme_key_cache_add (GpgmeKey key) -{ -  struct subkey_s *k; - -  if (!key) -    return; - -  _gpgme_key_cache_init (); - -  LOCK (key_cache_lock); -  /* Check if cache was enabled.  */ -  if (!key_cache_size) -    { -      UNLOCK (key_cache_lock); -      return; -    } - -  /* Put the key under each fingerprint into the cache.  We use the -     first 4 digits to calculate the hash.  */ -  for (k = &key->keys; k; k = k->next) -    { -      size_t n; -      unsigned int hash; -      struct key_cache_item_s *item; - -      if (hash_key (k->fingerprint, &hash)) -	continue; - -      hash %= key_cache_size; -      for (item = key_cache[hash], n=0; item; item = item->next, n++) -	{ -	  struct subkey_s *k2; -	  if (item->key == key)  -	    /* Already in cache.  */ -	    break; -	  /* Now do a deeper check.  */ -	  for (k2 = &item->key->keys; k2; k2 = k2->next) -	    { -	      if (k2->fingerprint && !strcmp (k->fingerprint, k2->fingerprint)) -		{ -		  /* Okay, replace it with the new copy.  */ -		  gpgme_key_unref (item->key); -		  item->key = key; -		  gpgme_key_ref (item->key); -		  UNLOCK (key_cache_lock); -		  return; -                } -            } -        } -      if (item) -	continue; -         -      if (n > key_cache_max_chain_length) -	{ -	  /* Remove the last entries.  */ -	  struct key_cache_item_s *last = NULL; - -	  for (item = key_cache[hash]; -	       item && n < key_cache_max_chain_length; -	       last = item, item = item->next, n++) -	    ; -	   -	  if (last) -	    { -	      struct key_cache_item_s *next; - -	      assert (last->next == item); -	      last->next = NULL; -	      for (; item; item = next) -		{ -		  next = item->next; -		  gpgme_key_unref (item->key); -		  item->key = NULL; -		  item->next = key_cache_unused_items; -		  key_cache_unused_items = item; -                } -            } -        } - -      item = key_cache_unused_items; -      if (item) -	{ -	  key_cache_unused_items = item->next; -	  item->next = NULL; -        } -      else -	{ -	  item = malloc (sizeof *item); -	  if (!item) -	    { -	      UNLOCK (key_cache_lock); -	      return; -	    } -        } - -      item->key = key; -      gpgme_key_ref (key); -      item->next = key_cache[hash]; -      key_cache[hash] = item; -    } -  UNLOCK (key_cache_lock); -} - - -GpgmeKey  -_gpgme_key_cache_get (const char *fpr) -{ -  struct key_cache_item_s *item; -  unsigned int hash; - -  LOCK (key_cache_lock); -  /* Check if cache is enabled already.  */ -  if (!key_cache_size) -    { -      UNLOCK (key_cache_lock); -      return NULL; -    } - -  if (hash_key (fpr, &hash)) -    { -      UNLOCK (key_cache_lock); -      return NULL; -    } - -  hash %= key_cache_size; -  for (item = key_cache[hash]; item; item = item->next) -    { -      struct subkey_s *k; - -      for (k = &item->key->keys; k; k = k->next) -	{ -	  if (k->fingerprint && !strcmp (k->fingerprint, fpr)) -	    { -	      gpgme_key_ref (item->key); -	      UNLOCK (key_cache_lock); -	      return item->key; -            } -        } -    } -  UNLOCK (key_cache_lock); -  return NULL; -} -  static const char *  pkalgo_to_string (int algo) @@ -1180,51 +967,3 @@ gpgme_key_sig_get_ulong_attr (GpgmeKey key, int uid_idx, GpgmeAttr what,        return 0;      }  } - - -/* Get the key with the fingerprint FPR from the key cache or from the -   crypto backend.  If FORCE_UPDATE is true, force a refresh of the -   key from the crypto backend and replace the key in the cache, if -   any.  If SECRET is true, get the secret key.  */ -GpgmeError -gpgme_get_key (GpgmeCtx ctx, const char *fpr, GpgmeKey *r_key, -	       int secret, int force_update) -{ -  GpgmeCtx listctx; -  GpgmeError err; - -  if (!ctx || !r_key) -    return GPGME_Invalid_Value; -   -  if (strlen (fpr) < 16)	/* We have at least a key ID.  */ -    return GPGME_Invalid_Key; - -  if (!force_update) -    { -      *r_key = _gpgme_key_cache_get (fpr); -      if (*r_key) -	{ -	  /* If the primary UID (if available) has no signatures, and -	     we are in the signature listing keylist mode, then try to -	     update the key below before returning.  */ -	  if (!((ctx->keylist_mode & GPGME_KEYLIST_MODE_SIGS) -		&& (*r_key)->uids && !(*r_key)->uids->certsigs)) -	    return 0; -	} -    } - -  /* We need our own context because we have to avoid the user's I/O -     callback handlers.  */ -  /* Fixme: This can be optimized by keeping an internal context -     used for such key listings.  */ -  err = gpgme_new (&listctx); -  if (err) -    return err; -  gpgme_set_protocol (listctx, gpgme_get_protocol (ctx)); -  gpgme_set_keylist_mode (listctx, ctx->keylist_mode); -  err = gpgme_op_keylist_start (listctx, fpr, secret); -  if (!err) -    err = gpgme_op_keylist_next (listctx, r_key); -  gpgme_release (listctx); -  return err; -} diff --git a/gpgme/key.h b/gpgme/key.h index c9e60416..4b60b608 100644 --- a/gpgme/key.h +++ b/gpgme/key.h @@ -96,11 +96,6 @@ struct gpgme_key_s  }; -void _gpgme_key_cache_init (void); -void _gpgme_key_cache_add (GpgmeKey key); -GpgmeKey _gpgme_key_cache_get (const char *fpr); - -  struct certsig_s *_gpgme_key_add_certsig (GpgmeKey key, char *src);  struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key);  struct subkey_s *_gpgme_key_add_secret_subkey (GpgmeKey key); diff --git a/gpgme/ops.h b/gpgme/ops.h index b3377a2d..c21de0bf 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -94,6 +94,17 @@ GpgmeError _gpgme_passphrase_start (GpgmeCtx ctx);  GpgmeError _gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code,  					   char *args); + +/* From key-cache.c.  */ + +/* Acquire a reference to KEY and add it to the key cache.  */ +void _gpgme_key_cache_add (GpgmeKey key); + +/* Look up a key with fingerprint FPR in the key cache.  If such a key +   is found, a reference is acquired for it and it is returned. +   Otherwise, NULL is returned.  */ +GpgmeKey _gpgme_key_cache_get (const char *fpr); +  /*-- keylist.c --*/  void _gpgme_op_keylist_event_cb (void *data, GpgmeEventIO type, void *type_data); diff --git a/gpgme/version.c b/gpgme/version.c index 0efdf40f..d64e67a3 100644 --- a/gpgme/version.c +++ b/gpgme/version.c @@ -31,9 +31,6 @@  /* For _gpgme_sema_subsystem_init ().  */  #include "sema.h" -/* For _gpgme_key_cache_init ().  */ -#include "key.h" -  /* Bootstrap the subsystems needed for concurrent operation.  This     must be done once at startup.  We can not guarantee this using a @@ -49,7 +46,6 @@ do_subsystem_inits (void)      return;    _gpgme_sema_subsystem_init (); -  _gpgme_key_cache_init ();    done = 1;  } | 
