2
0

regex_internal_dht.c 25 KB

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