- "%s: Called with reason shutdown, shutting down!\n",
- GNUNET_i2s (&my_identity));
-#endif
- return;
- }
-
- if (send_context->fast_gossip_list_head != NULL)
- {
- about_list = send_context->fast_gossip_list_head;
- about = about_list->about;
- GNUNET_CONTAINER_DLL_remove (send_context->fast_gossip_list_head,
- send_context->fast_gossip_list_tail,
- about_list);
- GNUNET_free (about_list);
- }
- else
- {
- /* FIXME: this may become a problem, because the heap walk has only one internal "walker". This means
- * that if two neighbor_send_tasks are operating in lockstep (which is quite possible, given default
- * values for all connected peers) there may be a serious bias as to which peers get gossiped about!
- * Probably the *best* way to fix would be to have an opaque pointer to the walk position passed as
- * part of the walk_get_next call. Then the heap would have to keep a list of walks, or reset the walk
- * whenever a modification has been detected. Yuck either way. Perhaps we could iterate over the heap
- * once to get a list of peers to gossip about and gossip them over time... But then if one goes away
- * in the mean time that becomes nasty. For now we'll just assume that the walking is done
- * asynchronously enough to avoid major problems (-;
- *
- * NOTE: probably fixed once we decided send rate based on allowed bandwidth.
- */
- about = GNUNET_CONTAINER_heap_walk_get_next (neighbor_min_heap);
- }
- to = send_context->toNeighbor;
-
- if ((about != NULL) && (to != about->referrer /* split horizon */ ) &&
-#if SUPPORT_HIDING
- (about->hidden == GNUNET_NO) &&
-#endif
- (to != NULL) &&
- (0 !=
- memcmp (&about->identity, &to->identity,
- sizeof (struct GNUNET_PeerIdentity))) && (about->pkey != NULL))
- {
-#if DEBUG_DV_GOSSIP_SEND
- encPeerAbout = GNUNET_strdup (GNUNET_i2s (&about->identity));
- encPeerTo = GNUNET_strdup (GNUNET_i2s (&to->identity));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: Sending info about peer %s id %u to directly connected peer %s\n",
- GNUNET_i2s (&my_identity), encPeerAbout, about->our_id,
- encPeerTo);
- GNUNET_free (encPeerAbout);
- GNUNET_free (encPeerTo);
-#endif
- about->last_gossip = GNUNET_TIME_absolute_get ();
- pending_message =
- GNUNET_malloc (sizeof (struct PendingMessage) +
- sizeof (p2p_dv_MESSAGE_NeighborInfo));
- 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, &to->identity,
- sizeof (struct GNUNET_PeerIdentity));
- pending_message->msg_size = sizeof (p2p_dv_MESSAGE_NeighborInfo);
- message = (p2p_dv_MESSAGE_NeighborInfo *) pending_message->msg;
- message->header.size = htons (sizeof (p2p_dv_MESSAGE_NeighborInfo));
- message->header.type = htons (GNUNET_MESSAGE_TYPE_DV_GOSSIP);
- message->cost = htonl (about->cost);
- message->neighbor_id = htonl (about->our_id);
-
- memcpy (&message->pkey, about->pkey,
- sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- memcpy (&message->neighbor, &about->identity,
- sizeof (struct GNUNET_PeerIdentity));
-
- GNUNET_CONTAINER_DLL_insert_after (core_pending_head, core_pending_tail,
- core_pending_tail, pending_message);
-
- GNUNET_SCHEDULER_add_now (try_core_send, NULL);
- /*if (core_transmit_handle == NULL)
- * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, default_dv_priority, GNUNET_TIME_relative_get_forever(), &to->identity, sizeof(p2p_dv_MESSAGE_NeighborInfo), &core_transmit_notify, NULL); */
-
- }
-
- if (send_context->fast_gossip_list_head != NULL) /* If there are other peers in the fast list, schedule right away */
- {
-#if DEBUG_DV_PEER_NUMBERS
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "DV SERVICE: still in fast send mode\n");
-#endif
- send_context->task =
- GNUNET_SCHEDULER_add_now (&neighbor_send_task, send_context);
- }
- else
- {
-#if DEBUG_DV_PEER_NUMBERS
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "DV SERVICE: entering slow send mode\n");
-#endif
- send_context->task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_DV_DEFAULT_SEND_INTERVAL,
- &neighbor_send_task, send_context);
- }
-
- return;
-}
-
-
-/**
- * Handle START-message. This is the first message sent to us
- * by the client (can only be one!).
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_start (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
-
-#if DEBUG_DV
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' request from client\n",
- "START");
-#endif
-
- client_handle = client;
-
- GNUNET_SERVER_client_keep (client_handle);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-#if UNSIMPLER
-/**
- * Iterate over hash map entries for a distant neighbor,
- * if direct neighbor matches context call send message
- *
- * @param cls closure, a DV_SendContext
- * @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.
- */
-int
-send_iterator (void *cls, const GNUNET_HashCode * key, void *abs_value)
-{
- struct DV_SendContext *send_context = cls;
- struct DistantNeighbor *distant_neighbor = abs_value;
-
- if (memcmp (distant_neighbor->referrer, send_context->direct_peer, sizeof (struct GNUNET_PeerIdentity)) == 0) /* They match, send and free */
- {
- send_message_via (&my_identity, distant_neighbor, send_context);
- return GNUNET_NO;
- }
- return GNUNET_YES;
-}
-#endif
-
-/**
- * Service server's handler for message send requests (which come
- * bubbling up to us through the DV plugin).
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-void
-handle_dv_send_message (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_DV_SendMessage *send_msg;
- struct GNUNET_DV_SendResultMessage *send_result_msg;
- struct PendingMessage *pending_message;
- size_t address_len;
- size_t message_size;
- struct GNUNET_PeerIdentity *destination;
- struct GNUNET_PeerIdentity *direct;
- struct GNUNET_MessageHeader *message_buf;
- char *temp_pos;
- int offset;
- static struct GNUNET_CRYPTO_HashAsciiEncoded dest_hash;
- struct DV_SendContext *send_context;
-
-#if DEBUG_DV_MESSAGES
- char *cbuf;
- struct GNUNET_MessageHeader *packed_message;
-#endif
-
- if (client_handle == NULL)
- {
- client_handle = client;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: Setting initial client handle, never received `%s' message?\n",
- "dv", "START");
- }
- else if (client_handle != client)
- {
- client_handle = client;
- /* What should we do in this case, assert fail or just log the warning? */
-#if DEBUG_DV
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: Setting client handle (was a different client!)!\n", "dv");
-#endif
- }
-
- GNUNET_assert (ntohs (message->size) > sizeof (struct GNUNET_DV_SendMessage));
- send_msg = (struct GNUNET_DV_SendMessage *) message;
-
- address_len = ntohl (send_msg->addrlen);
- GNUNET_assert (address_len == sizeof (struct GNUNET_PeerIdentity) * 2);
- message_size =
- ntohs (message->size) - sizeof (struct GNUNET_DV_SendMessage) -
- address_len;
- destination = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
- direct = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
- message_buf = GNUNET_malloc (message_size);
-
- temp_pos = (char *) &send_msg[1]; /* Set pointer to end of message */
- offset = 0; /* Offset starts at zero */
-
- memcpy (destination, &temp_pos[offset], sizeof (struct GNUNET_PeerIdentity));
- offset += sizeof (struct GNUNET_PeerIdentity);
-
- memcpy (direct, &temp_pos[offset], sizeof (struct GNUNET_PeerIdentity));
- offset += sizeof (struct GNUNET_PeerIdentity);
-
-
- memcpy (message_buf, &temp_pos[offset], message_size);
- if (memcmp
- (&send_msg->target, destination,
- sizeof (struct GNUNET_PeerIdentity)) != 0)
- {
- GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */
- dest_hash.encoding[4] = '\0';
- 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);
- }
-
-#if DEBUG_DV_MESSAGES
- cbuf = (char *) message_buf;
- offset = 0;
- while (offset < message_size)
- {
- packed_message = (struct GNUNET_MessageHeader *) &cbuf[offset];
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: DV PLUGIN SEND uid %u type %d to %s\n", my_short_id,
- ntohl (send_msg->uid), ntohs (packed_message->type),
- GNUNET_i2s (destination));
- offset += ntohs (packed_message->size);
- }
- /*GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: DV PLUGIN SEND uid %u type %d to %s\n", my_short_id, ntohl(send_msg->uid), ntohs(message_buf->type), GNUNET_i2s(destination)); */
-#endif
- GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */
- dest_hash.encoding[4] = '\0';
- send_context = GNUNET_malloc (sizeof (struct DV_SendContext));
-
- send_result_msg = GNUNET_malloc (sizeof (struct GNUNET_DV_SendResultMessage));
- send_result_msg->header.size =
- htons (sizeof (struct GNUNET_DV_SendResultMessage));
- send_result_msg->header.type =
- htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND_RESULT);
- send_result_msg->uid = send_msg->uid; /* No need to ntohl->htonl this */
-
- send_context->importance = ntohl (send_msg->priority);
- send_context->timeout = send_msg->timeout;
- send_context->direct_peer = direct;
- send_context->distant_peer = destination;
- send_context->message = message_buf;
- send_context->message_size = message_size;
- send_context->send_result = send_result_msg;
-#if DEBUG_DV_MESSAGES
- send_context->uid = send_msg->uid;
-#endif
-
- if (send_message_via (&my_identity, direct, send_context) != GNUNET_YES)
- {
- send_result_msg->result = htons (1);
- pending_message =
- GNUNET_malloc (sizeof (struct PendingMessage) +
- sizeof (struct GNUNET_DV_SendResultMessage));
- pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1];
- memcpy (&pending_message[1], send_result_msg,
- sizeof (struct GNUNET_DV_SendResultMessage));
- GNUNET_free (send_result_msg);
-
- GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail,
- plugin_pending_tail, pending_message);
-
- if (client_handle != NULL)
- {
- if (plugin_transmit_handle == NULL)
- {
- plugin_transmit_handle =
- GNUNET_SERVER_notify_transmit_ready (client_handle,
- sizeof (struct
- GNUNET_DV_SendResultMessage),
- GNUNET_TIME_UNIT_FOREVER_REL,
- &transmit_to_plugin, NULL);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to queue message for plugin, must be one in progress already!!\n");
- }
- }
- GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */
- dest_hash.encoding[4] = '\0';
- 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));
- }
-
- /* In bizarro world GNUNET_SYSERR indicates that we succeeded */
-#if UNSIMPLER
- if (GNUNET_SYSERR !=
- GNUNET_CONTAINER_multihashmap_get_multiple (extended_neighbors,
- &destination->hashPubKey,
- &send_iterator, send_context))
- {
- send_result_msg->result = htons (1);
- pending_message =
- GNUNET_malloc (sizeof (struct PendingMessage) +
- sizeof (struct GNUNET_DV_SendResultMessage));
- pending_message->msg = (struct GNUNET_MessageHeader *) &pending_message[1];
- memcpy (&pending_message[1], send_result_msg,
- sizeof (struct GNUNET_DV_SendResultMessage));
- GNUNET_free (send_result_msg);
-
- GNUNET_CONTAINER_DLL_insert_after (plugin_pending_head, plugin_pending_tail,
- plugin_pending_tail, pending_message);
-
- if (client_handle != NULL)
- {
- if (plugin_transmit_handle == NULL)
- {
- plugin_transmit_handle =
- GNUNET_SERVER_notify_transmit_ready (client_handle,
- sizeof (struct
- GNUNET_DV_SendResultMessage),
- GNUNET_TIME_UNIT_FOREVER_REL,
- &transmit_to_plugin, NULL);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Failed to queue message for plugin, must be one in progress already!!\n");
- }
- }
- GNUNET_CRYPTO_hash_to_enc (&destination->hashPubKey, &dest_hash); /* GNUNET_i2s won't properly work, need to hash one ourselves */
- dest_hash.encoding[4] = '\0';
- 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));
- }
-#endif
- GNUNET_free (message_buf);
- GNUNET_free (send_context);
- GNUNET_free (direct);
- GNUNET_free (destination);
-
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-/** Forward declarations **/
-static int
-handle_dv_gossip_message (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message,
- const struct GNUNET_ATS_Information *atsi,
- unsigned int atsi_count);
-
-static int
-handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message,
- const struct GNUNET_ATS_Information *atsi,
- unsigned int atsi_count);
-/** End forward declarations **/
-
-
-/**
- * List of handlers for the messages understood by this
- * service.
- *
- * Hmm... will we need to register some handlers with core and
- * some handlers with our server here? Because core should be
- * getting the incoming DV messages (from whichever lower level
- * transport) and then our server should be getting messages
- * from the dv_plugin, right?
- */
-static struct GNUNET_CORE_MessageHandler core_handlers[] = {
- {&handle_dv_data_message, GNUNET_MESSAGE_TYPE_DV_DATA, 0},
- {&handle_dv_gossip_message, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0},
- {&handle_dv_disconnect_message, GNUNET_MESSAGE_TYPE_DV_DISCONNECT, 0},
- {NULL, 0, 0}
-};
-
-static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
- {&handle_dv_send_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0},
- {&handle_start, NULL, GNUNET_MESSAGE_TYPE_DV_START, 0},
- {NULL, NULL, 0, 0}
-};
-
-/**
- * Free a DistantNeighbor node, including removing it
- * from the referer's list.
- */
-static void
-distant_neighbor_free (struct DistantNeighbor *referee)
-{
- struct DirectNeighbor *referrer;
-
- referrer = referee->referrer;
- if (referrer != NULL)
- {
- GNUNET_CONTAINER_DLL_remove (referrer->referee_head, referrer->referee_tail,
- referee);
- }
- GNUNET_CONTAINER_heap_remove_node (referee->max_loc);
- GNUNET_CONTAINER_heap_remove_node (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 (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);
-
- GNUNET_SCHEDULER_add_now (try_core_send, NULL);
- /*if (core_transmit_handle == NULL)
- * core_transmit_handle = GNUNET_CORE_notify_transmit_ready(coreAPI, GNUNET_YES, 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);
- coreAPI = NULL;
- 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)
-{
-
- if (server == NULL)
- {
- GNUNET_SCHEDULER_cancel (cleanup_task);
- GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
- return;
- }
-#if DEBUG_DV
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: Core connection initialized, I am peer: %s\n", "dv",
- GNUNET_i2s (identity));
-#endif
- memcpy (&my_identity, identity, sizeof (struct GNUNET_PeerIdentity));
- my_short_id = GNUNET_strdup (GNUNET_i2s (&my_identity));
- coreAPI = server;
-}
-
-
-#if PKEY_NO_NEIGHBOR_ON_ADD
-/**
- * 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
-add_pkey_to_extended (void *cls, const GNUNET_HashCode * key, void *abs_value)
-{
- struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey = cls;
- struct DistantNeighbor *distant_neighbor = abs_value;
-
- if (distant_neighbor->pkey == NULL)
- {
- distant_neighbor->pkey =
- GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- memcpy (distant_neighbor->pkey, pkey,
- sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- }
-
- return GNUNET_YES;
-}
-#endif
-
-/**
- * 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
-update_matching_neighbors (void *cls, const GNUNET_HashCode * key, void *value)
-{
- struct NeighborUpdateInfo *update_info = cls;
- struct DistantNeighbor *distant_neighbor = value;
-
- if (update_info->referrer == distant_neighbor->referrer) /* Direct neighbor matches, update it's info and return GNUNET_NO */
- {
- /* same referrer, cost change! */
- GNUNET_CONTAINER_heap_update_cost (neighbor_max_heap,
- update_info->neighbor->max_loc,
- update_info->cost);
- GNUNET_CONTAINER_heap_update_cost (neighbor_min_heap,
- update_info->neighbor->min_loc,
- update_info->cost);
- update_info->neighbor->last_activity = update_info->now;
- update_info->neighbor->cost = update_info->cost;
- update_info->neighbor->referrer_id = update_info->referrer_peer_id;
- return GNUNET_NO;
- }
-
- return GNUNET_YES;
-}
-
-
-/**
- * Iterate over all current direct peers, add DISTANT 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_distant_all_direct_neighbors (void *cls, const GNUNET_HashCode * key,
- void *value)
-{
- struct DirectNeighbor *direct = (struct DirectNeighbor *) value;
- struct DistantNeighbor *distant = (struct DistantNeighbor *) cls;
- struct NeighborSendContext *send_context = direct->send_context;
- struct FastGossipNeighborList *gossip_entry;
-
-#if DEBUG_DV
- char *encPeerAbout;
- char *encPeerTo;
-#endif
-
- if (distant == NULL)
- {
- return GNUNET_YES;
- }
-
- if (memcmp
- (&direct->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);
-#if DEBUG_DV
- encPeerAbout = GNUNET_strdup (GNUNET_i2s (&distant->identity));
- encPeerTo = GNUNET_strdup (GNUNET_i2s (&direct->identity));
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: Fast send info about peer %s id %u for directly connected peer %s\n",
- GNUNET_i2s (&my_identity), encPeerAbout, distant->our_id,
- encPeerTo);
- GNUNET_free (encPeerAbout);
- GNUNET_free (encPeerTo);
-#endif
- /*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);
- return GNUNET_YES;
-}
-
-/**
- * Callback for hello address creation.
- *
- * @param cls closure, a struct HelloContext
- * @param max maximum number of bytes that can be written to buf
- * @param buf where to write the address information
- *
- * @return number of bytes written, 0 to signal the
- * end of the iteration.
- */
-static size_t
-generate_hello_address (void *cls, size_t max, void *buf)
-{
- struct HelloContext *hello_context = cls;
- struct GNUNET_HELLO_Address hello_address;
- char *addr_buffer;
- size_t offset;
- size_t size;
- size_t ret;
-
- if (hello_context->addresses_to_add == 0)
- return 0;
-
- /* Hello "address" will be concatenation of distant peer and direct peer identities */
- size = 2 * sizeof (struct GNUNET_PeerIdentity);
- GNUNET_assert (max >= size);
-
- addr_buffer = GNUNET_malloc (size);
- offset = 0;
- /* Copy the distant peer identity to buffer */
- memcpy (addr_buffer, &hello_context->distant_peer,
- sizeof (struct GNUNET_PeerIdentity));
- offset += sizeof (struct GNUNET_PeerIdentity);
- /* Copy the direct peer identity to buffer */
- memcpy (&addr_buffer[offset], hello_context->direct_peer,
- sizeof (struct GNUNET_PeerIdentity));
- memset (&hello_address.peer, 0, sizeof (struct GNUNET_PeerIdentity));
- hello_address.address = addr_buffer;
- hello_address.transport_name = "dv";
- hello_address.address_length = size;
- ret =
- GNUNET_HELLO_add_address (&hello_address,
- GNUNET_TIME_relative_to_absolute
- (GNUNET_TIME_UNIT_HOURS), buf, max);
-
- hello_context->addresses_to_add--;
-
- GNUNET_free (addr_buffer);
- return ret;
-}
-
-
-/**
- * Handles when a peer is either added due to being newly connected
- * or having been gossiped about, also called when the cost for a neighbor
- * needs to be updated.
- *
- * @param peer identity of the peer whose info is being added/updated
- * @param pkey public key of the peer whose info is being added/updated
- * @param referrer_peer_id id to use when sending to 'peer'
- * @param referrer if this is a gossiped peer, who did we hear it from?
- * @param cost the cost of communicating with this peer via 'referrer'
- *
- * @return the added neighbor, the updated neighbor or NULL (neighbor
- * not added)
- */
-static struct DistantNeighbor *
-addUpdateNeighbor (const struct GNUNET_PeerIdentity *peer,
- struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey,
- unsigned int referrer_peer_id,
- struct DirectNeighbor *referrer, unsigned int cost)
-{
- struct DistantNeighbor *neighbor;
- struct DistantNeighbor *max;
- struct GNUNET_TIME_Absolute now;
- struct NeighborUpdateInfo *neighbor_update;
- struct HelloContext *hello_context;
- struct GNUNET_HELLO_Message *hello_msg;
- unsigned int our_id;
- char *addr1;
- char *addr2;
- int i;
-
-#if DEBUG_DV_PEER_NUMBERS
- char *encAbout;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s Received sender id (%u)!\n",
- "DV SERVICE", referrer_peer_id);
-#endif
-
- now = GNUNET_TIME_absolute_get ();
- neighbor =
- GNUNET_CONTAINER_multihashmap_get (extended_neighbors, &peer->hashPubKey);
- neighbor_update = GNUNET_malloc (sizeof (struct NeighborUpdateInfo));
- neighbor_update->neighbor = neighbor;
- neighbor_update->cost = cost;
- neighbor_update->now = now;
- neighbor_update->referrer = referrer;
- neighbor_update->referrer_peer_id = referrer_peer_id;
-
- if (neighbor != NULL)
- {
-#if USE_PEER_ID
- memcpy (&our_id, &neighbor->identity, sizeof (unsigned int));
-#else
- our_id = neighbor->our_id;
-#endif
- }
- else
- {
-#if USE_PEER_ID
- memcpy (&our_id, peer, sizeof (unsigned int));
-#else
- our_id =
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
- RAND_MAX - 1) + 1;
-#endif
- }
-
- /* Either we do not know this peer, or we already do but via a different immediate peer */
- if ((neighbor == NULL) ||
- (GNUNET_CONTAINER_multihashmap_get_multiple
- (extended_neighbors, &peer->hashPubKey, &update_matching_neighbors,
- neighbor_update) != GNUNET_SYSERR))
- {
-#if AT_MOST_ONE
- if ((neighbor != NULL) && (cost < neighbor->cost)) /* New cost is less than old, remove old */
- {
- distant_neighbor_free (neighbor);
- }
- else if (neighbor != NULL) /* Only allow one DV connection to each peer */
- {
- return NULL;
- }
-#endif
- /* new neighbor! */
- if (cost > fisheye_depth)
- {
- /* too costly */
- GNUNET_free (neighbor_update);
- return NULL;
- }
-
-#if DEBUG_DV_PEER_NUMBERS
- encAbout = GNUNET_strdup (GNUNET_i2s (peer));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: %s Chose NEW id (%u) for peer %s!\n",
- GNUNET_i2s (&my_identity), "DV SERVICE", our_id, encAbout);
- GNUNET_free (encAbout);
-#endif
-
- if (max_table_size <=
- GNUNET_CONTAINER_multihashmap_size (extended_neighbors))
- {
- /* remove most expensive entry */
- max = GNUNET_CONTAINER_heap_peek (neighbor_max_heap);
- GNUNET_assert (max != NULL);
- if (cost > max->cost)
- {
- /* new entry most expensive, don't create */
- GNUNET_free (neighbor_update);
- return NULL;
- }
- if (max->cost > 1)
- {
- /* only free if this is not a direct connection;
- * we could theoretically have more direct
- * connections than DV entries allowed total! */
- distant_neighbor_free (max);
- }
- }
-
- neighbor = GNUNET_malloc (sizeof (struct DistantNeighbor));
- GNUNET_CONTAINER_DLL_insert (referrer->referee_head, referrer->referee_tail,
- neighbor);
- neighbor->max_loc =
- GNUNET_CONTAINER_heap_insert (neighbor_max_heap, neighbor, cost);
- neighbor->min_loc =
- GNUNET_CONTAINER_heap_insert (neighbor_min_heap, neighbor, cost);
- neighbor->referrer = referrer;
- memcpy (&neighbor->identity, peer, sizeof (struct GNUNET_PeerIdentity));
- if (pkey != NULL) /* pkey will be null on direct neighbor addition */
- {
- neighbor->pkey =
- GNUNET_malloc (sizeof
- (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- memcpy (neighbor->pkey, pkey,
- sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- }
- else
- neighbor->pkey = pkey;
-
- neighbor->last_activity = now;
- neighbor->cost = cost;
- neighbor->referrer_id = referrer_peer_id;
- neighbor->our_id = our_id;
- neighbor->hidden =
- (cost ==
- DIRECT_NEIGHBOR_COST)
- ? (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 4) ==
- 0) : GNUNET_NO;
-
- GNUNET_CONTAINER_multihashmap_put (extended_neighbors, &peer->hashPubKey,
- neighbor,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- if (referrer_peer_id != 0)
- {
- for (i = 0; i < MAX_OUTSTANDING_MESSAGES; i++)
- {
- if (referrer->pending_messages[i].sender_id == referrer_peer_id) /* We have a queued message from just learned about peer! */
- {
-#if DEBUG_DV_MESSAGES
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: learned about peer %llu from which we have a previous unknown message, processing!\n",
- my_short_id, referrer_peer_id);
-#endif
- struct GNUNET_ATS_Information atsi[2];
-
- atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
- atsi[0].value = htonl (referrer->pending_messages[i].distance);
- atsi[1].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
- atsi[1].value =
- htonl ((uint32_t) referrer->pending_messages[i].
- latency.rel_value);
- handle_dv_data_message (NULL, &referrer->pending_messages[i].sender,
- referrer->pending_messages[i].message, atsi,
- 2);
- GNUNET_free (referrer->pending_messages[i].message);
- referrer->pending_messages[i].sender_id = 0;
- }
- }
- }
- if ((cost != DIRECT_NEIGHBOR_COST) && (neighbor->pkey != NULL))
- {
- /* Added neighbor, now send HELLO to transport */
- hello_context = GNUNET_malloc (sizeof (struct HelloContext));
- hello_context->direct_peer = &referrer->identity;
- memcpy (&hello_context->distant_peer, peer,
- sizeof (struct GNUNET_PeerIdentity));
- hello_context->addresses_to_add = 1;
- hello_msg =
- GNUNET_HELLO_create (pkey, &generate_hello_address, hello_context);
- GNUNET_assert (memcmp
- (hello_context->direct_peer, &hello_context->distant_peer,
- sizeof (struct GNUNET_PeerIdentity)) != 0);
- addr1 = GNUNET_strdup (GNUNET_i2s (hello_context->direct_peer));
- addr2 = GNUNET_strdup (GNUNET_i2s (&hello_context->distant_peer));
-#if DEBUG_DV
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: GIVING HELLO size %d for %s via %s to TRANSPORT\n",
- my_short_id, GNUNET_HELLO_size (hello_msg), addr2, addr1);
-#endif
- GNUNET_free (addr1);
- GNUNET_free (addr2);
- send_to_plugin (hello_context->direct_peer,
- GNUNET_HELLO_get_header (hello_msg),
- GNUNET_HELLO_size (hello_msg),
- &hello_context->distant_peer, cost);
- GNUNET_free (hello_context);
- GNUNET_free (hello_msg);
- }
-
- }
- else
- {
-#if DEBUG_DV_GOSSIP
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "%s: Already know peer %s distance %d, referrer id %d!\n", "dv",
- GNUNET_i2s (peer), cost, referrer_peer_id);
-#endif
- }
-#if DEBUG_DV
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Size of extended_neighbors is %d\n",
- "dv", GNUNET_CONTAINER_multihashmap_size (extended_neighbors));
-#endif
-
- GNUNET_free (neighbor_update);
- return neighbor;
-}
-
-
-/**
- * Core handler for dv disconnect messages. These will be used
- * by us to tell transport via the dv plugin that a peer can
- * no longer be contacted by us via a certain address. We should
- * then propagate these messages on, given that the distance to
- * the peer indicates we would have gossiped about it to others.
- *
- * @param cls closure
- * @param peer peer which sent the message (immediate sender)
- * @param message the message
- * @param atsi performance data
- * @param atsi_count number of entries in atsi
- */
-static int
-handle_dv_disconnect_message (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message,
- const struct GNUNET_ATS_Information *atsi,
- unsigned int atsi_count)
-{
- struct DirectNeighbor *referrer;
- struct DistantNeighbor *distant;
- p2p_dv_MESSAGE_Disconnect *enc_message =
- (p2p_dv_MESSAGE_Disconnect *) message;
-
- if (ntohs (message->size) < sizeof (p2p_dv_MESSAGE_Disconnect))
- {
- return GNUNET_SYSERR; /* invalid message */
- }
-
- referrer =
- GNUNET_CONTAINER_multihashmap_get (direct_neighbors, &peer->hashPubKey);
- if (referrer == NULL)