2003-04-24 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Thu, 24 Apr 2003 15:40:49 +0000 (15:40 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Thu, 24 Apr 2003 15:40:49 +0000 (15:40 +0000)
* 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.

gpgme/ChangeLog
gpgme/Makefile.am
gpgme/key-cache.c [new file with mode: 0644]
gpgme/key.c
gpgme/key.h
gpgme/ops.h
gpgme/version.c

index 59eed25..1b4d0b5 100644 (file)
@@ -1,5 +1,18 @@
 2003-04-24  Marcus Brinkmann  <marcus@g10code.de>
        
+       * 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.
 
index 364897f..f36872e 100644 (file)
@@ -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 (file)
index 0000000..0322ef2
--- /dev/null
@@ -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;
+
+\f
+/* 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;
+}
+
+\f
+/* 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;
+}
+
+\f
+/* 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;
+}
index 7a2b754..af87ac9 100644 (file)
 #include "key.h"
 #include "sema.h"
 
-#if SIZEOF_UNSIGNED_INT < 4
-#error unsigned int too short to be used as a hash value
-#endif
-
-\f
-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;
-}
-
 \f
 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;
-}
index c9e6041..4b60b60 100644 (file)
@@ -96,11 +96,6 @@ struct gpgme_key_s
 };
 
 \f
-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);
index b3377a2..c21de0b 100644 (file)
@@ -94,6 +94,17 @@ GpgmeError _gpgme_passphrase_start (GpgmeCtx ctx);
 GpgmeError _gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code,
                                           char *args);
 
+\f
+/* 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);
 
index 0efdf40..d64e67a 100644 (file)
@@ -31,9 +31,6 @@
 /* For _gpgme_sema_subsystem_init ().  */
 #include "sema.h"
 
-/* For _gpgme_key_cache_init ().  */
-#include "key.h"
-
 \f
 /* 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;
 }