d3c973560355a40248300a71d381ff418b65a620
[oweals/gnunet.git] / src / regex / plugin_block_regex.c
1 /*
2      This file is part of GNUnet
3      (C) 2013 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 regex/plugin_block_regex.c
23  * @brief blocks used for regex storage and search
24  * @author Bartlomiej Polot
25  */
26
27 #include "platform.h"
28 #include "gnunet_block_plugin.h"
29 #include "block_regex.h"
30 #include "regex_block_lib.h"
31
32 /**
33  * Number of bits we set per entry in the bloomfilter.
34  * Do not change!
35  */
36 #define BLOOMFILTER_K 16
37
38
39 /**
40  * Show debug info about outgoing edges from a block.
41  * 
42  * @param cls Closure (uunsed).
43  * @param token Edge label.
44  * @param len Length of @c token.
45  * @param key Block the edge point to.
46  * 
47  * @return GNUNET_YES to keep iterating.
48  */
49 static int
50 rdebug (void *cls,
51              const char *token,
52              size_t len,
53              const struct GNUNET_HashCode *key)
54 {
55   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "    %s: %.*s\n",
56               GNUNET_h2s (key), len, token);
57   return GNUNET_YES;
58 }
59
60
61 /**
62  * Function called to validate a reply or a request.  For
63  * request evaluation, simply pass "NULL" for the reply_block.
64  * Note that it is assumed that the reply has already been
65  * matched to the key (and signatures checked) as it would
66  * be done with the "get_key" function.
67  *
68  * @param cls closure
69  * @param type block type
70  * @param query original query (hash)
71  * @param bf pointer to bloom filter associated with query; possibly updated (!)
72  * @param bf_mutator mutation value for bf
73  * @param xquery extrended query data (can be NULL, depending on type)
74  * @param xquery_size number of bytes in xquery
75  * @param reply_block response to validate
76  * @param reply_block_size number of bytes in reply block
77  * @return characterization of result
78  */
79 static enum GNUNET_BLOCK_EvaluationResult
80 block_plugin_regex_evaluate (void *cls, enum GNUNET_BLOCK_Type type,
81                              const struct GNUNET_HashCode * query,
82                              struct GNUNET_CONTAINER_BloomFilter **bf,
83                              int32_t bf_mutator, const void *xquery,
84                              size_t xquery_size, const void *reply_block,
85                              size_t reply_block_size)
86 {
87   struct GNUNET_HashCode chash;
88   struct GNUNET_HashCode mhash;
89
90   switch (type)
91   {
92     case GNUNET_BLOCK_TYPE_REGEX:
93       if (NULL == reply_block)
94         return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
95       if (0 != xquery_size)
96       {
97         const char *query;
98
99         query = (const char *) xquery;
100         if ('\0' != query[xquery_size - 1]) /* must be valid string */
101         {
102           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
103                       "Block xquery not a valid string\n");
104           return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
105         }
106       }
107       else
108       {
109         const struct RegexBlock *rblock = reply_block;
110
111         GNUNET_break_op (0);
112         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Block with no xquery\n");
113         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  key: %s, %u edges\n",
114                     GNUNET_h2s (&rblock->key), ntohl (rblock->n_edges));
115         GNUNET_REGEX_block_iterate (rblock, reply_block_size, &rdebug, NULL);
116         return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
117       }
118       switch (GNUNET_REGEX_block_check (reply_block,
119                                         reply_block_size,
120                                         xquery))
121       {
122         case GNUNET_SYSERR:
123           GNUNET_break_op(0);
124           return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
125         case GNUNET_NO:
126           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
127                       "BLOCK XQUERY %s not accepted\n", xquery);
128           return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
129         default:
130           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131                       "BLOCK XQUERY %s accepted\n", xquery);
132           break;
133       }
134       if (NULL != bf)
135       {
136         GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
137         GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
138         if (NULL != *bf)
139         {
140           if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
141             return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
142         }
143         else
144         {
145           *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
146         }
147         GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
148       }
149       return GNUNET_BLOCK_EVALUATION_OK_MORE;
150
151
152     case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
153       if (0 != xquery_size)
154       {
155         GNUNET_break_op (0);
156         return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
157       }
158       if (NULL == reply_block)
159         return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
160       if (sizeof (struct RegexAccept) != reply_block_size)
161       {
162         GNUNET_break_op(0);
163         return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
164       }
165       if (NULL != bf)
166       {
167         GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
168         GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
169         if (NULL != *bf)
170         {
171           if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
172             return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
173         }
174         else
175         {
176           *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
177         }
178         GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
179       }
180       return GNUNET_BLOCK_EVALUATION_OK_MORE;
181
182
183     default:
184       return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
185   }
186 }
187
188
189 /**
190  * Function called to obtain the key for a block.
191  *
192  * @param cls closure
193  * @param type block type
194  * @param block block to get the key for
195  * @param block_size number of bytes in block
196  * @param key set to the key (query) for the given block
197  * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported
198  *         (or if extracting a key from a block of this type does not work)
199  */
200 static int
201 block_plugin_regex_get_key (void *cls, enum GNUNET_BLOCK_Type type,
202                             const void *block, size_t block_size,
203                             struct GNUNET_HashCode * key)
204 {
205   switch (type)
206   {
207     case GNUNET_BLOCK_TYPE_REGEX:
208       GNUNET_assert (sizeof (struct RegexBlock) <= block_size);
209       *key = ((struct RegexBlock *) block)->key;
210       return GNUNET_OK;
211     case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
212       GNUNET_assert (sizeof (struct RegexAccept) <= block_size);
213       *key = ((struct RegexAccept *) block)->key;
214       return GNUNET_OK;
215     default:
216       GNUNET_break (0);
217       return GNUNET_SYSERR;
218   }
219 }
220
221
222 /**
223  * Entry point for the plugin.
224  */
225 void *
226 libgnunet_plugin_block_regex_init (void *cls)
227 {
228   static enum GNUNET_BLOCK_Type types[] =
229   {
230     GNUNET_BLOCK_TYPE_REGEX,
231     GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
232     GNUNET_BLOCK_TYPE_ANY       /* end of list */
233   };
234   struct GNUNET_BLOCK_PluginFunctions *api;
235
236   api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions));
237   api->evaluate = &block_plugin_regex_evaluate;
238   api->get_key = &block_plugin_regex_get_key;
239   api->types = types;
240   return api;
241 }
242
243
244 /**
245  * Exit point from the plugin.
246  */
247 void *
248 libgnunet_plugin_block_regex_done (void *cls)
249 {
250   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
251
252   GNUNET_free (api);
253   return NULL;
254 }
255
256 /* end of plugin_block_regex.c */