check for NULL
[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 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 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500))
71
72 /**
73  * How long do we wait at most between sending out information?
74  */
75 #define GNUNET_DV_MAX_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
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 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1000))
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 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
93
94 /**
95  * How long to allow a message to be delayed?
96  */
97 #define DV_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
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 /**
112  * Task to run when we shut down, cleaning up all our trash
113  */
114 GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
115
116 /**
117  * Task to run to gossip about peers.  Will reschedule itself forever until shutdown!
118  */
119 GNUNET_SCHEDULER_TaskIdentifier gossip_task;
120
121 /**
122  * Struct where neighbor information is stored.
123  */
124 struct DistantNeighbor *referees;
125
126 static struct GNUNET_TIME_Relative client_transmit_timeout;
127
128 static struct GNUNET_TIME_Relative default_dv_delay;
129
130 static size_t default_dv_priority = 0;
131
132
133 /**
134  * Pending message struct, also a test to see if these can
135  * safely ONLY be freed by callback.
136  */
137 struct PendingMessage
138 {
139   /**
140    * Copy of message to be sent
141    */
142   struct GNUNET_MessageHeader *msg;
143
144   /**
145    * Size of message to be sent
146    */
147   size_t msg_size;
148
149   /**
150    * Transmit handle, for cancellation if necessary.
151    */
152   struct GNUNET_CORE_TransmitHandle *transmit_handle;
153
154 };
155
156
157 /**
158  * Context created whenever a direct peer connects to us,
159  * used to gossip other peers to it.
160  */
161 struct NeighborSendContext
162 {
163   /**
164    * The peer we will gossip to.
165    */
166   struct DirectNeighbor *toNeighbor;
167
168   /**
169    * The timeout for this task.
170    */
171   struct GNUNET_TIME_Relative timeout;
172
173   /**
174    * The task associated with this context.
175    */
176   GNUNET_SCHEDULER_TaskIdentifier task;
177
178 };
179
180
181 /**
182  * Struct to hold information for updating existing neighbors
183  */
184 struct NeighborUpdateInfo
185 {
186   /**
187    * Cost
188    */
189   unsigned int cost;
190
191   /**
192    * The existing neighbor
193    */
194   struct DistantNeighbor *neighbor;
195
196   /**
197    * The referrer of the possibly existing peer
198    */
199   struct DirectNeighbor *referrer;
200
201   /**
202    * The time we heard about this peer
203    */
204   struct GNUNET_TIME_Absolute now;
205 };
206
207 /**
208  * Struct where actual neighbor information is stored,
209  * referenced by min_heap and max_heap.  Freeing dealt
210  * with when items removed from hashmap.
211  */
212 struct DirectNeighbor
213 {
214   /**
215    * Identity of neighbor.
216    */
217   struct GNUNET_PeerIdentity identity;
218
219   /**
220    * Head of DLL of nodes that this direct neighbor referred to us.
221    */
222   struct DistantNeighbor *referee_head;
223
224   /**
225    * Tail of DLL of nodes that this direct neighbor referred to us.
226    */
227   struct DistantNeighbor *referee_tail;
228
229   /**
230    * The sending context for gossiping peers to this neighbor.
231    */
232   struct NeighborSendContext *send_context;
233
234   /**
235    * Is this one of the direct neighbors that we are "hiding"
236    * from DV?
237    */
238   int hidden;
239 };
240
241
242 /**
243  * Struct where actual neighbor information is stored,
244  * referenced by min_heap and max_heap.  Freeing dealt
245  * with when items removed from hashmap.
246  */
247 struct DistantNeighbor
248 {
249   /**
250    * We keep distant neighbor's of the same referrer in a DLL.
251    */
252   struct DistantNeighbor *next;
253
254   /**
255    * We keep distant neighbor's of the same referrer in a DLL.
256    */
257   struct DistantNeighbor *prev;
258
259   /**
260    * Node in min heap
261    */
262   struct GNUNET_CONTAINER_HeapNode *min_loc;
263
264   /**
265    * Node in max heap
266    */
267   struct GNUNET_CONTAINER_HeapNode *max_loc;
268
269   /**
270    * Identity of referrer (next hop towards 'neighbor').
271    */
272   struct DirectNeighbor *referrer;
273
274   /**
275    * Identity of neighbor.
276    */
277   struct GNUNET_PeerIdentity identity;
278
279   /**
280    * Last time we received routing information from this peer
281    */
282   struct GNUNET_TIME_Absolute last_activity;
283
284   /**
285    * Cost to neighbor, used for actual distance vector computations
286    */
287   unsigned int cost;
288
289   /**
290    * Random identifier *we* use for this peer, to be used as shortcut
291    * instead of sending full peer id for each message
292    */
293   unsigned int our_id;
294
295   /**
296    * Random identifier the *referrer* uses for this peer.
297    */
298   unsigned int referrer_id;
299
300   /**
301    * Is this one of the direct neighbors that we are "hiding"
302    * from DV?
303    */
304   int hidden;
305 };
306
307
308 /**
309  * Global construct
310  */
311 struct GNUNET_DV_Context
312 {
313   /**
314    * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for all
315    * directly connected peers.
316    */
317   struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
318
319   /**
320    * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for
321    * peers connected via DV (extended neighborhood).  Does ALSO
322    * include any peers that are in 'direct_neighbors'; for those
323    * peers, the cost will be zero and the referrer all zeros.
324    */
325   struct GNUNET_CONTAINER_MultiHashMap *extended_neighbors;
326
327   /**
328    * We use the min heap (min refers to cost) to prefer
329    * gossipping about peers with small costs.
330    */
331   struct GNUNET_CONTAINER_Heap *neighbor_min_heap;
332
333   /**
334    * We use the max heap (max refers to cost) for general
335    * iterations over all peers and to remove the most costly
336    * connection if we have too many.
337    */
338   struct GNUNET_CONTAINER_Heap *neighbor_max_heap;
339
340   unsigned long long fisheye_depth;
341
342   unsigned long long max_table_size;
343
344   unsigned int neighbor_id_loc;
345
346   int closing;
347
348 };
349
350 static struct GNUNET_DV_Context ctx;
351
352 struct FindDestinationContext
353 {
354   unsigned int tid;
355   struct DistantNeighbor *dest;
356 };
357
358
359 /**
360  * We've been given a target ID based on the random numbers that
361  * we assigned to our DV-neighborhood.  Find the entry for the
362  * respective neighbor.
363  */
364 static int
365 find_destination (void *cls,
366                   struct GNUNET_CONTAINER_HeapNode *node,
367                   void *element, GNUNET_CONTAINER_HeapCostType cost)
368 {
369   struct FindDestinationContext *fdc = cls;
370   struct DistantNeighbor *dn = element;
371
372   if (fdc->tid != dn->our_id)
373     return GNUNET_YES;
374   fdc->dest = dn;
375   return GNUNET_NO;
376 }
377
378 /**
379  * Function called to notify a client about the socket
380  * begin ready to queue more data.  "buf" will be
381  * NULL and "size" zero if the socket was closed for
382  * writing in the meantime.
383  *
384  * @param cls closure
385  * @param size number of bytes available in buf
386  * @param buf where the callee should write the message
387  * @return number of bytes written to buf
388  */
389 size_t transmit_to_plugin (void *cls,
390                size_t size, void *buf)
391 {
392   struct GNUNET_DV_MessageReceived *msg = cls;
393
394   if (buf == NULL)
395     return 0;
396
397   GNUNET_assert(size >= ntohs(msg->header.size));
398
399   memcpy(buf, msg, size);
400   GNUNET_free(msg);
401   return size;
402 }
403
404
405 void send_to_plugin(const struct GNUNET_PeerIdentity * sender, const struct GNUNET_MessageHeader *message, size_t message_size, struct DistantNeighbor *distant_neighbor)
406 {
407   struct GNUNET_DV_MessageReceived *received_msg;
408   int size;
409
410   size = sizeof(struct GNUNET_DV_MessageReceived) + sizeof(struct GNUNET_PeerIdentity) + message_size;
411   received_msg = GNUNET_malloc(size);
412   received_msg->header.size = htons(size);
413   received_msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE);
414   received_msg->sender_address_len = sizeof(struct GNUNET_PeerIdentity);
415   received_msg->distance = htonl(distant_neighbor->cost);
416   received_msg->msg_len = htons(message_size);
417   /* Set the sender in this message to be the original sender! */
418   memcpy(&received_msg->sender, &distant_neighbor->identity, sizeof(struct GNUNET_PeerIdentity));
419   /* Copy the intermediate sender to the end of the message, this is how the transport identifies this peer */
420   memcpy(&received_msg[1], sender, sizeof(struct GNUNET_PeerIdentity));
421   /* Copy the actual message after the sender */
422   memcpy(&received_msg[1 + sizeof(struct GNUNET_PeerIdentity)], message, message_size);
423
424   /* FIXME: Send to the client please */
425   GNUNET_SERVER_notify_transmit_ready (client_handle,
426                                        size, client_transmit_timeout,
427                                        &transmit_to_plugin, &received_msg);
428
429 }
430
431
432 /**
433  * Function called to notify a client about the socket
434  * begin ready to queue more data.  "buf" will be
435  * NULL and "size" zero if the socket was closed for
436  * writing in the meantime.
437  *
438  * @param cls closure
439  * @param size number of bytes available in buf
440  * @param buf where the callee should write the message
441  * @return number of bytes written to buf
442  */
443 size_t core_transmit_notify (void *cls,
444                              size_t size, void *buf)
445 {
446   struct PendingMessage *pending_message = cls;
447   char *send_buf = buf;
448   if ((buf == NULL) || (size < pending_message->msg_size))
449     {
450       return 0;
451     }
452
453   memcpy(send_buf, pending_message->msg, pending_message->msg_size);
454
455   GNUNET_free(pending_message->msg);
456   GNUNET_free(pending_message);
457
458   return size;
459 }
460
461 /**
462  * Send a DV data message via DV.
463  *
464  * @param recipient the ultimate recipient of this message
465  * @param the original sender of the message
466  * @param message the packed message
467  * @param importance what priority to send this message with
468  * @param timeout how long to possibly delay sending this message
469  */
470 static int
471 send_message (const struct GNUNET_PeerIdentity * recipient,
472               const struct GNUNET_PeerIdentity * sender,
473               const struct GNUNET_MessageHeader * message,
474               unsigned int importance, struct GNUNET_TIME_Relative timeout)
475 {
476   p2p_dv_MESSAGE_Data *toSend;
477   unsigned int msg_size;
478   unsigned int cost;
479   unsigned int recipient_id;
480   unsigned int sender_id;
481   struct DistantNeighbor *target;
482   struct DistantNeighbor *source;
483   struct PendingMessage *pending_message;
484
485   msg_size = ntohs (message->size) + sizeof (p2p_dv_MESSAGE_Data);
486
487   target = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
488                                               &recipient->hashPubKey);
489   if (target == NULL)
490     {
491       /* target unknown to us, drop! */
492       return GNUNET_SYSERR;
493     }
494   recipient_id = target->referrer_id;
495
496   source = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
497                                       &sender->hashPubKey);
498   if (source == NULL)
499     {
500       if (0 != (memcmp (&my_identity,
501                         sender, sizeof (struct GNUNET_PeerIdentity))))
502         {
503           /* sender unknown to us, drop! */
504           return GNUNET_SYSERR;
505         }
506       sender_id = 0;            /* 0 == us */
507     }
508   else
509     {
510       /* find out the number that we use when we gossip about
511          the sender */
512       sender_id = source->our_id;
513     }
514
515   cost = target->cost;
516   pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
517   pending_message->msg = GNUNET_malloc (msg_size);
518   toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg;
519   toSend->header.size = htons (msg_size);
520   toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
521   toSend->sender = htonl (sender_id);
522   toSend->recipient = htonl (recipient_id);
523   memcpy (&toSend[1], message, ntohs (message->size));
524   pending_message->msg_size = msg_size;
525
526   pending_message->transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, importance, timeout, &target->referrer->identity, msg_size, &core_transmit_notify, pending_message);
527   if (NULL == pending_message->transmit_handle)
528     {
529       GNUNET_free (pending_message->msg);
530       GNUNET_free (pending_message);
531       return GNUNET_SYSERR;
532     }
533
534   /*coreAPI->ciphertext_send (&target->referrer->identity,
535                             &toSend->header, importance, maxdelay);*/
536   return (int) cost;
537 }
538
539
540 /**
541  * Core handler for dv data messages.  Whatever this message
542  * contains all we really have to do is rip it out of its
543  * DV layering and give it to our pal the DV plugin to report
544  * in with.
545  *
546  * @param cls closure
547  * @param peer peer which sent the message (immediate sender)
548  * @param message the message
549  * @param latency the latency of the connection we received the message from
550  * @param distance the distance to the immediate peer
551  */
552 static int handle_dv_data_message (void *cls,
553                              const struct GNUNET_PeerIdentity * peer,
554                              const struct GNUNET_MessageHeader * message,
555                              struct GNUNET_TIME_Relative latency,
556                              uint32_t distance)
557 {
558 #if DEBUG_DV
559   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560               "%s: Receives %s message!\n", "dv", "DV DATA");
561 #endif
562
563   const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
564   const struct GNUNET_MessageHeader *packed_message = (const struct GNUNET_MessageHeader *) &incoming[1];
565   struct DirectNeighbor *dn;
566   struct DistantNeighbor *pos;
567   unsigned int sid;             /* Sender id */
568   unsigned int tid;             /* Target id */
569   struct GNUNET_PeerIdentity original_sender;
570   struct GNUNET_PeerIdentity destination;
571   struct FindDestinationContext fdc;
572   int ret;
573
574   if ((ntohs (incoming->header.size) <
575        sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader))
576       || (ntohs (incoming->header.size) !=
577           (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
578     {
579       return GNUNET_SYSERR;
580     }
581
582   dn = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
583                                   &peer->hashPubKey);
584   if (dn == NULL)
585     {
586       return GNUNET_OK;
587     }
588   sid = ntohl (incoming->sender);
589   pos = dn->referee_head;
590   while ((NULL != pos) && (pos->referrer_id != sid))
591     pos = pos->next;
592   if (pos == NULL)
593     {
594       /* unknown sender */
595       return GNUNET_OK;
596     }
597   original_sender = pos->identity;
598   tid = ntohl (incoming->recipient);
599   if (tid == 0)
600     {
601       /* 0 == us */
602
603       /* FIXME: Will we support wrapped messages being these types? Probably not, they should
604        * be encrypted messages that need decrypting and junk like that.
605        */
606       GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
607       GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
608       if ( (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
609           (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA) )
610       {
611         send_to_plugin(peer, packed_message, ntohs(packed_message->size), pos);
612       }
613
614       return GNUNET_OK;
615     }
616
617   /* FIXME: this is the *only* per-request operation we have in DV
618      that is O(n) in relation to the number of connected peers; a
619      hash-table lookup could easily solve this (minor performance
620      issue) */
621   fdc.tid = tid;
622   fdc.dest = NULL;
623   GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
624                                  &find_destination, &fdc);
625   if (fdc.dest == NULL)
626     {
627       return GNUNET_OK;
628     }
629   destination = fdc.dest->identity;
630
631   if (0 == memcmp (&destination, peer, sizeof (struct GNUNET_PeerIdentity)))
632     {
633       /* FIXME: create stat: routing loop-discard! */
634       return GNUNET_OK;
635     }
636
637   /* At this point we have a message, and we need to forward it on to the
638    * next DV hop.
639    */
640   /* FIXME: Can't send message on, we have to behave.
641    * We have to tell core we have a message for the next peer, and let
642    * transport do transport selection on how to get this message to 'em */
643   /*ret = send_message (&destination,
644                       &original_sender,
645                       packed_message, DV_PRIORITY, DV_DELAY);*/
646   ret = send_message(&destination, &original_sender, packed_message, default_dv_priority, default_dv_delay);
647
648   if (ret != GNUNET_SYSERR)
649     return GNUNET_OK;
650   else
651     return GNUNET_SYSERR;
652 }
653
654
655 /**
656  * Thread which chooses a peer to gossip about and a peer to gossip
657  * to, then constructs the message and sends it out.  Will run until
658  * done_module_dv is called.
659  */
660 static void
661 neighbor_send_task (void *cls,
662                       const struct GNUNET_SCHEDULER_TaskContext *tc)
663 {
664   struct NeighborSendContext *send_context = cls;
665 #if DEBUG_DV
666   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
667               "%s: Entering neighbor_send_task...\n",
668               GNUNET_i2s(&my_identity));
669   char * encPeerAbout;
670   char * encPeerTo;
671 #endif
672   struct DistantNeighbor *about;
673   struct DirectNeighbor *to;
674
675   p2p_dv_MESSAGE_NeighborInfo *message;
676   struct PendingMessage *pending_message;
677
678   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
679   {
680 #if DEBUG_DV
681   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682               "%s: Called with reason shutdown, shutting down!\n",
683               GNUNET_i2s(&my_identity));
684 #endif
685     send_context->toNeighbor->send_context = NULL;
686     GNUNET_free(send_context);
687     return;
688   }
689
690
691   /* FIXME: this may become a problem, because the heap walk has only one internal "walker".  This means
692    * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
693    * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
694    * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
695    * part of the walk_get_next call.  Then the heap would have to keep a list of walks, or reset the walk
696    * whenever a modification has been detected.  Yuck either way.  Perhaps we could iterate over the heap
697    * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
698    * in the mean time that becomes nasty.  For now we'll just assume that the walking is done
699    * asynchronously enough to avoid major problems (-;
700    */
701   about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap);
702   to = send_context->toNeighbor;
703
704   if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
705 #if SUPPORT_HIDING
706       (about->hidden == GNUNET_NO) &&
707 #endif
708       (to != NULL) &&
709       (0 != memcmp (&about->identity,
710                         &to->identity, sizeof (struct GNUNET_PeerIdentity))))
711     {
712 #if DEBUG_DV
713       encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity));
714       encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity));
715       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716                      "%s: Sending info about peer %s to directly connected peer %s\n",
717                      GNUNET_i2s(&my_identity),
718                      encPeerAbout, encPeerTo);
719 #endif
720       pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
721       pending_message->msg = GNUNET_malloc(sizeof(p2p_dv_MESSAGE_NeighborInfo));
722       message = (p2p_dv_MESSAGE_NeighborInfo *)pending_message->msg;
723       message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
724       message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
725       message->cost = htonl (about->cost);
726       message->neighbor_id = htonl (about->our_id);
727       memcpy (&message->neighbor,
728               &about->identity, sizeof (struct GNUNET_PeerIdentity));
729
730       pending_message->transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, default_dv_delay, &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, pending_message);
731
732       if (NULL == pending_message->transmit_handle)
733         {
734           GNUNET_free (pending_message->msg);
735           GNUNET_free (pending_message);
736           return;
737         }
738       /*coreAPI->ciphertext_send (&to->identity, &message.header,
739                                 GNUNET_DV_DHT_GOSSIP_PRIORITY,
740                                 ctx.send_interval);*/
741     }
742
743   GNUNET_SCHEDULER_add_delayed(sched, send_context->timeout, &neighbor_send_task, send_context);
744   return;
745 }
746
747 /**
748  * Core handler for dv gossip messages.  These will be used
749  * by us to create a HELLO message for the newly peer containing
750  * which direct peer we can connect through, and what the cost
751  * is.  This HELLO will then be scheduled for validation by the
752  * transport service so that it can be used by all others.
753  *
754  * @param cls closure
755  * @param peer peer which sent the message (immediate sender)
756  * @param message the message
757  * @param latency the latency of the connection we received the message from
758  * @param distance the distance to the immediate peer
759  */
760 static int handle_dv_gossip_message (void *cls,
761                                      const struct GNUNET_PeerIdentity *peer,
762                                      const struct GNUNET_MessageHeader *message,
763                                      struct GNUNET_TIME_Relative latency,
764                                      uint32_t distance)
765 {
766 #if DEBUG_DV
767   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768               "%s: Receives %s message!\n", "dv", "DV GOSSIP");
769 #endif
770
771   return 0;
772 }
773
774
775 /**
776  * Service server's handler for message send requests (which come
777  * bubbling up to us through the DV plugin).
778  *
779  * @param cls closure
780  * @param client identification of the client
781  * @param message the actual message
782  */
783 void send_dv_message (void *cls,
784                       struct GNUNET_SERVER_Client * client,
785                       const struct GNUNET_MessageHeader * message)
786 {
787 #if DEBUG_DV
788   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789               "%s: Receives %s message!\n", "dv", "SEND");
790 #endif
791   if (client_handle == NULL)
792   {
793     client_handle = client;
794 #if DEBUG_DV
795   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
796               "%s: Setting initial client handle!\n", "dv");
797 #endif
798   }
799   else if (client_handle != client)
800   {
801     client_handle = client;
802     /* What should we do in this case, assert fail or just log the warning? */
803     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
804                 "%s: Setting client handle (was a different client!)!\n", "dv");
805   }
806
807   GNUNET_SERVER_receive_done(client, GNUNET_OK);
808 }
809
810
811 /**
812  * List of handlers for the messages understood by this
813  * service.
814  *
815  * Hmm... will we need to register some handlers with core and
816  * some handlers with our server here?  Because core should be
817  * getting the incoming DV messages (from whichever lower level
818  * transport) and then our server should be getting messages
819  * from the dv_plugin, right?
820  */
821 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
822   {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
823   {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
824   {NULL, 0, 0}
825 };
826
827
828 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
829   {&send_dv_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
830   {NULL, NULL, 0, 0}
831 };
832
833
834 /**
835  * Task run during shutdown.
836  *
837  * @param cls unused
838  * @param tc unused
839  */
840 static void
841 shutdown_task (void *cls,
842                const struct GNUNET_SCHEDULER_TaskContext *tc)
843 {
844
845   GNUNET_CORE_disconnect (coreAPI);
846 }
847
848 /**
849  * To be called on core init/fail.
850  */
851 void core_init (void *cls,
852                 struct GNUNET_CORE_Handle * server,
853                 const struct GNUNET_PeerIdentity *identity,
854                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
855 {
856
857   if (server == NULL)
858     {
859       GNUNET_SCHEDULER_cancel(sched, cleanup_task);
860       GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
861       return;
862     }
863 #if DEBUG_DV
864   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
865               "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s(identity));
866 #endif
867   memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
868   coreAPI = server;
869 }
870
871
872 /**
873  * Iterator over hash map entries.
874  *
875  * @param cls closure
876  * @param key current key code
877  * @param value value in the hash map
878  * @return GNUNET_YES if we should continue to
879  *         iterate,
880  *         GNUNET_NO if not.
881  */
882 static int update_matching_neighbors (void *cls,
883                                       const GNUNET_HashCode * key,
884                                       void *value)
885 {
886   struct NeighborUpdateInfo * update_info = cls;
887   struct DirectNeighbor *direct_neighbor = value;
888
889   if (update_info->referrer == direct_neighbor) /* Direct neighbor matches, update it's info and return GNUNET_NO */
890   {
891     /* same referrer, cost change! */
892     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
893                                        update_info->neighbor->max_loc, update_info->cost);
894     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
895                                        update_info->neighbor->min_loc, update_info->cost);
896     update_info->neighbor->last_activity = update_info->now;
897     update_info->neighbor->cost = update_info->cost;
898     return GNUNET_NO;
899   }
900
901   return GNUNET_YES;
902 }
903
904
905 /**
906  * Free a DistantNeighbor node, including removing it
907  * from the referer's list.
908  */
909 static void
910 distant_neighbor_free (struct DistantNeighbor *referee)
911 {
912   struct DirectNeighbor *referrer;
913
914   referrer = referee->referrer;
915   if (referrer != NULL)
916     {
917       GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
918                          referrer->referee_tail, referee);
919     }
920   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc);
921   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc);
922   GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors,
923                                     &referee->identity.hashPubKey);
924   GNUNET_free (referee);
925 }
926
927
928 /**
929  * Handles when a peer is either added due to being newly connected
930  * or having been gossiped about, also called when a cost for a neighbor
931  * needs to be updated.
932  *
933  * @param peer identity of the peer whose info is being added/updated
934  * @param peer_id id to use when sending to 'peer'
935  * @param referrer if this is a gossiped peer, who did we hear it from?
936  * @param cost the cost of communicating with this peer via 'referrer'
937  */
938 static void
939 addUpdateNeighbor (const struct GNUNET_PeerIdentity * peer,
940                    unsigned int referrer_peer_id,
941                    struct DirectNeighbor *referrer, unsigned int cost)
942 {
943   struct DistantNeighbor *neighbor;
944   struct DistantNeighbor *max;
945   struct GNUNET_TIME_Absolute now;
946   struct NeighborUpdateInfo *neighbor_update;
947   unsigned int our_id;
948
949   now = GNUNET_TIME_absolute_get ();
950   our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, RAND_MAX - 1) + 1;
951
952   neighbor = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
953                                                 &peer->hashPubKey);
954   neighbor_update = GNUNET_malloc(sizeof(struct NeighborUpdateInfo));
955   neighbor_update->neighbor = neighbor;
956   neighbor_update->cost = cost;
957   neighbor_update->now = now;
958   neighbor_update->referrer = referrer;
959
960   /* Either we do not know this peer, or we already do but via a different immediate peer */
961   if ((neighbor == NULL) ||
962       (GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
963                                                   &peer->hashPubKey,
964                                                   &update_matching_neighbors,
965                                                   neighbor_update) != GNUNET_SYSERR))
966     {
967       /* new neighbor! */
968       if (cost > ctx.fisheye_depth)
969         {
970           /* too costly */
971           return;
972         }
973       if (ctx.max_table_size <=
974           GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors))
975         {
976           /* remove most expensive entry */
977           max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
978           if (cost > max->cost)
979             {
980               /* new entry most expensive, don't create */
981               return;
982             }
983           if (max->cost > 0)
984             {
985               /* only free if this is not a direct connection;
986                  we could theoretically have more direct
987                  connections than DV entries allowed total! */
988               distant_neighbor_free (max);
989             }
990         }
991
992       neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
993       GNUNET_CONTAINER_DLL_insert (referrer->referee_head,
994                          referrer->referee_tail, neighbor);
995       neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap,
996                                                         neighbor, cost);
997       neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
998                                                         neighbor, cost);
999       neighbor->referrer = referrer;
1000       memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1001       neighbor->last_activity = now;
1002       neighbor->cost = cost;
1003       neighbor->referrer_id = referrer_peer_id;
1004       neighbor->our_id = our_id;
1005       neighbor->hidden =
1006         (cost == 0) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
1007                        0) : GNUNET_NO;
1008       GNUNET_CONTAINER_multihashmap_put (ctx.extended_neighbors, &peer->hashPubKey,
1009                                  neighbor,
1010                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1011
1012       return;
1013     }
1014
1015   /* Old logic to remove entry and replace, not needed now as we only want to remove when full
1016    * or when the referring peer disconnects from us.
1017    */
1018   /*
1019   GNUNET_DLL_remove (neighbor->referrer->referee_head,
1020                      neighbor->referrer->referee_tail, neighbor);
1021   neighbor->referrer = referrer;
1022   GNUNET_DLL_insert (referrer->referee_head,
1023                      referrer->referee_tail, neighbor);
1024   GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
1025                                      neighbor->max_loc, cost);
1026   GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
1027                                      neighbor->min_loc, cost);
1028   neighbor->referrer_id = referrer_peer_id;
1029   neighbor->last_activity = now;
1030   neighbor->cost = cost;
1031   */
1032 }
1033
1034
1035 /**
1036  * Method called whenever a peer connects.
1037  *
1038  * @param cls closure
1039  * @param peer peer identity this notification is about
1040  * @param latency reported latency of the connection with peer
1041  * @param distance reported distance (DV) to peer
1042  */
1043 void handle_core_connect (void *cls,
1044                           const struct GNUNET_PeerIdentity * peer,
1045                           struct GNUNET_TIME_Relative latency,
1046                           uint32_t distance)
1047 {
1048   struct DirectNeighbor *neighbor;
1049 #if DEBUG_DV
1050   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051               "%s: Receives core connect message for peer %s distance %d!\n", "dv", GNUNET_i2s(peer), distance);
1052 #endif
1053
1054   if ((distance == 0) && (GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL))
1055   {
1056     neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
1057     neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext));
1058     neighbor->send_context->toNeighbor = neighbor;
1059     neighbor->send_context->timeout = default_dv_delay; /* FIXME: base this on total gossip tasks, or bandwidth */
1060     memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1061     GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors,
1062                                &peer->hashPubKey,
1063                                neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1064     addUpdateNeighbor (peer, 0, neighbor, 0);
1065     neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context);
1066   }
1067   else
1068   {
1069 #if DEBUG_DV
1070   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071               "%s: Distance (%d) greater than 0 or already know about peer (%s), not re-adding!\n", "dv", distance, GNUNET_i2s(peer));
1072 #endif
1073     return;
1074   }
1075 }
1076
1077 /**
1078  * Method called whenever a given peer either connects.
1079  *
1080  * @param cls closure
1081  * @param peer peer identity this notification is about
1082  */
1083 void handle_core_disconnect (void *cls,
1084                              const struct GNUNET_PeerIdentity * peer)
1085 {
1086   struct DirectNeighbor *neighbor;
1087   struct DistantNeighbor *referee;
1088
1089 #if DEBUG_DV
1090   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1091               "%s: Receives core peer disconnect message!\n", "dv");
1092 #endif
1093
1094   neighbor =
1095     GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, &peer->hashPubKey);
1096   if (neighbor == NULL)
1097     {
1098       return;
1099     }
1100   while (NULL != (referee = neighbor->referee_head))
1101     distant_neighbor_free (referee);
1102   GNUNET_assert (neighbor->referee_tail == NULL);
1103   GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors,
1104                                 &peer->hashPubKey, neighbor);
1105   if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK))
1106     GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task);
1107   GNUNET_free (neighbor);
1108 }
1109
1110
1111 /**
1112  * Process dv requests.
1113  *
1114  * @param cls closure
1115  * @param scheduler scheduler to use
1116  * @param server the initialized server
1117  * @param c configuration to use
1118  */
1119 static void
1120 run (void *cls,
1121      struct GNUNET_SCHEDULER_Handle *scheduler,
1122      struct GNUNET_SERVER_Handle *server,
1123      const struct GNUNET_CONFIGURATION_Handle *c)
1124 {
1125   struct GNUNET_TIME_Relative timeout;
1126   unsigned long long max_hosts;
1127   timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1128   sched = scheduler;
1129   cfg = c;
1130
1131   /* FIXME: Read from config, or calculate, or something other than this! */
1132   max_hosts = 50;
1133   ctx.max_table_size = 100;
1134   ctx.fisheye_depth = 3;
1135
1136   ctx.neighbor_min_heap =
1137     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1138   ctx.neighbor_max_heap =
1139     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
1140
1141   ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts);
1142   ctx.extended_neighbors =
1143     GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3);
1144
1145   client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1146   default_dv_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1147   GNUNET_SERVER_add_handlers (server, plugin_handlers);
1148   coreAPI =
1149   GNUNET_CORE_connect (sched,
1150                        cfg,
1151                        timeout,
1152                        NULL, /* FIXME: anything we want to pass around? */
1153                        &core_init,
1154                        NULL, /* Don't care about pre-connects */
1155                        &handle_core_connect,
1156                        &handle_core_disconnect,
1157                        NULL,
1158                        GNUNET_NO,
1159                        NULL,
1160                        GNUNET_NO,
1161                        core_handlers);
1162
1163   if (coreAPI == NULL)
1164     return;
1165   /* load (server); Huh? */
1166
1167   /* Scheduled the task to clean up when shutdown is called */
1168   cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
1169                                 GNUNET_TIME_UNIT_FOREVER_REL,
1170                                 &shutdown_task,
1171                                 NULL);
1172 }
1173
1174
1175 /**
1176  * The main function for the dv service.
1177  *
1178  * @param argc number of arguments from the command line
1179  * @param argv command line arguments
1180  * @return 0 ok, 1 on error
1181  */
1182 int
1183 main (int argc, char *const *argv)
1184 {
1185   return (GNUNET_OK ==
1186           GNUNET_SERVICE_run (argc,
1187                               argv,
1188                               "dv",
1189                               GNUNET_SERVICE_OPTION_NONE,
1190                               &run, NULL)) ? 0 : 1;
1191 }