16e10d674737a0d59f4b4bacb2c8b09ac6a966fe
[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  * TODO: The gossip rates need to be worked out.  Probably many other things
31  * as well.
32  *
33  */
34 #include "platform.h"
35 #include "gnunet_client_lib.h"
36 #include "gnunet_getopt_lib.h"
37 #include "gnunet_os_lib.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_service_lib.h"
40 #include "gnunet_core_service.h"
41 #include "gnunet_signal_lib.h"
42 #include "gnunet_util_lib.h"
43 #include "gnunet_hello_lib.h"
44 #include "gnunet_peerinfo_service.h"
45 #include "gnunet_crypto_lib.h"
46 #include "dv.h"
47
48 #define DEBUG_DV_PEER_NUMBERS GNUNET_YES
49
50 /**
51  * DV Service Context stuff goes here...
52  */
53
54 /**
55  * Handle to the core service api.
56  */
57 static struct GNUNET_CORE_Handle *coreAPI;
58
59 /**
60  * The identity of our peer.
61  */
62 static struct GNUNET_PeerIdentity my_identity;
63
64 /**
65  * The configuration for this service.
66  */
67 static const struct GNUNET_CONFIGURATION_Handle *cfg;
68
69 /**
70  * The scheduler for this service.
71  */
72 static struct GNUNET_SCHEDULER_Handle *sched;
73
74 /**
75  * How often do we check about sending out more peer information (if
76  * we are connected to no peers previously).
77  */
78 #define GNUNET_DV_DEFAULT_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50000)
79
80 /**
81  * How long do we wait at most between sending out information?
82  */
83 #define GNUNET_DV_MAX_SEND_INTERVAL GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 50000)
84
85 /**
86  * How long can we have not heard from a peer and
87  * still have it in our tables?
88  */
89 #define GNUNET_DV_PEER_EXPIRATION_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1000))
90
91 /**
92  * Priority for gossip.
93  */
94 #define GNUNET_DV_DHT_GOSSIP_PRIORITY (GNUNET_EXTREME_PRIORITY / 10)
95
96 /**
97  * How often should we check if expiration time has elapsed for
98  * some peer?
99  */
100 #define GNUNET_DV_MAINTAIN_FREQUENCY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
101
102 /**
103  * How long to allow a message to be delayed?
104  */
105 #define DV_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5))
106
107 /**
108  * Priority to use for DV data messages.
109  */
110 #define DV_PRIORITY 0
111
112 /**
113  * The cost to a direct neighbor.  We used to use 0, but 1 makes more sense.
114  */
115 #define DIRECT_NEIGHBOR_COST 1
116
117 /**
118  * The default number of direct connections to store in DV (max)
119  */
120 #define DEFAULT_DIRECT_CONNECTIONS 50
121
122 /**
123  * The default size of direct + extended peers in DV (max)
124  */
125 #define DEFAULT_DV_SIZE 100
126
127 /**
128  * The default fisheye depth, from how many hops away will
129  * we keep peers?
130  */
131 #define DEFAULT_FISHEYE_DEPTH 4
132
133 /**
134  * The client, the DV plugin connected to us.  Hopefully
135  * this client will never change, although if the plugin dies
136  * and returns for some reason it may happen.
137  */
138 static struct GNUNET_SERVER_Client * client_handle;
139
140 /**
141  * Task to run when we shut down, cleaning up all our trash
142  */
143 GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
144
145 /**
146  * Task to run to gossip about peers.  Will reschedule itself forever until shutdown!
147  */
148 GNUNET_SCHEDULER_TaskIdentifier gossip_task;
149
150 /**
151  * Struct where neighbor information is stored.
152  */
153 struct DistantNeighbor *referees;
154
155 static size_t default_dv_priority = 0;
156
157
158 /**
159  * Linked list of messages to send to clients.
160  */
161 struct PendingMessage
162 {
163   /**
164    * Pointer to next item in the list
165    */
166   struct PendingMessage *next;
167
168   /**
169    * Pointer to previous item in the list
170    */
171   struct PendingMessage *prev;
172
173   struct GNUNET_DV_SendResultMessage *send_result;
174   /**
175    * Actual message to be sent; // avoid allocation
176    */
177   const struct GNUNET_MessageHeader *msg; // msg = (cast) &pm[1]; // memcpy (&pm[1], data, len);
178
179 };
180
181 /**
182  * Transmit handle to the plugin.
183  */
184 struct GNUNET_CONNECTION_TransmitHandle * plugin_transmit_handle;
185
186 /**
187  * Head of DLL for client messages
188  */
189 struct PendingMessage *plugin_pending_head;
190
191 /**
192  * Tail of DLL for client messages
193  */
194 struct PendingMessage *plugin_pending_tail;
195
196 /**
197  * Handle to the peerinfo service
198  */
199 struct GNUNET_PEERINFO_Handle *peerinfo_handle;
200
201 /**
202  * Transmit handle to core service.
203  */
204 struct GNUNET_CORE_TransmitHandle * core_transmit_handle;
205
206 /**
207  * Head of DLL for core messages
208  */
209 struct PendingMessage *core_pending_head;
210
211 /**
212  * Tail of DLL for core messages
213  */
214 struct PendingMessage *core_pending_tail;
215
216
217 struct FastGossipNeighborList
218 {
219   /**
220    * Next element of DLL
221    */
222   struct FastGossipNeighborList *next;
223
224   /**
225    * Prev element of DLL
226    */
227   struct FastGossipNeighborList *prev;
228
229   /**
230    * The neighbor to gossip about
231    */
232   struct DistantNeighbor *about;
233 };
234
235 /**
236  * Context created whenever a direct peer connects to us,
237  * used to gossip other peers to it.
238  */
239 struct NeighborSendContext
240 {
241   /**
242    * The peer we will gossip to.
243    */
244   struct DirectNeighbor *toNeighbor;
245
246   /**
247    * The task associated with this context.
248    */
249   GNUNET_SCHEDULER_TaskIdentifier task;
250
251   /**
252    * Head of DLL of peers to gossip about
253    * as fast as possible to this peer, for initial
254    * set up.
255    */
256   struct FastGossipNeighborList *fast_gossip_list_head;
257
258   /**
259    * Tail of DLL of peers to gossip about
260    * as fast as possible to this peer, for initial
261    * set up.
262    */
263   struct FastGossipNeighborList *fast_gossip_list_tail;
264
265 };
266
267
268 /**
269  * Struct to hold information for updating existing neighbors
270  */
271 struct NeighborUpdateInfo
272 {
273   /**
274    * Cost
275    */
276   unsigned int cost;
277
278   /**
279    * The existing neighbor
280    */
281   struct DistantNeighbor *neighbor;
282
283   /**
284    * The referrer of the possibly existing peer
285    */
286   struct DirectNeighbor *referrer;
287
288   /**
289    * The time we heard about this peer
290    */
291   struct GNUNET_TIME_Absolute now;
292 };
293
294 /**
295  * Struct where actual neighbor information is stored,
296  * referenced by min_heap and max_heap.  Freeing dealt
297  * with when items removed from hashmap.
298  */
299 struct DirectNeighbor
300 {
301   /**
302    * Identity of neighbor.
303    */
304   struct GNUNET_PeerIdentity identity;
305
306   /**
307    * PublicKey of neighbor.
308    */
309   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
310
311   /**
312    * Head of DLL of nodes that this direct neighbor referred to us.
313    */
314   struct DistantNeighbor *referee_head;
315
316   /**
317    * Tail of DLL of nodes that this direct neighbor referred to us.
318    */
319   struct DistantNeighbor *referee_tail;
320
321   /**
322    * The sending context for gossiping peers to this neighbor.
323    */
324   struct NeighborSendContext *send_context;
325
326   /**
327    * Is this one of the direct neighbors that we are "hiding"
328    * from DV?
329    */
330   int hidden;
331 };
332
333
334 /**
335  * Struct where actual neighbor information is stored,
336  * referenced by min_heap and max_heap.  Freeing dealt
337  * with when items removed from hashmap.
338  */
339 struct DistantNeighbor
340 {
341   /**
342    * We keep distant neighbor's of the same referrer in a DLL.
343    */
344   struct DistantNeighbor *next;
345
346   /**
347    * We keep distant neighbor's of the same referrer in a DLL.
348    */
349   struct DistantNeighbor *prev;
350
351   /**
352    * Node in min heap
353    */
354   struct GNUNET_CONTAINER_HeapNode *min_loc;
355
356   /**
357    * Node in max heap
358    */
359   struct GNUNET_CONTAINER_HeapNode *max_loc;
360
361   /**
362    * Identity of referrer (next hop towards 'neighbor').
363    */
364   struct DirectNeighbor *referrer;
365
366   /**
367    * Identity of neighbor.
368    */
369   struct GNUNET_PeerIdentity identity;
370
371   /**
372    * PublicKey of neighbor.
373    */
374   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey;
375
376   /**
377    * Last time we received routing information from this peer
378    */
379   struct GNUNET_TIME_Absolute last_activity;
380
381   /**
382    * Cost to neighbor, used for actual distance vector computations
383    */
384   unsigned int cost;
385
386   /**
387    * Random identifier *we* use for this peer, to be used as shortcut
388    * instead of sending full peer id for each message
389    */
390   unsigned int our_id;
391
392   /**
393    * Random identifier the *referrer* uses for this peer.
394    */
395   unsigned int referrer_id;
396
397   /**
398    * Is this one of the direct neighbors that we are "hiding"
399    * from DV?
400    */
401   int hidden;
402
403 };
404
405 struct PeerIteratorContext
406 {
407   /**
408    * The actual context, to be freed later.
409    */
410   struct GNUNET_PEERINFO_IteratorContext *ic;
411
412   /**
413    * The neighbor about which we are concerned.
414    */
415   struct DirectNeighbor *neighbor;
416
417 };
418
419 /**
420  * Context used for creating hello messages when
421  * gossips are received.
422  */
423 struct HelloContext
424 {
425   /**
426    * Identity of distant neighbor.
427    */
428   struct GNUNET_PeerIdentity distant_peer;
429
430   /**
431    * Identity of direct neighbor, via which we send this message.
432    */
433   const struct GNUNET_PeerIdentity *direct_peer;
434
435   /**
436    * How many addresses do we need to add (always starts at 1, then set to 0)
437    */
438   int addresses_to_add;
439
440 };
441
442 struct DV_SendContext
443 {
444   /**
445    * The distant peer (should always match)
446    */
447   struct GNUNET_PeerIdentity *distant_peer;
448
449   /**
450    * The direct peer, we need to verify the referrer of.
451    */
452   struct GNUNET_PeerIdentity *direct_peer;
453
454   /**
455    * The message to be sent
456    */
457   struct GNUNET_MessageHeader *message;
458
459   /**
460    * The pre-built send result message.  Simply needs to be queued
461    * and freed once send has been called!
462    */
463   struct GNUNET_DV_SendResultMessage *send_result;
464
465   /**
466    * The size of the message being sent, may be larger
467    * than message->header.size because it's multiple
468    * messages packed into one!
469    */
470   size_t message_size;
471
472   /**
473    * How important is this message?
474    */
475   unsigned int importance;
476
477   /**
478    * Timeout for this message
479    */
480   struct GNUNET_TIME_Relative timeout;
481 };
482
483 /**
484  * Global construct
485  */
486 struct GNUNET_DV_Context
487 {
488   /**
489    * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for all
490    * directly connected peers.
491    */
492   struct GNUNET_CONTAINER_MultiHashMap *direct_neighbors;
493
494   /**
495    * Map of PeerIdentifiers to 'struct GNUNET_dv_neighbor*'s for
496    * peers connected via DV (extended neighborhood).  Does ALSO
497    * include any peers that are in 'direct_neighbors'; for those
498    * peers, the cost will be zero and the referrer all zeros.
499    */
500   struct GNUNET_CONTAINER_MultiHashMap *extended_neighbors;
501
502   /**
503    * We use the min heap (min refers to cost) to prefer
504    * gossipping about peers with small costs.
505    */
506   struct GNUNET_CONTAINER_Heap *neighbor_min_heap;
507
508   /**
509    * We use the max heap (max refers to cost) for general
510    * iterations over all peers and to remove the most costly
511    * connection if we have too many.
512    */
513   struct GNUNET_CONTAINER_Heap *neighbor_max_heap;
514
515   unsigned long long fisheye_depth;
516
517   unsigned long long max_table_size;
518
519   unsigned int neighbor_id_loc;
520
521   int closing;
522
523 };
524
525 static struct GNUNET_DV_Context ctx;
526
527 struct FindDestinationContext
528 {
529   unsigned int tid;
530   struct DistantNeighbor *dest;
531 };
532
533 struct DisconnectContext
534 {
535   /**
536    * Distant neighbor to get pid from.
537    */
538   struct DistantNeighbor *distant;
539
540   /**
541    * Direct neighbor that disconnected.
542    */
543   struct DirectNeighbor *direct;
544 };
545
546 /**
547  * We've been given a target ID based on the random numbers that
548  * we assigned to our DV-neighborhood.  Find the entry for the
549  * respective neighbor.
550  */
551 static int
552 find_destination (void *cls,
553                   struct GNUNET_CONTAINER_HeapNode *node,
554                   void *element, GNUNET_CONTAINER_HeapCostType cost)
555 {
556   struct FindDestinationContext *fdc = cls;
557   struct DistantNeighbor *dn = element;
558
559   if (fdc->tid != dn->our_id)
560     return GNUNET_YES;
561   fdc->dest = dn;
562   return GNUNET_NO;
563 }
564
565 /**
566  * Find a distant peer whose referrer_id matches what we're
567  * looking for.  For looking up a peer we've gossipped about
568  * but is now disconnected.  Need to do this because we don't
569  * want to remove those that may be accessible via a different
570  * route.
571  */
572 static int find_distant_peer (void *cls,
573                               const GNUNET_HashCode * key,
574                               void *value)
575 {
576   struct FindDestinationContext *fdc = cls;
577   struct DistantNeighbor *distant = value;
578
579   if (fdc->tid == distant->referrer_id)
580     {
581       fdc->dest = distant;
582       return GNUNET_NO;
583     }
584   return GNUNET_YES;
585 }
586
587 /**
588  * Function called to notify a client about the socket
589  * begin ready to queue more data.  "buf" will be
590  * NULL and "size" zero if the socket was closed for
591  * writing in the meantime.
592  *
593  * @param cls closure
594  * @param size number of bytes available in buf
595  * @param buf where the callee should write the message
596  * @return number of bytes written to buf
597  */
598 size_t transmit_to_plugin (void *cls,
599                            size_t size, void *buf)
600 {
601   char *cbuf = buf;
602   struct PendingMessage *reply;
603   size_t off;
604   size_t msize;
605
606   if (buf == NULL)
607     {
608       /* client disconnected */
609 #if DEBUG_DV
610       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s': buffer was NULL\n", "DHT");
611 #endif
612       return 0;
613     }
614   plugin_transmit_handle = NULL;
615   off = 0;
616   while ( (NULL != (reply = plugin_pending_head)) &&
617           (size >= off + (msize = ntohs (reply->msg->size))))
618     {
619 #if DEBUG_DV
620     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "`%s' : transmit_notify (plugin) called with size %d\n", "dv service", msize);
621 #endif
622       GNUNET_CONTAINER_DLL_remove (plugin_pending_head,
623                                    plugin_pending_tail,
624                                    reply);
625       memcpy (&cbuf[off], reply->msg, msize);
626       GNUNET_free (reply);
627       off += msize;
628     }
629
630   if (plugin_pending_head != NULL)
631     plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle,
632                                                                   ntohs(plugin_pending_head->msg->size),
633                                                                   GNUNET_TIME_UNIT_FOREVER_REL,
634                                                                   &transmit_to_plugin, NULL);
635
636   return off;
637 }
638
639 /**
640  * Send a message to the dv plugin.
641  *
642  * @param sender the direct sender of the message
643  * @param message the message to send to the plugin
644  *        (may be an encapsulated type)
645  * @param message_size the size of the message to be sent
646  * @param distant_neighbor the original sender of the message
647  * @param cost the cost to the original sender of the message
648  */
649 void send_to_plugin(const struct GNUNET_PeerIdentity * sender,
650                     const struct GNUNET_MessageHeader *message,
651                     size_t message_size,
652                     struct GNUNET_PeerIdentity *distant_neighbor,
653                     size_t cost)
654 {
655   struct GNUNET_DV_MessageReceived *received_msg;
656   struct PendingMessage *pending_message;
657 #if DEBUG_DV
658   struct GNUNET_MessageHeader * packed_message_header;
659   struct GNUNET_HELLO_Message *hello_msg;
660   struct GNUNET_PeerIdentity hello_identity;
661 #endif
662   char *sender_address;
663   size_t sender_address_len;
664   char *packed_msg_start;
665   int size;
666
667 #if DEBUG_DV
668   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send_to_plugin called with peer %s as sender\n", GNUNET_i2s(distant_neighbor));
669 #endif
670
671   if (memcmp(sender, distant_neighbor, sizeof(struct GNUNET_PeerIdentity)) != 0)
672   {
673     sender_address_len = sizeof(struct GNUNET_PeerIdentity) * 2;
674     sender_address = GNUNET_malloc(sender_address_len);
675     memcpy(sender_address, distant_neighbor, sizeof(struct GNUNET_PeerIdentity));
676     memcpy(&sender_address[sizeof(struct GNUNET_PeerIdentity)], sender, sizeof(struct GNUNET_PeerIdentity));
677   }
678   else
679   {
680     sender_address_len = sizeof(struct GNUNET_PeerIdentity);
681     sender_address = GNUNET_malloc(sender_address_len);
682     memcpy(sender_address, sender, sizeof(struct GNUNET_PeerIdentity));
683   }
684
685   size = sizeof(struct GNUNET_DV_MessageReceived) + sender_address_len + message_size;
686   received_msg = GNUNET_malloc(size);
687   received_msg->header.size = htons(size);
688   received_msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE);
689   received_msg->sender_address_len = htonl(sender_address_len);
690   received_msg->distance = htonl(cost);
691   received_msg->msg_len = htonl(message_size);
692   /* Set the sender in this message to be the original sender! */
693   memcpy(&received_msg->sender, distant_neighbor, sizeof(struct GNUNET_PeerIdentity));
694   /* Copy the intermediate sender to the end of the message, this is how the transport identifies this peer */
695   memcpy(&received_msg[1], sender_address, sender_address_len);
696   GNUNET_free(sender_address);
697   /* Copy the actual message after the sender */
698   packed_msg_start = (char *)&received_msg[1];
699   packed_msg_start = &packed_msg_start[sender_address_len];
700   memcpy(packed_msg_start, message, message_size);
701 #if DEBUG_DV
702   packed_message_header = (struct GNUNET_MessageHeader *)packed_msg_start;
703   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "dv service created received message. sender_address_len %lu, packed message len %d, total len %d\n", sender_address_len, ntohl(received_msg->msg_len), ntohs(received_msg->header.size));
704   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "dv packed message len %d, type %d\n", ntohs(packed_message_header->size), ntohs(packed_message_header->type));
705   if (ntohs(packed_message_header->type) == GNUNET_MESSAGE_TYPE_HELLO)
706   {
707     hello_msg = (struct GNUNET_HELLO_Message *)packed_message_header;
708     GNUNET_assert(GNUNET_OK == GNUNET_HELLO_get_id(hello_msg, &hello_identity));
709     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Packed HELLO message is about peer %s\n", GNUNET_i2s(&hello_identity));
710   }
711 #endif
712   pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + size);
713   pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1];
714   memcpy(&pending_message[1], received_msg, size);
715   GNUNET_free(received_msg);
716
717   GNUNET_CONTAINER_DLL_insert_after(plugin_pending_head, plugin_pending_tail, plugin_pending_tail, pending_message);
718
719   if (client_handle != NULL)
720     {
721       if (plugin_transmit_handle == NULL)
722         {
723           plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle,
724                                                                         size, GNUNET_TIME_UNIT_FOREVER_REL,
725                                                                         &transmit_to_plugin, NULL);
726         }
727 #if DEBUG_DV
728       else
729         {
730           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n");
731         }
732 #endif
733     }
734 }
735
736
737 /**
738  * Function called to notify a client about the socket
739  * being ready to queue more data.  "buf" will be
740  * NULL and "size" zero if the socket was closed for
741  * writing in the meantime.
742  *
743  * @param cls closure
744  * @param size number of bytes available in buf
745  * @param buf where the callee should write the message
746  * @return number of bytes written to buf
747  */
748 size_t core_transmit_notify (void *cls,
749                              size_t size, void *buf)
750 {
751   char *cbuf = buf;
752   struct PendingMessage *reply;
753   struct PendingMessage *client_reply;
754   size_t off;
755   size_t msize;
756
757   if (buf == NULL)
758     {
759       /* client disconnected */
760 #if DEBUG_DV
761       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s': buffer was NULL\n", "DHT");
762 #endif
763       return 0;
764     }
765
766   core_transmit_handle = NULL;
767   off = 0;
768   while ( (NULL != (reply = core_pending_head)) &&
769           (size >= off + (msize = ntohs (reply->msg->size))))
770     {
771 #if DEBUG_DV
772     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "`%s' : transmit_notify (core) called with size %d\n", "dv service", msize);
773 #endif
774       GNUNET_CONTAINER_DLL_remove (core_pending_head,
775                                    core_pending_tail,
776                                    reply);
777       if (reply->send_result != NULL) /* Will only be non-null if a real client asked for this send */
778         {
779           client_reply = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(struct GNUNET_DV_SendResultMessage));
780           client_reply->msg = (struct GNUNET_MessageHeader *)&client_reply[1];
781           memcpy(&client_reply[1], reply->send_result, sizeof(struct GNUNET_DV_SendResultMessage));
782           GNUNET_free(reply->send_result);
783
784           GNUNET_CONTAINER_DLL_insert_after(plugin_pending_head, plugin_pending_tail, plugin_pending_tail, client_reply);
785           if (client_handle != NULL)
786             {
787               if (plugin_transmit_handle == NULL)
788                 {
789                   plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle,
790                                                                                 sizeof(struct GNUNET_DV_SendResultMessage),
791                                                                                 GNUNET_TIME_UNIT_FOREVER_REL,
792                                                                                 &transmit_to_plugin, NULL);
793                 }
794               else
795                 {
796                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n");
797                 }
798             }
799         }
800       memcpy (&cbuf[off], reply->msg, msize);
801       GNUNET_free (reply);
802       off += msize;
803     }
804   return off;
805 }
806
807
808 /**
809  * Send a DV data message via DV.
810  *
811  * @param sender the original sender of the message
812  * @param specific_neighbor the specific DistantNeighbor to use, complete with referrer!
813  * @param send_context the send context
814  */
815 static int
816 send_message_via (const struct GNUNET_PeerIdentity * sender,
817               const struct DistantNeighbor * specific_neighbor,
818               struct DV_SendContext *send_context)
819 {
820   p2p_dv_MESSAGE_Data *toSend;
821   unsigned int msg_size;
822   unsigned int cost;
823   unsigned int recipient_id;
824   unsigned int sender_id;
825   struct DistantNeighbor *source;
826   struct PendingMessage *pending_message;
827 #if DEBUG_DV
828   char shortname[5];
829 #endif
830
831   msg_size = send_context->message_size + sizeof (p2p_dv_MESSAGE_Data);
832
833   if (specific_neighbor == NULL)
834     {
835       /* target unknown to us, drop! */
836       return GNUNET_SYSERR;
837     }
838   recipient_id = specific_neighbor->referrer_id;
839
840   source = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
841                                       &sender->hashPubKey);
842   if (source == NULL)
843     {
844       if (0 != (memcmp (&my_identity,
845                         sender, sizeof (struct GNUNET_PeerIdentity))))
846         {
847           /* sender unknown to us, drop! */
848           return GNUNET_SYSERR;
849         }
850       sender_id = 0;            /* 0 == us */
851     }
852   else
853     {
854       /* find out the number that we use when we gossip about
855          the sender */
856       sender_id = source->our_id;
857     }
858
859   cost = specific_neighbor->cost;
860   pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + msg_size);
861   pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1];
862   pending_message->send_result = send_context->send_result;
863   toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg;
864   toSend->header.size = htons (msg_size);
865   toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
866   toSend->sender = htonl (sender_id);
867   toSend->recipient = htonl (recipient_id);
868   memcpy (&toSend[1], send_context->message, send_context->message_size);
869
870 #if DEBUG_DV
871   memcpy(&shortname, GNUNET_i2s(&specific_neighbor->identity), 4);
872   shortname[4] = '\0';
873   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: Notifying core of send to destination `%s' via `%s' size %u\n", "DV", &shortname, GNUNET_i2s(&specific_neighbor->referrer->identity), msg_size);
874 #endif
875
876   GNUNET_CONTAINER_DLL_insert_after (core_pending_head,
877                                      core_pending_tail,
878                                      core_pending_tail,
879                                      pending_message);
880   if (core_transmit_handle == NULL)
881     core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, send_context->importance, send_context->timeout, &specific_neighbor->referrer->identity, msg_size, &core_transmit_notify, NULL);
882   else
883     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "`%s': Failed to schedule pending transmission (must be one in progress!)\n", "dv service");
884
885   return (int) cost;
886 }
887
888
889 /**
890  * Send a DV data message via DV.
891  *
892  * @param recipient the ultimate recipient of this message
893  * @param sender the original sender of the message
894  * @param specific_neighbor the specific neighbor to send this message via
895  * @param message the packed message
896  * @param message_size size of the message
897  * @param importance what priority to send this message with
898  * @param timeout how long to possibly delay sending this message
899  */
900 static int
901 send_message (const struct GNUNET_PeerIdentity * recipient,
902               const struct GNUNET_PeerIdentity * sender,
903               const struct DistantNeighbor * specific_neighbor,
904               const struct GNUNET_MessageHeader * message,
905               size_t message_size,
906               unsigned int importance, struct GNUNET_TIME_Relative timeout)
907 {
908   p2p_dv_MESSAGE_Data *toSend;
909   unsigned int msg_size;
910   unsigned int cost;
911   unsigned int recipient_id;
912   unsigned int sender_id;
913   struct DistantNeighbor *target;
914   struct DistantNeighbor *source;
915   struct PendingMessage *pending_message;
916
917   msg_size = message_size + sizeof (p2p_dv_MESSAGE_Data);
918
919   target = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
920                                               &recipient->hashPubKey);
921   if (target == NULL)
922     {
923       /* target unknown to us, drop! */
924       return GNUNET_SYSERR;
925     }
926   recipient_id = target->referrer_id;
927
928   source = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
929                                       &sender->hashPubKey);
930   if (source == NULL)
931     {
932       if (0 != (memcmp (&my_identity,
933                         sender, sizeof (struct GNUNET_PeerIdentity))))
934         {
935           /* sender unknown to us, drop! */
936           return GNUNET_SYSERR;
937         }
938       sender_id = 0;            /* 0 == us */
939     }
940   else
941     {
942       /* find out the number that we use when we gossip about
943          the sender */
944       sender_id = source->our_id;
945     }
946
947   cost = target->cost;
948   pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + msg_size);
949   pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1];
950   pending_message->send_result = NULL;
951   toSend = (p2p_dv_MESSAGE_Data *)pending_message->msg;
952   toSend->header.size = htons (msg_size);
953   toSend->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DATA);
954   toSend->sender = htonl (sender_id);
955   toSend->recipient = htonl (recipient_id);
956   memcpy (&toSend[1], message, message_size);
957
958   GNUNET_CONTAINER_DLL_insert_after (core_pending_head,
959                                      core_pending_tail,
960                                      core_pending_tail,
961                                      pending_message);
962 #if DEBUG_DV
963   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: Notifying core of send size %d to destination `%s'\n", "DV SEND MESSAGE", msg_size, GNUNET_i2s(recipient));
964 #endif
965   if (core_transmit_handle == NULL)
966     core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, importance, timeout, &target->referrer->identity, msg_size, &core_transmit_notify, NULL);
967
968   return (int) cost;
969 }
970
971
972 /**
973  * Core handler for dv data messages.  Whatever this message
974  * contains all we really have to do is rip it out of its
975  * DV layering and give it to our pal the DV plugin to report
976  * in with.
977  *
978  * @param cls closure
979  * @param peer peer which sent the message (immediate sender)
980  * @param message the message
981  * @param latency the latency of the connection we received the message from
982  * @param distance the distance to the immediate peer
983  */
984 static int handle_dv_data_message (void *cls,
985                              const struct GNUNET_PeerIdentity * peer,
986                              const struct GNUNET_MessageHeader * message,
987                              struct GNUNET_TIME_Relative latency,
988                              uint32_t distance)
989 {
990   const p2p_dv_MESSAGE_Data *incoming = (const p2p_dv_MESSAGE_Data *) message;
991   const struct GNUNET_MessageHeader *packed_message;
992   struct DirectNeighbor *dn;
993   struct DistantNeighbor *pos;
994   unsigned int sid;             /* Sender id */
995   unsigned int tid;             /* Target id */
996   struct GNUNET_PeerIdentity original_sender;
997   struct GNUNET_PeerIdentity destination;
998   struct FindDestinationContext fdc;
999   int ret;
1000   size_t packed_message_size;
1001   char *cbuf;
1002   size_t offset;
1003
1004   packed_message_size = ntohs(incoming->header.size) - sizeof(p2p_dv_MESSAGE_Data);
1005
1006 #if DEBUG_DV
1007   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008               "%s: Receives %s message size %d, packed message size %d!\n", "dv", "DV DATA", ntohs(incoming->header.size), packed_message_size);
1009 #endif
1010   if (ntohs (incoming->header.size) <  sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader))
1011     {
1012 #if DEBUG_DV
1013   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014               "`%s': Message sizes don't add up, total size %u, expected at least %u!\n", "dv service", ntohs(incoming->header.size), sizeof (p2p_dv_MESSAGE_Data) + sizeof (struct GNUNET_MessageHeader));
1015 #endif
1016       return GNUNET_SYSERR;
1017     }
1018
1019   dn = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
1020                                   &peer->hashPubKey);
1021   if (dn == NULL)
1022     {
1023 #if DEBUG_DV
1024       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1025                   "%s: dn NULL!\n", "dv");
1026 #endif
1027       return GNUNET_OK;
1028     }
1029   sid = ntohl (incoming->sender);
1030   pos = dn->referee_head;
1031   while ((NULL != pos) && (pos->referrer_id != sid))
1032     pos = pos->next;
1033
1034   if (pos == NULL)
1035     {
1036 #if DEBUG_DV_PEER_NUMBERS
1037       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1038                   "%s peer %s: unknown sender (%d)!\n", "DV SERVICE", GNUNET_i2s(&my_identity), ntohl(incoming->sender), GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors));
1039 #endif
1040       /* unknown sender */
1041       return GNUNET_OK;
1042     }
1043   original_sender = pos->identity;
1044   tid = ntohl (incoming->recipient);
1045   if (tid == 0)
1046     {
1047       /* 0 == us */
1048       cbuf = (char *)&incoming[1];
1049       offset = 0;
1050       while(offset < packed_message_size)
1051         {
1052           packed_message = (struct GNUNET_MessageHeader *)&cbuf[offset];
1053 #if DEBUG_DV
1054           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055                       "%s: Receives %s message for me, size %d type %d, cost %u!\n", "dv", "DV DATA", ntohs(packed_message->size), ntohs(packed_message->type), pos->cost);
1056 #endif
1057           GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP);
1058           GNUNET_break_op (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA);
1059           if ( (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_GOSSIP) &&
1060               (ntohs (packed_message->type) != GNUNET_MESSAGE_TYPE_DV_DATA) )
1061           {
1062             send_to_plugin(peer, packed_message, ntohs(packed_message->size), &pos->identity, pos->cost);
1063           }
1064           offset += ntohs(packed_message->size);
1065         }
1066
1067       return GNUNET_OK;
1068     }
1069   else
1070     {
1071       packed_message = (struct GNUNET_MessageHeader *)&incoming[1];
1072     }
1073
1074   /* FIXME: this is the *only* per-request operation we have in DV
1075      that is O(n) in relation to the number of connected peers; a
1076      hash-table lookup could easily solve this (minor performance
1077      issue) */
1078   fdc.tid = tid;
1079   fdc.dest = NULL;
1080   GNUNET_CONTAINER_heap_iterate (ctx.neighbor_max_heap,
1081                                  &find_destination, &fdc);
1082
1083 #if DEBUG_DV
1084       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085                   "%s: Receives %s message for someone else!\n", "dv", "DV DATA");
1086 #endif
1087
1088   if (fdc.dest == NULL)
1089     {
1090       return GNUNET_OK;
1091     }
1092   destination = fdc.dest->identity;
1093
1094   if (0 == memcmp (&destination, peer, sizeof (struct GNUNET_PeerIdentity)))
1095     {
1096       /* FIXME: create stat: routing loop-discard! */
1097 #if DEBUG_DV
1098       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "\n\n\nLoopy loo message\n\n\n");
1099 #endif
1100       return GNUNET_OK;
1101     }
1102
1103   /* At this point we have a message, and we need to forward it on to the
1104    * next DV hop.
1105    */
1106   /* FIXME: Can't send message on, we have to behave.
1107    * We have to tell core we have a message for the next peer, and let
1108    * transport do transport selection on how to get this message to 'em */
1109   /*ret = send_message (&destination,
1110                       &original_sender,
1111                       packed_message, DV_PRIORITY, DV_DELAY);*/
1112 #if DEBUG_DV
1113   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1114               "%s: Sends message size %d on!\n", "dv", packed_message_size);
1115 #endif
1116   ret = send_message(&destination, &original_sender, NULL, packed_message, packed_message_size, default_dv_priority, GNUNET_TIME_relative_get_forever());
1117
1118   if (ret != GNUNET_SYSERR)
1119     return GNUNET_OK;
1120   else
1121     return GNUNET_SYSERR;
1122 }
1123
1124
1125 /**
1126  *  Scheduled task which gossips about known direct peers to other connected
1127  *  peers.  Will run until called with reason shutdown.
1128  */
1129 static void
1130 neighbor_send_task (void *cls,
1131                     const struct GNUNET_SCHEDULER_TaskContext *tc)
1132 {
1133   struct NeighborSendContext *send_context = cls;
1134 #if DEBUG_DV_GOSSIP_SEND
1135   char * encPeerAbout;
1136   char * encPeerTo;
1137 #endif
1138   struct DistantNeighbor *about;
1139   struct DirectNeighbor *to;
1140   struct FastGossipNeighborList *about_list;
1141
1142   p2p_dv_MESSAGE_NeighborInfo *message;
1143   struct PendingMessage *pending_message;
1144
1145   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1146   {
1147 #if DEBUG_DV_GOSSIP
1148   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149               "%s: Called with reason shutdown, shutting down!\n",
1150               GNUNET_i2s(&my_identity));
1151 #endif
1152     send_context->task = GNUNET_SCHEDULER_NO_TASK;
1153     return;
1154   }
1155
1156   if (send_context->fast_gossip_list_head != NULL)
1157     {
1158       about_list = send_context->fast_gossip_list_head;
1159       about = send_context->fast_gossip_list_head->about;
1160       GNUNET_CONTAINER_DLL_remove(send_context->fast_gossip_list_head,
1161                                   send_context->fast_gossip_list_tail,
1162                                   about_list);
1163       GNUNET_free(about_list);
1164     }
1165   else
1166     {
1167       /* FIXME: this may become a problem, because the heap walk has only one internal "walker".  This means
1168        * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
1169        * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
1170        * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
1171        * part of the walk_get_next call.  Then the heap would have to keep a list of walks, or reset the walk
1172        * whenever a modification has been detected.  Yuck either way.  Perhaps we could iterate over the heap
1173        * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
1174        * in the mean time that becomes nasty.  For now we'll just assume that the walking is done
1175        * asynchronously enough to avoid major problems (-;
1176        */
1177       about = GNUNET_CONTAINER_heap_walk_get_next (ctx.neighbor_min_heap);
1178     }
1179   to = send_context->toNeighbor;
1180
1181   if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
1182 #if SUPPORT_HIDING
1183       (about->hidden == GNUNET_NO) &&
1184 #endif
1185       (to != NULL) &&
1186       (0 != memcmp (&about->identity,
1187                         &to->identity, sizeof (struct GNUNET_PeerIdentity))) &&
1188       (about->pkey != NULL))
1189     {
1190 #if DEBUG_DV_GOSSIP_SEND
1191       encPeerAbout = GNUNET_strdup(GNUNET_i2s(&about->identity));
1192       encPeerTo = GNUNET_strdup(GNUNET_i2s(&to->identity));
1193       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1194                   "%s: Sending info about peer %s id %u to directly connected peer %s\n",
1195                   GNUNET_i2s(&my_identity),
1196                   encPeerAbout, about->our_id, encPeerTo);
1197       GNUNET_free(encPeerAbout);
1198       GNUNET_free(encPeerTo);
1199 #endif
1200       pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(p2p_dv_MESSAGE_NeighborInfo));
1201       pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1];
1202       message = (p2p_dv_MESSAGE_NeighborInfo *)pending_message->msg;
1203       message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
1204       message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
1205       message->cost = htonl (about->cost);
1206       message->neighbor_id = htonl (about->our_id);
1207
1208       memcpy (&message->pkey, about->pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1209       memcpy (&message->neighbor,
1210               &about->identity, sizeof (struct GNUNET_PeerIdentity));
1211
1212       GNUNET_CONTAINER_DLL_insert_after (core_pending_head,
1213                                          core_pending_tail,
1214                                          core_pending_tail,
1215                                          pending_message);
1216
1217       if (core_transmit_handle == NULL)
1218         core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, GNUNET_TIME_relative_get_forever(), &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, NULL);
1219
1220     }
1221
1222   if (send_context->fast_gossip_list_head != NULL) /* If there are other peers in the fast list, schedule right away */
1223     {
1224 #if DEBUG_DV
1225       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DV SERVICE: still in fast send mode\n");
1226 #endif
1227       send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, send_context);
1228     }
1229   else
1230     {
1231 #if DEBUG_DV
1232       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DV SERVICE: entering slow send mode\n");
1233 #endif
1234       send_context->task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_DV_DEFAULT_SEND_INTERVAL, &neighbor_send_task, send_context);
1235     }
1236
1237   return;
1238 }
1239
1240
1241 /**
1242  * Handle START-message.  This is the first message sent to us
1243  * by the client (can only be one!).
1244  *
1245  * @param cls closure (always NULL)
1246  * @param client identification of the client
1247  * @param message the actual message
1248  */
1249 static void
1250 handle_start (void *cls,
1251               struct GNUNET_SERVER_Client *client,
1252               const struct GNUNET_MessageHeader *message)
1253 {
1254
1255 #if DEBUG_DV
1256   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1257               "Received `%s' request from client\n", "START");
1258 #endif
1259
1260   client_handle = client;
1261
1262   GNUNET_SERVER_client_keep(client_handle);
1263   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1264 }
1265
1266
1267 /**
1268  * Iterate over hash map entries for a distant neighbor,
1269  * if direct neighbor matches context call send message
1270  *
1271  * @param cls closure, a DV_SendContext
1272  * @param key current key code
1273  * @param value value in the hash map
1274  * @return GNUNET_YES if we should continue to
1275  *         iterate,
1276  *         GNUNET_NO if not.
1277  */
1278 int send_iterator (void *cls,
1279                    const GNUNET_HashCode * key,
1280                    void *value)
1281 {
1282   struct DV_SendContext *send_context = cls;
1283   struct DistantNeighbor *distant_neighbor = value;
1284
1285   if (memcmp(distant_neighbor->referrer, send_context->direct_peer, sizeof(struct GNUNET_PeerIdentity)) == 0) /* They match, send and free */
1286     {
1287       send_message_via(&my_identity, distant_neighbor, send_context);
1288       return GNUNET_NO;
1289     }
1290   return GNUNET_YES;
1291 }
1292
1293 /**
1294  * Service server's handler for message send requests (which come
1295  * bubbling up to us through the DV plugin).
1296  *
1297  * @param cls closure
1298  * @param client identification of the client
1299  * @param message the actual message
1300  */
1301 void handle_dv_send_message (void *cls,
1302                              struct GNUNET_SERVER_Client * client,
1303                              const struct GNUNET_MessageHeader * message)
1304 {
1305   struct GNUNET_DV_SendMessage *send_msg;
1306   struct GNUNET_DV_SendResultMessage *send_result_msg;
1307   struct PendingMessage *pending_message;
1308   size_t address_len;
1309   size_t message_size;
1310   struct GNUNET_PeerIdentity *destination;
1311   struct GNUNET_PeerIdentity *direct;
1312   struct GNUNET_MessageHeader *message_buf;
1313   char *temp_pos;
1314   int offset;
1315   static struct GNUNET_CRYPTO_HashAsciiEncoded dest_hash;
1316   struct DV_SendContext *send_context;
1317
1318   if (client_handle == NULL)
1319   {
1320     client_handle = client;
1321     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1322               "%s: Setting initial client handle, never received `%s' message?\n", "dv", "START");
1323   }
1324   else if (client_handle != client)
1325   {
1326     client_handle = client;
1327     /* What should we do in this case, assert fail or just log the warning? */
1328     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1329                 "%s: Setting client handle (was a different client!)!\n", "dv");
1330   }
1331
1332   GNUNET_assert(ntohs(message->size) > sizeof(struct GNUNET_DV_SendMessage));
1333   send_msg = (struct GNUNET_DV_SendMessage *)message;
1334
1335   address_len = ntohl(send_msg->addrlen);
1336   GNUNET_assert(address_len == sizeof(struct GNUNET_PeerIdentity) * 2);
1337   message_size = ntohl(send_msg->msgbuf_size);
1338
1339   GNUNET_assert(ntohs(message->size) == sizeof(struct GNUNET_DV_SendMessage) + address_len + message_size);
1340   destination = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
1341   direct = GNUNET_malloc(sizeof(struct GNUNET_PeerIdentity));
1342   message_buf = GNUNET_malloc(message_size);
1343
1344   temp_pos = (char *)&send_msg[1]; /* Set pointer to end of message */
1345   offset = 0; /* Offset starts at zero */
1346
1347   memcpy(destination, &temp_pos[offset], sizeof(struct GNUNET_PeerIdentity));
1348   offset += sizeof(struct GNUNET_PeerIdentity);
1349
1350   memcpy(direct, &temp_pos[offset], sizeof(struct GNUNET_PeerIdentity));
1351   offset += sizeof(struct GNUNET_PeerIdentity);
1352
1353
1354   memcpy(message_buf, &temp_pos[offset], message_size);
1355   if (memcmp(&send_msg->target, destination, sizeof(struct GNUNET_PeerIdentity)) != 0)
1356     {
1357       GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */
1358       dest_hash.encoding[4] = '\0';
1359       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%s: asked to send message to `%s', but address is for `%s'!", "DV SERVICE", GNUNET_i2s(&send_msg->target), (const char *)&dest_hash.encoding);
1360     }
1361
1362 #if DEBUG_DV
1363   GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */
1364   dest_hash.encoding[4] = '\0';
1365   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DV SEND called with message of size %d type %d, destination `%s' via `%s'\n", message_size, ntohs(message_buf->type), (const char *)&dest_hash.encoding, GNUNET_i2s(direct));
1366 #endif
1367   send_context = GNUNET_malloc(sizeof(struct DV_SendContext));
1368
1369   send_result_msg = GNUNET_malloc(sizeof(struct GNUNET_DV_SendResultMessage));
1370   send_result_msg->header.size = htons(sizeof(struct GNUNET_DV_SendResultMessage));
1371   send_result_msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT);
1372   send_result_msg->uid = send_msg->uid; /* No need to ntohl->htonl this */
1373
1374   send_context->importance = ntohl(send_msg->priority);
1375   send_context->timeout = send_msg->timeout;
1376   send_context->direct_peer = direct;
1377   send_context->distant_peer = destination;
1378   send_context->message = message_buf;
1379   send_context->message_size = message_size;
1380   send_context->send_result = send_result_msg;
1381
1382   /* In bizarro world GNUNET_SYSERR indicates that we succeeded */
1383   if (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors, &destination->hashPubKey, &send_iterator, send_context))
1384     {
1385       send_result_msg->result = htons(1);
1386       pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(struct GNUNET_DV_SendResultMessage));
1387       pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1];
1388       memcpy(&pending_message[1], send_result_msg, sizeof(struct GNUNET_DV_SendResultMessage));
1389       GNUNET_free(send_result_msg);
1390
1391       GNUNET_CONTAINER_DLL_insert_after(plugin_pending_head, plugin_pending_tail, plugin_pending_tail, pending_message);
1392
1393       if (client_handle != NULL)
1394         {
1395           if (plugin_transmit_handle == NULL)
1396             {
1397               plugin_transmit_handle = GNUNET_SERVER_notify_transmit_ready (client_handle,
1398                                                                             sizeof(struct GNUNET_DV_SendResultMessage),
1399                                                                             GNUNET_TIME_UNIT_FOREVER_REL,
1400                                                                             &transmit_to_plugin, NULL);
1401             }
1402           else
1403             {
1404               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to queue message for plugin, must be one in progress already!!\n");
1405             }
1406         }
1407       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "DV SEND failed to send message to destination `%s' via `%s'\n", (const char *)&dest_hash.encoding, GNUNET_i2s(direct));
1408     }
1409   else
1410     {
1411
1412     }
1413
1414   GNUNET_free(message_buf);
1415   GNUNET_free(send_context);
1416   GNUNET_free(direct);
1417   GNUNET_free(destination);
1418
1419   GNUNET_SERVER_receive_done(client, GNUNET_OK);
1420 }
1421
1422 /** Forward declarations **/
1423 static int handle_dv_gossip_message (void *cls,
1424                                      const struct GNUNET_PeerIdentity *peer,
1425                                      const struct GNUNET_MessageHeader *message,
1426                                      struct GNUNET_TIME_Relative latency,
1427                                      uint32_t distance);
1428
1429 static int handle_dv_disconnect_message (void *cls,
1430                                          const struct GNUNET_PeerIdentity *peer,
1431                                          const struct GNUNET_MessageHeader *message,
1432                                          struct GNUNET_TIME_Relative latency,
1433                                          uint32_t distance);
1434 /** End forward declarations **/
1435
1436
1437 /**
1438  * List of handlers for the messages understood by this
1439  * service.
1440  *
1441  * Hmm... will we need to register some handlers with core and
1442  * some handlers with our server here?  Because core should be
1443  * getting the incoming DV messages (from whichever lower level
1444  * transport) and then our server should be getting messages
1445  * from the dv_plugin, right?
1446  */
1447 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
1448   {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
1449   {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
1450   {&handle_dv_disconnect_message, GNUNET_MESSAGE_TYPE_DV_DISCONNECT, 0},
1451   {NULL, 0, 0}
1452 };
1453
1454 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
1455   {&handle_dv_send_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
1456   {&handle_start, NULL, GNUNET_MESSAGE_TYPE_DV_START, 0},
1457   {NULL, NULL, 0, 0}
1458 };
1459
1460 /**
1461  * Free a DistantNeighbor node, including removing it
1462  * from the referer's list.
1463  */
1464 static void
1465 distant_neighbor_free (struct DistantNeighbor *referee)
1466 {
1467   struct DirectNeighbor *referrer;
1468
1469   referrer = referee->referrer;
1470   if (referrer != NULL)
1471     {
1472       GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
1473                          referrer->referee_tail, referee);
1474     }
1475   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_max_heap, referee->max_loc);
1476   GNUNET_CONTAINER_heap_remove_node (ctx.neighbor_min_heap, referee->min_loc);
1477   GNUNET_CONTAINER_multihashmap_remove_all (ctx.extended_neighbors,
1478                                     &referee->identity.hashPubKey);
1479   GNUNET_free (referee->pkey);
1480   GNUNET_free (referee);
1481 }
1482
1483 /**
1484  * Free a DirectNeighbor node, including removing it
1485  * from the referer's list.
1486  */
1487 static void
1488 direct_neighbor_free (struct DirectNeighbor *direct)
1489 {
1490   struct NeighborSendContext *send_context;
1491   struct FastGossipNeighborList *about_list;
1492   struct FastGossipNeighborList *prev_about;
1493
1494   send_context = direct->send_context;
1495
1496   if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
1497     GNUNET_SCHEDULER_cancel(sched, send_context->task);
1498
1499   about_list = send_context->fast_gossip_list_head;
1500   while (about_list != NULL)
1501     {
1502       GNUNET_CONTAINER_DLL_remove(send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, about_list);
1503       prev_about = about_list;
1504       about_list = about_list->next;
1505       GNUNET_free(prev_about);
1506     }
1507   GNUNET_free(send_context);
1508   GNUNET_free(direct);
1509 }
1510
1511 /**
1512  * Multihashmap iterator for sending out disconnect messages
1513  * for a peer.
1514  *
1515  * @param cls the peer that was disconnected
1516  * @param key key value stored under
1517  * @param value the direct neighbor to send disconnect to
1518  *
1519  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1520  */
1521 static int schedule_disconnect_messages (void *cls,
1522                                     const GNUNET_HashCode * key,
1523                                     void *value)
1524 {
1525   struct DisconnectContext *disconnect_context = cls;
1526   struct DirectNeighbor *disconnected = disconnect_context->direct;
1527   struct DirectNeighbor *notify = value;
1528   struct PendingMessage *pending_message;
1529   p2p_dv_MESSAGE_Disconnect *disconnect_message;
1530
1531   if (memcmp(&notify->identity, &disconnected->identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
1532     return GNUNET_YES; /* Don't send disconnect message to peer that disconnected! */
1533
1534   pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(p2p_dv_MESSAGE_Disconnect));
1535   pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1];
1536   disconnect_message = (p2p_dv_MESSAGE_Disconnect *)pending_message->msg;
1537   disconnect_message->header.size = htons (sizeof (p2p_dv_MESSAGE_Disconnect));
1538   disconnect_message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
1539   disconnect_message->peer_id = htonl(disconnect_context->distant->our_id);
1540
1541   GNUNET_CONTAINER_DLL_insert_after (core_pending_head,
1542                                      core_pending_tail,
1543                                      core_pending_tail,
1544                                      pending_message);
1545
1546   if (core_transmit_handle == NULL)
1547     core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, GNUNET_TIME_relative_get_forever(), &notify->identity, sizeof(p2p_dv_MESSAGE_Disconnect), &core_transmit_notify, NULL);
1548
1549   return GNUNET_YES;
1550 }
1551
1552 /**
1553  * Multihashmap iterator for freeing extended neighbors.
1554  *
1555  * @param cls NULL
1556  * @param key key value stored under
1557  * @param value the distant neighbor to be freed
1558  *
1559  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1560  */
1561 static int free_extended_neighbors (void *cls,
1562                                     const GNUNET_HashCode * key,
1563                                     void *value)
1564 {
1565   struct DistantNeighbor *distant = value;
1566   distant_neighbor_free(distant);
1567   return GNUNET_YES;
1568 }
1569
1570 /**
1571  * Multihashmap iterator for freeing direct neighbors.
1572  *
1573  * @param cls NULL
1574  * @param key key value stored under
1575  * @param value the direct neighbor to be freed
1576  *
1577  * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
1578  */
1579 static int free_direct_neighbors (void *cls,
1580                                     const GNUNET_HashCode * key,
1581                                     void *value)
1582 {
1583   struct DirectNeighbor *direct = value;
1584   direct_neighbor_free(direct);
1585   return GNUNET_YES;
1586 }
1587
1588 /**
1589  * Task run during shutdown.
1590  *
1591  * @param cls unused
1592  * @param tc unused
1593  */
1594 static void
1595 shutdown_task (void *cls,
1596                const struct GNUNET_SCHEDULER_TaskContext *tc)
1597 {
1598 #if DEBUG_DV
1599   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "calling CORE_DISCONNECT\n");
1600 #endif
1601   GNUNET_CONTAINER_multihashmap_iterate(ctx.extended_neighbors, &free_extended_neighbors, NULL);
1602   GNUNET_CONTAINER_multihashmap_destroy(ctx.extended_neighbors);
1603   GNUNET_CONTAINER_multihashmap_iterate(ctx.direct_neighbors, &free_direct_neighbors, NULL);
1604   GNUNET_CONTAINER_multihashmap_destroy(ctx.direct_neighbors);
1605
1606   GNUNET_CONTAINER_heap_destroy(ctx.neighbor_max_heap);
1607   GNUNET_CONTAINER_heap_destroy(ctx.neighbor_min_heap);
1608
1609   GNUNET_CORE_disconnect (coreAPI);
1610   GNUNET_PEERINFO_disconnect(peerinfo_handle);
1611 #if DEBUG_DV
1612   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "CORE_DISCONNECT completed\n");
1613 #endif
1614 }
1615
1616 /**
1617  * To be called on core init/fail.
1618  */
1619 void core_init (void *cls,
1620                 struct GNUNET_CORE_Handle * server,
1621                 const struct GNUNET_PeerIdentity *identity,
1622                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey)
1623 {
1624
1625   if (server == NULL)
1626     {
1627       GNUNET_SCHEDULER_cancel(sched, cleanup_task);
1628       GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL);
1629       return;
1630     }
1631 #if DEBUG_DV
1632   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1633               "%s: Core connection initialized, I am peer: %s\n", "dv", GNUNET_i2s(identity));
1634 #endif
1635   memcpy(&my_identity, identity, sizeof(struct GNUNET_PeerIdentity));
1636   coreAPI = server;
1637 }
1638
1639 /**
1640  * Iterator over hash map entries.
1641  *
1642  * @param cls closure
1643  * @param key current key code
1644  * @param value value in the hash map
1645  * @return GNUNET_YES if we should continue to
1646  *         iterate,
1647  *         GNUNET_NO if not.
1648  */
1649 static int add_pkey_to_extended (void *cls,
1650                                  const GNUNET_HashCode * key,
1651                                  void *value)
1652 {
1653   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey = cls;
1654   struct DistantNeighbor *distant_neighbor = value;
1655
1656   if (distant_neighbor->pkey == NULL)
1657   {
1658     distant_neighbor->pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1659     memcpy(distant_neighbor->pkey, pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1660   }
1661
1662   return GNUNET_YES;
1663 }
1664
1665 /**
1666  * Iterator over hash map entries.
1667  *
1668  * @param cls closure
1669  * @param key current key code
1670  * @param value value in the hash map
1671  * @return GNUNET_YES if we should continue to
1672  *         iterate,
1673  *         GNUNET_NO if not.
1674  */
1675 static int update_matching_neighbors (void *cls,
1676                                       const GNUNET_HashCode * key,
1677                                       void *value)
1678 {
1679   struct NeighborUpdateInfo * update_info = cls;
1680   struct DistantNeighbor *distant_neighbor = value;
1681
1682   if (update_info->referrer == distant_neighbor->referrer) /* Direct neighbor matches, update it's info and return GNUNET_NO */
1683   {
1684     /* same referrer, cost change! */
1685     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_max_heap,
1686                                        update_info->neighbor->max_loc, update_info->cost);
1687     GNUNET_CONTAINER_heap_update_cost (ctx.neighbor_min_heap,
1688                                        update_info->neighbor->min_loc, update_info->cost);
1689     update_info->neighbor->last_activity = update_info->now;
1690     update_info->neighbor->cost = update_info->cost;
1691     return GNUNET_NO;
1692   }
1693
1694   return GNUNET_YES;
1695 }
1696
1697
1698 #if DEBUG_DV_GOSSIP
1699 /**
1700  * Iterator over hash map entries.
1701  *
1702  * @param cls closure (NULL)
1703  * @param key current key code
1704  * @param value value in the hash map (DistantNeighbor)
1705  * @return GNUNET_YES if we should continue to
1706  *         iterate,
1707  *         GNUNET_NO if not.
1708  */
1709 int print_neighbors (void *cls,
1710                      const GNUNET_HashCode * key,
1711                      void *value)
1712 {
1713   struct DistantNeighbor *distant_neighbor = value;
1714   char my_shortname[5];
1715   char referrer_shortname[5];
1716   memcpy(&my_shortname, GNUNET_i2s(&my_identity), 4);
1717   my_shortname[4] = '\0';
1718   memcpy(&referrer_shortname, GNUNET_i2s(&distant_neighbor->referrer->identity), 4);
1719   referrer_shortname[4] = '\0';
1720
1721   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "`%s' %s: Peer `%s', distance %d, referrer `%s'\n", &my_shortname, "DV", GNUNET_i2s(&distant_neighbor->identity), distant_neighbor->cost, &referrer_shortname);
1722   return GNUNET_YES;
1723 }
1724
1725 #endif
1726
1727 /**
1728  * Handles when a peer is either added due to being newly connected
1729  * or having been gossiped about, also called when the cost for a neighbor
1730  * needs to be updated.
1731  *
1732  * @param peer identity of the peer whose info is being added/updated
1733  * @param pkey public key of the peer whose info is being added/updated
1734  * @param referrer_peer_id id to use when sending to 'peer'
1735  * @param referrer if this is a gossiped peer, who did we hear it from?
1736  * @param cost the cost of communicating with this peer via 'referrer'
1737  */
1738 static void
1739 addUpdateNeighbor (const struct GNUNET_PeerIdentity * peer, struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey,
1740                    unsigned int referrer_peer_id,
1741                    struct DirectNeighbor *referrer, unsigned int cost)
1742 {
1743   struct DistantNeighbor *neighbor;
1744   struct DistantNeighbor *max;
1745   struct GNUNET_TIME_Absolute now;
1746   struct NeighborUpdateInfo *neighbor_update;
1747   unsigned int our_id;
1748
1749 #if DEBUG_DV_PEER_NUMBERS
1750   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1751               "%s Received sender id (%u)!\n", "DV SERVICE", referrer_peer_id);
1752 #endif
1753
1754   now = GNUNET_TIME_absolute_get ();
1755   neighbor = GNUNET_CONTAINER_multihashmap_get (ctx.extended_neighbors,
1756                                                 &peer->hashPubKey);
1757   neighbor_update = GNUNET_malloc(sizeof(struct NeighborUpdateInfo));
1758   neighbor_update->neighbor = neighbor;
1759   neighbor_update->cost = cost;
1760   neighbor_update->now = now;
1761   neighbor_update->referrer = referrer;
1762
1763
1764   our_id = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, RAND_MAX - 1) + 1;
1765 #if DEBUG_DV_PEER_NUMBERS
1766   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1767               "%s Chose NEW id (%u)!\n", "DV SERVICE", our_id);
1768 #endif
1769
1770   /* Either we do not know this peer, or we already do but via a different immediate peer */
1771   if ((neighbor == NULL) ||
1772       (GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
1773                                                   &peer->hashPubKey,
1774                                                   &update_matching_neighbors,
1775                                                   neighbor_update) != GNUNET_SYSERR))
1776     {
1777       /* new neighbor! */
1778       if (cost > ctx.fisheye_depth)
1779         {
1780           /* too costly */
1781           GNUNET_free(neighbor_update);
1782           return;
1783         }
1784       if (ctx.max_table_size <=
1785           GNUNET_CONTAINER_multihashmap_size (ctx.extended_neighbors))
1786         {
1787           /* remove most expensive entry */
1788           max = GNUNET_CONTAINER_heap_peek (ctx.neighbor_max_heap);
1789           if (cost > max->cost)
1790             {
1791               /* new entry most expensive, don't create */
1792               GNUNET_free(neighbor_update);
1793               return;
1794             }
1795           if (max->cost > 1)
1796             {
1797               /* only free if this is not a direct connection;
1798                  we could theoretically have more direct
1799                  connections than DV entries allowed total! */
1800               distant_neighbor_free (max);
1801             }
1802         }
1803
1804       neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
1805       GNUNET_CONTAINER_DLL_insert (referrer->referee_head,
1806                          referrer->referee_tail, neighbor);
1807       neighbor->max_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_max_heap,
1808                                                         neighbor, cost);
1809       neighbor->min_loc = GNUNET_CONTAINER_heap_insert (ctx.neighbor_min_heap,
1810                                                         neighbor, cost);
1811       neighbor->referrer = referrer;
1812       memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
1813       if (pkey != NULL) /* pkey will be null on direct neighbor addition */
1814       {
1815         neighbor->pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1816         memcpy (neighbor->pkey, pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1817       }
1818       else
1819         neighbor->pkey = pkey;
1820
1821       neighbor->last_activity = now;
1822       neighbor->cost = cost;
1823       neighbor->referrer_id = referrer_peer_id;
1824       neighbor->our_id = our_id;
1825       neighbor->hidden =
1826         (cost == DIRECT_NEIGHBOR_COST) ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
1827                        0) : GNUNET_NO;
1828
1829       GNUNET_CONTAINER_multihashmap_put (ctx.extended_neighbors, &peer->hashPubKey,
1830                                  neighbor,
1831                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1832     }
1833   else
1834     {
1835 #if DEBUG_DV_GOSSIP
1836       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1837                   "%s: Already know peer %s distance %d, referrer id %d!\n", "dv", GNUNET_i2s(peer), cost, referrer_peer_id);
1838 #endif
1839     }
1840 #if DEBUG_DV
1841     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1842                 "%s: Size of extended_neighbors is %d\n", "dv", GNUNET_CONTAINER_multihashmap_size(ctx.extended_neighbors));
1843 #endif
1844   GNUNET_free(neighbor_update);
1845
1846 }
1847
1848
1849 static size_t
1850 generate_hello_address (void *cls, size_t max, void *buf)
1851 {
1852   struct HelloContext *hello_context = cls;
1853   char *addr_buffer;
1854   size_t offset;
1855   size_t size;
1856   size_t ret;
1857
1858   if (hello_context->addresses_to_add == 0)
1859     return 0;
1860
1861   /* Hello "address" will be concatenation of distant peer and direct peer identities */
1862   size = 2 * sizeof(struct GNUNET_PeerIdentity);
1863   GNUNET_assert(max >= size);
1864
1865   addr_buffer = GNUNET_malloc(size);
1866   offset = 0;
1867   /* Copy the distant peer identity to buffer */
1868   memcpy(addr_buffer, &hello_context->distant_peer, sizeof(struct GNUNET_PeerIdentity));
1869   offset += sizeof(struct GNUNET_PeerIdentity);
1870   /* Copy the direct peer identity to buffer */
1871   memcpy(&addr_buffer[offset], hello_context->direct_peer, sizeof(struct GNUNET_PeerIdentity));
1872   ret = GNUNET_HELLO_add_address ("dv",
1873                                   GNUNET_TIME_relative_to_absolute
1874                                   (GNUNET_TIME_UNIT_HOURS), addr_buffer, size,
1875                                   buf, max);
1876
1877   hello_context->addresses_to_add--;
1878
1879   GNUNET_free(addr_buffer);
1880   return ret;
1881 }
1882
1883
1884 /**
1885  * Core handler for dv disconnect messages.  These will be used
1886  * by us to tell transport via the dv plugin that a peer can
1887  * no longer be contacted by us via a certain address.  We should
1888  * then propagate these messages on, given that the distance to
1889  * the peer indicates we would have gossiped about it to others.
1890  *
1891  * @param cls closure
1892  * @param peer peer which sent the message (immediate sender)
1893  * @param message the message
1894  * @param latency the latency of the connection we received the message from
1895  * @param distance the distance to the immediate peer
1896  */
1897 static int handle_dv_disconnect_message (void *cls,
1898                                          const struct GNUNET_PeerIdentity *peer,
1899                                          const struct GNUNET_MessageHeader *message,
1900                                          struct GNUNET_TIME_Relative latency,
1901                                          uint32_t distance)
1902 {
1903   struct DirectNeighbor *referrer;
1904   struct DistantNeighbor *distant;
1905   p2p_dv_MESSAGE_Disconnect *enc_message = (p2p_dv_MESSAGE_Disconnect *)message;
1906
1907   if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_Disconnect))
1908     {
1909       return GNUNET_SYSERR;     /* invalid message */
1910     }
1911
1912   referrer = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
1913                                                 &peer->hashPubKey);
1914   if (referrer == NULL)
1915     return GNUNET_OK;
1916
1917   distant = referrer->referee_head;
1918   while (distant != NULL)
1919     {
1920       if (distant->referrer_id == ntohl(enc_message->peer_id))
1921         {
1922           distant_neighbor_free(distant);
1923         }
1924     }
1925
1926   return GNUNET_OK;
1927 }
1928
1929
1930 /**
1931  * Core handler for dv gossip messages.  These will be used
1932  * by us to create a HELLO message for the newly peer containing
1933  * which direct peer we can connect through, and what the cost
1934  * is.  This HELLO will then be scheduled for validation by the
1935  * transport service so that it can be used by all others.
1936  *
1937  * @param cls closure
1938  * @param peer peer which sent the message (immediate sender)
1939  * @param message the message
1940  * @param latency the latency of the connection we received the message from
1941  * @param distance the distance to the immediate peer
1942  */
1943 static int handle_dv_gossip_message (void *cls,
1944                                      const struct GNUNET_PeerIdentity *peer,
1945                                      const struct GNUNET_MessageHeader *message,
1946                                      struct GNUNET_TIME_Relative latency,
1947                                      uint32_t distance)
1948 {
1949   struct HelloContext *hello_context;
1950   struct GNUNET_HELLO_Message *hello_msg;
1951   struct DirectNeighbor *referrer;
1952   p2p_dv_MESSAGE_NeighborInfo *enc_message = (p2p_dv_MESSAGE_NeighborInfo *)message;
1953
1954   if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_NeighborInfo))
1955     {
1956       return GNUNET_SYSERR;     /* invalid message */
1957     }
1958
1959 #if DEBUG_DV_GOSSIP_RECEIPT
1960   char * encPeerAbout;
1961   char * encPeerFrom;
1962
1963   encPeerAbout = GNUNET_strdup(GNUNET_i2s(&enc_message->neighbor));
1964   encPeerFrom = GNUNET_strdup(GNUNET_i2s(peer));
1965   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1966               "%s: Receives %s message from peer %s about peer %s id %u distance %d!\n", "dv", "DV GOSSIP", encPeerFrom, encPeerAbout, ntohl(enc_message->neighbor_id), ntohl (enc_message->cost) + 1);
1967   GNUNET_free(encPeerAbout);
1968   GNUNET_free(encPeerFrom);
1969 #endif
1970
1971   referrer = GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors,
1972                                                 &peer->hashPubKey);
1973   if (referrer == NULL)
1974     return GNUNET_OK;
1975
1976   addUpdateNeighbor (&enc_message->neighbor, &enc_message->pkey,
1977                      ntohl (enc_message->neighbor_id),
1978                      referrer, ntohl (enc_message->cost) + 1);
1979
1980   hello_context = GNUNET_malloc(sizeof(struct HelloContext));
1981   hello_context->direct_peer = peer;
1982   memcpy(&hello_context->distant_peer, &enc_message->neighbor, sizeof(struct GNUNET_PeerIdentity));
1983   hello_context->addresses_to_add = 1;
1984   hello_msg = GNUNET_HELLO_create(&enc_message->pkey, &generate_hello_address, hello_context);
1985
1986   send_to_plugin(hello_context->direct_peer, GNUNET_HELLO_get_header(hello_msg), GNUNET_HELLO_size(hello_msg), &hello_context->distant_peer, ntohl(enc_message->cost) + 1);
1987   GNUNET_free(hello_context);
1988   GNUNET_free(hello_msg);
1989   return GNUNET_OK;
1990 }
1991
1992
1993 /**
1994  * Iterate over all currently known peers, add them to the
1995  * fast gossip list for this peer so we get DV routing information
1996  * out as fast as possible!
1997  *
1998  * @param cls the direct neighbor we will gossip to
1999  * @param key the hashcode of the peer
2000  * @param value the distant neighbor we should add to the list
2001  *
2002  * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
2003  */
2004 static int add_all_extended_peers (void *cls,
2005                                    const GNUNET_HashCode * key,
2006                                    void *value)
2007 {
2008   struct NeighborSendContext *send_context = (struct NeighborSendContext *)cls;
2009   struct DistantNeighbor *distant = (struct DistantNeighbor *)value;
2010   struct FastGossipNeighborList *gossip_entry;
2011
2012   if (memcmp(&send_context->toNeighbor->identity, &distant->identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
2013     return GNUNET_YES; /* Don't gossip to a peer about itself! */
2014
2015 #if SUPPORT_HIDING
2016   if (distant->hidden == GNUNET_YES)
2017     return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
2018 #endif
2019   gossip_entry = GNUNET_malloc(sizeof(struct FastGossipNeighborList));
2020   gossip_entry->about = distant;
2021
2022   GNUNET_CONTAINER_DLL_insert_after(send_context->fast_gossip_list_head,
2023                                     send_context->fast_gossip_list_tail,
2024                                     send_context->fast_gossip_list_tail,
2025                                     gossip_entry);
2026
2027   return GNUNET_YES;
2028 }
2029
2030
2031 /**
2032  * Iterate over all current direct peers, add DISTANT newly connected
2033  * peer to the fast gossip list for that peer so we get DV routing
2034  * information out as fast as possible!
2035  *
2036  * @param cls the newly connected neighbor we will gossip about
2037  * @param key the hashcode of the peer
2038  * @param value the direct neighbor we should gossip to
2039  *
2040  * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
2041  */
2042 static int add_distant_all_direct_neighbors (void *cls,
2043                                      const GNUNET_HashCode * key,
2044                                      void *value)
2045 {
2046   struct DirectNeighbor *direct = (struct DirectNeighbor *)value;
2047   struct DistantNeighbor *distant = (struct DistantNeighbor *)cls;
2048   struct NeighborSendContext *send_context = direct->send_context;
2049   struct FastGossipNeighborList *gossip_entry;
2050
2051   if (distant == NULL)
2052     {
2053       return GNUNET_YES;
2054     }
2055
2056   if (memcmp(&direct->identity, &distant->identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
2057     {
2058       return GNUNET_YES; /* Don't gossip to a peer about itself! */
2059     }
2060
2061 #if SUPPORT_HIDING
2062   if (distant->hidden == GNUNET_YES)
2063     return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
2064 #endif
2065   gossip_entry = GNUNET_malloc(sizeof(struct FastGossipNeighborList));
2066   gossip_entry->about = distant;
2067
2068   GNUNET_CONTAINER_DLL_insert_after(send_context->fast_gossip_list_head,
2069                                     send_context->fast_gossip_list_tail,
2070                                     send_context->fast_gossip_list_tail,
2071                                     gossip_entry);
2072   if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
2073     GNUNET_SCHEDULER_cancel(sched, send_context->task);
2074
2075   send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, send_context);
2076   return GNUNET_YES;
2077 }
2078
2079
2080 /**
2081  * Iterate over all current direct peers, add newly connected peer
2082  * to the fast gossip list for that peer so we get DV routing
2083  * information out as fast as possible!
2084  *
2085  * @param cls the newly connected neighbor we will gossip about
2086  * @param key the hashcode of the peer
2087  * @param value the direct neighbor we should gossip to
2088  *
2089  * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
2090  */
2091 static int add_all_direct_neighbors (void *cls,
2092                                      const GNUNET_HashCode * key,
2093                                      void *value)
2094 {
2095   struct DirectNeighbor *direct = (struct DirectNeighbor *)value;
2096   struct DirectNeighbor *to = (struct DirectNeighbor *)cls;
2097   struct DistantNeighbor *distant;
2098   struct NeighborSendContext *send_context = direct->send_context;
2099   struct FastGossipNeighborList *gossip_entry;
2100
2101   distant = GNUNET_CONTAINER_multihashmap_get(ctx.extended_neighbors, &to->identity.hashPubKey);
2102   if (distant == NULL)
2103     {
2104       return GNUNET_YES;
2105     }
2106
2107   if (memcmp(&direct->identity, &to->identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
2108     {
2109       return GNUNET_YES; /* Don't gossip to a peer about itself! */
2110     }
2111
2112 #if SUPPORT_HIDING
2113   if (distant->hidden == GNUNET_YES)
2114     return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
2115 #endif
2116   gossip_entry = GNUNET_malloc(sizeof(struct FastGossipNeighborList));
2117   gossip_entry->about = distant;
2118
2119   GNUNET_CONTAINER_DLL_insert_after(send_context->fast_gossip_list_head,
2120                                     send_context->fast_gossip_list_tail,
2121                                     send_context->fast_gossip_list_tail,
2122                                     gossip_entry);
2123   if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
2124     GNUNET_SCHEDULER_cancel(sched, send_context->task);
2125
2126   send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, send_context);
2127   return GNUNET_YES;
2128 }
2129
2130
2131 static void
2132 process_peerinfo (void *cls,
2133                   const struct GNUNET_PeerIdentity *peer,
2134                   const struct GNUNET_HELLO_Message *hello, uint32_t trust)
2135 {
2136   struct PeerIteratorContext *peerinfo_iterator = cls;
2137   struct DirectNeighbor *neighbor = peerinfo_iterator->neighbor;
2138
2139   if ((peer == NULL))/* && (neighbor->pkey == NULL))*/
2140     {
2141       /* FIXME: Remove peer! */
2142       GNUNET_free(peerinfo_iterator);
2143       return;
2144     }
2145
2146   if (memcmp(&neighbor->identity, peer, sizeof(struct GNUNET_PeerIdentity) != 0))
2147     return;
2148
2149   if ((hello != NULL) && (GNUNET_HELLO_get_key (hello, &neighbor->pkey) == GNUNET_OK))
2150     {
2151       GNUNET_CONTAINER_multihashmap_get_multiple(ctx.extended_neighbors,
2152                                                  &peer->hashPubKey,
2153                                                  &add_pkey_to_extended,
2154                                                  &neighbor->pkey);
2155
2156       GNUNET_CONTAINER_multihashmap_iterate (ctx.extended_neighbors, &add_all_extended_peers, neighbor->send_context);
2157
2158       GNUNET_CONTAINER_multihashmap_iterate (ctx.direct_neighbors, &add_all_direct_neighbors, neighbor);
2159       neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context);
2160     }
2161 }
2162
2163
2164 /**
2165  * Method called whenever a peer connects.
2166  *
2167  * @param cls closure
2168  * @param peer peer identity this notification is about
2169  * @param latency reported latency of the connection with peer
2170  * @param distance reported distance (DV) to peer
2171  */
2172 void handle_core_connect (void *cls,
2173                           const struct GNUNET_PeerIdentity * peer,
2174                           struct GNUNET_TIME_Relative latency,
2175                           uint32_t distance)
2176 {
2177   struct DirectNeighbor *neighbor;
2178   struct DistantNeighbor *about;
2179   struct PeerIteratorContext *peerinfo_iterator;
2180 #if DEBUG_DV
2181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2182               "%s: Receives core connect message for peer %s distance %d!\n", "dv", GNUNET_i2s(peer), distance);
2183 #endif
2184
2185   if ((distance == DIRECT_NEIGHBOR_COST) && (GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL))
2186   {
2187     peerinfo_iterator = GNUNET_malloc(sizeof(struct PeerIteratorContext));
2188     neighbor = GNUNET_malloc (sizeof (struct DirectNeighbor));
2189     neighbor->send_context = GNUNET_malloc(sizeof(struct NeighborSendContext));
2190     neighbor->send_context->toNeighbor = neighbor;
2191     memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
2192
2193     GNUNET_CONTAINER_multihashmap_put (ctx.direct_neighbors,
2194                                &peer->hashPubKey,
2195                                neighbor, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
2196     addUpdateNeighbor (peer, NULL, 0, neighbor, DIRECT_NEIGHBOR_COST);
2197     peerinfo_iterator->neighbor = neighbor;
2198     peerinfo_iterator->ic = GNUNET_PEERINFO_iterate (peerinfo_handle,
2199                                                      peer,
2200                                                      0,
2201                                                      GNUNET_TIME_UNIT_FOREVER_REL,
2202                                                      &process_peerinfo,
2203                                                      peerinfo_iterator);
2204
2205     /* Only add once we get the publicKey of this guy
2206      *
2207      * neighbor->send_context->task = GNUNET_SCHEDULER_add_now(sched, &neighbor_send_task, neighbor->send_context);
2208      */
2209   }
2210   else
2211   {
2212     about = GNUNET_CONTAINER_multihashmap_get(ctx.extended_neighbors, &peer->hashPubKey);
2213     if ((GNUNET_CONTAINER_multihashmap_get(ctx.direct_neighbors, &peer->hashPubKey) == NULL) && (about != NULL))
2214       GNUNET_CONTAINER_multihashmap_iterate(ctx.direct_neighbors, &add_distant_all_direct_neighbors, about);
2215
2216 #if DEBUG_DV
2217     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2218                 "%s: Distance (%d) greater than %d or already know about peer (%s), not re-adding!\n", "dv", distance, DIRECT_NEIGHBOR_COST, GNUNET_i2s(peer));
2219 #endif
2220     return;
2221   }
2222 }
2223
2224 /**
2225  * Method called whenever a given peer disconnects.
2226  *
2227  * @param cls closure
2228  * @param peer peer identity this notification is about
2229  */
2230 void handle_core_disconnect (void *cls,
2231                              const struct GNUNET_PeerIdentity * peer)
2232 {
2233   struct DirectNeighbor *neighbor;
2234   struct DistantNeighbor *referee;
2235   struct FindDestinationContext fdc;
2236   struct DisconnectContext disconnect_context;
2237 #if DEBUG_DV
2238   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2239               "%s: Receives core peer disconnect message!\n", "dv");
2240 #endif
2241
2242   neighbor =
2243     GNUNET_CONTAINER_multihashmap_get (ctx.direct_neighbors, &peer->hashPubKey);
2244   if (neighbor == NULL)
2245     {
2246       return;
2247     }
2248   while (NULL != (referee = neighbor->referee_head))
2249     distant_neighbor_free (referee);
2250
2251   fdc.dest = NULL;
2252   fdc.tid = 0;
2253
2254   GNUNET_CONTAINER_multihashmap_iterate (ctx.extended_neighbors, &find_distant_peer, &fdc);
2255
2256   if (fdc.dest != NULL)
2257     {
2258       disconnect_context.direct = neighbor;
2259       disconnect_context.distant = fdc.dest;
2260       GNUNET_CONTAINER_multihashmap_iterate (ctx.direct_neighbors, &schedule_disconnect_messages, &disconnect_context);
2261     }
2262
2263   GNUNET_assert (neighbor->referee_tail == NULL);
2264   GNUNET_CONTAINER_multihashmap_remove (ctx.direct_neighbors,
2265                                         &peer->hashPubKey, neighbor);
2266   if ((neighbor->send_context != NULL) && (neighbor->send_context->task != GNUNET_SCHEDULER_NO_TASK))
2267     GNUNET_SCHEDULER_cancel(sched, neighbor->send_context->task);
2268   GNUNET_free (neighbor);
2269 }
2270
2271
2272 /**
2273  * Process dv requests.
2274  *
2275  * @param cls closure
2276  * @param scheduler scheduler to use
2277  * @param server the initialized server
2278  * @param c configuration to use
2279  */
2280 static void
2281 run (void *cls,
2282      struct GNUNET_SCHEDULER_Handle *scheduler,
2283      struct GNUNET_SERVER_Handle *server,
2284      const struct GNUNET_CONFIGURATION_Handle *c)
2285 {
2286   unsigned long long max_hosts;
2287   sched = scheduler;
2288   cfg = c;
2289
2290   /* FIXME: Read from config, or calculate, or something other than this! */
2291   max_hosts = DEFAULT_DIRECT_CONNECTIONS;
2292   ctx.max_table_size = DEFAULT_DV_SIZE;
2293   ctx.fisheye_depth = DEFAULT_FISHEYE_DEPTH;
2294
2295   if (GNUNET_CONFIGURATION_have_value(cfg, "dv", "max_direct_connections"))
2296     {
2297       GNUNET_CONFIGURATION_get_value_number(cfg, "dv", "max_direct_connections", &max_hosts);
2298     }
2299
2300   if (GNUNET_CONFIGURATION_have_value(cfg, "dv", "max_total_connections"))
2301     {
2302       GNUNET_CONFIGURATION_get_value_number(cfg, "dv", "max_total_connections", &ctx.max_table_size);
2303     }
2304
2305   if (GNUNET_CONFIGURATION_have_value(cfg, "dv", "fisheye_depth"))
2306     {
2307       GNUNET_CONFIGURATION_get_value_number(cfg, "dv", "fisheye_depth", &ctx.fisheye_depth);
2308     }
2309
2310   ctx.neighbor_min_heap =
2311     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2312   ctx.neighbor_max_heap =
2313     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
2314
2315   ctx.direct_neighbors = GNUNET_CONTAINER_multihashmap_create (max_hosts);
2316   ctx.extended_neighbors =
2317     GNUNET_CONTAINER_multihashmap_create (ctx.max_table_size * 3);
2318
2319   GNUNET_SERVER_add_handlers (server, plugin_handlers);
2320   coreAPI =
2321   GNUNET_CORE_connect (sched,
2322                        cfg,
2323                        GNUNET_TIME_relative_get_forever(),
2324                        NULL, /* FIXME: anything we want to pass around? */
2325                        &core_init,
2326                        &handle_core_connect,
2327                        &handle_core_disconnect,
2328                        NULL,
2329                        GNUNET_NO,
2330                        NULL,
2331                        GNUNET_NO,
2332                        core_handlers);
2333
2334   if (coreAPI == NULL)
2335     return;
2336
2337    peerinfo_handle = GNUNET_PEERINFO_connect(sched, cfg);
2338
2339    if (peerinfo_handle == NULL)
2340      {
2341        GNUNET_CORE_disconnect(coreAPI);
2342        return;
2343      }
2344
2345   /* Scheduled the task to clean up when shutdown is called */
2346   cleanup_task = GNUNET_SCHEDULER_add_delayed (sched,
2347                                 GNUNET_TIME_UNIT_FOREVER_REL,
2348                                 &shutdown_task,
2349                                 NULL);
2350 }
2351
2352
2353 /**
2354  * The main function for the dv service.
2355  *
2356  * @param argc number of arguments from the command line
2357  * @param argv command line arguments
2358  * @return 0 ok, 1 on error
2359  */
2360 int
2361 main (int argc, char *const *argv)
2362 {
2363   return (GNUNET_OK ==
2364           GNUNET_SERVICE_run (argc,
2365                               argv,
2366                               "dv",
2367                               GNUNET_SERVICE_OPTION_NONE,
2368                               &run, NULL)) ? 0 : 1;
2369 }