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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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_neighbours.h"
30 #include "gnunet-service-dht_routing.h"
31 #include "gnunet-service-dht.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "dht-dhtcache",__VA_ARGS__)
36 * How many "closest" results to we return for migration when
39 #define NUM_CLOSEST 42
42 * Handle to the datacache service (for inserting/retrieving data)
44 static struct GNUNET_DATACACHE_Handle *datacache;
48 * Handle a datum we've received from another peer. Cache if
51 * @param expiration when will the reply expire
52 * @param key the query this reply is for
53 * @param put_path_length number of peers in @a put_path
54 * @param put_path path the reply took on put
55 * @param type type of the reply
56 * @param data_size number of bytes in @a data
57 * @param data application payload data
60 GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
61 const struct GNUNET_HashCode *key,
62 unsigned int put_path_length,
63 const struct GNUNET_PeerIdentity *put_path,
64 enum GNUNET_BLOCK_Type type,
70 if (NULL == datacache)
72 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
73 _("%s request received, but have no datacache!\n"), "PUT");
76 if (data_size >= GNUNET_MAX_MESSAGE_SIZE)
81 /* Put size is actual data size plus struct overhead plus path length (if any) */
82 GNUNET_STATISTICS_update (GDS_stats,
83 gettext_noop ("# ITEMS stored in datacache"),
86 r = GNUNET_DATACACHE_put (datacache,
88 GNUNET_CRYPTO_hash_matching_bits (key,
96 LOG (GNUNET_ERROR_TYPE_DEBUG,
97 "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
106 * Context containing information about a GET request.
108 struct GetRequestContext
111 * extended query (see gnunet_block_lib.h).
116 * The key this request was about
118 struct GNUNET_HashCode key;
121 * Block group to use to evaluate replies (updated)
123 struct GNUNET_BLOCK_Group *bg;
126 * Function to call on results.
128 GDS_DATACACHE_GetCallback gc;
136 * Number of bytes in xquery.
141 * Return value to give back.
143 enum GNUNET_BLOCK_EvaluationResult eval;
149 * Iterator for local get request results,
151 * @param cls closure for iterator, a `struct GetRequestContext`
152 * @param exp when does this value expire?
153 * @param key the key this data is stored under
154 * @param data_size the size of the data identified by key
155 * @param data the actual data
156 * @param type the type of the @a data
157 * @param put_path_length number of peers in @a put_path
158 * @param put_path path the reply took on put
159 * @return #GNUNET_OK to continue iteration, anything else
163 datacache_get_iterator (void *cls,
164 const struct GNUNET_HashCode *key,
167 enum GNUNET_BLOCK_Type type,
168 struct GNUNET_TIME_Absolute exp,
169 unsigned int put_path_length,
170 const struct GNUNET_PeerIdentity *put_path)
172 static char non_null;
173 struct GetRequestContext *ctx = cls;
174 enum GNUNET_BLOCK_EvaluationResult eval;
176 if (0 == GNUNET_TIME_absolute_get_remaining (exp).rel_value_us)
178 GNUNET_break (0); /* why does datacache return expired values? */
179 return GNUNET_OK; /* skip expired record */
181 if ( (NULL == data) &&
183 data = &non_null; /* point anywhere, but not to NULL */
186 = GNUNET_BLOCK_evaluate (GDS_block_context,
189 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
195 LOG (GNUNET_ERROR_TYPE_DEBUG,
196 "Found reply for query %s in datacache, evaluation result is %d\n",
202 case GNUNET_BLOCK_EVALUATION_OK_MORE:
203 case GNUNET_BLOCK_EVALUATION_OK_LAST:
204 /* forward to local clients */
205 GNUNET_STATISTICS_update (GDS_stats,
207 ("# Good RESULTS found in datacache"), 1,
209 ctx->gc (ctx->gc_cls,
213 put_path_length, put_path,
217 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
218 GNUNET_STATISTICS_update (GDS_stats,
219 gettext_noop ("# Duplicate RESULTS found in datacache"),
223 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
224 GNUNET_STATISTICS_update (GDS_stats,
225 gettext_noop ("# Invalid RESULTS found in datacache"),
229 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
230 GNUNET_STATISTICS_update (GDS_stats,
231 gettext_noop ("# Irrelevant RESULTS found in datacache"),
235 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
238 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
240 return GNUNET_SYSERR;
241 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
242 GNUNET_STATISTICS_update (GDS_stats,
243 gettext_noop ("# Unsupported RESULTS found in datacache"),
246 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
247 _("Unsupported block type (%u) in local response!\n"),
251 return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
256 * Handle a GET request we've received from another peer.
258 * @param key the query
259 * @param type requested data type
260 * @param xquery extended query
261 * @param xquery_size number of bytes in @a xquery
262 * @param bg block group to use for reply evaluation
263 * @param gc function to call on the results
264 * @param gc_cls closure for @a gc
265 * @return evaluation result for the local replies
267 enum GNUNET_BLOCK_EvaluationResult
268 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
269 enum GNUNET_BLOCK_Type type,
272 struct GNUNET_BLOCK_Group *bg,
273 GDS_DATACACHE_GetCallback gc,
276 struct GetRequestContext ctx;
279 if (NULL == datacache)
280 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
281 GNUNET_STATISTICS_update (GDS_stats,
282 gettext_noop ("# GET requests given to datacache"),
285 ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
288 ctx.xquery_size = xquery_size;
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 */