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/>.
19 * @file dht/gnunet-service-dht_datacache.c
20 * @brief GNUnet DHT service's datacache integration
21 * @author Christian Grothoff
22 * @author Nathan Evans
25 #include "gnunet_datacache_lib.h"
26 #include "gnunet-service-dht_datacache.h"
27 #include "gnunet-service-dht_neighbours.h"
28 #include "gnunet-service-dht_routing.h"
29 #include "gnunet-service-dht.h"
31 #define LOG(kind,...) GNUNET_log_from (kind, "dht-dhtcache",__VA_ARGS__)
34 * How many "closest" results to we return for migration when
37 #define NUM_CLOSEST 42
40 * Handle to the datacache service (for inserting/retrieving data)
42 static struct GNUNET_DATACACHE_Handle *datacache;
46 * Handle a datum we've received from another peer. Cache if
49 * @param expiration when will the reply expire
50 * @param key the query this reply is for
51 * @param put_path_length number of peers in @a put_path
52 * @param put_path path the reply took on put
53 * @param type type of the reply
54 * @param data_size number of bytes in @a data
55 * @param data application payload data
58 GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
59 const struct GNUNET_HashCode *key,
60 unsigned int put_path_length,
61 const struct GNUNET_PeerIdentity *put_path,
62 enum GNUNET_BLOCK_Type type,
68 if (NULL == datacache)
70 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
71 _("%s request received, but have no datacache!\n"), "PUT");
74 if (data_size >= GNUNET_MAX_MESSAGE_SIZE)
79 /* Put size is actual data size plus struct overhead plus path length (if any) */
80 GNUNET_STATISTICS_update (GDS_stats,
81 gettext_noop ("# ITEMS stored in datacache"),
84 r = GNUNET_DATACACHE_put (datacache,
86 GNUNET_CRYPTO_hash_matching_bits (key,
94 LOG (GNUNET_ERROR_TYPE_DEBUG,
95 "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
104 * Context containing information about a GET request.
106 struct GetRequestContext
109 * extended query (see gnunet_block_lib.h).
114 * The key this request was about
116 struct GNUNET_HashCode key;
119 * Block group to use to evaluate replies (updated)
121 struct GNUNET_BLOCK_Group *bg;
124 * Function to call on results.
126 GDS_DATACACHE_GetCallback gc;
134 * Number of bytes in xquery.
139 * Return value to give back.
141 enum GNUNET_BLOCK_EvaluationResult eval;
147 * Iterator for local get request results,
149 * @param cls closure for iterator, a `struct GetRequestContext`
150 * @param exp when does this value expire?
151 * @param key the key this data is stored under
152 * @param data_size the size of the data identified by key
153 * @param data the actual data
154 * @param type the type of the @a data
155 * @param put_path_length number of peers in @a put_path
156 * @param put_path path the reply took on put
157 * @return #GNUNET_OK to continue iteration, anything else
161 datacache_get_iterator (void *cls,
162 const struct GNUNET_HashCode *key,
165 enum GNUNET_BLOCK_Type type,
166 struct GNUNET_TIME_Absolute exp,
167 unsigned int put_path_length,
168 const struct GNUNET_PeerIdentity *put_path)
170 static char non_null;
171 struct GetRequestContext *ctx = cls;
172 enum GNUNET_BLOCK_EvaluationResult eval;
174 if (0 == GNUNET_TIME_absolute_get_remaining (exp).rel_value_us)
176 GNUNET_break (0); /* why does datacache return expired values? */
177 return GNUNET_OK; /* skip expired record */
179 if ( (NULL == data) &&
181 data = &non_null; /* point anywhere, but not to NULL */
184 = GNUNET_BLOCK_evaluate (GDS_block_context,
187 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
193 LOG (GNUNET_ERROR_TYPE_DEBUG,
194 "Found reply for query %s in datacache, evaluation result is %d\n",
200 case GNUNET_BLOCK_EVALUATION_OK_MORE:
201 case GNUNET_BLOCK_EVALUATION_OK_LAST:
202 /* forward to local clients */
203 GNUNET_STATISTICS_update (GDS_stats,
205 ("# Good RESULTS found in datacache"), 1,
207 ctx->gc (ctx->gc_cls,
211 put_path_length, put_path,
215 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
216 GNUNET_STATISTICS_update (GDS_stats,
217 gettext_noop ("# Duplicate RESULTS found in datacache"),
221 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
222 GNUNET_STATISTICS_update (GDS_stats,
223 gettext_noop ("# Invalid RESULTS found in datacache"),
227 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
228 GNUNET_STATISTICS_update (GDS_stats,
229 gettext_noop ("# Irrelevant RESULTS found in datacache"),
233 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
236 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
238 return GNUNET_SYSERR;
239 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
240 GNUNET_STATISTICS_update (GDS_stats,
241 gettext_noop ("# Unsupported RESULTS found in datacache"),
244 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
245 _("Unsupported block type (%u) in local response!\n"),
249 return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
254 * Handle a GET request we've received from another peer.
256 * @param key the query
257 * @param type requested data type
258 * @param xquery extended query
259 * @param xquery_size number of bytes in @a xquery
260 * @param bg block group to use for reply evaluation
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_BLOCK_Group *bg,
271 GDS_DATACACHE_GetCallback gc,
274 struct GetRequestContext ctx;
277 if (NULL == datacache)
278 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
279 GNUNET_STATISTICS_update (GDS_stats,
280 gettext_noop ("# GET requests given to datacache"),
283 ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
286 ctx.xquery_size = xquery_size;
290 r = GNUNET_DATACACHE_get (datacache,
293 &datacache_get_iterator,
295 LOG (GNUNET_ERROR_TYPE_DEBUG,
296 "DATACACHE GET for key %s completed (%d). %u results found.\n",
305 * Function called with a random element from the datacache.
306 * Stores the key in the closure.
308 * @param cls a `struct GNUNET_HashCode *`, where to store the @a key
309 * @param key key for the content
310 * @param data_size number of bytes in @a data
311 * @param data content stored
312 * @param type type of the content
313 * @param exp when will the content expire?
314 * @param path_info_len number of entries in @a path_info
315 * @param path_info a path through the network
316 * @return #GNUNET_OK to continue iterating, #GNUNET_SYSERR to abort
319 datacache_random_iterator (void *cls,
320 const struct GNUNET_HashCode *key,
323 enum GNUNET_BLOCK_Type type,
324 struct GNUNET_TIME_Absolute exp,
325 unsigned int path_info_len,
326 const struct GNUNET_PeerIdentity *path_info)
328 struct GNUNET_HashCode *dest = cls;
331 return GNUNET_OK; /* should actually not matter which we return */
336 * Obtain a random key from the datacache.
337 * Used by Whanau for load-balancing.
339 * @param[out] key where to store the key of a random element,
340 * randomized by PRNG if datacache is empty
341 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the datacache is empty
344 GDS_DATACACHE_get_random_key (struct GNUNET_HashCode *key)
347 GNUNET_DATACACHE_get_random (datacache,
348 &datacache_random_iterator,
351 /* randomize key in this case */
352 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
354 return GNUNET_SYSERR;
361 * Closure for #datacache_get_successors_iterator().
366 * Function to call on the result
368 GDS_DATACACHE_SuccessorCallback cb;
378 * Iterator for local get request results,
380 * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
381 * @param key the key this data is stored under
382 * @param size the size of the data identified by key
383 * @param data the actual data
384 * @param type the type of the data
385 * @param exp when does this value expire?
386 * @param put_path_length number of peers in @a put_path
387 * @param put_path path the reply took on put
388 * @return #GNUNET_OK to continue iteration, anything else
392 datacache_get_successors_iterator (void *cls,
393 const struct GNUNET_HashCode *key,
396 enum GNUNET_BLOCK_Type type,
397 struct GNUNET_TIME_Absolute exp,
398 unsigned int put_path_length,
399 const struct GNUNET_PeerIdentity *put_path)
401 const struct SuccContext *sc = cls;
403 /* NOTE: The datacache currently does not store the RO from
404 the original 'put', so we don't know the 'correct' option
405 at this point anymore. Thus, we conservatively assume
406 that recording is desired (for now). */
408 GNUNET_DHT_RO_RECORD_ROUTE,
411 put_path_length, put_path,
420 * Handle a request for data close to a key that we have received from
423 * @param key the location at which the peer is looking for data that is close
424 * @param cb function to call with the result
425 * @param cb_cls closure for @a cb
428 GDS_DATACACHE_get_successors (const struct GNUNET_HashCode *key,
429 GDS_DATACACHE_SuccessorCallback cb,
432 struct SuccContext sc;
436 (void) GNUNET_DATACACHE_get_closest (datacache,
439 &datacache_get_successors_iterator,
445 * Initialize datacache subsystem.
448 GDS_DATACACHE_init ()
450 datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
455 * Shutdown datacache subsystem.
458 GDS_DATACACHE_done ()
460 if (NULL != datacache)
462 GNUNET_DATACACHE_destroy (datacache);
468 /* end of gnunet-service-dht_datacache.c */