regex_block_lib.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2012,2013 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. * @author Bartlomiej Polot
  19. * @file regex/regex_block_lib.c
  20. * @brief functions for manipulating non-accept blocks stored for
  21. * regex in the DHT
  22. */
  23. #include "platform.h"
  24. #include "regex_block_lib.h"
  25. #include "gnunet_constants.h"
  26. #define LOG(kind,...) GNUNET_log_from (kind,"regex-bck",__VA_ARGS__)
  27. GNUNET_NETWORK_STRUCT_BEGIN
  28. /**
  29. * Information for each edge.
  30. */
  31. struct EdgeInfo
  32. {
  33. /**
  34. * Index of the destination of this edge in the
  35. * unique destinations array.
  36. */
  37. uint16_t destination_index GNUNET_PACKED;
  38. /**
  39. * Number of bytes the token for this edge takes in the
  40. * token area.
  41. */
  42. uint16_t token_length GNUNET_PACKED;
  43. };
  44. /**
  45. * @brief Block to announce a regex state.
  46. */
  47. struct RegexBlock
  48. {
  49. /**
  50. * Length of the proof regex string.
  51. */
  52. uint16_t proof_len GNUNET_PACKED;
  53. /**
  54. * Is this state an accepting state?
  55. */
  56. int16_t is_accepting GNUNET_PACKED;
  57. /**
  58. * Number of edges parting from this state.
  59. */
  60. uint16_t num_edges GNUNET_PACKED;
  61. /**
  62. * Nubmer of unique destinations reachable from this state.
  63. */
  64. uint16_t num_destinations GNUNET_PACKED;
  65. /* followed by 'struct GNUNET_HashCode[num_destinations]' */
  66. /* followed by 'struct EdgeInfo[edge_destination_indices]' */
  67. /* followed by 'char proof[n_proof]', NOT 0-terminated */
  68. /* followed by 'char tokens[num_edges][edge_info[k].token_length]';
  69. essentially all of the tokens one after the other in the
  70. order of the edges; tokens are NOT 0-terminated */
  71. };
  72. GNUNET_NETWORK_STRUCT_END
  73. /**
  74. * Test if this block is marked as being an accept state.
  75. *
  76. * @param block block to test
  77. * @param size number of bytes in block
  78. * @return #GNUNET_YES if the block is accepting, #GNUNET_NO if not
  79. */
  80. int
  81. GNUNET_BLOCK_is_accepting (const struct RegexBlock *block,
  82. size_t size)
  83. {
  84. if (size < sizeof (struct RegexBlock))
  85. {
  86. GNUNET_break_op (0);
  87. return GNUNET_SYSERR;
  88. }
  89. return ntohs (block->is_accepting);
  90. }
  91. /**
  92. * Check if the given 'proof' matches the given 'key'.
  93. *
  94. * @param proof partial regex of a state
  95. * @param proof_len number of bytes in 'proof'
  96. * @param key hash of a state.
  97. * @return #GNUNET_OK if the proof is valid for the given key.
  98. */
  99. int
  100. REGEX_BLOCK_check_proof (const char *proof,
  101. size_t proof_len,
  102. const struct GNUNET_HashCode *key)
  103. {
  104. struct GNUNET_HashCode key_check;
  105. if ( (NULL == proof) || (NULL == key))
  106. {
  107. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Proof check failed, was NULL.\n");
  108. return GNUNET_NO;
  109. }
  110. GNUNET_CRYPTO_hash (proof, proof_len, &key_check);
  111. return (0 ==
  112. GNUNET_CRYPTO_hash_cmp (key, &key_check)) ? GNUNET_OK : GNUNET_NO;
  113. }
  114. /**
  115. * Struct to keep track of the xquery while iterating all the edges in a block.
  116. */
  117. struct CheckEdgeContext
  118. {
  119. /**
  120. * Xquery: string we are looking for.
  121. */
  122. const char *xquery;
  123. /**
  124. * Has any edge matched the xquery so far? (GNUNET_OK / GNUNET_NO)
  125. */
  126. int found;
  127. };
  128. /**
  129. * Iterator over all edges in a block, checking for a presence of a given query.
  130. *
  131. * @param cls Closure, (xquery context).
  132. * @param token Token that follows to next state.
  133. * @param len Lenght of token.
  134. * @param key Hash of next state.
  135. *
  136. * @return GNUNET_YES, to keep iterating
  137. */
  138. static int
  139. check_edge (void *cls,
  140. const char *token,
  141. size_t len,
  142. const struct GNUNET_HashCode *key)
  143. {
  144. struct CheckEdgeContext *ctx = cls;
  145. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  146. "edge %.*s [%u]: %s->%s\n",
  147. (int) len, token, len, GNUNET_h2s(key));
  148. if (NULL == ctx->xquery)
  149. return GNUNET_YES;
  150. if (strlen (ctx->xquery) < len)
  151. return GNUNET_YES; /* too long */
  152. if (0 == strncmp (ctx->xquery, token, len))
  153. ctx->found = GNUNET_OK;
  154. return GNUNET_YES; /* keep checking for malformed data! */
  155. }
  156. /**
  157. * Check if the regex block is well formed, including all edges.
  158. *
  159. * @param block The start of the block.
  160. * @param size The size of the block.
  161. * @param query the query for the block
  162. * @param xquery String describing the edge we are looking for.
  163. * Can be NULL in case this is a put block.
  164. * @return #GNUNET_OK in case it's fine.
  165. * #GNUNET_NO in case the xquery exists and is not found (IRRELEVANT).
  166. * #GNUNET_SYSERR if the block is invalid.
  167. */
  168. int
  169. REGEX_BLOCK_check (const struct RegexBlock *block,
  170. size_t size,
  171. const struct GNUNET_HashCode *query,
  172. const char *xquery)
  173. {
  174. struct GNUNET_HashCode key;
  175. struct CheckEdgeContext ctx;
  176. int res;
  177. LOG (GNUNET_ERROR_TYPE_DEBUG, "Block check\n");
  178. if (GNUNET_OK !=
  179. REGEX_BLOCK_get_key (block, size,
  180. &key))
  181. {
  182. GNUNET_break_op (0);
  183. return GNUNET_SYSERR;
  184. }
  185. if (NULL != query &&
  186. 0 != memcmp (&key,
  187. query,
  188. sizeof (struct GNUNET_HashCode)))
  189. {
  190. GNUNET_break_op (0);
  191. return GNUNET_SYSERR;
  192. }
  193. if ( (GNUNET_YES == ntohs (block->is_accepting)) &&
  194. ( (NULL == xquery) || ('\0' == xquery[0]) ) )
  195. {
  196. LOG (GNUNET_ERROR_TYPE_DEBUG,
  197. " out! Is accepting: %u, xquery %p\n",
  198. ntohs(block->is_accepting), xquery);
  199. return GNUNET_OK;
  200. }
  201. ctx.xquery = xquery;
  202. ctx.found = GNUNET_NO;
  203. res = REGEX_BLOCK_iterate (block, size, &check_edge, &ctx);
  204. if (GNUNET_SYSERR == res)
  205. return GNUNET_SYSERR;
  206. if (NULL == xquery)
  207. return GNUNET_YES;
  208. LOG (GNUNET_ERROR_TYPE_DEBUG, "Result %d\n", ctx.found);
  209. return ctx.found;
  210. }
  211. /**
  212. * Obtain the key that a particular block is to be stored under.
  213. *
  214. * @param block block to get the key from
  215. * @param block_len number of bytes in block
  216. * @param key where to store the key
  217. * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block is malformed
  218. */
  219. int
  220. REGEX_BLOCK_get_key (const struct RegexBlock *block,
  221. size_t block_len,
  222. struct GNUNET_HashCode *key)
  223. {
  224. uint16_t len;
  225. const struct GNUNET_HashCode *destinations;
  226. const struct EdgeInfo *edges;
  227. uint16_t num_destinations;
  228. uint16_t num_edges;
  229. size_t total;
  230. if (block_len < sizeof (struct RegexBlock))
  231. {
  232. GNUNET_break_op (0);
  233. return GNUNET_SYSERR;
  234. }
  235. num_destinations = ntohs (block->num_destinations);
  236. num_edges = ntohs (block->num_edges);
  237. len = ntohs (block->proof_len);
  238. destinations = (const struct GNUNET_HashCode *) &block[1];
  239. edges = (const struct EdgeInfo *) &destinations[num_destinations];
  240. total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges * sizeof (struct EdgeInfo) + len;
  241. if (block_len < total)
  242. {
  243. GNUNET_break_op (0);
  244. return GNUNET_SYSERR;
  245. }
  246. GNUNET_CRYPTO_hash (&edges[num_edges], len, key);
  247. return GNUNET_OK;
  248. }
  249. /**
  250. * Iterate over all edges of a block of a regex state.
  251. *
  252. * @param block Block to iterate over.
  253. * @param size Size of @a block.
  254. * @param iterator Function to call on each edge in the block.
  255. * @param iter_cls Closure for the @a iterator.
  256. * @return #GNUNET_SYSERR if an error has been encountered.
  257. * #GNUNET_OK if no error has been encountered.
  258. * Note that if the iterator stops the iteration by returning
  259. * #GNUNET_NO, the block will no longer be checked for further errors.
  260. * The return value will be GNUNET_OK meaning that no errors were
  261. * found until the edge last notified to the iterator, but there might
  262. * be errors in further edges.
  263. */
  264. int
  265. REGEX_BLOCK_iterate (const struct RegexBlock *block,
  266. size_t size,
  267. REGEX_INTERNAL_EgdeIterator iterator,
  268. void *iter_cls)
  269. {
  270. uint16_t len;
  271. const struct GNUNET_HashCode *destinations;
  272. const struct EdgeInfo *edges;
  273. const char *aux;
  274. uint16_t num_destinations;
  275. uint16_t num_edges;
  276. size_t total;
  277. unsigned int n;
  278. size_t off;
  279. LOG (GNUNET_ERROR_TYPE_DEBUG, "Block iterate\n");
  280. if (size < sizeof (struct RegexBlock))
  281. {
  282. GNUNET_break_op (0);
  283. return GNUNET_SYSERR;
  284. }
  285. num_destinations = ntohs (block->num_destinations);
  286. num_edges = ntohs (block->num_edges);
  287. len = ntohs (block->proof_len);
  288. destinations = (const struct GNUNET_HashCode *) &block[1];
  289. edges = (const struct EdgeInfo *) &destinations[num_destinations];
  290. aux = (const char *) &edges[num_edges];
  291. total = sizeof (struct RegexBlock) + num_destinations * sizeof (struct GNUNET_HashCode) + num_edges * sizeof (struct EdgeInfo) + len;
  292. if (size < total)
  293. {
  294. GNUNET_break_op (0);
  295. return GNUNET_SYSERR;
  296. }
  297. for (n=0;n<num_edges;n++)
  298. total += ntohs (edges[n].token_length);
  299. if (size != total)
  300. {
  301. fprintf (stderr, "Expected %u, got %u\n",
  302. (unsigned int) size,
  303. (unsigned int) total);
  304. GNUNET_break_op (0);
  305. return GNUNET_SYSERR;
  306. }
  307. off = len;
  308. LOG (GNUNET_ERROR_TYPE_DEBUG,
  309. "Start iterating block of size %u, proof %u, off %u edges %u\n",
  310. size, len, off, n);
  311. /* &aux[off] always points to our token */
  312. for (n=0;n<num_edges;n++)
  313. {
  314. LOG (GNUNET_ERROR_TYPE_DEBUG,
  315. "Edge %u/%u, off %u tokenlen %u (%.*s)\n",
  316. n+1, num_edges, off,
  317. ntohs (edges[n].token_length), ntohs (edges[n].token_length),
  318. &aux[off]);
  319. if (NULL != iterator)
  320. if (GNUNET_NO == iterator (iter_cls,
  321. &aux[off],
  322. ntohs (edges[n].token_length),
  323. &destinations[ntohs (edges[n].destination_index)]))
  324. return GNUNET_OK;
  325. off += ntohs (edges[n].token_length);
  326. }
  327. return GNUNET_OK;
  328. }
  329. /**
  330. * Construct a regex block to be stored in the DHT.
  331. *
  332. * @param proof proof string for the block
  333. * @param num_edges number of edges in the block
  334. * @param edges the edges of the block
  335. * @param accepting is this an accepting state
  336. * @param rsize set to the size of the returned block (OUT-only)
  337. * @return the regex block, NULL on error
  338. */
  339. struct RegexBlock *
  340. REGEX_BLOCK_create (const char *proof,
  341. unsigned int num_edges,
  342. const struct REGEX_BLOCK_Edge *edges,
  343. int accepting,
  344. size_t *rsize)
  345. {
  346. struct RegexBlock *block;
  347. struct GNUNET_HashCode destinations[1024]; /* 1024 = 64k/64 bytes/key == absolute MAX */
  348. uint16_t destination_indices[num_edges];
  349. struct GNUNET_HashCode *dests;
  350. struct EdgeInfo *edgeinfos;
  351. size_t off;
  352. size_t len;
  353. size_t total;
  354. size_t slen;
  355. unsigned int unique_destinations;
  356. unsigned int j;
  357. unsigned int i;
  358. char *aux;
  359. len = strlen (proof);
  360. if (len > UINT16_MAX)
  361. {
  362. GNUNET_break (0);
  363. return NULL;
  364. }
  365. unique_destinations = 0;
  366. total = sizeof (struct RegexBlock) + len;
  367. for (i=0;i<num_edges;i++)
  368. {
  369. slen = strlen (edges[i].label);
  370. if (slen > UINT16_MAX)
  371. {
  372. GNUNET_break (0);
  373. return NULL;
  374. }
  375. total += slen;
  376. for (j=0;j<unique_destinations;j++)
  377. if (0 == memcmp (&destinations[j],
  378. &edges[i].destination,
  379. sizeof (struct GNUNET_HashCode)))
  380. break;
  381. if (j >= 1024)
  382. {
  383. GNUNET_break (0);
  384. return NULL;
  385. }
  386. destination_indices[i] = j;
  387. if (j == unique_destinations)
  388. destinations[unique_destinations++] = edges[i].destination;
  389. }
  390. total += num_edges * sizeof (struct EdgeInfo) + unique_destinations * sizeof (struct GNUNET_HashCode);
  391. if (total >= GNUNET_CONSTANTS_MAX_BLOCK_SIZE)
  392. {
  393. GNUNET_break (0);
  394. return NULL;
  395. }
  396. block = GNUNET_malloc (total);
  397. block->proof_len = htons (len);
  398. block->is_accepting = htons (accepting);
  399. block->num_edges = htons (num_edges);
  400. block->num_destinations = htons (unique_destinations);
  401. dests = (struct GNUNET_HashCode *) &block[1];
  402. memcpy (dests, destinations, sizeof (struct GNUNET_HashCode) * unique_destinations);
  403. edgeinfos = (struct EdgeInfo *) &dests[unique_destinations];
  404. aux = (char *) &edgeinfos[num_edges];
  405. off = len;
  406. memcpy (aux, proof, len);
  407. for (i=0;i<num_edges;i++)
  408. {
  409. slen = strlen (edges[i].label);
  410. edgeinfos[i].token_length = htons ((uint16_t) slen);
  411. edgeinfos[i].destination_index = htons (destination_indices[i]);
  412. memcpy (&aux[off],
  413. edges[i].label,
  414. slen);
  415. off += slen;
  416. }
  417. *rsize = total;
  418. return block;
  419. }
  420. /* end of regex_block_lib.c */