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