2 This file is part of GNUnet.
3 (C) 2010,2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file transport/gnunet-service-transport_validation.c
23 * @brief address validation subsystem
24 * @author Christian Grothoff
27 #include "gnunet-service-transport_validation.h"
28 #include "gnunet-service-transport_plugins.h"
29 #include "gnunet-service-transport.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet_signatures.h"
36 * How long until a HELLO verification attempt should time out?
37 * Must be rather small, otherwise a partially successful HELLO
38 * validation (some addresses working) might not be available
39 * before a client's request for a connection fails for good.
40 * Besides, if a single request to an address takes a long time,
41 * then the peer is unlikely worthwhile anyway.
43 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
46 * How long is a PONG signature valid? We'll recycle a signature until
47 * 1/4 of this time is remaining. PONGs should expire so that if our
48 * external addresses change an adversary cannot replay them indefinitely.
49 * OTOH, we don't want to spend too much time generating PONG signatures,
50 * so they must have some lifetime to reduce our CPU usage.
52 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
55 * After how long do we expire an address in a HELLO that we just
56 * validated? This value is also used for our own addresses when we
59 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
62 * How long before an existing address expires should we again try to
63 * validate it? Must be (significantly) smaller than
64 * HELLO_ADDRESS_EXPIRATION.
66 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
69 * How long before we try to check an address again (if it turned out to
70 * be invalid the first time)?
72 #define MAX_REVALIDATION_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
75 * Size of the validation map hashmap.
77 #define VALIDATION_MAP_SIZE 256
80 * Priority to use for PINGs and PONGs
82 #define PING_PRIORITY 1
85 * Priority to use for PINGs and PONGs
87 #define PONG_PRIORITY 1
91 * Message used to ask a peer to validate receipt (to check an address
92 * from a HELLO). Followed by the address we are trying to validate,
93 * or an empty address if we are just sending a PING to confirm that a
94 * connection which the receiver (of the PING) initiated is still valid.
96 struct TransportPingMessage
100 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
102 struct GNUNET_MessageHeader header;
105 * Challenge code (to ensure fresh reply).
107 uint32_t challenge GNUNET_PACKED;
110 * Who is the intended recipient?
112 struct GNUNET_PeerIdentity target;
118 * Message used to validate a HELLO. The challenge is included in the
119 * confirmation to make matching of replies to requests possible. The
120 * signature signs our public key, an expiration time and our address.<p>
122 * This message is followed by our transport address that the PING tried
123 * to confirm (if we liked it). The address can be empty (zero bytes)
124 * if the PING had not address either (and we received the request via
125 * a connection that we initiated).
127 struct TransportPongMessage
131 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
133 struct GNUNET_MessageHeader header;
136 * Challenge code from PING (showing freshness). Not part of what
137 * is signed so that we can re-use signatures.
139 uint32_t challenge GNUNET_PACKED;
144 struct GNUNET_CRYPTO_RsaSignature signature;
147 * What are we signing and why? Two possible reason codes can be here:
148 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
149 * plausible address for this peer (pid is set to identity of signer); or
150 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
151 * an address we used to connect to the peer with the given pid.
153 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
156 * When does this signature expire?
158 struct GNUNET_TIME_AbsoluteNBO expiration;
161 * Either the identity of the peer Who signed this message, or the
162 * identity of the peer that we're connected to using the given
163 * address (depending on purpose.type).
165 struct GNUNET_PeerIdentity pid;
168 * Size of address appended to this message (part of what is
169 * being signed, hence not redundant).
177 * Information about an address under validation
179 struct ValidationEntry
183 * Name of the transport.
185 char *transport_name;
188 * The address, actually a pointer to the end
189 * of this struct. Do not free!
194 * The identity of the peer.
196 struct GNUNET_PeerIdentity pid;
199 * ID of task that will clean up this entry if nothing happens.
201 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
204 * At what time did we send the latest validation request?
206 struct GNUNET_TIME_Absolute send_time;
209 * Until when is this address valid?
210 * ZERO if it is not currently considered valid.
212 struct GNUNET_TIME_Absolute valid_until;
215 * How long until we can try to validate this address again?
216 * FOREVER if the address is for an unsupported plugin (from PEERINFO)
217 * ZERO if the address is considered valid (no validation needed)
218 * otherwise a time in the future if we're currently denying re-validation
220 struct GNUNET_TIME_Absolute validation_block;
223 * Challenge number we used.
236 * Context of currently active requests to peerinfo
237 * for validation of HELLOs.
239 struct CheckHelloValidatedContext
243 * This is a doubly-linked list.
245 struct CheckHelloValidatedContext *next;
248 * This is a doubly-linked list.
250 struct CheckHelloValidatedContext *prev;
253 * Hello that we are validating.
255 const struct GNUNET_HELLO_Message *hello;
258 * Context for peerinfo iteration.
260 struct GNUNET_PEERINFO_IteratorContext *piter;
266 * Head of linked list of HELLOs awaiting validation.
268 static struct CheckHelloValidatedContext *chvc_head;
271 * Tail of linked list of HELLOs awaiting validation
273 static struct CheckHelloValidatedContext *chvc_tail;
276 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
277 * of the given peer that we are currently validating, have validated
278 * or are blocked from re-validation for a while).
280 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
283 * Map of PeerIdentities to 'struct GST_ValidationIteratorContext's.
285 static struct GNUNET_CONTAINER_MultiHashMap *notify_map;
289 * Start the validation subsystem.
292 GST_validation_start ()
294 validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE);
295 notify_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE);
300 * Iterate over validation entries and free them.
302 * @param cls (unused)
303 * @param key peer identity (unused)
304 * @param value a 'struct ValidationEntry' to clean up
305 * @return GNUNET_YES (continue to iterate)
308 cleanup_validation_entry (void *cls,
309 const GNUNET_HashCode *key,
312 struct ValidationEntry *ve = value;
314 GNUNET_free (ve->transport_name);
315 if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task)
317 GNUNET_SCHEDULER_cancel (ve->timeout_task);
318 ve->timeout_task = GNUNET_SCHEDULER_NO_TASK;
326 * Stop the validation subsystem.
329 GST_validation_stop ()
331 struct CheckHelloValidatedContext *chvc;
333 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
334 &cleanup_validation_entry,
336 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
337 validation_map = NULL;
338 GNUNET_assert (GNUNET_CONTAINER_multihashmap_size (notify_map) == 0);
339 GNUNET_CONTAINER_multihashmap_destroy (notify_map);
341 while (NULL != (chvc = chvc_head))
343 GNUNET_CONTAINER_DLL_remove (chvc_head,
346 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
354 * Address validation cleanup task (record no longer needed).
356 * @param cls the 'struct ValidationEntry'
357 * @param tc scheduler context (unused)
360 timeout_hello_validation (void *cls,
361 const struct GNUNET_SCHEDULER_TaskContext *tc)
363 struct ValidationEntry *va = cls;
365 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
366 GNUNET_STATISTICS_update (GST_stats,
367 gettext_noop ("# address records discarded"),
370 GNUNET_break (GNUNET_OK ==
371 GNUNET_CONTAINER_multihashmap_remove (validation_map,
374 GNUNET_free (va->transport_name);
381 * Context for the validation entry match function.
383 struct ValidationEntryMatchContext
386 * Where to store the result?
388 struct ValidationEntry *ve;
391 * Transport name we're looking for.
393 const char *transport_name;
396 * Address we're interested in.
401 * Number of bytes in 'addr'.
408 * Iterate over validation entries until a matching one is found.
410 * @param cls the 'struct ValidationEntryMatchContext'
411 * @param key peer identity (unused)
412 * @param value a 'struct ValidationEntry' to match
413 * @return GNUNET_YES if the entry does not match,
414 * GNUNET_NO if the entry does match
417 validation_entry_match (void *cls,
418 const GNUNET_HashCode *key,
421 struct ValidationEntryMatchContext *vemc = cls;
422 struct ValidationEntry *ve = value;
424 if ( (ve->addrlen == vemc->addrlen) &&
425 (0 == memcmp (ve->addr, vemc->addr, ve->addrlen)) &&
426 (0 == strcmp (ve->transport_name, vemc->transport_name)) )
436 * Find a ValidationEntry entry for the given neighbour that matches
437 * the given address and transport. If none exists, create one (but
438 * without starting any validation).
440 * @param neighbour which peer we care about
441 * @param tname name of the transport plugin
442 * @param session session to look for, NULL for 'any'; otherwise
443 * can be used for the service to "learn" this session ID
445 * @param addr binary address
446 * @param addrlen length of addr
447 * @return validation entry matching the given specifications
449 static struct ValidationEntry *
450 find_validation_entry (struct GNUNET_PeerIdentity *neighbour,
455 struct ValidationEntryMatchContext vemc;
456 struct ValidationEntry *ve;
459 vemc.transport_name = tname;
461 vemc.addrlen = addrlen;
462 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
463 &neighbour->hashPubKey,
464 &validation_entry_match,
466 if (NULL != (ve = vemc.ve))
468 ve = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
469 ve->transport_name = GNUNET_strdup (tname);
470 ve->addr = (void*) &ve[1];
471 ve->pid = *neighbour;
472 ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
474 memcpy (&ve[1], addr, addrlen);
475 ve->addrlen = addrlen;
476 GNUNET_CONTAINER_multihashmap_put (validation_map,
477 &neighbour->hashPubKey,
479 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
485 * Send the given PONG to the given address.
487 * @param cls the PONG message
488 * @param target peer this change is about, never NULL
489 * @param valid_until is ZERO if we never validated the address,
490 * otherwise a time up to when we consider it (or was) valid
491 * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO)
492 * is ZERO if the address is considered valid (no validation needed)
493 * otherwise a time in the future if we're currently denying re-validation
494 * @param plugin_name name of the plugin
495 * @param plugin_address binary address
496 * @param plugin_address_len length of address
499 multicast_pong (void *cls,
500 const struct GNUNET_PeerIdentity *target,
501 struct GNUNET_TIME_Absolute valid_until,
502 struct GNUNET_TIME_Absolute validation_block,
503 const char *plugin_name,
504 const void *plugin_address,
505 size_t plugin_address_len)
507 struct TransportPongMessage *pong = cls;
508 struct GNUNET_TRANSPORT_PluginFunctions *papi;
510 papi = GST_plugins_find (plugin_name);
513 (void) papi->send (papi->cls,
516 ntohs (pong->header.size),
518 HELLO_VERIFICATION_TIMEOUT,
528 * We've received a PING. If appropriate, generate a PONG.
530 * @param sender peer sending the PING
531 * @param hdr the PING
532 * @param session session we got the PING from
533 * @param plugin_name name of plugin that received the PING
534 * @param sender_address address of the sender as known to the plugin, NULL
535 * if we did not initiate the connection
536 * @param sender_address_len number of bytes in sender_address
539 GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
540 const struct GNUNET_MessageHeader *hdr,
541 const char *plugin_name,
542 struct Session *session,
543 const void *sender_address,
544 size_t sender_address_len)
547 const struct TransportPingMessage *ping;
548 struct TransportPongMessage *pong;
549 struct GNUNET_TRANSPORT_PluginFunctions *papi;
556 if (ntohs (hdr->size) < sizeof (struct TransportPingMessage))
561 ping = (const struct TransportPingMessage *) hdr;
562 if (0 != memcmp (&ping->target,
564 sizeof (struct GNUNET_PeerIdentity)))
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
568 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
570 (sender_address != NULL)
571 ? GST_plugin_a2s (plugin_name,
575 GNUNET_i2s (&ping->target));
580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
581 "Processing `%s' from `%s'\n",
583 (sender_address != NULL)
584 ? GST_plugin_a2s (plugin_name,
589 GNUNET_STATISTICS_update (GST_stats,
590 gettext_noop ("# PING messages received"),
593 addr = (const char*) &ping[1];
594 alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage);
597 /* peer wants to confirm that we have an outbound connection to him */
598 if (sender_address == NULL)
600 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
601 _("Refusing to create PONG since I do initiate the session with `%s'.\n"),
602 GNUNET_i2s (sender));
606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
607 "Creating PONG indicating that we initiated a connection to peer `%s' using address `%s' \n",
609 GST_plugin_a2s (plugin_name,
611 sender_address_len));
613 slen = strlen (plugin_name) + 1;
614 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
615 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
616 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
618 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
620 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
621 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
622 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
623 pong->challenge = ping->challenge;
624 pong->addrlen = htonl(sender_address_len + slen);
629 memcpy (&((char*)&pong[1])[slen],
633 /* FIXME: lookup signature! */
634 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value <
635 PONG_SIGNATURE_LIFETIME.rel_value / 4)
637 /* create / update cached sig */
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640 "Creating PONG signature to indicate active connection.\n");
642 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
643 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
644 GNUNET_assert (GNUNET_OK ==
645 GNUNET_CRYPTO_rsa_sign (my_private_key,
647 &session_header->pong_signature));
651 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
653 memcpy (&pong->signature,
654 &session_header->pong_signature,
655 sizeof (struct GNUNET_CRYPTO_RsaSignature));
657 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
658 GNUNET_assert (GNUNET_OK ==
659 GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
666 /* peer wants to confirm that this is one of our addresses */
667 addrend = memchr (addr, '\0', alen);
676 papi = GST_plugins_find (addr);
678 if ( (NULL == papi) ||
680 papi->check_address (papi->cls,
684 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
685 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
686 GST_plugins_a2s (addr,
692 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
693 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
694 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
696 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
698 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
699 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
700 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
701 pong->challenge = ping->challenge;
702 pong->addrlen = htonl(alen + slen);
703 pong->pid = GST_my_identity;
704 memcpy (&pong[1], addr, slen);
705 memcpy (&((char*)&pong[1])[slen], addrend, alen);
707 if ( (oal != NULL) &&
708 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
710 /* create / update cached sig */
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713 "Creating PONG signature to indicate ownership.\n");
715 oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
716 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
717 GNUNET_assert (GNUNET_OK ==
718 GNUNET_CRYPTO_rsa_sign (my_private_key,
720 &oal->pong_signature));
721 memcpy (&pong->signature,
722 &oal->pong_signature,
723 sizeof (struct GNUNET_CRYPTO_RsaSignature));
725 else if (oal == NULL)
728 /* not using cache (typically DV-only) */
729 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
730 GNUNET_assert (GNUNET_OK ==
731 GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
739 /* can used cached version */
740 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
741 memcpy (&pong->signature,
742 &oal->pong_signature,
743 sizeof (struct GNUNET_CRYPTO_RsaSignature));
748 /* first see if the session we got this PING from can be used to transmit
749 a response reliably */
750 papi = GST_plugins_find (plugin_name);
754 ret = papi->send (papi->cls,
757 ntohs (pong->header.size),
759 HELLO_VERIFICATION_TIMEOUT,
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "Transmitted PONG to `%s' via reliable mechanism\n",
769 GNUNET_i2s (sender));
771 GNUNET_STATISTICS_update (GST_stats,
772 gettext_noop ("# PONGs unicast via reliable transport"),
779 /* no reliable method found, try transmission via all known addresses */
780 GNUNET_STATISTICS_update (GST_stats,
781 gettext_noop ("# PONGs multicast to all available addresses"),
784 (void) GST_validation_get_addresses (sender,
793 * We've received a PONG. Check if it matches a pending PING and
794 * mark the respective address as confirmed.
796 * @param sender peer sending the PONG
797 * @param hdr the PONG
798 * @param plugin_name name of plugin that received the PONG
799 * @param sender_address address of the sender as known to the plugin, NULL
800 * if we did not initiate the connection
801 * @param sender_address_len number of bytes in sender_address
804 GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
805 const struct GNUNET_MessageHeader *hdr,
806 const char *plugin_name,
807 const void *sender_address,
808 size_t sender_address_len)
814 * Iterator callback to go over all addresses and try to validate them
815 * (unless blocked or already validated).
817 * @param cls pointer to the 'struct PeerIdentity' of the peer
818 * @param tname name of the transport
819 * @param expiration expiration time
820 * @param addr the address
821 * @param addrlen length of the address
822 * @return GNUNET_OK (keep the address)
825 validate_address (void *cls,
827 struct GNUNET_TIME_Absolute expiration,
831 struct GNUNET_PeerIdentity *pid = cls;
832 struct ValidationEntry *ve;
833 struct TransportPingMessage ping;
834 struct GNUNET_TRANSPORT_PluginFunctions *papi;
839 if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
840 return GNUNET_OK; /* expired */
841 ve = find_validation_entry (pid, tname, addr, addrlen);
842 if (GNUNET_TIME_absolute_get_remaining (ve->validation_block).rel_value > 0)
843 return GNUNET_OK; /* blocked */
844 if (GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value > 0)
845 return GNUNET_OK; /* valid */
846 ve->validation_block = GNUNET_TIME_relative_to_absolute (MAX_REVALIDATION_FREQUENCY);
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 "Transmitting plain PING to `%s'\n",
851 ping.header.size = htons(sizeof(struct TransportPingMessage));
852 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
853 ping.challenge = htonl(ve->challenge);
856 slen = strlen(ve->transport_name) + 1;
857 tsize = sizeof(struct TransportPingMessage) + ve->addrlen + slen;
859 char message_buf[tsize];
861 memcpy(message_buf, &ping, sizeof (struct TransportPingMessage));
862 memcpy(&message_buf[sizeof (struct TransportPingMessage)],
865 memcpy(&message_buf[sizeof (struct TransportPingMessage) + slen],
868 papi = GST_plugins_find (ve->transport_name);
872 ret = papi->send (papi->cls,
877 HELLO_VERIFICATION_TIMEOUT,
878 NULL /* no session */,
886 ve->send_time = GNUNET_TIME_absolute_get ();
887 GNUNET_STATISTICS_update (GST_stats,
888 gettext_noop ("# PING without HELLO messages sent"),
897 * We've received a HELLO, check which addresses are new and trigger
900 * @param hello the HELLO we received
903 GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello)
905 const struct GNUNET_HELLO_Message* hm = (const struct GNUNET_HELLO_Message*) hello;
906 struct GNUNET_PeerIdentity pid;
909 GNUNET_HELLO_get_id (hm, &pid))
911 /* malformed HELLO */
915 GNUNET_assert (NULL ==
916 GNUNET_HELLO_iterate_addresses (hm,
924 * Opaque handle to stop incremental validation address callbacks.
926 struct GST_ValidationIteratorContext
929 * Function to call on each address.
931 GST_ValidationAddressCallback cb;
939 * Which peer are we monitoring?
941 struct GNUNET_PeerIdentity target;
946 * Call the callback in the closure for each validation entry.
948 * @param cls the 'struct GST_ValidationIteratorContext'
949 * @param key the peer's identity
950 * @param value the 'struct ValidationEntry'
951 * @return GNUNET_OK (continue to iterate)
954 iterate_addresses (void *cls,
955 const GNUNET_HashCode *key,
958 struct GST_ValidationIteratorContext *vic = cls;
959 struct ValidationEntry *ve = value;
961 vic->cb (vic->cb_cls,
964 ve->validation_block,
973 * Call the given function for each address for the given target.
974 * Can either give a snapshot (synchronous API) or be continuous.
976 * @param target peer information is requested for
977 * @param snapshot_only GNUNET_YES to iterate over addresses once, GNUNET_NO to
978 * continue to give information about addresses as it evolves
979 * @param cb function to call; will not be called after this function returns
980 * if snapshot_only is GNUNET_YES
981 * @param cb_cls closure for 'cb'
982 * @return context to cancel, NULL if 'snapshot_only' is GNUNET_YES
984 struct GST_ValidationIteratorContext *
985 GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target,
987 GST_ValidationAddressCallback cb,
990 struct GST_ValidationIteratorContext *vic;
992 vic = GNUNET_malloc (sizeof (struct GST_ValidationIteratorContext));
994 vic->cb_cls = cb_cls;
995 vic->target = *target;
996 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
1000 if (GNUNET_YES == snapshot_only)
1005 GNUNET_CONTAINER_multihashmap_put (notify_map,
1006 &target->hashPubKey,
1008 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1014 * Cancel an active validation address iteration.
1016 * @param ctx the context of the operation that is cancelled
1019 GST_validation_get_addresses_cancel (struct GST_ValidationIteratorContext *ctx)
1021 GNUNET_assert (GNUNET_OK ==
1022 GNUNET_CONTAINER_multihashmap_remove (notify_map,
1023 &ctx->target.hashPubKey,
1029 /* end of file gnunet-service-transport_validation.c */