gnunet-service-dht_datacache.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 2010, 2011, 2015, 2017 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your 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. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file dht/gnunet-service-dht_datacache.c
  18. * @brief GNUnet DHT service's datacache integration
  19. * @author Christian Grothoff
  20. * @author Nathan Evans
  21. */
  22. #include "platform.h"
  23. #include "gnunet_datacache_lib.h"
  24. #include "gnunet-service-dht_datacache.h"
  25. #include "gnunet-service-dht_neighbours.h"
  26. #include "gnunet-service-dht_routing.h"
  27. #include "gnunet-service-dht.h"
  28. #define LOG(kind, ...) GNUNET_log_from (kind, "dht-dhtcache", __VA_ARGS__)
  29. /**
  30. * How many "closest" results to we return for migration when
  31. * asked (at most)?
  32. */
  33. #define NUM_CLOSEST 42
  34. /**
  35. * Handle to the datacache service (for inserting/retrieving data)
  36. */
  37. static struct GNUNET_DATACACHE_Handle *datacache;
  38. /**
  39. * Handle a datum we've received from another peer. Cache if
  40. * possible.
  41. *
  42. * @param expiration when will the reply expire
  43. * @param key the query this reply is for
  44. * @param put_path_length number of peers in @a put_path
  45. * @param put_path path the reply took on put
  46. * @param type type of the reply
  47. * @param data_size number of bytes in @a data
  48. * @param data application payload data
  49. */
  50. void
  51. GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
  52. const struct GNUNET_HashCode *key,
  53. unsigned int put_path_length,
  54. const struct GNUNET_PeerIdentity *put_path,
  55. enum GNUNET_BLOCK_Type type,
  56. size_t data_size,
  57. const void *data)
  58. {
  59. int r;
  60. if (NULL == datacache)
  61. {
  62. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  63. _ ("%s request received, but have no datacache!\n"), "PUT");
  64. return;
  65. }
  66. if (data_size >= GNUNET_MAX_MESSAGE_SIZE)
  67. {
  68. GNUNET_break (0);
  69. return;
  70. }
  71. /* Put size is actual data size plus struct overhead plus path length (if any) */
  72. GNUNET_STATISTICS_update (GDS_stats,
  73. gettext_noop ("# ITEMS stored in datacache"),
  74. 1,
  75. GNUNET_NO);
  76. r = GNUNET_DATACACHE_put (datacache,
  77. key,
  78. GNUNET_CRYPTO_hash_matching_bits (key,
  79. &my_identity_hash),
  80. data_size,
  81. data,
  82. type,
  83. expiration,
  84. put_path_length,
  85. put_path);
  86. LOG (GNUNET_ERROR_TYPE_DEBUG,
  87. "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
  88. GNUNET_h2s (key),
  89. data_size,
  90. r,
  91. put_path_length);
  92. }
  93. /**
  94. * Context containing information about a GET request.
  95. */
  96. struct GetRequestContext
  97. {
  98. /**
  99. * extended query (see gnunet_block_lib.h).
  100. */
  101. const void *xquery;
  102. /**
  103. * The key this request was about
  104. */
  105. struct GNUNET_HashCode key;
  106. /**
  107. * Block group to use to evaluate replies (updated)
  108. */
  109. struct GNUNET_BLOCK_Group *bg;
  110. /**
  111. * Function to call on results.
  112. */
  113. GDS_DATACACHE_GetCallback gc;
  114. /**
  115. * Closure for @e gc.
  116. */
  117. void *gc_cls;
  118. /**
  119. * Number of bytes in xquery.
  120. */
  121. size_t xquery_size;
  122. /**
  123. * Return value to give back.
  124. */
  125. enum GNUNET_BLOCK_EvaluationResult eval;
  126. };
  127. /**
  128. * Iterator for local get request results,
  129. *
  130. * @param cls closure for iterator, a `struct GetRequestContext`
  131. * @param exp when does this value expire?
  132. * @param key the key this data is stored under
  133. * @param data_size the size of the data identified by key
  134. * @param data the actual data
  135. * @param type the type of the @a data
  136. * @param put_path_length number of peers in @a put_path
  137. * @param put_path path the reply took on put
  138. * @return #GNUNET_OK to continue iteration, anything else
  139. * to stop iteration.
  140. */
  141. static int
  142. datacache_get_iterator (void *cls,
  143. const struct GNUNET_HashCode *key,
  144. size_t data_size,
  145. const char *data,
  146. enum GNUNET_BLOCK_Type type,
  147. struct GNUNET_TIME_Absolute exp,
  148. unsigned int put_path_length,
  149. const struct GNUNET_PeerIdentity *put_path)
  150. {
  151. static char non_null;
  152. struct GetRequestContext *ctx = cls;
  153. enum GNUNET_BLOCK_EvaluationResult eval;
  154. if (0 == GNUNET_TIME_absolute_get_remaining (exp).rel_value_us)
  155. {
  156. GNUNET_break (0); /* why does datacache return expired values? */
  157. return GNUNET_OK; /* skip expired record */
  158. }
  159. if ((NULL == data) &&
  160. (0 == data_size))
  161. data = &non_null; /* point anywhere, but not to NULL */
  162. eval
  163. = GNUNET_BLOCK_evaluate (GDS_block_context,
  164. type,
  165. ctx->bg,
  166. GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
  167. key,
  168. ctx->xquery,
  169. ctx->xquery_size,
  170. data,
  171. data_size);
  172. LOG (GNUNET_ERROR_TYPE_DEBUG,
  173. "Found reply for query %s in datacache, evaluation result is %d\n",
  174. GNUNET_h2s (key),
  175. (int) eval);
  176. ctx->eval = eval;
  177. switch (eval)
  178. {
  179. case GNUNET_BLOCK_EVALUATION_OK_MORE:
  180. case GNUNET_BLOCK_EVALUATION_OK_LAST:
  181. /* forward to local clients */
  182. GNUNET_STATISTICS_update (GDS_stats,
  183. gettext_noop
  184. ("# Good RESULTS found in datacache"), 1,
  185. GNUNET_NO);
  186. ctx->gc (ctx->gc_cls,
  187. type,
  188. exp,
  189. key,
  190. put_path_length, put_path,
  191. 0, NULL,
  192. data, data_size);
  193. break;
  194. case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
  195. GNUNET_STATISTICS_update (GDS_stats,
  196. gettext_noop (
  197. "# Duplicate RESULTS found in datacache"),
  198. 1,
  199. GNUNET_NO);
  200. break;
  201. case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
  202. GNUNET_STATISTICS_update (GDS_stats,
  203. gettext_noop (
  204. "# Invalid RESULTS found in datacache"),
  205. 1,
  206. GNUNET_NO);
  207. break;
  208. case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
  209. GNUNET_STATISTICS_update (GDS_stats,
  210. gettext_noop (
  211. "# Irrelevant RESULTS found in datacache"),
  212. 1,
  213. GNUNET_NO);
  214. break;
  215. case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
  216. GNUNET_break (0);
  217. break;
  218. case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
  219. GNUNET_break_op (0);
  220. return GNUNET_SYSERR;
  221. case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
  222. GNUNET_STATISTICS_update (GDS_stats,
  223. gettext_noop (
  224. "# Unsupported RESULTS found in datacache"),
  225. 1,
  226. GNUNET_NO);
  227. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  228. _ ("Unsupported block type (%u) in local response!\n"),
  229. type);
  230. break;
  231. }
  232. return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
  233. }
  234. /**
  235. * Handle a GET request we've received from another peer.
  236. *
  237. * @param key the query
  238. * @param type requested data type
  239. * @param xquery extended query
  240. * @param xquery_size number of bytes in @a xquery
  241. * @param bg block group to use for reply evaluation
  242. * @param gc function to call on the results
  243. * @param gc_cls closure for @a gc
  244. * @return evaluation result for the local replies
  245. */
  246. enum GNUNET_BLOCK_EvaluationResult
  247. GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
  248. enum GNUNET_BLOCK_Type type,
  249. const void *xquery,
  250. size_t xquery_size,
  251. struct GNUNET_BLOCK_Group *bg,
  252. GDS_DATACACHE_GetCallback gc,
  253. void *gc_cls)
  254. {
  255. struct GetRequestContext ctx;
  256. unsigned int r;
  257. if (NULL == datacache)
  258. return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
  259. GNUNET_STATISTICS_update (GDS_stats,
  260. gettext_noop ("# GET requests given to datacache"),
  261. 1,
  262. GNUNET_NO);
  263. ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
  264. ctx.key = *key;
  265. ctx.xquery = xquery;
  266. ctx.xquery_size = xquery_size;
  267. ctx.bg = bg;
  268. ctx.gc = gc;
  269. ctx.gc_cls = gc_cls;
  270. r = GNUNET_DATACACHE_get (datacache,
  271. key,
  272. type,
  273. &datacache_get_iterator,
  274. &ctx);
  275. LOG (GNUNET_ERROR_TYPE_DEBUG,
  276. "DATACACHE GET for key %s completed (%d). %u results found.\n",
  277. GNUNET_h2s (key),
  278. ctx.eval,
  279. r);
  280. return ctx.eval;
  281. }
  282. /**
  283. * Function called with a random element from the datacache.
  284. * Stores the key in the closure.
  285. *
  286. * @param cls a `struct GNUNET_HashCode *`, where to store the @a key
  287. * @param key key for the content
  288. * @param data_size number of bytes in @a data
  289. * @param data content stored
  290. * @param type type of the content
  291. * @param exp when will the content expire?
  292. * @param path_info_len number of entries in @a path_info
  293. * @param path_info a path through the network
  294. * @return #GNUNET_OK to continue iterating, #GNUNET_SYSERR to abort
  295. */
  296. static int
  297. datacache_random_iterator (void *cls,
  298. const struct GNUNET_HashCode *key,
  299. size_t data_size,
  300. const char *data,
  301. enum GNUNET_BLOCK_Type type,
  302. struct GNUNET_TIME_Absolute exp,
  303. unsigned int path_info_len,
  304. const struct GNUNET_PeerIdentity *path_info)
  305. {
  306. struct GNUNET_HashCode *dest = cls;
  307. *dest = *key;
  308. return GNUNET_OK; /* should actually not matter which we return */
  309. }
  310. /**
  311. * Obtain a random key from the datacache.
  312. * Used by Whanau for load-balancing.
  313. *
  314. * @param[out] key where to store the key of a random element,
  315. * randomized by PRNG if datacache is empty
  316. * @return #GNUNET_OK on success, #GNUNET_SYSERR if the datacache is empty
  317. */
  318. int
  319. GDS_DATACACHE_get_random_key (struct GNUNET_HashCode *key)
  320. {
  321. if (0 ==
  322. GNUNET_DATACACHE_get_random (datacache,
  323. &datacache_random_iterator,
  324. key))
  325. {
  326. /* randomize key in this case */
  327. GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
  328. key);
  329. return GNUNET_SYSERR;
  330. }
  331. return GNUNET_OK;
  332. }
  333. /**
  334. * Closure for #datacache_get_successors_iterator().
  335. */
  336. struct SuccContext
  337. {
  338. /**
  339. * Function to call on the result
  340. */
  341. GDS_DATACACHE_SuccessorCallback cb;
  342. /**
  343. * Closure for @e cb.
  344. */
  345. void *cb_cls;
  346. };
  347. /**
  348. * Iterator for local get request results,
  349. *
  350. * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
  351. * @param key the key this data is stored under
  352. * @param size the size of the data identified by key
  353. * @param data the actual data
  354. * @param type the type of the data
  355. * @param exp when does this value expire?
  356. * @param put_path_length number of peers in @a put_path
  357. * @param put_path path the reply took on put
  358. * @return #GNUNET_OK to continue iteration, anything else
  359. * to stop iteration.
  360. */
  361. static int
  362. datacache_get_successors_iterator (void *cls,
  363. const struct GNUNET_HashCode *key,
  364. size_t size,
  365. const char *data,
  366. enum GNUNET_BLOCK_Type type,
  367. struct GNUNET_TIME_Absolute exp,
  368. unsigned int put_path_length,
  369. const struct GNUNET_PeerIdentity *put_path)
  370. {
  371. const struct SuccContext *sc = cls;
  372. /* NOTE: The datacache currently does not store the RO from
  373. the original 'put', so we don't know the 'correct' option
  374. at this point anymore. Thus, we conservatively assume
  375. that recording is desired (for now). */
  376. sc->cb (sc->cb_cls,
  377. GNUNET_DHT_RO_RECORD_ROUTE,
  378. key,
  379. type,
  380. put_path_length, put_path,
  381. exp,
  382. data,
  383. size);
  384. return GNUNET_OK;
  385. }
  386. /**
  387. * Handle a request for data close to a key that we have received from
  388. * another peer.
  389. *
  390. * @param key the location at which the peer is looking for data that is close
  391. * @param cb function to call with the result
  392. * @param cb_cls closure for @a cb
  393. */
  394. void
  395. GDS_DATACACHE_get_successors (const struct GNUNET_HashCode *key,
  396. GDS_DATACACHE_SuccessorCallback cb,
  397. void *cb_cls)
  398. {
  399. struct SuccContext sc;
  400. sc.cb = cb;
  401. sc.cb_cls = cb_cls;
  402. (void) GNUNET_DATACACHE_get_closest (datacache,
  403. key,
  404. NUM_CLOSEST,
  405. &datacache_get_successors_iterator,
  406. &sc);
  407. }
  408. /**
  409. * Initialize datacache subsystem.
  410. */
  411. void
  412. GDS_DATACACHE_init ()
  413. {
  414. datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
  415. }
  416. /**
  417. * Shutdown datacache subsystem.
  418. */
  419. void
  420. GDS_DATACACHE_done ()
  421. {
  422. if (NULL != datacache)
  423. {
  424. GNUNET_DATACACHE_destroy (datacache);
  425. datacache = NULL;
  426. }
  427. }
  428. /* end of gnunet-service-dht_datacache.c */