diff options
author | lurchi <lurchi@strangeplace.net> | 2018-06-25 18:38:13 +0200 |
---|---|---|
committer | lurchi <lurchi@strangeplace.net> | 2018-06-25 18:38:27 +0200 |
commit | a4186fc2fd00b3fe2899bffcdbbbf8fead31115f (patch) | |
tree | d70c5939cc99d43e29ce63a4faa9ef334de0c81d /src/regex/regex_internal_dht.c | |
parent | 7da98cf076e9c5101244dfbbf8c3ddff045d298e (diff) | |
download | gnunet-a4186fc2fd00b3fe2899bffcdbbbf8fead31115f.tar.gz gnunet-a4186fc2fd00b3fe2899bffcdbbbf8fead31115f.zip |
Revert "integrate dnsparser and dnsstub and tun with libgnunetutil"
This reverts commit 7da98cf076e9c5101244dfbbf8c3ddff045d298e.
Diffstat (limited to 'src/regex/regex_internal_dht.c')
-rw-r--r-- | src/regex/regex_internal_dht.c | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/src/regex/regex_internal_dht.c b/src/regex/regex_internal_dht.c new file mode 100644 index 000000000..2555ef1df --- /dev/null +++ b/src/regex/regex_internal_dht.c | |||
@@ -0,0 +1,829 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2012, 2015 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | /** | ||
19 | * @file src/regex/regex_internal_dht.c | ||
20 | * @brief library to announce regexes in the network and match strings | ||
21 | * against published regexes. | ||
22 | * @author Bartlomiej Polot | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "regex_internal_lib.h" | ||
26 | #include "regex_block_lib.h" | ||
27 | #include "gnunet_dht_service.h" | ||
28 | #include "gnunet_statistics_service.h" | ||
29 | #include "gnunet_constants.h" | ||
30 | #include "gnunet_signatures.h" | ||
31 | |||
32 | |||
33 | #define LOG(kind,...) GNUNET_log_from (kind,"regex-dht",__VA_ARGS__) | ||
34 | |||
35 | /** | ||
36 | * DHT replication level to use. | ||
37 | */ | ||
38 | #define DHT_REPLICATION 5 | ||
39 | |||
40 | /** | ||
41 | * DHT record lifetime to use. | ||
42 | */ | ||
43 | #define DHT_TTL GNUNET_TIME_UNIT_HOURS | ||
44 | |||
45 | /** | ||
46 | * DHT options to set. | ||
47 | */ | ||
48 | #define DHT_OPT GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Handle to store cached data about a regex announce. | ||
53 | */ | ||
54 | struct REGEX_INTERNAL_Announcement | ||
55 | { | ||
56 | /** | ||
57 | * DHT handle to use, must be initialized externally. | ||
58 | */ | ||
59 | struct GNUNET_DHT_Handle *dht; | ||
60 | |||
61 | /** | ||
62 | * Regular expression. | ||
63 | */ | ||
64 | const char *regex; | ||
65 | |||
66 | /** | ||
67 | * Automaton representation of the regex (expensive to build). | ||
68 | */ | ||
69 | struct REGEX_INTERNAL_Automaton *dfa; | ||
70 | |||
71 | /** | ||
72 | * Our private key. | ||
73 | */ | ||
74 | const struct GNUNET_CRYPTO_EddsaPrivateKey *priv; | ||
75 | |||
76 | /** | ||
77 | * Optional statistics handle to report usage. Can be NULL. | ||
78 | */ | ||
79 | struct GNUNET_STATISTICS_Handle *stats; | ||
80 | }; | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Regex callback iterator to store own service description in the DHT. | ||
85 | * | ||
86 | * @param cls closure. | ||
87 | * @param key hash for current state. | ||
88 | * @param proof proof for current state. | ||
89 | * @param accepting #GNUNET_YES if this is an accepting state, #GNUNET_NO if not. | ||
90 | * @param num_edges number of edges leaving current state. | ||
91 | * @param edges edges leaving current state. | ||
92 | */ | ||
93 | static void | ||
94 | regex_iterator (void *cls, | ||
95 | const struct GNUNET_HashCode *key, | ||
96 | const char *proof, | ||
97 | int accepting, | ||
98 | unsigned int num_edges, | ||
99 | const struct REGEX_BLOCK_Edge *edges) | ||
100 | { | ||
101 | struct REGEX_INTERNAL_Announcement *h = cls; | ||
102 | struct RegexBlock *block; | ||
103 | size_t size; | ||
104 | unsigned int i; | ||
105 | |||
106 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
107 | "DHT PUT for state %s with proof `%s' and %u edges:\n", | ||
108 | GNUNET_h2s (key), | ||
109 | proof, | ||
110 | num_edges); | ||
111 | for (i = 0; i < num_edges; i++) | ||
112 | { | ||
113 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
114 | "Edge %u `%s' towards %s\n", | ||
115 | i, | ||
116 | edges[i].label, | ||
117 | GNUNET_h2s (&edges[i].destination)); | ||
118 | } | ||
119 | if (GNUNET_YES == accepting) | ||
120 | { | ||
121 | struct RegexAcceptBlock ab; | ||
122 | |||
123 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
124 | "State %s is accepting, putting own id\n", | ||
125 | GNUNET_h2s (key)); | ||
126 | size = sizeof (struct RegexAcceptBlock); | ||
127 | ab.purpose.size = ntohl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | ||
128 | sizeof (struct GNUNET_TIME_AbsoluteNBO) + | ||
129 | sizeof (struct GNUNET_HashCode)); | ||
130 | ab.purpose.purpose = ntohl (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT); | ||
131 | ab.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_DHT_MAX_EXPIRATION)); | ||
132 | ab.key = *key; | ||
133 | GNUNET_CRYPTO_eddsa_key_get_public (h->priv, | ||
134 | &ab.peer.public_key); | ||
135 | GNUNET_assert (GNUNET_OK == | ||
136 | GNUNET_CRYPTO_eddsa_sign (h->priv, | ||
137 | &ab.purpose, | ||
138 | &ab.signature)); | ||
139 | |||
140 | GNUNET_STATISTICS_update (h->stats, "# regex accepting blocks stored", | ||
141 | 1, GNUNET_NO); | ||
142 | GNUNET_STATISTICS_update (h->stats, "# regex accepting block bytes stored", | ||
143 | sizeof (struct RegexAcceptBlock), GNUNET_NO); | ||
144 | (void) | ||
145 | GNUNET_DHT_put (h->dht, key, | ||
146 | DHT_REPLICATION, | ||
147 | DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE, | ||
148 | GNUNET_BLOCK_TYPE_REGEX_ACCEPT, | ||
149 | size, | ||
150 | &ab, | ||
151 | GNUNET_TIME_relative_to_absolute (DHT_TTL), | ||
152 | NULL, NULL); | ||
153 | } | ||
154 | block = REGEX_BLOCK_create (proof, | ||
155 | num_edges, | ||
156 | edges, | ||
157 | accepting, | ||
158 | &size); | ||
159 | if (NULL == block) | ||
160 | return; | ||
161 | (void) GNUNET_DHT_put (h->dht, | ||
162 | key, | ||
163 | DHT_REPLICATION, | ||
164 | DHT_OPT, | ||
165 | GNUNET_BLOCK_TYPE_REGEX, | ||
166 | size, | ||
167 | block, | ||
168 | GNUNET_TIME_relative_to_absolute (DHT_TTL), | ||
169 | NULL, | ||
170 | NULL); | ||
171 | GNUNET_STATISTICS_update (h->stats, | ||
172 | "# regex blocks stored", | ||
173 | 1, | ||
174 | GNUNET_NO); | ||
175 | GNUNET_STATISTICS_update (h->stats, | ||
176 | "# regex block bytes stored", | ||
177 | size, | ||
178 | GNUNET_NO); | ||
179 | GNUNET_free (block); | ||
180 | } | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Announce a regular expression: put all states of the automaton in the DHT. | ||
185 | * Does not free resources, must call #REGEX_INTERNAL_announce_cancel() for that. | ||
186 | * | ||
187 | * @param dht An existing and valid DHT service handle. CANNOT be NULL. | ||
188 | * @param priv our private key, must remain valid until the announcement is cancelled | ||
189 | * @param regex Regular expression to announce. | ||
190 | * @param compression How many characters per edge can we squeeze? | ||
191 | * @param stats Optional statistics handle to report usage. Can be NULL. | ||
192 | * @return Handle to reuse o free cached resources. | ||
193 | * Must be freed by calling #REGEX_INTERNAL_announce_cancel(). | ||
194 | */ | ||
195 | struct REGEX_INTERNAL_Announcement * | ||
196 | REGEX_INTERNAL_announce (struct GNUNET_DHT_Handle *dht, | ||
197 | const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, | ||
198 | const char *regex, | ||
199 | uint16_t compression, | ||
200 | struct GNUNET_STATISTICS_Handle *stats) | ||
201 | { | ||
202 | struct REGEX_INTERNAL_Announcement *h; | ||
203 | |||
204 | GNUNET_assert (NULL != dht); | ||
205 | h = GNUNET_new (struct REGEX_INTERNAL_Announcement); | ||
206 | h->regex = regex; | ||
207 | h->dht = dht; | ||
208 | h->stats = stats; | ||
209 | h->priv = priv; | ||
210 | h->dfa = REGEX_INTERNAL_construct_dfa (regex, strlen (regex), compression); | ||
211 | REGEX_INTERNAL_reannounce (h); | ||
212 | return h; | ||
213 | } | ||
214 | |||
215 | |||
216 | /** | ||
217 | * Announce again a regular expression previously announced. | ||
218 | * Does use caching to speed up process. | ||
219 | * | ||
220 | * @param h Handle returned by a previous #REGEX_INTERNAL_announce call(). | ||
221 | */ | ||
222 | void | ||
223 | REGEX_INTERNAL_reannounce (struct REGEX_INTERNAL_Announcement *h) | ||
224 | { | ||
225 | GNUNET_assert (NULL != h->dfa); /* make sure to call announce first */ | ||
226 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
227 | "REGEX_INTERNAL_reannounce: %s\n", | ||
228 | h->regex); | ||
229 | REGEX_INTERNAL_iterate_reachable_edges (h->dfa, | ||
230 | ®ex_iterator, | ||
231 | h); | ||
232 | } | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Clear all cached data used by a regex announce. | ||
237 | * Does not close DHT connection. | ||
238 | * | ||
239 | * @param h Handle returned by a previous #REGEX_INTERNAL_announce() call. | ||
240 | */ | ||
241 | void | ||
242 | REGEX_INTERNAL_announce_cancel (struct REGEX_INTERNAL_Announcement *h) | ||
243 | { | ||
244 | REGEX_INTERNAL_automaton_destroy (h->dfa); | ||
245 | GNUNET_free (h); | ||
246 | } | ||
247 | |||
248 | |||
249 | /******************************************************************************/ | ||
250 | |||
251 | |||
252 | /** | ||
253 | * Struct to keep state of running searches that have consumed a part of | ||
254 | * the inital string. | ||
255 | */ | ||
256 | struct RegexSearchContext | ||
257 | { | ||
258 | /** | ||
259 | * Part of the description already consumed by | ||
260 | * this particular search branch. | ||
261 | */ | ||
262 | size_t position; | ||
263 | |||
264 | /** | ||
265 | * Information about the search. | ||
266 | */ | ||
267 | struct REGEX_INTERNAL_Search *info; | ||
268 | |||
269 | /** | ||
270 | * We just want to look for one edge, the longer the better. | ||
271 | * Keep its length. | ||
272 | */ | ||
273 | unsigned int longest_match; | ||
274 | |||
275 | /** | ||
276 | * Destination hash of the longest match. | ||
277 | */ | ||
278 | struct GNUNET_HashCode hash; | ||
279 | }; | ||
280 | |||
281 | |||
282 | /** | ||
283 | * Type of values in `dht_get_results`. | ||
284 | */ | ||
285 | struct Result | ||
286 | { | ||
287 | /** | ||
288 | * Number of bytes in data. | ||
289 | */ | ||
290 | size_t size; | ||
291 | |||
292 | /** | ||
293 | * The raw result data. | ||
294 | */ | ||
295 | const void *data; | ||
296 | }; | ||
297 | |||
298 | |||
299 | /** | ||
300 | * Struct to keep information of searches of services described by a regex | ||
301 | * using a user-provided string service description. | ||
302 | */ | ||
303 | struct REGEX_INTERNAL_Search | ||
304 | { | ||
305 | /** | ||
306 | * DHT handle to use, must be initialized externally. | ||
307 | */ | ||
308 | struct GNUNET_DHT_Handle *dht; | ||
309 | |||
310 | /** | ||
311 | * Optional statistics handle to report usage. Can be NULL. | ||
312 | */ | ||
313 | struct GNUNET_STATISTICS_Handle *stats; | ||
314 | |||
315 | /** | ||
316 | * User provided description of the searched service. | ||
317 | */ | ||
318 | char *description; | ||
319 | |||
320 | /** | ||
321 | * Running DHT GETs. | ||
322 | */ | ||
323 | struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles; | ||
324 | |||
325 | /** | ||
326 | * Results from running DHT GETs, values are of type | ||
327 | * 'struct Result'. | ||
328 | */ | ||
329 | struct GNUNET_CONTAINER_MultiHashMap *dht_get_results; | ||
330 | |||
331 | /** | ||
332 | * Contexts, for each running DHT GET. Free all on end of search. | ||
333 | */ | ||
334 | struct RegexSearchContext **contexts; | ||
335 | |||
336 | /** | ||
337 | * Number of contexts (branches/steps in search). | ||
338 | */ | ||
339 | unsigned int n_contexts; | ||
340 | |||
341 | /** | ||
342 | * @param callback Callback for found peers. | ||
343 | */ | ||
344 | REGEX_INTERNAL_Found callback; | ||
345 | |||
346 | /** | ||
347 | * @param callback_cls Closure for @c callback. | ||
348 | */ | ||
349 | void *callback_cls; | ||
350 | }; | ||
351 | |||
352 | |||
353 | /** | ||
354 | * Jump to the next edge, with the longest matching token. | ||
355 | * | ||
356 | * @param block Block found in the DHT. | ||
357 | * @param size Size of the block. | ||
358 | * @param ctx Context of the search. | ||
359 | */ | ||
360 | static void | ||
361 | regex_next_edge (const struct RegexBlock *block, | ||
362 | size_t size, | ||
363 | struct RegexSearchContext *ctx); | ||
364 | |||
365 | |||
366 | /** | ||
367 | * Function to process DHT string to regex matching. | ||
368 | * Called on each result obtained for the DHT search. | ||
369 | * | ||
370 | * @param cls Closure (search context). | ||
371 | * @param exp When will this value expire. | ||
372 | * @param key Key of the result. | ||
373 | * @param get_path Path of the get request. | ||
374 | * @param get_path_length Lenght of get_path. | ||
375 | * @param put_path Path of the put request. | ||
376 | * @param put_path_length Length of the put_path. | ||
377 | * @param type Type of the result. | ||
378 | * @param size Number of bytes in data. | ||
379 | * @param data Pointer to the result data. | ||
380 | */ | ||
381 | static void | ||
382 | dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp, | ||
383 | const struct GNUNET_HashCode *key, | ||
384 | const struct GNUNET_PeerIdentity *get_path, | ||
385 | unsigned int get_path_length, | ||
386 | const struct GNUNET_PeerIdentity *put_path, | ||
387 | unsigned int put_path_length, | ||
388 | enum GNUNET_BLOCK_Type type, | ||
389 | size_t size, const void *data) | ||
390 | { | ||
391 | const struct RegexAcceptBlock *block = data; | ||
392 | struct RegexSearchContext *ctx = cls; | ||
393 | struct REGEX_INTERNAL_Search *info = ctx->info; | ||
394 | |||
395 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
396 | "Regex result accept for %s (key %s)\n", | ||
397 | info->description, GNUNET_h2s(key)); | ||
398 | |||
399 | GNUNET_STATISTICS_update (info->stats, | ||
400 | "# regex accepting blocks found", | ||
401 | 1, GNUNET_NO); | ||
402 | GNUNET_STATISTICS_update (info->stats, | ||
403 | "# regex accepting block bytes found", | ||
404 | size, GNUNET_NO); | ||
405 | info->callback (info->callback_cls, | ||
406 | &block->peer, | ||
407 | get_path, get_path_length, | ||
408 | put_path, put_path_length); | ||
409 | } | ||
410 | |||
411 | |||
412 | /** | ||
413 | * Find a path to a peer that offers a regex service compatible | ||
414 | * with a given string. | ||
415 | * | ||
416 | * @param key The key of the accepting state. | ||
417 | * @param ctx Context containing info about the string, tunnel, etc. | ||
418 | */ | ||
419 | static void | ||
420 | regex_find_path (const struct GNUNET_HashCode *key, | ||
421 | struct RegexSearchContext *ctx) | ||
422 | { | ||
423 | struct GNUNET_DHT_GetHandle *get_h; | ||
424 | |||
425 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
426 | "Accept state found, now searching for paths to %s\n", | ||
427 | GNUNET_h2s (key), | ||
428 | (unsigned int) ctx->position); | ||
429 | get_h = GNUNET_DHT_get_start (ctx->info->dht, /* handle */ | ||
430 | GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */ | ||
431 | key, /* key to search */ | ||
432 | DHT_REPLICATION, /* replication level */ | ||
433 | DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE, | ||
434 | NULL, /* xquery */ // FIXME BLOOMFILTER | ||
435 | 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE | ||
436 | &dht_get_string_accept_handler, ctx); | ||
437 | GNUNET_break (GNUNET_OK == | ||
438 | GNUNET_CONTAINER_multihashmap_put(ctx->info->dht_get_handles, | ||
439 | key, | ||
440 | get_h, | ||
441 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
442 | } | ||
443 | |||
444 | |||
445 | /** | ||
446 | * Function to process DHT string to regex matching. | ||
447 | * Called on each result obtained for the DHT search. | ||
448 | * | ||
449 | * @param cls closure (search context) | ||
450 | * @param exp when will this value expire | ||
451 | * @param key key of the result | ||
452 | * @param get_path path of the get request (not used) | ||
453 | * @param get_path_length length of @a get_path (not used) | ||
454 | * @param put_path path of the put request (not used) | ||
455 | * @param put_path_length length of the @a put_path (not used) | ||
456 | * @param type type of the result | ||
457 | * @param size number of bytes in data | ||
458 | * @param data pointer to the result data | ||
459 | * | ||
460 | * TODO: re-issue the request after certain time? cancel after X results? | ||
461 | */ | ||
462 | static void | ||
463 | dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp, | ||
464 | const struct GNUNET_HashCode *key, | ||
465 | const struct GNUNET_PeerIdentity *get_path, | ||
466 | unsigned int get_path_length, | ||
467 | const struct GNUNET_PeerIdentity *put_path, | ||
468 | unsigned int put_path_length, | ||
469 | enum GNUNET_BLOCK_Type type, | ||
470 | size_t size, const void *data) | ||
471 | { | ||
472 | const struct RegexBlock *block = data; | ||
473 | struct RegexSearchContext *ctx = cls; | ||
474 | struct REGEX_INTERNAL_Search *info = ctx->info; | ||
475 | size_t len; | ||
476 | struct Result *copy; | ||
477 | |||
478 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
479 | "DHT GET result for %s (%s)\n", | ||
480 | GNUNET_h2s (key), ctx->info->description); | ||
481 | copy = GNUNET_malloc (sizeof (struct Result) + size); | ||
482 | copy->size = size; | ||
483 | copy->data = ©[1]; | ||
484 | GNUNET_memcpy (©[1], block, size); | ||
485 | GNUNET_break (GNUNET_OK == | ||
486 | GNUNET_CONTAINER_multihashmap_put (info->dht_get_results, | ||
487 | key, copy, | ||
488 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); | ||
489 | len = strlen (info->description); | ||
490 | if (len == ctx->position) // String processed | ||
491 | { | ||
492 | if (GNUNET_YES == GNUNET_BLOCK_is_accepting (block, size)) | ||
493 | { | ||
494 | regex_find_path (key, ctx); | ||
495 | } | ||
496 | else | ||
497 | { | ||
498 | LOG (GNUNET_ERROR_TYPE_INFO, "block not accepting!\n"); | ||
499 | /* FIXME REGEX this block not successful, wait for more? start timeout? */ | ||
500 | } | ||
501 | return; | ||
502 | } | ||
503 | regex_next_edge (block, size, ctx); | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Iterator over found existing cadet regex blocks that match an ongoing search. | ||
509 | * | ||
510 | * @param cls Closure (current context)- | ||
511 | * @param key Current key code (key for cached block). | ||
512 | * @param value Value in the hash map (cached RegexBlock). | ||
513 | * @return #GNUNET_YES: we should always continue to iterate. | ||
514 | */ | ||
515 | static int | ||
516 | regex_result_iterator (void *cls, | ||
517 | const struct GNUNET_HashCode * key, | ||
518 | void *value) | ||
519 | { | ||
520 | struct Result *result = value; | ||
521 | const struct RegexBlock *block = result->data; | ||
522 | struct RegexSearchContext *ctx = cls; | ||
523 | |||
524 | if ( (GNUNET_YES == | ||
525 | GNUNET_BLOCK_is_accepting (block, result->size)) && | ||
526 | (ctx->position == strlen (ctx->info->description)) ) | ||
527 | { | ||
528 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
529 | "Found accepting known block\n"); | ||
530 | regex_find_path (key, ctx); | ||
531 | return GNUNET_YES; // We found an accept state! | ||
532 | } | ||
533 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
534 | "* %u, %u, [%u]\n", | ||
535 | ctx->position, | ||
536 | strlen (ctx->info->description), | ||
537 | GNUNET_BLOCK_is_accepting (block, result->size)); | ||
538 | regex_next_edge (block, result->size, ctx); | ||
539 | |||
540 | GNUNET_STATISTICS_update (ctx->info->stats, "# regex cadet blocks iterated", | ||
541 | 1, GNUNET_NO); | ||
542 | |||
543 | return GNUNET_YES; | ||
544 | } | ||
545 | |||
546 | |||
547 | /** | ||
548 | * Iterator over edges in a regex block retrieved from the DHT. | ||
549 | * | ||
550 | * @param cls Closure (context of the search). | ||
551 | * @param token Token that follows to next state. | ||
552 | * @param len Lenght of token. | ||
553 | * @param key Hash of next state. | ||
554 | * @return #GNUNET_YES if should keep iterating, #GNUNET_NO otherwise. | ||
555 | */ | ||
556 | static int | ||
557 | regex_edge_iterator (void *cls, | ||
558 | const char *token, | ||
559 | size_t len, | ||
560 | const struct GNUNET_HashCode *key) | ||
561 | { | ||
562 | struct RegexSearchContext *ctx = cls; | ||
563 | struct REGEX_INTERNAL_Search *info = ctx->info; | ||
564 | const char *current; | ||
565 | size_t current_len; | ||
566 | |||
567 | GNUNET_STATISTICS_update (info->stats, "# regex edges iterated", | ||
568 | 1, GNUNET_NO); | ||
569 | current = &info->description[ctx->position]; | ||
570 | current_len = strlen (info->description) - ctx->position; | ||
571 | if (len > current_len) | ||
572 | { | ||
573 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Token too long, END\n"); | ||
574 | return GNUNET_YES; | ||
575 | } | ||
576 | if (0 != strncmp (current, token, len)) | ||
577 | { | ||
578 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Token doesn't match, END\n"); | ||
579 | return GNUNET_YES; | ||
580 | } | ||
581 | |||
582 | if (len > ctx->longest_match) | ||
583 | { | ||
584 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is longer, KEEP\n"); | ||
585 | ctx->longest_match = len; | ||
586 | ctx->hash = *key; | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Token is not longer, IGNORE\n"); | ||
591 | } | ||
592 | |||
593 | LOG (GNUNET_ERROR_TYPE_DEBUG, "* End of regex edge iterator\n"); | ||
594 | return GNUNET_YES; | ||
595 | } | ||
596 | |||
597 | |||
598 | /** | ||
599 | * Jump to the next edge, with the longest matching token. | ||
600 | * | ||
601 | * @param block Block found in the DHT. | ||
602 | * @param size Size of the block. | ||
603 | * @param ctx Context of the search. | ||
604 | */ | ||
605 | static void | ||
606 | regex_next_edge (const struct RegexBlock *block, | ||
607 | size_t size, | ||
608 | struct RegexSearchContext *ctx) | ||
609 | { | ||
610 | struct RegexSearchContext *new_ctx; | ||
611 | struct REGEX_INTERNAL_Search *info = ctx->info; | ||
612 | struct GNUNET_DHT_GetHandle *get_h; | ||
613 | struct GNUNET_HashCode *hash; | ||
614 | const char *rest; | ||
615 | int result; | ||
616 | |||
617 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Next edge\n"); | ||
618 | /* Find the longest match for the current string position, | ||
619 | * among tokens in the given block */ | ||
620 | ctx->longest_match = 0; | ||
621 | result = REGEX_BLOCK_iterate (block, size, | ||
622 | ®ex_edge_iterator, ctx); | ||
623 | GNUNET_break (GNUNET_OK == result); | ||
624 | |||
625 | /* Did anything match? */ | ||
626 | if (0 == ctx->longest_match) | ||
627 | { | ||
628 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
629 | "no match in block\n"); | ||
630 | return; | ||
631 | } | ||
632 | |||
633 | hash = &ctx->hash; | ||
634 | new_ctx = GNUNET_new (struct RegexSearchContext); | ||
635 | new_ctx->info = info; | ||
636 | new_ctx->position = ctx->position + ctx->longest_match; | ||
637 | GNUNET_array_append (info->contexts, info->n_contexts, new_ctx); | ||
638 | |||
639 | /* Check whether we already have a DHT GET running for it */ | ||
640 | if (GNUNET_YES == | ||
641 | GNUNET_CONTAINER_multihashmap_contains (info->dht_get_handles, hash)) | ||
642 | { | ||
643 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
644 | "GET for %s running, END\n", | ||
645 | GNUNET_h2s (hash)); | ||
646 | GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results, | ||
647 | hash, | ||
648 | ®ex_result_iterator, | ||
649 | new_ctx); | ||
650 | return; /* We are already looking for it */ | ||
651 | } | ||
652 | |||
653 | GNUNET_STATISTICS_update (info->stats, "# regex nodes traversed", | ||
654 | 1, GNUNET_NO); | ||
655 | |||
656 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
657 | "Following edges at %s for offset %u in `%s'\n", | ||
658 | GNUNET_h2s (hash), | ||
659 | (unsigned int) ctx->position, | ||
660 | info->description); | ||
661 | rest = &new_ctx->info->description[new_ctx->position]; | ||
662 | get_h = | ||
663 | GNUNET_DHT_get_start (info->dht, /* handle */ | ||
664 | GNUNET_BLOCK_TYPE_REGEX, /* type */ | ||
665 | hash, /* key to search */ | ||
666 | DHT_REPLICATION, /* replication level */ | ||
667 | DHT_OPT, | ||
668 | rest, /* xquery */ | ||
669 | strlen (rest) + 1, /* xquery bits */ | ||
670 | &dht_get_string_handler, new_ctx); | ||
671 | if (GNUNET_OK != | ||
672 | GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles, | ||
673 | hash, | ||
674 | get_h, | ||
675 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) | ||
676 | { | ||
677 | GNUNET_break (0); | ||
678 | return; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | |||
683 | /** | ||
684 | * Search for a peer offering a regex matching certain string in the DHT. | ||
685 | * The search runs until #REGEX_INTERNAL_search_cancel() is called, even if results | ||
686 | * are returned. | ||
687 | * | ||
688 | * @param dht An existing and valid DHT service handle. | ||
689 | * @param string String to match against the regexes in the DHT. | ||
690 | * @param callback Callback for found peers. | ||
691 | * @param callback_cls Closure for @c callback. | ||
692 | * @param stats Optional statistics handle to report usage. Can be NULL. | ||
693 | * @return Handle to stop search and free resources. | ||
694 | * Must be freed by calling #REGEX_INTERNAL_search_cancel(). | ||
695 | */ | ||
696 | struct REGEX_INTERNAL_Search * | ||
697 | REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht, | ||
698 | const char *string, | ||
699 | REGEX_INTERNAL_Found callback, | ||
700 | void *callback_cls, | ||
701 | struct GNUNET_STATISTICS_Handle *stats) | ||
702 | { | ||
703 | struct REGEX_INTERNAL_Search *h; | ||
704 | struct GNUNET_DHT_GetHandle *get_h; | ||
705 | struct RegexSearchContext *ctx; | ||
706 | struct GNUNET_HashCode key; | ||
707 | size_t size; | ||
708 | size_t len; | ||
709 | |||
710 | /* Initialize handle */ | ||
711 | GNUNET_assert (NULL != dht); | ||
712 | GNUNET_assert (NULL != callback); | ||
713 | h = GNUNET_new (struct REGEX_INTERNAL_Search); | ||
714 | h->dht = dht; | ||
715 | h->description = GNUNET_strdup (string); | ||
716 | h->callback = callback; | ||
717 | h->callback_cls = callback_cls; | ||
718 | h->stats = stats; | ||
719 | h->dht_get_handles = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); | ||
720 | h->dht_get_results = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); | ||
721 | |||
722 | /* Initialize context */ | ||
723 | len = strlen (string); | ||
724 | size = REGEX_INTERNAL_get_first_key (string, len, &key); | ||
725 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
726 | "Initial key for `%s' is %s (based on `%.*s')\n", | ||
727 | string, | ||
728 | GNUNET_h2s (&key), | ||
729 | size, | ||
730 | string); | ||
731 | ctx = GNUNET_new (struct RegexSearchContext); | ||
732 | ctx->position = size; | ||
733 | ctx->info = h; | ||
734 | GNUNET_array_append (h->contexts, | ||
735 | h->n_contexts, | ||
736 | ctx); | ||
737 | /* Start search in DHT */ | ||
738 | get_h = GNUNET_DHT_get_start (h->dht, /* handle */ | ||
739 | GNUNET_BLOCK_TYPE_REGEX, /* type */ | ||
740 | &key, /* key to search */ | ||
741 | DHT_REPLICATION, /* replication level */ | ||
742 | DHT_OPT, | ||
743 | &h->description[size], /* xquery */ | ||
744 | // FIXME add BLOOMFILTER to exclude filtered peers | ||
745 | len + 1 - size, /* xquery bits */ | ||
746 | // FIXME add BLOOMFILTER SIZE | ||
747 | &dht_get_string_handler, ctx); | ||
748 | GNUNET_break ( | ||
749 | GNUNET_OK == | ||
750 | GNUNET_CONTAINER_multihashmap_put (h->dht_get_handles, | ||
751 | &key, | ||
752 | get_h, | ||
753 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST) | ||
754 | ); | ||
755 | |||
756 | return h; | ||
757 | } | ||
758 | |||
759 | |||
760 | /** | ||
761 | * Iterator over hash map entries to cancel DHT GET requests after a | ||
762 | * successful connect_by_string. | ||
763 | * | ||
764 | * @param cls Closure (unused). | ||
765 | * @param key Current key code (unused). | ||
766 | * @param value Value in the hash map (get handle). | ||
767 | * @return #GNUNET_YES if we should continue to iterate, | ||
768 | * #GNUNET_NO if not. | ||
769 | */ | ||
770 | static int | ||
771 | regex_cancel_dht_get (void *cls, | ||
772 | const struct GNUNET_HashCode * key, | ||
773 | void *value) | ||
774 | { | ||
775 | struct GNUNET_DHT_GetHandle *h = value; | ||
776 | |||
777 | GNUNET_DHT_get_stop (h); | ||
778 | return GNUNET_YES; | ||
779 | } | ||
780 | |||
781 | |||
782 | /** | ||
783 | * Iterator over hash map entries to free CadetRegexBlocks stored during the | ||
784 | * search for connect_by_string. | ||
785 | * | ||
786 | * @param cls Closure (unused). | ||
787 | * @param key Current key code (unused). | ||
788 | * @param value CadetRegexBlock in the hash map. | ||
789 | * @return #GNUNET_YES if we should continue to iterate, | ||
790 | * #GNUNET_NO if not. | ||
791 | */ | ||
792 | static int | ||
793 | regex_free_result (void *cls, | ||
794 | const struct GNUNET_HashCode * key, | ||
795 | void *value) | ||
796 | { | ||
797 | GNUNET_free (value); | ||
798 | return GNUNET_YES; | ||
799 | } | ||
800 | |||
801 | |||
802 | /** | ||
803 | * Cancel an ongoing regex search in the DHT and free all resources. | ||
804 | * | ||
805 | * @param h the search context. | ||
806 | */ | ||
807 | void | ||
808 | REGEX_INTERNAL_search_cancel (struct REGEX_INTERNAL_Search *h) | ||
809 | { | ||
810 | unsigned int i; | ||
811 | |||
812 | GNUNET_free (h->description); | ||
813 | GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_handles, | ||
814 | ®ex_cancel_dht_get, NULL); | ||
815 | GNUNET_CONTAINER_multihashmap_iterate (h->dht_get_results, | ||
816 | ®ex_free_result, NULL); | ||
817 | GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_results); | ||
818 | GNUNET_CONTAINER_multihashmap_destroy (h->dht_get_handles); | ||
819 | if (0 < h->n_contexts) | ||
820 | { | ||
821 | for (i = 0; i < h->n_contexts; i++) | ||
822 | GNUNET_free (h->contexts[i]); | ||
823 | GNUNET_free (h->contexts); | ||
824 | } | ||
825 | GNUNET_free (h); | ||
826 | } | ||
827 | |||
828 | |||
829 | /* end of regex_internal_dht.c */ | ||