diff options
Diffstat (limited to 'src/dht/gnunet-service-xdht_routing.c')
-rw-r--r-- | src/dht/gnunet-service-xdht_routing.c | 419 |
1 files changed, 62 insertions, 357 deletions
diff --git a/src/dht/gnunet-service-xdht_routing.c b/src/dht/gnunet-service-xdht_routing.c index 83568e237..66ab88eb4 100644 --- a/src/dht/gnunet-service-xdht_routing.c +++ b/src/dht/gnunet-service-xdht_routing.c | |||
@@ -21,14 +21,17 @@ | |||
21 | /** | 21 | /** |
22 | * @file dht/gnunet-service-xdht_routing.c | 22 | * @file dht/gnunet-service-xdht_routing.c |
23 | * @brief GNUnet DHT tracking of requests for routing replies | 23 | * @brief GNUnet DHT tracking of requests for routing replies |
24 | * @author Christian Grothoff | 24 | * @author Supriti Singh |
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet-service-xdht_neighbours.h" | 27 | #include "gnunet-service-xdht_neighbours.h" |
28 | #include "gnunet-service-xdht_routing.h" | 28 | #include "gnunet-service-xdht_routing.h" |
29 | #include "gnunet-service-xdht.h" | 29 | #include "gnunet-service-xdht.h" |
30 | 30 | ||
31 | 31 | /* FIXME | |
32 | * 1. We need field to understand which routing table is for which peer. | ||
33 | * 2. Better function names and variable names. | ||
34 | */ | ||
32 | /** | 35 | /** |
33 | * Number of requests we track at most (for routing replies). | 36 | * Number of requests we track at most (for routing replies). |
34 | */ | 37 | */ |
@@ -36,223 +39,81 @@ | |||
36 | 39 | ||
37 | 40 | ||
38 | /** | 41 | /** |
39 | * Information we keep about all recent GET requests | 42 | * Routing table entry . |
40 | * so that we can route replies. | ||
41 | */ | 43 | */ |
42 | struct RecentRequest | 44 | struct RoutingTrail |
43 | { | 45 | { |
44 | 46 | /** | |
45 | /** | 47 | * Source peer . |
46 | * The peer this request was received from. | 48 | */ |
47 | */ | 49 | struct GNUNET_PeerIdentity endpoint1; |
48 | struct GNUNET_PeerIdentity peer; | 50 | |
49 | 51 | /** | |
50 | /** | 52 | * Destination peer. |
51 | * Key of this request. | 53 | */ |
52 | */ | 54 | struct GNUNET_PeerIdentity endppoint2; |
53 | struct GNUNET_HashCode key; | 55 | |
54 | 56 | /** | |
55 | /** | 57 | * The peer this request was received from. |
56 | * Position of this node in the min heap. | 58 | */ |
57 | */ | 59 | struct GNUNET_PeerIdentity previous_hop; |
58 | struct GNUNET_CONTAINER_HeapNode *heap_node; | 60 | |
59 | 61 | /** | |
60 | /** | 62 | * The peer to which this request should be passed to. |
61 | * Bloomfilter for replies to drop. | 63 | */ |
62 | */ | 64 | struct GNUNET_PeerIdentity next_hop; |
63 | struct GNUNET_CONTAINER_BloomFilter *reply_bf; | ||
64 | |||
65 | /** | ||
66 | * Type of the requested block. | ||
67 | */ | ||
68 | enum GNUNET_BLOCK_Type type; | ||
69 | |||
70 | /** | ||
71 | * extended query (see gnunet_block_lib.h). Allocated at the | ||
72 | * end of this struct. | ||
73 | */ | ||
74 | const void *xquery; | ||
75 | |||
76 | /** | ||
77 | * Number of bytes in xquery. | ||
78 | */ | ||
79 | size_t xquery_size; | ||
80 | |||
81 | /** | ||
82 | * Mutator value for the reply_bf, see gnunet_block_lib.h | ||
83 | */ | ||
84 | uint32_t reply_bf_mutator; | ||
85 | |||
86 | /** | ||
87 | * Request options. | ||
88 | */ | ||
89 | enum GNUNET_DHT_RouteOption options; | ||
90 | |||
91 | }; | 65 | }; |
92 | 66 | ||
93 | 67 | ||
94 | /** | 68 | /** |
95 | * Recent requests by time inserted. | 69 | * Routing table of the peer |
96 | */ | 70 | */ |
97 | static struct GNUNET_CONTAINER_Heap *recent_heap; | 71 | static struct GNUNET_CONTAINER_MultiPeerMap *routing_table; |
98 | |||
99 | /** | ||
100 | * Recently seen requests by key. | ||
101 | */ | ||
102 | static struct GNUNET_CONTAINER_MultiHashMap *recent_map; | ||
103 | 72 | ||
104 | 73 | ||
105 | /** | 74 | /** |
106 | * Closure for the 'process' function. | 75 | * Find the next hop to pass the message to . |
76 | * @return | ||
107 | */ | 77 | */ |
108 | struct ProcessContext | 78 | //static struct GNUNET_PeerIdentity * |
109 | { | 79 | //find_next_hop() |
110 | /** | 80 | //{ |
111 | * Path of the original PUT | 81 | |
112 | */ | 82 | //} |
113 | const struct GNUNET_PeerIdentity *put_path; | ||
114 | |||
115 | /** | ||
116 | * Path of the reply. | ||
117 | */ | ||
118 | const struct GNUNET_PeerIdentity *get_path; | ||
119 | |||
120 | /** | ||
121 | * Payload of the reply. | ||
122 | */ | ||
123 | const void *data; | ||
124 | 83 | ||
125 | /** | ||
126 | * Expiration time of the result. | ||
127 | */ | ||
128 | struct GNUNET_TIME_Absolute expiration_time; | ||
129 | |||
130 | /** | ||
131 | * Number of entries in 'put_path'. | ||
132 | */ | ||
133 | unsigned int put_path_length; | ||
134 | |||
135 | /** | ||
136 | * Number of entries in 'get_path'. | ||
137 | */ | ||
138 | unsigned int get_path_length; | ||
139 | |||
140 | /** | ||
141 | * Number of bytes in 'data'. | ||
142 | */ | ||
143 | size_t data_size; | ||
144 | |||
145 | /** | ||
146 | * Type of the reply. | ||
147 | */ | ||
148 | enum GNUNET_BLOCK_Type type; | ||
149 | |||
150 | }; | ||
151 | 84 | ||
152 | 85 | ||
153 | /** | 86 | /** |
154 | * Forward the result to the given peer if it matches the request. | 87 | * Add a new entry to our routing table. |
155 | * | 88 | * |
156 | * @param cls the `struct ProcessContext` with the result | 89 | * @param sender peer that originated the request |
157 | * @param key the query | 90 | * @param type type of the block |
158 | * @param value the `struct RecentRequest` with the request | 91 | * @param options options for processing |
159 | * @return #GNUNET_OK (continue to iterate), | 92 | * @param key key for the content |
160 | * #GNUNET_SYSERR if the result is malformed or type unsupported | 93 | * @param xquery extended query |
94 | * @param xquery_size number of bytes in @a xquery | ||
95 | * @param reply_bf bloomfilter to filter duplicates | ||
96 | * @param reply_bf_mutator mutator for @a reply_bf | ||
161 | */ | 97 | */ |
162 | static int | 98 | void |
163 | process (void *cls, const struct GNUNET_HashCode * key, void *value) | 99 | GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, |
100 | enum GNUNET_BLOCK_Type type, | ||
101 | enum GNUNET_DHT_RouteOption options, | ||
102 | const struct GNUNET_HashCode * key, const void *xquery, | ||
103 | size_t xquery_size, | ||
104 | const struct GNUNET_CONTAINER_BloomFilter *reply_bf, | ||
105 | uint32_t reply_bf_mutator) | ||
164 | { | 106 | { |
165 | struct ProcessContext *pc = cls; | ||
166 | struct RecentRequest *rr = value; | ||
167 | enum GNUNET_BLOCK_EvaluationResult eval; | ||
168 | unsigned int gpl; | ||
169 | unsigned int ppl; | ||
170 | struct GNUNET_HashCode hc; | ||
171 | const struct GNUNET_HashCode *eval_key; | ||
172 | |||
173 | if ((rr->type != GNUNET_BLOCK_TYPE_ANY) && (rr->type != pc->type)) | ||
174 | return GNUNET_OK; /* type missmatch */ | ||
175 | 107 | ||
176 | if (0 != (rr->options & GNUNET_DHT_RO_RECORD_ROUTE)) | ||
177 | { | ||
178 | gpl = pc->get_path_length; | ||
179 | ppl = pc->put_path_length; | ||
180 | } | ||
181 | else | ||
182 | { | ||
183 | gpl = 0; | ||
184 | ppl = 0; | ||
185 | } | ||
186 | if ((0 != (rr->options & GNUNET_DHT_RO_FIND_PEER)) && | ||
187 | (pc->type == GNUNET_BLOCK_TYPE_DHT_HELLO)) | ||
188 | { | ||
189 | /* key may not match HELLO, which is OK since | ||
190 | * the search is approximate. Still, the evaluation | ||
191 | * would fail since the match is not exact. So | ||
192 | * we fake it by changing the key to the actual PID ... */ | ||
193 | GNUNET_BLOCK_get_key (GDS_block_context, GNUNET_BLOCK_TYPE_DHT_HELLO, | ||
194 | pc->data, pc->data_size, &hc); | ||
195 | eval_key = &hc; | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | eval_key = key; | ||
200 | } | ||
201 | eval = | ||
202 | GNUNET_BLOCK_evaluate (GDS_block_context, pc->type, eval_key, | ||
203 | &rr->reply_bf, rr->reply_bf_mutator, rr->xquery, | ||
204 | rr->xquery_size, pc->data, pc->data_size); | ||
205 | switch (eval) | ||
206 | { | ||
207 | case GNUNET_BLOCK_EVALUATION_OK_MORE: | ||
208 | case GNUNET_BLOCK_EVALUATION_OK_LAST: | ||
209 | GNUNET_STATISTICS_update (GDS_stats, | ||
210 | gettext_noop | ||
211 | ("# Good REPLIES matched against routing table"), | ||
212 | 1, GNUNET_NO); | ||
213 | GDS_NEIGHBOURS_handle_reply (&rr->peer, pc->type, pc->expiration_time, key, | ||
214 | ppl, pc->put_path, gpl, pc->get_path, pc->data, | ||
215 | pc->data_size); | ||
216 | break; | ||
217 | case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: | ||
218 | GNUNET_STATISTICS_update (GDS_stats, | ||
219 | gettext_noop | ||
220 | ("# Duplicate REPLIES matched against routing table"), | ||
221 | 1, GNUNET_NO); | ||
222 | return GNUNET_OK; | ||
223 | case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: | ||
224 | GNUNET_STATISTICS_update (GDS_stats, | ||
225 | gettext_noop | ||
226 | ("# Invalid REPLIES matched against routing table"), | ||
227 | 1, GNUNET_NO); | ||
228 | return GNUNET_SYSERR; | ||
229 | case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT: | ||
230 | GNUNET_STATISTICS_update (GDS_stats, | ||
231 | gettext_noop | ||
232 | ("# Irrelevant REPLIES matched against routing table"), | ||
233 | 1, GNUNET_NO); | ||
234 | return GNUNET_OK; | ||
235 | case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: | ||
236 | GNUNET_break (0); | ||
237 | return GNUNET_OK; | ||
238 | case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: | ||
239 | GNUNET_break (0); | ||
240 | return GNUNET_OK; | ||
241 | case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: | ||
242 | GNUNET_STATISTICS_update (GDS_stats, | ||
243 | gettext_noop | ||
244 | ("# Unsupported REPLIES matched against routing table"), | ||
245 | 1, GNUNET_NO); | ||
246 | return GNUNET_SYSERR; | ||
247 | default: | ||
248 | GNUNET_break (0); | ||
249 | return GNUNET_SYSERR; | ||
250 | } | ||
251 | return GNUNET_OK; | ||
252 | } | 108 | } |
253 | 109 | ||
110 | /* search in routing table for next hop to pass the message to . | ||
111 | * struct GNUNET_PeerIdentity * | ||
112 | GDS_Routing_search() | ||
113 | { | ||
114 | }*/ | ||
254 | 115 | ||
255 | /** | 116 | /**FIXME: Old implementation just to remove error |
256 | * Handle a reply (route to origin). Only forwards the reply back to | 117 | * Handle a reply (route to origin). Only forwards the reply back to |
257 | * other peers waiting for it. Does not do local caching or | 118 | * other peers waiting for it. Does not do local caching or |
258 | * forwarding to local clients. Essentially calls | 119 | * forwarding to local clients. Essentially calls |
@@ -278,164 +139,14 @@ GDS_ROUTING_process (enum GNUNET_BLOCK_Type type, | |||
278 | const struct GNUNET_PeerIdentity *get_path, | 139 | const struct GNUNET_PeerIdentity *get_path, |
279 | const void *data, size_t data_size) | 140 | const void *data, size_t data_size) |
280 | { | 141 | { |
281 | struct ProcessContext pc; | ||
282 | |||
283 | pc.type = type; | ||
284 | pc.expiration_time = expiration_time; | ||
285 | pc.put_path_length = put_path_length; | ||
286 | pc.put_path = put_path; | ||
287 | pc.get_path_length = get_path_length; | ||
288 | pc.get_path = get_path; | ||
289 | pc.data = data; | ||
290 | pc.data_size = data_size; | ||
291 | if (NULL == data) | ||
292 | { | ||
293 | /* Some apps might have an 'empty' reply as a valid reply; however, | ||
294 | 'process' will call GNUNET_BLOCK_evaluate' which treats a 'NULL' | ||
295 | reply as request-validation (but we need response-validation). | ||
296 | So we set 'data' to a 0-byte non-NULL value just to be sure */ | ||
297 | GNUNET_break (0 == data_size); | ||
298 | pc.data_size = 0; | ||
299 | pc.data = ""; /* something not null */ | ||
300 | } | ||
301 | GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key, &process, &pc); | ||
302 | } | 142 | } |
303 | |||
304 | |||
305 | /** | ||
306 | * Remove the oldest entry from the DHT routing table. Must only | ||
307 | * be called if it is known that there is at least one entry | ||
308 | * in the heap and hashmap. | ||
309 | */ | ||
310 | static void | ||
311 | expire_oldest_entry () | ||
312 | { | ||
313 | struct RecentRequest *recent_req; | ||
314 | |||
315 | GNUNET_STATISTICS_update (GDS_stats, | ||
316 | gettext_noop | ||
317 | ("# Entries removed from routing table"), 1, | ||
318 | GNUNET_NO); | ||
319 | recent_req = GNUNET_CONTAINER_heap_peek (recent_heap); | ||
320 | GNUNET_assert (recent_req != NULL); | ||
321 | GNUNET_CONTAINER_heap_remove_node (recent_req->heap_node); | ||
322 | GNUNET_CONTAINER_bloomfilter_free (recent_req->reply_bf); | ||
323 | GNUNET_assert (GNUNET_YES == | ||
324 | GNUNET_CONTAINER_multihashmap_remove (recent_map, | ||
325 | &recent_req->key, | ||
326 | recent_req)); | ||
327 | GNUNET_free (recent_req); | ||
328 | } | ||
329 | |||
330 | |||
331 | /** | ||
332 | * Try to combine multiple recent requests for the same value | ||
333 | * (if they come from the same peer). | ||
334 | * | ||
335 | * @param cls the new 'struct RecentRequest' (to discard upon successful combination) | ||
336 | * @param key the query | ||
337 | * @param value the existing 'struct RecentRequest' (to update upon successful combination) | ||
338 | * @return GNUNET_OK (continue to iterate), | ||
339 | * GNUNET_SYSERR if the request was successfully combined | ||
340 | */ | ||
341 | static int | ||
342 | try_combine_recent (void *cls, const struct GNUNET_HashCode * key, void *value) | ||
343 | { | ||
344 | struct RecentRequest *in = cls; | ||
345 | struct RecentRequest *rr = value; | ||
346 | |||
347 | if ( (0 != memcmp (&in->peer, | ||
348 | &rr->peer, | ||
349 | sizeof (struct GNUNET_PeerIdentity))) || | ||
350 | (in->type != rr->type) || | ||
351 | (in->xquery_size != rr->xquery_size) || | ||
352 | (0 != memcmp (in->xquery, | ||
353 | rr->xquery, | ||
354 | in->xquery_size)) ) | ||
355 | return GNUNET_OK; | ||
356 | if (in->reply_bf_mutator != rr->reply_bf_mutator) | ||
357 | { | ||
358 | rr->reply_bf_mutator = in->reply_bf_mutator; | ||
359 | GNUNET_CONTAINER_bloomfilter_free (rr->reply_bf); | ||
360 | rr->reply_bf = in->reply_bf; | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | GNUNET_CONTAINER_bloomfilter_or2 (rr->reply_bf, | ||
365 | in->reply_bf); | ||
366 | GNUNET_CONTAINER_bloomfilter_free (in->reply_bf); | ||
367 | } | ||
368 | GNUNET_free (in); | ||
369 | return GNUNET_SYSERR; | ||
370 | } | ||
371 | |||
372 | |||
373 | /** | ||
374 | * Add a new entry to our routing table. | ||
375 | * | ||
376 | * @param sender peer that originated the request | ||
377 | * @param type type of the block | ||
378 | * @param options options for processing | ||
379 | * @param key key for the content | ||
380 | * @param xquery extended query | ||
381 | * @param xquery_size number of bytes in @a xquery | ||
382 | * @param reply_bf bloomfilter to filter duplicates | ||
383 | * @param reply_bf_mutator mutator for @a reply_bf | ||
384 | */ | ||
385 | void | ||
386 | GDS_ROUTING_add (const struct GNUNET_PeerIdentity *sender, | ||
387 | enum GNUNET_BLOCK_Type type, | ||
388 | enum GNUNET_DHT_RouteOption options, | ||
389 | const struct GNUNET_HashCode * key, const void *xquery, | ||
390 | size_t xquery_size, | ||
391 | const struct GNUNET_CONTAINER_BloomFilter *reply_bf, | ||
392 | uint32_t reply_bf_mutator) | ||
393 | { | ||
394 | struct RecentRequest *recent_req; | ||
395 | |||
396 | while (GNUNET_CONTAINER_heap_get_size (recent_heap) >= DHT_MAX_RECENT) | ||
397 | expire_oldest_entry (); | ||
398 | GNUNET_STATISTICS_update (GDS_stats, | ||
399 | gettext_noop ("# Entries added to routing table"), | ||
400 | 1, GNUNET_NO); | ||
401 | recent_req = GNUNET_malloc (sizeof (struct RecentRequest) + xquery_size); | ||
402 | recent_req->peer = *sender; | ||
403 | recent_req->key = *key; | ||
404 | recent_req->reply_bf = GNUNET_CONTAINER_bloomfilter_copy (reply_bf); | ||
405 | recent_req->type = type; | ||
406 | recent_req->options = options; | ||
407 | recent_req->xquery = &recent_req[1]; | ||
408 | memcpy (&recent_req[1], xquery, xquery_size); | ||
409 | recent_req->xquery_size = xquery_size; | ||
410 | recent_req->reply_bf_mutator = reply_bf_mutator; | ||
411 | if (GNUNET_SYSERR == | ||
412 | GNUNET_CONTAINER_multihashmap_get_multiple (recent_map, key, | ||
413 | &try_combine_recent, recent_req)) | ||
414 | { | ||
415 | GNUNET_STATISTICS_update (GDS_stats, | ||
416 | gettext_noop | ||
417 | ("# DHT requests combined"), | ||
418 | 1, GNUNET_NO); | ||
419 | return; | ||
420 | } | ||
421 | recent_req->heap_node = | ||
422 | GNUNET_CONTAINER_heap_insert (recent_heap, recent_req, | ||
423 | GNUNET_TIME_absolute_get ().abs_value_us); | ||
424 | GNUNET_CONTAINER_multihashmap_put (recent_map, key, recent_req, | ||
425 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
426 | |||
427 | |||
428 | } | ||
429 | |||
430 | |||
431 | /** | 143 | /** |
432 | * Initialize routing subsystem. | 144 | * Initialize routing subsystem. |
433 | */ | 145 | */ |
434 | void | 146 | void |
435 | GDS_ROUTING_init () | 147 | GDS_ROUTING_init () |
436 | { | 148 | { |
437 | recent_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | 149 | routing_table = GNUNET_CONTAINER_multipeermap_create (DHT_MAX_RECENT * 4 / 3, GNUNET_NO); |
438 | recent_map = GNUNET_CONTAINER_multihashmap_create (DHT_MAX_RECENT * 4 / 3, GNUNET_NO); | ||
439 | } | 150 | } |
440 | 151 | ||
441 | 152 | ||
@@ -445,14 +156,8 @@ GDS_ROUTING_init () | |||
445 | void | 156 | void |
446 | GDS_ROUTING_done () | 157 | GDS_ROUTING_done () |
447 | { | 158 | { |
448 | while (GNUNET_CONTAINER_heap_get_size (recent_heap) > 0) | 159 | GNUNET_assert (0 == GNUNET_CONTAINER_multipeermap_size (routing_table)); |
449 | expire_oldest_entry (); | 160 | GNUNET_CONTAINER_multipeermap_destroy (routing_table); |
450 | GNUNET_assert (0 == GNUNET_CONTAINER_heap_get_size (recent_heap)); | ||
451 | GNUNET_CONTAINER_heap_destroy (recent_heap); | ||
452 | recent_heap = NULL; | ||
453 | GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (recent_map)); | ||
454 | GNUNET_CONTAINER_multihashmap_destroy (recent_map); | ||
455 | recent_map = NULL; | ||
456 | } | 161 | } |
457 | 162 | ||
458 | /* end of gnunet-service-dht_routing.c */ | 163 | /* end of gnunet-service-xdht_routing.c */ \ No newline at end of file |