diff options
author | Christian Grothoff <christian@grothoff.org> | 2014-04-23 11:04:53 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2014-04-23 11:04:53 +0000 |
commit | a19683a4b76e10843c4e75db928bac5750c6430a (patch) | |
tree | 7aeff0c4d49b5f3750c569216e77912016fd5a81 /src | |
parent | 21bac846638fbbbe2b03672295d4f14fc3ceb839 (diff) |
fix #3348: send typemap confirmation messages, perform faster typemap retransmissions for unconfirmed typemaps, restart retransmissions on reconnect
Diffstat (limited to 'src')
-rw-r--r-- | src/core/gnunet-service-core_kx.c | 17 | ||||
-rw-r--r-- | src/core/gnunet-service-core_sessions.c | 232 | ||||
-rw-r--r-- | src/core/gnunet-service-core_sessions.h | 28 | ||||
-rw-r--r-- | src/core/gnunet-service-core_typemap.c | 67 | ||||
-rw-r--r-- | src/core/gnunet-service-core_typemap.h | 21 | ||||
-rw-r--r-- | src/include/gnunet_protocols.h | 7 |
6 files changed, 326 insertions, 46 deletions
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c index 79155a660b..8f13dd111b 100644 --- a/src/core/gnunet-service-core_kx.c +++ b/src/core/gnunet-service-core_kx.c @@ -821,13 +821,15 @@ GSC_KX_handle_ephemeral_key (struct GSC_KeyExchangeInfo *kx, (GNUNET_CORE_KX_STATE_REKEY_SENT == kx->status) ) && (end_t.abs_value_us <= kx->foreign_key_expires.abs_value_us) ) { - GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# old ephemeral keys ignored"), + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# old ephemeral keys ignored"), 1, GNUNET_NO); return; } start_t = GNUNET_TIME_absolute_ntoh (m->creation_time); - GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# ephemeral keys received"), + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# ephemeral keys received"), 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -884,11 +886,17 @@ GSC_KX_handle_ephemeral_key (struct GSC_KeyExchangeInfo *kx, break; case GNUNET_CORE_KX_STATE_KEY_SENT: /* fine, need to send our key after updating our status, see below */ + GSC_SESSIONS_reinit (&kx->peer); break; case GNUNET_CORE_KX_STATE_KEY_RECEIVED: + /* other peer already got our key, but typemap did go down */ + GSC_SESSIONS_reinit (&kx->peer); + break; case GNUNET_CORE_KX_STATE_UP: + /* other peer already got our key, typemap NOT down */ + break; case GNUNET_CORE_KX_STATE_REKEY_SENT: - /* other peer already got our key */ + /* other peer already got our key, typemap NOT down */ break; default: GNUNET_break (0); @@ -1509,6 +1517,9 @@ deliver_message (void *cls, case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: GSC_SESSIONS_set_typemap (dmc->peer, m); return GNUNET_OK; + case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP: + GSC_SESSIONS_confirm_typemap (dmc->peer, m); + return GNUNET_OK; default: GSC_CLIENTS_deliver_message (dmc->peer, m, ntohs (m->size), diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c index eb0013790a..09bb3d6c44 100644 --- a/src/core/gnunet-service-core_sessions.c +++ b/src/core/gnunet-service-core_sessions.c @@ -137,6 +137,12 @@ struct Session GNUNET_SCHEDULER_TaskIdentifier typemap_task; /** + * Retransmission delay we currently use for the typemap + * transmissions (if not confirmed). + */ + struct GNUNET_TIME_Relative typemap_delay; + + /** * Is the neighbour queue empty and thus ready for us * to transmit an encrypted message? */ @@ -151,6 +157,34 @@ struct Session }; +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message sent to confirm that a typemap was received. + */ +struct TypeMapConfirmationMessage +{ + + /** + * Header with type #GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP. + */ + struct GNUNET_MessageHeader header; + + /** + * Reserved, always zero. + */ + uint32_t reserved GNUNET_PACKED; + + /** + * Hash of the (decompressed) type map that was received. + */ + struct GNUNET_HashCode tm_hash; + +}; + +GNUNET_NETWORK_STRUCT_END + + /** * Map of peer identities to `struct Session`. */ @@ -203,10 +237,16 @@ GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) } while (NULL != (sme = session->sme_head)) { - GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); + GNUNET_CONTAINER_DLL_remove (session->sme_head, + session->sme_tail, + sme); GNUNET_free (sme); } - GNUNET_SCHEDULER_cancel (session->typemap_task); + if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task) + { + GNUNET_SCHEDULER_cancel (session->typemap_task); + session->typemap_task = GNUNET_SCHEDULER_NO_TASK; + } GSC_CLIENTS_notify_clients_about_neighbour (&session->peer, session->tmap, NULL); GNUNET_assert (GNUNET_YES == @@ -224,7 +264,7 @@ GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) /** * Transmit our current typemap message to the other peer. - * (Done periodically in case an update got lost). + * (Done periodically until the typemap is confirmed). * * @param cls the `struct Session *` * @param tc unused @@ -237,20 +277,14 @@ transmit_typemap_task (void *cls, struct GNUNET_MessageHeader *hdr; struct GNUNET_TIME_Relative delay; - if (0 == session->first_typemap) - { - delay = TYPEMAP_FREQUENCY_FIRST; - session->first_typemap = 1; - } - else - { - delay = TYPEMAP_FREQUENCY; - } + session->typemap_delay = GNUNET_TIME_STD_BACKOFF (session->typemap_delay); + delay = session->typemap_delay; /* randomize a bit to avoid spont. sync */ delay.rel_value_us += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000 * 1000); session->typemap_task = - GNUNET_SCHEDULER_add_delayed (delay, &transmit_typemap_task, session); + GNUNET_SCHEDULER_add_delayed (delay, + &transmit_typemap_task, session); GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# type map refreshes sent"), 1, GNUNET_NO); @@ -261,6 +295,24 @@ transmit_typemap_task (void *cls, /** + * Restart the typemap task for the given session. + * + * @param session session to restart typemap transmission for + */ +static void +start_typemap_task (struct Session *session) +{ + if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task) + GNUNET_SCHEDULER_cancel (session->typemap_task); + session->typemap_delay = GNUNET_TIME_UNIT_SECONDS; + session->typemap_task = + GNUNET_SCHEDULER_add_delayed (session->typemap_delay, + &transmit_typemap_task, + session); +} + + +/** * Create a session, a key exchange was just completed. * * @param peer peer that is now connected @@ -279,10 +331,9 @@ GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, session->tmap = GSC_TYPEMAP_create (); session->peer = *peer; session->kxinfo = kx; - session->typemap_task = - GNUNET_SCHEDULER_add_now (&transmit_typemap_task, session); GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (sessions, peer, + GNUNET_CONTAINER_multipeermap_put (sessions, + &session->peer, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); GNUNET_STATISTICS_set (GSC_stats, gettext_noop ("# peers connected"), @@ -290,6 +341,79 @@ GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, GNUNET_NO); GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, session->tmap); + start_typemap_task (session); +} + + +/** + * The other peer has indicated that he 'lost' the session + * (KX down), reinitialize the session on our end, in particular + * this means to restart the typemap transmission. + * + * @param peer peer that is now connected + */ +void +GSC_SESSIONS_reinit (const struct GNUNET_PeerIdentity *peer) +{ + struct Session *session; + + session = find_session (peer); + if (NULL == session) + { + /* KX/session is new for both sides; thus no need to restart what + has not yet begun */ + return; + } + start_typemap_task (session); +} + + +/** + * The other peer has confirmed receiving our type map, + * check if it is current and if so, stop retransmitting it. + * + * @param peer peer that confirmed the type map + * @param msg confirmation message we received + */ +void +GSC_SESSIONS_confirm_typemap (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *msg) +{ + const struct TypeMapConfirmationMessage *cmsg; + struct Session *session; + + session = find_session (peer); + if (NULL == session) + { + GNUNET_break (0); + return; + } + if (ntohs (msg->size) != sizeof (struct TypeMapConfirmationMessage)) + { + GNUNET_break_op (0); + return; + } + cmsg = (const struct TypeMapConfirmationMessage *) msg; + if (GNUNET_YES != + GSC_TYPEMAP_check_hash (&cmsg->tm_hash)) + { + /* our typemap has changed in the meantime, do not + accept confirmation */ + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# outdated typemap confirmations received"), + 1, GNUNET_NO); + return; + } + if (GNUNET_SCHEDULER_NO_TASK != session->typemap_task) + { + GNUNET_SCHEDULER_cancel (session->typemap_task); + session->typemap_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop + ("# valid typemap confirmations received"), + 1, GNUNET_NO); } @@ -325,7 +449,8 @@ void GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client) { /* notify new client about existing sessions */ - GNUNET_CONTAINER_multipeermap_iterate (sessions, ¬ify_client_about_session, + GNUNET_CONTAINER_multipeermap_iterate (sessions, + ¬ify_client_about_session, client); } @@ -592,11 +717,14 @@ try_transmission (struct Session *session) size_t used; used = 0; - while ((NULL != (pos = session->sme_head)) && (used + pos->size <= msize)) + while ( (NULL != (pos = session->sme_head)) && + (used + pos->size <= msize) ) { memcpy (&pbuf[used], &pos[1], pos->size); used += pos->size; - GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, pos); + GNUNET_CONTAINER_DLL_remove (session->sme_head, + session->sme_tail, + pos); GNUNET_free (pos); } /* compute average payload size */ @@ -619,7 +747,8 @@ try_transmission (struct Session *session) /** - * Send a message to the neighbour now. + * Send an updated typemap message to the neighbour now, + * and restart typemap transmissions. * * @param cls the message * @param key neighbour's identity @@ -627,38 +756,42 @@ try_transmission (struct Session *session) * @return always #GNUNET_OK */ static int -do_send_message (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) +do_restart_typemap_message (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) { const struct GNUNET_MessageHeader *hdr = cls; struct Session *session = value; - struct SessionMessageEntry *m; + struct SessionMessageEntry *sme; uint16_t size; size = ntohs (hdr->size); - m = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size); - memcpy (&m[1], hdr, size); - m->size = size; - m->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL; - GNUNET_CONTAINER_DLL_insert_tail (session->sme_head, session->sme_tail, m); + sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + size); + memcpy (&sme[1], hdr, size); + sme->size = size; + sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL; + GNUNET_CONTAINER_DLL_insert (session->sme_head, + session->sme_tail, + sme); try_transmission (session); + start_typemap_task (session); return GNUNET_OK; } /** - * Broadcast a message to all neighbours. + * Broadcast an updated typemap message to all neighbours. + * Restarts the retransmissions until the typemaps are confirmed. * * @param msg message to transmit */ void -GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg) +GSC_SESSIONS_broadcast_typemap (const struct GNUNET_MessageHeader *msg) { if (NULL == sessions) return; GNUNET_CONTAINER_multipeermap_iterate (sessions, - &do_send_message, + &do_restart_typemap_message, (void *) msg); } @@ -732,7 +865,7 @@ GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, /** - * We've received a typemap message from a peer, update ours. + * We have received a typemap message from a peer, update ours. * Notifies clients about the session. * * @param peer peer this is about @@ -744,6 +877,8 @@ GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, { struct Session *session; struct GSC_TypeMap *nmap; + struct SessionMessageEntry *sme; + struct TypeMapConfirmationMessage *tmc; nmap = GSC_TYPEMAP_get_from_message (msg); if (NULL == nmap) @@ -754,8 +889,24 @@ GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, GNUNET_break (0); return; } + sme = GNUNET_malloc (sizeof (struct SessionMessageEntry) + + sizeof (struct TypeMapConfirmationMessage)); + sme->deadline = GNUNET_TIME_absolute_get (); + sme->size = sizeof (struct TypeMapConfirmationMessage); + sme->priority = GNUNET_CORE_PRIO_CRITICAL_CONTROL; + tmc = (struct TypeMapConfirmationMessage *) &sme[1]; + tmc->header.size = htons (sizeof (struct TypeMapConfirmationMessage)); + tmc->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP); + tmc->reserved = htonl (0); + GSC_TYPEMAP_hash (nmap, + &tmc->tm_hash); + GNUNET_CONTAINER_DLL_insert (session->sme_head, + session->sme_tail, + sme); + try_transmission (session); GSC_CLIENTS_notify_clients_about_neighbour (peer, - session->tmap, nmap); + session->tmap, + nmap); GSC_TYPEMAP_destroy (session->tmap); session->tmap = nmap; } @@ -776,7 +927,9 @@ GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, struct Session *session; struct GSC_TypeMap *nmap; - if (0 == memcmp (peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) + if (0 == memcmp (peer, + &GSC_my_identity, + sizeof (struct GNUNET_PeerIdentity))) return; session = find_session (peer); GNUNET_assert (NULL != session); @@ -796,12 +949,14 @@ GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, void GSC_SESSIONS_init () { - sessions = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO); + sessions = GNUNET_CONTAINER_multipeermap_create (128, + GNUNET_YES); } /** - * Helper function for GSC_SESSIONS_handle_client_iterate_peers. + * Helper function for #GSC_SESSIONS_done() to free all + * active sessions. * * @param cls NULL * @param key identity of the connected peer @@ -828,7 +983,8 @@ GSC_SESSIONS_done () { if (NULL != sessions) { - GNUNET_CONTAINER_multipeermap_iterate (sessions, &free_session_helper, NULL); + GNUNET_CONTAINER_multipeermap_iterate (sessions, + &free_session_helper, NULL); GNUNET_CONTAINER_multipeermap_destroy (sessions); sessions = NULL; } diff --git a/src/core/gnunet-service-core_sessions.h b/src/core/gnunet-service-core_sessions.h index 81581e84df..793d7af8c3 100644 --- a/src/core/gnunet-service-core_sessions.h +++ b/src/core/gnunet-service-core_sessions.h @@ -42,6 +42,29 @@ GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, /** + * The other peer has indicated that he 'lost' the session + * (KX down), reinitialize the session on our end, in particular + * this means to restart the typemap transmission. + * + * @param peer peer that is now connected + */ +void +GSC_SESSIONS_reinit (const struct GNUNET_PeerIdentity *peer); + + +/** + * The other peer has confirmed receiving our type map, + * check if it is current and if so, stop retransmitting it. + * + * @param peer peer that confirmed the type map + * @param msg confirmation message we received + */ +void +GSC_SESSIONS_confirm_typemap (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *msg); + + +/** * End the session with the given peer (we are no longer * connected). * @@ -102,12 +125,13 @@ GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, /** - * Broadcast a message to all neighbours. + * Broadcast an updated typemap message to all neighbours. + * Restarts the retransmissions until the typemaps are confirmed. * * @param msg message to transmit */ void -GSC_SESSIONS_broadcast (const struct GNUNET_MessageHeader *msg); +GSC_SESSIONS_broadcast_typemap (const struct GNUNET_MessageHeader *msg); /** diff --git a/src/core/gnunet-service-core_typemap.c b/src/core/gnunet-service-core_typemap.c index 8d9fcbec76..13f5309fbd 100644 --- a/src/core/gnunet-service-core_typemap.c +++ b/src/core/gnunet-service-core_typemap.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2011 Christian Grothoff (and other contributing authors) + (C) 2011-2014 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -51,6 +51,63 @@ static struct GSC_TypeMap my_type_map; */ static uint8_t map_counters[UINT16_MAX + 1]; +/** + * Current hash of our (uncompressed) type map. + * Lazily computed when needed. + */ +static struct GNUNET_HashCode my_tm_hash; + +/** + * Is #my_tm_hash() current with respect to our type map? + */ +static int hash_current; + + +/** + * Our type map changed, recompute its hash. + */ +static void +rehash_typemap () +{ + hash_current = GNUNET_NO; +} + + +/** + * Hash the contents of a type map. + * + * @param tm map to hash + * @param hc where to store the hash code + */ +void +GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm, + struct GNUNET_HashCode *hc) +{ + GNUNET_CRYPTO_hash (tm, + sizeof (struct GSC_TypeMap), + hc); +} + + +/** + * Check if the given hash matches our current type map. + * + * @param hc hash code to check if it matches our type map + * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not + */ +int +GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc) +{ + if (GNUNET_NO == hash_current) + { + GSC_TYPEMAP_hash (&my_type_map, + &my_tm_hash); + hash_current = GNUNET_YES; + } + return (0 == memcmp (hc, &my_tm_hash, sizeof (struct GNUNET_HashCode))) + ? GNUNET_YES : GNUNET_NO; +} + /** * Compute a type map message for this peer. @@ -152,7 +209,7 @@ broadcast_my_type_map () GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# updates to my type map"), 1, GNUNET_NO); - GSC_SESSIONS_broadcast (hdr); + GSC_SESSIONS_broadcast_typemap (hdr); GNUNET_free (hdr); } @@ -180,7 +237,10 @@ GSC_TYPEMAP_add (const uint16_t *types, } } if (GNUNET_YES == changed) + { + rehash_typemap (); broadcast_my_type_map (); + } } @@ -207,7 +267,10 @@ GSC_TYPEMAP_remove (const uint16_t *types, } } if (GNUNET_YES == changed) + { + rehash_typemap (); broadcast_my_type_map (); + } } diff --git a/src/core/gnunet-service-core_typemap.h b/src/core/gnunet-service-core_typemap.h index 7572d39db9..1cf6972e9d 100644 --- a/src/core/gnunet-service-core_typemap.h +++ b/src/core/gnunet-service-core_typemap.h @@ -67,6 +67,27 @@ GSC_TYPEMAP_compute_type_map_message (void); /** + * Check if the given hash matches our current type map. + * + * @param hc hash code to check if it matches our type map + * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not + */ +int +GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc); + + +/** + * Hash the contents of a type map. + * + * @param tm map to hash + * @param hc where to store the hash code + */ +void +GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm, + struct GNUNET_HashCode *hc); + + +/** * Extract a type map from a * #GNUNET_MESSAGE_TYPE_CORE_COMRESSED_TYPE_MAP or * #GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP message. diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 39ce583770..9fed293041 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -378,6 +378,11 @@ extern "C" */ #define GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY 88 +/** + * Other peer confirms having received the type map + */ +#define GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP 89 + /******************************************************************************* * DATASTORE message types @@ -636,7 +641,7 @@ extern "C" #define GNUNET_MESSAGE_TYPE_DHT_P2P_GET_RESULT 162 /** - * Trail Rejection Message. + * Trail Rejection Message. */ #define GNUNET_MESSAGE_TYPE_DHT_P2P_TRAIL_REJECTION 163 /******************************************************************************* |