+ referrer = referee->referrer;
+ if (referrer != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove (referrer->referee_head,
+ referrer->referee_tail, referee);
+ }
+ GNUNET_CONTAINER_heap_remove_node (neighbor_max_heap, referee->max_loc);
+ GNUNET_CONTAINER_heap_remove_node (neighbor_min_heap, referee->min_loc);
+ GNUNET_CONTAINER_multihashmap_remove_all (extended_neighbors,
+ &referee->identity.hashPubKey);
+ GNUNET_free_non_null (referee->pkey);
+ GNUNET_free (referee);
+}
+
+/**
+ * Free a DirectNeighbor node, including removing it
+ * from the referer's list.
+ */
+static void
+direct_neighbor_free (struct DirectNeighbor *direct)
+{
+ struct NeighborSendContext *send_context;
+ struct FastGossipNeighborList *about_list;
+ struct FastGossipNeighborList *prev_about;
+
+ send_context = direct->send_context;
+
+ if (send_context->task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(sched, send_context->task);
+
+ about_list = send_context->fast_gossip_list_head;
+ while (about_list != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove(send_context->fast_gossip_list_head, send_context->fast_gossip_list_tail, about_list);
+ prev_about = about_list;
+ about_list = about_list->next;
+ GNUNET_free(prev_about);
+ }
+ GNUNET_free(send_context);
+ GNUNET_free(direct);
+}
+
+/**
+ * Multihashmap iterator for sending out disconnect messages
+ * for a peer.
+ *
+ * @param cls the peer that was disconnected
+ * @param key key value stored under
+ * @param value the direct neighbor to send disconnect to
+ *
+ * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
+ */
+static int schedule_disconnect_messages (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct DisconnectContext *disconnect_context = cls;
+ struct DirectNeighbor *disconnected = disconnect_context->direct;
+ struct DirectNeighbor *notify = value;
+ struct PendingMessage *pending_message;
+ p2p_dv_MESSAGE_Disconnect *disconnect_message;
+
+ if (memcmp(¬ify->identity, &disconnected->identity, sizeof(struct GNUNET_PeerIdentity)) == 0)
+ return GNUNET_YES; /* Don't send disconnect message to peer that disconnected! */
+
+ pending_message = GNUNET_malloc(sizeof(struct PendingMessage) + sizeof(p2p_dv_MESSAGE_Disconnect));
+ pending_message->msg = (struct GNUNET_MessageHeader *)&pending_message[1];
+ pending_message->importance = default_dv_priority;
+ pending_message->timeout = GNUNET_TIME_relative_get_forever();
+ memcpy(&pending_message->recipient, ¬ify->identity, sizeof(struct GNUNET_PeerIdentity));
+ pending_message->msg_size = sizeof(p2p_dv_MESSAGE_Disconnect);
+ disconnect_message = (p2p_dv_MESSAGE_Disconnect *)pending_message->msg;
+ disconnect_message->header.size = htons (sizeof (p2p_dv_MESSAGE_Disconnect));
+ disconnect_message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_DISCONNECT);
+ disconnect_message->peer_id = htonl(disconnect_context->distant->our_id);
+
+ GNUNET_CONTAINER_DLL_insert_after (core_pending_head,
+ core_pending_tail,
+ core_pending_tail,
+ pending_message);
+
+ if (core_transmit_handle == NULL)
+ core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, default_dv_priority, GNUNET_TIME_relative_get_forever(), ¬ify->identity, sizeof(p2p_dv_MESSAGE_Disconnect), &core_transmit_notify, NULL);
+
+ return GNUNET_YES;
+}
+
+/**
+ * Multihashmap iterator for freeing extended neighbors.
+ *
+ * @param cls NULL
+ * @param key key value stored under
+ * @param value the distant neighbor to be freed
+ *
+ * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
+ */
+static int free_extended_neighbors (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct DistantNeighbor *distant = value;
+ distant_neighbor_free(distant);
+ return GNUNET_YES;
+}
+
+/**
+ * Multihashmap iterator for freeing direct neighbors.
+ *
+ * @param cls NULL
+ * @param key key value stored under
+ * @param value the direct neighbor to be freed
+ *
+ * @return GNUNET_YES to continue iteration, GNUNET_NO to stop
+ */
+static int free_direct_neighbors (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct DirectNeighbor *direct = value;
+ direct_neighbor_free(direct);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+#if DEBUG_DV
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "calling CORE_DISCONNECT\n");
+ GNUNET_CONTAINER_multihashmap_iterate(extended_neighbors, &print_neighbors, NULL);
+#endif
+ GNUNET_CONTAINER_multihashmap_iterate(extended_neighbors, &free_extended_neighbors, NULL);
+ GNUNET_CONTAINER_multihashmap_destroy(extended_neighbors);
+ GNUNET_CONTAINER_multihashmap_iterate(direct_neighbors, &free_direct_neighbors, NULL);
+ GNUNET_CONTAINER_multihashmap_destroy(direct_neighbors);
+
+ GNUNET_CONTAINER_heap_destroy(neighbor_max_heap);
+ GNUNET_CONTAINER_heap_destroy(neighbor_min_heap);
+
+ GNUNET_CORE_disconnect (coreAPI);
+ GNUNET_PEERINFO_disconnect(peerinfo_handle);
+ GNUNET_SERVER_mst_destroy(coreMST);
+ GNUNET_free_non_null(my_short_id);
+#if DEBUG_DV
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "CORE_DISCONNECT completed\n");
+#endif
+}
+
+/**
+ * To be called on core init/fail.
+ */
+void core_init (void *cls,
+ struct GNUNET_CORE_Handle * server,
+ const struct GNUNET_PeerIdentity *identity,