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.
22 * @file dht/gnunet-service-wdht_datacache.c
23 * @brief GNUnet DHT service's datacache integration
24 * @author Christian Grothoff
25 * @author Nathan Evans
28 #include "gnunet_datacache_lib.h"
29 #include "gnunet-service-wdht_clients.h"
30 #include "gnunet-service-wdht_datacache.h"
31 #include "gnunet-service-wdht_neighbours.h"
32 #include "gnunet-service-dht.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "dht-dtcache",__VA_ARGS__)
37 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
40 * How many "closest" results to we return for migration when
43 #define NUM_CLOSEST 42
46 * Handle to the datacache service (for inserting/retrieving data)
48 static struct GNUNET_DATACACHE_Handle *datacache;
52 * Handle a datum we've received from another peer. Cache if
55 * @param expiration when will the reply expire
56 * @param key the query this reply is for
57 * @param put_path_length number of peers in @a put_path
58 * @param put_path path the reply took on put
59 * @param get_path_length number of peers in @a get_path
60 * @param get_path path the reply took on get
61 * @param type type of the reply
62 * @param data_size number of bytes in @a data
63 * @param data application payload data
66 GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
67 const struct GNUNET_HashCode *key,
68 unsigned int put_path_length,
69 const struct GNUNET_PeerIdentity *put_path,
70 unsigned int get_path_length,
71 const struct GNUNET_PeerIdentity *get_path,
72 enum GNUNET_BLOCK_Type type,
77 struct GNUNET_PeerIdentity path[get_path_length + put_path_length];
79 if (NULL == datacache)
81 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
82 _("PUT request received, but have no datacache!\n"));
85 if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
92 put_path_length * sizeof (struct GNUNET_PeerIdentity));
93 memcpy (&path[put_path_length],
95 get_path_length * sizeof (struct GNUNET_PeerIdentity));
96 /* Put size is actual data size plus struct overhead plus path length (if any) */
97 r = GNUNET_DATACACHE_put (datacache,
103 get_path_length + put_path_length,
106 GNUNET_STATISTICS_update (GDS_stats,
107 gettext_noop ("# ITEMS stored in datacache"), 1,
109 LOG (GNUNET_ERROR_TYPE_DEBUG,
110 "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
114 put_path_length + get_path_length);
119 * Context containing information about a GET request.
121 struct GetRequestContext
124 * extended query (see gnunet_block_lib.h).
129 * Bloomfilter to filter out duplicate replies (updated)
131 struct GNUNET_CONTAINER_BloomFilter **reply_bf;
134 * The key this request was about
136 struct GNUNET_HashCode key;
139 * The trail this request was for
141 const struct GNUNET_HashCode *trail_id;
144 * Number of bytes in @e xquery.
149 * Mutator value for the @e reply_bf, see gnunet_block_lib.h
151 uint32_t reply_bf_mutator;
154 * Return value to give back.
156 enum GNUNET_BLOCK_EvaluationResult eval;
159 * Routing options of the GET.
161 enum GNUNET_DHT_RouteOption options;
167 * Iterator for local get request results,
169 * @param cls closure for iterator, a `struct GetRequestContext`
170 * @param key the key this data is stored under
171 * @param size the size of the data identified by key
172 * @param data the actual data
173 * @param type the type of the data
174 * @param exp when does this value expire?
175 * @param put_path_length number of peers in @a put_path
176 * @param put_path path the reply took on put
177 * @return #GNUNET_OK to continue iteration, anything else
181 datacache_get_iterator (void *cls,
182 const struct GNUNET_HashCode *key,
185 enum GNUNET_BLOCK_Type type,
186 struct GNUNET_TIME_Absolute exp,
187 unsigned int put_path_length,
188 const struct GNUNET_PeerIdentity *put_path)
190 struct GetRequestContext *ctx = cls;
191 enum GNUNET_BLOCK_EvaluationResult eval;
194 GNUNET_BLOCK_evaluate (GDS_block_context,
196 GNUNET_BLOCK_EO_NONE,
199 ctx->reply_bf_mutator,
204 LOG (GNUNET_ERROR_TYPE_DEBUG,
205 "Found reply for query %s in datacache, evaluation result is %d\n",
206 GNUNET_h2s (key), (int) eval);
211 case GNUNET_BLOCK_EVALUATION_OK_MORE:
212 case GNUNET_BLOCK_EVALUATION_OK_LAST:
213 /* forward to local clients */
214 GNUNET_STATISTICS_update (GDS_stats,
216 ("# Good RESULTS found in datacache"), 1,
218 GDS_NEIGHBOURS_send_get_result (ctx->trail_id,
228 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
229 GNUNET_STATISTICS_update (GDS_stats,
231 ("# Duplicate RESULTS found in datacache"), 1,
234 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
235 GNUNET_STATISTICS_update (GDS_stats,
237 ("# Invalid RESULTS found in datacache"), 1,
240 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
241 GNUNET_STATISTICS_update (GDS_stats,
243 ("# Irrelevant RESULTS found in datacache"), 1,
246 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
249 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
251 return GNUNET_SYSERR;
252 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
253 GNUNET_STATISTICS_update (GDS_stats,
255 ("# Unsupported RESULTS found in datacache"), 1,
257 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
258 _("Unsupported block type (%u) in local response!\n"), type);
262 return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
267 * Handle a GET request we've received from another peer.
269 * @param trail_id trail identifying where to send the result to, NULL for us
270 * @param options routing options (to be passed along)
271 * @param key the query
272 * @param type requested data type
273 * @param xquery extended query
274 * @param xquery_size number of bytes in @a xquery
275 * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL
276 * @param reply_bf_mutator mutation value for @a reply_bf
277 * @return evaluation result for the local replies
279 enum GNUNET_BLOCK_EvaluationResult
280 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *trail_id,
281 enum GNUNET_DHT_RouteOption options,
282 const struct GNUNET_HashCode *key,
283 enum GNUNET_BLOCK_Type type,
286 struct GNUNET_CONTAINER_BloomFilter **reply_bf,
287 uint32_t reply_bf_mutator)
289 struct GetRequestContext ctx;
292 if (NULL == datacache)
293 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
294 GNUNET_STATISTICS_update (GDS_stats,
295 gettext_noop ("# GET requests given to datacache"),
297 ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
298 ctx.trail_id = trail_id;
299 ctx.options = options;
302 ctx.xquery_size = xquery_size;
303 ctx.reply_bf = reply_bf;
304 ctx.reply_bf_mutator = reply_bf_mutator;
305 r = GNUNET_DATACACHE_get (datacache,
308 &datacache_get_iterator,
310 DEBUG ("DATACACHE_GET for key %s completed (%d). %u results found.\n",
319 * Function called with a random element from the datacache.
320 * Stores the key in the closure.
322 * @param cls a `struct GNUNET_HashCode *`, where to store the @a key
323 * @param key key for the content
324 * @param data_size number of bytes in @a data
325 * @param data content stored
326 * @param type type of the content
327 * @param exp when will the content expire?
328 * @param path_info_len number of entries in @a path_info
329 * @param path_info a path through the network
330 * @return #GNUNET_OK to continue iterating, #GNUNET_SYSERR to abort
333 datacache_random_iterator (void *cls,
334 const struct GNUNET_HashCode *key,
337 enum GNUNET_BLOCK_Type type,
338 struct GNUNET_TIME_Absolute exp,
339 unsigned int path_info_len,
340 const struct GNUNET_PeerIdentity *path_info)
342 struct GNUNET_HashCode *dest = cls;
345 return GNUNET_OK; /* should actually not matter which we return */
350 * Obtain a random key from the datacache.
351 * Used by Whanau for load-balancing.
353 * @param[out] key where to store the key of a random element,
354 * randomized by PRNG if datacache is empty
355 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the datacache is empty
358 GDS_DATACACHE_get_random_key (struct GNUNET_HashCode *key)
361 GNUNET_DATACACHE_get_random (datacache,
362 &datacache_random_iterator,
365 /* randomize key in this case */
366 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
368 return GNUNET_SYSERR;
375 * Iterator for local get request results,
377 * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
378 * @param key the key this data is stored under
379 * @param size the size of the data identified by key
380 * @param data the actual data
381 * @param type the type of the data
382 * @param exp when does this value expire?
383 * @param put_path_length number of peers in @a put_path
384 * @param put_path path the reply took on put
385 * @return #GNUNET_OK to continue iteration, anything else
389 datacache_get_successors_iterator (void *cls,
390 const struct GNUNET_HashCode *key,
393 enum GNUNET_BLOCK_Type type,
394 struct GNUNET_TIME_Absolute exp,
395 unsigned int put_path_length,
396 const struct GNUNET_PeerIdentity *put_path)
398 const struct GNUNET_HashCode *trail_id = cls;
400 /* NOTE: The datacache currently does not store the RO from
401 the original 'put', so we don't know the 'correct' option
402 at this point anymore. Thus, we conservatively assume
403 that recording is desired (for now). */
404 GDS_NEIGHBOURS_send_get_result (trail_id,
405 GNUNET_DHT_RO_RECORD_ROUTE,
408 put_path_length, put_path,
417 * Handle a request for data close to a key that we have received from
420 * @param trail_id trail where the reply needs to be send to
421 * @param key the location at which the peer is looking for data that is close
424 GDS_DATACACHE_get_successors (const struct GNUNET_HashCode *trail_id,
425 const struct GNUNET_HashCode *key)
427 (void) GNUNET_DATACACHE_get_closest (datacache,
430 &datacache_get_successors_iterator,
436 * Initialize datacache subsystem.
439 GDS_DATACACHE_init ()
441 datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
446 * Shutdown datacache subsystem.
449 GDS_DATACACHE_done ()
451 if (NULL != datacache)
453 GNUNET_DATACACHE_destroy (datacache);
459 /* end of gnunet-service-wdht_datacache.c */