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