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