bb5e03193454f917020d7e25f9a642719f838581
[oweals/gnunet.git] / src / dv / gnunet-service-dv.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 2, 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_client_lib.h"
33 #include "gnunet_getopt_lib.h"
34 #include "gnunet_os_lib.h"
35 #include "gnunet_protocols.h"
36 #include "gnunet_service_lib.h"
37 #include "gnunet_core_service.h"
38 #include "gnunet_signal_lib.h"
39 #include "gnunet_util_lib.h"
40 #include "dv.h"
41
42 /**
43  * DV Service Context stuff goes here...
44  */
45
46 /**
47  * Handle to the core service api.
48  */
49 static struct GNUNET_CORE_Handle *coreAPI;
50
51 /**
52  * The identity of our peer.
53  */
54 const struct GNUNET_PeerIdentity *my_identity;
55
56 /**
57  * The configuration for this service.
58  */
59 const struct GNUNET_CONFIGURATION_Handle *cfg;
60
61 /**
62  * The scheduler for this service.
63  */
64 static struct GNUNET_SCHEDULER_Handle *sched;
65
66 /**
67  * How often do we check about sending out more peer information (if
68  * we are connected to no peers previously).
69  */
70 #define GNUNET_DV_DEFAULT_SEND_INTERVAL (500 * GNUNET_CRON_MILLISECONDS)
71
72 /**
73  * How long do we wait at most between sending out information?
74  */
75 #define GNUNET_DV_MAX_SEND_INTERVAL (5000 * GNUNET_CRON_MILLISECONDS)
76
77 /**
78  * How long can we have not heard from a peer and
79  * still have it in our tables?
80  */
81 #define GNUNET_DV_PEER_EXPIRATION_TIME (3000 * GNUNET_CRON_SECONDS)
82
83 /**
84  * Priority for gossip.
85  */
86 #define GNUNET_DV_DHT_GOSSIP_PRIORITY (GNUNET_EXTREME_PRIORITY / 10)
87
88 /**
89  * How often should we check if expiration time has elapsed for
90  * some peer?
91  */
92 #define GNUNET_DV_MAINTAIN_FREQUENCY (5 * GNUNET_CRON_SECONDS)
93
94 /**
95  * How long to allow a message to be delayed?
96  */
97 #define DV_DELAY (5000 * GNUNET_CRON_MILLISECONDS)
98
99 /**
100  * Priority to use for DV data messages.
101  */
102 #define DV_PRIORITY 0
103
104 /**
105  * The client, should be the DV plugin connected to us.  Hopefully
106  * this client will never change, although if the plugin dies
107  * and returns for some reason it may happen.
108  */
109 static struct GNUNET_SERVER_Client * client_handle;
110
111 GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
112
113 /**
114  * Struct where neighbor information is stored.
115  */
116 struct DistantNeighbor *referees;
117
118 /**
119  * Struct to hold information for updating existing neighbors
120  */
121 struct NeighborUpdateInfo
122 {
123   /**
124    * Cost
125    */
126   unsigned int cost;
127
128   /**
129    * The existing neighbor
130    */
131   struct DistantNeighbor *neighbor;
132
133   /**
134    * The referrer of the possibly existing peer
135    */
136   struct DirectNeighbor *referrer;
137
138   /**
139    * The time we heard about this peer
140    */
141   struct GNUNET_TIME_Absolute now;
142 };
143
144 /**
145  * Struct where actual neighbor information is stored,
146  * referenced by min_heap and max_heap.  Freeing dealt
147  * with when items removed from hashmap.
148  */
149 struct DirectNeighbor
150 {
151   /**
152    * Identity of neighbor.
153    */
154   struct GNUNET_PeerIdentity identity;
155
156   /**
157    * Head of DLL of nodes that this direct neighbor referred to us.
158    */
159   struct DistantNeighbor *referee_head;
160
161   /**
162    * Tail of DLL of nodes that this direct neighbor referred to us.
163    */
164   struct DistantNeighbor *referee_tail;
165
166   /**
167    * Is this one of the direct neighbors that we are "hiding"
168    * from DV?
169    */
170   int hidden;
171 };
172
173
174 /**
175  * Struct where actual neighbor information is stored,
176  * referenced by min_heap and max_heap.  Freeing dealt
177  * with when items removed from hashmap.
178  */
179 struct DistantNeighbor
180 {
181   /**
182    * We keep distant neighbor's of the same referrer in a DLL.
183    */
184   struct DistantNeighbor *next;
185
186   /**
187    * We keep distant neighbor's of the same referrer in a DLL.
188    */
189   struct DistantNeighbor *prev;
190
191   /**
192    * Node in min heap
193    */
194   struct GNUNET_CONTAINER_HeapNode *min_loc;
195
196   /**
197    * Node in max heap
198    */
199   struct GNUNET_CONTAINER_HeapNode *max_loc;
200
201   /**
202    * Identity of referrer (next hop towards 'neighbor').
203    */
204   struct DirectNeighbor *referrer;
205
206   /**
207    * Identity of neighbor.
208    */
209   struct GNUNET_PeerIdentity identity;
210
211   /**
212    * Last time we received routing information from this peer
213    */
214   struct GNUNET_TIME_Absolute last_activity;
215
216   /**
217    * Cost to neighbor, used for actual distance vector computations
218    */
219   unsigned int cost;
220
221   /**
222    * Random identifier *we* use for this peer, to be used as shortcut
223    * instead of sending full peer id for each message
224    */
225   unsigned int our_id;
226
227   /**
228    * Random identifier the *referrer* uses for this peer.
229    */
230   unsigned int referrer_id;
231
232   /**
233    * Is this one of the direct neighbors that we are "hiding"
234    * from DV?
235    */
236   int hidden;
237 };
238
239
240 /**
241  * Global construct
242  */
243 struct GNUNET_DV_Context
244 {
245   /**
246    * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for all
247    * directly connected peers.
248    */
249   struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
250
251   /**
252    * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for
253    * peers connected via DV (extended neighborhood).  Does ALSO
254    * include any peers that are in 'direct_neighbors'; for those
255    * peers, the cost will be zero and the referrer all zeros.
256    */
257   struct GNUNET_CONTAINER_MultiHashMap *extended_neighbors;
258
259   /**
260    * We use the min heap (min refers to cost) to prefer
261    * gossipping about peers with small costs.
262    */
263   struct GNUNET_CONTAINER_Heap *neighbor_min_heap;
264
265   /**
266    * We use the max heap (max refers to cost) for general
267    * iterations over all peers and to remove the most costly
268    * connection if we have too many.
269    */
270   struct GNUNET_CONTAINER_Heap *neighbor_max_heap;
271
272   unsigned long long fisheye_depth;
273
274   unsigned long long max_table_size;
275
276   unsigned int send_interval;
277
278   unsigned int neighbor_id_loc;
279
280   int closing;
281 };
282
283 static char shortID[5];
284
285 static struct GNUNET_DV_Context ctx;
286
287 struct FindDestinationContext
288 {
289   unsigned int tid;
290   struct DistantNeighbor *dest;
291 };
292
293
294 /**
295  * We've been given a target ID based on the random numbers that
296  * we assigned to our DV-neighborhood.  Find the entry for the
297  * respective neighbor.
298  */
299 static int
300 find_destination (void *cls,
301                   struct GNUNET_CONTAINER_HeapNode *node,
302                   void *element, GNUNET_CONTAINER_HeapCostType cost)
303 {
304   struct FindDestinationContext *fdc = cls;
305   struct DistantNeighbor *dn = element;
306
307   if (fdc->tid != dn->our_id)
308     return GNUNET_YES;
309   fdc->dest = dn;
310   return GNUNET_NO;
311 }
312
313 /**
314  * Function called to notify a client about the socket
315  * begin ready to queue more data.  "buf" will be
316  * NULL and "size" zero if the socket was closed for
317  * writing in the meantime.
318  *
319  * @param cls closure
320  * @param size number of bytes available in buf
321  * @param buf where the callee should write the message
322  * @return number of bytes written to buf
323  */
324 size_t transmit_to_plugin (void *cls,
325                size_t size, void *buf)
326 {
327   struct GNUNET_DV_MessageReceived *msg = cls;
328
329   if (buf == NULL)
330     return 0;
331
332   GNUNET_assert(size >= ntohs(msg->header.size));
333
334   memcpy(buf, msg, size);
335   GNUNET_free(msg);
336   return size;
337 }
338
339
340 void send_to_plugin(const struct GNUNET_PeerIdentity * sender, const struct GNUNET_MessageHeader *message, size_t message_size, struct DistantNeighbor *distant_neighbor)
341 {
342   struct GNUNET_DV_MessageReceived *received_msg;
343   int size;
344
345   if (ntohs(msg->size) < sizeof(struct GNUNET_DV_MessageReceived))
346     return;
347
348   size = sizeof(struct GNUNET_DV_MessageReceived) + message_size + sizeof(struct GNUNET_PeerIdentity);
349   received_msg = GNUNET_malloc(size);
350   received_msg->header.size = htons(size);
351   received_msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE);
352   received_msg->sender_address_len = sizeof(struct GNUNET_PeerIdentity);
353   received_msg->distance = htonl(distant_neighbor->cost);
354   /* Set the sender in this message to be the original sender! */
355   memcpy(&received_msg->sender, &distant_neighbor->identity, sizeof(struct GNUNET_PeerIdentity));
356   /* Copy the intermediate sender to the end of the message, this is how the transport identifies this peer */
357   memcpy(&received_msg[1], sender, sizeof(struct GNUNET_PeerIdentity));
358
359   /* FIXME: Send to the client please */
360   GNUNET_SERVER_notify_transmit_ready (client_handle,
361                                        size, CLIENT_TRANSMIT_TIMEOUT,
362                                        &transmit_to_plugin, &received_msg);
363
364 }
365
366 /**
367  * Core handler for dv data messages.  Whatever this message
368  * contains all we really have to do is rip it out of its
369  * DV layering and give it to our pal the DV plugin to report
370  * in with.
371  *
372  * @param cls closure
373  * @param peer peer which sent the message (immediate sender)
374  * @param message the message
375  * @param latency the latency of the connection we received the message from
376  * @param distance the distance to the immediate peer
377  */
378 static int handle_dv_data_message (void *cls,
379                              const struct GNUNET_PeerIdentity * peer,
380                              const struct GNUNET_MessageHeader * message,
381                              struct GNUNET_TIME_Relative latency,
382                              uint32_t distance)
383 {
384 #if DEBUG_DV
385   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386               "%s: Receives %s message!\n", "dv", "DV DATA");
387 #endif
388
389   const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
390   const struct GNUNET_MessageHeader *packed_message = (const struct GNUNET_MessageHeader *) &incoming[1];
391   struct DirectNeighbor *dn;
392   struct DistantNeighbor *pos;
393   unsigned int sid;             /* Sender id */
394   unsigned int tid;             /* Target id */
395   struct GNUNET_PeerIdentity original_sender;
396   struct GNUNET_PeerIdentity destination;
397   struct FindDestinationContext fdc;
398   int ret;
399
400   if ((ntohs (incoming->header.size) <
401        sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader))
402       || (ntohs (incoming->header.size) !=
403           (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
404     {
405       return GNUNET_SYSERR;
406     }
407
408   dn = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
409                                   &peer->hashPubKey);
410   if (dn == NULL)
411     {
412       return GNUNET_OK;
413     }
414   sid = ntohl (incoming->sender);
415   pos = dn->referee_head;
416   while ((NULL != pos) && (pos->referrer_id != sid))
417     pos = pos->next;
418   if (pos == NULL)
419     {
420       /* unknown sender */
421       return GNUNET_OK;
422     }
423   original_sender = pos->identity;
424   tid = ntohl (incoming->recipient);
425   if (tid == 0)
426     {
427       /* 0 == us */
428
429       /* FIXME: Will we support wrapped messages being these types? Probably not, they should
430        * be encrypted messages that need decrypting and junk like that.
431        */
432       GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
433       GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
434       if ( (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
435           (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA) )
436       {
437         /* FIXME: send the message, wrap it up and return it to the DV plugin */
438         /*coreAPI->loopback_send (&original_sender, (const char *) packed_message,
439         ntohs (packed_message->size), GNUNET_YES, NULL);*/
440         send_to_plugin(peer, packed_message, ntohs(packed_message->size), pos);
441       }
442
443       return GNUNET_OK;
444     }
445
446   /* FIXME: this is the *only* per-request operation we have in DV
447      that is O(n) in relation to the number of connected peers; a
448      hash-table lookup could easily solve this (minor performance
449      issue) */
450   fdc.tid = tid;
451   fdc.dest = NULL;
452   GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
453                                  &find_destination, &fdc);
454   if (fdc.dest == NULL)
455     {
456       return GNUNET_OK;
457     }
458   destination = fdc.dest->identity;
459
460   if (0 == memcmp (&destination, peer, sizeof (struct GNUNET_PeerIdentity)))
461     {
462       /* FIXME: create stat: routing loop-discard! */
463       return GNUNET_OK;
464     }
465
466   /* FIXME: Can't send message on, we have to behave.
467    * We have to tell core we have a message for the next peer, and let
468    * transport do transport selection on how to get this message to 'em */
469   /*ret = send_message (&destination,
470                       &original_sender,
471                       packed_message, DV_PRIORITY, DV_DELAY);*/
472   send_to_core(&destination, &original_sender, packed_message, DV_PRIORITY, DV_DELAY);
473
474   return GNUNET_OK;
475 }
476
477 /**
478  * Core handler for dv gossip messages.  These will be used
479  * by us to create a HELLO message for the newly peer containing
480  * which direct peer we can connect through, and what the cost
481  * is.  This HELLO will then be scheduled for validation by the
482  * transport service so that it can be used by all others.
483  *
484  * @param cls closure
485  * @param peer peer which sent the message (immediate sender)
486  * @param message the message
487  * @param latency the latency of the connection we received the message from
488  * @param distance the distance to the immediate peer
489  */
490 static int handle_dv_gossip_message (void *cls,
491                                      const struct GNUNET_PeerIdentity *peer,
492                                      const struct GNUNET_MessageHeader *message,
493                                      struct GNUNET_TIME_Relative latency,
494                                      uint32_t distance)
495 {
496 #if DEBUG_DV
497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498               "%s: Receives %s message!\n", "dv", "DV GOSSIP");
499 #endif
500
501   return 0;
502 }
503
504
505 /**
506  * Service server's handler for message send requests (which come
507  * bubbling up to us through the DV plugin).
508  *
509  * @param cls closure
510  * @param client identification of the client
511  * @param message the actual message
512  */
513 void send_dv_message (void *cls,
514                       struct GNUNET_SERVER_Client * client,
515                       const struct GNUNET_MessageHeader * message)
516 {
517 #if DEBUG_DV
518   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519               "%s: Receives %s message!\n", "dv", "SEND");
520 #endif
521   if (client_handle == NULL)
522   {
523     client_handle = client;
524 #if DEBUG_DV
525   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
526               "%s: Setting initial client handle!\n", "dv");
527 #endif
528   }
529   else if (client_handle != client)
530   {
531     client_handle = client;
532     /* What should we do in this case, assert fail or just log the warning? */
533     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
534                 "%s: Setting client handle (was a different client!)!\n", "dv");
535   }
536
537   GNUNET_SERVER_receive_done(client, GNUNET_OK);
538 }
539
540
541 /**
542  * List of handlers for the messages understood by this
543  * service.
544  *
545  * Hmm... will we need to register some handlers with core and
546  * some handlers with our server here?  Because core should be
547  * getting the incoming DV messages (from whichever lower level
548  * transport) and then our server should be getting messages
549  * from the dv_plugin, right?
550  */
551 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
552   {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
553   {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
554   {NULL, 0, 0}
555 };
556
557
558 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
559   {&send_dv_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
560   {NULL, NULL, 0, 0}
561 };
562
563
564 /**
565  * Task run during shutdown.
566  *
567  * @param cls unused
568  * @param tc unused
569  */
570 static void
571 shutdown_task (void *cls,
572                const struct GNUNET_SCHEDULER_TaskContext *tc)
573 {
574
575   GNUNET_CORE_disconnect (coreAPI);
576 }
577
578 /**
579  * To be called on core init/fail.
580  */
581 void core_init (void *cls,
582                 struct GNUNET_CORE_Handle * server,
583                 const struct GNUNET_PeerIdentity *identity,
584                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
585 {
586
587   if (server == NULL)
588     {
589       GNUNET_SCHEDULER_cancel(sched, cleanup_task);
590       GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
591       return;
592     }
593 #if DEBUG_DV
594   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
595               "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s(identity));
596 #endif
597   my_identity = identity;
598   coreAPI = server;
599 }
600
601
602 /**
603  * Iterator over hash map entries.
604  *
605  * @param cls closure
606  * @param key current key code
607  * @param value value in the hash map
608  * @return GNUNET_YES if we should continue to
609  *         iterate,
610  *         GNUNET_NO if not.
611  */
612 static int update_matching_neighbors (void *cls,
613                                       const GNUNET_HashCode * key,
614                                       void *value)
615 {
616   struct NeighborUpdateInfo * update_info = cls;
617   struct DirectNeighbor *direct_neighbor = value;
618
619   if (update_info->referrer == direct_neighbor) /* Direct neighbor matches, update it's info and return GNUNET_NO */
620   {
621     /* same referrer, cost change! */
622     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
623                                        update_info->neighbor->max_loc, update_info->cost);
624     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
625                                        update_info->neighbor->min_loc, update_info->cost);
626     update_info->neighbor->last_activity = update_info->now;
627     update_info->neighbor->cost = update_info->cost;
628     return GNUNET_NO;
629   }
630
631   return GNUNET_YES;
632 }
633
634
635 /**
636  * Free a DistantNeighbor node, including removing it
637  * from the referer's list.
638  */
639 static void
640 distant_neighbor_free (struct DistantNeighbor *referee)
641 {
642   struct DirectNeighbor *referrer;
643
644   referrer = referee->referrer;
645   if (referrer != NULL)
646     {
647       GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
648                          referrer->referee_tail, referee);
649     }
650   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc);
651   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc);
652   GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors,
653                                     &referee->identity.hashPubKey);
654   GNUNET_free (referee);
655 }
656
657
658 /**
659  * Handles when a peer is either added due to being newly connected
660  * or having been gossiped about, also called when a cost for a neighbor
661  * needs to be updated.
662  *
663  * @param peer identity of the peer whose info is being added/updated
664  * @param peer_id id to use when sending to 'peer'
665  * @param referrer if this is a gossiped peer, who did we hear it from?
666  * @param cost the cost of communicating with this peer via 'referrer'
667  */
668 static void
669 addUpdateNeighbor (const struct GNUNET_PeerIdentity * peer,
670                    unsigned int referrer_peer_id,
671                    struct DirectNeighbor *referrer, unsigned int cost)
672 {
673   struct DistantNeighbor *neighbor;
674   struct DistantNeighbor *max;
675   struct GNUNET_TIME_Absolute now;
676   struct NeighborUpdateInfo *neighbor_update;
677   unsigned int our_id;
678
679   now = GNUNET_TIME_absolute_get ();
680   our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, RAND_MAX - 1) + 1;
681
682   neighbor = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
683                                                 &peer->hashPubKey);
684   neighbor_update = GNUNET_malloc(sizeof(struct NeighborUpdateInfo));
685   neighbor_update->neighbor = neighbor;
686   neighbor_update->cost = cost;
687   neighbor_update->now = now;
688   neighbor_update->referrer = referrer;
689
690   /* Either we do not know this peer, or we already do but via a different immediate peer */
691   if ((neighbor == NULL) ||
692       (GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
693                                                   &peer->hashPubKey,
694                                                   &update_matching_neighbors,
695                                                   neighbor_update) != GNUNET_SYSERR))
696     {
697       /* new neighbor! */
698       if (cost > ctx.fisheye_depth)
699         {
700           /* too costly */
701           return;
702         }
703       if (ctx.max_table_size <=
704           GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors))
705         {
706           /* remove most expensive entry */
707           max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
708           if (cost > max->cost)
709             {
710               /* new entry most expensive, don't create */
711               return;
712             }
713           if (max->cost > 0)
714             {
715               /* only free if this is not a direct connection;
716                  we could theoretically have more direct
717                  connections than DV entries allowed total! */
718               distant_neighbor_free (max);
719             }
720         }
721
722       neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
723       GNUNET_CONTAINER_DLL_insert (referrer->referee_head,
724                          referrer->referee_tail, neighbor);
725       neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap,
726                                                         neighbor, cost);
727       neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
728                                                         neighbor, cost);
729       neighbor->referrer = referrer;
730       memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
731       neighbor->last_activity = now;
732       neighbor->cost = cost;
733       neighbor->referrer_id = referrer_peer_id;
734       neighbor->our_id = our_id;
735       neighbor->hidden =
736         (cost == 0) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
737                        0) : GNUNET_NO;
738       GNUNET_CONTAINER_multihashmap_put (ctx.extended_neighbors, &peer->hashPubKey,
739                                  neighbor,
740                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
741
742       return;
743     }
744
745   /* Old logic to remove entry and replace, not needed now as we only want to remove when full
746    * or when the referring peer disconnects from us.
747    */
748   /*
749   GNUNET_DLL_remove (neighbor->referrer->referee_head,
750                      neighbor->referrer->referee_tail, neighbor);
751   neighbor->referrer = referrer;
752   GNUNET_DLL_insert (referrer->referee_head,
753                      referrer->referee_tail, neighbor);
754   GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
755                                      neighbor->max_loc, cost);
756   GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
757                                      neighbor->min_loc, cost);
758   neighbor->referrer_id = referrer_peer_id;
759   neighbor->last_activity = now;
760   neighbor->cost = cost;
761   */
762 }
763
764
765 /**
766  * Method called whenever a given peer either connects.
767  *
768  * @param cls closure
769  * @param peer peer identity this notification is about
770  * @param latency reported latency of the connection with peer
771  * @param distance reported distance (DV) to peer
772  */
773 void handle_core_connect (void *cls,
774                           const struct GNUNET_PeerIdentity * peer,
775                           struct GNUNET_TIME_Relative latency,
776                           uint32_t distance)
777 {
778   struct DirectNeighbor *neighbor;
779 #if DEBUG_DV
780   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781               "%s: Receives core connect message for peer %s distance %d!\n", "dv", GNUNET_i2s(peer), distance);
782 #endif
783
784   neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
785   memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
786   GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors,
787                              &peer->hashPubKey,
788                              neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
789   addUpdateNeighbor (peer, 0, neighbor, 0);
790 }
791
792 /**
793  * Method called whenever a given peer either connects.
794  *
795  * @param cls closure
796  * @param peer peer identity this notification is about
797  */
798 void handle_core_disconnect (void *cls,
799                              const struct GNUNET_PeerIdentity * peer)
800 {
801   struct DirectNeighbor *neighbor;
802   struct DistantNeighbor *referee;
803
804 #if DEBUG_DV
805   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
806               "%s: Receives core peer disconnect message!\n", "dv");
807 #endif
808
809   neighbor =
810     GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, &peer->hashPubKey);
811   if (neighbor == NULL)
812     {
813       return;
814     }
815   while (NULL != (referee = neighbor->referee_head))
816     distant_neighbor_free (referee);
817   GNUNET_assert (neighbor->referee_tail == NULL);
818   GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors,
819                                 &peer->hashPubKey, neighbor);
820   GNUNET_free (neighbor);
821 }
822
823
824 /**
825  * Process dv requests.
826  *
827  * @param cls closure
828  * @param scheduler scheduler to use
829  * @param server the initialized server
830  * @param c configuration to use
831  */
832 static void
833 run (void *cls,
834      struct GNUNET_SCHEDULER_Handle *scheduler,
835      struct GNUNET_SERVER_Handle *server,
836      const struct GNUNET_CONFIGURATION_Handle *c)
837 {
838   struct GNUNET_TIME_Relative timeout;
839
840   timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
841   sched = scheduler;
842   cfg = c;
843   GNUNET_SERVER_add_handlers (server, plugin_handlers);
844   coreAPI =
845   GNUNET_CORE_connect (sched,
846                        cfg,
847                        timeout,
848                        NULL, /* FIXME: anything we want to pass around? */
849                        &core_init,
850                        NULL, /* Don't care about pre-connects */
851                        &handle_core_connect,
852                        &handle_core_disconnect,
853                        NULL,
854                        GNUNET_NO,
855                        NULL,
856                        GNUNET_NO,
857                        core_handlers);
858
859   if (coreAPI == NULL)
860     return;
861   /* load (server); Huh? */
862
863   /* Scheduled the task to clean up when shutdown is called */
864
865   cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
866                                 GNUNET_TIME_UNIT_FOREVER_REL,
867                                 &shutdown_task,
868                                 NULL);
869 }
870
871
872 /**
873  * The main function for the dv service.
874  *
875  * @param argc number of arguments from the command line
876  * @param argv command line arguments
877  * @return 0 ok, 1 on error
878  */
879 int
880 main (int argc, char *const *argv)
881 {
882   return (GNUNET_OK ==
883           GNUNET_SERVICE_run (argc,
884                               argv,
885                               "dv",
886                               GNUNET_SERVICE_OPTION_NONE,
887                               &run, NULL)) ? 0 : 1;
888 }