change hostname in config files when created, if running remotely... Otherwise the...
[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 static struct GNUNET_PeerIdentity my_identity;
55
56 /**
57  * The configuration for this service.
58  */
59 static 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   size_t ssize;
448
449   if (buf == NULL)
450     {
451       /* FIXME: error handling: try again? free pending_message? */
452       return 0;
453     }
454   ssize = pending_message->msg_size;
455   GNUNET_assert(size >= ssize);
456   memcpy(buf, pending_message->msg, ssize);
457   GNUNET_free(pending_message->msg);
458   GNUNET_free(pending_message);
459   return ssize;
460 }
461
462 /**
463  * Send a DV data message via DV.
464  *
465  * @param recipient the ultimate recipient of this message
466  * @param the original sender of the message
467  * @param message the packed message
468  * @param importance what priority to send this message with
469  * @param timeout how long to possibly delay sending this message
470  */
471 static int
472 send_message (const struct GNUNET_PeerIdentity * recipient,
473               const struct GNUNET_PeerIdentity * sender,
474               const struct GNUNET_MessageHeader * message,
475               unsigned int importance, struct GNUNET_TIME_Relative timeout)
476 {
477   p2p_dv_MESSAGE_Data *toSend;
478   unsigned int msg_size;
479   unsigned int cost;
480   unsigned int recipient_id;
481   unsigned int sender_id;
482   struct DistantNeighbor *target;
483   struct DistantNeighbor *source;
484   struct PendingMessage *pending_message;
485
486   msg_size = ntohs (message->size) + sizeof (p2p_dv_MESSAGE_Data);
487
488   target = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
489                                               &recipient->hashPubKey);
490   if (target == NULL)
491     {
492       /* target unknown to us, drop! */
493       return GNUNET_SYSERR;
494     }
495   recipient_id = target->referrer_id;
496
497   source = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
498                                       &sender->hashPubKey);
499   if (source == NULL)
500     {
501       if (0 != (memcmp (&my_identity,
502                         sender, sizeof (struct GNUNET_PeerIdentity))))
503         {
504           /* sender unknown to us, drop! */
505           return GNUNET_SYSERR;
506         }
507       sender_id = 0;            /* 0 == us */
508     }
509   else
510     {
511       /* find out the number that we use when we gossip about
512          the sender */
513       sender_id = source->our_id;
514     }
515
516   cost = target->cost;
517   pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
518   pending_message->msg = GNUNET_malloc (msg_size);
519   toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg;
520   toSend->header.size = htons (msg_size);
521   toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
522   toSend->sender = htonl (sender_id);
523   toSend->recipient = htonl (recipient_id);
524   memcpy (&toSend[1], message, ntohs (message->size));
525   pending_message->msg_size = msg_size;
526
527   pending_message->transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, importance, timeout, &target->referrer->identity, msg_size, &core_transmit_notify, pending_message);
528   if (NULL == pending_message->transmit_handle)
529     {
530       GNUNET_free (pending_message->msg);
531       GNUNET_free (pending_message);
532       return GNUNET_SYSERR;
533     }
534
535   /*coreAPI->ciphertext_send (&target->referrer->identity,
536                             &toSend->header, importance, maxdelay);*/
537   return (int) cost;
538 }
539
540
541 /**
542  * Core handler for dv data messages.  Whatever this message
543  * contains all we really have to do is rip it out of its
544  * DV layering and give it to our pal the DV plugin to report
545  * in with.
546  *
547  * @param cls closure
548  * @param peer peer which sent the message (immediate sender)
549  * @param message the message
550  * @param latency the latency of the connection we received the message from
551  * @param distance the distance to the immediate peer
552  */
553 static int handle_dv_data_message (void *cls,
554                              const struct GNUNET_PeerIdentity * peer,
555                              const struct GNUNET_MessageHeader * message,
556                              struct GNUNET_TIME_Relative latency,
557                              uint32_t distance)
558 {
559 #if DEBUG_DV
560   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561               "%s: Receives %s message!\n", "dv", "DV DATA");
562 #endif
563
564   const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
565   const struct GNUNET_MessageHeader *packed_message = (const struct GNUNET_MessageHeader *) &incoming[1];
566   struct DirectNeighbor *dn;
567   struct DistantNeighbor *pos;
568   unsigned int sid;             /* Sender id */
569   unsigned int tid;             /* Target id */
570   struct GNUNET_PeerIdentity original_sender;
571   struct GNUNET_PeerIdentity destination;
572   struct FindDestinationContext fdc;
573   int ret;
574
575   if ((ntohs (incoming->header.size) <
576        sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader))
577       || (ntohs (incoming->header.size) !=
578           (sizeof (p2p_dv_MESSAGE_Data) + ntohs (packed_message->size))))
579     {
580       return GNUNET_SYSERR;
581     }
582
583   dn = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
584                                   &peer->hashPubKey);
585   if (dn == NULL)
586     {
587       return GNUNET_OK;
588     }
589   sid = ntohl (incoming->sender);
590   pos = dn->referee_head;
591   while ((NULL != pos) && (pos->referrer_id != sid))
592     pos = pos->next;
593   if (pos == NULL)
594     {
595       /* unknown sender */
596       return GNUNET_OK;
597     }
598   original_sender = pos->identity;
599   tid = ntohl (incoming->recipient);
600   if (tid == 0)
601     {
602       /* 0 == us */
603
604       /* FIXME: Will we support wrapped messages being these types? Probably not, they should
605        * be encrypted messages that need decrypting and junk like that.
606        */
607       GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
608       GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
609       if ( (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
610           (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA) )
611       {
612         send_to_plugin(peer, packed_message, ntohs(packed_message->size), pos);
613       }
614
615       return GNUNET_OK;
616     }
617
618   /* FIXME: this is the *only* per-request operation we have in DV
619      that is O(n) in relation to the number of connected peers; a
620      hash-table lookup could easily solve this (minor performance
621      issue) */
622   fdc.tid = tid;
623   fdc.dest = NULL;
624   GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
625                                  &find_destination, &fdc);
626   if (fdc.dest == NULL)
627     {
628       return GNUNET_OK;
629     }
630   destination = fdc.dest->identity;
631
632   if (0 == memcmp (&destination, peer, sizeof (struct GNUNET_PeerIdentity)))
633     {
634       /* FIXME: create stat: routing loop-discard! */
635       return GNUNET_OK;
636     }
637
638   /* At this point we have a message, and we need to forward it on to the
639    * next DV hop.
640    */
641   /* FIXME: Can't send message on, we have to behave.
642    * We have to tell core we have a message for the next peer, and let
643    * transport do transport selection on how to get this message to 'em */
644   /*ret = send_message (&destination,
645                       &original_sender,
646                       packed_message, DV_PRIORITY, DV_DELAY);*/
647   ret = send_message(&destination, &original_sender, packed_message, default_dv_priority, default_dv_delay);
648
649   if (ret != GNUNET_SYSERR)
650     return GNUNET_OK;
651   else
652     return GNUNET_SYSERR;
653 }
654
655
656 /**
657  * Thread which chooses a peer to gossip about and a peer to gossip
658  * to, then constructs the message and sends it out.  Will run until
659  * done_module_dv is called.
660  */
661 static void
662 neighbor_send_task (void *cls,
663                       const struct GNUNET_SCHEDULER_TaskContext *tc)
664 {
665   struct NeighborSendContext *send_context = cls;
666 #if DEBUG_DV
667   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668               "%s: Entering neighbor_send_task...\n",
669               GNUNET_i2s(&my_identity));
670   char * encPeerAbout;
671   char * encPeerTo;
672 #endif
673   struct DistantNeighbor *about;
674   struct DirectNeighbor *to;
675
676   p2p_dv_MESSAGE_NeighborInfo *message;
677   struct PendingMessage *pending_message;
678
679   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
680   {
681 #if DEBUG_DV
682   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
683               "%s: Called with reason shutdown, shutting down!\n",
684               GNUNET_i2s(&my_identity));
685 #endif
686     send_context->toNeighbor->send_context = NULL;
687     GNUNET_free(send_context);
688     return;
689   }
690
691
692   /* FIXME: this may become a problem, because the heap walk has only one internal "walker".  This means
693    * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
694    * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
695    * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
696    * part of the walk_get_next call.  Then the heap would have to keep a list of walks, or reset the walk
697    * whenever a modification has been detected.  Yuck either way.  Perhaps we could iterate over the heap
698    * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
699    * in the mean time that becomes nasty.  For now we'll just assume that the walking is done
700    * asynchronously enough to avoid major problems (-;
701    */
702   about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap);
703   to = send_context->toNeighbor;
704
705   if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
706 #if SUPPORT_HIDING
707       (about->hidden == GNUNET_NO) &&
708 #endif
709       (to != NULL) &&
710       (0 != memcmp (&about->identity,
711                         &to->identity, sizeof (struct GNUNET_PeerIdentity))))
712     {
713 #if DEBUG_DV
714       encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity));
715       encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity));
716       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717                   "%s: Sending info about peer %s to directly connected peer %s\n",
718                   GNUNET_i2s(&my_identity),
719                   encPeerAbout, encPeerTo);
720       GNUNET_free(encPeerAbout);
721       GNUNET_free(encPeerTo);
722 #endif
723       pending_message = GNUNET_malloc(sizeof(struct PendingMessage));
724       pending_message->msg = GNUNET_malloc(sizeof(p2p_dv_MESSAGE_NeighborInfo));
725       message = (p2p_dv_MESSAGE_NeighborInfo *)pending_message->msg;
726       message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
727       message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
728       message->cost = htonl (about->cost);
729       message->neighbor_id = htonl (about->our_id);
730       memcpy (&message->neighbor,
731               &about->identity, sizeof (struct GNUNET_PeerIdentity));
732
733       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);
734
735       if (NULL == pending_message->transmit_handle)
736         {
737           GNUNET_free (pending_message->msg);
738           GNUNET_free (pending_message);
739           return;
740         }
741       /*coreAPI->ciphertext_send (&to->identity, &message.header,
742                                 GNUNET_DV_DHT_GOSSIP_PRIORITY,
743                                 ctx.send_interval);*/
744     }
745
746   GNUNET_SCHEDULER_add_delayed(sched, send_context->timeout, &neighbor_send_task, send_context);
747   return;
748 }
749
750 /**
751  * Core handler for dv gossip messages.  These will be used
752  * by us to create a HELLO message for the newly peer containing
753  * which direct peer we can connect through, and what the cost
754  * is.  This HELLO will then be scheduled for validation by the
755  * transport service so that it can be used by all others.
756  *
757  * @param cls closure
758  * @param peer peer which sent the message (immediate sender)
759  * @param message the message
760  * @param latency the latency of the connection we received the message from
761  * @param distance the distance to the immediate peer
762  */
763 static int handle_dv_gossip_message (void *cls,
764                                      const struct GNUNET_PeerIdentity *peer,
765                                      const struct GNUNET_MessageHeader *message,
766                                      struct GNUNET_TIME_Relative latency,
767                                      uint32_t distance)
768 {
769 #if DEBUG_DV
770   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771               "%s: Receives %s message!\n", "dv", "DV GOSSIP");
772 #endif
773
774   return 0;
775 }
776
777
778 /**
779  * Service server's handler for message send requests (which come
780  * bubbling up to us through the DV plugin).
781  *
782  * @param cls closure
783  * @param client identification of the client
784  * @param message the actual message
785  */
786 void send_dv_message (void *cls,
787                       struct GNUNET_SERVER_Client * client,
788                       const struct GNUNET_MessageHeader * message)
789 {
790 #if DEBUG_DV
791   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792               "%s: Receives %s message!\n", "dv", "SEND");
793 #endif
794   if (client_handle == NULL)
795   {
796     client_handle = client;
797 #if DEBUG_DV
798   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
799               "%s: Setting initial client handle!\n", "dv");
800 #endif
801   }
802   else if (client_handle != client)
803   {
804     client_handle = client;
805     /* What should we do in this case, assert fail or just log the warning? */
806     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
807                 "%s: Setting client handle (was a different client!)!\n", "dv");
808   }
809
810   GNUNET_SERVER_receive_done(client, GNUNET_OK);
811 }
812
813
814 /**
815  * List of handlers for the messages understood by this
816  * service.
817  *
818  * Hmm... will we need to register some handlers with core and
819  * some handlers with our server here?  Because core should be
820  * getting the incoming DV messages (from whichever lower level
821  * transport) and then our server should be getting messages
822  * from the dv_plugin, right?
823  */
824 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
825   {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
826   {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
827   {NULL, 0, 0}
828 };
829
830
831 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
832   {&send_dv_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
833   {NULL, NULL, 0, 0}
834 };
835
836
837 /**
838  * Task run during shutdown.
839  *
840  * @param cls unused
841  * @param tc unused
842  */
843 static void
844 shutdown_task (void *cls,
845                const struct GNUNET_SCHEDULER_TaskContext *tc)
846 {
847   GNUNET_CORE_disconnect (coreAPI);
848 }
849
850 /**
851  * To be called on core init/fail.
852  */
853 void core_init (void *cls,
854                 struct GNUNET_CORE_Handle * server,
855                 const struct GNUNET_PeerIdentity *identity,
856                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
857 {
858
859   if (server == NULL)
860     {
861       GNUNET_SCHEDULER_cancel(sched, cleanup_task);
862       GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
863       return;
864     }
865 #if DEBUG_DV
866   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867               "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s(identity));
868 #endif
869   memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
870   coreAPI = server;
871 }
872
873
874 /**
875  * Iterator over hash map entries.
876  *
877  * @param cls closure
878  * @param key current key code
879  * @param value value in the hash map
880  * @return GNUNET_YES if we should continue to
881  *         iterate,
882  *         GNUNET_NO if not.
883  */
884 static int update_matching_neighbors (void *cls,
885                                       const GNUNET_HashCode * key,
886                                       void *value)
887 {
888   struct NeighborUpdateInfo * update_info = cls;
889   struct DirectNeighbor *direct_neighbor = value;
890
891   if (update_info->referrer == direct_neighbor) /* Direct neighbor matches, update it's info and return GNUNET_NO */
892   {
893     /* same referrer, cost change! */
894     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
895                                        update_info->neighbor->max_loc, update_info->cost);
896     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
897                                        update_info->neighbor->min_loc, update_info->cost);
898     update_info->neighbor->last_activity = update_info->now;
899     update_info->neighbor->cost = update_info->cost;
900     return GNUNET_NO;
901   }
902
903   return GNUNET_YES;
904 }
905
906
907 /**
908  * Free a DistantNeighbor node, including removing it
909  * from the referer's list.
910  */
911 static void
912 distant_neighbor_free (struct DistantNeighbor *referee)
913 {
914   struct DirectNeighbor *referrer;
915
916   referrer = referee->referrer;
917   if (referrer != NULL)
918     {
919       GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
920                          referrer->referee_tail, referee);
921     }
922   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc);
923   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc);
924   GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors,
925                                     &referee->identity.hashPubKey);
926   GNUNET_free (referee);
927 }
928
929
930 /**
931  * Handles when a peer is either added due to being newly connected
932  * or having been gossiped about, also called when a cost for a neighbor
933  * needs to be updated.
934  *
935  * @param peer identity of the peer whose info is being added/updated
936  * @param referrer_peer_id id to use when sending to 'peer'
937  * @param referrer if this is a gossiped peer, who did we hear it from?
938  * @param cost the cost of communicating with this peer via 'referrer'
939  */
940 static void
941 addUpdateNeighbor (const struct GNUNET_PeerIdentity * peer,
942                    unsigned int referrer_peer_id,
943                    struct DirectNeighbor *referrer, unsigned int cost)
944 {
945   struct DistantNeighbor *neighbor;
946   struct DistantNeighbor *max;
947   struct GNUNET_TIME_Absolute now;
948   struct NeighborUpdateInfo *neighbor_update;
949   unsigned int our_id;
950
951   now = GNUNET_TIME_absolute_get ();
952   our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, RAND_MAX - 1) + 1;
953
954   neighbor = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
955                                                 &peer->hashPubKey);
956   neighbor_update = GNUNET_malloc(sizeof(struct NeighborUpdateInfo));
957   neighbor_update->neighbor = neighbor;
958   neighbor_update->cost = cost;
959   neighbor_update->now = now;
960   neighbor_update->referrer = referrer;
961
962   /* Either we do not know this peer, or we already do but via a different immediate peer */
963   if ((neighbor == NULL) ||
964       (GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
965                                                   &peer->hashPubKey,
966                                                   &update_matching_neighbors,
967                                                   neighbor_update) != GNUNET_SYSERR))
968     {
969       /* new neighbor! */
970       if (cost > ctx.fisheye_depth)
971         {
972           /* too costly */
973           GNUNET_free(neighbor_update);
974           return;
975         }
976       if (ctx.max_table_size <=
977           GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors))
978         {
979           /* remove most expensive entry */
980           max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
981           if (cost > max->cost)
982             {
983               /* new entry most expensive, don't create */
984               GNUNET_free(neighbor_update);
985               return;
986             }
987           if (max->cost > 0)
988             {
989               /* only free if this is not a direct connection;
990                  we could theoretically have more direct
991                  connections than DV entries allowed total! */
992               distant_neighbor_free (max);
993             }
994         }
995
996       neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
997       GNUNET_CONTAINER_DLL_insert (referrer->referee_head,
998                          referrer->referee_tail, neighbor);
999       neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap,
1000                                                         neighbor, cost);
1001       neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
1002                                                         neighbor, cost);
1003       neighbor->referrer = referrer;
1004       memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1005       neighbor->last_activity = now;
1006       neighbor->cost = cost;
1007       neighbor->referrer_id = referrer_peer_id;
1008       neighbor->our_id = our_id;
1009       neighbor->hidden =
1010         (cost == 0) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
1011                        0) : GNUNET_NO;
1012       GNUNET_CONTAINER_multihashmap_put (ctx.extended_neighbors, &peer->hashPubKey,
1013                                  neighbor,
1014                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1015     }
1016
1017   GNUNET_free(neighbor_update);
1018   /* Old logic to remove entry and replace, not needed now as we only want to remove when full
1019    * or when the referring peer disconnects from us.
1020    */
1021   /*
1022   GNUNET_DLL_remove (neighbor->referrer->referee_head,
1023                      neighbor->referrer->referee_tail, neighbor);
1024   neighbor->referrer = referrer;
1025   GNUNET_DLL_insert (referrer->referee_head,
1026                      referrer->referee_tail, neighbor);
1027   GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
1028                                      neighbor->max_loc, cost);
1029   GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
1030                                      neighbor->min_loc, cost);
1031   neighbor->referrer_id = referrer_peer_id;
1032   neighbor->last_activity = now;
1033   neighbor->cost = cost;
1034   */
1035 }
1036
1037
1038 /**
1039  * Method called whenever a peer connects.
1040  *
1041  * @param cls closure
1042  * @param peer peer identity this notification is about
1043  * @param latency reported latency of the connection with peer
1044  * @param distance reported distance (DV) to peer
1045  */
1046 void handle_core_connect (void *cls,
1047                           const struct GNUNET_PeerIdentity * peer,
1048                           struct GNUNET_TIME_Relative latency,
1049                           uint32_t distance)
1050 {
1051   struct DirectNeighbor *neighbor;
1052 #if DEBUG_DV
1053   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1054               "%s: Receives core connect message for peer %s distance %d!\n", "dv", GNUNET_i2s(peer), distance);
1055 #endif
1056
1057   if ((distance == 0) && (GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL))
1058   {
1059     neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
1060     neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext));
1061     neighbor->send_context->toNeighbor = neighbor;
1062     neighbor->send_context->timeout = default_dv_delay; /* FIXME: base this on total gossip tasks, or bandwidth */
1063     memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1064     GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors,
1065                                &peer->hashPubKey,
1066                                neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1067     addUpdateNeighbor (peer, 0, neighbor, 0);
1068     neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context);
1069   }
1070   else
1071   {
1072 #if DEBUG_DV
1073   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074               "%s: Distance (%d) greater than 0 or already know about peer (%s), not re-adding!\n", "dv", distance, GNUNET_i2s(peer));
1075 #endif
1076     return;
1077   }
1078 }
1079
1080 /**
1081  * Method called whenever a given peer either connects.
1082  *
1083  * @param cls closure
1084  * @param peer peer identity this notification is about
1085  */
1086 void handle_core_disconnect (void *cls,
1087                              const struct GNUNET_PeerIdentity * peer)
1088 {
1089   struct DirectNeighbor *neighbor;
1090   struct DistantNeighbor *referee;
1091
1092 #if DEBUG_DV
1093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094               "%s: Receives core peer disconnect message!\n", "dv");
1095 #endif
1096
1097   neighbor =
1098     GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, &peer->hashPubKey);
1099   if (neighbor == NULL)
1100     {
1101       return;
1102     }
1103   while (NULL != (referee = neighbor->referee_head))
1104     distant_neighbor_free (referee);
1105   GNUNET_assert (neighbor->referee_tail == NULL);
1106   GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors,
1107                                 &peer->hashPubKey, neighbor);
1108   if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK))
1109     GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task);
1110   GNUNET_free (neighbor);
1111 }
1112
1113
1114 /**
1115  * Process dv requests.
1116  *
1117  * @param cls closure
1118  * @param scheduler scheduler to use
1119  * @param server the initialized server
1120  * @param c configuration to use
1121  */
1122 static void
1123 run (void *cls,
1124      struct GNUNET_SCHEDULER_Handle *scheduler,
1125      struct GNUNET_SERVER_Handle *server,
1126      const struct GNUNET_CONFIGURATION_Handle *c)
1127 {
1128   struct GNUNET_TIME_Relative timeout;
1129   unsigned long long max_hosts;
1130   timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1131   sched = scheduler;
1132   cfg = c;
1133
1134   /* FIXME: Read from config, or calculate, or something other than this! */
1135   max_hosts = 50;
1136   ctx.max_table_size = 100;
1137   ctx.fisheye_depth = 3;
1138
1139   ctx.neighbor_min_heap =
1140     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1141   ctx.neighbor_max_heap =
1142     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
1143
1144   ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts);
1145   ctx.extended_neighbors =
1146     GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3);
1147
1148   client_transmit_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1149   default_dv_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5);
1150   GNUNET_SERVER_add_handlers (server, plugin_handlers);
1151   coreAPI =
1152   GNUNET_CORE_connect (sched,
1153                        cfg,
1154                        timeout,
1155                        NULL, /* FIXME: anything we want to pass around? */
1156                        &core_init,
1157                        NULL, /* Don't care about pre-connects */
1158                        &handle_core_connect,
1159                        &handle_core_disconnect,
1160                        NULL,
1161                        GNUNET_NO,
1162                        NULL,
1163                        GNUNET_NO,
1164                        core_handlers);
1165
1166   if (coreAPI == NULL)
1167     return;
1168   /* load (server); Huh? */
1169
1170   /* Scheduled the task to clean up when shutdown is called */
1171   cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
1172                                 GNUNET_TIME_UNIT_FOREVER_REL,
1173                                 &shutdown_task,
1174                                 NULL);
1175 }
1176
1177
1178 /**
1179  * The main function for the dv service.
1180  *
1181  * @param argc number of arguments from the command line
1182  * @param argv command line arguments
1183  * @return 0 ok, 1 on error
1184  */
1185 int
1186 main (int argc, char *const *argv)
1187 {
1188   return (GNUNET_OK ==
1189           GNUNET_SERVICE_run (argc,
1190                               argv,
1191                               "dv",
1192                               GNUNET_SERVICE_OPTION_NONE,
1193                               &run, NULL)) ? 0 : 1;
1194 }