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