+
+/**
+ * Iterate over all currently known peers, add them to the
+ * fast gossip list for this peer so we get DV routing information
+ * out as fast as possible!
+ *
+ * @param cls the direct neighbor we will gossip to
+ * @param key the hashcode of the peer
+ * @param value the distant neighbor we should add to the list
+ *
+ * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
+ */
+static int
+add_all_extended_peers (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct NeighborSendContext *send_context = (struct NeighborSendContext *)cls;
+ struct DistantNeighbor *distant = (struct DistantNeighbor *)value;
+ struct FastGossipNeighborList *gossip_entry;
+
+ if (memcmp(&send_context->toNeighbor->identity, &distant->identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
+ return GNUNET_YES; /* Don't gossip to a peer about itself! */
+
+#if SUPPORT_HIDING
+ if (distant->hidden == GNUNET_YES)
+ return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
+#endif
+ gossip_entry = GNUNET_malloc(sizeof(struct FastGossipNeighborList));
+ gossip_entry->about = distant;
+
+ GNUNET_CONTAINER_DLL_insert_after(send_context->fast_gossip_list_head,
+ send_context->fast_gossip_list_tail,
+ send_context->fast_gossip_list_tail,
+ gossip_entry);
+
+ return GNUNET_YES;
+}
+
+#if INSANE_GOSSIP
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+gossip_all_to_all_iterator (void *cls,
+ const GNUNET_HashCode * key,
+ void *abs_value)
+{
+ struct DirectNeighbor *direct = abs_value;
+
+ GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &add_all_extended_peers, direct->send_context);
+
+ if (direct->send_context->task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(direct->send_context->task);
+
+ direct->send_context->task = GNUNET_SCHEDULER_add_now(&neighbor_send_task, direct->send_context);
+ return GNUNET_YES;
+}
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+gossip_all_to_all (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, &gossip_all_to_all_iterator, NULL);
+
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5),
+ &gossip_all_to_all,
+ NULL);
+
+}
+#endif
+/**
+ * Iterate over all current direct peers, add newly connected peer
+ * to the fast gossip list for that peer so we get DV routing
+ * information out as fast as possible!
+ *
+ * @param cls the newly connected neighbor we will gossip about
+ * @param key the hashcode of the peer
+ * @param value the direct neighbor we should gossip to
+ *
+ * @return GNUNET_YES to continue iteration, GNUNET_NO otherwise
+ */
+static int
+add_all_direct_neighbors (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct DirectNeighbor *direct = (struct DirectNeighbor *)value;
+ struct DirectNeighbor *to = (struct DirectNeighbor *)cls;
+ struct DistantNeighbor *distant;
+ struct NeighborSendContext *send_context = direct->send_context;
+ struct FastGossipNeighborList *gossip_entry;
+ char *direct_id;
+
+
+ distant = GNUNET_CONTAINER_multihashmap_get(extended_neighbors, &to->identity.hashPubKey);
+ if (distant == NULL)
+ {
+ return GNUNET_YES;
+ }
+
+ if (memcmp(&direct->identity, &to->identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
+ {
+ return GNUNET_YES; /* Don't gossip to a peer about itself! */
+ }
+
+#if SUPPORT_HIDING
+ if (distant->hidden == GNUNET_YES)
+ return GNUNET_YES; /* This peer should not be gossipped about (hidden) */
+#endif
+ direct_id = GNUNET_strdup(GNUNET_i2s(&direct->identity));
+#if DEBUG_DV_GOSSIP
+ 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);
+#endif
+ GNUNET_free(direct_id);
+ gossip_entry = GNUNET_malloc(sizeof(struct FastGossipNeighborList));
+ gossip_entry->about = distant;
+
+ GNUNET_CONTAINER_DLL_insert_after(send_context->fast_gossip_list_head,
+ send_context->fast_gossip_list_tail,
+ send_context->fast_gossip_list_tail,
+ gossip_entry);
+ if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(send_context->task);
+
+ send_context->task = GNUNET_SCHEDULER_add_now(&neighbor_send_task, send_context);
+ //tc.reason = GNUNET_SCHEDULER_REASON_TIMEOUT;
+ //neighbor_send_task(send_context, &tc);
+ return GNUNET_YES;
+}
+
+/**
+ * Type of an iterator over the hosts. Note that each
+ * host will be called with each available protocol.
+ *
+ * @param cls closure
+ * @param peer id of the peer, NULL for last call
+ * @param hello hello message for the peer (can be NULL)
+ * @param err_msg NULL if successful, otherwise contains error message
+ */
+static void
+process_peerinfo (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Message *hello,
+ const char *err_msg)
+{
+ struct PeerIteratorContext *peerinfo_iterator = cls;
+ struct DirectNeighbor *neighbor = peerinfo_iterator->neighbor;
+ struct DistantNeighbor *distant = peerinfo_iterator->distant;
+#if DEBUG_DV_PEER_NUMBERS
+ char *neighbor_pid;
+#endif
+ int sent;
+ if (err_msg != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Error in communication with PEERINFO service\n"));
+ /* return; */
+ }
+ if (peer == NULL)
+ {
+ if (distant->pkey == NULL)
+ {
+#if DEBUG_DV
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to get peerinfo information for this peer, retrying!\n");
+#endif
+ peerinfo_iterator->ic = GNUNET_PEERINFO_iterate(peerinfo_handle,
+ &peerinfo_iterator->neighbor->identity,
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3),
+ &process_peerinfo,
+ peerinfo_iterator);
+ }
+ else
+ {
+ GNUNET_free(peerinfo_iterator);
+ }
+ return;
+ }
+
+ if (memcmp(&neighbor->identity, peer, sizeof(struct GNUNET_PeerIdentity) != 0))
+ return;
+
+ if ((hello != NULL) && (GNUNET_HELLO_get_key (hello, &neighbor->pkey) == GNUNET_OK))
+ {
+ if (distant->pkey == NULL)
+ {
+ distant->pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+ memcpy(distant->pkey, &neighbor->pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+ }
+
+ sent = GNUNET_CONTAINER_multihashmap_iterate (extended_neighbors, &add_all_extended_peers, neighbor->send_context);
+ if (stats != NULL)
+ {
+ GNUNET_STATISTICS_update (stats, "# distant peers gossiped to direct neighbors", sent, GNUNET_NO);
+ }
+#if DEBUG_DV_PEER_NUMBERS
+ neighbor_pid = GNUNET_strdup(GNUNET_i2s(&neighbor->identity));
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: Gossipped %d extended peers to %s\n", GNUNET_i2s(&my_identity), sent, neighbor_pid);
+#endif
+ sent = GNUNET_CONTAINER_multihashmap_iterate (direct_neighbors, &add_all_direct_neighbors, neighbor);
+ if (stats != NULL)
+ {
+ GNUNET_STATISTICS_update (stats, "# direct peers gossiped to direct neighbors", sent, GNUNET_NO);
+ }
+#if DEBUG_DV_PEER_NUMBERS
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: Gossipped about %s to %d direct peers\n", GNUNET_i2s(&my_identity), neighbor_pid, sent);
+ GNUNET_free(neighbor_pid);
+#endif
+ neighbor->send_context->task = GNUNET_SCHEDULER_add_now(&neighbor_send_task, neighbor->send_context);
+ }
+}
+
+