+static struct GNUNET_CORE_Handle *coreAPI;
+
+/**
+ * Handle to the transport service, for getting our hello
+ */
+static struct GNUNET_TRANSPORT_Handle *transport_handle;
+
+/**
+ * The identity of our peer.
+ */
+static struct GNUNET_PeerIdentity my_identity;
+
+/**
+ * Short id of the peer, for printing
+ */
+static char *my_short_id;
+
+/**
+ * Our HELLO
+ */
+static struct GNUNET_MessageHeader *my_hello;
+
+/**
+ * Task to run when we shut down, cleaning up all our trash
+ */
+static GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
+
+/**
+ * The lowest currently used bucket.
+ */
+static unsigned int lowest_bucket; /* Initially equal to MAX_BUCKETS - 1 */
+
+/**
+ * The buckets (Kademlia routing table, complete with growth).
+ * Array of size MAX_BUCKET_SIZE.
+ */
+static struct PeerBucket k_buckets[MAX_BUCKETS]; /* From 0 to MAX_BUCKETS - 1 */
+
+/**
+ * Maximum size for each bucket.
+ */
+static unsigned int bucket_size = DEFAULT_BUCKET_SIZE; /* Initially equal to DEFAULT_BUCKET_SIZE */
+
+/**
+ * List of active clients.
+ */
+static struct ClientList *client_list;
+
+/**
+ * Handle to the DHT logger.
+ */
+static struct GNUNET_DHTLOG_Handle *dhtlog_handle;
+
+/*
+ * Whether or not to send routing debugging information
+ * to the dht logging server
+ */
+static unsigned int debug_routes;
+
+/*
+ * Whether or not to send FULL route information to
+ * logging server
+ */
+static unsigned int debug_routes_extended;
+
+/**
+ * Forward declaration.
+ */
+static size_t send_generic_reply (void *cls, size_t size, void *buf);
+
+/* Declare here so retry_core_send is aware of it */
+size_t core_transmit_notify (void *cls,
+ size_t size, void *buf);
+
+/**
+ * Try to send another message from our core send list
+ */
+static void
+try_core_send (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PeerInfo *peer = cls;
+ struct P2PPendingMessage *pending;
+ size_t ssize;
+
+ peer->send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ return;
+
+ if (peer->th != NULL)
+ return; /* Message send already in progress */
+
+ pending = peer->head;
+ if (pending != NULL)
+ {
+ ssize = ntohs(pending->msg->size);
+#if DEBUG_DHT > 1
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "`%s:%s': Calling notify_transmit_ready with size %d for peer %s\n", my_short_id,
+ "DHT", ssize, GNUNET_i2s(&peer->id));
+#endif
+ peer->th = GNUNET_CORE_notify_transmit_ready(coreAPI, pending->importance,
+ pending->timeout, &peer->id,
+ ssize, &core_transmit_notify, peer);
+ }
+}
+
+/**
+ * Function called to send a request out to another peer.
+ * Called both for locally initiated requests and those
+ * received from other peers.
+ *
+ * @param cls DHT service closure argument
+ * @param msg the encapsulated message
+ * @param peer the peer to forward the message to
+ * @param msg_ctx the context of the message (hop count, bloom, etc.)
+ */
+static void forward_result_message (void *cls,
+ const struct GNUNET_MessageHeader *msg,
+ struct PeerInfo *peer,
+ struct DHT_MessageContext *msg_ctx)
+{
+ struct GNUNET_DHT_P2PRouteResultMessage *result_message;
+ struct P2PPendingMessage *pending;
+ size_t msize;
+ size_t psize;
+
+ msize = sizeof (struct GNUNET_DHT_P2PRouteResultMessage) + ntohs(msg->size);
+ GNUNET_assert(msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ psize = sizeof(struct P2PPendingMessage) + msize;
+ pending = GNUNET_malloc(psize);
+ pending->msg = (struct GNUNET_MessageHeader *)&pending[1];
+ pending->importance = DHT_SEND_PRIORITY;
+ pending->timeout = GNUNET_TIME_relative_get_forever();
+ result_message = (struct GNUNET_DHT_P2PRouteResultMessage *)pending->msg;
+ result_message->header.size = htons(msize);
+ result_message->header.type = htons(GNUNET_MESSAGE_TYPE_P2P_DHT_ROUTE_RESULT);
+ result_message->options = htonl(msg_ctx->msg_options);
+ result_message->hop_count = htonl(msg_ctx->hop_count + 1);
+ GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_bloomfilter_get_raw_data(msg_ctx->bloom, result_message->bloomfilter, DHT_BLOOM_SIZE));
+ result_message->unique_id = GNUNET_htonll(msg_ctx->unique_id);
+ memcpy(&result_message->key, msg_ctx->key, sizeof(GNUNET_HashCode));
+ memcpy(&result_message[1], msg, ntohs(msg->size));
+#if DEBUG_DHT > 1
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s:%s Adding pending message size %d for peer %s\n", my_short_id, "DHT", msize, GNUNET_i2s(&peer->id));
+#endif
+ GNUNET_CONTAINER_DLL_insert_after(peer->head, peer->tail, peer->tail, pending);
+ if (peer->send_task == GNUNET_SCHEDULER_NO_TASK)
+ peer->send_task = GNUNET_SCHEDULER_add_now(sched, &try_core_send, peer);
+}
+/**
+ * Called when core is ready to send a message we asked for
+ * out to the destination.
+ *
+ * @param cls closure (NULL)
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+size_t core_transmit_notify (void *cls,
+ size_t size, void *buf)
+{
+ struct PeerInfo *peer = cls;
+ char *cbuf = buf;
+ struct P2PPendingMessage *pending;
+
+ size_t off;
+ size_t msize;
+
+ if (buf == NULL)
+ {
+ /* client disconnected */
+#if DEBUG_DHT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s:%s': buffer was NULL\n", my_short_id, "DHT");
+#endif
+ return 0;
+ }
+
+ if (peer->head == NULL)
+ return 0;
+
+ peer->th = NULL;
+ off = 0;
+ pending = peer->head;
+ msize = ntohs(pending->msg->size);
+ if (msize <= size)
+ {
+ off = msize;
+ memcpy (cbuf, pending->msg, msize);
+ GNUNET_CONTAINER_DLL_remove (peer->head,
+ peer->tail,
+ pending);
+#if DEBUG_DHT > 1
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s:%s Removing pending message size %d for peer %s\n", my_short_id, "DHT", msize, GNUNET_i2s(&peer->id));
+#endif
+ GNUNET_free (pending);
+ }
+#if SMART
+ while (NULL != pending &&
+ (size - off >= (msize = ntohs (pending->msg->size))))
+ {
+#if DEBUG_DHT_ROUTING
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "`%s:%s' : transmit_notify (core) called with size %d, available %d\n", my_short_id, "dht service", msize, size);
+#endif
+ memcpy (&cbuf[off], pending->msg, msize);
+ off += msize;
+ GNUNET_CONTAINER_DLL_remove (peer->head,
+ peer->tail,
+ pending);
+ GNUNET_free (pending);
+ pending = peer->head;
+ }
+#endif
+ if ((peer->head != NULL) && (peer->send_task == GNUNET_SCHEDULER_NO_TASK))
+ peer->send_task = GNUNET_SCHEDULER_add_now(sched, &try_core_send, peer);
+#if DEBUG_DHT > 1
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "`%s:%s' : transmit_notify (core) called with size %d, available %d, returning %d\n", my_short_id, "dht service", msize, size, off);
+#endif
+ return off;
+}
+
+/**
+ * Determine how many low order bits match in two
+ * GNUNET_HashCodes. i.e. - 010011 and 011111 share
+ * the first two lowest order bits, and therefore the
+ * return value is two (NOT XOR distance, nor how many
+ * bits match absolutely!).
+ *
+ * @param first the first hashcode
+ * @param second the hashcode to compare first to
+ *
+ * @return the number of bits that match
+ */
+static unsigned int matching_bits(const GNUNET_HashCode *first, const GNUNET_HashCode *second)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (GNUNET_HashCode) * 8; i++)
+ if (GNUNET_CRYPTO_hash_get_bit (first, i) != GNUNET_CRYPTO_hash_get_bit (second, i))
+ return i;
+ return sizeof (GNUNET_HashCode) * 8;
+}
+
+/**
+ * Compute the distance between have and target as a 32-bit value.
+ * Differences in the lower bits must count stronger than differences
+ * in the higher bits.
+ *
+ * @return 0 if have==target, otherwise a number
+ * that is larger as the distance between
+ * the two hash codes increases
+ */
+static unsigned int
+distance (const GNUNET_HashCode * target, const GNUNET_HashCode * have)
+{
+ unsigned int bucket;
+ unsigned int msb;
+ unsigned int lsb;
+ unsigned int i;
+
+ /* We have to represent the distance between two 2^9 (=512)-bit
+ numbers as a 2^5 (=32)-bit number with "0" being used for the
+ two numbers being identical; furthermore, we need to
+ guarantee that a difference in the number of matching
+ bits is always represented in the result.
+
+ We use 2^32/2^9 numerical values to distinguish between
+ hash codes that have the same LSB bit distance and
+ use the highest 2^9 bits of the result to signify the
+ number of (mis)matching LSB bits; if we have 0 matching
+ and hence 512 mismatching LSB bits we return -1 (since
+ 512 itself cannot be represented with 9 bits) */
+
+ /* first, calculate the most significant 9 bits of our
+ result, aka the number of LSBs */
+ bucket = matching_bits (target, have);
+ /* bucket is now a value between 0 and 512 */
+ if (bucket == 512)
+ return 0; /* perfect match */
+ if (bucket == 0)
+ return (unsigned int) -1; /* LSB differs; use max (if we did the bit-shifting
+ below, we'd end up with max+1 (overflow)) */
+
+ /* calculate the most significant bits of the final result */
+ msb = (512 - bucket) << (32 - 9);
+ /* calculate the 32-9 least significant bits of the final result by
+ looking at the differences in the 32-9 bits following the
+ mismatching bit at 'bucket' */
+ lsb = 0;
+ for (i = bucket + 1;
+ (i < sizeof (GNUNET_HashCode) * 8) && (i < bucket + 1 + 32 - 9); i++)
+ {
+ if (GNUNET_CRYPTO_hash_get_bit (target, i) != GNUNET_CRYPTO_hash_get_bit (have, i))
+ lsb |= (1 << (bucket + 32 - 9 - i)); /* first bit set will be 10,
+ last bit set will be 31 -- if
+ i does not reach 512 first... */
+ }
+ return msb | lsb;
+}
+
+/**
+ * Return a number that is larger the closer the
+ * "have" GNUNET_hash code is to the "target".
+ *
+ * @return inverse distance metric, non-zero.
+ * Must fudge the value if NO bits match.
+ */
+static unsigned int
+inverse_distance (const GNUNET_HashCode * target,
+ const GNUNET_HashCode * have)
+{
+ if (matching_bits(target, have) == 0)
+ return 1; /* Never return 0! */
+ return ((unsigned int) -1) - distance (target, have);
+}
+
+/**
+ * Find the optimal bucket for this key, regardless
+ * of the current number of buckets in use.
+ *
+ * @param hc the hashcode to compare our identity to
+ *
+ * @return the proper bucket index, or GNUNET_SYSERR
+ * on error (same hashcode)
+ */
+static int find_bucket(const GNUNET_HashCode *hc)
+{
+ unsigned int bits;
+
+ bits = matching_bits(&my_identity.hashPubKey, hc);
+ if (bits == MAX_BUCKETS)
+ return GNUNET_SYSERR;
+ return MAX_BUCKETS - bits - 1;
+}
+
+/**
+ * Find which k-bucket this peer should go into,
+ * taking into account the size of the k-bucket
+ * array. This means that if more bits match than
+ * there are currently buckets, lowest_bucket will
+ * be returned.
+ *
+ * @param hc GNUNET_HashCode we are finding the bucket for.
+ *
+ * @return the proper bucket index for this key,
+ * or GNUNET_SYSERR on error (same hashcode)
+ */
+static int find_current_bucket(const GNUNET_HashCode *hc)
+{
+ int actual_bucket;
+ actual_bucket = find_bucket(hc);
+
+ if (actual_bucket == GNUNET_SYSERR) /* hc and our peer identity match! */
+ return GNUNET_SYSERR;
+ else if (actual_bucket < lowest_bucket) /* actual_bucket not yet used */
+ return lowest_bucket;
+ else
+ return actual_bucket;
+}
+
+/**
+ * Find a routing table entry from a peer identity
+ *
+ * @param peer the peer identity to look up
+ *
+ * @return the routing table entry, or NULL if not found
+ */
+static struct PeerInfo *
+find_peer_by_id(const struct GNUNET_PeerIdentity *peer)
+{
+ int bucket;
+ struct PeerInfo *pos;
+ bucket = find_current_bucket(&peer->hashPubKey);
+
+ if (bucket == GNUNET_SYSERR)
+ return NULL;
+
+ pos = k_buckets[bucket].head;
+ while (pos != NULL)
+ {
+ if (0 == memcmp(&pos->id, peer, sizeof(struct GNUNET_PeerIdentity)))
+ return pos;
+ pos = pos->next;
+ }
+ return NULL; /* No such peer. */
+}
+
+/**
+ * Really add a peer to a bucket (only do assertions
+ * on size, etc.)
+ *
+ * @param peer GNUNET_PeerIdentity of the peer to add
+ * @param bucket the already figured out bucket to add
+ * the peer to
+ * @param latency the core reported latency of this peer
+ * @param distance the transport level distance to this peer
+ */
+static void add_peer(const struct GNUNET_PeerIdentity *peer,
+ unsigned int bucket,
+ struct GNUNET_TIME_Relative latency,
+ unsigned int distance)
+{
+ struct PeerInfo *new_peer;
+ GNUNET_assert(bucket < MAX_BUCKETS);
+ GNUNET_assert(peer != NULL);
+ new_peer = GNUNET_malloc(sizeof(struct PeerInfo));
+ new_peer->latency = latency;
+ new_peer->distance = distance;
+ memcpy(&new_peer->id, peer, sizeof(struct GNUNET_PeerIdentity));
+
+ GNUNET_CONTAINER_DLL_insert_after(k_buckets[bucket].head,
+ k_buckets[bucket].tail,
+ k_buckets[bucket].tail,
+ new_peer);
+ k_buckets[bucket].peers_size++;
+}
+
+/**
+ * Given a peer and its corresponding bucket,
+ * remove it from that bucket. Does not free
+ * the PeerInfo struct, nor cancel messages
+ * or free messages waiting to be sent to this
+ * peer!
+ *
+ * @param peer the peer to remove
+ * @param bucket the bucket the peer belongs to
+ */
+static void remove_peer (struct PeerInfo *peer,
+ unsigned int bucket)
+{
+ GNUNET_assert(k_buckets[bucket].peers_size > 0);
+ GNUNET_CONTAINER_DLL_remove(k_buckets[bucket].head,
+ k_buckets[bucket].tail,
+ peer);
+ k_buckets[bucket].peers_size--;
+}
+
+/**
+ * Removes peer from a bucket, then frees associated
+ * resources and frees peer.
+ *
+ * @param peer peer to be removed and freed
+ * @param bucket which bucket this peer belongs to
+ */
+static void delete_peer (struct PeerInfo *peer,
+ unsigned int bucket)
+{
+ struct P2PPendingMessage *pos;
+ struct P2PPendingMessage *next;
+ remove_peer(peer, bucket); /* First remove the peer from its bucket */
+
+ if (peer->send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(sched, peer->send_task);
+ if (peer->th != NULL)
+ GNUNET_CORE_notify_transmit_ready_cancel(peer->th);
+
+ pos = peer->head;
+ while (pos != NULL) /* Remove any pending messages for this peer */
+ {
+ next = pos->next;
+ GNUNET_free(pos);
+ pos = next;
+ }
+ GNUNET_free(peer);
+}
+
+/**
+ * The current lowest bucket is full, so change the lowest
+ * bucket to the next lower down, and move any appropriate
+ * entries in the current lowest bucket to the new bucket.
+ */
+static void enable_next_bucket()
+{
+ unsigned int new_bucket;
+ unsigned int to_remove;
+ int i;
+ struct PeerInfo *to_remove_list[bucket_size]; /* We either use CPU by making a list, or memory with array. Use memory. */
+ struct PeerInfo *pos;
+ GNUNET_assert(lowest_bucket > 0);
+
+ pos = k_buckets[lowest_bucket].head;
+ memset(to_remove_list, 0, sizeof(to_remove_list));
+ to_remove = 0;
+ /* Populate the array of peers which should be in the next lowest bucket */
+ while (pos->next != NULL)
+ {
+ if (find_bucket(&pos->id.hashPubKey) < lowest_bucket)
+ {
+ to_remove_list[to_remove] = pos;
+ to_remove++;
+ }
+ pos = pos->next;
+ }
+ new_bucket = lowest_bucket - 1;
+
+ /* Remove peers from lowest bucket, insert into next lowest bucket */
+ for (i = 0; i < bucket_size; i++)
+ {
+ if (to_remove_list[i] != NULL)
+ {
+ remove_peer(to_remove_list[i], lowest_bucket);
+ GNUNET_CONTAINER_DLL_insert_after(k_buckets[new_bucket].head,
+ k_buckets[new_bucket].tail,
+ k_buckets[new_bucket].tail,
+ to_remove_list[i]);
+ k_buckets[new_bucket].peers_size++;
+ }
+ else
+ break;
+ }
+ lowest_bucket = new_bucket;
+}
+/**
+ * Attempt to add a peer to our k-buckets.
+ *
+ * @param peer, the peer identity of the peer being added
+ *
+ * @return GNUNET_YES if the peer was added,
+ * GNUNET_NO if not,
+ * GNUNET_SYSERR on err (peer is us!)
+ */
+static int try_add_peer(const struct GNUNET_PeerIdentity *peer,
+ unsigned int bucket,
+ struct GNUNET_TIME_Relative latency,
+ unsigned int distance)
+{
+ int peer_bucket;
+
+ peer_bucket = find_current_bucket(&peer->hashPubKey);
+ if (peer_bucket == GNUNET_SYSERR)
+ return GNUNET_SYSERR;
+
+ GNUNET_assert(peer_bucket >= lowest_bucket);
+ if ((k_buckets[peer_bucket].peers_size) < bucket_size)
+ {
+ add_peer(peer, peer_bucket, latency, distance);
+ return GNUNET_YES;
+ }
+ else if ((peer_bucket == lowest_bucket) && (lowest_bucket > 0))
+ {
+ enable_next_bucket();
+ return try_add_peer(peer, bucket, latency, distance); /* Recurse, if proper bucket still full ping peers */
+ }
+ else if ((k_buckets[peer_bucket].peers_size) == bucket_size)
+ {
+ /* TODO: implement ping_oldest_peer */
+ //ping_oldest_peer(bucket, peer, latency, distance); /* Find oldest peer, ping it. If no response, remove and add new peer! */
+ return GNUNET_NO;
+ }
+ GNUNET_break(0);
+ return GNUNET_NO;
+}
+
+
+/**
+ * Task run to check for messages that need to be sent to a client.
+ *
+ * @param client a ClientList, containing the client and any messages to be sent to it
+ */
+static void
+process_pending_messages (struct ClientList *client)
+{
+ if (client->pending_head == NULL)
+ return;
+ if (client->transmit_handle != NULL)
+ return;
+ client->transmit_handle =
+ GNUNET_SERVER_notify_transmit_ready (client->client_handle,
+ ntohs (client->pending_head->msg->
+ size),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &send_generic_reply, client);
+}
+
+/**
+ * Callback called as a result of issuing a GNUNET_SERVER_notify_transmit_ready
+ * request. A ClientList is passed as closure, take the head of the list
+ * and copy it into buf, which has the result of sending the message to the
+ * client.
+ *
+ * @param cls closure to this call
+ * @param size maximum number of bytes available to send
+ * @param buf where to copy the actual message to
+ *
+ * @return the number of bytes actually copied, 0 indicates failure
+ */
+static size_t
+send_generic_reply (void *cls, size_t size, void *buf)
+{
+ struct ClientList *client = cls;
+ char *cbuf = buf;
+ struct PendingMessage *reply;
+ size_t off;
+ size_t msize;
+
+ client->transmit_handle = NULL;
+ if (buf == NULL)
+ {
+ /* client disconnected */
+ return 0;
+ }
+ off = 0;
+ while ( (NULL != (reply = client->pending_head)) &&
+ (size >= off + (msize = ntohs (reply->msg->size))))
+ {
+ GNUNET_CONTAINER_DLL_remove (client->pending_head,
+ client->pending_tail,
+ reply);
+ memcpy (&cbuf[off], reply->msg, msize);
+ GNUNET_free (reply);
+ off += msize;
+ }
+ process_pending_messages (client);
+ return off;
+}
+
+
+/**
+ * Add a PendingMessage to the clients list of messages to be sent
+ *
+ * @param client the active client to send the message to
+ * @param pending_message the actual message to send
+ */
+static void
+add_pending_message (struct ClientList *client,
+ struct PendingMessage *pending_message)
+{
+ GNUNET_CONTAINER_DLL_insert_after (client->pending_head,
+ client->pending_tail,
+ client->pending_tail,
+ pending_message);
+ process_pending_messages (client);
+}
+
+
+/**
+ * Called when a reply needs to be sent to a client, as
+ * a result it found to a GET or FIND PEER request.
+ *
+ * @param client the client to send the reply to
+ * @param message the encapsulated message to send
+ * @param uid the unique identifier of this request
+ */
+static void
+send_reply_to_client (struct ClientList *client,
+ const struct GNUNET_MessageHeader *message,