2 This file is part of GNUnet.
3 (C) 2011 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file dht/gnunet-service-dht_routing.c
23 * @brief GNUnet DHT tracking of requests for routing replies
24 * @author Christian Grothoff
27 #include "gnunet-service-dht_neighbours.h"
28 #include "gnunet-service-dht_routing.h"
29 #include "gnunet-service-dht.h"
33 * Number of requests we track at most (for routing replies).
35 #define DHT_MAX_RECENT (1024 * 16)
39 * Information we keep about all recent GET requests
40 * so that we can route replies.
46 * The peer this request was received from.
48 struct GNUNET_PeerIdentity peer;
51 * Key of this request.
56 * Position of this node in the min heap.
58 struct GNUNET_CONTAINER_HeapNode *heap_node;
61 * Bloomfilter for replies to drop.
63 struct GNUNET_CONTAINER_BloomFilter *reply_bf;
66 * Type of the requested block.
68 enum GNUNET_BLOCK_Type type;
71 * extended query (see gnunet_block_lib.h). Allocated at the
77 * Number of bytes in xquery.
82 * Mutator value for the reply_bf, see gnunet_block_lib.h
84 uint32_t reply_bf_mutator;
89 enum GNUNET_DHT_RouteOption options;
95 * Recent requests by time inserted.
97 static struct GNUNET_CONTAINER_Heap *recent_heap;
100 * Recently seen requests by key.
102 static struct GNUNET_CONTAINER_MultiHashMap *recent_map;
106 * Closure for the 'process' function.
108 struct ProcessContext
111 * Path of the original PUT
113 const struct GNUNET_PeerIdentity *put_path;
118 const struct GNUNET_PeerIdentity *get_path;
121 * Payload of the reply.
126 * Expiration time of the result.
128 struct GNUNET_TIME_Absolute expiration_time;
131 * Number of entries in 'put_path'.
133 unsigned int put_path_length;
136 * Number of entries in 'get_path'.
138 unsigned int get_path_length;
141 * Number of bytes in 'data'.
148 enum GNUNET_BLOCK_Type type;
154 * Forward the result to the given peer if it matches the request.
156 * @param cls the 'struct ProcessContext' with the result
157 * @param key the query
158 * @param value the 'struct RecentRequest' with the request
159 * @return GNUNET_OK (continue to iterate),
160 * GNUNET_SYSERR if the result is malformed or type unsupported
164 const GNUNET_HashCode *key,
167 struct ProcessContext *pc = cls;
168 struct RecentRequest *rr = value;
169 enum GNUNET_BLOCK_EvaluationResult eval;
173 const GNUNET_HashCode *eval_key;
175 if ( (rr->type != GNUNET_BLOCK_TYPE_ANY) &&
176 (rr->type != pc->type) )
177 return GNUNET_OK; /* type missmatch */
179 if (0 != (rr->options & GNUNET_DHT_RO_RECORD_ROUTE))
181 gpl = pc->get_path_length;
182 ppl = pc->put_path_length;
189 if ( (0 != (rr->options & GNUNET_DHT_RO_FIND_PEER)) &&
190 (pc->type == GNUNET_BLOCK_TYPE_DHT_HELLO) )
192 /* key may not match HELLO, which is OK since
193 the search is approximate. Still, the evaluation
194 would fail since the match is not exact. So
195 we fake it by changing the key to the actual PID ... */
196 GNUNET_BLOCK_get_key (GDS_block_context,
197 GNUNET_BLOCK_TYPE_DHT_HELLO,
198 pc->data, pc->data_size,
206 eval = GNUNET_BLOCK_evaluate (GDS_block_context,
210 rr->reply_bf_mutator,
217 case GNUNET_BLOCK_EVALUATION_OK_MORE:
218 case GNUNET_BLOCK_EVALUATION_OK_LAST:
219 GDS_NEIGHBOURS_handle_reply (&rr->peer,
230 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
232 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
234 return GNUNET_SYSERR;
235 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
236 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
239 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
240 return GNUNET_SYSERR;
243 return GNUNET_SYSERR;
250 * Handle a reply (route to origin). Only forwards the reply back to
251 * other peers waiting for it. Does not do local caching or
252 * forwarding to local clients. Essentially calls
253 * GDS_NEIGHBOURS_handle_reply for all peers that sent us a matching
256 * @param type type of the block
257 * @param expiration_time when does the content expire
258 * @param key key for the content
259 * @param put_path_length number of entries in put_path
260 * @param put_path peers the original PUT traversed (if tracked)
261 * @param get_path_length number of entries in put_path
262 * @param get_path peers this reply has traversed so far (if tracked)
263 * @param data payload of the reply
264 * @param data_size number of bytes in data
267 GDS_ROUTING_process (enum GNUNET_BLOCK_Type type,
268 struct GNUNET_TIME_Absolute expiration_time,
269 const GNUNET_HashCode *key,
270 unsigned int put_path_length,
271 const struct GNUNET_PeerIdentity *put_path,
272 unsigned int get_path_length,
273 const struct GNUNET_PeerIdentity *get_path,
277 struct ProcessContext pc;
280 pc.expiration_time = expiration_time;
281 pc.put_path_length = put_path_length;
282 pc.put_path = put_path;
283 pc.get_path_length = get_path_length;
284 pc.get_path = get_path;
286 pc.data_size = data_size;
287 GNUNET_CONTAINER_multihashmap_get_multiple (recent_map,
295 * Add a new entry to our routing table.
297 * @param sender peer that originated the request
298 * @param type type of the block
299 * @param options options for processing
300 * @param key key for the content
301 * @param xquery extended query
302 * @param xquery_size number of bytes in xquery
303 * @param reply_bf bloomfilter to filter duplicates
304 * @param reply_bf_mutator mutator for reply_bf
307 GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender,
308 enum GNUNET_BLOCK_Type type,
309 enum GNUNET_DHT_RouteOption options,
310 const GNUNET_HashCode *key,
313 const struct GNUNET_CONTAINER_BloomFilter *reply_bf,
314 uint32_t reply_bf_mutator)
316 struct RecentRequest *recent_req;
318 while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT)
320 recent_req = GNUNET_CONTAINER_heap_peek (recent_heap);
321 GNUNET_assert (recent_req != NULL);
322 GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node);
323 GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf);
324 GNUNET_free (recent_req);
327 recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size);
328 recent_req->peer = *sender;
329 recent_req->key = *key;
330 recent_req->heap_node =
331 GNUNET_CONTAINER_heap_insert (recent_heap, recent_req,
332 GNUNET_TIME_absolute_get ().abs_value);
333 recent_req->reply_bf =
334 GNUNET_CONTAINER_bloomfilter_copy (reply_bf);
335 recent_req->type = type;
336 recent_req->options = options;
337 recent_req->xquery = &recent_req[1];
338 recent_req->xquery_size = xquery_size;
339 recent_req->reply_bf_mutator = reply_bf_mutator;
340 GNUNET_CONTAINER_multihashmap_put (recent_map,
343 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
350 * Initialize routing subsystem.
356 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
358 GNUNET_CONTAINER_multihashmap_create (DHT_MAX_RECENT * 4 / 3);
363 * Shutdown routing subsystem.
368 struct RecentRequest *recent_req;
370 while (GNUNET_CONTAINER_heap_get_size (recent_heap) > 0)
372 recent_req = GNUNET_CONTAINER_heap_peek (recent_heap);
373 GNUNET_assert (recent_req != NULL);
374 GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node);
375 GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf);
376 GNUNET_free (recent_req);
378 GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (recent_heap));
379 GNUNET_CONTAINER_heap_destroy (recent_heap);
381 GNUNET_CONTAINER_multihashmap_destroy (recent_map);
385 /* end of gnunet-service-dht_routing.c */