Index: src/chat/chat.c =================================================================== --- src/chat/chat.c (revision 14557) +++ src/chat/chat.c (working copy) @@ -149,7 +149,7 @@ * Ask client to send a join request. */ static int -GNUNET_CHAT_rejoin_room (struct GNUNET_CHAT_Room *chat_room); +rejoin_room (struct GNUNET_CHAT_Room *chat_room); /** @@ -448,7 +448,7 @@ if (NULL == msg) { GNUNET_break (0); - GNUNET_CHAT_rejoin_room (chat_room); + rejoin_room (chat_room); return; } process_result (chat_room, msg); @@ -468,8 +468,8 @@ * Returns the private key on success, NULL on error. */ static struct GNUNET_CRYPTO_RsaPrivateKey * -GNUNET_CHAT_initPrivateKey (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *nick_name) +init_private_key (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *nick_name) { char *home; char *keyfile; @@ -548,7 +548,7 @@ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit join request, retrying...\n"); #endif - GNUNET_CHAT_rejoin_room (chat_room); + rejoin_room (chat_room); return 0; } #if DEBUG_CHAT @@ -591,7 +591,7 @@ * Ask to send a join request. */ static int -GNUNET_CHAT_rejoin_room (struct GNUNET_CHAT_Room *chat_room) +rejoin_room (struct GNUNET_CHAT_Room *chat_room) { size_t size_of_join; @@ -682,7 +682,7 @@ #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining the room '%s'\n", room_name); #endif - priv_key = GNUNET_CHAT_initPrivateKey (cfg, nick_name); + priv_key = init_private_key (cfg, nick_name); if (NULL == priv_key) return NULL; GNUNET_CRYPTO_rsa_key_get_public (priv_key, &pub_key); @@ -732,7 +732,7 @@ chat_room->cfg = cfg; chat_room->client = client; chat_room->members = NULL; - if (GNUNET_SYSERR == GNUNET_CHAT_rejoin_room (chat_room)) + if (GNUNET_SYSERR == rejoin_room (chat_room)) { GNUNET_CHAT_leave_room (chat_room); return NULL; Index: src/chat/gnunet-service-chat.c =================================================================== --- src/chat/gnunet-service-chat.c (revision 14557) +++ src/chat/gnunet-service-chat.c (working copy) @@ -35,6 +35,7 @@ #define DEBUG_CHAT_SERVICE GNUNET_NO #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) +#define EXPECTED_NEIGHBOUR_COUNT 16 #define QUEUE_SIZE 16 #define MAX_ANONYMOUS_MSG_LIST_LENGTH 16 @@ -95,6 +96,19 @@ }; /** + * Information about a peer that we are connected to. + * We track data that is useful for determining which + * peers should receive our requests. + */ +struct ConnectedPeer +{ + /** + * The peer's identity. + */ + GNUNET_PEER_Id pid; +}; + +/** * Linked list of recent anonymous messages. */ struct AnonymousMessage @@ -138,6 +152,11 @@ * Head of the list of recent anonymous messages. */ static struct AnonymousMessage *anonymous_list_head = NULL; + +/** + * Map of peer identifiers to "struct ConnectedPeer" (for that peer). + */ +static struct GNUNET_CONTAINER_MultiHashMap *connected_peers; static void @@ -226,33 +245,32 @@ /** * Ask to send a message notification to the peer. */ -static void +static int send_message_noficiation (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_TRANSPORT_ATS_Information *atsi) + const GNUNET_HashCode *key, + void *value) { struct P2PReceiveNotificationMessage *msg = cls; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; struct P2PReceiveNotificationMessage *my_msg; - struct GNUNET_CORE_TransmitHandle *th; - if (NULL == peer) - GNUNET_free (msg); - else - { + GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending message notification to `%s'\n", GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message notification to `%s'\n", GNUNET_i2s (&pid)); #endif - my_msg = GNUNET_memdup (msg, ntohs (msg->header.size)); - th = GNUNET_CORE_notify_transmit_ready (core, - 1, - MAX_TRANSMIT_DELAY, - peer, - ntohs (msg->header.size), - &transmit_message_notification_to_peer, - my_msg); - GNUNET_assert (NULL != th); - } + my_msg = GNUNET_memdup (msg, ntohs (msg->header.size)); + if (NULL == GNUNET_CORE_notify_transmit_ready (core, + 1, + MAX_TRANSMIT_DELAY, + &pid, + ntohs (msg->header.size), + &transmit_message_notification_to_peer, + my_msg)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a message notification\n")); + return GNUNET_YES; } @@ -460,9 +478,10 @@ p2p_rnmsg->target = trmsg->target; if (is_anon) remember_anonymous_message (p2p_rnmsg); - GNUNET_CORE_iterate_peers (cfg, - &send_message_noficiation, - p2p_rnmsg); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_message_noficiation, + p2p_rnmsg); + GNUNET_free (p2p_rnmsg); GNUNET_SERVER_receive_done (client, GNUNET_OK); GNUNET_free (rnmsg); } @@ -515,33 +534,34 @@ /** * Ask to send a join notification to the peer. */ -static void +static int send_join_noficiation (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_TRANSPORT_ATS_Information *atsi) + const GNUNET_HashCode *key, + void *value) { struct ChatClient *entry = cls; - struct GNUNET_CORE_TransmitHandle *th; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; size_t msg_size; - if (NULL != peer) - { + GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending join notification to `%s'\n", GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending join notification to `%s'\n", GNUNET_i2s (&pid)); #endif - msg_size = sizeof (struct P2PJoinNotificationMessage) + - strlen (entry->room) + - entry->meta_len; - th = GNUNET_CORE_notify_transmit_ready (core, - 1, - MAX_TRANSMIT_DELAY, - peer, - msg_size, - &transmit_join_notification_to_peer, - entry); - GNUNET_assert (NULL != th); - } + msg_size = sizeof (struct P2PJoinNotificationMessage) + + strlen (entry->room) + + entry->meta_len; + if (NULL == GNUNET_CORE_notify_transmit_ready (core, + 1, + MAX_TRANSMIT_DELAY, + &pid, + msg_size, + &transmit_join_notification_to_peer, + entry)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a join notification\n")); + return GNUNET_YES; } @@ -662,9 +682,9 @@ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting join notification to neighbour peers\n"); #endif - GNUNET_CORE_iterate_peers (cfg, - &send_join_noficiation, - new_entry); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_join_noficiation, + new_entry); GNUNET_SERVER_receive_done (client, GNUNET_OK); GNUNET_free (jnmsg); } @@ -710,36 +730,35 @@ /** * Ask to send a confirmation receipt to the peer. */ -static void +static int send_confirmation_receipt (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_TRANSPORT_ATS_Information *atsi) + const GNUNET_HashCode *key, + void *value) { struct P2PConfirmationReceiptMessage *receipt = cls; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; struct P2PConfirmationReceiptMessage *my_receipt; - struct GNUNET_CORE_TransmitHandle *th; size_t msg_size; - if (NULL == peer) - GNUNET_free (receipt); - else - { + GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending confirmation receipt to `%s'\n", GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending confirmation receipt to `%s'\n", GNUNET_i2s (&pid)); #endif - msg_size = sizeof (struct P2PConfirmationReceiptMessage); - my_receipt = GNUNET_memdup (receipt, - sizeof (struct P2PConfirmationReceiptMessage)); - th = GNUNET_CORE_notify_transmit_ready (core, - 1, - MAX_TRANSMIT_DELAY, - peer, - msg_size, - &transmit_confirmation_receipt_to_peer, - my_receipt); - GNUNET_assert (NULL != th); - } + msg_size = sizeof (struct P2PConfirmationReceiptMessage); + my_receipt = GNUNET_memdup (receipt, + sizeof (struct P2PConfirmationReceiptMessage)); + if (NULL == GNUNET_CORE_notify_transmit_ready (core, + 1, + MAX_TRANSMIT_DELAY, + &pid, + msg_size, + &transmit_confirmation_receipt_to_peer, + my_receipt)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a confirmation receipt\n")); + return GNUNET_YES; } @@ -812,9 +831,10 @@ p2p_crmsg->author = receipt->author; p2p_crmsg->content = receipt->content; p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number); - GNUNET_CORE_iterate_peers (cfg, - &send_confirmation_receipt, - p2p_crmsg); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_confirmation_receipt, + p2p_crmsg); + GNUNET_free (p2p_crmsg); } else { @@ -896,40 +916,35 @@ /** * Ask to send a leave notification to the peer. */ -static void +static int send_leave_noficiation (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_TRANSPORT_ATS_Information *atsi) + const GNUNET_HashCode *key, + void *value) { struct ChatClient *entry = cls; + struct ConnectedPeer *cp = value; + struct GNUNET_PeerIdentity pid; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; size_t msg_size; - if (NULL == peer) - { - GNUNET_free (entry->room); - GNUNET_free_non_null (entry->member_info); - GNUNET_free (entry); - } - else - { + GNUNET_PEER_resolve (cp->pid, &pid); #if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending leave notification to `%s'\n", GNUNET_i2s (peer)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending leave notification to `%s'\n", GNUNET_i2s (&pid)); #endif - msg_size = sizeof (struct P2PLeaveNotificationMessage); - public_key = GNUNET_memdup (&entry->public_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - if (NULL == GNUNET_CORE_notify_transmit_ready (core, - 1, - MAX_TRANSMIT_DELAY, - peer, - msg_size, - &transmit_leave_notification_to_peer, - public_key)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to queue a leave notification\n")); - } + msg_size = sizeof (struct P2PLeaveNotificationMessage); + public_key = GNUNET_memdup (&entry->public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (NULL == GNUNET_CORE_notify_transmit_ready (core, + 1, + MAX_TRANSMIT_DELAY, + &pid, + msg_size, + &transmit_leave_notification_to_peer, + public_key)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to queue a leave notification\n")); + return GNUNET_YES; } @@ -994,9 +1009,12 @@ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting leave notification to neighbour peers\n"); #endif - GNUNET_CORE_iterate_peers (cfg, - &send_leave_noficiation, - pos); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_leave_noficiation, + pos); + GNUNET_free (pos->room); + GNUNET_free_non_null (pos->member_info); + GNUNET_free (pos); } @@ -1112,9 +1130,9 @@ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting join notification to neighbour peers\n"); #endif - GNUNET_CORE_iterate_peers (cfg, - &send_join_noficiation, - new_entry); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_join_noficiation, + new_entry); GNUNET_free (jnmsg); return GNUNET_OK; } @@ -1194,9 +1212,12 @@ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Broadcasting leave notification to neighbour peers\n"); #endif - GNUNET_CORE_iterate_peers (cfg, - &send_leave_noficiation, - pos); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_leave_noficiation, + pos); + GNUNET_free (pos->room); + GNUNET_free_non_null (pos->member_info); + GNUNET_free (pos); return GNUNET_OK; } @@ -1347,9 +1368,9 @@ "Broadcasting message notification to neighbour peers\n"); #endif my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size)); - GNUNET_CORE_iterate_peers (cfg, - &send_message_noficiation, - my_p2p_rnmsg); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_message_noficiation, + my_p2p_rnmsg); GNUNET_free (rnmsg); return GNUNET_OK; } @@ -1470,9 +1491,10 @@ " Broadcasting receipt to neighbour peers\n"); #endif my_p2p_crmsg = GNUNET_memdup (p2p_crmsg, sizeof (struct P2PConfirmationReceiptMessage)); - GNUNET_CORE_iterate_peers (cfg, - &send_confirmation_receipt, - my_p2p_crmsg); + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &send_confirmation_receipt, + my_p2p_crmsg); + GNUNET_free (my_p2p_crmsg); } else { @@ -1559,12 +1581,13 @@ const struct GNUNET_PeerIdentity *peer, const struct GNUNET_TRANSPORT_ATS_Information *atsi) { + struct ConnectedPeer *cp; struct GNUNET_CORE_TransmitHandle *th; + if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity))) + return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer connected: %s\n", GNUNET_i2s (peer)); - if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity))) - return; th = GNUNET_CORE_notify_transmit_ready (core, 1, MAX_TRANSMIT_DELAY, @@ -1573,10 +1596,54 @@ &transmit_sync_request_to_peer, NULL); GNUNET_assert (NULL != th); + cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, + &peer->hashPubKey); + if (NULL != cp) + { + GNUNET_break (0); + return; + } + cp = GNUNET_malloc (sizeof (struct ConnectedPeer)); + cp->pid = GNUNET_PEER_intern (peer); + GNUNET_break (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (connected_peers, + &peer->hashPubKey, + cp, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } /** + * Iterator to free peer entries. + * + * @param cls closure, unused + * @param key current key code + * @param value value in the hash map (peer entry) + * @return GNUNET_YES (we should continue to iterate) + */ +static int +clean_peer (void *cls, + const GNUNET_HashCode * key, + void *value) +{ + struct ConnectedPeer *cp; + const struct GNUNET_PeerIdentity *peer = (const struct GNUNET_PeerIdentity *) key; + + cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, + &peer->hashPubKey); + if (cp == NULL) + return GNUNET_YES; + GNUNET_break (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (connected_peers, + &peer->hashPubKey, + cp)); + GNUNET_PEER_change_rc (cp->pid, -1); + GNUNET_free (cp); + return GNUNET_YES; +} + + +/** * Method called whenever a peer disconnects. * * @param cls closure, not used @@ -1586,8 +1653,12 @@ peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) { + + if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity))) + return; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer disconnected: %s\n", GNUNET_i2s (peer)); + clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL); } @@ -1629,6 +1700,11 @@ GNUNET_free (anonymous_list_head); anonymous_list_head = next_msg; } + GNUNET_CONTAINER_multihashmap_iterate (connected_peers, + &clean_peer, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (connected_peers); + connected_peers = NULL; } @@ -1701,6 +1777,7 @@ NULL); cfg = c; nc = GNUNET_SERVER_notification_context_create (server, 16); + connected_peers = GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT); GNUNET_SERVER_add_handlers (server, handlers); core = GNUNET_CORE_connect (cfg, QUEUE_SIZE,