2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2015 GNUnet e.V.
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.
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.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @file dht/gnunet-service-dht_datacache.c
22 * @brief GNUnet DHT service's datacache integration
23 * @author Christian Grothoff
24 * @author Nathan Evans
27 #include "gnunet_datacache_lib.h"
28 #include "gnunet-service-dht_datacache.h"
29 #include "gnunet-service-dht_routing.h"
30 #include "gnunet-service-dht.h"
32 #define LOG(kind,...) GNUNET_log_from (kind, "dht-dhtcache",__VA_ARGS__)
35 * How many "closest" results to we return for migration when
38 #define NUM_CLOSEST 42
41 * Handle to the datacache service (for inserting/retrieving data)
43 static struct GNUNET_DATACACHE_Handle *datacache;
47 * Handle a datum we've received from another peer. Cache if
50 * @param expiration when will the reply expire
51 * @param key the query this reply is for
52 * @param put_path_length number of peers in @a put_path
53 * @param put_path path the reply took on put
54 * @param type type of the reply
55 * @param data_size number of bytes in @a data
56 * @param data application payload data
59 GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
60 const struct GNUNET_HashCode *key,
61 unsigned int put_path_length,
62 const struct GNUNET_PeerIdentity *put_path,
63 enum GNUNET_BLOCK_Type type,
69 if (NULL == datacache)
71 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
72 _("%s request received, but have no datacache!\n"), "PUT");
75 if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
80 /* Put size is actual data size plus struct overhead plus path length (if any) */
81 GNUNET_STATISTICS_update (GDS_stats,
82 gettext_noop ("# ITEMS stored in datacache"), 1,
84 r = GNUNET_DATACACHE_put (datacache,
92 LOG (GNUNET_ERROR_TYPE_DEBUG,
93 "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
102 * Context containing information about a GET request.
104 struct GetRequestContext
107 * extended query (see gnunet_block_lib.h).
112 * Bloomfilter to filter out duplicate replies (updated)
114 struct GNUNET_CONTAINER_BloomFilter **reply_bf;
117 * The key this request was about
119 struct GNUNET_HashCode key;
122 * Number of bytes in xquery.
127 * Mutator value for the @e reply_bf, see gnunet_block_lib.h
129 uint32_t reply_bf_mutator;
132 * Return value to give back.
134 enum GNUNET_BLOCK_EvaluationResult eval;
137 * Function to call on results.
139 GDS_DATACACHE_GetCallback gc;
150 * Iterator for local get request results,
152 * @param cls closure for iterator, a `struct GetRequestContext`
153 * @param exp when does this value expire?
154 * @param key the key this data is stored under
155 * @param data_size the size of the data identified by key
156 * @param data the actual data
157 * @param type the type of the @a data
158 * @param put_path_length number of peers in @a put_path
159 * @param put_path path the reply took on put
160 * @return #GNUNET_OK to continue iteration, anything else
164 datacache_get_iterator (void *cls,
165 const struct GNUNET_HashCode *key,
168 enum GNUNET_BLOCK_Type type,
169 struct GNUNET_TIME_Absolute exp,
170 unsigned int put_path_length,
171 const struct GNUNET_PeerIdentity *put_path)
173 static char non_null;
174 struct GetRequestContext *ctx = cls;
175 enum GNUNET_BLOCK_EvaluationResult eval;
177 if ( (NULL == data) &&
179 data = &non_null; /* point anywhere, but not to NULL */
182 = GNUNET_BLOCK_evaluate (GDS_block_context,
184 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
187 ctx->reply_bf_mutator,
192 LOG (GNUNET_ERROR_TYPE_DEBUG,
193 "Found reply for query %s in datacache, evaluation result is %d\n",
199 case GNUNET_BLOCK_EVALUATION_OK_MORE:
200 case GNUNET_BLOCK_EVALUATION_OK_LAST:
201 /* forward to local clients */
202 GNUNET_STATISTICS_update (GDS_stats,
204 ("# Good RESULTS found in datacache"), 1,
206 ctx->gc (ctx->gc_cls,
210 put_path_length, put_path,
214 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
215 GNUNET_STATISTICS_update (GDS_stats,
216 gettext_noop ("# Duplicate RESULTS found in datacache"),
220 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
221 GNUNET_STATISTICS_update (GDS_stats,
222 gettext_noop ("# Invalid RESULTS found in datacache"),
226 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
227 GNUNET_STATISTICS_update (GDS_stats,
228 gettext_noop ("# Irrelevant RESULTS found in datacache"),
232 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
235 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
237 return GNUNET_SYSERR;
238 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
239 GNUNET_STATISTICS_update (GDS_stats,
240 gettext_noop ("# Unsupported RESULTS found in datacache"),
243 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
244 _("Unsupported block type (%u) in local response!\n"),
248 return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
253 * Handle a GET request we've received from another peer.
255 * @param key the query
256 * @param type requested data type
257 * @param xquery extended query
258 * @param xquery_size number of bytes in @a xquery
259 * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL
260 * @param reply_bf_mutator mutation value for @a reply_bf
261 * @param gc function to call on the results
262 * @param gc_cls closure for @a gc
263 * @return evaluation result for the local replies
265 enum GNUNET_BLOCK_EvaluationResult
266 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
267 enum GNUNET_BLOCK_Type type,
270 struct GNUNET_CONTAINER_BloomFilter **reply_bf,
271 uint32_t reply_bf_mutator,
272 GDS_DATACACHE_GetCallback gc,
275 struct GetRequestContext ctx;
278 if (NULL == datacache)
279 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
280 GNUNET_STATISTICS_update (GDS_stats,
281 gettext_noop ("# GET requests given to datacache"),
284 ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
287 ctx.xquery_size = xquery_size;
288 ctx.reply_bf = reply_bf;
289 ctx.reply_bf_mutator = reply_bf_mutator;
292 r = GNUNET_DATACACHE_get (datacache,
295 &datacache_get_iterator,
297 LOG (GNUNET_ERROR_TYPE_DEBUG,
298 "DATACACHE GET for key %s completed (%d). %u results found.\n",
307 * Function called with a random element from the datacache.
308 * Stores the key in the closure.
310 * @param cls a `struct GNUNET_HashCode *`, where to store the @a key
311 * @param key key for the content
312 * @param data_size number of bytes in @a data
313 * @param data content stored
314 * @param type type of the content
315 * @param exp when will the content expire?
316 * @param path_info_len number of entries in @a path_info
317 * @param path_info a path through the network
318 * @return #GNUNET_OK to continue iterating, #GNUNET_SYSERR to abort
321 datacache_random_iterator (void *cls,
322 const struct GNUNET_HashCode *key,
325 enum GNUNET_BLOCK_Type type,
326 struct GNUNET_TIME_Absolute exp,
327 unsigned int path_info_len,
328 const struct GNUNET_PeerIdentity *path_info)
330 struct GNUNET_HashCode *dest = cls;
333 return GNUNET_OK; /* should actually not matter which we return */
338 * Obtain a random key from the datacache.
339 * Used by Whanau for load-balancing.
341 * @param[out] key where to store the key of a random element,
342 * randomized by PRNG if datacache is empty
343 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the datacache is empty
346 GDS_DATACACHE_get_random_key (struct GNUNET_HashCode *key)
349 GNUNET_DATACACHE_get_random (datacache,
350 &datacache_random_iterator,
353 /* randomize key in this case */
354 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
356 return GNUNET_SYSERR;
363 * Closure for #datacache_get_successors_iterator().
368 * Function to call on the result
370 GDS_DATACACHE_SuccessorCallback cb;
380 * Iterator for local get request results,
382 * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
383 * @param key the key this data is stored under
384 * @param size the size of the data identified by key
385 * @param data the actual data
386 * @param type the type of the data
387 * @param exp when does this value expire?
388 * @param put_path_length number of peers in @a put_path
389 * @param put_path path the reply took on put
390 * @return #GNUNET_OK to continue iteration, anything else
394 datacache_get_successors_iterator (void *cls,
395 const struct GNUNET_HashCode *key,
398 enum GNUNET_BLOCK_Type type,
399 struct GNUNET_TIME_Absolute exp,
400 unsigned int put_path_length,
401 const struct GNUNET_PeerIdentity *put_path)
403 const struct SuccContext *sc = cls;
405 /* NOTE: The datacache currently does not store the RO from
406 the original 'put', so we don't know the 'correct' option
407 at this point anymore. Thus, we conservatively assume
408 that recording is desired (for now). */
410 GNUNET_DHT_RO_RECORD_ROUTE,
413 put_path_length, put_path,
422 * Handle a request for data close to a key that we have received from
425 * @param key the location at which the peer is looking for data that is close
426 * @param cb function to call with the result
427 * @param cb_cls closure for @a cb
430 GDS_DATACACHE_get_successors (const struct GNUNET_HashCode *key,
431 GDS_DATACACHE_SuccessorCallback cb,
434 struct SuccContext sc;
438 (void) GNUNET_DATACACHE_get_closest (datacache,
441 &datacache_get_successors_iterator,
447 * Initialize datacache subsystem.
450 GDS_DATACACHE_init ()
452 datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
457 * Shutdown datacache subsystem.
460 GDS_DATACACHE_done ()
462 if (NULL != datacache)
464 GNUNET_DATACACHE_destroy (datacache);
470 /* end of gnunet-service-dht_datacache.c */