b1cf51dd94327ad61b850484f2ee17f4540d4cb7
[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 #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_consensus_service.h"
38 #include "dv.h"
39
40 /**
41  * How often do we establish the consensu?
42  */
43 #define GNUNET_DV_CONSENSUS_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5))
44
45 /**
46  * The default fisheye depth, from how many hops away will
47  * we keep peers?
48  */
49 #define DEFAULT_FISHEYE_DEPTH 3
50
51 /**
52  * How many hops is a direct neighbor away?
53  */
54 #define DIRECT_NEIGHBOR_COST 1
55
56
57 GNUNET_NETWORK_STRUCT_BEGIN
58
59 /**
60  * Information about a peer DV can route to.  These entries are what
61  * we use as the binary format to establish consensus to create our
62  * routing table and as the address format in the HELLOs.
63  */
64 struct Target
65 {
66
67   /**
68    * Identity of the peer we can reach.
69    */
70   struct GNUNET_PeerIdentity peer;
71
72   /**
73    * How many hops (1-3) is this peer away?
74    */
75   uint32_t distance GNUNET_PACKED;
76
77 };
78
79
80 /**
81  * Message exchanged between DV services (via core), requesting a
82  * message to be routed.  
83  */
84 struct RouteMessage
85 {
86   /**
87    * Type: GNUNET_MESSAGE_TYPE_DV_ROUTE
88    */
89   struct GNUNET_MessageHeader header;
90
91   /**
92    * Expected (remaining) distance.  Must be always smaller than
93    * DEFAULT_FISHEYE_DEPTH, should be zero at the target.  Must
94    * be decremented by one at each hop.  Peers must not forward
95    * these messages further once the counter has reached zero.
96    */
97   uint32_t distance GNUNET_PACKED;
98
99   /**
100    * The (actual) target of the message (this peer, if distance is zero).
101    */
102   struct GNUNET_PeerIdentity target;
103
104 };
105
106 GNUNET_NETWORK_STRUCT_END
107
108
109 /**
110  * Linked list of messages to send to clients.
111  */
112 struct PendingMessage
113 {
114   /**
115    * Pointer to next item in the list
116    */
117   struct PendingMessage *next;
118
119   /**
120    * Pointer to previous item in the list
121    */
122   struct PendingMessage *prev;
123
124   /**
125    * Actual message to be sent, allocated after this struct.
126    */
127   const struct GNUNET_MessageHeader *msg;
128
129   /**
130    * Ultimate target for the message.
131    */
132   struct GNUNET_PeerIdentity ultimate_target;
133
134   /**
135    * Unique ID of the message.
136    */
137   uint32_t uid;
138
139 };
140
141
142 /**
143  * Information about a direct neighbor (core-level, excluding
144  * DV-links, only DV-enabled peers).
145  */
146 struct DirectNeighbor
147 {
148
149   /**
150    * Identity of the peer.
151    */
152   struct GNUNET_PeerIdentity peer;
153   
154   /**
155    * Head of linked list of messages to send to this peer.
156    */
157   struct PendingMessage *pm_head;
158
159   /**
160    * Tail of linked list of messages to send to this peer.
161    */
162   struct PendingMessage *pm_tail;
163
164   /**
165    * Transmit handle to core service.
166    */
167   struct GNUNET_CORE_TransmitHandle *cth;
168
169   /**
170    * Routing table of the neighbor, NULL if not yet established.
171    * Keys are peer identities, values are 'struct Target' entries.
172    * Note that the distances in the targets are from the point-of-view
173    * of the peer, not from us!
174    */ 
175   struct GNUNET_CONTAINER_MultiHashMap *neighbor_table;
176
177   /**
178    * Updated routing table of the neighbor, under construction,
179    * NULL if we are not currently building it.
180    * Keys are peer identities, values are 'struct Target' entries.
181    * Note that the distances in the targets are from the point-of-view
182    * of the peer, not from us!
183    */ 
184   struct GNUNET_CONTAINER_MultiHashMap *neighbor_table_consensus;
185
186   /**
187    * Active consensus, if we are currently synchronizing the
188    * routing tables.
189    */
190   struct GNUNET_CONSENSUS_Handle *consensus;
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
206
207 /**
208  * A route includes information about the next hop,
209  * the target, and the ultimate distance to the
210  * target.
211  */
212 struct Route
213 {
214
215   /**
216    * Which peer do we need to forward the message to?
217    */
218   struct DirectNeighbor *next_hop;
219
220   /**
221    * What would be the target, and how far is it away?
222    */
223   struct Target target;
224
225   /**
226    * Offset of this target in the respective consensus set.
227    */
228   unsigned int set_offset;
229
230 };
231
232
233 /**
234  * Set of targets we bring to a consensus; all targets in a set have a
235  * distance equal to the sets distance (which is implied by the array
236  * index of the set).
237  */
238 struct ConsensusSet
239 {
240
241   /**
242    * Array of targets in the set, may include NULL entries if a
243    * neighbor has disconnected; the targets are allocated with the
244    * respective container (all_routes), not here.
245    */
246   struct Route **targets;
247
248   /**
249    * Size of the 'targets' array.
250    */
251   unsigned int array_length;
252
253 };
254
255
256 /**
257  * Hashmap of all of our direct neighbors (no DV routing).
258  */
259 static struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
260
261 /**
262  * Hashmap with all routes that we currently support; contains 
263  * routing information for all peers from distance 2
264  * up to distance DEFAULT_FISHEYE_DEPTH.
265  */
266 static struct GNUNET_CONTAINER_MultiHashMap *all_routes;
267
268 /**
269  * Array of consensus sets we expose to the outside world.  Sets
270  * are structured by the distance to the target.
271  */
272 static struct ConsensusSet consensi[DEFAULT_FISHEYE_DEPTH - 1];
273
274 /**
275  * ID of the task we use to (periodically) update our consensus
276  * with other peers.
277  */
278 static GNUNET_SCHEDULER_Task consensus_task;
279
280 /**
281  * Handle to the core service api.
282  */
283 static struct GNUNET_CORE_Handle *core_api;
284
285 /**
286  * The identity of our peer.
287  */
288 static struct GNUNET_PeerIdentity my_identity;
289
290 /**
291  * The configuration for this service.
292  */
293 static const struct GNUNET_CONFIGURATION_Handle *cfg;
294
295 /**
296  * The client, the DV plugin connected to us.  Hopefully
297  * this client will never change, although if the plugin dies
298  * and returns for some reason it may happen.
299  */
300 static struct GNUNET_SERVER_Client *client_handle;
301
302 /**
303  * Transmit handle to the plugin.
304  */
305 static struct GNUNET_SERVER_TransmitHandle *plugin_transmit_handle;
306
307 /**
308  * Head of DLL for client messages
309  */
310 static struct PendingMessage *plugin_pending_head;
311
312 /**
313  * Tail of DLL for client messages
314  */
315 static struct PendingMessage *plugin_pending_tail;
316
317 /**
318  * Handle for the statistics service.
319  */
320 struct GNUNET_STATISTICS_Handle *stats;
321
322 /**
323  * How far out to keep peers we learn about.
324  */
325 static unsigned long long fisheye_depth;
326
327
328 /**
329  * Get distance information from 'atsi'.
330  *
331  * @param atsi performance data
332  * @param atsi_count number of entries in atsi
333  * @return connected transport distance
334  */
335 static uint32_t
336 get_atsi_distance (const struct GNUNET_ATS_Information *atsi,
337                    unsigned int atsi_count)
338 {
339   unsigned int i;
340
341   for (i = 0; i < atsi_count; i++)
342     if (ntohl (atsi[i].type) == GNUNET_ATS_QUALITY_NET_DISTANCE)
343       return ntohl (atsi->value);
344   /* FIXME: we do not have distance data? Assume direct neighbor. */
345   return DIRECT_NEIGHBOR_COST;
346 }
347
348
349 /**
350  * Function called to notify a client about the socket
351  * begin ready to queue more data.  "buf" will be
352  * NULL and "size" zero if the socket was closed for
353  * writing in the meantime.
354  *
355  * @param cls closure
356  * @param size number of bytes available in buf
357  * @param buf where the callee should write the message
358  * @return number of bytes written to buf
359  */
360 static size_t
361 transmit_to_plugin (void *cls, size_t size, void *buf)
362 {
363   char *cbuf = buf;
364   struct PendingMessage *reply;
365   size_t off;
366   size_t msize;
367
368   plugin_transmit_handle = NULL;
369   if (NULL == buf)
370   {
371     /* client disconnected */    
372     return 0;
373   }
374   off = 0;
375   while ( (NULL != (reply = plugin_pending_head)) &&
376           (size >= off + (msize = ntohs (reply->msg->size))))
377   {
378     GNUNET_CONTAINER_DLL_remove (plugin_pending_head, plugin_pending_tail,
379                                  reply);
380     memcpy (&cbuf[off], reply->msg, msize);
381     GNUNET_free (reply);
382     off += msize;
383   }
384   if (NULL != plugin_pending_head)
385     plugin_transmit_handle =
386       GNUNET_SERVER_notify_transmit_ready (client_handle,
387                                            msize,
388                                            GNUNET_TIME_UNIT_FOREVER_REL,
389                                            &transmit_to_plugin, NULL);
390   return off;
391 }
392
393
394 /**
395  * Forward a message from another peer to the plugin.
396  *
397  * @param message the message to send to the plugin
398  * @param distant_neighbor the original sender of the message
399  * @param distnace distance to the original sender of the message
400  */
401 static void
402 send_data_to_plugin (const struct GNUNET_MessageHeader *message, 
403                      struct GNUNET_PeerIdentity *distant_neighbor, 
404                      uint32_t distance)
405 {
406   struct GNUNET_DV_ReceivedMessage *received_msg;
407   struct PendingMessage *pending_message;
408   size_t size;
409
410   if (NULL == client_handle)
411   {
412     GNUNET_STATISTICS_update (stats,
413                               "# messages discarded (no plugin)",
414                               1, GNUNET_NO);
415     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
416                 _("Refusing to queue messages, DV plugin not active.\n"));
417     return;
418   }
419   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420               "Delivering message from peer `%s'\n",
421               GNUNET_i2s (distant_neighbor));
422   size = sizeof (struct GNUNET_DV_ReceivedMessage) + 
423     ntohs (message->size);
424   if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
425   {    
426     GNUNET_break (0); /* too big */
427     return;
428   }
429   pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
430   received_msg = (struct GNUNET_DV_ReceivedMessage *) &pending_message[1];
431   received_msg->header.size = htons (size);
432   received_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DV_RECV);
433   received_msg->distance = htonl (distance);
434   received_msg->sender = *distant_neighbor;
435   memcpy (&received_msg[1], message, ntohs (message->size));
436   GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head, 
437                                     plugin_pending_tail,
438                                     pending_message);  
439   if (NULL == plugin_transmit_handle)
440     plugin_transmit_handle =
441       GNUNET_SERVER_notify_transmit_ready (client_handle, size,
442                                            GNUNET_TIME_UNIT_FOREVER_REL,
443                                            &transmit_to_plugin, NULL);
444 }
445
446
447 /**
448  * Forward a control message to the plugin.
449  *
450  * @param message the message to send to the plugin
451  * @param distant_neighbor the original sender of the message
452  * @param distnace distance to the original sender of the message
453  */
454 static void
455 send_control_to_plugin (const struct GNUNET_MessageHeader *message)
456 {
457   struct PendingMessage *pending_message;
458   size_t size;
459
460   if (NULL == client_handle)
461   {
462     GNUNET_STATISTICS_update (stats,
463                               "# control messages discarded (no plugin)",
464                               1, GNUNET_NO);
465     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
466                 _("Refusing to queue messages, DV plugin not active.\n"));
467     return;
468   }
469   size = ntohs (message->size);
470   pending_message = GNUNET_malloc (sizeof (struct PendingMessage) + size);
471   memcpy (&pending_message[1], message, size);
472   GNUNET_CONTAINER_DLL_insert_tail (plugin_pending_head, 
473                                     plugin_pending_tail,
474                                     pending_message);  
475   if (NULL == plugin_transmit_handle)
476     plugin_transmit_handle =
477       GNUNET_SERVER_notify_transmit_ready (client_handle, size,
478                                            GNUNET_TIME_UNIT_FOREVER_REL,
479                                            &transmit_to_plugin, NULL);
480 }
481
482
483 /**
484  * Give an ACK message to the plugin, we transmitted a message for it.
485  *
486  * @param target peer that received the message
487  * @param uid plugin-chosen UID for the message
488  */
489 static void
490 send_ack_to_plugin (struct GNUNET_PeerIdentity *target, 
491                     uint32_t uid)
492 {
493   struct GNUNET_DV_AckMessage ack_msg;
494
495   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496               "Delivering ACK for message to peer `%s'\n",
497               GNUNET_i2s (target));
498   ack_msg.header.size = htons (sizeof (ack_msg));
499   ack_msg.header.type = htons (GNUNET_MESSAGE_TYPE_DV_SEND_ACK);
500   ack_msg.uid = htonl (uid);
501   ack_msg.target = *target;
502   send_control_to_plugin (&ack_msg.header);
503 }
504
505
506 /**
507  * Give a CONNECT message to the plugin.
508  *
509  * @param target peer that connected
510  * @param distance distance to the target
511  */
512 static void
513 send_connect_to_plugin (const struct GNUNET_PeerIdentity *target, 
514                         uint32_t distance)
515 {
516   struct GNUNET_DV_ConnectMessage cm;
517
518   if (NULL == client_handle)
519     return;
520   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521               "Delivering CONNECT about peer `%s'\n",
522               GNUNET_i2s (target));
523   cm.header.size = htons (sizeof (cm));
524   cm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_CONNECT);
525   cm.distance = htonl (distance);
526   cm.peer = *target;
527   send_control_to_plugin (&cm.header);
528 }
529
530
531 /**
532  * Give a DISCONNECT message to the plugin.
533  *
534  * @param target peer that disconnected
535  */
536 static void
537 send_disconnect_to_plugin (const struct GNUNET_PeerIdentity *target)
538 {
539   struct GNUNET_DV_DisconnectMessage dm;
540
541   if (NULL == client_handle)
542     return;
543   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544               "Delivering DISCONNECT about peer `%s'\n",
545               GNUNET_i2s (target));
546   dm.header.size = htons (sizeof (dm));
547   dm.header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
548   dm.reserved = htonl (0);
549   dm.peer = *target;
550   send_control_to_plugin (&dm.header);
551 }
552
553
554 /**
555  * Function called to transfer a message to another peer
556  * via core.
557  *
558  * @param cls closure with the direct neighbor
559  * @param size number of bytes available in buf
560  * @param buf where the callee should write the message
561  * @return number of bytes written to buf
562  */
563 static size_t
564 core_transmit_notify (void *cls, size_t size, void *buf)
565 {
566   struct DirectNeighbor *dn = cls;
567   char *cbuf = buf;
568   struct PendingMessage *pending;
569   size_t off;
570   size_t msize;
571
572   dn->cth = NULL;
573   if (NULL == buf)
574   {
575     /* peer disconnected */
576     return 0;
577   }
578   off = 0;
579   pending = dn->pm_head;
580   off = 0;
581   while ( (NULL != (pending = dn->pm_head)) &&
582           (size >= off + (msize = ntohs (pending->msg->size))))
583   {
584     GNUNET_CONTAINER_DLL_remove (dn->pm_head,
585                                  dn->pm_tail,
586                                  pending);
587     memcpy (&cbuf[off], pending->msg, msize);
588     send_ack_to_plugin (&pending->ultimate_target,
589                         pending->uid);
590     GNUNET_free (pending);
591     off += msize;
592   }
593   if (NULL != dn->pm_head)
594     dn->cth =
595       GNUNET_CORE_notify_transmit_ready (core_api,
596                                          GNUNET_YES /* cork */,
597                                          0 /* priority */,
598                                          GNUNET_TIME_UNIT_FOREVER_REL,
599                                          &dn->peer,
600                                          msize,                                  
601                                          &core_transmit_notify, dn);
602   return off;
603 }
604
605
606 /**
607  * Find a free slot for storing a 'route' in the 'consensi'
608  * set at the given distance.
609  *
610  * @param distance distance to use for the set slot
611  */
612 static unsigned int
613 get_consensus_slot (uint32_t distance)
614 {
615   struct ConsensusSet *cs;
616   unsigned int i;
617
618   cs = &consensi[distance];
619   i = 0;
620   while ( (i < cs->array_length) &&
621           (NULL != cs->targets[i]) ) i++;
622   if (i == cs->array_length)
623     GNUNET_array_grow (cs->targets,
624                        cs->array_length,
625                        cs->array_length * 2 + 2);
626   return i;
627 }
628
629
630 /**
631  * Allocate a slot in the consensus set for a route.
632  *
633  * @param route route to initialize
634  * @param distance which consensus set to use
635  */
636 static void
637 allocate_route (struct Route *route,
638                 uint32_t distance)
639 {
640   unsigned int i;
641
642   i = get_consensus_slot (distance);
643   route->set_offset = i;
644   consensi[distance].targets[i] = route;
645   route->target.distance = distance;
646 }
647
648
649 /**
650  * Release a slot in the consensus set for a route.
651  *
652  * @param route route to release the slot from
653  */
654 static void
655 release_route (struct Route *route)
656 {
657   consensi[route->target.distance].targets[route->set_offset] = NULL;
658   route->set_offset = UINT_MAX; /* indicate invalid slot */
659 }
660
661
662 /**
663  * Move a route from one consensus set to another.
664  *
665  * @param route route to move
666  * @param new_distance new distance for the route (destination set)
667  */
668 static void
669 move_route (struct Route *route,
670             uint32_t new_distance)
671 {
672   unsigned int i;
673
674   release_route (route);
675   i = get_consensus_slot (new_distance);
676   route->set_offset = i;
677   consensi[new_distance].targets[i] = route;     
678   route->target.distance = new_distance;
679 }
680
681
682 /**
683  * Method called whenever a peer connects.
684  *
685  * @param cls closure
686  * @param peer peer identity this notification is about
687  * @param atsi performance data
688  * @param atsi_count number of entries in atsi
689  */
690 static void
691 handle_core_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
692                      const struct GNUNET_ATS_Information *atsi,
693                      unsigned int atsi_count)
694 {
695   struct DirectNeighbor *neighbor;
696   struct Route *route;
697   uint32_t distance;
698
699   /* Check for connect to self message */
700   if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
701     return;
702   distance = get_atsi_distance (atsi, atsi_count);
703   neighbor = GNUNET_CONTAINER_multihashmap_get (direct_neighbors, 
704                                                 &peer->hashPubKey);
705   if (NULL != neighbor)
706   {
707     GNUNET_break (0);
708     return;
709   }
710   if (DIRECT_NEIGHBOR_COST != distance) 
711     return; /* is a DV-neighbor */
712   neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
713   neighbor->peer = *peer;
714   GNUNET_assert (GNUNET_YES ==
715                  GNUNET_CONTAINER_multihashmap_put (direct_neighbors,
716                                                     &peer->hashPubKey,
717                                                     neighbor,
718                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
719   route = GNUNET_CONTAINER_multihashmap_get (all_routes, 
720                                              &peer->hashPubKey);
721   if (NULL != route)  
722   {
723     send_disconnect_to_plugin (peer);
724     release_route (route);
725     GNUNET_free (route);
726   }
727   route->next_hop = neighbor;
728   // FIXME: begin exchange_routing_information!
729 }
730
731
732
733 /**
734  * Core handler for DV data messages.  Whatever this message
735  * contains all we really have to do is rip it out of its
736  * DV layering and give it to our pal the DV plugin to report
737  * in with.
738  *
739  * @param cls closure
740  * @param peer peer which sent the message (immediate sender)
741  * @param message the message
742  * @param atsi transport ATS information (latency, distance, etc.)
743  * @param atsi_count number of entries in atsi
744  */
745 static int
746 handle_dv_route_message (void *cls, const struct GNUNET_PeerIdentity *peer,
747                          const struct GNUNET_MessageHeader *message,
748                          const struct GNUNET_ATS_Information *atsi,
749                          unsigned int atsi_count)
750 {
751   GNUNET_break (0); // FIXME
752   return GNUNET_OK;  
753 }
754
755
756 /**
757  * Service server's handler for message send requests (which come
758  * bubbling up to us through the DV plugin).
759  *
760  * @param cls closure
761  * @param client identification of the client
762  * @param message the actual message
763  */
764 static void
765 handle_dv_send_message (void *cls, struct GNUNET_SERVER_Client *client,
766                         const struct GNUNET_MessageHeader *message)
767 {
768   GNUNET_break (0); // FIXME
769   GNUNET_SERVER_receive_done (client, GNUNET_OK);
770 }
771
772
773 /**
774  * Multihashmap iterator for freeing routes that go via a particular
775  * neighbor that disconnected and is thus no longer available.
776  *
777  * @param cls the direct neighbor that is now unavailable
778  * @param key key value stored under
779  * @param value a 'struct Route' that may or may not go via neighbor
780  *
781  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
782  */
783 static int
784 cull_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
785 {
786   struct DirectNeighbor *neighbor = cls;
787   struct Route *route = value;
788
789   if (route->next_hop != neighbor)
790     return GNUNET_YES; /* not affected */
791   GNUNET_assert (GNUNET_YES ==
792                  GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
793   release_route (route);
794   send_disconnect_to_plugin (&route->target.peer);
795   GNUNET_free (route);
796   return GNUNET_YES;
797 }
798
799
800 /**
801  * Multihashmap iterator for checking if a given route is
802  * (now) useful to this peer.
803  *
804  * @param cls the direct neighbor for the given route
805  * @param key key value stored under
806  * @param value a 'struct Target' that may or may not be useful; not that
807  *        the distance in 'target' does not include the first hop yet
808  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
809  */
810 static int
811 check_possible_route (void *cls, const struct GNUNET_HashCode * key, void *value)
812 {
813   struct DirectNeighbor *neighbor = cls;
814   struct Target *target = value;
815   struct Route *route;
816   
817   route = GNUNET_CONTAINER_multihashmap_get (all_routes,
818                                            key);
819   if (NULL != route)
820   {
821     if (route->target.distance > target->distance + 1)
822     {
823       /* this 'target' is cheaper than the existing route; switch to alternative route! */
824       move_route (route, target->distance + 1);
825       route->next_hop = neighbor;
826       // FIXME: notify plugin about distance update?
827     }
828     return GNUNET_YES; /* got a route to this target already */
829   }
830   route = GNUNET_malloc (sizeof (struct Route));
831   route->next_hop = neighbor;
832   route->target.distance = target->distance + 1;
833   route->target.peer = target->peer;
834   allocate_route (route, route->target.distance);
835   GNUNET_assert (GNUNET_YES ==
836                  GNUNET_CONTAINER_multihashmap_put (all_routes,
837                                                     &route->target.peer.hashPubKey,
838                                                     route,
839                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
840   send_connect_to_plugin (&route->target.peer, target->distance);
841   return GNUNET_YES;
842 }
843
844
845 /**
846  * Multihashmap iterator for finding routes that were previously
847  * "hidden" due to a better route (called after a disconnect event).
848  *
849  * @param cls NULL
850  * @param key peer identity of the given direct neighbor
851  * @param value a 'struct DirectNeighbor' to check for additional routes
852  * @return GNUNET_YES to continue iteration
853  */
854 static int
855 refresh_routes (void *cls, const struct GNUNET_HashCode * key, void *value)
856 {
857   struct DirectNeighbor *neighbor = value;
858
859   if (NULL != neighbor->neighbor_table)
860     GNUNET_CONTAINER_multihashmap_iterate (neighbor->neighbor_table,
861                                            &check_possible_route,
862                                            neighbor);
863   return GNUNET_YES;
864 }
865
866
867 /**
868  * Cleanup all of the data structures associated with a given neighbor.
869  *
870  * @param neighbor neighbor to clean up
871  */
872 static void
873 cleanup_neighbor (struct DirectNeighbor *neighbor)
874 {
875   struct PendingMessage *pending;
876
877   while (NULL != (pending = neighbor->pm_head))
878   {
879     GNUNET_CONTAINER_DLL_remove (neighbor->pm_head,
880                                  neighbor->pm_tail,
881                                  pending);    
882     GNUNET_free (pending);
883   }
884   GNUNET_CONTAINER_multihashmap_iterate (all_routes,
885                                          &cull_routes,
886                                          neighbor);
887   if (NULL != neighbor->cth)
888   {
889     GNUNET_CORE_notify_transmit_ready_cancel (neighbor->cth);
890     neighbor->cth = NULL;
891   }
892   GNUNET_assert (GNUNET_YES ==
893                  GNUNET_CONTAINER_multihashmap_remove (direct_neighbors, 
894                                                        &neighbor->peer.hashPubKey,
895                                                        neighbor));
896   GNUNET_free (neighbor);
897 }
898
899
900 /**
901  * Method called whenever a given peer disconnects.
902  *
903  * @param cls closure
904  * @param peer peer identity this notification is about
905  */
906 static void
907 handle_core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
908 {
909   struct DirectNeighbor *neighbor;
910
911   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
912               "Received core peer disconnect message for peer `%s'!\n",
913               GNUNET_i2s (peer));
914   /* Check for disconnect from self message */
915   if (0 == memcmp (&my_identity, peer, sizeof (struct GNUNET_PeerIdentity)))
916     return;
917   neighbor =
918       GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey);
919   if (NULL == neighbor)
920   {
921     /* must have been a DV-neighbor, ignore */
922     return;
923   }
924   cleanup_neighbor (neighbor);
925   GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
926                                          &refresh_routes,
927                                          NULL);
928 }
929
930
931 /**
932  * Multihashmap iterator for freeing routes.  Should never be called.
933  *
934  * @param cls NULL
935  * @param key key value stored under
936  * @param value the route to be freed
937  *
938  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
939  */
940 static int
941 free_route (void *cls, const struct GNUNET_HashCode * key, void *value)
942 {
943   struct Route *route = value;
944
945   GNUNET_break (0);
946   GNUNET_assert (GNUNET_YES ==
947                  GNUNET_CONTAINER_multihashmap_remove (all_routes, key, value));
948   release_route (route);
949   send_disconnect_to_plugin (&route->target.peer);
950   GNUNET_free (route);
951   return GNUNET_YES;
952 }
953
954
955 /**
956  * Multihashmap iterator for freeing direct neighbors. Should never be called.
957  *
958  * @param cls NULL
959  * @param key key value stored under
960  * @param value the direct neighbor to be freed
961  *
962  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
963  */
964 static int
965 free_direct_neighbors (void *cls, const struct GNUNET_HashCode * key, void *value)
966 {
967   struct DirectNeighbor *neighbor = value;
968
969   GNUNET_break (0);
970   cleanup_neighbor (neighbor);
971   return GNUNET_YES;
972 }
973
974
975 /**
976  * Task run during shutdown.
977  *
978  * @param cls unused
979  * @param tc unused
980  */
981 static void
982 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
983 {
984   struct PendingMessage *pending;
985   unsigned int i;
986
987   GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors,
988                                          &free_direct_neighbors, NULL);
989   GNUNET_CONTAINER_multihashmap_destroy (direct_neighbors);
990   GNUNET_CONTAINER_multihashmap_iterate (all_routes,
991                                          &free_route, NULL);
992   GNUNET_CONTAINER_multihashmap_destroy (all_routes);
993   GNUNET_CORE_disconnect (core_api);
994   core_api = NULL;
995   GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
996   stats = NULL;
997   while (NULL != (pending = plugin_pending_head))
998   {
999     GNUNET_CONTAINER_DLL_remove (plugin_pending_head,
1000                                  plugin_pending_tail,
1001                                  pending);
1002     GNUNET_free (pending);
1003   }
1004   for (i=0;i<DEFAULT_FISHEYE_DEPTH - 1;i++)
1005     GNUNET_array_grow (consensi[i].targets,
1006                        consensi[i].array_length,
1007                        0);
1008 }
1009
1010
1011 /**
1012  * Handle START-message.  This is the first message sent to us
1013  * by the client (can only be one!).
1014  *
1015  * @param cls closure (always NULL)
1016  * @param client identification of the client
1017  * @param message the actual message
1018  */
1019 static void
1020 handle_start (void *cls, struct GNUNET_SERVER_Client *client,
1021               const struct GNUNET_MessageHeader *message)
1022 {
1023   if (NULL != client_handle)
1024   {
1025     /* forcefully drop old client */
1026     GNUNET_SERVER_client_disconnect (client_handle);
1027     GNUNET_SERVER_client_drop (client_handle);
1028   }
1029   client_handle = client;
1030   GNUNET_SERVER_client_keep (client_handle);
1031   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1032 }
1033
1034
1035 /**
1036  * Called on core init.
1037  *
1038  * @param cls unused
1039  * @param server legacy
1040  * @param identity this peer's identity
1041  */
1042 static void
1043 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1044            const struct GNUNET_PeerIdentity *identity)
1045 {
1046   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1047               "I am peer: %s\n",
1048               GNUNET_i2s (identity));
1049   my_identity = *identity;
1050 }
1051
1052
1053 /**
1054  * Process dv requests.
1055  *
1056  * @param cls closure
1057  * @param server the initialized server
1058  * @param c configuration to use
1059  */
1060 static void
1061 run (void *cls, struct GNUNET_SERVER_Handle *server,
1062      const struct GNUNET_CONFIGURATION_Handle *c)
1063 {
1064   static struct GNUNET_CORE_MessageHandler core_handlers[] = {
1065     {&handle_dv_route_message, GNUNET_MESSAGE_TYPE_DV_ROUTE, 0},
1066     {NULL, 0, 0}
1067   };
1068   static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
1069     {&handle_start, NULL, 
1070      GNUNET_MESSAGE_TYPE_DV_START, 
1071      sizeof (struct GNUNET_MessageHeader) },
1072     { &handle_dv_send_message, NULL, 
1073       GNUNET_MESSAGE_TYPE_DV_SEND, 
1074       0},
1075     {NULL, NULL, 0, 0}
1076   };
1077
1078   cfg = c;
1079   direct_neighbors = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
1080   all_routes = GNUNET_CONTAINER_multihashmap_create (65536, GNUNET_NO);
1081   core_api = GNUNET_CORE_connect (cfg, NULL,
1082                                   &core_init, 
1083                                   &handle_core_connect,
1084                                   &handle_core_disconnect,
1085                                   NULL, GNUNET_NO, 
1086                                   NULL, GNUNET_NO, 
1087                                   core_handlers);
1088
1089   if (NULL == core_api)
1090     return;
1091   stats = GNUNET_STATISTICS_create ("dv", cfg);
1092   GNUNET_SERVER_add_handlers (server, plugin_handlers);
1093   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1094                                 &shutdown_task, NULL);
1095 }
1096
1097
1098 /**
1099  * The main function for the dv service.
1100  *
1101  * @param argc number of arguments from the command line
1102  * @param argv command line arguments
1103  * @return 0 ok, 1 on error
1104  */
1105 int
1106 main (int argc, char *const *argv)
1107 {
1108   return (GNUNET_OK ==
1109           GNUNET_SERVICE_run (argc, argv, "dv", GNUNET_SERVICE_OPTION_NONE,
1110                               &run, NULL)) ? 0 : 1;
1111 }
1112
1113 /* end of gnunet-service-dv.c */