2003-07-07 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / src / module.c
1 /* module.c - Module management for libgcrypt.
2  * Copyright (C) 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <assert.h>
22 #include <config.h>
23 #include <errno.h>
24 #include "g10lib.h"
25
26 /* Internal function.  Generate a new, unique module ID for a module
27    that should be inserted into the module chain starting at
28    MODULES.  */
29 static gpg_err_code_t
30 _gcry_module_id_new (gcry_module_t modules, unsigned int *id_new)
31 {
32   /* FIXME, what should be the ID of the first module registered by
33      the user?  */
34   unsigned int id_min = 600, id_max = (unsigned int) -1, mod_id;
35   gpg_err_code_t err = GPG_ERR_NO_ERROR;
36   gcry_module_t module;
37
38   /* Search for unused ID.  */
39   for (mod_id = id_min; mod_id < id_max; mod_id++)
40     {
41       /* Search for a module with the current ID.  */
42       for (module = modules; module; module = module->next)
43         if (mod_id == module->mod_id)
44           break;
45
46       if (! module)
47         /* None found -> the ID is available for use.  */
48         break;
49     }
50
51   if (mod_id < id_max)
52     /* Done.  */
53     *id_new = mod_id;
54   else
55     /* No free ID found.  */
56     err = GPG_ERR_INTERNAL;
57
58   return err;
59 }
60
61 /* Add a module specification to the list ENTRIES.  The new module has
62    it's use-counter set to one.  */
63 gpg_err_code_t
64 _gcry_module_add (gcry_module_t *entries, unsigned int mod_id,
65                   void *spec, gcry_module_t *module)
66 {
67   gpg_err_code_t err = 0;
68   gcry_module_t entry;
69
70   if (! mod_id)
71     err = _gcry_module_id_new (*entries, &mod_id);
72
73   if (! err)
74     {
75       entry = gcry_malloc (sizeof (struct gcry_module));
76       if (! entry)
77         err = gpg_err_code_from_errno (errno);
78     }
79
80   if (! err)
81     {
82       /* Fill new module entry.  */
83       entry->flags = 0;
84       entry->counter = 1;
85       entry->spec = spec;
86       entry->mod_id = mod_id;
87
88       /* Link it into the list.  */
89       entry->next = *entries;
90       entry->prevp = entries;
91       if (*entries)
92         (*entries)->prevp = &entry->next;
93       *entries = entry;
94
95       /* And give it to the caller.  */
96       if (module)
97         *module = entry;
98     }
99   return err;
100 }
101
102 /* Internal function.  Unlink CIPHER_ENTRY from the list of registered
103    ciphers and destroy it.  */
104 static void
105 _gcry_module_drop (gcry_module_t entry)
106 {
107   *entry->prevp = entry->next;
108   if (entry->next)
109     entry->next->prevp = entry->prevp;
110
111   gcry_free (entry);
112 }
113
114 /* Lookup a module specification by it's ID.  After a successfull
115    lookup, the module has it's resource counter incremented.  */
116 gcry_module_t 
117 _gcry_module_lookup_id (gcry_module_t entries, unsigned int mod_id)
118 {
119   gcry_module_t entry;
120
121   for (entry = entries; entry; entry = entry->next)
122     if (entry->mod_id == mod_id)
123       {
124         entry->counter++;
125         break;
126       }
127
128   return entry;
129 }
130
131 /* Lookup a module specification.  After a successfull lookup, the
132    module has it's resource counter incremented.  FUNC is a function
133    provided by the caller, which is responsible for identifying the
134    wanted module.  */
135 gcry_module_t 
136 _gcry_module_lookup (gcry_module_t entries, void *data,
137                      gcry_module_lookup_t func)
138 {
139   gcry_module_t entry;
140
141   for (entry = entries; entry; entry = entry->next)
142     if ((*func) (entry->spec, data))
143       {
144         entry->counter++;
145         break;
146       }
147
148   return entry;
149 }
150
151 /* Release a module.  In case the use-counter reaches zero, destroy
152    the module.  */
153 void
154 _gcry_module_release (gcry_module_t module)
155 {
156   if (! --module->counter)
157     _gcry_module_drop (module);
158 }
159
160 /* Add a reference to a module.  */
161 void
162 _gcry_module_use (gcry_module_t module)
163 {
164   ++module->counter;
165 }
166
167 /* If LIST is zero, write the number of modules identified by MODULES
168    to LIST_LENGTH and return.  If LIST is non-zero, the first
169    *LIST_LENGTH algorithm IDs are stored in LIST, which must be of
170    according size.  In case there are less cipher modules than
171    *LIST_LENGTH, *LIST_LENGTH is updated to the correct number.  */
172 gpg_err_code_t
173 _gcry_module_list (gcry_module_t modules,
174                    int *list, int *list_length)
175 {
176   gpg_err_code_t err = GPG_ERR_NO_ERROR;
177   gcry_module_t module;
178   int length, i;
179
180   for (module = modules, length = 0; module; module = module->next, length++);
181
182   if (list)
183     {
184       if (length > *list_length)
185         length = *list_length;
186
187       for (module = modules, i = 0; i < length; module = module->next, i++)
188         list[i] = module->mod_id;
189
190       if (length < *list_length)
191         *list_length = length;
192     }
193   else
194     *list_length = length;
195
196   return err;
197 }