X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fgnunet-service-transport_validation.c;h=86172fab3aca26bbdb229a99183ab0a423d8ae0f;hb=395052f780eed32332f6b7ceada109b8a800eb07;hp=ff786079f649232d0d53257c257c77a5da897400;hpb=9fac6b6eefdc9144053f736fd388cb2199a97046;p=oweals%2Fgnunet.git diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index ff786079f..86172fab3 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2010,2011 Christian Grothoff (and other contributing authors) + (C) 2010-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 @@ -24,10 +24,12 @@ * @author Christian Grothoff */ #include "platform.h" +#include "gnunet-service-transport_clients.h" #include "gnunet-service-transport_validation.h" #include "gnunet-service-transport_plugins.h" #include "gnunet-service-transport_hello.h" #include "gnunet-service-transport_blacklist.h" +#include "gnunet-service-transport_neighbours.h" #include "gnunet-service-transport.h" #include "gnunet_hello_lib.h" #include "gnunet_ats_service.h" @@ -148,13 +150,13 @@ struct TransportPongMessage /** * Signature. */ - struct GNUNET_CRYPTO_RsaSignature signature; + struct GNUNET_CRYPTO_EddsaSignature signature; /** * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a * plausible address for the signing peer. */ - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** * When does this signature expire? @@ -189,13 +191,18 @@ struct ValidationEntry /** * Public key of the peer. */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + struct GNUNET_CRYPTO_EddsaPublicKey public_key; /** * The identity of the peer. FIXME: duplicated (also in 'address') */ struct GNUNET_PeerIdentity pid; + /** + * Cached PONG signature + */ + struct GNUNET_CRYPTO_EddsaSignature pong_sig_cache; + /** * ID of task that will clean up this entry if nothing happens. */ @@ -211,12 +218,23 @@ struct ValidationEntry */ struct GNUNET_TIME_Absolute send_time; + /** + * At what time do we send the next validation request (PING)? + */ + struct GNUNET_TIME_Absolute next_validation; + /** * Until when is this address valid? * ZERO if it is not currently considered valid. */ struct GNUNET_TIME_Absolute valid_until; + /** + * Until when is the cached PONG signature valid? + * ZERO if it is not currently considered valid. + */ + struct GNUNET_TIME_Absolute pong_sig_valid_until; + /** * How long until we can try to validate this address again? * FOREVER if the address is for an unsupported plugin (from PEERINFO) @@ -231,6 +249,10 @@ struct ValidationEntry */ struct GNUNET_TIME_Relative latency; + /** + * Current state of this validation entry + */ + enum GNUNET_TRANSPORT_ValidationState state; /** * Challenge number we used. */ @@ -252,9 +274,7 @@ struct ValidationEntry */ int expecting_pong; - /* FIXME: DEBUGGING */ - int last_line_set_to_no; - int last_line_set_to_yes; + enum GNUNET_ATS_Network_Type network; }; @@ -298,13 +318,33 @@ static struct CheckHelloValidatedContext *chvc_tail; * of the given peer that we are currently validating, have validated * or are blocked from re-validation for a while). */ -static struct GNUNET_CONTAINER_MultiHashMap *validation_map; +static struct GNUNET_CONTAINER_MultiPeerMap *validation_map; /** * Context for peerinfo iteration. */ static struct GNUNET_PEERINFO_NotifyContext *pnc; +/** + * Minimum delay between to validations + */ +static struct GNUNET_TIME_Relative validation_delay; + +/** + * Number of validations running + */ +static unsigned int validations_running; + +/** + * Validition fast start threshold + */ +static unsigned int validations_fast_start_threshold; + +/** + * When is next validation allowed + */ +static struct GNUNET_TIME_Absolute validation_next; + /** * Context for the validation entry match function. @@ -327,14 +367,16 @@ struct ValidationEntryMatchContext /** * Iterate over validation entries until a matching one is found. * - * @param cls the 'struct ValidationEntryMatchContext' + * @param cls the `struct ValidationEntryMatchContext *` * @param key peer identity (unused) - * @param value a 'struct ValidationEntry' to match - * @return GNUNET_YES if the entry does not match, - * GNUNET_NO if the entry does match + * @param value a `struct ValidationEntry *` to match + * @return #GNUNET_YES if the entry does not match, + * #GNUNET_NO if the entry does match */ static int -validation_entry_match (void *cls, const GNUNET_HashCode * key, void *value) +validation_entry_match (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) { struct ValidationEntryMatchContext *vemc = cls; struct ValidationEntry *ve = value; @@ -348,27 +390,56 @@ validation_entry_match (void *cls, const GNUNET_HashCode * key, void *value) } +/** + * A validation entry changed. Update the state and notify + * monitors. + * + * @param ve validation entry that changed + * @param state new state + */ +static void +validation_entry_changed (struct ValidationEntry *ve, + enum GNUNET_TRANSPORT_ValidationState state) +{ + ve->state = state; + GST_clients_broadcast_validation_notification (&ve->pid, + ve->address, + ve->send_time, + ve->valid_until, + ve->next_validation, + state); +} + + /** * Iterate over validation entries and free them. * * @param cls (unused) * @param key peer identity (unused) - * @param value a 'struct ValidationEntry' to clean up - * @return GNUNET_YES (continue to iterate) + * @param value a `struct ValidationEntry *` to clean up + * @return #GNUNET_YES (continue to iterate) */ static int -cleanup_validation_entry (void *cls, const GNUNET_HashCode * key, void *value) +cleanup_validation_entry (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) { struct ValidationEntry *ve = value; + ve->next_validation = GNUNET_TIME_absolute_get_zero_(); + ve->valid_until = GNUNET_TIME_UNIT_ZERO_ABS; + + /* Notify about deleted entry */ + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_REMOVE); + if (NULL != ve->bc) { GST_blacklist_test_cancel (ve->bc); ve->bc = NULL; } GNUNET_break (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_remove (validation_map, - &ve->pid.hashPubKey, ve)); + GNUNET_CONTAINER_multipeermap_remove (validation_map, + &ve->pid, ve)); GNUNET_HELLO_address_free (ve->address); if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task) { @@ -380,6 +451,14 @@ cleanup_validation_entry (void *cls, const GNUNET_HashCode * key, void *value) GNUNET_SCHEDULER_cancel (ve->revalidation_task); ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK; } + if ((GNUNET_YES == ve->expecting_pong) && + (validations_running > 0)) + { + validations_running --; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Validation finished, %u validation processes running\n", + validations_running); + } GNUNET_free (ve); return GNUNET_OK; } @@ -403,7 +482,7 @@ timeout_hello_validation (void *cls, ve->timeout_task = GNUNET_SCHEDULER_NO_TASK; max = GNUNET_TIME_absolute_max (ve->valid_until, ve->revalidation_block); left = GNUNET_TIME_absolute_get_remaining (max); - if (left.rel_value > 0) + if (left.rel_value_us > 0) { /* should wait a bit longer */ ve->timeout_task = @@ -413,7 +492,7 @@ timeout_hello_validation (void *cls, GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# address records discarded"), 1, GNUNET_NO); - cleanup_validation_entry (NULL, &ve->pid.hashPubKey, ve); + cleanup_validation_entry (NULL, &ve->pid, ve); } @@ -423,24 +502,45 @@ timeout_hello_validation (void *cls, * * @param cls our 'struct ValidationEntry' * @param pid identity of the other peer - * @param result GNUNET_OK if the connection is allowed, GNUNET_NO if not + * @param result #GNUNET_OK if the connection is allowed, #GNUNET_NO if not */ static void -transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, +transmit_ping_if_allowed (void *cls, + const struct GNUNET_PeerIdentity *pid, int result) { struct ValidationEntry *ve = cls; struct TransportPingMessage ping; struct GNUNET_TRANSPORT_PluginFunctions *papi; + struct GNUNET_TIME_Absolute next; const struct GNUNET_MessageHeader *hello; + enum GNUNET_ATS_Network_Type network; ssize_t ret; size_t tsize; size_t slen; uint16_t hsize; ve->bc = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s' %s\n", - GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); + if (GNUNET_NO == result) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklist denies to send PING to `%s' `%s' `%s'\n", + GNUNET_i2s (pid), + GST_plugins_a2s (ve->address), + ve->address->transport_name); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting plain PING to `%s' `%s' `%s'\n", + GNUNET_i2s (pid), + GST_plugins_a2s (ve->address), + ve->address->transport_name); + + next = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), + validation_delay); + if (next.abs_value_us > validation_next.abs_value_us) + validation_next = next; /* We're going to send a PING so delay next validation */ slen = strlen (ve->address->transport_name) + 1; hello = GST_hello_get (); @@ -478,14 +578,14 @@ transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize], ve->address->transport_name, slen); memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize], - ve->address, ve->address->address_length); + ve->address->address, ve->address->address_length); papi = GST_plugins_find (ve->address->transport_name); if (papi == NULL) ret = -1; else { - GNUNET_assert (papi->send != NULL); - GNUNET_assert (papi->get_session != NULL); + GNUNET_assert (NULL != papi->send); + GNUNET_assert (NULL != papi->get_session); struct Session * session = papi->get_session(papi->cls, ve->address); if (session != NULL) @@ -494,12 +594,24 @@ transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, message_buf, tsize, PING_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); + network = papi->get_network (papi->cls, session); + if (GNUNET_ATS_NET_UNSPECIFIED == network) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not obtain a valid network for `%s' `%s'\n", + GNUNET_i2s (pid), + GST_plugins_a2s (ve->address)); + GNUNET_break(0); + } + GST_neighbours_notify_data_sent (pid, ve->address, session, tsize); } else { /* Could not get a valid session */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not get a valid session for `%s' %s\n", - GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Could not get a valid session for `%s' `%s'\n", + GNUNET_i2s (pid), + GST_plugins_a2s (ve->address)); ret = -1; } } @@ -511,7 +623,15 @@ transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, gettext_noop ("# PING without HELLO messages sent"), 1, GNUNET_NO); + + ve->network = network; ve->expecting_pong = GNUNET_YES; + validations_running++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Validation started, %u validation processes running\n", + validations_running); + /* Notify about PING sent */ + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_UPDATE); } } @@ -523,11 +643,13 @@ transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, * @param tc scheduler context (unused) */ static void -revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +revalidate_address (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ValidationEntry *ve = cls; struct GNUNET_TIME_Relative canonical_delay; struct GNUNET_TIME_Relative delay; + struct GNUNET_TIME_Relative blocked_for; struct GST_BlacklistCheck *bc; uint32_t rdelay; @@ -537,19 +659,40 @@ revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) canonical_delay = (ve->in_use == GNUNET_YES) ? CONNECTED_PING_FREQUENCY - : ((GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > + : ((GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value_us > 0) ? VALIDATED_PING_FREQUENCY : UNVALIDATED_PING_KEEPALIVE); - if (delay.rel_value > canonical_delay.rel_value * 2) + if (delay.rel_value_us > canonical_delay.rel_value_us * 2) { /* situation changed, recalculate delay */ delay = canonical_delay; ve->revalidation_block = GNUNET_TIME_relative_to_absolute (delay); } - if (delay.rel_value > 0) + if (delay.rel_value_us > 0) { /* should wait a bit longer */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Waiting for %s longer before validating address `%s'\n", + GNUNET_STRINGS_relative_time_to_string (delay, + GNUNET_YES), + GST_plugins_a2s (ve->address)); ve->revalidation_task = GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); + ve->next_validation = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), delay); + return; + } + blocked_for = GNUNET_TIME_absolute_get_remaining(validation_next); + if ((validations_running > validations_fast_start_threshold) && + (blocked_for.rel_value_us > 0)) + { + /* Validations are blocked, have to wait for blocked_for time */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Validations blocked for another %s, delaying validating address `%s'\n", + GNUNET_STRINGS_relative_time_to_string (blocked_for, + GNUNET_YES), + GST_plugins_a2s (ve->address)); + ve->revalidation_task = + GNUNET_SCHEDULER_add_delayed (blocked_for, &revalidate_address, ve); + ve->next_validation = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), blocked_for); return; } ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay); @@ -557,13 +700,30 @@ revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */ rdelay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - canonical_delay.rel_value); - delay = - GNUNET_TIME_relative_add (canonical_delay, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, rdelay)); + canonical_delay.rel_value_us); + + /* Debug code for mantis 0002726 */ + if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, rdelay).rel_value_us) + { + GNUNET_break (0); + delay = canonical_delay; + } + else + { + delay = GNUNET_TIME_relative_add (canonical_delay, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MICROSECONDS, rdelay)); + } + /* End debug code for mantis 0002726*/ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Validating now, next scheduled for %s, now validating address `%s'\n", + GNUNET_STRINGS_relative_time_to_string (blocked_for, + GNUNET_YES), + GST_plugins_a2s (ve->address)); ve->revalidation_task = GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); + ve->next_validation = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), delay); /* start PINGing by checking blacklist */ GNUNET_STATISTICS_update (GST_stats, @@ -588,37 +748,38 @@ revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * if we don't have an existing entry and no public key was given */ static struct ValidationEntry * -find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded - *public_key, const struct GNUNET_HELLO_Address *address) +find_validation_entry (const struct GNUNET_CRYPTO_EddsaPublicKey *public_key, + const struct GNUNET_HELLO_Address *address) { struct ValidationEntryMatchContext vemc; struct ValidationEntry *ve; vemc.ve = NULL; vemc.address = address; - GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, - &address->peer.hashPubKey, + GNUNET_CONTAINER_multipeermap_get_multiple (validation_map, + &address->peer, &validation_entry_match, &vemc); if (NULL != (ve = vemc.ve)) return ve; if (public_key == NULL) return NULL; - ve = GNUNET_malloc (sizeof (struct ValidationEntry)); + ve = GNUNET_new (struct ValidationEntry); ve->in_use = GNUNET_SYSERR; /* not defined */ - ve->last_line_set_to_no = 0; - ve->last_line_set_to_yes = 0; ve->address = GNUNET_HELLO_address_copy (address); ve->public_key = *public_key; ve->pid = address->peer; + ve->pong_sig_valid_until = GNUNET_TIME_absolute_get_zero_(); + memset (&ve->pong_sig_cache, '\0', sizeof (struct GNUNET_CRYPTO_EddsaSignature)); ve->latency = GNUNET_TIME_UNIT_FOREVER_REL; ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); ve->timeout_task = GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE, &timeout_hello_validation, ve); - GNUNET_CONTAINER_multihashmap_put (validation_map, &address->peer.hashPubKey, + GNUNET_CONTAINER_multipeermap_put (validation_map, &address->peer, ve, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_NEW); ve->expecting_pong = GNUNET_NO; return ve; } @@ -631,18 +792,20 @@ find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * @param cls original HELLO message * @param address the address * @param expiration expiration time - * @return GNUNET_OK (keep the address) + * @return #GNUNET_OK (keep the address) */ static int -add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address, +add_valid_address (void *cls, + const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration) { const struct GNUNET_HELLO_Message *hello = cls; struct ValidationEntry *ve; struct GNUNET_PeerIdentity pid; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + struct GNUNET_ATS_Information ats; + struct GNUNET_CRYPTO_EddsaPublicKey public_key; - if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) + if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) return GNUNET_OK; /* expired */ if ((GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) || (GNUNET_OK != GNUNET_HELLO_get_key (hello, &public_key))) @@ -650,7 +813,9 @@ add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address, GNUNET_break (0); return GNUNET_OK; /* invalid HELLO !? */ } - if (0 == memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity))) + if (0 == memcmp (&GST_my_identity, + &pid, + sizeof (struct GNUNET_PeerIdentity))) { /* Peerinfo returned own identity, skip validation */ return GNUNET_OK; @@ -660,8 +825,19 @@ add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address, ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration); if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting revalidations for valid address `%s'\n", + GST_plugins_a2s (ve->address)); + ve->next_validation = GNUNET_TIME_absolute_get(); ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); - GNUNET_ATS_address_update (GST_ats, address, NULL, NULL, 0); + } + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_UPDATE); + + ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); + ats.value = htonl (ve->network); + GNUNET_ATS_address_add (GST_ats, address, NULL, &ats, 1); + return GNUNET_OK; } @@ -682,6 +858,9 @@ process_peerinfo_hello (void *cls, const struct GNUNET_PeerIdentity *peer, GNUNET_assert (NULL != peer); if (NULL == hello) return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Handling HELLO for peer `%s'\n", + GNUNET_i2s (peer)); GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &add_valid_address, @@ -691,12 +870,37 @@ process_peerinfo_hello (void *cls, const struct GNUNET_PeerIdentity *peer, /** * Start the validation subsystem. + * + * @param max_fds maximum number of fds to use */ void -GST_validation_start () +GST_validation_start (unsigned int max_fds) { - validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE); - pnc = GNUNET_PEERINFO_notify (GST_cfg, &process_peerinfo_hello, NULL); + /** + * Initialization for validation throttling + * + * We have a maximum number max_fds of connections we can use for validation + * We monitor the number of validations in parallel and start to throttle it + * when doing to many validations in parallel: + * if (running validations < (max_fds / 2)) + * - "fast start": run validation immediately + * - have delay of (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us) / (max_fds / 2) + * (300 sec / ~150 == ~2 sec.) between two validations + */ + + validation_next = GNUNET_TIME_absolute_get(); + validation_delay.rel_value_us = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us) / (max_fds / 2); + validations_fast_start_threshold = (max_fds / 2); + validations_running = 0; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Validation uses a fast start threshold of %u connections and a delay between of %s\n ", + validations_fast_start_threshold, + GNUNET_STRINGS_relative_time_to_string (validation_delay, + GNUNET_YES)); + validation_map = GNUNET_CONTAINER_multipeermap_create (VALIDATION_MAP_SIZE, + GNUNET_NO); + pnc = GNUNET_PEERINFO_notify (GST_cfg, GNUNET_YES, + &process_peerinfo_hello, NULL); } @@ -708,9 +912,9 @@ GST_validation_stop () { struct CheckHelloValidatedContext *chvc; - GNUNET_CONTAINER_multihashmap_iterate (validation_map, + GNUNET_CONTAINER_multipeermap_iterate (validation_map, &cleanup_validation_entry, NULL); - GNUNET_CONTAINER_multihashmap_destroy (validation_map); + GNUNET_CONTAINER_multipeermap_destroy (validation_map); validation_map = NULL; while (NULL != (chvc = chvc_head)) { @@ -735,32 +939,38 @@ GST_validation_stop () */ static void multicast_pong (void *cls, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded - *public_key, struct GNUNET_TIME_Absolute valid_until, + const struct GNUNET_CRYPTO_EddsaPublicKey *public_key, + struct GNUNET_TIME_Absolute valid_until, struct GNUNET_TIME_Absolute validation_block, const struct GNUNET_HELLO_Address *address) { struct TransportPongMessage *pong = cls; struct GNUNET_TRANSPORT_PluginFunctions *papi; + struct Session *session; papi = GST_plugins_find (address->transport_name); - if (papi == NULL) + if (NULL == papi) return; - GNUNET_assert (papi->send != NULL); - GNUNET_assert (papi->get_session != NULL); - - struct Session * session = papi->get_session(papi->cls, address); - if (session == NULL) + GNUNET_assert (NULL != papi->send); + GNUNET_assert (NULL != papi->get_session); + session = papi->get_session(papi->cls, address); + if (NULL == session) { GNUNET_break (0); return; } - papi->send (papi->cls, session, - (const char *) pong, ntohs (pong->header.size), - PONG_PRIORITY, ACCEPTABLE_PING_DELAY, + (const char *) pong, + ntohs (pong->header.size), + PONG_PRIORITY, + ACCEPTABLE_PING_DELAY, NULL, NULL); + GST_neighbours_notify_data_sent (&address->peer, + address, + session, + pong->header.size); + } @@ -771,8 +981,9 @@ multicast_pong (void *cls, * @param hdr the PING * @param sender_address the sender address as we got it * @param session session we got the PING from + * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error */ -void +int GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *hdr, const struct GNUNET_HELLO_Address *sender_address, @@ -781,19 +992,22 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, const struct TransportPingMessage *ping; struct TransportPongMessage *pong; struct GNUNET_TRANSPORT_PluginFunctions *papi; - struct GNUNET_CRYPTO_RsaSignature *sig_cache; + struct GNUNET_CRYPTO_EddsaSignature *sig_cache; struct GNUNET_TIME_Absolute *sig_cache_exp; const char *addr; const char *addrend; + char *plugin_name; + char *pos; size_t alen; size_t slen; ssize_t ret; + int buggy = GNUNET_NO; struct GNUNET_HELLO_Address address; if (ntohs (hdr->size) < sizeof (struct TransportPingMessage)) { GNUNET_break_op (0); - return; + return GNUNET_SYSERR; } ping = (const struct TransportPingMessage *) hdr; if (0 != @@ -804,7 +1018,7 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, gettext_noop ("# PING message for different peer received"), 1, GNUNET_NO); - return; + return GNUNET_SYSERR; } GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PING messages received"), 1, @@ -816,67 +1030,140 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, sig_cache = NULL; sig_cache_exp = NULL; - - if (0 < alen) + papi = NULL; + if (alen > 0) { addrend = memchr (addr, '\0', alen); if (NULL == addrend) { GNUNET_break_op (0); - return; + return GNUNET_SYSERR; } addrend++; slen = strlen (addr) + 1; alen -= slen; + address.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE; address.address = addrend; address.address_length = alen; address.transport_name = addr; - address.peer = *sender; - if (GNUNET_YES != - GST_hello_test_address (&address, &sig_cache, &sig_cache_exp)) + address.peer = GST_my_identity; + + if (NULL == address.transport_name) + { + GNUNET_break (0); + } + + if (0 != strstr (address.transport_name, "_client")) + { + plugin_name = GNUNET_strdup (address.transport_name); + pos = strstr (plugin_name, "_client"); + GNUNET_assert (NULL != pos); + GNUNET_snprintf (pos, strlen ("_server") + 1, "%s", "_server"); + } + else + plugin_name = GNUNET_strdup (address.transport_name); + + if (NULL == (papi = GST_plugins_find (plugin_name))) + { + /* we don't have the plugin for this address */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Plugin `%s' not available, cannot confirm having this address\n"), + plugin_name); + GNUNET_free (plugin_name); + return GNUNET_SYSERR; + } + GNUNET_free (plugin_name); + if (GNUNET_OK != papi->check_address (papi->cls, addrend, alen)) { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# failed address checks during validation"), 1, + GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _ - ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"), + _("Address `%s' is not one of my addresses, not confirming PING\n"), GST_plugins_a2s (&address)); - return; + return GNUNET_SYSERR; + } + else + { + GNUNET_STATISTICS_update (GST_stats, + gettext_noop + ("# successful address checks during validation"), 1, + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Address `%s' is one of my addresses, confirming PING\n", + GST_plugins_a2s (&address)); + } + + if (GNUNET_YES != GST_hello_test_address (&address, &sig_cache, &sig_cache_exp)) + { + if (GNUNET_NO == buggy) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Not confirming PING from peer `%s' with address `%s' since I cannot confirm having this address.\n"), + GNUNET_i2s (sender), + GST_plugins_a2s (&address)); + return GNUNET_SYSERR; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Received a PING message with validation bug from `%s'\n"), + GNUNET_i2s (sender)); + } } } else { addrend = NULL; /* make gcc happy */ slen = 0; - static struct GNUNET_CRYPTO_RsaSignature no_address_signature; + static struct GNUNET_CRYPTO_EddsaSignature no_address_signature; static struct GNUNET_TIME_Absolute no_address_signature_expiration; sig_cache = &no_address_signature; sig_cache_exp = &no_address_signature_expiration; } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "I am `%s', sending PONG to peer `%s'\n", + GNUNET_i2s_full (&GST_my_identity), + GNUNET_i2s (sender)); + + /* message with structure: + * [TransportPongMessage][Transport name][Address] */ + pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen); pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen); pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG); pong->purpose.size = - htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + alen + slen); pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN); - pong->challenge = ping->challenge; + memcpy (&pong->challenge, &ping->challenge, sizeof (ping->challenge)); pong->addrlen = htonl (alen + slen); - memcpy (&pong[1], addr, slen); - memcpy (&((char *) &pong[1])[slen], addrend, alen); - if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value < - PONG_SIGNATURE_LIFETIME.rel_value / 4) + memcpy (&pong[1], addr, slen); /* Copy transport plugin */ + if (alen > 0) + { + GNUNET_assert (NULL != addrend); + memcpy (&((char *) &pong[1])[slen], addrend, alen); + } + if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value_us < + PONG_SIGNATURE_LIFETIME.rel_value_us / 4) { /* create / update cached sig */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating PONG signature to indicate ownership.\n"); + "Creating PONG signature to indicate ownership.\n"); *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME); pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (GST_my_private_key, &pong->purpose, - sig_cache)); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_sign (GST_my_private_key, &pong->purpose, + sig_cache)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to create PONG signature for peer `%s'\n"), GNUNET_i2s (sender)); + } } else { @@ -888,7 +1175,6 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, /* first see if the session we got this PING from can be used to transmit * a response reliably */ - papi = GST_plugins_find (sender_address->transport_name); if (papi == NULL) ret = -1; else @@ -911,9 +1197,13 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, (const char *) pong, ntohs (pong->header.size), PONG_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); + if (-1 != ret) + GST_neighbours_notify_data_sent (sender, + sender_address, session, + pong->header.size); } } - if (ret != -1) + if (-1 != ret) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitted PONG to `%s' via reliable mechanism\n", @@ -924,7 +1214,7 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, ("# PONGs unicast via reliable transport"), 1, GNUNET_NO); GNUNET_free (pong); - return; + return GNUNET_OK; } /* no reliable method found, try transmission via all known addresses */ @@ -932,13 +1222,15 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, gettext_noop ("# PONGs multicast to all available addresses"), 1, GNUNET_NO); - GST_validation_get_addresses (sender, &multicast_pong, pong); + GST_validation_get_addresses (sender, + &multicast_pong, pong); GNUNET_free (pong); + return GNUNET_OK; } /** - * Context for the 'validate_address' function + * Context for the #validate_address_iterator() function */ struct ValidateAddressContext { @@ -950,7 +1242,8 @@ struct ValidateAddressContext /** * Public key of the peer whose address is being validated. */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + struct GNUNET_CRYPTO_EddsaPublicKey public_key; + }; @@ -958,10 +1251,10 @@ struct ValidateAddressContext * Iterator callback to go over all addresses and try to validate them * (unless blocked or already validated). * - * @param cls pointer to a 'struct ValidateAddressContext' + * @param cls pointer to a `struct ValidateAddressContext *` * @param address the address * @param expiration expiration time - * @return GNUNET_OK (keep the address) + * @return #GNUNET_OK (keep the address) */ static int validate_address_iterator (void *cls, @@ -971,11 +1264,20 @@ validate_address_iterator (void *cls, const struct ValidateAddressContext *vac = cls; struct ValidationEntry *ve; - if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0) + if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Skipping expired address from HELLO\n"); return GNUNET_OK; /* expired */ + } ve = find_validation_entry (&vac->public_key, address); if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Validation process started for fresh address `%s'\n", + GST_plugins_a2s (ve->address)); ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); + } return GNUNET_OK; } @@ -983,19 +1285,21 @@ validate_address_iterator (void *cls, /** * Add the validated peer address to the HELLO. * - * @param cls the 'struct ValidationEntry' with the validated address - * @param max space in buf + * @param cls the `struct ValidationEntry *` with the validated address + * @param max space in @a buf * @param buf where to add the address - * @return number of bytes written, 0 to signal the + * @return number of bytes written, #GNUNET_SYSERR to signal the * end of the iteration. */ -static size_t -add_valid_peer_address (void *cls, size_t max, void *buf) +static ssize_t +add_valid_peer_address (void *cls, + size_t max, + void *buf) { struct ValidationEntry *ve = cls; if (GNUNET_YES == ve->copied) - return 0; /* terminate */ + return GNUNET_SYSERR; /* Done */ ve->copied = GNUNET_YES; return GNUNET_HELLO_add_address (ve->address, ve->valid_until, buf, max); } @@ -1007,8 +1311,9 @@ add_valid_peer_address (void *cls, size_t max, void *buf) * * @param sender peer sending the PONG * @param hdr the PONG + * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error */ -void +int GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *hdr) { @@ -1021,16 +1326,21 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, size_t size; struct GNUNET_HELLO_Message *hello; struct GNUNET_HELLO_Address address; + int sig_res; + int do_verify; if (ntohs (hdr->size) < sizeof (struct TransportPongMessage)) { GNUNET_break_op (0); - return; + return GNUNET_SYSERR; } GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONG messages received"), 1, GNUNET_NO); + /* message with structure: + * [TransportPongMessage][Transport name][Address] */ + pong = (const struct TransportPongMessage *) hdr; tname = (const char *) &pong[1]; size = ntohs (hdr->size) - sizeof (struct TransportPongMessage); @@ -1038,7 +1348,7 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, if (NULL == addr) { GNUNET_break_op (0); - return; + return GNUNET_SYSERR; } addr++; slen = strlen (tname) + 1; @@ -1047,59 +1357,116 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, address.address = addr; address.address_length = addrlen; address.transport_name = tname; + address.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE; ve = find_validation_entry (NULL, &address); - if ((NULL == ve) || (ve->expecting_pong == GNUNET_NO)) + if ((NULL == ve) || (GNUNET_NO == ve->expecting_pong)) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs dropped, no matching pending validation"), 1, GNUNET_NO); - return; + return GNUNET_OK; } /* now check that PONG is well-formed */ if (0 != memcmp (&ve->pid, sender, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_break_op (0); - return; - } - - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN, - &pong->purpose, &pong->signature, - &ve->public_key)) - { - GNUNET_break_op (0); - return; + return GNUNET_SYSERR; } - if (GNUNET_TIME_absolute_get_remaining - (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0) + (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value_us == 0) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs dropped, signature expired"), 1, GNUNET_NO); - return; + return GNUNET_SYSERR; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Address validated for peer `%s' with plugin `%s': `%s'\n", - GNUNET_i2s (sender), tname, GST_plugins_a2s (&address)); + + sig_res = GNUNET_SYSERR; + do_verify = GNUNET_YES; + if (0 != GNUNET_TIME_absolute_get_remaining (ve->pong_sig_valid_until).rel_value_us) + { + /* We have a cached and valid signature for this peer, + * try to compare instead of verify */ + if (0 == memcmp (&ve->pong_sig_cache, &pong->signature, sizeof (struct GNUNET_CRYPTO_EddsaSignature))) + { + /* signatures are identical, we can skip verification */ + sig_res = GNUNET_OK; + do_verify = GNUNET_NO; + } + else + { + sig_res = GNUNET_SYSERR; + /* signatures do not match, we have to verify */ + } + } + + if (GNUNET_YES == do_verify) + { + /* Do expensive verification */ + sig_res = GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN, + &pong->purpose, &pong->signature, + &ve->public_key); + if (sig_res == GNUNET_SYSERR) + { + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to verify: invalid signature on address `%s':%s from peer `%s'\n", + tname, + GST_plugins_a2s (ve->address), + GNUNET_i2s (sender)); + } + } + if (sig_res == GNUNET_SYSERR) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Validation process successful for peer `%s' with plugin `%s' address `%s'\n", + GNUNET_i2s (sender), + tname, + GST_plugins_a2s (ve->address)); /* validity achieved, remember it! */ ve->expecting_pong = GNUNET_NO; ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION); + ve->pong_sig_cache = pong->signature; + ve->pong_sig_valid_until = GNUNET_TIME_absolute_ntoh (pong->expiration); ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time); { - struct GNUNET_ATS_Information ats; + struct GNUNET_ATS_Information ats[2]; - ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); - ats.value = htonl ((uint32_t) ve->latency.rel_value); - GNUNET_ATS_address_update (GST_ats, ve->address, NULL, &ats, 1); + ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY); + ats[0].value = htonl ((uint32_t) ve->latency.rel_value_us); + ats[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); + ats[1].value = htonl ((uint32_t) ve->network); + GNUNET_ATS_address_add (GST_ats, ve->address, NULL, ats, 2); } + if (validations_running > 0) + { + validations_running --; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Validation finished, %u validation processes running\n", + validations_running); + } + else + { + GNUNET_break (0); + } + + /* Notify about new validity */ + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_UPDATE); + /* build HELLO to store in PEERINFO */ ve->copied = GNUNET_NO; - hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve); + hello = GNUNET_HELLO_create (&ve->public_key, + &add_valid_peer_address, ve, + GNUNET_NO); GNUNET_PEERINFO_add_peer (GST_peerinfo, hello, NULL, NULL); GNUNET_free (hello); + return GNUNET_OK; } @@ -1108,43 +1475,54 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, * validation. * * @param hello the HELLO we received + * @return #GNUNET_OK if the message was fine, #GNUNET_SYSERR on serious error */ -void +int GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello) { const struct GNUNET_HELLO_Message *hm = (const struct GNUNET_HELLO_Message *) hello; struct ValidateAddressContext vac; struct GNUNET_HELLO_Message *h; + int friend; - if ((GNUNET_OK != GNUNET_HELLO_get_id (hm, &vac.pid)) || - (GNUNET_OK != GNUNET_HELLO_get_key (hm, &vac.public_key))) + friend = GNUNET_HELLO_is_friend_only (hm); + if ( ( (GNUNET_YES != friend) && + (GNUNET_NO != friend) ) || + (GNUNET_OK != GNUNET_HELLO_get_id (hm, &vac.pid)) || + (GNUNET_OK != GNUNET_HELLO_get_key (hm, &vac.public_key))) { /* malformed HELLO */ - GNUNET_break (0); - return; + GNUNET_break_op (0); + return GNUNET_SYSERR; } if (0 == memcmp (&GST_my_identity, &vac.pid, sizeof (struct GNUNET_PeerIdentity))) - return; + return GNUNET_OK; /* Add peer identity without addresses to peerinfo service */ - h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL); + h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL, friend); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Validation received new %s message for peer `%s' with size %u\n"), + "HELLO", + GNUNET_i2s (&vac.pid), + ntohs (hello->size)); GNUNET_PEERINFO_add_peer (GST_peerinfo, h, NULL, NULL); -#if VERBOSE_VALIDATION + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Adding `%s' without addresses for peer `%s'\n"), "HELLO", GNUNET_i2s (&vac.pid)); -#endif + GNUNET_free (h); GNUNET_assert (NULL == GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO, &validate_address_iterator, &vac)); + return GNUNET_OK; } /** - * Closure for 'iterate_addresses' + * Closure for #iterate_addresses(). */ struct IteratorContext { @@ -1154,7 +1532,7 @@ struct IteratorContext GST_ValidationAddressCallback cb; /** - * Closure for 'cb'. + * Closure for @e cb. */ void *cb_cls; @@ -1164,13 +1542,15 @@ struct IteratorContext /** * Call the callback in the closure for each validation entry. * - * @param cls the 'struct GST_ValidationIteratorContext' + * @param cls the `struct IteratorContext` * @param key the peer's identity - * @param value the 'struct ValidationEntry' - * @return GNUNET_OK (continue to iterate) + * @param value the `struct ValidationEntry` + * @return #GNUNET_OK (continue to iterate) */ static int -iterate_addresses (void *cls, const GNUNET_HashCode * key, void *value) +iterate_addresses (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) { struct IteratorContext *ic = cls; struct ValidationEntry *ve = value; @@ -1187,7 +1567,7 @@ iterate_addresses (void *cls, const GNUNET_HashCode * key, void *value) * * @param target peer information is requested for * @param cb function to call; will not be called after this function returns - * @param cb_cls closure for 'cb' + * @param cb_cls closure for @a cb */ void GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, @@ -1197,8 +1577,8 @@ GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, ic.cb = cb; ic.cb_cls = cb_cls; - GNUNET_CONTAINER_multihashmap_get_multiple (validation_map, - &target->hashPubKey, + GNUNET_CONTAINER_multipeermap_get_multiple (validation_map, + target, &iterate_addresses, &ic); } @@ -1210,15 +1590,13 @@ GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target, * * @param address the address * @param session the session - * @param in_use GNUNET_YES if we are now using the address for a connection, - * GNUNET_NO if we are no longer using the address for a connection - * @param line line of caller just for DEBUGGING! + * @param in_use #GNUNET_YES if we are now using the address for a connection, + * #GNUNET_NO if we are no longer using the address for a connection */ void GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, struct Session *session, - int in_use, - int line) + int in_use) { struct ValidationEntry *ve; @@ -1237,28 +1615,17 @@ GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address, if (GNUNET_YES == in_use) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error setting address in use for peer `%s' `%s' to USED: set last time by %i, called now by %i\n", - GNUNET_i2s (&address->peer), GST_plugins_a2s (address), - ve->last_line_set_to_yes, line); + "Error setting address in use for peer `%s' `%s' to USED\n", + GNUNET_i2s (&address->peer), GST_plugins_a2s (address)); } if (GNUNET_NO == in_use) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error setting address in use for peer `%s' `%s' to NOT_USED: set last time by %i, called now by %i\n", - GNUNET_i2s (&address->peer), GST_plugins_a2s (address), - ve->last_line_set_to_no, line); + "Error setting address in use for peer `%s' `%s' to NOT_USED\n", + GNUNET_i2s (&address->peer), GST_plugins_a2s (address)); } } - if (GNUNET_YES == in_use) - { - ve->last_line_set_to_yes = line; - } - if (GNUNET_NO == in_use) - { - ve->last_line_set_to_no = line; - } - GNUNET_break (ve->in_use != in_use); /* should be different... */ ve->in_use = in_use; if (in_use == GNUNET_YES) @@ -1298,5 +1665,58 @@ GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, return ve->latency; } +/** + * Closure for the validation_entries_iterate function. + */ +struct ValidationIteratorContext +{ + /** + * Function to call on each validation entry + */ + GST_ValidationChangedCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; +}; + + +static int +validation_entries_iterate (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct ValidationIteratorContext *ic = cls; + struct ValidationEntry *ve = value; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notifying about validation entry for peer `%s' address `%s' \n", + GNUNET_i2s (&ve->pid), GST_plugins_a2s (ve->address)); + ic->cb (ic->cb_cls, &ve->pid, ve->address, ve->send_time, + ve->valid_until, ve->next_validation, ve->state); + + return GNUNET_OK; +} + +/** + * Iterate over all iteration entries + * + * @param cb function to call + * @param cb_cls closure for cb + */ +void +GST_validation_iterate (GST_ValidationChangedCallback cb, + void *cb_cls) +{ + struct ValidationIteratorContext ic; + + if (NULL == validation_map) + return; /* can happen during shutdown */ + ic.cb = cb; + ic.cb_cls = cb_cls; + GNUNET_CONTAINER_multipeermap_iterate (validation_map, + &validation_entries_iterate, + &ic); +} /* end of file gnunet-service-transport_validation.c */