bea6b148c423242af39de9189ffd1079255d7043
[oweals/gnunet.git] / src / fs / plugin_block_fs.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2010, 2013 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file fs/plugin_block_fs.c
23  * @brief blocks used for file-sharing
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_block_plugin.h"
28 #include "gnunet_fs_service.h"
29 #include "block_fs.h"
30 #include "gnunet_signatures.h"
31 #include "gnunet_block_group_lib.h"
32
33
34 /**
35  * Number of bits we set per entry in the bloomfilter.
36  * Do not change!
37  */
38 #define BLOOMFILTER_K 16
39
40
41 /**
42  * How many bytes should a bloomfilter be if we have already seen
43  * entry_count responses?  Note that #GNUNET_CONSTANTS_BLOOMFILTER_K
44  * gives us the number of bits set per entry.  Furthermore, we should
45  * not re-size the filter too often (to keep it cheap).
46  *
47  * Since other peers will also add entries but not resize the filter,
48  * we should generally pick a slightly larger size than what the
49  * strict math would suggest.
50  *
51  * @param entry_count expected number of entries in the Bloom filter
52  * @return must be a power of two and smaller or equal to 2^15.
53  */
54 static size_t
55 compute_bloomfilter_size (unsigned int entry_count)
56 {
57   size_t size;
58   unsigned int ideal = (entry_count * BLOOMFILTER_K) / 4;
59   uint16_t max = 1 << 15;
60
61   if (entry_count > max)
62     return max;
63   size = 8;
64   while ((size < max) && (size < ideal))
65     size *= 2;
66   if (size > max)
67     return max;
68   return size;
69 }
70
71
72 /**
73  * Create a new block group.
74  *
75  * @param ctx block context in which the block group is created
76  * @param type type of the block for which we are creating the group
77  * @param nonce random value used to seed the group creation
78  * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
79  * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
80  * @param va variable arguments specific to @a type
81  * @return block group handle, NULL if block groups are not supported
82  *         by this @a type of block (this is not an error)
83  */
84 static struct GNUNET_BLOCK_Group *
85 block_plugin_fs_create_group (void *cls,
86                               enum GNUNET_BLOCK_Type type,
87                               uint32_t nonce,
88                               const void *raw_data,
89                               size_t raw_data_size,
90                               va_list va)
91 {
92   unsigned int size;
93   const char *guard;
94
95   switch (type)
96   {
97   case GNUNET_BLOCK_TYPE_FS_DBLOCK:
98     GNUNET_break (NULL == va_arg (va, const char *));
99     return NULL;
100   case GNUNET_BLOCK_TYPE_FS_IBLOCK:
101     GNUNET_break (NULL == va_arg (va, const char *));
102     return NULL;
103   case GNUNET_BLOCK_TYPE_FS_UBLOCK:
104     guard = va_arg (va, const char *);
105     if (0 != memcmp (guard,
106                      "seen-set-size",
107                      strlen ("seen-set-size")))
108     {
109       /* va-args invalid! bad bug, complain! */
110       GNUNET_break (0);
111       size = 8;
112     }
113     else
114     {
115       size = compute_bloomfilter_size (va_arg (va, unsigned int));
116     }
117     if (0 == size)
118       size = raw_data_size; /* not for us to determine, use what we got! */
119     GNUNET_break (NULL == va_arg (va, const char *));
120     return GNUNET_BLOCK_GROUP_bf_create (cls,
121                                          size,
122                                          BLOOMFILTER_K,
123                                          type,
124                                          nonce,
125                                          raw_data,
126                                          raw_data_size);
127   default:
128     GNUNET_break (NULL == va_arg (va, const char *));
129     GNUNET_break (0);
130     return NULL;
131   }
132 }
133
134
135 /**
136  * Function called to validate a reply or a request.  For
137  * request evaluation, simply pass "NULL" for the reply_block.
138  * Note that it is assumed that the reply has already been
139  * matched to the key (and signatures checked) as it would
140  * be done with the #GNUNET_BLOCK_get_key() function.
141  *
142  * @param cls closure
143  * @param type block type
144  * @param bg group to use for evaluation
145  * @param eo control flags
146  * @param query original query (hash)
147  * @param xquery extrended query data (can be NULL, depending on type)
148  * @param xquery_size number of bytes in @a xquery
149  * @param reply_block response to validate
150  * @param reply_block_size number of bytes in @a reply_block
151  * @return characterization of result
152  */
153 static enum GNUNET_BLOCK_EvaluationResult
154 block_plugin_fs_evaluate (void *cls,
155                           enum GNUNET_BLOCK_Type type,
156                           struct GNUNET_BLOCK_Group *bg,
157                           enum GNUNET_BLOCK_EvaluationOptions eo,
158                           const struct GNUNET_HashCode *query,
159                           const void *xquery,
160                           size_t xquery_size,
161                           const void *reply_block,
162                           size_t reply_block_size)
163 {
164   const struct UBlock *ub;
165   struct GNUNET_HashCode hc;
166   struct GNUNET_HashCode chash;
167
168   switch (type)
169   {
170   case GNUNET_BLOCK_TYPE_FS_DBLOCK:
171   case GNUNET_BLOCK_TYPE_FS_IBLOCK:
172     if (0 != xquery_size)
173     {
174       GNUNET_break_op (0);
175       return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
176     }
177     if (NULL == reply_block)
178       return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
179     return GNUNET_BLOCK_EVALUATION_OK_LAST;
180   case GNUNET_BLOCK_TYPE_FS_UBLOCK:
181     if (0 != xquery_size)
182     {
183       GNUNET_break_op (0);
184       return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
185     }
186     if (NULL == reply_block)
187       return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
188
189     if (reply_block_size < sizeof (struct UBlock))
190     {
191       GNUNET_break_op (0);
192       return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
193     }
194     ub = reply_block;
195     GNUNET_CRYPTO_hash (&ub->verification_key,
196                         sizeof (ub->verification_key),
197                         &hc);
198     if (0 != memcmp (&hc,
199                      query,
200                      sizeof (struct GNUNET_HashCode)))
201     {
202       GNUNET_break_op (0);
203       return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
204     }
205     if (reply_block_size != ntohl (ub->purpose.size) + sizeof (struct GNUNET_CRYPTO_EcdsaSignature))
206     {
207       GNUNET_break_op (0);
208       return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
209     }
210     if ( (0 == (eo & GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO)) &&
211          (GNUNET_OK !=
212           GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK,
213                                       &ub->purpose,
214                                       &ub->signature,
215                                       &ub->verification_key)) )
216     {
217       GNUNET_break_op (0);
218       return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
219     }
220     GNUNET_CRYPTO_hash (reply_block,
221                         reply_block_size,
222                         &chash);
223     if (GNUNET_YES ==
224         GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
225                                             &chash))
226       return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
227     return GNUNET_BLOCK_EVALUATION_OK_MORE;
228   default:
229     return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
230   }
231 }
232
233
234 /**
235  * Function called to obtain the key for a block.
236  *
237  * @param cls closure
238  * @param type block type
239  * @param block block to get the key for
240  * @param block_size number of bytes in @a block
241  * @param key set to the key (query) for the given block
242  * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
243  *         (or if extracting a key from a block of this type does not work)
244  */
245 static int
246 block_plugin_fs_get_key (void *cls,
247                          enum GNUNET_BLOCK_Type type,
248                          const void *block,
249                          size_t block_size,
250                          struct GNUNET_HashCode *key)
251 {
252   const struct UBlock *ub;
253
254   switch (type)
255   {
256   case GNUNET_BLOCK_TYPE_FS_DBLOCK:
257   case GNUNET_BLOCK_TYPE_FS_IBLOCK:
258     GNUNET_CRYPTO_hash (block, block_size, key);
259     return GNUNET_OK;
260   case GNUNET_BLOCK_TYPE_FS_UBLOCK:
261     if (block_size < sizeof (struct UBlock))
262     {
263       GNUNET_break (0);
264       return GNUNET_SYSERR;
265     }
266     ub = block;
267     GNUNET_CRYPTO_hash (&ub->verification_key,
268                         sizeof (ub->verification_key),
269                         key);
270     return GNUNET_OK;
271   default:
272     GNUNET_break (0);
273     return GNUNET_SYSERR;
274   }
275 }
276
277
278 /**
279  * Entry point for the plugin.
280  */
281 void *
282 libgnunet_plugin_block_fs_init (void *cls)
283 {
284   static enum GNUNET_BLOCK_Type types[] =
285   {
286     GNUNET_BLOCK_TYPE_FS_DBLOCK,
287     GNUNET_BLOCK_TYPE_FS_IBLOCK,
288     GNUNET_BLOCK_TYPE_FS_UBLOCK,
289     GNUNET_BLOCK_TYPE_ANY       /* end of list */
290   };
291   struct GNUNET_BLOCK_PluginFunctions *api;
292
293   api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
294   api->evaluate = &block_plugin_fs_evaluate;
295   api->get_key = &block_plugin_fs_get_key;
296   api->create_group = &block_plugin_fs_create_group;
297   api->types = types;
298   return api;
299 }
300
301
302 /**
303  * Exit point from the plugin.
304  */
305 void *
306 libgnunet_plugin_block_fs_done (void *cls)
307 {
308   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
309
310   GNUNET_free (api);
311   return NULL;
312 }
313
314 /* end of plugin_block_fs.c */