diff options
Diffstat (limited to 'src/dv/gnunet-service-dv.c')
-rw-r--r-- | src/dv/gnunet-service-dv.c | 2146 |
1 files changed, 0 insertions, 2146 deletions
diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c deleted file mode 100644 index dd2ff9c12..000000000 --- a/src/dv/gnunet-service-dv.c +++ /dev/null | |||
@@ -1,2146 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2016 GNUnet e.V. | ||
4 | |||
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. | ||
9 | |||
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. | ||
14 | |||
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/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file dv/gnunet-service-dv.c | ||
23 | * @brief the distance vector service, primarily handles gossip of nearby | ||
24 | * peers and sending/receiving DV messages from core and decapsulating | ||
25 | * them | ||
26 | * | ||
27 | * @author Christian Grothoff | ||
28 | * @author Nathan Evans | ||
29 | */ | ||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_protocols.h" | ||
33 | #include "gnunet_core_service.h" | ||
34 | #include "gnunet_hello_lib.h" | ||
35 | #include "gnunet_peerinfo_service.h" | ||
36 | #include "gnunet_statistics_service.h" | ||
37 | #include "gnunet_set_service.h" | ||
38 | #include "gnunet_ats_service.h" | ||
39 | #include "dv.h" | ||
40 | #include <gcrypt.h> | ||
41 | |||
42 | |||
43 | /** | ||
44 | * How often do we establish the consensu? | ||
45 | */ | ||
46 | #define GNUNET_DV_CONSENSUS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5) | ||
47 | |||
48 | /** | ||
49 | * Maximum number of messages we queue per peer. | ||
50 | */ | ||
51 | #define MAX_QUEUE_SIZE 16 | ||
52 | |||
53 | /** | ||
54 | * Maximum number of messages we queue towards the clients/plugin. | ||
55 | */ | ||
56 | #define MAX_QUEUE_SIZE_PLUGIN 1024 | ||
57 | |||
58 | /** | ||
59 | * The default fisheye depth, from how many hops away will | ||
60 | * we keep peers? | ||
61 | */ | ||
62 | #define DEFAULT_FISHEYE_DEPTH 3 | ||
63 | |||
64 | /** | ||
65 | * How many hops is a direct neighbor away? | ||
66 | */ | ||
67 | #define DIRECT_NEIGHBOR_COST 1 | ||
68 | |||
69 | |||
70 | GNUNET_NETWORK_STRUCT_BEGIN | ||
71 | |||
72 | /** | ||
73 | * Information about a peer DV can route to. These entries are what | ||
74 | * we use as the binary format to establish consensus to create our | ||
75 | * routing table and as the address format in the HELLOs. | ||
76 | */ | ||
77 | struct Target | ||
78 | { | ||
79 | |||
80 | /** | ||
81 | * Identity of the peer we can reach. | ||
82 | */ | ||
83 | struct GNUNET_PeerIdentity peer; | ||
84 | |||
85 | /** | ||
86 | * How many hops (1-3) is this peer away? in network byte order | ||
87 | */ | ||
88 | uint32_t distance GNUNET_PACKED; | ||
89 | |||
90 | }; | ||
91 | |||
92 | |||
93 | /** | ||
94 | * Message exchanged between DV services (via core), requesting a | ||
95 | * message to be routed. | ||
96 | */ | ||
97 | struct RouteMessage | ||
98 | { | ||
99 | /** | ||
100 | * Type: #GNUNET_MESSAGE_TYPE_DV_ROUTE | ||
101 | */ | ||
102 | struct GNUNET_MessageHeader header; | ||
103 | |||
104 | /** | ||
105 | * Expected (remaining) distance. Must be always smaller than | ||
106 | * #DEFAULT_FISHEYE_DEPTH, should be zero at the target. Must | ||
107 | * be decremented by one at each hop. Peers must not forward | ||
108 | * these messages further once the counter has reached zero. | ||
109 | */ | ||
110 | uint32_t distance GNUNET_PACKED; | ||
111 | |||
112 | /** | ||
113 | * The (actual) target of the message (this peer, if distance is zero). | ||
114 | */ | ||
115 | struct GNUNET_PeerIdentity target; | ||
116 | |||
117 | /** | ||
118 | * The (actual) sender of the message. | ||
119 | */ | ||
120 | struct GNUNET_PeerIdentity sender; | ||
121 | |||
122 | }; | ||
123 | |||
124 | GNUNET_NETWORK_STRUCT_END | ||
125 | |||
126 | |||
127 | /** | ||
128 | * Information about a direct neighbor (core-level, excluding | ||
129 | * DV-links, only DV-enabled peers). | ||
130 | */ | ||
131 | struct DirectNeighbor | ||
132 | { | ||
133 | |||
134 | /** | ||
135 | * Identity of the peer. | ||
136 | */ | ||
137 | struct GNUNET_PeerIdentity peer; | ||
138 | |||
139 | /** | ||
140 | * Session ID we use whenever we create a set union with | ||
141 | * this neighbor; constructed from the XOR of our peer | ||
142 | * IDs and then salted with "DV-SALT" to avoid conflicts | ||
143 | * with other applications. | ||
144 | */ | ||
145 | struct GNUNET_HashCode real_session_id; | ||
146 | |||
147 | /** | ||
148 | * Transmit handle to core service. | ||
149 | */ | ||
150 | struct GNUNET_MQ_Handle *mq; | ||
151 | |||
152 | /** | ||
153 | * Routing table of the neighbor, NULL if not yet established. | ||
154 | * Keys are peer identities, values are 'struct Target' entries. | ||
155 | * Note that the distances in the targets are from the point-of-view | ||
156 | * of the peer, not from us! | ||
157 | */ | ||
158 | struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table; | ||
159 | |||
160 | /** | ||
161 | * Updated routing table of the neighbor, under construction, | ||
162 | * NULL if we are not currently building it. | ||
163 | * Keys are peer identities, values are 'struct Target' entries. | ||
164 | * Note that the distances in the targets are from the point-of-view | ||
165 | * of the other peer, not from us! | ||
166 | */ | ||
167 | struct GNUNET_CONTAINER_MultiPeerMap *neighbor_table_consensus; | ||
168 | |||
169 | /** | ||
170 | * Our current (exposed) routing table as a set. | ||
171 | */ | ||
172 | struct GNUNET_SET_Handle *my_set; | ||
173 | |||
174 | /** | ||
175 | * Handle for our current active set union operation. | ||
176 | */ | ||
177 | struct GNUNET_SET_OperationHandle *set_op; | ||
178 | |||
179 | /** | ||
180 | * Handle used if we are listening for this peer, waiting for the | ||
181 | * other peer to initiate construction of the set union. NULL if | ||
182 | * we ar the initiating peer. | ||
183 | */ | ||
184 | struct GNUNET_SET_ListenHandle *listen_handle; | ||
185 | |||
186 | /** | ||
187 | * ID of the task we use to (periodically) update our consensus | ||
188 | * with this peer. Used if we are the initiating peer. | ||
189 | */ | ||
190 | struct GNUNET_SCHEDULER_Task *initiate_task; | ||
191 | |||
192 | /** | ||
193 | * At what offset are we, with respect to inserting our own routes | ||
194 | * into the consensus? | ||
195 | */ | ||
196 | unsigned int consensus_insertion_offset; | ||
197 | |||
198 | /** | ||
199 | * At what distance are we, with respect to inserting our own routes | ||
200 | * into the consensus? | ||
201 | */ | ||
202 | unsigned int consensus_insertion_distance; | ||
203 | |||
204 | /** | ||
205 | * Elements in consensus | ||
206 | */ | ||
207 | unsigned int consensus_elements; | ||
208 | |||
209 | /** | ||
210 | * Direct one hop route | ||
211 | */ | ||
212 | struct Route *direct_route; | ||
213 | |||
214 | /** | ||
215 | * Flag set within 'check_target_removed' to trigger full global route refresh. | ||
216 | */ | ||
217 | int target_removed; | ||
218 | |||
219 | /** | ||
220 | * Our distance to this peer, 0 for unknown. | ||
221 | */ | ||
222 | uint32_t distance; | ||
223 | |||
224 | /** | ||
225 | * The network this peer is in | ||
226 | */ | ||
227 | enum GNUNET_NetworkType network; | ||
228 | |||
229 | /** | ||
230 | * Is this neighbor connected at the core level? | ||
231 | */ | ||
232 | int connected; | ||
233 | |||
234 | }; | ||
235 | |||
236 | |||
237 | /** | ||
238 | * A route includes information about the next hop, | ||
239 | * the target, and the ultimate distance to the | ||
240 | * target. | ||
241 | */ | ||
242 | struct Route | ||
243 | { | ||
244 | |||
245 | /** | ||
246 | * Which peer do we need to forward the message to? | ||
247 | */ | ||
248 | struct DirectNeighbor *next_hop; | ||
249 | |||
250 | /** | ||
251 | * What would be the target, and how far is it away? | ||
252 | */ | ||
253 | struct Target target; | ||
254 | |||
255 | /** | ||
256 | * Offset of this target in the respective consensus set. | ||
257 | */ | ||
258 | unsigned int set_offset; | ||
259 | |||
260 | }; | ||
261 | |||
262 | |||
263 | /** | ||
264 | * Set of targets we bring to a consensus; all targets in a set have a | ||
265 | * distance equal to the sets distance (which is implied by the array | ||
266 | * index of the set). | ||
267 | */ | ||
268 | struct ConsensusSet | ||
269 | { | ||
270 | |||
271 | /** | ||
272 | * Array of targets in the set, may include NULL entries if a | ||
273 | * neighbor has disconnected; the targets are allocated with the | ||
274 | * respective container (all_routes), not here. | ||
275 | */ | ||
276 | struct Route **targets; | ||
277 | |||
278 | /** | ||
279 | * Size of the @e targets array. | ||
280 | */ | ||
281 | unsigned int array_length; | ||
282 | |||
283 | }; | ||
284 | |||
285 | |||
286 | /** | ||
287 | * Peermap of all of our neighbors; processing these usually requires | ||
288 | * first checking to see if the peer is core-connected and if the | ||
289 | * distance is 1, in which case they are direct neighbors. | ||
290 | */ | ||
291 | static struct GNUNET_CONTAINER_MultiPeerMap *direct_neighbors; | ||
292 | |||
293 | /** | ||
294 | * Hashmap with all routes that we currently support; contains | ||
295 | * routing information for all peers from distance 2 | ||
296 | * up to distance #DEFAULT_FISHEYE_DEPTH. | ||
297 | */ | ||
298 | static struct GNUNET_CONTAINER_MultiPeerMap *all_routes; | ||
299 | |||
300 | /** | ||
301 | * Array of consensus sets we expose to the outside world. Sets | ||
302 | * are structured by the distance to the target. | ||
303 | */ | ||
304 | static struct ConsensusSet consensi[DEFAULT_FISHEYE_DEPTH]; | ||
305 | |||
306 | /** | ||
307 | * Handle to the core service api. | ||
308 | */ | ||
309 | static struct GNUNET_CORE_Handle *core_api; | ||
310 | |||
311 | /** | ||
312 | * The identity of our peer. | ||
313 | */ | ||
314 | static struct GNUNET_PeerIdentity my_identity; | ||
315 | |||
316 | /** | ||
317 | * The configuration for this service. | ||
318 | */ | ||
319 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
320 | |||
321 | /** | ||
322 | * The client, the DV plugin connected to us (or an event monitor). | ||
323 | * Hopefully this client will never change, although if the plugin | ||
324 | * dies and returns for some reason it may happen. | ||
325 | */ | ||
326 | static struct GNUNET_NotificationContext *nc; | ||
327 | |||
328 | /** | ||
329 | * Handle for the statistics service. | ||
330 | */ | ||
331 | static struct GNUNET_STATISTICS_Handle *stats; | ||
332 | |||
333 | /** | ||
334 | * Handle to ATS service. | ||
335 | */ | ||
336 | static struct GNUNET_ATS_PerformanceHandle *ats; | ||
337 | |||
338 | /** | ||
339 | * Task scheduled to refresh routes based on direct neighbours. | ||
340 | */ | ||
341 | static struct GNUNET_SCHEDULER_Task *rr_task; | ||
342 | |||
343 | /** | ||
344 | * #GNUNET_YES if we are shutting down. | ||
345 | */ | ||
346 | static int in_shutdown; | ||
347 | |||
348 | /** | ||
349 | * Start creating a new DV set union by initiating the connection. | ||
350 | * | ||
351 | * @param cls the 'struct DirectNeighbor' of the peer we're building | ||
352 | * a routing consensus with | ||
353 | */ | ||
354 | static void | ||
355 | initiate_set_union (void *cls); | ||
356 | |||
357 | |||
358 | /** | ||
359 | * Start creating a new DV set union construction, our neighbour has | ||
360 | * asked for it (callback for listening peer). | ||
361 | * | ||
362 | * @param cls the 'struct DirectNeighbor' of the peer we're building | ||
363 | * a routing consensus with | ||
364 | * @param other_peer the other peer | ||
365 | * @param context_msg message with application specific information from | ||
366 | * the other peer | ||
367 | * @param request request from the other peer, use GNUNET_SET_accept | ||
368 | * to accept it, otherwise the request will be refused | ||
369 | * Note that we don't use a return value here, as it is also | ||
370 | * necessary to specify the set we want to do the operation with, | ||
371 | * whith sometimes can be derived from the context message. | ||
372 | * Also necessary to specify the timeout. | ||
373 | */ | ||
374 | static void | ||
375 | listen_set_union (void *cls, | ||
376 | const struct GNUNET_PeerIdentity *other_peer, | ||
377 | const struct GNUNET_MessageHeader *context_msg, | ||
378 | struct GNUNET_SET_Request *request); | ||
379 | |||
380 | |||
381 | /** | ||
382 | * Forward a message from another peer to the plugin. | ||
383 | * | ||
384 | * @param message the message to send to the plugin | ||
385 | * @param origin the original sender of the message | ||
386 | * @param distance distance to the original sender of the message | ||
387 | */ | ||
388 | static void | ||
389 | send_data_to_plugin (const struct GNUNET_MessageHeader *message, | ||
390 | const struct GNUNET_PeerIdentity *origin, | ||
391 | uint32_t distance) | ||
392 | { | ||
393 | struct GNUNET_DV_ReceivedMessage *received_msg; | ||
394 | size_t size; | ||
395 | |||
396 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
397 | "Delivering message from peer `%s' at distance %u\n", | ||
398 | GNUNET_i2s (origin), | ||
399 | (unsigned int) distance); | ||
400 | size = sizeof (struct GNUNET_DV_ReceivedMessage) + | ||
401 | ntohs (message->size); | ||
402 | if (size >= GNUNET_MAX_MESSAGE_SIZE) | ||
403 | { | ||
404 | GNUNET_break (0); /* too big */ | ||
405 | return; | ||
406 | } | ||
407 | received_msg = GNUNET_malloc (size); | ||
408 | received_msg->header.size = htons (size); | ||
409 | received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV); | ||
410 | received_msg->distance = htonl (distance); | ||
411 | received_msg->sender = *origin; | ||
412 | GNUNET_memcpy (&received_msg[1], message, ntohs (message->size)); | ||
413 | GNUNET_notification_context_broadcast (nc, | ||
414 | &received_msg->header, | ||
415 | GNUNET_YES); | ||
416 | GNUNET_free (received_msg); | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * Forward a control message to the plugin. | ||
422 | * | ||
423 | * @param message the message to send to the plugin | ||
424 | */ | ||
425 | static void | ||
426 | send_control_to_plugin (const struct GNUNET_MessageHeader *message) | ||
427 | { | ||
428 | GNUNET_notification_context_broadcast (nc, | ||
429 | message, | ||
430 | GNUNET_NO); | ||
431 | } | ||
432 | |||
433 | |||
434 | /** | ||
435 | * Send a DISTANCE_CHANGED message to the plugin. | ||
436 | * | ||
437 | * @param peer peer with a changed distance | ||
438 | * @param distance new distance to the peer | ||
439 | * @param network network used by the neighbor | ||
440 | */ | ||
441 | static void | ||
442 | send_distance_change_to_plugin (const struct GNUNET_PeerIdentity *peer, | ||
443 | uint32_t distance, | ||
444 | enum GNUNET_NetworkType network) | ||
445 | { | ||
446 | struct GNUNET_DV_DistanceUpdateMessage du_msg; | ||
447 | |||
448 | GNUNET_break (GNUNET_NT_UNSPECIFIED != network); | ||
449 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
450 | "Delivering DISTANCE_CHANGED for message about peer `%s'\n", | ||
451 | GNUNET_i2s (peer)); | ||
452 | du_msg.header.size = htons (sizeof (du_msg)); | ||
453 | du_msg.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED); | ||
454 | du_msg.distance = htonl (distance); | ||
455 | du_msg.peer = *peer; | ||
456 | du_msg.network = htonl ((uint32_t) network); | ||
457 | send_control_to_plugin (&du_msg.header); | ||
458 | } | ||
459 | |||
460 | |||
461 | /** | ||
462 | * Give a CONNECT message to the plugin. | ||
463 | * | ||
464 | * @param target peer that connected | ||
465 | * @param distance distance to the target | ||
466 | * @param network the network the next hop is located in | ||
467 | */ | ||
468 | static void | ||
469 | send_connect_to_plugin (const struct GNUNET_PeerIdentity *target, | ||
470 | uint32_t distance, | ||
471 | enum GNUNET_NetworkType network) | ||
472 | { | ||
473 | struct GNUNET_DV_ConnectMessage cm; | ||
474 | |||
475 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
476 | "Delivering CONNECT about peer %s with distance %u\n", | ||
477 | GNUNET_i2s (target), distance); | ||
478 | cm.header.size = htons (sizeof (cm)); | ||
479 | cm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_CONNECT); | ||
480 | cm.distance = htonl (distance); | ||
481 | cm.network = htonl ((uint32_t) network); | ||
482 | cm.peer = *target; | ||
483 | send_control_to_plugin (&cm.header); | ||
484 | } | ||
485 | |||
486 | |||
487 | /** | ||
488 | * Give a DISCONNECT message to the plugin. | ||
489 | * | ||
490 | * @param target peer that disconnected | ||
491 | */ | ||
492 | static void | ||
493 | send_disconnect_to_plugin (const struct GNUNET_PeerIdentity *target) | ||
494 | { | ||
495 | struct GNUNET_DV_DisconnectMessage dm; | ||
496 | |||
497 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
498 | "Delivering DISCONNECT about peer `%s'\n", | ||
499 | GNUNET_i2s (target)); | ||
500 | dm.header.size = htons (sizeof (dm)); | ||
501 | dm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT); | ||
502 | dm.reserved = htonl (0); | ||
503 | dm.peer = *target; | ||
504 | send_control_to_plugin (&dm.header); | ||
505 | } | ||
506 | |||
507 | |||
508 | /** | ||
509 | * Forward the given payload to the given target. | ||
510 | * | ||
511 | * @param target where to send the message | ||
512 | * @param distance distance to the @a sender | ||
513 | * @param sender original sender of the message | ||
514 | * @param actual_target ultimate recipient for the message | ||
515 | * @param payload payload of the message | ||
516 | */ | ||
517 | static void | ||
518 | forward_payload (struct DirectNeighbor *target, | ||
519 | uint32_t distance, | ||
520 | const struct GNUNET_PeerIdentity *sender, | ||
521 | const struct GNUNET_PeerIdentity *actual_target, | ||
522 | const struct GNUNET_MessageHeader *payload) | ||
523 | { | ||
524 | struct GNUNET_MQ_Envelope *env; | ||
525 | struct RouteMessage *rm; | ||
526 | |||
527 | if ( (GNUNET_MQ_get_length (target->mq) >= MAX_QUEUE_SIZE) && | ||
528 | (0 != memcmp (sender, | ||
529 | &my_identity, | ||
530 | sizeof (struct GNUNET_PeerIdentity))) ) | ||
531 | { | ||
532 | /* not _our_ client and queue is full, drop */ | ||
533 | GNUNET_STATISTICS_update (stats, | ||
534 | "# messages dropped", | ||
535 | 1, | ||
536 | GNUNET_NO); | ||
537 | return; | ||
538 | } | ||
539 | if (sizeof (struct RouteMessage) + ntohs (payload->size) | ||
540 | >= GNUNET_MAX_MESSAGE_SIZE) | ||
541 | { | ||
542 | GNUNET_break (0); | ||
543 | return; | ||
544 | } | ||
545 | env = GNUNET_MQ_msg_nested_mh (rm, | ||
546 | GNUNET_MESSAGE_TYPE_DV_ROUTE, | ||
547 | payload); | ||
548 | rm->distance = htonl (distance); | ||
549 | rm->target = *actual_target; | ||
550 | rm->sender = *sender; | ||
551 | GNUNET_MQ_send (target->mq, | ||
552 | env); | ||
553 | } | ||
554 | |||
555 | |||
556 | /** | ||
557 | * Find a free slot for storing a 'route' in the 'consensi' | ||
558 | * set at the given distance. | ||
559 | * | ||
560 | * @param distance distance to use for the set slot | ||
561 | */ | ||
562 | static unsigned int | ||
563 | get_consensus_slot (uint32_t distance) | ||
564 | { | ||
565 | struct ConsensusSet *cs; | ||
566 | unsigned int i; | ||
567 | |||
568 | GNUNET_assert (distance < DEFAULT_FISHEYE_DEPTH); | ||
569 | cs = &consensi[distance]; | ||
570 | i = 0; | ||
571 | while ( (i < cs->array_length) && | ||
572 | (NULL != cs->targets[i]) ) i++; | ||
573 | if (i == cs->array_length) | ||
574 | { | ||
575 | GNUNET_array_grow (cs->targets, | ||
576 | cs->array_length, | ||
577 | cs->array_length * 2 + 2); | ||
578 | } | ||
579 | return i; | ||
580 | } | ||
581 | |||
582 | |||
583 | /** | ||
584 | * Allocate a slot in the consensus set for a route. | ||
585 | * | ||
586 | * @param route route to initialize | ||
587 | * @param distance which consensus set to use | ||
588 | */ | ||
589 | static void | ||
590 | allocate_route (struct Route *route, | ||
591 | uint32_t distance) | ||
592 | { | ||
593 | unsigned int i; | ||
594 | |||
595 | if (distance >= DEFAULT_FISHEYE_DEPTH) | ||
596 | { | ||
597 | route->target.distance = htonl (distance); | ||
598 | route->set_offset = UINT_MAX; /* invalid slot */ | ||
599 | return; | ||
600 | } | ||
601 | i = get_consensus_slot (distance); | ||
602 | route->set_offset = i; | ||
603 | consensi[distance].targets[i] = route; | ||
604 | route->target.distance = htonl (distance); | ||
605 | } | ||
606 | |||
607 | |||
608 | /** | ||
609 | * Release a slot in the consensus set for a route. | ||
610 | * | ||
611 | * @param route route to release the slot from | ||
612 | */ | ||
613 | static void | ||
614 | release_route (struct Route *route) | ||
615 | { | ||
616 | if (UINT_MAX == route->set_offset) | ||
617 | return; | ||
618 | GNUNET_assert (ntohl (route->target.distance) < DEFAULT_FISHEYE_DEPTH); | ||
619 | consensi[ntohl (route->target.distance)].targets[route->set_offset] = NULL; | ||
620 | route->set_offset = UINT_MAX; /* indicate invalid slot */ | ||
621 | } | ||
622 | |||
623 | |||
624 | /** | ||
625 | * Move a route from one consensus set to another. | ||
626 | * | ||
627 | * @param route route to move | ||
628 | * @param new_distance new distance for the route (destination set) | ||
629 | */ | ||
630 | static void | ||
631 | move_route (struct Route *route, | ||
632 | uint32_t new_distance) | ||
633 | { | ||
634 | release_route (route); | ||
635 | allocate_route (route, new_distance); | ||
636 | } | ||
637 | |||
638 | |||
639 | /** | ||
640 | * Initialize this neighbors 'my_set' and when done give | ||
641 | * it to the pending set operation for execution. | ||
642 | * | ||
643 | * Add a single element to the set per call: | ||
644 | * | ||
645 | * If we reached the last element of a consensus element: increase distance | ||
646 | * | ||
647 | * | ||
648 | * @param cls the neighbor for which we are building the set | ||
649 | */ | ||
650 | static void | ||
651 | build_set (void *cls) | ||
652 | { | ||
653 | struct DirectNeighbor *neighbor = cls; | ||
654 | struct GNUNET_SET_Element element; | ||
655 | struct Target *target; | ||
656 | struct Route *route; | ||
657 | |||
658 | target = NULL; | ||
659 | /* skip over NULL entries */ | ||
660 | while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) && | ||
661 | (consensi[neighbor->consensus_insertion_distance].array_length > neighbor->consensus_insertion_offset) && | ||
662 | (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) ) | ||
663 | neighbor->consensus_insertion_offset++; | ||
664 | while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) && | ||
665 | (consensi[neighbor->consensus_insertion_distance].array_length == neighbor->consensus_insertion_offset) ) | ||
666 | { | ||
667 | /* If we reached the last element of a consensus array element: increase distance and start with next array */ | ||
668 | neighbor->consensus_insertion_offset = 0; | ||
669 | neighbor->consensus_insertion_distance++; | ||
670 | /* skip over NULL entries */ | ||
671 | while ( (DEFAULT_FISHEYE_DEPTH > neighbor->consensus_insertion_distance) && | ||
672 | (consensi[neighbor->consensus_insertion_distance].array_length > neighbor->consensus_insertion_offset) && | ||
673 | (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) ) | ||
674 | neighbor->consensus_insertion_offset++; | ||
675 | } | ||
676 | if (DEFAULT_FISHEYE_DEPTH == neighbor->consensus_insertion_distance) | ||
677 | { | ||
678 | /* we have added all elements to the set, run the operation */ | ||
679 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
680 | "Finished building my SET for peer `%s' with %u elements, committing\n", | ||
681 | GNUNET_i2s (&neighbor->peer), | ||
682 | neighbor->consensus_elements); | ||
683 | GNUNET_SET_commit (neighbor->set_op, | ||
684 | neighbor->my_set); | ||
685 | GNUNET_SET_destroy (neighbor->my_set); | ||
686 | neighbor->my_set = NULL; | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | route = consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]; | ||
691 | GNUNET_assert (NULL != route); | ||
692 | target = &route->target; | ||
693 | GNUNET_assert (ntohl (target->distance) < DEFAULT_FISHEYE_DEPTH); | ||
694 | element.size = sizeof (struct Target); | ||
695 | element.element_type = htons (0); | ||
696 | element.data = target; | ||
697 | |||
698 | /* Find next non-NULL entry */ | ||
699 | neighbor->consensus_insertion_offset++; | ||
700 | if ( (0 != memcmp (&target->peer, | ||
701 | &my_identity, | ||
702 | sizeof (my_identity))) && | ||
703 | (0 != memcmp (&target->peer, | ||
704 | &neighbor->peer, | ||
705 | sizeof (struct GNUNET_PeerIdentity))) ) | ||
706 | { | ||
707 | /* Add target if it is not the neighbor or this peer */ | ||
708 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
709 | "Adding peer `%s' with distance %u to SET\n", | ||
710 | GNUNET_i2s (&target->peer), | ||
711 | ntohl (target->distance) + 1); | ||
712 | GNUNET_SET_add_element (neighbor->my_set, | ||
713 | &element, | ||
714 | &build_set, neighbor); | ||
715 | neighbor->consensus_elements++; | ||
716 | } | ||
717 | else | ||
718 | build_set (neighbor); | ||
719 | } | ||
720 | |||
721 | |||
722 | /** | ||
723 | * A peer is now connected to us at distance 1. Initiate DV exchange. | ||
724 | * | ||
725 | * @param neighbor entry for the neighbor at distance 1 | ||
726 | */ | ||
727 | static void | ||
728 | handle_direct_connect (struct DirectNeighbor *neighbor) | ||
729 | { | ||
730 | struct Route *route; | ||
731 | struct GNUNET_HashCode h1; | ||
732 | struct GNUNET_HashCode h2; | ||
733 | struct GNUNET_HashCode session_id; | ||
734 | |||
735 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
736 | "Direct connection to %s established, routing table exchange begins.\n", | ||
737 | GNUNET_i2s (&neighbor->peer)); | ||
738 | GNUNET_STATISTICS_update (stats, | ||
739 | "# peers connected (1-hop)", | ||
740 | 1, GNUNET_NO); | ||
741 | route = GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
742 | &neighbor->peer); | ||
743 | if (NULL != route) | ||
744 | { | ||
745 | GNUNET_assert (GNUNET_YES == | ||
746 | GNUNET_CONTAINER_multipeermap_remove (all_routes, | ||
747 | &neighbor->peer, | ||
748 | route)); | ||
749 | send_disconnect_to_plugin (&neighbor->peer); | ||
750 | release_route (route); | ||
751 | GNUNET_free (route); | ||
752 | } | ||
753 | |||
754 | neighbor->direct_route = GNUNET_new (struct Route); | ||
755 | neighbor->direct_route->next_hop = neighbor; | ||
756 | neighbor->direct_route->target.peer = neighbor->peer; | ||
757 | allocate_route (neighbor->direct_route, DIRECT_NEIGHBOR_COST); | ||
758 | |||
759 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
760 | "Adding direct route to %s\n", | ||
761 | GNUNET_i2s (&neighbor->direct_route->target.peer)); | ||
762 | |||
763 | |||
764 | /* construct session ID seed as XOR of both peer's identities */ | ||
765 | GNUNET_CRYPTO_hash (&my_identity, | ||
766 | sizeof (my_identity), | ||
767 | &h1); | ||
768 | GNUNET_CRYPTO_hash (&neighbor->peer, | ||
769 | sizeof (struct GNUNET_PeerIdentity), | ||
770 | &h2); | ||
771 | GNUNET_CRYPTO_hash_xor (&h1, | ||
772 | &h2, | ||
773 | &session_id); | ||
774 | /* make sure session ID is unique across applications by salting it with 'DV' */ | ||
775 | GNUNET_CRYPTO_hkdf (&neighbor->real_session_id, sizeof (struct GNUNET_HashCode), | ||
776 | GCRY_MD_SHA512, GCRY_MD_SHA256, | ||
777 | "DV-SALT", 2, | ||
778 | &session_id, sizeof (session_id), | ||
779 | NULL, 0); | ||
780 | if (0 < memcmp (&neighbor->peer, | ||
781 | &my_identity, | ||
782 | sizeof (struct GNUNET_PeerIdentity))) | ||
783 | { | ||
784 | if (NULL != neighbor->listen_handle) | ||
785 | { | ||
786 | GNUNET_break (0); | ||
787 | } | ||
788 | else | ||
789 | neighbor->initiate_task = GNUNET_SCHEDULER_add_now (&initiate_set_union, | ||
790 | neighbor); | ||
791 | } | ||
792 | else | ||
793 | { | ||
794 | if (NULL != neighbor->listen_handle) | ||
795 | { | ||
796 | GNUNET_break (0); | ||
797 | } | ||
798 | else | ||
799 | { | ||
800 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
801 | "Starting SET listen operation with peer `%s'\n", | ||
802 | GNUNET_i2s (&neighbor->peer)); | ||
803 | neighbor->listen_handle = GNUNET_SET_listen (cfg, | ||
804 | GNUNET_SET_OPERATION_UNION, | ||
805 | &neighbor->real_session_id, | ||
806 | &listen_set_union, | ||
807 | neighbor); | ||
808 | } | ||
809 | } | ||
810 | } | ||
811 | |||
812 | |||
813 | /** | ||
814 | * Method called whenever a peer connects. | ||
815 | * | ||
816 | * @param cls closure | ||
817 | * @param peer peer identity this notification is about | ||
818 | * @param mq message queue for sending data to @a peer | ||
819 | * @return our `struct DirectNeighbour` for this peer | ||
820 | */ | ||
821 | static void * | ||
822 | handle_core_connect (void *cls, | ||
823 | const struct GNUNET_PeerIdentity *peer, | ||
824 | struct GNUNET_MQ_Handle *mq) | ||
825 | { | ||
826 | struct DirectNeighbor *neighbor; | ||
827 | |||
828 | /* Check for connect to self message */ | ||
829 | if (0 == memcmp (&my_identity, | ||
830 | peer, | ||
831 | sizeof (struct GNUNET_PeerIdentity))) | ||
832 | return NULL; | ||
833 | /* check if entry exists */ | ||
834 | neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors, | ||
835 | peer); | ||
836 | if (NULL != neighbor) | ||
837 | { | ||
838 | GNUNET_break (GNUNET_NT_UNSPECIFIED != neighbor->network); | ||
839 | GNUNET_break (GNUNET_YES != neighbor->connected); | ||
840 | neighbor->connected = GNUNET_YES; | ||
841 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
842 | "Core connected to %s (distance %u)\n", | ||
843 | GNUNET_i2s (peer), | ||
844 | (unsigned int) neighbor->distance); | ||
845 | if (DIRECT_NEIGHBOR_COST != neighbor->distance) | ||
846 | return NULL; | ||
847 | handle_direct_connect (neighbor); | ||
848 | return NULL; | ||
849 | } | ||
850 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
851 | "Core connected to %s (distance unknown)\n", | ||
852 | GNUNET_i2s (peer)); | ||
853 | neighbor = GNUNET_new (struct DirectNeighbor); | ||
854 | neighbor->peer = *peer; | ||
855 | GNUNET_assert (GNUNET_YES == | ||
856 | GNUNET_CONTAINER_multipeermap_put (direct_neighbors, | ||
857 | &neighbor->peer, | ||
858 | neighbor, | ||
859 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
860 | neighbor->connected = GNUNET_YES; | ||
861 | neighbor->distance = 0; /* unknown */ | ||
862 | neighbor->network = GNUNET_NT_UNSPECIFIED; | ||
863 | return neighbor; | ||
864 | } | ||
865 | |||
866 | |||
867 | /** | ||
868 | * Called for each 'target' in a neighbor table to free the associated memory. | ||
869 | * | ||
870 | * @param cls NULL | ||
871 | * @param key key of the value | ||
872 | * @param value value to free | ||
873 | * @return #GNUNET_OK to continue to iterate | ||
874 | */ | ||
875 | static int | ||
876 | free_targets (void *cls, | ||
877 | const struct GNUNET_PeerIdentity *key, | ||
878 | void *value) | ||
879 | { | ||
880 | GNUNET_free (value); | ||
881 | return GNUNET_OK; | ||
882 | } | ||
883 | |||
884 | |||
885 | /** | ||
886 | * Add a new route to the given @a target via the given @a neighbor. | ||
887 | * | ||
888 | * @param target the target of the route | ||
889 | * @param neighbor the next hop for communicating with the @a target | ||
890 | */ | ||
891 | static void | ||
892 | add_new_route (struct Target *target, | ||
893 | struct DirectNeighbor *neighbor) | ||
894 | { | ||
895 | struct Route *route; | ||
896 | |||
897 | route = GNUNET_new (struct Route); | ||
898 | route->next_hop = neighbor; | ||
899 | route->target.peer = target->peer; | ||
900 | allocate_route (route, ntohl (target->distance) + 1); | ||
901 | GNUNET_assert (GNUNET_YES == | ||
902 | GNUNET_CONTAINER_multipeermap_put (all_routes, | ||
903 | &route->target.peer, | ||
904 | route, | ||
905 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
906 | send_connect_to_plugin (&route->target.peer, | ||
907 | ntohl (route->target.distance), | ||
908 | neighbor->network); | ||
909 | } | ||
910 | |||
911 | |||
912 | /** | ||
913 | * Multipeerhmap iterator for checking if a given route is | ||
914 | * (now) useful to this peer. | ||
915 | * | ||
916 | * @param cls the direct neighbor for the given route | ||
917 | * @param key key value stored under | ||
918 | * @param value a 'struct Target' that may or may not be useful; not that | ||
919 | * the distance in 'target' does not include the first hop yet | ||
920 | * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop | ||
921 | */ | ||
922 | static int | ||
923 | check_possible_route (void *cls, | ||
924 | const struct GNUNET_PeerIdentity *key, | ||
925 | void *value) | ||
926 | { | ||
927 | struct DirectNeighbor *neighbor = cls; | ||
928 | struct Target *target = value; | ||
929 | struct Route *route; | ||
930 | |||
931 | if (GNUNET_YES == | ||
932 | GNUNET_CONTAINER_multipeermap_contains (direct_neighbors, | ||
933 | key)) | ||
934 | return GNUNET_YES; /* direct route, do not care about alternatives */ | ||
935 | route = GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
936 | key); | ||
937 | if (NULL != route) | ||
938 | { | ||
939 | /* we have an existing route, check how it compares with going via 'target' */ | ||
940 | if (ntohl (route->target.distance) > ntohl (target->distance) + 1) | ||
941 | { | ||
942 | /* via 'target' is cheaper than the existing route; switch to alternative route! */ | ||
943 | move_route (route, ntohl (target->distance) + 1); | ||
944 | route->next_hop = neighbor; | ||
945 | send_distance_change_to_plugin (&target->peer, | ||
946 | ntohl (target->distance) + 1, | ||
947 | neighbor->network); | ||
948 | } | ||
949 | return GNUNET_YES; /* got a route to this target already */ | ||
950 | } | ||
951 | if (ntohl (target->distance) >= DEFAULT_FISHEYE_DEPTH) | ||
952 | return GNUNET_YES; /* distance is too large to be interesting */ | ||
953 | add_new_route (target, neighbor); | ||
954 | return GNUNET_YES; | ||
955 | } | ||
956 | |||
957 | |||
958 | /** | ||
959 | * Multipeermap iterator for finding routes that were previously | ||
960 | * "hidden" due to a better route (called after a disconnect event). | ||
961 | * | ||
962 | * @param cls NULL | ||
963 | * @param key peer identity of the given direct neighbor | ||
964 | * @param value a `struct DirectNeighbor` to check for additional routes | ||
965 | * @return #GNUNET_YES to continue iteration | ||
966 | */ | ||
967 | static int | ||
968 | refresh_routes (void *cls, | ||
969 | const struct GNUNET_PeerIdentity *key, | ||
970 | void *value) | ||
971 | { | ||
972 | struct DirectNeighbor *neighbor = value; | ||
973 | |||
974 | if ( (GNUNET_YES != neighbor->connected) || | ||
975 | (DIRECT_NEIGHBOR_COST != neighbor->distance) ) | ||
976 | return GNUNET_YES; | ||
977 | if (NULL != neighbor->neighbor_table) | ||
978 | GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table, | ||
979 | &check_possible_route, | ||
980 | neighbor); | ||
981 | return GNUNET_YES; | ||
982 | } | ||
983 | |||
984 | |||
985 | /** | ||
986 | * Task to run #refresh_routes() on all direct neighbours. | ||
987 | * | ||
988 | * @param cls NULL | ||
989 | */ | ||
990 | static void | ||
991 | refresh_routes_task (void *cls) | ||
992 | { | ||
993 | rr_task = NULL; | ||
994 | GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors, | ||
995 | &refresh_routes, | ||
996 | NULL); | ||
997 | } | ||
998 | |||
999 | |||
1000 | /** | ||
1001 | * Asynchronously run #refresh_routes() at the next opportunity | ||
1002 | * on all direct neighbours. | ||
1003 | */ | ||
1004 | static void | ||
1005 | schedule_refresh_routes () | ||
1006 | { | ||
1007 | if (NULL == rr_task) | ||
1008 | rr_task = GNUNET_SCHEDULER_add_now (&refresh_routes_task, | ||
1009 | NULL); | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | /** | ||
1014 | * Multipeermap iterator for freeing routes that go via a particular | ||
1015 | * neighbor that disconnected and is thus no longer available. | ||
1016 | * | ||
1017 | * @param cls the direct neighbor that is now unavailable | ||
1018 | * @param key key value stored under | ||
1019 | * @param value a `struct Route` that may or may not go via neighbor | ||
1020 | * | ||
1021 | * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop | ||
1022 | */ | ||
1023 | static int | ||
1024 | cull_routes (void *cls, | ||
1025 | const struct GNUNET_PeerIdentity *key, | ||
1026 | void *value) | ||
1027 | { | ||
1028 | struct DirectNeighbor *neighbor = cls; | ||
1029 | struct Route *route = value; | ||
1030 | |||
1031 | if (route->next_hop != neighbor) | ||
1032 | return GNUNET_YES; /* not affected */ | ||
1033 | GNUNET_assert (GNUNET_YES == | ||
1034 | GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value)); | ||
1035 | release_route (route); | ||
1036 | send_disconnect_to_plugin (&route->target.peer); | ||
1037 | GNUNET_free (route); | ||
1038 | return GNUNET_YES; | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | /** | ||
1043 | * Handle the case that a direct connection to a peer is | ||
1044 | * disrupted. Remove all routes via that peer and | ||
1045 | * stop the consensus with it. | ||
1046 | * | ||
1047 | * @param neighbor peer that was disconnected (or at least is no | ||
1048 | * longer at distance 1) | ||
1049 | */ | ||
1050 | static void | ||
1051 | handle_direct_disconnect (struct DirectNeighbor *neighbor) | ||
1052 | { | ||
1053 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1054 | "Culling routes via %s due to direct disconnect\n", | ||
1055 | GNUNET_i2s (&neighbor->peer)); | ||
1056 | GNUNET_CONTAINER_multipeermap_iterate (all_routes, | ||
1057 | &cull_routes, | ||
1058 | neighbor); | ||
1059 | if (NULL != neighbor->direct_route) | ||
1060 | { | ||
1061 | release_route (neighbor->direct_route); | ||
1062 | GNUNET_free (neighbor->direct_route); | ||
1063 | neighbor->direct_route = NULL; | ||
1064 | } | ||
1065 | if (NULL != neighbor->neighbor_table_consensus) | ||
1066 | { | ||
1067 | GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus, | ||
1068 | &free_targets, | ||
1069 | NULL); | ||
1070 | GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus); | ||
1071 | neighbor->neighbor_table_consensus = NULL; | ||
1072 | } | ||
1073 | if (NULL != neighbor->neighbor_table) | ||
1074 | { | ||
1075 | GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table, | ||
1076 | &free_targets, | ||
1077 | NULL); | ||
1078 | GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table); | ||
1079 | neighbor->neighbor_table = NULL; | ||
1080 | } | ||
1081 | if (NULL != neighbor->set_op) | ||
1082 | { | ||
1083 | GNUNET_SET_operation_cancel (neighbor->set_op); | ||
1084 | neighbor->set_op = NULL; | ||
1085 | } | ||
1086 | if (NULL != neighbor->my_set) | ||
1087 | { | ||
1088 | GNUNET_SET_destroy (neighbor->my_set); | ||
1089 | neighbor->my_set = NULL; | ||
1090 | } | ||
1091 | if (NULL != neighbor->listen_handle) | ||
1092 | { | ||
1093 | GNUNET_SET_listen_cancel (neighbor->listen_handle); | ||
1094 | neighbor->listen_handle = NULL; | ||
1095 | } | ||
1096 | if (NULL != neighbor->initiate_task) | ||
1097 | { | ||
1098 | GNUNET_SCHEDULER_cancel (neighbor->initiate_task); | ||
1099 | neighbor->initiate_task = NULL; | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | |||
1104 | /** | ||
1105 | * Function that is called with QoS information about an address; used | ||
1106 | * to update our current distance to another peer. | ||
1107 | * | ||
1108 | * @param cls closure | ||
1109 | * @param address the address | ||
1110 | * @param active #GNUNET_YES if this address is actively used | ||
1111 | * to maintain a connection to a peer; | ||
1112 | * #GNUNET_NO if the address is not actively used; | ||
1113 | * #GNUNET_SYSERR if this address is no longer available for ATS | ||
1114 | * @param bandwidth_out assigned outbound bandwidth for the connection | ||
1115 | * @param bandwidth_in assigned inbound bandwidth for the connection | ||
1116 | * @param prop performance data for the address (as far as known) | ||
1117 | */ | ||
1118 | static void | ||
1119 | handle_ats_update (void *cls, | ||
1120 | const struct GNUNET_HELLO_Address *address, | ||
1121 | int active, | ||
1122 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out, | ||
1123 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
1124 | const struct GNUNET_ATS_Properties *prop) | ||
1125 | { | ||
1126 | struct DirectNeighbor *neighbor; | ||
1127 | uint32_t distance; | ||
1128 | enum GNUNET_NetworkType network; | ||
1129 | |||
1130 | if (NULL == address) | ||
1131 | { | ||
1132 | /* ATS service temporarily disconnected */ | ||
1133 | return; | ||
1134 | } | ||
1135 | |||
1136 | if (GNUNET_YES != active) | ||
1137 | { | ||
1138 | // FIXME: handle disconnect/inactive case too! | ||
1139 | return; | ||
1140 | } | ||
1141 | distance = prop->distance; | ||
1142 | network = prop->scope; | ||
1143 | GNUNET_break (GNUNET_NT_UNSPECIFIED != network); | ||
1144 | /* check if entry exists */ | ||
1145 | neighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors, | ||
1146 | &address->peer); | ||
1147 | if (NULL != neighbor) | ||
1148 | { | ||
1149 | neighbor->network = network; | ||
1150 | if (neighbor->distance == distance) | ||
1151 | return; /* nothing new to see here, move along */ | ||
1152 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1153 | "ATS says distance to %s is now %u\n", | ||
1154 | GNUNET_i2s (&address->peer), | ||
1155 | (unsigned int) distance); | ||
1156 | if ( (DIRECT_NEIGHBOR_COST == neighbor->distance) && | ||
1157 | (DIRECT_NEIGHBOR_COST == distance) ) | ||
1158 | return; /* no change */ | ||
1159 | if (DIRECT_NEIGHBOR_COST == neighbor->distance) | ||
1160 | { | ||
1161 | neighbor->distance = distance; | ||
1162 | GNUNET_STATISTICS_update (stats, | ||
1163 | "# peers connected (1-hop)", | ||
1164 | -1, GNUNET_NO); | ||
1165 | handle_direct_disconnect (neighbor); | ||
1166 | schedule_refresh_routes (); | ||
1167 | return; | ||
1168 | } | ||
1169 | neighbor->distance = distance; | ||
1170 | if (DIRECT_NEIGHBOR_COST != neighbor->distance) | ||
1171 | return; | ||
1172 | if (GNUNET_YES != neighbor->connected) | ||
1173 | return; | ||
1174 | handle_direct_connect (neighbor); | ||
1175 | return; | ||
1176 | } | ||
1177 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1178 | "ATS says distance to %s is now %u\n", | ||
1179 | GNUNET_i2s (&address->peer), | ||
1180 | (unsigned int) distance); | ||
1181 | neighbor = GNUNET_new (struct DirectNeighbor); | ||
1182 | neighbor->peer = address->peer; | ||
1183 | GNUNET_assert (GNUNET_YES == | ||
1184 | GNUNET_CONTAINER_multipeermap_put (direct_neighbors, | ||
1185 | &neighbor->peer, | ||
1186 | neighbor, | ||
1187 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1188 | neighbor->connected = GNUNET_NO; /* not yet */ | ||
1189 | neighbor->distance = distance; | ||
1190 | neighbor->network = network; | ||
1191 | } | ||
1192 | |||
1193 | |||
1194 | /** | ||
1195 | * Check if a target was removed from the set of the other peer; if so, | ||
1196 | * if we also used it for our route, we need to remove it from our | ||
1197 | * 'all_routes' set (and later check if an alternative path now exists). | ||
1198 | * | ||
1199 | * @param cls the `struct DirectNeighbor` | ||
1200 | * @param key peer identity for the target | ||
1201 | * @param value a `struct Target` previously reachable via the given neighbor | ||
1202 | */ | ||
1203 | static int | ||
1204 | check_target_removed (void *cls, | ||
1205 | const struct GNUNET_PeerIdentity *key, | ||
1206 | void *value) | ||
1207 | { | ||
1208 | struct DirectNeighbor *neighbor = cls; | ||
1209 | struct Target *new_target; | ||
1210 | struct Route *current_route; | ||
1211 | |||
1212 | new_target = GNUNET_CONTAINER_multipeermap_get (neighbor->neighbor_table_consensus, | ||
1213 | key); | ||
1214 | current_route = GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
1215 | key); | ||
1216 | if (NULL != new_target) | ||
1217 | { | ||
1218 | /* target was in old set, is in new set */ | ||
1219 | if ( (NULL != current_route) && | ||
1220 | (current_route->next_hop == neighbor) && | ||
1221 | (current_route->target.distance != new_target->distance) ) | ||
1222 | { | ||
1223 | /* need to recalculate routes due to distance change */ | ||
1224 | neighbor->target_removed = GNUNET_YES; | ||
1225 | } | ||
1226 | return GNUNET_OK; | ||
1227 | } | ||
1228 | /* target was revoked, check if it was used */ | ||
1229 | if ( (NULL == current_route) || | ||
1230 | (current_route->next_hop != neighbor) ) | ||
1231 | { | ||
1232 | /* didn't matter, wasn't used */ | ||
1233 | return GNUNET_OK; | ||
1234 | } | ||
1235 | /* remove existing route */ | ||
1236 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1237 | "Lost route to %s\n", | ||
1238 | GNUNET_i2s (¤t_route->target.peer)); | ||
1239 | GNUNET_assert (GNUNET_YES == | ||
1240 | GNUNET_CONTAINER_multipeermap_remove (all_routes, key, current_route)); | ||
1241 | send_disconnect_to_plugin (¤t_route->target.peer); | ||
1242 | release_route (current_route); | ||
1243 | GNUNET_free (current_route); | ||
1244 | neighbor->target_removed = GNUNET_YES; | ||
1245 | return GNUNET_OK; | ||
1246 | } | ||
1247 | |||
1248 | |||
1249 | /** | ||
1250 | * Check if a target was added to the set of the other peer; if it | ||
1251 | * was added or impoves the existing route, do the needed updates. | ||
1252 | * | ||
1253 | * @param cls the `struct DirectNeighbor` | ||
1254 | * @param key peer identity for the target | ||
1255 | * @param value a `struct Target` now reachable via the given neighbor | ||
1256 | */ | ||
1257 | static int | ||
1258 | check_target_added (void *cls, | ||
1259 | const struct GNUNET_PeerIdentity *key, | ||
1260 | void *value) | ||
1261 | { | ||
1262 | struct DirectNeighbor *neighbor = cls; | ||
1263 | struct Target *target = value; | ||
1264 | struct Route *current_route; | ||
1265 | |||
1266 | /* target was revoked, check if it was used */ | ||
1267 | current_route = GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
1268 | key); | ||
1269 | if (NULL != current_route) | ||
1270 | { | ||
1271 | /* route exists */ | ||
1272 | if (current_route->next_hop == neighbor) | ||
1273 | { | ||
1274 | /* we had the same route before, no change in target */ | ||
1275 | if (ntohl (target->distance) + 1 != ntohl (current_route->target.distance)) | ||
1276 | { | ||
1277 | /* but distance changed! */ | ||
1278 | if (ntohl (target->distance) + 1 > DEFAULT_FISHEYE_DEPTH) | ||
1279 | { | ||
1280 | /* distance increased beyond what is allowed, kill route */ | ||
1281 | GNUNET_assert (GNUNET_YES == | ||
1282 | GNUNET_CONTAINER_multipeermap_remove (all_routes, | ||
1283 | key, | ||
1284 | current_route)); | ||
1285 | send_disconnect_to_plugin (key); | ||
1286 | release_route (current_route); | ||
1287 | GNUNET_free (current_route); | ||
1288 | } | ||
1289 | else | ||
1290 | { | ||
1291 | /* distance decreased, update route */ | ||
1292 | move_route (current_route, | ||
1293 | ntohl (target->distance) + 1); | ||
1294 | send_distance_change_to_plugin (&target->peer, | ||
1295 | ntohl (target->distance) + 1, | ||
1296 | neighbor->network); | ||
1297 | } | ||
1298 | } | ||
1299 | return GNUNET_OK; | ||
1300 | } | ||
1301 | if (ntohl (current_route->target.distance) <= ntohl (target->distance) + 1) | ||
1302 | { | ||
1303 | /* alternative, shorter route exists, ignore */ | ||
1304 | return GNUNET_OK; | ||
1305 | } | ||
1306 | /* new route is better than the existing one, take over! */ | ||
1307 | /* NOTE: minor security issue: malicious peers may advertise | ||
1308 | very short routes to take over longer paths; as we don't | ||
1309 | check that the shorter routes actually work, a malicious | ||
1310 | direct neighbor can use this to DoS our long routes */ | ||
1311 | |||
1312 | move_route (current_route, ntohl (target->distance) + 1); | ||
1313 | current_route->next_hop = neighbor; | ||
1314 | send_distance_change_to_plugin (&target->peer, | ||
1315 | ntohl (target->distance) + 1, | ||
1316 | neighbor->network); | ||
1317 | return GNUNET_OK; | ||
1318 | } | ||
1319 | /* new route */ | ||
1320 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1321 | "Discovered new route to %s using %u hops\n", | ||
1322 | GNUNET_i2s (&target->peer), | ||
1323 | (unsigned int) (ntohl (target->distance) + 1)); | ||
1324 | current_route = GNUNET_new (struct Route); | ||
1325 | current_route->next_hop = neighbor; | ||
1326 | current_route->target.peer = target->peer; | ||
1327 | allocate_route (current_route, ntohl (target->distance) + 1); | ||
1328 | GNUNET_assert (GNUNET_YES == | ||
1329 | GNUNET_CONTAINER_multipeermap_put (all_routes, | ||
1330 | ¤t_route->target.peer, | ||
1331 | current_route, | ||
1332 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1333 | |||
1334 | send_connect_to_plugin (¤t_route->target.peer, | ||
1335 | ntohl (current_route->target.distance), | ||
1336 | neighbor->network); | ||
1337 | return GNUNET_OK; | ||
1338 | } | ||
1339 | |||
1340 | |||
1341 | /** | ||
1342 | * Callback for set operation results. Called for each element | ||
1343 | * in the result set. | ||
1344 | * We have learned a new route from the other peer. Add it to the | ||
1345 | * route set we're building. | ||
1346 | * | ||
1347 | * @param cls the `struct DirectNeighbor` we're building the consensus with | ||
1348 | * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK | ||
1349 | * @param current_size current set size | ||
1350 | * @param status see `enum GNUNET_SET_Status` | ||
1351 | */ | ||
1352 | static void | ||
1353 | handle_set_union_result (void *cls, | ||
1354 | const struct GNUNET_SET_Element *element, | ||
1355 | uint64_t current_size, | ||
1356 | enum GNUNET_SET_Status status) | ||
1357 | { | ||
1358 | struct DirectNeighbor *neighbor = cls; | ||
1359 | struct DirectNeighbor *dn; | ||
1360 | struct Target *target; | ||
1361 | const struct Target *ctarget; | ||
1362 | char *status_str; | ||
1363 | |||
1364 | switch (status) | ||
1365 | { | ||
1366 | case GNUNET_SET_STATUS_OK: | ||
1367 | status_str = "GNUNET_SET_STATUS_OK"; | ||
1368 | break; | ||
1369 | case GNUNET_SET_STATUS_FAILURE: | ||
1370 | status_str = "GNUNET_SET_STATUS_FAILURE"; | ||
1371 | break; | ||
1372 | case GNUNET_SET_STATUS_HALF_DONE: | ||
1373 | status_str = "GNUNET_SET_STATUS_HALF_DONE"; | ||
1374 | break; | ||
1375 | case GNUNET_SET_STATUS_DONE: | ||
1376 | status_str = "GNUNET_SET_STATUS_DONE"; | ||
1377 | break; | ||
1378 | default: | ||
1379 | status_str = "UNDEFINED"; | ||
1380 | break; | ||
1381 | } | ||
1382 | |||
1383 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1384 | "Got SET union result: %s\n", | ||
1385 | status_str); | ||
1386 | switch (status) | ||
1387 | { | ||
1388 | case GNUNET_SET_STATUS_OK: | ||
1389 | if (sizeof (struct Target) != element->size) | ||
1390 | { | ||
1391 | GNUNET_break_op (0); | ||
1392 | return; | ||
1393 | } | ||
1394 | ctarget = element->data; | ||
1395 | if ( (NULL != | ||
1396 | (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors, | ||
1397 | &ctarget->peer))) && | ||
1398 | (DIRECT_NEIGHBOR_COST == dn->distance) ) | ||
1399 | { | ||
1400 | /* this is a direct neighbor of ours, we do not care about routes | ||
1401 | to this peer */ | ||
1402 | return; | ||
1403 | } | ||
1404 | target = GNUNET_new (struct Target); | ||
1405 | GNUNET_memcpy (target, element->data, sizeof (struct Target)); | ||
1406 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1407 | "Received information about peer `%s' with distance %u from SET\n", | ||
1408 | GNUNET_i2s (&target->peer), | ||
1409 | ntohl (target->distance) + 1); | ||
1410 | |||
1411 | if (NULL == neighbor->neighbor_table_consensus) | ||
1412 | neighbor->neighbor_table_consensus | ||
1413 | = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO); | ||
1414 | if (GNUNET_YES != | ||
1415 | GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table_consensus, | ||
1416 | &target->peer, | ||
1417 | target, | ||
1418 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1419 | { | ||
1420 | GNUNET_break_op (0); | ||
1421 | GNUNET_free (target); | ||
1422 | } | ||
1423 | break; | ||
1424 | case GNUNET_SET_STATUS_FAILURE: | ||
1425 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1426 | "Failed to establish DV union, will try again later\n"); | ||
1427 | neighbor->set_op = NULL; | ||
1428 | if (NULL != neighbor->neighbor_table_consensus) | ||
1429 | { | ||
1430 | GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus, | ||
1431 | &free_targets, | ||
1432 | NULL); | ||
1433 | GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table_consensus); | ||
1434 | neighbor->neighbor_table_consensus = NULL; | ||
1435 | } | ||
1436 | if (0 < memcmp (&neighbor->peer, | ||
1437 | &my_identity, | ||
1438 | sizeof (struct GNUNET_PeerIdentity))) | ||
1439 | neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY, | ||
1440 | &initiate_set_union, | ||
1441 | neighbor); | ||
1442 | break; | ||
1443 | case GNUNET_SET_STATUS_HALF_DONE: | ||
1444 | break; | ||
1445 | case GNUNET_SET_STATUS_DONE: | ||
1446 | /* we got all of our updates; integrate routing table! */ | ||
1447 | neighbor->target_removed = GNUNET_NO; | ||
1448 | if (NULL == neighbor->neighbor_table_consensus) | ||
1449 | neighbor->neighbor_table_consensus = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO); | ||
1450 | if (NULL != neighbor->neighbor_table) | ||
1451 | GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table, | ||
1452 | &check_target_removed, | ||
1453 | neighbor); | ||
1454 | if (GNUNET_YES == neighbor->target_removed) | ||
1455 | { | ||
1456 | /* check if we got an alternative for the removed routes */ | ||
1457 | schedule_refresh_routes (); | ||
1458 | } | ||
1459 | /* add targets that appeared (and check for improved routes) */ | ||
1460 | GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table_consensus, | ||
1461 | &check_target_added, | ||
1462 | neighbor); | ||
1463 | if (NULL != neighbor->neighbor_table) | ||
1464 | { | ||
1465 | GNUNET_CONTAINER_multipeermap_iterate (neighbor->neighbor_table, | ||
1466 | &free_targets, | ||
1467 | NULL); | ||
1468 | GNUNET_CONTAINER_multipeermap_destroy (neighbor->neighbor_table); | ||
1469 | neighbor->neighbor_table = NULL; | ||
1470 | } | ||
1471 | neighbor->neighbor_table = neighbor->neighbor_table_consensus; | ||
1472 | neighbor->neighbor_table_consensus = NULL; | ||
1473 | |||
1474 | /* operation done, schedule next run! */ | ||
1475 | neighbor->set_op = NULL; | ||
1476 | if (0 < memcmp (&neighbor->peer, | ||
1477 | &my_identity, | ||
1478 | sizeof (struct GNUNET_PeerIdentity))) | ||
1479 | neighbor->initiate_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY, | ||
1480 | &initiate_set_union, | ||
1481 | neighbor); | ||
1482 | break; | ||
1483 | default: | ||
1484 | GNUNET_break (0); | ||
1485 | return; | ||
1486 | } | ||
1487 | } | ||
1488 | |||
1489 | |||
1490 | /** | ||
1491 | * Start creating a new DV set union construction, our neighbour has | ||
1492 | * asked for it (callback for listening peer). | ||
1493 | * | ||
1494 | * @param cls the 'struct DirectNeighbor' of the peer we're building | ||
1495 | * a routing consensus with | ||
1496 | * @param other_peer the other peer | ||
1497 | * @param context_msg message with application specific information from | ||
1498 | * the other peer | ||
1499 | * @param request request from the other peer, use GNUNET_SET_accept | ||
1500 | * to accept it, otherwise the request will be refused | ||
1501 | * Note that we don't use a return value here, as it is also | ||
1502 | * necessary to specify the set we want to do the operation with, | ||
1503 | * whith sometimes can be derived from the context message. | ||
1504 | * Also necessary to specify the timeout. | ||
1505 | */ | ||
1506 | static void | ||
1507 | listen_set_union (void *cls, | ||
1508 | const struct GNUNET_PeerIdentity *other_peer, | ||
1509 | const struct GNUNET_MessageHeader *context_msg, | ||
1510 | struct GNUNET_SET_Request *request) | ||
1511 | { | ||
1512 | struct DirectNeighbor *neighbor = cls; | ||
1513 | |||
1514 | if (NULL == request) | ||
1515 | return; /* why??? */ | ||
1516 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1517 | "Starting to create consensus with %s\n", | ||
1518 | GNUNET_i2s (&neighbor->peer)); | ||
1519 | if (NULL != neighbor->set_op) | ||
1520 | { | ||
1521 | GNUNET_SET_operation_cancel (neighbor->set_op); | ||
1522 | neighbor->set_op = NULL; | ||
1523 | } | ||
1524 | if (NULL != neighbor->my_set) | ||
1525 | { | ||
1526 | GNUNET_SET_destroy (neighbor->my_set); | ||
1527 | neighbor->my_set = NULL; | ||
1528 | } | ||
1529 | neighbor->my_set = GNUNET_SET_create (cfg, | ||
1530 | GNUNET_SET_OPERATION_UNION); | ||
1531 | neighbor->set_op = GNUNET_SET_accept (request, | ||
1532 | GNUNET_SET_RESULT_ADDED, | ||
1533 | (struct GNUNET_SET_Option[]) {{ 0 }}, | ||
1534 | &handle_set_union_result, | ||
1535 | neighbor); | ||
1536 | neighbor->consensus_insertion_offset = 0; | ||
1537 | neighbor->consensus_insertion_distance = 0; | ||
1538 | neighbor->consensus_elements = 0; | ||
1539 | build_set (neighbor); | ||
1540 | } | ||
1541 | |||
1542 | |||
1543 | /** | ||
1544 | * Start creating a new DV set union by initiating the connection. | ||
1545 | * | ||
1546 | * @param cls the `struct DirectNeighbor *` of the peer we're building | ||
1547 | * a routing consensus with | ||
1548 | */ | ||
1549 | static void | ||
1550 | initiate_set_union (void *cls) | ||
1551 | { | ||
1552 | struct DirectNeighbor *neighbor = cls; | ||
1553 | |||
1554 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1555 | "Initiating SET union with peer `%s'\n", | ||
1556 | GNUNET_i2s (&neighbor->peer)); | ||
1557 | neighbor->initiate_task = NULL; | ||
1558 | neighbor->my_set = GNUNET_SET_create (cfg, | ||
1559 | GNUNET_SET_OPERATION_UNION); | ||
1560 | neighbor->set_op = GNUNET_SET_prepare (&neighbor->peer, | ||
1561 | &neighbor->real_session_id, | ||
1562 | NULL, | ||
1563 | GNUNET_SET_RESULT_ADDED, | ||
1564 | (struct GNUNET_SET_Option[]) {{ 0 }}, | ||
1565 | &handle_set_union_result, | ||
1566 | neighbor); | ||
1567 | neighbor->consensus_insertion_offset = 0; | ||
1568 | neighbor->consensus_insertion_distance = 0; | ||
1569 | neighbor->consensus_elements = 0; | ||
1570 | build_set (neighbor); | ||
1571 | } | ||
1572 | |||
1573 | |||
1574 | /** | ||
1575 | * Check that @a rm is well-formed. | ||
1576 | * | ||
1577 | * @param cls closure | ||
1578 | * @param rm the message | ||
1579 | * @return #GNUNET_OK if @a rm is well-formed. | ||
1580 | */ | ||
1581 | static int | ||
1582 | check_dv_route_message (void *cls, | ||
1583 | const struct RouteMessage *rm) | ||
1584 | { | ||
1585 | const struct GNUNET_MessageHeader *payload; | ||
1586 | |||
1587 | if (ntohs (rm->header.size) < sizeof (struct RouteMessage) + sizeof (struct GNUNET_MessageHeader)) | ||
1588 | { | ||
1589 | GNUNET_break_op (0); | ||
1590 | return GNUNET_SYSERR; | ||
1591 | } | ||
1592 | payload = (const struct GNUNET_MessageHeader *) &rm[1]; | ||
1593 | if (ntohs (rm->header.size) != sizeof (struct RouteMessage) + ntohs (payload->size)) | ||
1594 | { | ||
1595 | GNUNET_break_op (0); | ||
1596 | return GNUNET_SYSERR; | ||
1597 | } | ||
1598 | return GNUNET_OK; | ||
1599 | } | ||
1600 | |||
1601 | |||
1602 | /** | ||
1603 | * Core handler for DV data messages. Whatever this message | ||
1604 | * contains all we really have to do is rip it out of its | ||
1605 | * DV layering and give it to our pal the DV plugin to report | ||
1606 | * in with. | ||
1607 | * | ||
1608 | * @param cls closure | ||
1609 | * @param rm the message | ||
1610 | */ | ||
1611 | static void | ||
1612 | handle_dv_route_message (void *cls, | ||
1613 | const struct RouteMessage *rm) | ||
1614 | { | ||
1615 | struct DirectNeighbor *neighbor = cls; | ||
1616 | const struct GNUNET_MessageHeader *payload; | ||
1617 | struct Route *route; | ||
1618 | struct DirectNeighbor *nneighbor; | ||
1619 | struct DirectNeighbor *dn; | ||
1620 | struct Target *target; | ||
1621 | uint32_t distance; | ||
1622 | char me[5]; | ||
1623 | char src[5]; | ||
1624 | char prev[5]; | ||
1625 | char dst[5]; | ||
1626 | |||
1627 | distance = ntohl (rm->distance); | ||
1628 | payload = (const struct GNUNET_MessageHeader *) &rm[1]; | ||
1629 | strncpy (prev, GNUNET_i2s (&neighbor->peer), 4); | ||
1630 | strncpy (me, GNUNET_i2s (&my_identity), 4); | ||
1631 | strncpy (src, GNUNET_i2s (&rm->sender), 4); | ||
1632 | strncpy (dst, GNUNET_i2s (&rm->target), 4); | ||
1633 | prev[4] = me[4] = src[4] = dst[4] = '\0'; | ||
1634 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1635 | "Handling DV message with %u bytes payload of type %u from %s to %s routed by %s to me (%s @ hop %u)\n", | ||
1636 | (unsigned int) (ntohs (rm->header.size) - sizeof (struct RouteMessage)), | ||
1637 | ntohs (payload->type), | ||
1638 | src, | ||
1639 | dst, | ||
1640 | prev, | ||
1641 | me, | ||
1642 | (unsigned int) distance + 1); | ||
1643 | |||
1644 | if (0 == memcmp (&rm->target, | ||
1645 | &my_identity, | ||
1646 | sizeof (struct GNUNET_PeerIdentity))) | ||
1647 | { | ||
1648 | if ((NULL != | ||
1649 | (dn = GNUNET_CONTAINER_multipeermap_get (direct_neighbors, | ||
1650 | &rm->sender))) && | ||
1651 | (DIRECT_NEIGHBOR_COST == dn->distance)) | ||
1652 | { | ||
1653 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1654 | "Discarding DV message, as %s is a direct neighbor\n", | ||
1655 | GNUNET_i2s (&rm->sender)); | ||
1656 | GNUNET_STATISTICS_update (stats, | ||
1657 | "# messages discarded (direct neighbor)", | ||
1658 | 1, GNUNET_NO); | ||
1659 | return; | ||
1660 | } | ||
1661 | /* message is for me, check reverse route! */ | ||
1662 | route = GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
1663 | &rm->sender); | ||
1664 | if ( (NULL == route) && | ||
1665 | (distance < DEFAULT_FISHEYE_DEPTH) ) | ||
1666 | { | ||
1667 | /* don't have reverse route yet, learn it! */ | ||
1668 | target = GNUNET_new (struct Target); | ||
1669 | target->peer = rm->sender; | ||
1670 | target->distance = htonl (distance); | ||
1671 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1672 | "Learning sender %s at distance %u from delivery!\n", | ||
1673 | GNUNET_i2s (&rm->sender), | ||
1674 | (unsigned int) distance + 1); | ||
1675 | if (NULL == neighbor->neighbor_table) | ||
1676 | neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO); | ||
1677 | if (GNUNET_YES != | ||
1678 | GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table, | ||
1679 | &target->peer, | ||
1680 | target, | ||
1681 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1682 | { | ||
1683 | GNUNET_break_op (0); | ||
1684 | GNUNET_free (target); | ||
1685 | return; | ||
1686 | } | ||
1687 | add_new_route (target, neighbor); | ||
1688 | } | ||
1689 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1690 | "Delivering %u bytes from %s to myself!\n", | ||
1691 | ntohs (payload->size), | ||
1692 | GNUNET_i2s (&rm->sender)); | ||
1693 | send_data_to_plugin (payload, | ||
1694 | &rm->sender, | ||
1695 | 1 + distance); | ||
1696 | return; | ||
1697 | } | ||
1698 | if ( (NULL == GNUNET_CONTAINER_multipeermap_get (direct_neighbors, | ||
1699 | &rm->sender)) && | ||
1700 | (NULL == GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
1701 | &rm->sender)) ) | ||
1702 | { | ||
1703 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1704 | "Learning sender %s at distance %u from forwarding!\n", | ||
1705 | GNUNET_i2s (&rm->sender), | ||
1706 | 1 + distance); | ||
1707 | target = GNUNET_new (struct Target); | ||
1708 | target->peer = rm->sender; | ||
1709 | target->distance = htonl (distance); | ||
1710 | if (NULL == neighbor->neighbor_table) | ||
1711 | neighbor->neighbor_table = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO); | ||
1712 | if (GNUNET_YES != | ||
1713 | GNUNET_CONTAINER_multipeermap_put (neighbor->neighbor_table, | ||
1714 | &target->peer, | ||
1715 | target, | ||
1716 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
1717 | { | ||
1718 | GNUNET_break_op (0); | ||
1719 | GNUNET_free (target); | ||
1720 | return; | ||
1721 | } | ||
1722 | add_new_route (target, neighbor); | ||
1723 | } | ||
1724 | |||
1725 | route = GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
1726 | &rm->target); | ||
1727 | if (NULL == route) | ||
1728 | { | ||
1729 | nneighbor = GNUNET_CONTAINER_multipeermap_get (direct_neighbors, | ||
1730 | &rm->target); | ||
1731 | if (NULL == nneighbor) | ||
1732 | { | ||
1733 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1734 | "No route to %s, not routing %u bytes!\n", | ||
1735 | GNUNET_i2s (&rm->target), | ||
1736 | ntohs (payload->size)); | ||
1737 | GNUNET_STATISTICS_update (stats, | ||
1738 | "# messages discarded (no route)", | ||
1739 | 1, GNUNET_NO); | ||
1740 | return; | ||
1741 | } | ||
1742 | } | ||
1743 | else | ||
1744 | { | ||
1745 | nneighbor = route->next_hop; | ||
1746 | } | ||
1747 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1748 | "Forwarding message to %s\n", | ||
1749 | GNUNET_i2s (&nneighbor->peer)); | ||
1750 | forward_payload (nneighbor, | ||
1751 | distance + 1, | ||
1752 | &rm->sender, | ||
1753 | &rm->target, | ||
1754 | payload); | ||
1755 | } | ||
1756 | |||
1757 | |||
1758 | /** | ||
1759 | * Check that @a msg is well-formed | ||
1760 | * | ||
1761 | * @param cls identification of the client | ||
1762 | * @param message the actual message | ||
1763 | * @return #GNUNET_OK if @a msg is well-formed | ||
1764 | */ | ||
1765 | static int | ||
1766 | check_dv_send_message (void *cls, | ||
1767 | const struct GNUNET_DV_SendMessage *msg) | ||
1768 | { | ||
1769 | const struct GNUNET_MessageHeader *payload; | ||
1770 | |||
1771 | if (ntohs (msg->header.size) < sizeof (struct GNUNET_DV_SendMessage) + | ||
1772 | sizeof (struct GNUNET_MessageHeader)) | ||
1773 | { | ||
1774 | GNUNET_break (0); | ||
1775 | return GNUNET_SYSERR; | ||
1776 | } | ||
1777 | payload = (const struct GNUNET_MessageHeader *) &msg[1]; | ||
1778 | if (ntohs (msg->header.size) != sizeof (struct GNUNET_DV_SendMessage) + ntohs (payload->size)) | ||
1779 | { | ||
1780 | GNUNET_break (0); | ||
1781 | return GNUNET_SYSERR; | ||
1782 | } | ||
1783 | return GNUNET_OK; | ||
1784 | } | ||
1785 | |||
1786 | |||
1787 | /** | ||
1788 | * Service server's handler for message send requests (which come | ||
1789 | * bubbling up to us through the DV plugin). | ||
1790 | * | ||
1791 | * @param cls identification of the client | ||
1792 | * @param message the actual message | ||
1793 | */ | ||
1794 | static void | ||
1795 | handle_dv_send_message (void *cls, | ||
1796 | const struct GNUNET_DV_SendMessage *msg) | ||
1797 | { | ||
1798 | struct GNUNET_SERVICE_Client *client = cls; | ||
1799 | struct Route *route; | ||
1800 | const struct GNUNET_MessageHeader *payload; | ||
1801 | |||
1802 | payload = (const struct GNUNET_MessageHeader *) &msg[1]; | ||
1803 | route = GNUNET_CONTAINER_multipeermap_get (all_routes, | ||
1804 | &msg->target); | ||
1805 | if (NULL == route) | ||
1806 | { | ||
1807 | /* got disconnected */ | ||
1808 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1809 | "No route to %s, dropping local message of type %u\n", | ||
1810 | GNUNET_i2s (&msg->target), | ||
1811 | ntohs (payload->type)); | ||
1812 | GNUNET_STATISTICS_update (stats, | ||
1813 | "# local messages discarded (no route)", | ||
1814 | 1, GNUNET_NO); | ||
1815 | GNUNET_SERVICE_client_continue (client); | ||
1816 | return; | ||
1817 | } | ||
1818 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1819 | "Forwarding %u bytes of type %u to %s\n", | ||
1820 | ntohs (payload->size), | ||
1821 | ntohs (payload->type), | ||
1822 | GNUNET_i2s (&msg->target)); | ||
1823 | |||
1824 | forward_payload (route->next_hop, | ||
1825 | 0 /* first hop, distance is zero */, | ||
1826 | &my_identity, | ||
1827 | &msg->target, | ||
1828 | payload); | ||
1829 | GNUNET_SERVICE_client_continue (client); | ||
1830 | } | ||
1831 | |||
1832 | |||
1833 | /** | ||
1834 | * Cleanup all of the data structures associated with a given neighbor. | ||
1835 | * | ||
1836 | * @param neighbor neighbor to clean up | ||
1837 | */ | ||
1838 | static void | ||
1839 | cleanup_neighbor (struct DirectNeighbor *neighbor) | ||
1840 | { | ||
1841 | handle_direct_disconnect (neighbor); | ||
1842 | GNUNET_assert (GNUNET_YES == | ||
1843 | GNUNET_CONTAINER_multipeermap_remove (direct_neighbors, | ||
1844 | &neighbor->peer, | ||
1845 | neighbor)); | ||
1846 | GNUNET_free (neighbor); | ||
1847 | } | ||
1848 | |||
1849 | |||
1850 | /** | ||
1851 | * Method called whenever a given peer disconnects. | ||
1852 | * | ||
1853 | * @param cls closure | ||
1854 | * @param peer peer identity this notification is about | ||
1855 | * @param internal_cls the corresponding `struct DirectNeighbor` | ||
1856 | */ | ||
1857 | static void | ||
1858 | handle_core_disconnect (void *cls, | ||
1859 | const struct GNUNET_PeerIdentity *peer, | ||
1860 | void *internal_cls) | ||
1861 | { | ||
1862 | struct DirectNeighbor *neighbor = internal_cls; | ||
1863 | |||
1864 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1865 | "Received core peer disconnect message for peer `%s'!\n", | ||
1866 | GNUNET_i2s (peer)); | ||
1867 | /* Check for disconnect from self message */ | ||
1868 | if (NULL == neighbor) | ||
1869 | return; | ||
1870 | GNUNET_break (GNUNET_YES == neighbor->connected); | ||
1871 | neighbor->connected = GNUNET_NO; | ||
1872 | if (DIRECT_NEIGHBOR_COST == neighbor->distance) | ||
1873 | { | ||
1874 | GNUNET_STATISTICS_update (stats, | ||
1875 | "# peers connected (1-hop)", | ||
1876 | -1, | ||
1877 | GNUNET_NO); | ||
1878 | } | ||
1879 | cleanup_neighbor (neighbor); | ||
1880 | if (GNUNET_YES == in_shutdown) | ||
1881 | return; | ||
1882 | schedule_refresh_routes (); | ||
1883 | } | ||
1884 | |||
1885 | |||
1886 | /** | ||
1887 | * Multipeermap iterator for freeing routes. Should never be called. | ||
1888 | * | ||
1889 | * @param cls NULL | ||
1890 | * @param key key value stored under | ||
1891 | * @param value the route to be freed | ||
1892 | * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop | ||
1893 | */ | ||
1894 | static int | ||
1895 | free_route (void *cls, | ||
1896 | const struct GNUNET_PeerIdentity *key, | ||
1897 | void *value) | ||
1898 | { | ||
1899 | struct Route *route = value; | ||
1900 | |||
1901 | GNUNET_break (0); | ||
1902 | GNUNET_assert (GNUNET_YES == | ||
1903 | GNUNET_CONTAINER_multipeermap_remove (all_routes, key, value)); | ||
1904 | release_route (route); | ||
1905 | send_disconnect_to_plugin (&route->target.peer); | ||
1906 | GNUNET_free (route); | ||
1907 | return GNUNET_YES; | ||
1908 | } | ||
1909 | |||
1910 | |||
1911 | /** | ||
1912 | * Multipeermap iterator for freeing direct neighbors. Should never be called. | ||
1913 | * | ||
1914 | * @param cls NULL | ||
1915 | * @param key key value stored under | ||
1916 | * @param value the direct neighbor to be freed | ||
1917 | * @return #GNUNET_YES to continue iteration, #GNUNET_NO to stop | ||
1918 | */ | ||
1919 | static int | ||
1920 | free_direct_neighbors (void *cls, | ||
1921 | const struct GNUNET_PeerIdentity *key, | ||
1922 | void *value) | ||
1923 | { | ||
1924 | struct DirectNeighbor *neighbor = value; | ||
1925 | |||
1926 | cleanup_neighbor (neighbor); | ||
1927 | return GNUNET_YES; | ||
1928 | } | ||
1929 | |||
1930 | |||
1931 | /** | ||
1932 | * Task run during shutdown. | ||
1933 | * | ||
1934 | * @param cls unused | ||
1935 | */ | ||
1936 | static void | ||
1937 | shutdown_task (void *cls) | ||
1938 | { | ||
1939 | unsigned int i; | ||
1940 | |||
1941 | in_shutdown = GNUNET_YES; | ||
1942 | GNUNET_assert (NULL != core_api); | ||
1943 | GNUNET_CORE_disconnect (core_api); | ||
1944 | core_api = NULL; | ||
1945 | GNUNET_ATS_performance_done (ats); | ||
1946 | ats = NULL; | ||
1947 | GNUNET_CONTAINER_multipeermap_iterate (direct_neighbors, | ||
1948 | &free_direct_neighbors, | ||
1949 | NULL); | ||
1950 | GNUNET_CONTAINER_multipeermap_iterate (all_routes, | ||
1951 | &free_route, | ||
1952 | NULL); | ||
1953 | GNUNET_CONTAINER_multipeermap_destroy (direct_neighbors); | ||
1954 | GNUNET_CONTAINER_multipeermap_destroy (all_routes); | ||
1955 | GNUNET_STATISTICS_destroy (stats, GNUNET_NO); | ||
1956 | stats = NULL; | ||
1957 | GNUNET_notification_context_destroy (nc); | ||
1958 | nc = NULL; | ||
1959 | for (i=0;i<DEFAULT_FISHEYE_DEPTH;i++) | ||
1960 | { | ||
1961 | GNUNET_array_grow (consensi[i].targets, | ||
1962 | consensi[i].array_length, | ||
1963 | 0); | ||
1964 | } | ||
1965 | if (NULL != rr_task) | ||
1966 | { | ||
1967 | GNUNET_SCHEDULER_cancel (rr_task); | ||
1968 | rr_task = NULL; | ||
1969 | } | ||
1970 | } | ||
1971 | |||
1972 | |||
1973 | /** | ||
1974 | * Notify newly connected client about an existing route. | ||
1975 | * | ||
1976 | * @param cls the `struct GNUNET_SERVICE_Client *` | ||
1977 | * @param key peer identity | ||
1978 | * @param value the `struct Route *` | ||
1979 | * @return #GNUNET_OK (continue to iterate) | ||
1980 | */ | ||
1981 | static int | ||
1982 | notify_client_about_route (void *cls, | ||
1983 | const struct GNUNET_PeerIdentity *key, | ||
1984 | void *value) | ||
1985 | { | ||
1986 | struct GNUNET_SERVICE_Client *client = cls; | ||
1987 | struct Route *route = value; | ||
1988 | struct GNUNET_MQ_Envelope *env; | ||
1989 | struct GNUNET_DV_ConnectMessage *cm; | ||
1990 | |||
1991 | env = GNUNET_MQ_msg (cm, | ||
1992 | GNUNET_MESSAGE_TYPE_DV_CONNECT); | ||
1993 | cm->distance = htonl (route->target.distance); | ||
1994 | cm->peer = route->target.peer; | ||
1995 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1996 | env); | ||
1997 | return GNUNET_OK; | ||
1998 | } | ||
1999 | |||
2000 | |||
2001 | /** | ||
2002 | * Handle START-message. This is the first message sent to us | ||
2003 | * by the client (can only be one!). | ||
2004 | * | ||
2005 | * @param cls closure (always NULL) | ||
2006 | * @param client identification of the client | ||
2007 | * @param message the actual message | ||
2008 | */ | ||
2009 | static void | ||
2010 | handle_start (void *cls, | ||
2011 | const struct GNUNET_MessageHeader *message) | ||
2012 | { | ||
2013 | struct GNUNET_SERVICE_Client *client = cls; | ||
2014 | |||
2015 | GNUNET_notification_context_add (nc, | ||
2016 | GNUNET_SERVICE_client_get_mq (client)); | ||
2017 | GNUNET_SERVICE_client_continue (client); | ||
2018 | GNUNET_CONTAINER_multipeermap_iterate (all_routes, | ||
2019 | ¬ify_client_about_route, | ||
2020 | client); | ||
2021 | } | ||
2022 | |||
2023 | |||
2024 | /** | ||
2025 | * Called on core init. | ||
2026 | * | ||
2027 | * @param cls unused | ||
2028 | * @param identity this peer's identity | ||
2029 | */ | ||
2030 | static void | ||
2031 | core_init (void *cls, | ||
2032 | const struct GNUNET_PeerIdentity *identity) | ||
2033 | { | ||
2034 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2035 | "I am peer: %s\n", | ||
2036 | GNUNET_i2s (identity)); | ||
2037 | my_identity = *identity; | ||
2038 | } | ||
2039 | |||
2040 | |||
2041 | /** | ||
2042 | * Process dv requests. | ||
2043 | * | ||
2044 | * @param cls closure | ||
2045 | * @param c configuration to use | ||
2046 | * @param service the initialized service | ||
2047 | */ | ||
2048 | static void | ||
2049 | run (void *cls, | ||
2050 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
2051 | struct GNUNET_SERVICE_Handle *service) | ||
2052 | { | ||
2053 | struct GNUNET_MQ_MessageHandler core_handlers[] = { | ||
2054 | GNUNET_MQ_hd_var_size (dv_route_message, | ||
2055 | GNUNET_MESSAGE_TYPE_DV_ROUTE, | ||
2056 | struct RouteMessage, | ||
2057 | NULL), | ||
2058 | GNUNET_MQ_handler_end () | ||
2059 | }; | ||
2060 | in_shutdown = GNUNET_NO; | ||
2061 | cfg = c; | ||
2062 | direct_neighbors = GNUNET_CONTAINER_multipeermap_create (128, | ||
2063 | GNUNET_NO); | ||
2064 | all_routes = GNUNET_CONTAINER_multipeermap_create (65536, | ||
2065 | GNUNET_NO); | ||
2066 | core_api = GNUNET_CORE_connect (cfg, | ||
2067 | NULL, | ||
2068 | &core_init, | ||
2069 | &handle_core_connect, | ||
2070 | &handle_core_disconnect, | ||
2071 | core_handlers); | ||
2072 | |||
2073 | if (NULL == core_api) | ||
2074 | return; | ||
2075 | ats = GNUNET_ATS_performance_init (cfg, | ||
2076 | &handle_ats_update, | ||
2077 | NULL); | ||
2078 | if (NULL == ats) | ||
2079 | { | ||
2080 | GNUNET_CORE_disconnect (core_api); | ||
2081 | core_api = NULL; | ||
2082 | return; | ||
2083 | } | ||
2084 | nc = GNUNET_notification_context_create (MAX_QUEUE_SIZE_PLUGIN); | ||
2085 | stats = GNUNET_STATISTICS_create ("dv", | ||
2086 | cfg); | ||
2087 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
2088 | NULL); | ||
2089 | } | ||
2090 | |||
2091 | |||
2092 | /** | ||
2093 | * Callback called when a client connects to the service. | ||
2094 | * | ||
2095 | * @param cls closure for the service | ||
2096 | * @param c the new client that connected to the service | ||
2097 | * @param mq the message queue used to send messages to the client | ||
2098 | * @return @a c | ||
2099 | */ | ||
2100 | static void * | ||
2101 | client_connect_cb (void *cls, | ||
2102 | struct GNUNET_SERVICE_Client *c, | ||
2103 | struct GNUNET_MQ_Handle *mq) | ||
2104 | { | ||
2105 | return c; | ||
2106 | } | ||
2107 | |||
2108 | |||
2109 | /** | ||
2110 | * Callback called when a client disconnected from the service | ||
2111 | * | ||
2112 | * @param cls closure for the service | ||
2113 | * @param c the client that disconnected | ||
2114 | * @param internal_cls should be equal to @a c | ||
2115 | */ | ||
2116 | static void | ||
2117 | client_disconnect_cb (void *cls, | ||
2118 | struct GNUNET_SERVICE_Client *c, | ||
2119 | void *internal_cls) | ||
2120 | { | ||
2121 | GNUNET_assert (c == internal_cls); | ||
2122 | } | ||
2123 | |||
2124 | |||
2125 | /** | ||
2126 | * Define "main" method using service macro. | ||
2127 | */ | ||
2128 | GNUNET_SERVICE_MAIN | ||
2129 | ("dv", | ||
2130 | GNUNET_SERVICE_OPTION_NONE, | ||
2131 | &run, | ||
2132 | &client_connect_cb, | ||
2133 | &client_disconnect_cb, | ||
2134 | NULL, | ||
2135 | GNUNET_MQ_hd_fixed_size (start, | ||
2136 | GNUNET_MESSAGE_TYPE_DV_START, | ||
2137 | struct GNUNET_MessageHeader, | ||
2138 | NULL), | ||
2139 | GNUNET_MQ_hd_var_size (dv_send_message, | ||
2140 | GNUNET_MESSAGE_TYPE_DV_SEND, | ||
2141 | struct GNUNET_DV_SendMessage, | ||
2142 | NULL), | ||
2143 | GNUNET_MQ_handler_end ()); | ||
2144 | |||
2145 | |||
2146 | /* end of gnunet-service-dv.c */ | ||