check
[oweals/gnunet.git] / src / block / block.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file block/block.c
23  * @brief library for data block manipulation
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_signatures.h"
29 #include "gnunet_block_lib.h"
30 #include "gnunet_block_plugin.h"
31
32
33 /**
34  * Handle for a plugin.
35  */
36 struct Plugin
37 {
38   /**
39    * Name of the shared library.
40    */ 
41   char *library_name;
42   
43   /**
44    * Plugin API.
45    */
46   struct GNUNET_BLOCK_PluginFunctions *api;
47 };
48
49
50 /**
51  * Handle to an initialized block library.
52  */
53 struct GNUNET_BLOCK_Context
54 {
55   /**
56    * NULL-terminated array of our plugins.
57    */
58   struct Plugin **plugins;
59
60   /**
61    * Our configuration.
62    */ 
63   const struct GNUNET_CONFIGURATION_Handle *cfg;
64 };
65
66
67 /**
68  * Mingle hash with the mingle_number to produce different bits.
69  * 
70  * @param in original hash code
71  * @param mingle_number number for hash permutation
72  * @param hc where to store the result.
73  */
74 void
75 GNUNET_BLOCK_mingle_hash (const GNUNET_HashCode * in,
76                           uint32_t mingle_number, 
77                           GNUNET_HashCode * hc)
78 {
79   GNUNET_HashCode m;
80
81   GNUNET_CRYPTO_hash (&mingle_number, 
82                       sizeof (uint32_t), 
83                       &m);
84   GNUNET_CRYPTO_hash_xor (&m, in, hc);
85 }
86
87
88 /**
89  * Create a block context.  Loads the block plugins.
90  *
91  * @param cfg configuration to use
92  * @return NULL on error
93  */
94 struct GNUNET_BLOCK_Context *
95 GNUNET_BLOCK_context_create (const struct GNUNET_CONFIGURATION_Handle *cfg)
96 {
97   struct GNUNET_BLOCK_Context *ctx;
98   struct GNUNET_BLOCK_PluginFunctions *api;
99   struct Plugin *plugin;
100   unsigned int num_plugins;
101   char *plugs;
102   char *pos;
103   char *libname;
104
105   ctx = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_Context));
106   ctx->cfg = cfg;
107   num_plugins = 0;
108   if (GNUNET_OK ==
109       GNUNET_CONFIGURATION_get_value_string (cfg,
110                                              "block", "PLUGINS", &plugs))
111     {
112       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
113                   _("Loading block plugins `%s'\n"), plugs);
114       pos = strtok (plugs, " ");
115       while (pos != NULL)
116         {
117           GNUNET_asprintf (&libname, "libgnunet_plugin_block_%s", pos);
118           api = GNUNET_PLUGIN_load (libname, NULL);
119           if (api == NULL)
120             {
121               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
122                           _("Failed to load block plugin `%s'\n"),
123                           pos);
124               GNUNET_free (libname);
125             }
126           else
127             {
128               plugin = GNUNET_malloc (sizeof (struct Plugin));
129               plugin->api = api;
130               plugin->library_name = libname;
131               GNUNET_array_append (ctx->plugins,
132                                    num_plugins,
133                                    plugin);
134             }
135           pos = strtok (NULL, " ");
136         }
137       GNUNET_free (plugs);
138     }
139   GNUNET_array_append (ctx->plugins,
140                        num_plugins,
141                        NULL);
142   return ctx;
143 }
144
145
146 /**
147  * Destroy the block context.
148  *
149  * @param ctx context to destroy
150  */
151 void
152 GNUNET_BLOCK_context_destroy (struct GNUNET_BLOCK_Context *ctx)
153 {
154   unsigned int i;
155   struct Plugin *plugin;
156
157   i = 0;
158   while (NULL != (plugin = ctx->plugins[i]))
159     {
160       GNUNET_break (NULL == 
161                     GNUNET_PLUGIN_unload (plugin->library_name,
162                                           plugin->api));
163       GNUNET_free (plugin->library_name);
164       GNUNET_free (plugin);
165       i++;
166     }
167   GNUNET_free (ctx->plugins);
168   GNUNET_free (ctx);
169 }
170
171
172 /**
173  * Find a plugin for the given type.
174  *
175  * @param ctx context to search
176  * @param type type to look for
177  * @return NULL if no matching plugin exists
178  */
179 static struct GNUNET_BLOCK_PluginFunctions *
180 find_plugin (struct GNUNET_BLOCK_Context *ctx,
181              enum GNUNET_BLOCK_Type type)
182 {
183   struct Plugin *plugin;
184   unsigned int i;
185   unsigned int j;
186
187   i = 0;
188   while (NULL != (plugin = ctx->plugins[i]))
189     {
190       j = 0;
191       while (0 != (plugin->api->types[j]))
192         {
193           if (type == plugin->api->types[j])
194             return plugin->api;
195           j++;
196         }
197       i++;
198     }
199   return NULL;
200 }
201
202
203 /**
204  * Function called to validate a reply or a request.  For
205  * request evaluation, simply pass "NULL" for the reply_block.
206  * Note that it is assumed that the reply has already been 
207  * matched to the key (and signatures checked) as it would
208  * be done with the "get_key" function.
209  *
210  * @param ctx block contxt
211  * @param type block type
212  * @param query original query (hash)
213  * @param bf pointer to bloom filter associated with query; possibly updated (!)
214  * @param bf_mutator mutation value for bf
215  * @param xquery extended query data (can be NULL, depending on type)
216  * @param xquery_size number of bytes in xquery
217  * @param reply_block response to validate
218  * @param reply_block_size number of bytes in reply block
219  * @return characterization of result
220  */
221 enum GNUNET_BLOCK_EvaluationResult
222 GNUNET_BLOCK_evaluate (struct GNUNET_BLOCK_Context *ctx,
223                        enum GNUNET_BLOCK_Type type,
224                        const GNUNET_HashCode *query,
225                        struct GNUNET_CONTAINER_BloomFilter **bf,
226                        int32_t bf_mutator,
227                        const void *xquery,
228                        size_t xquery_size,
229                        const void *reply_block,
230                        size_t reply_block_size)
231 {
232   struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type);
233
234   if (plugin == NULL)
235     return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
236   return plugin->evaluate (plugin->cls,
237                            type, query, bf, bf_mutator,
238                            xquery, xquery_size, reply_block, reply_block_size);
239 }
240
241
242 /**
243  * Function called to obtain the key for a block.
244  *
245  * @param ctx block context
246  * @param type block type
247  * @param block block to get the key for
248  * @param block_size number of bytes in block
249  * @param key set to the key (query) for the given block
250  * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported
251  *         (or if extracting a key from a block of this type does not work)
252  */
253 int
254 GNUNET_BLOCK_get_key (struct GNUNET_BLOCK_Context *ctx,
255                       enum GNUNET_BLOCK_Type type,
256                       const void *block,
257                       size_t block_size,
258                       GNUNET_HashCode *key)
259 {
260   struct GNUNET_BLOCK_PluginFunctions *plugin = find_plugin (ctx, type);
261
262   if (plugin == NULL)
263     return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
264   return plugin->get_key (plugin->cls,
265                           type, block, block_size, key);
266 }
267
268
269 /* end of block.c */