23fff3f3b52998f77725b31f04aee765fc1aa168
[oweals/gnunet.git] / src / dv / gnunet-service-dv.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
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  * TODO:
31  * - distance updates are not properly communicate to US by core/transport/ats
32  */
33 #include "platform.h"
34 #include "gnunet_util_lib.h"
35 #include "gnunet_protocols.h"
36 #include "gnunet_core_service.h"
37 #include "gnunet_hello_lib.h"
38 #include "gnunet_peerinfo_service.h"
39 #include "gnunet_statistics_service.h"
40 #include "gnunet_consensus_service.h"
41 #include "dv.h"
42 #include <gcrypt.h>
43
44 /**
45  * How often do we establish the consensu?
46  */
47 #define GNUNET_DV_CONSENSUS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
48
49 /**
50  * Maximum number of messages we queue per peer.
51  */
52 #define MAX_QUEUE_SIZE 16
53
54 /**
55  * The default fisheye depth, from how many hops away will
56  * we keep peers?
57  */
58 #define DEFAULT_FISHEYE_DEPTH 3
59
60 /**
61  * How many hops is a direct neighbor away?
62  */
63 #define DIRECT_NEIGHBOR_COST 1
64
65
66 GNUNET_NETWORK_STRUCT_BEGIN
67
68 /**
69  * Information about a peer DV can route to.  These entries are what
70  * we use as the binary format to establish consensus to create our
71  * routing table and as the address format in the HELLOs.
72  */
73 struct Target
74 {
75
76   /**
77    * Identity of the peer we can reach.
78    */
79   struct GNUNET_PeerIdentity peer;
80
81   /**
82    * How many hops (1-3) is this peer away? in network byte order
83    */
84   uint32_t distance GNUNET_PACKED;
85
86 };
87
88
89 /**
90  * Message exchanged between DV services (via core), requesting a
91  * message to be routed.  
92  */
93 struct RouteMessage
94 {
95   /**
96    * Type: GNUNET_MESSAGE_TYPE_DV_ROUTE
97    */
98   struct GNUNET_MessageHeader header;
99
100   /**
101    * Expected (remaining) distance.  Must be always smaller than
102    * DEFAULT_FISHEYE_DEPTH, should be zero at the target.  Must
103    * be decremented by one at each hop.  Peers must not forward
104    * these messages further once the counter has reached zero.
105    */
106   uint32_t distance GNUNET_PACKED;
107
108   /**
109    * The (actual) target of the message (this peer, if distance is zero).
110    */
111   struct GNUNET_PeerIdentity target;
112
113   /**
114    * The (actual) sender of the message.
115    */
116   struct GNUNET_PeerIdentity sender;
117
118 };
119
120 GNUNET_NETWORK_STRUCT_END
121
122
123 /**
124  * Linked list of messages to send to clients.
125  */
126 struct PendingMessage
127 {
128   /**
129    * Pointer to next item in the list
130    */
131   struct PendingMessage *next;
132
133   /**
134    * Pointer to previous item in the list
135    */
136   struct PendingMessage *prev;
137
138   /**
139    * Actual message to be sent, allocated after this struct.
140    */
141   const struct GNUNET_MessageHeader *msg;
142
143   /**
144    * Ultimate target for the message.
145    */
146   struct GNUNET_PeerIdentity ultimate_target;
147
148   /**
149    * Unique ID of the message.
150    */
151   uint32_t uid;
152
153 };
154
155
156 /**
157  * Information about a direct neighbor (core-level, excluding
158  * DV-links, only DV-enabled peers).
159  */
160 struct DirectNeighbor
161 {
162
163   /**
164    * Identity of the peer.
165    */
166   struct GNUNET_PeerIdentity peer;
167   
168   /**
169    * Head of linked list of messages to send to this peer.
170    */
171   struct PendingMessage *pm_head;
172
173   /**
174    * Tail of linked list of messages to send to this peer.
175    */
176   struct PendingMessage *pm_tail;
177
178   /**
179    * Transmit handle to core service.
180    */
181   struct GNUNET_CORE_TransmitHandle *cth;
182
183   /**
184    * Routing table of the neighbor, NULL if not yet established.
185    * Keys are peer identities, values are 'struct Target' entries.
186    * Note that the distances in the targets are from the point-of-view
187    * of the peer, not from us!
188    */ 
189   struct GNUNET_CONTAINER_MultiHashMap *neighbor_table;
190
191   /**
192    * Updated routing table of the neighbor, under construction,
193    * NULL if we are not currently building it.
194    * Keys are peer identities, values are 'struct Target' entries.
195    * Note that the distances in the targets are from the point-of-view
196    * of the peer, not from us!
197    */ 
198   struct GNUNET_CONTAINER_MultiHashMap *neighbor_table_consensus;
199
200   /**
201    * Active consensus, if we are currently synchronizing the
202    * routing tables.
203    */
204   struct GNUNET_CONSENSUS_Handle *consensus;
205
206   /**
207    * ID of the task we use to (periodically) update our consensus
208    * with this peer.
209    */
210   GNUNET_SCHEDULER_TaskIdentifier consensus_task;
211
212   /**
213    * At what offset are we, with respect to inserting our own routes
214    * into the consensus?
215    */
216   unsigned int consensus_insertion_offset;
217
218   /**
219    * At what distance are we, with respect to inserting our own routes
220    * into the consensus?
221    */
222   unsigned int consensus_insertion_distance;
223
224   /**
225    * Number of messages currently in the 'pm_XXXX'-DLL.
226    */
227   unsigned int pm_queue_size;
228
229   /**
230    * Flag set within 'check_target_removed' to trigger full global route refresh.
231    */
232   int target_removed;
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 'targets' array.
280    */
281   unsigned int array_length;
282
283 };
284
285
286 /**
287  * Hashmap of all of our direct neighbors (no DV routing).
288  */
289 static struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
290
291 /**
292  * Hashmap with all routes that we currently support; contains 
293  * routing information for all peers from distance 2
294  * up to distance DEFAULT_FISHEYE_DEPTH.
295  */
296 static struct GNUNET_CONTAINER_MultiHashMap *all_routes;
297
298 /**
299  * Array of consensus sets we expose to the outside world.  Sets
300  * are structured by the distance to the target.
301  */
302 static struct ConsensusSet consensi[DEFAULT_FISHEYE_DEPTH - 1];
303
304 /**
305  * Handle to the core service api.
306  */
307 static struct GNUNET_CORE_Handle *core_api;
308
309 /**
310  * The identity of our peer.
311  */
312 static struct GNUNET_PeerIdentity my_identity;
313
314 /**
315  * The configuration for this service.
316  */
317 static const struct GNUNET_CONFIGURATION_Handle *cfg;
318
319 /**
320  * The client, the DV plugin connected to us.  Hopefully
321  * this client will never change, although if the plugin dies
322  * and returns for some reason it may happen.
323  */
324 static struct GNUNET_SERVER_Client *client_handle;
325
326 /**
327  * Transmit handle to the plugin.
328  */
329 static struct GNUNET_SERVER_TransmitHandle *plugin_transmit_handle;
330
331 /**
332  * Head of DLL for client messages
333  */
334 static struct PendingMessage *plugin_pending_head;
335
336 /**
337  * Tail of DLL for client messages
338  */
339 static struct PendingMessage *plugin_pending_tail;
340
341 /**
342  * Handle for the statistics service.
343  */
344 struct GNUNET_STATISTICS_Handle *stats;
345
346
347 /**
348  * Get distance information from 'atsi'.
349  *
350  * @param atsi performance data
351  * @param atsi_count number of entries in atsi
352  * @return connected transport distance
353  */
354 static uint32_t
355 get_atsi_distance (const struct GNUNET_ATS_Information *atsi,
356                    unsigned int atsi_count)
357 {
358   unsigned int i;
359
360   for (i = 0; i < atsi_count; i++)
361     if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DISTANCE)
362       return ntohl (atsi->value);
363   /* FIXME: we do not have distance data? Assume direct neighbor. */
364   return DIRECT_NEIGHBOR_COST;
365 }
366
367
368 /**
369  * Function called to notify a client about the socket
370  * begin ready to queue more data.  "buf" will be
371  * NULL and "size" zero if the socket was closed for
372  * writing in the meantime.
373  *
374  * @param cls closure
375  * @param size number of bytes available in buf
376  * @param buf where the callee should write the message
377  * @return number of bytes written to buf
378  */
379 static size_t
380 transmit_to_plugin (void *cls, size_t size, void *buf)
381 {
382   char *cbuf = buf;
383   struct PendingMessage *reply;
384   size_t off;
385   size_t msize;
386
387   plugin_transmit_handle = NULL;
388   if (NULL == buf)
389   {
390     /* client disconnected */    
391     return 0;
392   }
393   off = 0;
394   while ( (NULL != (reply = plugin_pending_head)) &&
395           (size >= off + (msize = ntohs (reply->msg->size))))
396   {
397     GNUNET_CONTAINER_DLL_remove (plugin_pending_head, plugin_pending_tail,
398                                  reply);
399     memcpy (&cbuf[off], reply->msg, msize);
400     GNUNET_free (reply);
401     off += msize;
402   }
403   if (NULL != plugin_pending_head)
404     plugin_transmit_handle =
405       GNUNET_SERVER_notify_transmit_ready (client_handle,
406                                            msize,
407                                            GNUNET_TIME_UNIT_FOREVER_REL,
408                                            &transmit_to_plugin, NULL);
409   return off;
410 }
411
412
413 /**
414  * Forward a message from another peer to the plugin.
415  *
416  * @param message the message to send to the plugin
417  * @param origin the original sender of the message
418  * @param distnace distance to the original sender of the message
419  */
420 static void
421 send_data_to_plugin (const struct GNUNET_MessageHeader *message, 
422                      const struct GNUNET_PeerIdentity *origin,
423                      uint32_t distance)
424 {
425   struct GNUNET_DV_ReceivedMessage *received_msg;
426   struct PendingMessage *pending_message;
427   size_t size;
428
429   if (NULL == client_handle)
430   {
431     GNUNET_STATISTICS_update (stats,
432                               "# messages discarded (no plugin)",
433                               1, GNUNET_NO);
434     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
435                 _("Refusing to queue messages, DV plugin not active.\n"));
436     return;
437   }
438   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
439               "Delivering message from peer `%s'\n",
440               GNUNET_i2s (origin));
441   size = sizeof (struct GNUNET_DV_ReceivedMessage) + 
442     ntohs (message->size);
443   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
444   {    
445     GNUNET_break (0); /* too big */
446     return;
447   }
448   pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
449   received_msg = (struct GNUNET_DV_ReceivedMessage *) &pending_message[1];
450   received_msg->header.size = htons (size);
451   received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV);
452   received_msg->distance = htonl (distance);
453   received_msg->sender = *origin;
454   memcpy (&received_msg[1], message, ntohs (message->size));
455   GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head, 
456                                     plugin_pending_tail,
457                                     pending_message);  
458   if (NULL == plugin_transmit_handle)
459     plugin_transmit_handle =
460       GNUNET_SERVER_notify_transmit_ready (client_handle, size,
461                                            GNUNET_TIME_UNIT_FOREVER_REL,
462                                            &transmit_to_plugin, NULL);
463 }
464
465
466 /**
467  * Forward a control message to the plugin.
468  *
469  * @param message the message to send to the plugin
470  * @param distant_neighbor the original sender of the message
471  * @param distnace distance to the original sender of the message
472  */
473 static void
474 send_control_to_plugin (const struct GNUNET_MessageHeader *message)
475 {
476   struct PendingMessage *pending_message;
477   size_t size;
478
479   if (NULL == client_handle)
480   {
481     GNUNET_STATISTICS_update (stats,
482                               "# control messages discarded (no plugin)",
483                               1, GNUNET_NO);
484     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
485                 _("Refusing to queue messages, DV plugin not active.\n"));
486     return;
487   }
488   size = ntohs (message->size);
489   pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
490   memcpy (&pending_message[1], message, size);
491   GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head, 
492                                     plugin_pending_tail,
493                                     pending_message);  
494   if (NULL == plugin_transmit_handle)
495     plugin_transmit_handle =
496       GNUNET_SERVER_notify_transmit_ready (client_handle, size,
497                                            GNUNET_TIME_UNIT_FOREVER_REL,
498                                            &transmit_to_plugin, NULL);
499 }
500
501
502 /**
503  * Give an (N)ACK message to the plugin, we transmitted a message for it.
504  *
505  * @param target peer that received the message
506  * @param uid plugin-chosen UID for the message
507  * @param nack GNUNET_NO to send ACK, GNUNET_YES to send NACK
508  */
509 static void
510 send_ack_to_plugin (const struct GNUNET_PeerIdentity *target, 
511                     uint32_t uid,
512                     int nack)
513 {
514   struct GNUNET_DV_AckMessage ack_msg;
515
516   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517               "Delivering ACK for message to peer `%s'\n",
518               GNUNET_i2s (target));
519   ack_msg.header.size = htons (sizeof (ack_msg));
520   ack_msg.header.type = htons ((GNUNET_YES == nack) 
521                                ? GNUNET_MESSAGE_TYPE_DV_SEND_NACK
522                                : GNUNET_MESSAGE_TYPE_DV_SEND_ACK);
523   ack_msg.uid = htonl (uid);
524   ack_msg.target = *target;
525   send_control_to_plugin (&ack_msg.header);
526 }
527
528
529 /**
530  * Send a DISTANCE_CHANGED message to the plugin.
531  *
532  * @param peer peer with a changed distance
533  * @param distance new distance to the peer
534  */
535 static void
536 send_distance_change_to_plugin (const struct GNUNET_PeerIdentity *peer, 
537                                 uint32_t distance)
538 {
539   struct GNUNET_DV_DistanceUpdateMessage du_msg;
540
541   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542               "Delivering DISTANCE_CHANGED for message about peer `%s'\n",
543               GNUNET_i2s (peer));
544   du_msg.header.size = htons (sizeof (du_msg));
545   du_msg.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISTANCE_CHANGED);
546   du_msg.distance = htonl (distance);
547   du_msg.peer = *peer;
548   send_control_to_plugin (&du_msg.header);
549 }
550
551
552 /**
553  * Give a CONNECT message to the plugin.
554  *
555  * @param target peer that connected
556  * @param distance distance to the target
557  */
558 static void
559 send_connect_to_plugin (const struct GNUNET_PeerIdentity *target, 
560                         uint32_t distance)
561 {
562   struct GNUNET_DV_ConnectMessage cm;
563
564   if (NULL == client_handle)
565     return;
566   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
567               "Delivering CONNECT about peer `%s'\n",
568               GNUNET_i2s (target));
569   cm.header.size = htons (sizeof (cm));
570   cm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_CONNECT);
571   cm.distance = htonl (distance);
572   cm.peer = *target;
573   send_control_to_plugin (&cm.header);
574 }
575
576
577 /**
578  * Give a DISCONNECT message to the plugin.
579  *
580  * @param target peer that disconnected
581  */
582 static void
583 send_disconnect_to_plugin (const struct GNUNET_PeerIdentity *target)
584 {
585   struct GNUNET_DV_DisconnectMessage dm;
586
587   if (NULL == client_handle)
588     return;
589   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590               "Delivering DISCONNECT about peer `%s'\n",
591               GNUNET_i2s (target));
592   dm.header.size = htons (sizeof (dm));
593   dm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
594   dm.reserved = htonl (0);
595   dm.peer = *target;
596   send_control_to_plugin (&dm.header);
597 }
598
599
600 /**
601  * Function called to transfer a message to another peer
602  * via core.
603  *
604  * @param cls closure with the direct neighbor
605  * @param size number of bytes available in buf
606  * @param buf where the callee should write the message
607  * @return number of bytes written to buf
608  */
609 static size_t
610 core_transmit_notify (void *cls, size_t size, void *buf)
611 {
612   struct DirectNeighbor *dn = cls;
613   char *cbuf = buf;
614   struct PendingMessage *pending;
615   size_t off;
616   size_t msize;
617
618   dn->cth = NULL;
619   if (NULL == buf)
620   {
621     /* peer disconnected */
622     return 0;
623   }
624   off = 0;
625   pending = dn->pm_head;
626   off = 0;
627   while ( (NULL != (pending = dn->pm_head)) &&
628           (size >= off + (msize = ntohs (pending->msg->size))))
629   {
630     dn->pm_queue_size--;
631     GNUNET_CONTAINER_DLL_remove (dn->pm_head,
632                                  dn->pm_tail,
633                                  pending);
634     memcpy (&cbuf[off], pending->msg, msize);
635     if (0 != pending->uid) 
636       send_ack_to_plugin (&pending->ultimate_target,
637                           pending->uid,
638                           GNUNET_NO);
639     GNUNET_free (pending);
640     off += msize;
641   }
642   if (NULL != dn->pm_head)
643     dn->cth =
644       GNUNET_CORE_notify_transmit_ready (core_api,
645                                          GNUNET_YES /* cork */,
646                                          0 /* priority */,
647                                          GNUNET_TIME_UNIT_FOREVER_REL,
648                                          &dn->peer,
649                                          msize,                                  
650                                          &core_transmit_notify, dn);
651   return off;
652 }
653
654
655 /**
656  * Forward the given payload to the given target.
657  *
658  * @param target where to send the message
659  * @param uid unique ID for the message
660  * @param ultimate_target ultimate recipient for the message
661  * @param distance expected (remaining) distance to the target
662  * @param sender original sender of the message
663  * @param payload payload of the message
664  */
665 static void
666 forward_payload (struct DirectNeighbor *target,
667                  uint32_t distance,
668                  uint32_t uid,
669                  const struct GNUNET_PeerIdentity *sender,
670                  const struct GNUNET_PeerIdentity *ultimate_target,
671                  const struct GNUNET_MessageHeader *payload)
672 {
673   struct PendingMessage *pm;
674   struct RouteMessage *rm;
675   size_t msize;
676
677   if ( (target->pm_queue_size >= MAX_QUEUE_SIZE) &&
678        (0 != memcmp (sender,
679                      &my_identity,
680                      sizeof (struct GNUNET_PeerIdentity))) )
681   {
682     GNUNET_break (0 == uid);
683     return;
684   }
685   msize = sizeof (struct RouteMessage) + ntohs (payload->size);
686   if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
687   {
688     GNUNET_break (0);
689     return;
690   }
691   pm = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
692   pm->ultimate_target = *ultimate_target;
693   pm->uid = uid;
694   pm->msg = (const struct GNUNET_MessageHeader *) &pm[1];
695   rm = (struct RouteMessage *) &pm[1];
696   rm->header.size = htons ((uint16_t) msize);
697   rm->header.type = htons (GNUNET_MESSAGE_TYPE_DV_ROUTE);
698   rm->distance = htonl (distance);
699   rm->target = target->peer;
700   rm->sender = *sender;
701   memcpy (&rm[1], payload, ntohs (payload->size));
702   GNUNET_CONTAINER_DLL_insert_tail (target->pm_head,
703                                     target->pm_tail,
704                                     pm);
705   target->pm_queue_size++;
706   if (NULL == target->cth)
707     target->cth = GNUNET_CORE_notify_transmit_ready (core_api,
708                                                      GNUNET_YES /* cork */,
709                                                      0 /* priority */,
710                                                      GNUNET_TIME_UNIT_FOREVER_REL,
711                                                      &target->peer,
712                                                      msize,                                      
713                                                      &core_transmit_notify, target);
714 }
715
716
717 /**
718  * Find a free slot for storing a 'route' in the 'consensi'
719  * set at the given distance.
720  *
721  * @param distance distance to use for the set slot
722  */
723 static unsigned int
724 get_consensus_slot (uint32_t distance)
725 {
726   struct ConsensusSet *cs;
727   unsigned int i;
728
729   cs = &consensi[distance];
730   i = 0;
731   while ( (i < cs->array_length) &&
732           (NULL != cs->targets[i]) ) i++;
733   if (i == cs->array_length)
734     GNUNET_array_grow (cs->targets,
735                        cs->array_length,
736                        cs->array_length * 2 + 2);
737   return i;
738 }
739
740
741 /**
742  * Allocate a slot in the consensus set for a route.
743  *
744  * @param route route to initialize
745  * @param distance which consensus set to use
746  */
747 static void
748 allocate_route (struct Route *route,
749                 uint32_t distance)
750 {
751   unsigned int i;
752
753   i = get_consensus_slot (distance);
754   route->set_offset = i;
755   consensi[distance].targets[i] = route;
756   route->target.distance = htonl (distance);
757 }
758
759
760 /**
761  * Release a slot in the consensus set for a route.
762  *
763  * @param route route to release the slot from
764  */
765 static void
766 release_route (struct Route *route)
767 {
768   consensi[ntohl (route->target.distance)].targets[route->set_offset] = NULL;
769   route->set_offset = UINT_MAX; /* indicate invalid slot */
770 }
771
772
773 /**
774  * Move a route from one consensus set to another.
775  *
776  * @param route route to move
777  * @param new_distance new distance for the route (destination set)
778  */
779 static void
780 move_route (struct Route *route,
781             uint32_t new_distance)
782 {
783   unsigned int i;
784
785   release_route (route);
786   i = get_consensus_slot (new_distance);
787   route->set_offset = i;
788   consensi[new_distance].targets[i] = route;     
789   route->target.distance = htonl (new_distance);
790 }
791
792
793 /**
794  * Start creating a new consensus from scratch.
795  *
796  * @param cls the 'struct DirectNeighbor' of the peer we're building
797  *        a routing consensus with
798  * @param tc scheduler context
799  */    
800 static void
801 start_consensus (void *cls,
802                  const struct GNUNET_SCHEDULER_TaskContext *tc);
803
804
805 /**
806  * Method called whenever a peer connects.
807  *
808  * @param cls closure
809  * @param peer peer identity this notification is about
810  * @param atsi performance data
811  * @param atsi_count number of entries in atsi
812  */
813 static void
814 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
815                      const struct GNUNET_ATS_Information *atsi,
816                      unsigned int atsi_count)
817 {
818   struct DirectNeighbor *neighbor;
819   struct Route *route;
820   uint32_t distance;
821  
822   /* Check for connect to self message */
823   if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
824     return;
825   distance = get_atsi_distance (atsi, atsi_count);
826   neighbor = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, 
827                                                 &peer->hashPubKey);
828   if (NULL != neighbor)
829   {
830     GNUNET_break (0);
831     return;
832   }
833   if (DIRECT_NEIGHBOR_COST != distance) 
834     return; /* is a DV-neighbor */
835   neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
836   neighbor->peer = *peer;
837   GNUNET_assert (GNUNET_YES ==
838                  GNUNET_CONTAINER_multihashmap_put (direct_neighbors,
839                                                     &peer->hashPubKey,
840                                                     neighbor,
841                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
842   route = GNUNET_CONTAINER_multihashmap_get (all_routes, 
843                                              &peer->hashPubKey);
844   if (NULL != route)  
845   {
846     send_disconnect_to_plugin (peer);
847     release_route (route);
848     GNUNET_free (route);
849   }
850   route->next_hop = neighbor;
851   neighbor->consensus_task = GNUNET_SCHEDULER_add_now (&start_consensus,
852                                                        neighbor);
853 }
854
855
856 /**
857  * Called for each 'target' in a neighbor table to free the associated memory.
858  *
859  * @param cls NULL
860  * @param key key of the value
861  * @param value value to free
862  * @return GNUNET_OK to continue to iterate
863  */
864 static int
865 free_targets (void *cls,
866               const struct GNUNET_HashCode *key,
867               void *value)
868 {
869   GNUNET_free (value);
870   return GNUNET_OK;
871 }
872
873
874 /**
875  * Multihashmap iterator for checking if a given route is
876  * (now) useful to this peer.
877  *
878  * @param cls the direct neighbor for the given route
879  * @param key key value stored under
880  * @param value a 'struct Target' that may or may not be useful; not that
881  *        the distance in 'target' does not include the first hop yet
882  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
883  */
884 static int
885 check_possible_route (void *cls, const struct GNUNET_HashCode * key, void *value)
886 {
887   struct DirectNeighbor *neighbor = cls;
888   struct Target *target = value;
889   struct Route *route;
890   
891   route = GNUNET_CONTAINER_multihashmap_get (all_routes,
892                                            key);
893   if (NULL != route)
894   {
895     if (ntohl (route->target.distance) > ntohl (target->distance) + 1)
896     {
897       /* this 'target' is cheaper than the existing route; switch to alternative route! */
898       move_route (route, ntohl (target->distance) + 1);
899       route->next_hop = neighbor;
900       send_distance_change_to_plugin (&target->peer, ntohl (target->distance) + 1);
901     }
902     return GNUNET_YES; /* got a route to this target already */
903   }
904   route = GNUNET_malloc (sizeof (struct Route));
905   route->next_hop = neighbor;
906   route->target.distance = htonl (ntohl (target->distance) + 1);
907   route->target.peer = target->peer;
908   allocate_route (route, ntohl (route->target.distance));
909   GNUNET_assert (GNUNET_YES ==
910                  GNUNET_CONTAINER_multihashmap_put (all_routes,
911                                                     &route->target.peer.hashPubKey,
912                                                     route,
913                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
914   send_connect_to_plugin (&route->target.peer, ntohl (target->distance));
915   return GNUNET_YES;
916 }
917
918
919 /**
920  * Multihashmap iterator for finding routes that were previously
921  * "hidden" due to a better route (called after a disconnect event).
922  *
923  * @param cls NULL
924  * @param key peer identity of the given direct neighbor
925  * @param value a 'struct DirectNeighbor' to check for additional routes
926  * @return GNUNET_YES to continue iteration
927  */
928 static int
929 refresh_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
930 {
931   struct DirectNeighbor *neighbor = value;
932
933   if (NULL != neighbor->neighbor_table)
934     GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
935                                            &check_possible_route,
936                                            neighbor);
937   return GNUNET_YES;
938 }
939
940
941 /**
942  * Check if a target was removed from the set of the other peer; if so,
943  * if we also used it for our route, we need to remove it from our
944  * 'all_routes' set (and later check if an alternative path now exists).
945  *
946  * @param cls the 'struct DirectNeighbor'
947  * @param key peer identity for the target
948  * @param value a 'struct Target' previously reachable via the given neighbor
949  */
950 static int
951 check_target_removed (void *cls,
952                       const struct GNUNET_HashCode *key,
953                       void *value)
954 {
955   struct DirectNeighbor *neighbor = cls;
956   struct Target *new_target;
957   struct Route *current_route;
958
959   new_target = GNUNET_CONTAINER_multihashmap_get (neighbor->neighbor_table_consensus,
960                                                   key);
961   if (NULL == new_target)
962   {
963     /* target was revoked, check if it was used */
964     current_route = GNUNET_CONTAINER_multihashmap_get (all_routes,
965                                                        key);
966     if ( (NULL == current_route) ||
967          (current_route->next_hop != neighbor) )
968     {
969       /* didn't matter, wasn't used */
970       return GNUNET_OK;
971     }
972     /* remove existing route */
973     GNUNET_assert (GNUNET_YES ==
974                    GNUNET_CONTAINER_multihashmap_remove (all_routes, key, current_route));
975     send_disconnect_to_plugin (&current_route->target.peer);
976     GNUNET_free (current_route);
977     neighbor->target_removed = GNUNET_YES;
978     return GNUNET_OK;
979   }
980   return GNUNET_OK;
981 }
982
983
984 /**
985  * Check if a target was added to the set of the other peer; if it
986  * was added or impoves the existing route, do the needed updates.
987  *
988  * @param cls the 'struct DirectNeighbor'
989  * @param key peer identity for the target
990  * @param value a 'struct Target' now reachable via the given neighbor
991  */
992 static int
993 check_target_added (void *cls,
994                       const struct GNUNET_HashCode *key,
995                       void *value)
996 {
997   struct DirectNeighbor *neighbor = cls;
998   struct Target *target = value;
999   struct Route *current_route;
1000
1001   /* target was revoked, check if it was used */
1002   current_route = GNUNET_CONTAINER_multihashmap_get (all_routes,
1003                                                      key);
1004   if (NULL != current_route)
1005   {
1006     /* route exists */
1007     if (current_route->next_hop == neighbor)
1008     {
1009       /* we had the same route before, no change */
1010       if (ntohl (target->distance) + 1 != ntohl (current_route->target.distance))
1011       {
1012         current_route->target.distance = htonl (ntohl (target->distance) + 1);
1013         send_distance_change_to_plugin (&target->peer, ntohl (target->distance) + 1);
1014       }
1015       return GNUNET_OK;
1016     }
1017     if (ntohl (current_route->target.distance) >= ntohl (target->distance) + 1)
1018     {
1019       /* alternative, shorter route exists, ignore */
1020       return GNUNET_OK;
1021     }
1022     /* new route is better than the existing one, take over! */
1023     /* NOTE: minor security issue: malicious peers may advertise
1024        very short routes to take over longer paths; as we don't
1025        check that the shorter routes actually work, a malicious
1026        direct neighbor can use this to DoS our long routes */
1027     current_route->next_hop = neighbor;
1028     current_route->target.distance = htonl (ntohl (target->distance) + 1);
1029     send_distance_change_to_plugin (&target->peer, ntohl (target->distance) + 1);
1030     return GNUNET_OK;
1031   }
1032   /* new route */
1033   current_route = GNUNET_malloc (sizeof (struct Route));
1034   current_route->next_hop = neighbor;
1035   current_route->target.peer = target->peer;
1036   current_route->target.distance = htonl (ntohl (target->distance) + 1);
1037   GNUNET_assert (GNUNET_YES ==
1038                  GNUNET_CONTAINER_multihashmap_put (all_routes,
1039                                                     &current_route->target.peer.hashPubKey,
1040                                                     current_route,
1041                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1042   send_connect_to_plugin (&current_route->target.peer,
1043                           ntohl (current_route->target.distance));
1044   return GNUNET_OK;
1045 }
1046
1047
1048
1049 /**
1050  * The consensus has concluded, clean up and schedule the next one.
1051  *
1052  * @param cls the 'struct GNUNET_DirectNeighbor' with which we created the consensus
1053  * @param group FIXME
1054  */
1055 static void
1056 consensus_done_cb (void *cls,
1057                    const struct GNUNET_CONSENSUS_Group *group)
1058 {
1059   struct DirectNeighbor *neighbor = cls;
1060
1061   GNUNET_CONSENSUS_destroy (neighbor->consensus);
1062   neighbor->consensus = NULL;
1063   /* remove targets that disappeared */
1064   neighbor->target_removed = GNUNET_NO;
1065   GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
1066                                          &check_target_removed,
1067                                          neighbor);
1068   if (GNUNET_YES == neighbor->target_removed)
1069   {
1070     /* check if we got an alternative for the removed routes */
1071     GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
1072                                            &refresh_routes,
1073                                            NULL);    
1074   }
1075   /* add targets that appeared (and check for improved routes) */
1076   GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table_consensus,
1077                                          &check_target_added,
1078                                          neighbor);
1079   if (NULL != neighbor->neighbor_table)
1080   {
1081     GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
1082                                            &free_targets,
1083                                            NULL);
1084     GNUNET_CONTAINER_multihashmap_destroy (neighbor->neighbor_table);
1085     neighbor->neighbor_table = NULL;
1086   }
1087   neighbor->neighbor_table = neighbor->neighbor_table_consensus;
1088   neighbor->neighbor_table_consensus = NULL;
1089   neighbor->consensus_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1090                                                            &start_consensus,
1091                                                            neighbor);
1092 }
1093
1094
1095 /**
1096  * We inserted the last element into the consensus, get ready to
1097  * insert the next element into the consensus or conclude if
1098  * we're done.
1099  *
1100  * @param cls the 'struct DirectNeighbor' of the peer we're building
1101  *        a routing consensus with
1102  * @param success GNUNET_OK if the last element was added successfully,
1103  *                GNUNET_SYSERR if we failed
1104  */
1105 static void
1106 insert_next_element (void *cls,
1107                      int success)
1108 {
1109   struct DirectNeighbor *neighbor = cls;
1110   struct GNUNET_CONSENSUS_Element element;
1111
1112   while ( (DEFAULT_FISHEYE_DEPTH - 1 > neighbor->consensus_insertion_distance) &&
1113           (consensi[neighbor->consensus_insertion_distance].array_length == neighbor->consensus_insertion_offset) )
1114   {
1115     neighbor->consensus_insertion_offset = 0;
1116     neighbor->consensus_insertion_distance++;
1117     /* skip over NULL entries */
1118     while ( (DEFAULT_FISHEYE_DEPTH - 1 > neighbor->consensus_insertion_distance) &&
1119             (consensi[neighbor->consensus_insertion_distance].array_length < neighbor->consensus_insertion_offset) &&
1120             (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
1121       neighbor->consensus_insertion_offset++;
1122   }
1123   if (DEFAULT_FISHEYE_DEPTH - 1 == neighbor->consensus_insertion_distance)
1124   {
1125     /* we're done, conclude! */
1126     GNUNET_CONSENSUS_conclude (neighbor->consensus,
1127                                GNUNET_DV_CONSENSUS_FREQUENCY,
1128                                2 /* both peers */,
1129                                &consensus_done_cb,
1130                                neighbor);
1131     return;
1132   }
1133   element.size = sizeof (struct Target);
1134   element.data = &consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset++]->target;
1135
1136   /* skip over NULL entries */
1137   while ( (DEFAULT_FISHEYE_DEPTH - 1 > neighbor->consensus_insertion_distance) &&
1138           (consensi[neighbor->consensus_insertion_distance].array_length < neighbor->consensus_insertion_offset) &&
1139           (NULL == consensi[neighbor->consensus_insertion_distance].targets[neighbor->consensus_insertion_offset]) )
1140     neighbor->consensus_insertion_offset++;  
1141   GNUNET_CONSENSUS_insert (neighbor->consensus,
1142                            &element,
1143                            &insert_next_element,
1144                            neighbor);
1145 }
1146
1147
1148 /**
1149  * We have learned a new route from the other peer.  Add it to the
1150  * route set we're building.
1151  *
1152  * @param cls the 'struct DirectNeighbor' we're building the consensus with
1153  * @param element the new element we have learned
1154  * @return GNUNET_OK if the valid is well-formed and should be added to the consensus,
1155  *         GNUNET_SYSERR if the element should be ignored and not be propagated
1156  */
1157 static int
1158 learn_route_cb (void *cls,
1159                 const struct GNUNET_CONSENSUS_Element *element)
1160 {
1161   struct DirectNeighbor *neighbor = cls;
1162   struct Target *target;
1163
1164   if (sizeof (struct Target) != element->size)
1165   {
1166     GNUNET_break_op (0);
1167     return GNUNET_SYSERR;
1168   }
1169   target = GNUNET_malloc (sizeof (struct Target));
1170   memcpy (target, element->data, sizeof (struct Target));
1171   if (GNUNET_YES !=
1172       GNUNET_CONTAINER_multihashmap_put (neighbor->neighbor_table_consensus,
1173                                          &target->peer.hashPubKey,
1174                                          target,
1175                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1176   {
1177     GNUNET_break_op (0);
1178     GNUNET_free (target);
1179     return GNUNET_SYSERR;
1180   }
1181   return GNUNET_OK;
1182 }
1183
1184
1185 /**
1186  * Start creating a new consensus from scratch.
1187  *
1188  * @param cls the 'struct DirectNeighbor' of the peer we're building
1189  *        a routing consensus with
1190  * @param tc scheduler context
1191  */    
1192 static void
1193 start_consensus (void *cls,
1194                  const struct GNUNET_SCHEDULER_TaskContext *tc)
1195 {
1196   struct DirectNeighbor *neighbor = cls;
1197   struct GNUNET_HashCode session_id;
1198   struct GNUNET_HashCode real_session_id;
1199
1200   neighbor->consensus_task = GNUNET_SCHEDULER_NO_TASK;
1201   neighbor->consensus_insertion_offset = 0;
1202   neighbor->consensus_insertion_distance = 0;
1203   GNUNET_assert (NULL == neighbor->neighbor_table_consensus);
1204   GNUNET_assert (NULL == neighbor->consensus);
1205   neighbor->neighbor_table_consensus = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
1206   /* construct session ID seed as XOR of both peer's identities */
1207   GNUNET_CRYPTO_hash_xor (&my_identity.hashPubKey, 
1208                           &neighbor->peer.hashPubKey, 
1209                           &session_id);
1210   /* make sure session ID is unique across applications by salting it with 'DV' */
1211   GNUNET_CRYPTO_hkdf (&real_session_id, sizeof (real_session_id),
1212                       GCRY_MD_SHA512, GCRY_MD_SHA256,
1213                       "DV-SALT", 2,
1214                       &session_id, sizeof (session_id),
1215                       NULL, 0);
1216   neighbor->consensus = GNUNET_CONSENSUS_create (cfg,
1217                                                  1,
1218                                                  &neighbor->peer,
1219                                                  &real_session_id,
1220                                                  &learn_route_cb,
1221                                                  neighbor);
1222   if (NULL == neighbor->consensus)
1223   {
1224     neighbor->consensus_task = GNUNET_SCHEDULER_add_delayed (GNUNET_DV_CONSENSUS_FREQUENCY,
1225                                                              &start_consensus,
1226                                                              neighbor);
1227     return;
1228   }
1229   insert_next_element (neighbor, GNUNET_OK);
1230 }
1231
1232
1233 /**
1234  * Core handler for DV data messages.  Whatever this message
1235  * contains all we really have to do is rip it out of its
1236  * DV layering and give it to our pal the DV plugin to report
1237  * in with.
1238  *
1239  * @param cls closure
1240  * @param peer peer which sent the message (immediate sender)
1241  * @param message the message
1242  * @param atsi transport ATS information (latency, distance, etc.)
1243  * @param atsi_count number of entries in atsi
1244  * @return GNUNET_OK on success, GNUNET_SYSERR if the other peer violated the protocol
1245  */
1246 static int
1247 handle_dv_route_message (void *cls, const struct GNUNET_PeerIdentity *peer,
1248                          const struct GNUNET_MessageHeader *message,
1249                          const struct GNUNET_ATS_Information *atsi,
1250                          unsigned int atsi_count)
1251 {
1252   const struct RouteMessage *rm;
1253   const struct GNUNET_MessageHeader *payload;
1254   struct Route *route;
1255
1256   if (ntohs (message->size) < sizeof (struct RouteMessage) + sizeof (struct GNUNET_MessageHeader))
1257   {
1258     GNUNET_break_op (0);
1259     return GNUNET_SYSERR;
1260   }
1261   rm = (const struct RouteMessage *) message;
1262   payload = (const struct GNUNET_MessageHeader *) &rm[1];
1263   if (ntohs (message->size) != sizeof (struct RouteMessage) + ntohs (payload->size))
1264   {
1265     GNUNET_break_op (0);
1266     return GNUNET_SYSERR;
1267   }
1268   if (0 == memcmp (&rm->target,
1269                    &my_identity,
1270                    sizeof (struct GNUNET_PeerIdentity)))
1271   {
1272     /* message is for me, check reverse route! */
1273     route = GNUNET_CONTAINER_multihashmap_get (all_routes,
1274                                                &rm->sender.hashPubKey);
1275     if (NULL == route)
1276     {
1277       /* don't have reverse route, drop */
1278       GNUNET_STATISTICS_update (stats,
1279                                 "# message discarded (no reverse route)",
1280                                 1, GNUNET_NO);
1281       return GNUNET_OK;
1282     }
1283     send_data_to_plugin (payload,
1284                          &rm->sender,
1285                          ntohl (route->target.distance));
1286     return GNUNET_OK;
1287   }
1288   route = GNUNET_CONTAINER_multihashmap_get (all_routes,
1289                                              &rm->target.hashPubKey);
1290   if (NULL == route)
1291   {
1292     GNUNET_STATISTICS_update (stats,
1293                               "# messages discarded (no route)",
1294                               1, GNUNET_NO);
1295     return GNUNET_OK;
1296   }
1297   if (ntohl (route->target.distance) > ntohl (rm->distance) + 1)
1298   {
1299     GNUNET_STATISTICS_update (stats,
1300                               "# messages discarded (target too far)",
1301                               1, GNUNET_NO);
1302     return GNUNET_OK;
1303   }
1304   forward_payload (route->next_hop,
1305                    ntohl (route->target.distance),
1306                    0,
1307                    &rm->target,
1308                    &rm->sender,
1309                    payload);
1310   return GNUNET_OK;  
1311 }
1312
1313
1314 /**
1315  * Service server's handler for message send requests (which come
1316  * bubbling up to us through the DV plugin).
1317  *
1318  * @param cls closure
1319  * @param client identification of the client
1320  * @param message the actual message
1321  */
1322 static void
1323 handle_dv_send_message (void *cls, struct GNUNET_SERVER_Client *client,
1324                         const struct GNUNET_MessageHeader *message)
1325 {
1326   struct Route *route;
1327   const struct GNUNET_DV_SendMessage *msg;
1328   const struct GNUNET_MessageHeader *payload;
1329
1330   if (ntohs (message->size) < sizeof (struct GNUNET_DV_SendMessage) + sizeof (struct GNUNET_MessageHeader))
1331   {
1332     GNUNET_break (0);
1333     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1334     return;
1335   }
1336   msg = (const struct GNUNET_DV_SendMessage *) message;
1337   GNUNET_break (0 != ntohl (msg->uid));
1338   payload = (const struct GNUNET_MessageHeader *) &msg[1];
1339   if (ntohs (message->size) != sizeof (struct GNUNET_DV_SendMessage) + ntohs (payload->size))
1340   {
1341     GNUNET_break (0);
1342     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1343     return;
1344   }
1345   route = GNUNET_CONTAINER_multihashmap_get (all_routes,
1346                                              &msg->target.hashPubKey);
1347   if (NULL == route)
1348   {
1349     /* got disconnected */
1350     GNUNET_STATISTICS_update (stats,
1351                               "# local messages discarded (no route)",
1352                               1, GNUNET_NO);
1353     send_ack_to_plugin (&msg->target, ntohl (msg->uid), GNUNET_YES);
1354     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1355     return;
1356   }
1357   forward_payload (route->next_hop,
1358                    ntohl (route->target.distance),
1359                    htonl (msg->uid),
1360                    &msg->target,
1361                    &my_identity,
1362                    payload);
1363   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1364 }
1365
1366
1367 /**
1368  * Multihashmap iterator for freeing routes that go via a particular
1369  * neighbor that disconnected and is thus no longer available.
1370  *
1371  * @param cls the direct neighbor that is now unavailable
1372  * @param key key value stored under
1373  * @param value a 'struct Route' that may or may not go via neighbor
1374  *
1375  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1376  */
1377 static int
1378 cull_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
1379 {
1380   struct DirectNeighbor *neighbor = cls;
1381   struct Route *route = value;
1382
1383   if (route->next_hop != neighbor)
1384     return GNUNET_YES; /* not affected */
1385   GNUNET_assert (GNUNET_YES ==
1386                  GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
1387   release_route (route);
1388   send_disconnect_to_plugin (&route->target.peer);
1389   GNUNET_free (route);
1390   return GNUNET_YES;
1391 }
1392
1393
1394 /**
1395  * Cleanup all of the data structures associated with a given neighbor.
1396  *
1397  * @param neighbor neighbor to clean up
1398  */
1399 static void
1400 cleanup_neighbor (struct DirectNeighbor *neighbor)
1401 {
1402   struct PendingMessage *pending;
1403
1404   while (NULL != (pending = neighbor->pm_head))
1405   {
1406     neighbor->pm_queue_size--;
1407     GNUNET_CONTAINER_DLL_remove (neighbor->pm_head,
1408                                  neighbor->pm_tail,
1409                                  pending);    
1410     GNUNET_free (pending);
1411   }
1412   GNUNET_CONTAINER_multihashmap_iterate (all_routes,
1413                                          &cull_routes,
1414                                          neighbor);
1415   if (NULL != neighbor->cth)
1416   {
1417     GNUNET_CORE_notify_transmit_ready_cancel (neighbor->cth);
1418     neighbor->cth = NULL;
1419   }
1420   if (NULL != neighbor->neighbor_table_consensus)
1421   {
1422     GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table_consensus,
1423                                            &free_targets,
1424                                            NULL);
1425     GNUNET_CONTAINER_multihashmap_destroy (neighbor->neighbor_table_consensus);
1426     neighbor->neighbor_table_consensus = NULL;
1427   }
1428   if (NULL != neighbor->neighbor_table)
1429   {
1430     GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
1431                                            &free_targets,
1432                                            NULL);
1433     GNUNET_CONTAINER_multihashmap_destroy (neighbor->neighbor_table);
1434     neighbor->neighbor_table = NULL;
1435   }
1436   if (GNUNET_SCHEDULER_NO_TASK != neighbor->consensus_task)
1437   {
1438     GNUNET_SCHEDULER_cancel (neighbor->consensus_task);
1439     neighbor->consensus_task = GNUNET_SCHEDULER_NO_TASK;
1440   }
1441   if (NULL != neighbor->consensus)
1442   {
1443     GNUNET_CONSENSUS_destroy (neighbor->consensus);
1444     neighbor->consensus = NULL;
1445   }
1446   GNUNET_assert (GNUNET_YES ==
1447                  GNUNET_CONTAINER_multihashmap_remove (direct_neighbors, 
1448                                                        &neighbor->peer.hashPubKey,
1449                                                        neighbor));
1450   GNUNET_free (neighbor);
1451 }
1452
1453
1454 /**
1455  * Method called whenever a given peer disconnects.
1456  *
1457  * @param cls closure
1458  * @param peer peer identity this notification is about
1459  */
1460 static void
1461 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
1462 {
1463   struct DirectNeighbor *neighbor;
1464
1465   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1466               "Received core peer disconnect message for peer `%s'!\n",
1467               GNUNET_i2s (peer));
1468   /* Check for disconnect from self message */
1469   if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
1470     return;
1471   neighbor =
1472       GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey);
1473   if (NULL == neighbor)
1474   {
1475     /* must have been a DV-neighbor, ignore */
1476     return;
1477   }
1478   cleanup_neighbor (neighbor);
1479   GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
1480                                          &refresh_routes,
1481                                          NULL);
1482 }
1483
1484
1485 /**
1486  * Multihashmap iterator for freeing routes.  Should never be called.
1487  *
1488  * @param cls NULL
1489  * @param key key value stored under
1490  * @param value the route to be freed
1491  *
1492  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1493  */
1494 static int
1495 free_route (void *cls, const struct GNUNET_HashCode * key, void *value)
1496 {
1497   struct Route *route = value;
1498
1499   GNUNET_break (0);
1500   GNUNET_assert (GNUNET_YES ==
1501                  GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
1502   release_route (route);
1503   send_disconnect_to_plugin (&route->target.peer);
1504   GNUNET_free (route);
1505   return GNUNET_YES;
1506 }
1507
1508
1509 /**
1510  * Multihashmap iterator for freeing direct neighbors. Should never be called.
1511  *
1512  * @param cls NULL
1513  * @param key key value stored under
1514  * @param value the direct neighbor to be freed
1515  *
1516  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1517  */
1518 static int
1519 free_direct_neighbors (void *cls, const struct GNUNET_HashCode * key, void *value)
1520 {
1521   struct DirectNeighbor *neighbor = value;
1522
1523   GNUNET_break (0);
1524   cleanup_neighbor (neighbor);
1525   return GNUNET_YES;
1526 }
1527
1528
1529 /**
1530  * Task run during shutdown.
1531  *
1532  * @param cls unused
1533  * @param tc unused
1534  */
1535 static void
1536 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1537 {
1538   struct PendingMessage *pending;
1539   unsigned int i;
1540
1541   GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
1542                                          &free_direct_neighbors, NULL);
1543   GNUNET_CONTAINER_multihashmap_destroy (direct_neighbors);
1544   GNUNET_CONTAINER_multihashmap_iterate (all_routes,
1545                                          &free_route, NULL);
1546   GNUNET_CONTAINER_multihashmap_destroy (all_routes);
1547   GNUNET_CORE_disconnect (core_api);
1548   core_api = NULL;
1549   GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1550   stats = NULL;
1551   while (NULL != (pending = plugin_pending_head))
1552   {
1553     GNUNET_CONTAINER_DLL_remove (plugin_pending_head,
1554                                  plugin_pending_tail,
1555                                  pending);
1556     GNUNET_free (pending);
1557   }
1558   for (i=0;i<DEFAULT_FISHEYE_DEPTH - 1;i++)
1559     GNUNET_array_grow (consensi[i].targets,
1560                        consensi[i].array_length,
1561                        0);
1562 }
1563
1564
1565 /**
1566  * Handle START-message.  This is the first message sent to us
1567  * by the client (can only be one!).
1568  *
1569  * @param cls closure (always NULL)
1570  * @param client identification of the client
1571  * @param message the actual message
1572  */
1573 static void
1574 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
1575               const struct GNUNET_MessageHeader *message)
1576 {
1577   if (NULL != client_handle)
1578   {
1579     /* forcefully drop old client */
1580     GNUNET_SERVER_client_disconnect (client_handle);
1581     GNUNET_SERVER_client_drop (client_handle);
1582   }
1583   client_handle = client;
1584   GNUNET_SERVER_client_keep (client_handle);
1585   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1586 }
1587
1588
1589 /**
1590  * Called on core init.
1591  *
1592  * @param cls unused
1593  * @param server legacy
1594  * @param identity this peer's identity
1595  */
1596 static void
1597 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1598            const struct GNUNET_PeerIdentity *identity)
1599 {
1600   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1601               "I am peer: %s\n",
1602               GNUNET_i2s (identity));
1603   my_identity = *identity;
1604 }
1605
1606
1607 /**
1608  * Process dv requests.
1609  *
1610  * @param cls closure
1611  * @param server the initialized server
1612  * @param c configuration to use
1613  */
1614 static void
1615 run (void *cls, struct GNUNET_SERVER_Handle *server,
1616      const struct GNUNET_CONFIGURATION_Handle *c)
1617 {
1618   static struct GNUNET_CORE_MessageHandler core_handlers[] = {
1619     {&handle_dv_route_message, GNUNET_MESSAGE_TYPE_DV_ROUTE, 0},
1620     {NULL, 0, 0}
1621   };
1622   static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
1623     {&handle_start, NULL, 
1624      GNUNET_MESSAGE_TYPE_DV_START, 
1625      sizeof (struct GNUNET_MessageHeader) },
1626     { &handle_dv_send_message, NULL, 
1627       GNUNET_MESSAGE_TYPE_DV_SEND, 
1628       0},
1629     {NULL, NULL, 0, 0}
1630   };
1631
1632   cfg = c;
1633   direct_neighbors = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
1634   all_routes = GNUNET_CONTAINER_multihashmap_create (65536, GNUNET_NO);
1635   core_api = GNUNET_CORE_connect (cfg, NULL,
1636                                   &core_init, 
1637                                   &handle_core_connect,
1638                                   &handle_core_disconnect,
1639                                   NULL, GNUNET_NO, 
1640                                   NULL, GNUNET_NO, 
1641                                   core_handlers);
1642
1643   if (NULL == core_api)
1644     return;
1645   stats = GNUNET_STATISTICS_create ("dv", cfg);
1646   GNUNET_SERVER_add_handlers (server, plugin_handlers);
1647   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1648                                 &shutdown_task, NULL);
1649 }
1650
1651
1652 /**
1653  * The main function for the dv service.
1654  *
1655  * @param argc number of arguments from the command line
1656  * @param argv command line arguments
1657  * @return 0 ok, 1 on error
1658  */
1659 int
1660 main (int argc, char *const *argv)
1661 {
1662   return (GNUNET_OK ==
1663           GNUNET_SERVICE_run (argc, argv, "dv", GNUNET_SERVICE_OPTION_NONE,
1664                               &run, NULL)) ? 0 : 1;
1665 }
1666
1667 /* end of gnunet-service-dv.c */