2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2015, 2017 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 * The key this request was about
114 struct GNUNET_HashCode key;
117 * Block group to use to evaluate replies (updated)
119 struct GNUNET_BLOCK_Group *bg;
122 * Function to call on results.
124 GDS_DATACACHE_GetCallback gc;
132 * Number of bytes in xquery.
137 * Return value to give back.
139 enum GNUNET_BLOCK_EvaluationResult eval;
145 * Iterator for local get request results,
147 * @param cls closure for iterator, a `struct GetRequestContext`
148 * @param exp when does this value expire?
149 * @param key the key this data is stored under
150 * @param data_size the size of the data identified by key
151 * @param data the actual data
152 * @param type the type of the @a data
153 * @param put_path_length number of peers in @a put_path
154 * @param put_path path the reply took on put
155 * @return #GNUNET_OK to continue iteration, anything else
159 datacache_get_iterator (void *cls,
160 const struct GNUNET_HashCode *key,
163 enum GNUNET_BLOCK_Type type,
164 struct GNUNET_TIME_Absolute exp,
165 unsigned int put_path_length,
166 const struct GNUNET_PeerIdentity *put_path)
168 static char non_null;
169 struct GetRequestContext *ctx = cls;
170 enum GNUNET_BLOCK_EvaluationResult eval;
172 if ( (NULL == data) &&
174 data = &non_null; /* point anywhere, but not to NULL */
177 = GNUNET_BLOCK_evaluate (GDS_block_context,
180 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
186 LOG (GNUNET_ERROR_TYPE_DEBUG,
187 "Found reply for query %s in datacache, evaluation result is %d\n",
193 case GNUNET_BLOCK_EVALUATION_OK_MORE:
194 case GNUNET_BLOCK_EVALUATION_OK_LAST:
195 /* forward to local clients */
196 GNUNET_STATISTICS_update (GDS_stats,
198 ("# Good RESULTS found in datacache"), 1,
200 ctx->gc (ctx->gc_cls,
204 put_path_length, put_path,
208 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
209 GNUNET_STATISTICS_update (GDS_stats,
210 gettext_noop ("# Duplicate RESULTS found in datacache"),
214 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
215 GNUNET_STATISTICS_update (GDS_stats,
216 gettext_noop ("# Invalid RESULTS found in datacache"),
220 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
221 GNUNET_STATISTICS_update (GDS_stats,
222 gettext_noop ("# Irrelevant RESULTS found in datacache"),
226 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
229 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
231 return GNUNET_SYSERR;
232 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
233 GNUNET_STATISTICS_update (GDS_stats,
234 gettext_noop ("# Unsupported RESULTS found in datacache"),
237 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
238 _("Unsupported block type (%u) in local response!\n"),
242 return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
247 * Handle a GET request we've received from another peer.
249 * @param key the query
250 * @param type requested data type
251 * @param xquery extended query
252 * @param xquery_size number of bytes in @a xquery
253 * @param bg block group to use for reply evaluation
254 * @param gc function to call on the results
255 * @param gc_cls closure for @a gc
256 * @return evaluation result for the local replies
258 enum GNUNET_BLOCK_EvaluationResult
259 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
260 enum GNUNET_BLOCK_Type type,
263 struct GNUNET_BLOCK_Group *bg,
264 GDS_DATACACHE_GetCallback gc,
267 struct GetRequestContext ctx;
270 if (NULL == datacache)
271 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
272 GNUNET_STATISTICS_update (GDS_stats,
273 gettext_noop ("# GET requests given to datacache"),
276 ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
279 ctx.xquery_size = xquery_size;
283 r = GNUNET_DATACACHE_get (datacache,
286 &datacache_get_iterator,
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "DATACACHE GET for key %s completed (%d). %u results found.\n",
298 * Function called with a random element from the datacache.
299 * Stores the key in the closure.
301 * @param cls a `struct GNUNET_HashCode *`, where to store the @a key
302 * @param key key for the content
303 * @param data_size number of bytes in @a data
304 * @param data content stored
305 * @param type type of the content
306 * @param exp when will the content expire?
307 * @param path_info_len number of entries in @a path_info
308 * @param path_info a path through the network
309 * @return #GNUNET_OK to continue iterating, #GNUNET_SYSERR to abort
312 datacache_random_iterator (void *cls,
313 const struct GNUNET_HashCode *key,
316 enum GNUNET_BLOCK_Type type,
317 struct GNUNET_TIME_Absolute exp,
318 unsigned int path_info_len,
319 const struct GNUNET_PeerIdentity *path_info)
321 struct GNUNET_HashCode *dest = cls;
324 return GNUNET_OK; /* should actually not matter which we return */
329 * Obtain a random key from the datacache.
330 * Used by Whanau for load-balancing.
332 * @param[out] key where to store the key of a random element,
333 * randomized by PRNG if datacache is empty
334 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the datacache is empty
337 GDS_DATACACHE_get_random_key (struct GNUNET_HashCode *key)
340 GNUNET_DATACACHE_get_random (datacache,
341 &datacache_random_iterator,
344 /* randomize key in this case */
345 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
347 return GNUNET_SYSERR;
354 * Closure for #datacache_get_successors_iterator().
359 * Function to call on the result
361 GDS_DATACACHE_SuccessorCallback cb;
371 * Iterator for local get request results,
373 * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
374 * @param key the key this data is stored under
375 * @param size the size of the data identified by key
376 * @param data the actual data
377 * @param type the type of the data
378 * @param exp when does this value expire?
379 * @param put_path_length number of peers in @a put_path
380 * @param put_path path the reply took on put
381 * @return #GNUNET_OK to continue iteration, anything else
385 datacache_get_successors_iterator (void *cls,
386 const struct GNUNET_HashCode *key,
389 enum GNUNET_BLOCK_Type type,
390 struct GNUNET_TIME_Absolute exp,
391 unsigned int put_path_length,
392 const struct GNUNET_PeerIdentity *put_path)
394 const struct SuccContext *sc = cls;
396 /* NOTE: The datacache currently does not store the RO from
397 the original 'put', so we don't know the 'correct' option
398 at this point anymore. Thus, we conservatively assume
399 that recording is desired (for now). */
401 GNUNET_DHT_RO_RECORD_ROUTE,
404 put_path_length, put_path,
413 * Handle a request for data close to a key that we have received from
416 * @param key the location at which the peer is looking for data that is close
417 * @param cb function to call with the result
418 * @param cb_cls closure for @a cb
421 GDS_DATACACHE_get_successors (const struct GNUNET_HashCode *key,
422 GDS_DATACACHE_SuccessorCallback cb,
425 struct SuccContext sc;
429 (void) GNUNET_DATACACHE_get_closest (datacache,
432 &datacache_get_successors_iterator,
438 * Initialize datacache subsystem.
441 GDS_DATACACHE_init ()
443 datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
448 * Shutdown datacache subsystem.
451 GDS_DATACACHE_done ()
453 if (NULL != datacache)
455 GNUNET_DATACACHE_destroy (datacache);
461 /* end of gnunet-service-dht_datacache.c */