2 This file is part of GNUnet.
3 (C) 2009, 2010 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.c
23 * @brief low-level P2P messaging
24 * @author Christian Grothoff
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "transport.h"
42 #define DEBUG_BLACKLIST GNUNET_YES
44 #define DEBUG_PING_PONG GNUNET_YES
46 #define DEBUG_TRANSPORT_HELLO GNUNET_YES
49 * Should we do some additional checks (to validate behavior
52 #define EXTRA_CHECKS GNUNET_YES
55 * How many messages can we have pending for a given client process
56 * before we start to drop incoming messages? We typically should
57 * have only one client and so this would be the primary buffer for
58 * messages, so the number should be chosen rather generously.
60 * The expectation here is that most of the time the queue is large
61 * enough so that a drop is virtually never required. Note that
62 * this value must be about as large as 'TOTAL_MSGS' in the
63 * 'test_transport_api_reliability.c', otherwise that testcase may
66 #define MAX_PENDING (128 * 1024)
69 * Size of the per-transport blacklist hash maps.
71 #define TRANSPORT_BLACKLIST_HT_SIZE 16
74 * How often should we try to reconnect to a peer using a particular
75 * transport plugin before giving up? Note that the plugin may be
76 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
78 #define MAX_CONNECT_RETRY 3
81 * Limit on the number of ready-to-run tasks when validating
82 * HELLOs. If more tasks are ready to run, we will drop
83 * HELLOs instead of validating them.
85 #define MAX_HELLO_LOAD 4
88 * How often must a peer violate bandwidth quotas before we start
89 * to simply drop its messages?
91 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
94 * How long until a HELLO verification attempt should time out?
95 * Must be rather small, otherwise a partially successful HELLO
96 * validation (some addresses working) might not be available
97 * before a client's request for a connection fails for good.
98 * Besides, if a single request to an address takes a long time,
99 * then the peer is unlikely worthwhile anyway.
101 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
104 * How long is a PONG signature valid? We'll recycle a signature until
105 * 1/4 of this time is remaining. PONGs should expire so that if our
106 * external addresses change an adversary cannot replay them indefinitely.
107 * OTOH, we don't want to spend too much time generating PONG signatures,
108 * so they must have some lifetime to reduce our CPU usage.
110 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
113 * Priority to use for PONG messages.
115 #define TRANSPORT_PONG_PRIORITY 4
118 * How often do we re-add (cheaper) plugins to our list of plugins
119 * to try for a given connected peer?
121 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
124 * After how long do we expire an address in a HELLO that we just
125 * validated? This value is also used for our own addresses when we
128 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
132 * How long before an existing address expires should we again try to
133 * validate it? Must be (significantly) smaller than
134 * HELLO_ADDRESS_EXPIRATION.
136 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
139 * Maximum frequency for re-evaluating latencies for all transport addresses.
141 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144 * Maximum frequency for re-evaluating latencies for connected addresses.
146 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
150 * List of addresses of other peers
152 struct ForeignAddressList
155 * This is a linked list.
157 struct ForeignAddressList *next;
160 * Which ready list does this entry belong to.
162 struct ReadyList *ready_list;
165 * How long until we auto-expire this address (unless it is
166 * re-confirmed by the transport)?
168 struct GNUNET_TIME_Absolute expires;
171 * Task used to re-validate addresses, updates latencies and
174 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
182 * Session (or NULL if no valid session currently exists or if the
183 * plugin does not use sessions).
185 struct Session *session;
188 * What was the last latency observed for this address, plugin and peer?
190 struct GNUNET_TIME_Relative latency;
193 * If we did not successfully transmit a message to the given peer
194 * via this connection during the specified time, we should consider
195 * the connection to be dead. This is used in the case that a TCP
196 * transport simply stalls writing to the stream but does not
197 * formerly get a signal that the other peer died.
199 struct GNUNET_TIME_Absolute timeout;
202 * How often have we tried to connect using this plugin? Used to
203 * discriminate against addresses that do not work well.
204 * FIXME: not yet used, but should be!
206 unsigned int connect_attempts;
209 * DV distance to this peer (1 if no DV is used).
210 * FIXME: need to set this from transport plugins!
220 * Have we ever estimated the latency of this address? Used to
221 * ensure that the first time we add an address, we immediately
227 * Are we currently connected via this address? The first time we
228 * successfully transmit or receive data to a peer via a particular
229 * address, we set this to GNUNET_YES. If we later get an error
230 * (disconnect notification, transmission failure, timeout), we set
231 * it back to GNUNET_NO.
236 * Is this plugin currently busy transmitting to the specific target?
237 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
238 * messages do not count as 'in transmit'.
243 * Has this address been validated yet?
251 * Entry in linked list of network addresses for ourselves. Also
252 * includes a cached signature for 'struct TransportPongMessage's.
254 struct OwnAddressList
257 * This is a linked list.
259 struct OwnAddressList *next;
262 * How long until we actually auto-expire this address (unless it is
263 * re-confirmed by the transport)?
265 struct GNUNET_TIME_Absolute expires;
268 * How long until the current signature expires? (ZERO if the
269 * signature was never created).
271 struct GNUNET_TIME_Absolute pong_sig_expires;
274 * Signature for a 'struct TransportPongMessage' for this address.
276 struct GNUNET_CRYPTO_RsaSignature pong_signature;
287 * Entry in linked list of all of our plugins.
289 struct TransportPlugin
293 * This is a linked list.
295 struct TransportPlugin *next;
298 * API of the transport as returned by the plugin's
299 * initialization function.
301 struct GNUNET_TRANSPORT_PluginFunctions *api;
304 * Short name for the plugin (i.e. "tcp").
309 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
314 * List of our known addresses for this transport.
316 struct OwnAddressList *addresses;
319 * Environment this transport service is using
322 struct GNUNET_TRANSPORT_PluginEnvironment env;
325 * ID of task that is used to clean up expired addresses.
327 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
330 * Set to GNUNET_YES if we need to scrap the existing list of
331 * "addresses" and start fresh when we receive the next address
332 * update from a transport. Set to GNUNET_NO if we should just add
333 * the new address to the list and wait for the commit call.
338 * Hashmap of blacklisted peers for this particular transport.
340 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
343 struct NeighbourList;
346 * For each neighbour we keep a list of messages
347 * that we still want to transmit to the neighbour.
353 * This is a doubly linked list.
355 struct MessageQueue *next;
358 * This is a doubly linked list.
360 struct MessageQueue *prev;
363 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
364 * stuck together in memory. Allocated at the end of this struct.
366 const char *message_buf;
369 * Size of the message buf
371 size_t message_buf_size;
374 * Client responsible for queueing the message;
375 * used to check that a client has no two messages
376 * pending for the same target. Can be NULL.
378 struct TransportClient *client;
381 * Using which specific address should we send this message?
383 struct ForeignAddressList *specific_address;
386 * Peer ID of the Neighbour this entry belongs to.
388 struct GNUNET_PeerIdentity neighbour_id;
391 * Plugin that we used for the transmission.
392 * NULL until we scheduled a transmission.
394 struct TransportPlugin *plugin;
397 * At what time should we fail?
399 struct GNUNET_TIME_Absolute timeout;
402 * Internal message of the transport system that should not be
403 * included in the usual SEND-SEND_OK transmission confirmation
404 * traffic management scheme. Typically, "internal_msg" will
405 * be set whenever "client" is NULL (but it is not strictly
411 * How important is the message?
413 unsigned int priority;
419 * For a given Neighbour, which plugins are available
420 * to talk to this peer and what are their costs?
425 * This is a linked list.
427 struct ReadyList *next;
430 * Which of our transport plugins does this entry
433 struct TransportPlugin *plugin;
436 * Transport addresses, latency, and readiness for
437 * this particular plugin.
439 struct ForeignAddressList *addresses;
442 * To which neighbour does this ready list belong to?
444 struct NeighbourList *neighbour;
450 * Entry in linked list of all of our current neighbours.
456 * This is a linked list.
458 struct NeighbourList *next;
461 * Which of our transports is connected to this peer
462 * and what is their status?
464 struct ReadyList *plugins;
467 * Head of list of messages we would like to send to this peer;
468 * must contain at most one message per client.
470 struct MessageQueue *messages_head;
473 * Tail of list of messages we would like to send to this peer; must
474 * contain at most one message per client.
476 struct MessageQueue *messages_tail;
479 * Buffer for at most one payload message used when we receive
480 * payload data before our PING-PONG has succeeded. We then
481 * store such messages in this intermediary buffer until the
482 * connection is fully up.
484 struct GNUNET_MessageHeader *pre_connect_message_buffer;
487 * Context for peerinfo iteration.
488 * NULL after we are done processing peerinfo's information.
490 struct GNUNET_PEERINFO_IteratorContext *piter;
493 * Public key for this peer. Valid only if the respective flag is set below.
495 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
498 * Identity of this neighbour.
500 struct GNUNET_PeerIdentity id;
503 * ID of task scheduled to run when this peer is about to
504 * time out (will free resources associated with the peer).
506 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
509 * ID of task scheduled to run when we should retry transmitting
510 * the head of the message queue. Actually triggered when the
511 * transmission is timing out (we trigger instantly when we have
512 * a chance of success).
514 GNUNET_SCHEDULER_TaskIdentifier retry_task;
517 * How long until we should consider this peer dead
518 * (if we don't receive another message in the
521 struct GNUNET_TIME_Absolute peer_timeout;
524 * Tracker for inbound bandwidth.
526 struct GNUNET_BANDWIDTH_Tracker in_tracker;
529 * The latency we have seen for this particular address for
530 * this particular peer. This latency may have been calculated
531 * over multiple transports. This value reflects how long it took
532 * us to receive a response when SENDING via this particular
533 * transport/neighbour/address combination!
535 * FIXME: we need to periodically send PINGs to update this
536 * latency (at least more often than the current "huge" (11h?)
539 struct GNUNET_TIME_Relative latency;
542 * How often has the other peer (recently) violated the
543 * inbound traffic limit? Incremented by 10 per violation,
544 * decremented by 1 per non-violation (for each
547 unsigned int quota_violation_count;
550 * DV distance to this peer (1 if no DV is used).
555 * Have we seen an PONG from this neighbour in the past (and
556 * not had a disconnect since)?
561 * Do we have a valid public key for this neighbour?
563 int public_key_valid;
566 * Performance data for the peer.
568 struct GNUNET_TRANSPORT_ATS_Information *ats;
571 * Identity of the neighbour.
573 struct GNUNET_PeerIdentity peer;
578 * Message used to ask a peer to validate receipt (to check an address
579 * from a HELLO). Followed by the address we are trying to validate,
580 * or an empty address if we are just sending a PING to confirm that a
581 * connection which the receiver (of the PING) initiated is still valid.
583 struct TransportPingMessage
587 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
589 struct GNUNET_MessageHeader header;
592 * Challenge code (to ensure fresh reply).
594 uint32_t challenge GNUNET_PACKED;
597 * Who is the intended recipient?
599 struct GNUNET_PeerIdentity target;
605 * Message used to validate a HELLO. The challenge is included in the
606 * confirmation to make matching of replies to requests possible. The
607 * signature signs our public key, an expiration time and our address.<p>
609 * This message is followed by our transport address that the PING tried
610 * to confirm (if we liked it). The address can be empty (zero bytes)
611 * if the PING had not address either (and we received the request via
612 * a connection that we initiated).
614 struct TransportPongMessage
618 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
620 struct GNUNET_MessageHeader header;
623 * Challenge code from PING (showing freshness). Not part of what
624 * is signed so that we can re-use signatures.
626 uint32_t challenge GNUNET_PACKED;
631 struct GNUNET_CRYPTO_RsaSignature signature;
634 * What are we signing and why? Two possible reason codes can be here:
635 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
636 * plausible address for this peer (pid is set to identity of signer); or
637 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
638 * an address we used to connect to the peer with the given pid.
640 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
643 * When does this signature expire?
645 struct GNUNET_TIME_AbsoluteNBO expiration;
648 * Either the identity of the peer Who signed this message, or the
649 * identity of the peer that we're connected to using the given
650 * address (depending on purpose.type).
652 struct GNUNET_PeerIdentity pid;
655 * Size of address appended to this message (part of what is
656 * being signed, hence not redundant).
664 * Linked list of messages to be transmitted to the client. Each
665 * entry is followed by the actual message.
667 struct ClientMessageQueueEntry
670 * This is a doubly-linked list.
672 struct ClientMessageQueueEntry *next;
675 * This is a doubly-linked list.
677 struct ClientMessageQueueEntry *prev;
682 * Client connected to the transport service.
684 struct TransportClient
688 * This is a linked list.
690 struct TransportClient *next;
693 * Handle to the client.
695 struct GNUNET_SERVER_Client *client;
698 * Linked list of messages yet to be transmitted to
701 struct ClientMessageQueueEntry *message_queue_head;
704 * Tail of linked list of messages yet to be transmitted to the
707 struct ClientMessageQueueEntry *message_queue_tail;
710 * Current transmit request handle.
712 struct GNUNET_CONNECTION_TransmitHandle *th;
715 * Is a call to "transmit_send_continuation" pending? If so, we
716 * must not free this struct (even if the corresponding client
717 * disconnects) and instead only remove it from the linked list and
718 * set the "client" field to NULL.
723 * Length of the list of messages pending for this client.
725 unsigned int message_count;
731 * Context of currently active requests to peerinfo
732 * for validation of HELLOs.
734 struct CheckHelloValidatedContext;
738 * Entry in map of all HELLOs awaiting validation.
740 struct ValidationEntry
744 * NULL if this entry is not part of a larger HELLO validation.
746 struct CheckHelloValidatedContext *chvc;
749 * The address, actually a pointer to the end
750 * of this struct. Do not free!
755 * Name of the transport.
757 char *transport_name;
760 * The public key of the peer.
762 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
765 * ID of task that will clean up this entry if we don't succeed
766 * with the validation first.
768 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
771 * At what time did we send this validation?
773 struct GNUNET_TIME_Absolute send_time;
776 * Session being validated (or NULL for none).
778 struct Session *session;
781 * Challenge number we used.
794 * Context of currently active requests to peerinfo
795 * for validation of HELLOs.
797 struct CheckHelloValidatedContext
801 * This is a doubly-linked list.
803 struct CheckHelloValidatedContext *next;
806 * This is a doubly-linked list.
808 struct CheckHelloValidatedContext *prev;
811 * Hello that we are validating.
813 const struct GNUNET_HELLO_Message *hello;
816 * Context for peerinfo iteration.
817 * NULL after we are done processing peerinfo's information.
819 struct GNUNET_PEERINFO_IteratorContext *piter;
822 * Was a HELLO known for this peer to peerinfo?
827 * Number of validation entries currently referring to this
830 unsigned int ve_count;
838 static struct GNUNET_HELLO_Message *our_hello;
843 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
848 static struct GNUNET_PeerIdentity my_identity;
853 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
858 const struct GNUNET_CONFIGURATION_Handle *cfg;
861 * Linked list of all clients to this service.
863 static struct TransportClient *clients;
866 * All loaded plugins.
868 static struct TransportPlugin *plugins;
871 * Handle to peerinfo service.
873 static struct GNUNET_PEERINFO_Handle *peerinfo;
876 * All known neighbours and their HELLOs.
878 static struct NeighbourList *neighbours;
881 * Number of neighbours we'd like to have.
883 static uint32_t max_connect_per_transport;
886 * Head of linked list.
888 static struct CheckHelloValidatedContext *chvc_head;
891 * Tail of linked list.
893 static struct CheckHelloValidatedContext *chvc_tail;
896 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
897 * of the given peer that we are currently validating).
899 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
902 * Handle for reporting statistics.
904 static struct GNUNET_STATISTICS_Handle *stats;
907 * Handle for ats information
909 static struct ATS_info *ats;
912 * The peer specified by the given neighbour has timed-out or a plugin
913 * has disconnected. We may either need to do nothing (other plugins
914 * still up), or trigger a full disconnect and clean up. This
915 * function updates our state and do the necessary notifications.
916 * Also notifies our clients that the neighbour is now officially
919 * @param n the neighbour list entry for the peer
920 * @param check should we just check if all plugins
921 * disconnected or must we ask all plugins to
924 static void disconnect_neighbour (struct NeighbourList *n, int check);
927 * Check the ready list for the given neighbour and if a plugin is
928 * ready for transmission (and if we have a message), do so!
930 * @param neighbour target peer for which to transmit
932 static void try_transmission_to_peer (struct NeighbourList *neighbour);
935 struct ATS_info * ats_init ();
937 void ats_shutdown (struct ATS_info * ats);
939 void ats_notify_peer_connect (struct ATS_info * ats,
940 const struct GNUNET_PeerIdentity *peer,
941 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
943 void ats_notify_peer_disconnect (struct ATS_info * ats,
944 const struct GNUNET_PeerIdentity *peer);
946 void ats_notify_ats_data (struct ATS_info * ats,
947 const struct GNUNET_PeerIdentity *peer,
948 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
951 * Find an entry in the neighbour list for a particular peer.
953 * @return NULL if not found.
955 static struct NeighbourList *
956 find_neighbour (const struct GNUNET_PeerIdentity *key)
958 struct NeighbourList *head = neighbours;
960 while ((head != NULL) &&
961 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
968 * Find an entry in the transport list for a particular transport.
970 * @return NULL if not found.
972 static struct TransportPlugin *
973 find_transport (const char *short_name)
975 struct TransportPlugin *head = plugins;
976 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
982 * Is a particular peer blacklisted for a particular transport?
984 * @param peer the peer to check for
985 * @param plugin the plugin used to connect to the peer
987 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
990 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
993 if (plugin->blacklist != NULL)
995 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
999 "Peer `%s:%s' is blacklisted!\n",
1000 plugin->short_name, GNUNET_i2s (peer));
1003 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1013 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1015 struct TransportPlugin *plugin;
1017 plugin = find_transport(transport_name);
1018 if (plugin == NULL) /* Nothing to do */
1020 if (plugin->blacklist == NULL)
1021 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1022 GNUNET_assert(plugin->blacklist != NULL);
1023 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1025 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1030 * Read the blacklist file, containing transport:peer entries.
1031 * Provided the transport is loaded, set up hashmap with these
1032 * entries to blacklist peers by transport.
1036 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1043 struct GNUNET_PeerIdentity pid;
1045 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1046 unsigned int entries_found;
1047 char *transport_name;
1050 GNUNET_CONFIGURATION_get_value_filename (cfg,
1056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1057 "Option `%s' in section `%s' not specified!\n",
1063 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1064 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1065 | GNUNET_DISK_PERM_USER_WRITE);
1066 if (0 != STAT (fn, &frstat))
1068 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1069 _("Could not read blacklist file `%s'\n"), fn);
1073 if (frstat.st_size == 0)
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 _("Blacklist file `%s' is empty.\n"),
1083 /* FIXME: use mmap */
1084 data = GNUNET_malloc_large (frstat.st_size);
1085 GNUNET_assert(data != NULL);
1086 if (frstat.st_size !=
1087 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1089 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1090 _("Failed to read blacklist from `%s'\n"), fn);
1097 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1099 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1100 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1103 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1106 if (colon_pos >= frstat.st_size)
1108 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1109 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1110 (unsigned long long) colon_pos);
1116 if (isspace( (unsigned char) data[colon_pos]))
1118 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1119 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1120 (unsigned long long) colon_pos);
1122 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1126 tsize = colon_pos - pos;
1127 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1129 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1130 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1131 (unsigned long long) colon_pos);
1140 transport_name = GNUNET_malloc(tsize + 1);
1141 memcpy(transport_name, &data[pos], tsize);
1142 pos = colon_pos + 1;
1144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1145 "Read transport name %s in blacklist file.\n",
1148 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1149 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1151 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1152 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1153 (unsigned long long) pos);
1155 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1157 GNUNET_free_non_null(transport_name);
1160 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1161 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1163 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1164 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1165 (unsigned long long) pos,
1170 if (0 != memcmp (&pid,
1172 sizeof (struct GNUNET_PeerIdentity)))
1175 add_peer_to_blacklist (&pid,
1180 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1181 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1185 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1186 GNUNET_free_non_null(transport_name);
1187 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1190 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1197 * Function called to notify a client about the socket being ready to
1198 * queue more data. "buf" will be NULL and "size" zero if the socket
1199 * was closed for writing in the meantime.
1201 * @param cls closure
1202 * @param size number of bytes available in buf
1203 * @param buf where the callee should write the message
1204 * @return number of bytes written to buf
1207 transmit_to_client_callback (void *cls, size_t size, void *buf)
1209 struct TransportClient *client = cls;
1210 struct ClientMessageQueueEntry *q;
1213 const struct GNUNET_MessageHeader *msg;
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Transmission to client failed, closing connection.\n");
1223 /* fatal error with client, free message queue! */
1224 while (NULL != (q = client->message_queue_head))
1226 GNUNET_STATISTICS_update (stats,
1227 gettext_noop ("# bytes discarded (could not transmit to client)"),
1228 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1230 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1231 client->message_queue_tail,
1235 client->message_count = 0;
1240 while (NULL != (q = client->message_queue_head))
1242 msg = (const struct GNUNET_MessageHeader *) &q[1];
1243 msize = ntohs (msg->size);
1244 if (msize + tsize > size)
1247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1248 "Transmitting message of type %u to client.\n",
1251 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1252 client->message_queue_tail,
1254 memcpy (&cbuf[tsize], msg, msize);
1257 client->message_count--;
1261 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1262 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1264 GNUNET_TIME_UNIT_FOREVER_REL,
1265 &transmit_to_client_callback,
1267 GNUNET_assert (client->th != NULL);
1274 * Convert an address to a string.
1276 * @param plugin name of the plugin responsible for the address
1277 * @param addr binary address
1278 * @param addr_len number of bytes in addr
1279 * @return NULL on error, otherwise address string
1282 a2s (const char *plugin,
1286 struct TransportPlugin *p;
1290 p = find_transport (plugin);
1293 return p->api->address_to_string (p->api->cls,
1300 * Mark the given FAL entry as 'connected' (and hence preferred for
1301 * sending); also mark all others for the same peer as 'not connected'
1302 * (since only one can be preferred).
1304 * @param fal address to set to 'connected'
1307 mark_address_connected (struct ForeignAddressList *fal)
1309 struct ForeignAddressList *pos;
1312 GNUNET_assert (GNUNET_YES == fal->validated);
1313 if (fal->connected == GNUNET_YES)
1314 return; /* nothing to do */
1316 pos = fal->ready_list->addresses;
1319 if (GNUNET_YES == pos->connected)
1322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1324 a2s (pos->ready_list->plugin->short_name,
1328 GNUNET_break (cnt == GNUNET_YES);
1330 pos->connected = GNUNET_NO;
1331 GNUNET_STATISTICS_update (stats,
1332 gettext_noop ("# connected addresses"),
1338 fal->connected = GNUNET_YES;
1339 if (GNUNET_YES == cnt)
1341 GNUNET_STATISTICS_update (stats,
1342 gettext_noop ("# connected addresses"),
1350 * Send the specified message to the specified client. Since multiple
1351 * messages may be pending for the same client at a time, this code
1352 * makes sure that no message is lost.
1354 * @param client client to transmit the message to
1355 * @param msg the message to send
1356 * @param may_drop can this message be dropped if the
1357 * message queue for this client is getting far too large?
1360 transmit_to_client (struct TransportClient *client,
1361 const struct GNUNET_MessageHeader *msg, int may_drop)
1363 struct ClientMessageQueueEntry *q;
1366 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1368 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1370 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1373 client->message_count,
1375 GNUNET_STATISTICS_update (stats,
1376 gettext_noop ("# messages dropped due to slow client"),
1381 msize = ntohs (msg->size);
1382 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1383 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1384 memcpy (&q[1], msg, msize);
1385 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1386 client->message_queue_tail,
1387 client->message_queue_tail,
1389 client->message_count++;
1390 if (client->th == NULL)
1392 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1394 GNUNET_TIME_UNIT_FOREVER_REL,
1395 &transmit_to_client_callback,
1397 GNUNET_assert (client->th != NULL);
1403 * Transmit a 'SEND_OK' notification to the given client for the
1406 * @param client who to notify
1407 * @param n neighbour to notify about, can be NULL (on failure)
1408 * @param target target of the transmission
1409 * @param result status code for the transmission request
1412 transmit_send_ok (struct TransportClient *client,
1413 struct NeighbourList *n,
1414 const struct GNUNET_PeerIdentity *target,
1417 struct SendOkMessage send_ok_msg;
1419 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1420 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1421 send_ok_msg.success = htonl (result);
1423 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1425 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1426 send_ok_msg.peer = *target;
1427 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1432 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1433 * upon "completion" of a send request. This tells the API
1434 * that it is now legal to send another message to the given
1437 * @param cls closure, identifies the entry on the
1438 * message queue that was transmitted and the
1439 * client responsible for queuing the message
1440 * @param target the peer receiving the message
1441 * @param result GNUNET_OK on success, if the transmission
1442 * failed, we should not tell the client to transmit
1446 transmit_send_continuation (void *cls,
1447 const struct GNUNET_PeerIdentity *target,
1450 struct MessageQueue *mq = cls;
1451 struct NeighbourList *n;
1453 GNUNET_STATISTICS_update (stats,
1454 gettext_noop ("# bytes pending with plugins"),
1455 - (int64_t) mq->message_buf_size,
1457 if (result == GNUNET_OK)
1459 GNUNET_STATISTICS_update (stats,
1460 gettext_noop ("# bytes successfully transmitted by plugins"),
1461 mq->message_buf_size,
1466 GNUNET_STATISTICS_update (stats,
1467 gettext_noop ("# bytes with transmission failure by plugins"),
1468 mq->message_buf_size,
1471 if (mq->specific_address != NULL)
1473 if (result == GNUNET_OK)
1475 mq->specific_address->timeout =
1476 GNUNET_TIME_relative_to_absolute
1477 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1478 if (mq->specific_address->validated == GNUNET_YES)
1479 mark_address_connected (mq->specific_address);
1483 if (mq->specific_address->connected != GNUNET_NO)
1486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1487 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1488 a2s (mq->specific_address->ready_list->plugin->short_name,
1489 mq->specific_address->addr,
1490 mq->specific_address->addrlen));
1492 GNUNET_STATISTICS_update (stats,
1493 gettext_noop ("# connected addresses"),
1496 mq->specific_address->connected = GNUNET_NO;
1499 if (! mq->internal_msg)
1500 mq->specific_address->in_transmit = GNUNET_NO;
1502 n = find_neighbour(&mq->neighbour_id);
1503 if (mq->client != NULL)
1504 transmit_send_ok (mq->client, n, target, result);
1507 try_transmission_to_peer (n);
1512 * Find an address in any of the available transports for
1513 * the given neighbour that would be good for message
1514 * transmission. This is essentially the transport selection
1517 * @param neighbour for whom to select an address
1518 * @return selected address, NULL if we have none
1520 struct ForeignAddressList *
1521 find_ready_address(struct NeighbourList *neighbour)
1523 struct ReadyList *head = neighbour->plugins;
1524 struct ForeignAddressList *addresses;
1525 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1526 struct ForeignAddressList *best_address;
1528 best_address = NULL;
1529 while (head != NULL)
1531 addresses = head->addresses;
1532 while (addresses != NULL)
1534 if ( (addresses->timeout.abs_value < now.abs_value) &&
1535 (addresses->connected == GNUNET_YES) )
1538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1539 "Marking long-time inactive connection to `%4s' as down.\n",
1540 GNUNET_i2s (&neighbour->id));
1542 GNUNET_STATISTICS_update (stats,
1543 gettext_noop ("# connected addresses"),
1546 addresses->connected = GNUNET_NO;
1548 addresses = addresses->next;
1551 addresses = head->addresses;
1552 while (addresses != NULL)
1554 #if DEBUG_TRANSPORT > 1
1555 if (addresses->addr != NULL)
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1558 a2s (head->plugin->short_name,
1560 addresses->addrlen),
1561 GNUNET_i2s (&neighbour->id),
1562 addresses->connected,
1563 addresses->in_transmit,
1564 addresses->validated,
1565 addresses->connect_attempts,
1566 (unsigned long long) addresses->timeout.abs_value,
1567 (unsigned int) addresses->distance);
1569 if ( ( (best_address == NULL) ||
1570 (addresses->connected == GNUNET_YES) ||
1571 (best_address->connected == GNUNET_NO) ) &&
1572 (addresses->in_transmit == GNUNET_NO) &&
1573 ( (best_address == NULL) ||
1574 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1575 best_address = addresses;
1576 /* FIXME: also give lower-latency addresses that are not
1577 connected a chance some times... */
1578 addresses = addresses->next;
1582 if (best_address != NULL)
1585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1586 "Best address found (`%s') has latency of %llu ms.\n",
1587 (best_address->addrlen > 0)
1588 ? a2s (best_address->ready_list->plugin->short_name,
1590 best_address->addrlen)
1592 best_address->latency.rel_value);
1597 GNUNET_STATISTICS_update (stats,
1598 gettext_noop ("# transmission attempts failed (no address)"),
1602 return best_address;
1608 * We should re-try transmitting to the given peer,
1609 * hopefully we've learned something in the meantime.
1612 retry_transmission_task (void *cls,
1613 const struct GNUNET_SCHEDULER_TaskContext *tc)
1615 struct NeighbourList *n = cls;
1617 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1618 try_transmission_to_peer (n);
1623 * Check the ready list for the given neighbour and if a plugin is
1624 * ready for transmission (and if we have a message), do so!
1626 * @param neighbour target peer for which to transmit
1629 try_transmission_to_peer (struct NeighbourList *neighbour)
1631 struct ReadyList *rl;
1632 struct MessageQueue *mq;
1633 struct GNUNET_TIME_Relative timeout;
1637 if (neighbour->messages_head == NULL)
1640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1641 "Transmission queue for `%4s' is empty\n",
1642 GNUNET_i2s (&neighbour->id));
1644 return; /* nothing to do */
1647 mq = neighbour->messages_head;
1648 force_address = GNUNET_YES;
1649 if (mq->specific_address == NULL)
1652 mq->specific_address = find_ready_address(neighbour);
1653 GNUNET_STATISTICS_update (stats,
1654 gettext_noop ("# transport selected peer address freely"),
1657 force_address = GNUNET_NO;
1659 if (mq->specific_address == NULL)
1661 GNUNET_STATISTICS_update (stats,
1662 gettext_noop ("# transport failed to selected peer address"),
1665 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1666 if (timeout.rel_value == 0)
1669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1670 "No destination address available to transmit message of size %u to peer `%4s'\n",
1671 mq->message_buf_size,
1672 GNUNET_i2s (&mq->neighbour_id));
1674 GNUNET_STATISTICS_update (stats,
1675 gettext_noop ("# bytes in message queue for other peers"),
1676 - (int64_t) mq->message_buf_size,
1678 GNUNET_STATISTICS_update (stats,
1679 gettext_noop ("# bytes discarded (no destination address available)"),
1680 mq->message_buf_size,
1682 if (mq->client != NULL)
1683 transmit_send_ok (mq->client, neighbour, &neighbour->id, GNUNET_NO);
1684 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1685 neighbour->messages_tail,
1688 return; /* nobody ready */
1690 GNUNET_STATISTICS_update (stats,
1691 gettext_noop ("# message delivery deferred (no address)"),
1694 if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1695 GNUNET_SCHEDULER_cancel (neighbour->retry_task);
1696 neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1697 &retry_transmission_task,
1700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1701 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1702 mq->message_buf_size,
1703 GNUNET_i2s (&mq->neighbour_id),
1706 /* FIXME: might want to trigger peerinfo lookup here
1707 (unless that's already pending...) */
1710 GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1711 neighbour->messages_tail,
1713 if (mq->specific_address->connected == GNUNET_NO)
1714 mq->specific_address->connect_attempts++;
1715 rl = mq->specific_address->ready_list;
1716 mq->plugin = rl->plugin;
1717 if (!mq->internal_msg)
1718 mq->specific_address->in_transmit = GNUNET_YES;
1720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1721 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1722 mq->message_buf_size,
1723 GNUNET_i2s (&neighbour->id),
1724 (mq->specific_address->addr != NULL)
1725 ? a2s (mq->plugin->short_name,
1726 mq->specific_address->addr,
1727 mq->specific_address->addrlen)
1729 rl->plugin->short_name);
1731 GNUNET_STATISTICS_update (stats,
1732 gettext_noop ("# bytes in message queue for other peers"),
1733 - (int64_t) mq->message_buf_size,
1735 GNUNET_STATISTICS_update (stats,
1736 gettext_noop ("# bytes pending with plugins"),
1737 mq->message_buf_size,
1739 ret = rl->plugin->api->send (rl->plugin->api->cls,
1742 mq->message_buf_size,
1744 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1745 mq->specific_address->session,
1746 mq->specific_address->addr,
1747 mq->specific_address->addrlen,
1749 &transmit_send_continuation, mq);
1752 /* failure, but 'send' would not call continuation in this case,
1753 so we need to do it here! */
1754 transmit_send_continuation (mq,
1762 * Send the specified message to the specified peer.
1764 * @param client source of the transmission request (can be NULL)
1765 * @param peer_address ForeignAddressList where we should send this message
1766 * @param priority how important is the message
1767 * @param timeout how long do we have to transmit?
1768 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1769 * @param message_buf_size total size of all messages in message_buf
1770 * @param is_internal is this an internal message; these are pre-pended and
1771 * also do not count for plugins being "ready" to transmit
1772 * @param neighbour handle to the neighbour for transmission
1775 transmit_to_peer (struct TransportClient *client,
1776 struct ForeignAddressList *peer_address,
1777 unsigned int priority,
1778 struct GNUNET_TIME_Relative timeout,
1779 const char *message_buf,
1780 size_t message_buf_size,
1781 int is_internal, struct NeighbourList *neighbour)
1783 struct MessageQueue *mq;
1788 /* check for duplicate submission */
1789 mq = neighbour->messages_head;
1792 if (mq->client == client)
1794 /* client transmitted to same peer twice
1795 before getting SEND_OK! */
1803 GNUNET_STATISTICS_update (stats,
1804 gettext_noop ("# bytes in message queue for other peers"),
1807 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1808 mq->specific_address = peer_address;
1809 mq->client = client;
1810 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1811 memcpy (&mq[1], message_buf, message_buf_size);
1812 mq->message_buf = (const char*) &mq[1];
1813 mq->message_buf_size = message_buf_size;
1814 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1815 mq->internal_msg = is_internal;
1816 mq->priority = priority;
1817 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1819 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1820 neighbour->messages_tail,
1823 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1824 neighbour->messages_tail,
1825 neighbour->messages_tail,
1827 try_transmission_to_peer (neighbour);
1834 struct GeneratorContext
1836 struct TransportPlugin *plug_pos;
1837 struct OwnAddressList *addr_pos;
1838 struct GNUNET_TIME_Absolute expiration;
1846 address_generator (void *cls, size_t max, void *buf)
1848 struct GeneratorContext *gc = cls;
1851 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1853 gc->plug_pos = gc->plug_pos->next;
1854 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1856 if (NULL == gc->plug_pos)
1861 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1864 gc->addr_pos->addrlen, buf, max);
1865 gc->addr_pos = gc->addr_pos->next;
1871 * Construct our HELLO message from all of the addresses of
1872 * all of the transports.
1877 struct GNUNET_HELLO_Message *hello;
1878 struct TransportClient *cpos;
1879 struct NeighbourList *npos;
1880 struct GeneratorContext gc;
1882 gc.plug_pos = plugins;
1883 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1884 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1885 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1888 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1890 GNUNET_STATISTICS_update (stats,
1891 gettext_noop ("# refreshed my HELLO"),
1895 while (cpos != NULL)
1897 transmit_to_client (cpos,
1898 (const struct GNUNET_MessageHeader *) hello,
1903 GNUNET_free_non_null (our_hello);
1905 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1907 while (npos != NULL)
1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1911 "Transmitting updated `%s' to neighbour `%4s'\n",
1912 "HELLO", GNUNET_i2s (&npos->id));
1914 GNUNET_STATISTICS_update (stats,
1915 gettext_noop ("# transmitted my HELLO to other peers"),
1918 transmit_to_peer (NULL, NULL, 0,
1919 HELLO_ADDRESS_EXPIRATION,
1920 (const char *) our_hello,
1921 GNUNET_HELLO_size(our_hello),
1929 * Task used to clean up expired addresses for a plugin.
1931 * @param cls closure
1935 expire_address_task (void *cls,
1936 const struct GNUNET_SCHEDULER_TaskContext *tc);
1940 * Update the list of addresses for this plugin,
1941 * expiring those that are past their expiration date.
1943 * @param plugin addresses of which plugin should be recomputed?
1944 * @param fresh set to GNUNET_YES if a new address was added
1945 * and we need to regenerate the HELLO even if nobody
1949 update_addresses (struct TransportPlugin *plugin,
1952 static struct GNUNET_TIME_Absolute last_update;
1953 struct GNUNET_TIME_Relative min_remaining;
1954 struct GNUNET_TIME_Relative remaining;
1955 struct GNUNET_TIME_Absolute now;
1956 struct OwnAddressList *pos;
1957 struct OwnAddressList *prev;
1958 struct OwnAddressList *next;
1961 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1962 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1963 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1964 now = GNUNET_TIME_absolute_get ();
1965 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1966 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
1968 pos = plugin->addresses;
1972 if (pos->expires.abs_value < now.abs_value)
1974 expired = GNUNET_YES;
1976 plugin->addresses = pos->next;
1978 prev->next = pos->next;
1983 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1984 if (remaining.rel_value < min_remaining.rel_value)
1985 min_remaining = remaining;
1991 if (expired || fresh)
1996 min_remaining = GNUNET_TIME_relative_min (min_remaining,
1997 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1999 plugin->address_update_task
2000 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2001 &expire_address_task, plugin);
2006 * Task used to clean up expired addresses for a plugin.
2008 * @param cls closure
2012 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2014 struct TransportPlugin *plugin = cls;
2016 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2017 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2018 update_addresses (plugin, GNUNET_NO);
2023 * Iterator over hash map entries that NULLs the session of validation
2024 * entries that match the given session.
2026 * @param cls closure (the 'struct Session*' to match against)
2027 * @param key current key code (peer ID, not used)
2028 * @param value value in the hash map ('struct ValidationEntry*')
2029 * @return GNUNET_YES (we should continue to iterate)
2032 remove_session_validations (void *cls,
2033 const GNUNET_HashCode * key,
2036 struct Session *session = cls;
2037 struct ValidationEntry *ve = value;
2039 if (session == ve->session)
2046 * We've been disconnected from the other peer (for some
2047 * connection-oriented transport). Either quickly
2048 * re-establish the connection or signal the disconnect
2051 * Only signal CORE level disconnect if ALL addresses
2052 * for the peer are exhausted.
2054 * @param p overall plugin context
2055 * @param nl neighbour that was disconnected
2058 try_fast_reconnect (struct TransportPlugin *p,
2059 struct NeighbourList *nl)
2061 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2062 /* Note: the idea here is to hide problems with transports (or
2063 switching between plugins) from the core to eliminate the need to
2064 re-negotiate session keys and the like; OTOH, we should tell core
2065 quickly (much faster than timeout) `if a connection was lost and
2066 could not be re-established (i.e. other peer went down or is
2067 unable / refuses to communicate);
2069 So we should consider:
2070 1) ideally: our own willingness / need to connect
2071 2) prior failures to connect to this peer (by plugin)
2072 3) ideally: reasons why other peer terminated (as far as knowable)
2074 Most importantly, it must be POSSIBLE for another peer to terminate
2075 a connection for a while (without us instantly re-establishing it).
2076 Similarly, if another peer is gone we should quickly notify CORE.
2077 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2078 on the other end), we should reconnect in such a way that BOTH CORE
2079 services never even notice.
2080 Furthermore, the same mechanism (or small variation) could be used
2081 to switch to a better-performing plugin (ATS).
2083 Finally, this needs to be tested throughly... */
2086 * GNUNET_NO in the call below makes transport disconnect the peer,
2087 * even if only a single address (out of say, six) went away. This
2088 * function must be careful to ONLY disconnect if the peer is gone,
2089 * not just a specifi address.
2091 * More specifically, half the places it was used had it WRONG.
2094 /* No reconnect, signal disconnect instead! */
2095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2096 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2097 "try_fast_reconnect");
2098 disconnect_neighbour (nl, GNUNET_YES);
2103 * Function that will be called whenever the plugin internally
2104 * cleans up a session pointer and hence the service needs to
2105 * discard all of those sessions as well. Plugins that do not
2106 * use sessions can simply omit calling this function and always
2107 * use NULL wherever a session pointer is needed.
2109 * @param cls closure
2110 * @param peer which peer was the session for
2111 * @param session which session is being destoyed
2114 plugin_env_session_end (void *cls,
2115 const struct GNUNET_PeerIdentity *peer,
2116 struct Session *session)
2118 struct TransportPlugin *p = cls;
2119 struct NeighbourList *nl;
2120 struct ReadyList *rl;
2121 struct ForeignAddressList *pos;
2122 struct ForeignAddressList *prev;
2124 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2125 &remove_session_validations,
2127 nl = find_neighbour (peer);
2129 return; /* was never marked as connected */
2133 if (rl->plugin == p)
2138 return; /* was never marked as connected */
2140 pos = rl->addresses;
2141 while ( (pos != NULL) &&
2142 (pos->session != session) )
2148 return; /* was never marked as connected */
2149 pos->session = NULL;
2150 if (pos->addrlen != 0)
2152 if (nl->received_pong != GNUNET_NO)
2153 try_fast_reconnect (p, nl);
2156 /* was inbound connection, free 'pos' */
2158 rl->addresses = pos->next;
2160 prev->next = pos->next;
2161 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2163 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2164 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2167 if (nl->received_pong == GNUNET_NO)
2168 return; /* nothing to do, never connected... */
2169 /* check if we have any validated addresses left */
2170 pos = rl->addresses;
2175 try_fast_reconnect (p, nl);
2180 /* no valid addresses left, signal disconnect! */
2182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2183 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2184 "plugin_env_session_end");
2185 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2186 * it means there aren't any left for this PLUGIN/PEER combination! So
2187 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2188 * when it isn't necessary. Using GNUNET_YES at least checks to see
2189 * if there are any addresses that work first, so as not to overdo it.
2192 disconnect_neighbour (nl, GNUNET_YES);
2197 * Function that must be called by each plugin to notify the
2198 * transport service about the addresses under which the transport
2199 * provided by the plugin can be reached.
2201 * @param cls closure
2202 * @param name name of the transport that generated the address
2203 * @param addr one of the addresses of the host, NULL for the last address
2204 * the specific address format depends on the transport
2205 * @param addrlen length of the address
2206 * @param expires when should this address automatically expire?
2209 plugin_env_notify_address (void *cls,
2213 struct GNUNET_TIME_Relative expires)
2215 struct TransportPlugin *p = cls;
2216 struct OwnAddressList *al;
2217 struct GNUNET_TIME_Absolute abex;
2219 GNUNET_assert (addr != NULL);
2220 abex = GNUNET_TIME_relative_to_absolute (expires);
2221 GNUNET_assert (p == find_transport (name));
2225 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2228 update_addresses (p, GNUNET_NO);
2234 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2235 al->next = p->addresses;
2238 al->addrlen = addrlen;
2239 memcpy (&al[1], addr, addrlen);
2240 update_addresses (p, GNUNET_YES);
2245 * Notify all of our clients about a peer connecting.
2248 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2249 struct GNUNET_TIME_Relative latency,
2252 struct ConnectInfoMessage * cim;
2253 struct TransportClient *cpos;
2258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2259 "Notifying clients about connection from `%s'\n",
2262 GNUNET_STATISTICS_update (stats,
2263 gettext_noop ("# peers connected"),
2268 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2269 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2273 cim = GNUNET_malloc (size);
2275 cim->header.size = htons (size);
2276 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2277 cim->ats_count = htonl(2);
2278 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2279 (&(cim->ats))[0].value = htonl (distance);
2280 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2281 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2282 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2283 (&(cim->ats))[2].value = htonl (0);
2284 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2286 /* notify ats about connecting peer */
2287 ats_notify_peer_connect(ats, peer, &(cim->ats));
2290 while (cpos != NULL)
2292 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2301 * Notify all of our clients about a peer disconnecting.
2304 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2306 struct DisconnectInfoMessage dim;
2307 struct TransportClient *cpos;
2310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2311 "Notifying clients about lost connection to `%s'\n",
2314 GNUNET_STATISTICS_update (stats,
2315 gettext_noop ("# peers connected"),
2318 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2319 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2320 dim.reserved = htonl (0);
2321 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2323 /* notify ats about connecting peer */
2324 ats_notify_peer_disconnect(ats, peer);
2327 while (cpos != NULL)
2329 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2336 * Find a ForeignAddressList entry for the given neighbour
2337 * that matches the given address and transport.
2339 * @param neighbour which peer we care about
2340 * @param tname name of the transport plugin
2341 * @param session session to look for, NULL for 'any'; otherwise
2342 * can be used for the service to "learn" this session ID
2344 * @param addr binary address
2345 * @param addrlen length of addr
2346 * @return NULL if no such entry exists
2348 static struct ForeignAddressList *
2349 find_peer_address(struct NeighbourList *neighbour,
2351 struct Session *session,
2355 struct ReadyList *head;
2356 struct ForeignAddressList *pos;
2358 head = neighbour->plugins;
2359 while (head != NULL)
2361 if (0 == strcmp (tname, head->plugin->short_name))
2367 pos = head->addresses;
2368 while ( (pos != NULL) &&
2369 ( (pos->addrlen != addrlen) ||
2370 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2372 if ( (session != NULL) &&
2373 (pos->session == session) )
2377 if ( (session != NULL) && (pos != NULL) )
2378 pos->session = session; /* learn it! */
2384 * Get the peer address struct for the given neighbour and
2385 * address. If it doesn't yet exist, create it.
2387 * @param neighbour which peer we care about
2388 * @param tname name of the transport plugin
2389 * @param session session of the plugin, or NULL for none
2390 * @param addr binary address
2391 * @param addrlen length of addr
2392 * @return NULL if we do not have a transport plugin for 'tname'
2394 static struct ForeignAddressList *
2395 add_peer_address (struct NeighbourList *neighbour,
2397 struct Session *session,
2401 struct ReadyList *head;
2402 struct ForeignAddressList *ret;
2404 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2407 head = neighbour->plugins;
2409 while (head != NULL)
2411 if (0 == strcmp (tname, head->plugin->short_name))
2417 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2418 ret->session = session;
2421 ret->addr = (const char*) &ret[1];
2422 memcpy (&ret[1], addr, addrlen);
2428 ret->addrlen = addrlen;
2429 ret->expires = GNUNET_TIME_relative_to_absolute
2430 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2431 ret->latency = GNUNET_TIME_relative_get_forever();
2433 ret->timeout = GNUNET_TIME_relative_to_absolute
2434 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2435 ret->ready_list = head;
2436 ret->next = head->addresses;
2437 head->addresses = ret;
2443 * Closure for 'add_validated_address'.
2445 struct AddValidatedAddressContext
2448 * Entry that has been validated.
2450 const struct ValidationEntry *ve;
2453 * Flag set after we have added the address so
2454 * that we terminate the iteration next time.
2461 * Callback function used to fill a buffer of max bytes with a list of
2462 * addresses in the format used by HELLOs. Should use
2463 * "GNUNET_HELLO_add_address" as a helper function.
2465 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2466 * @param max maximum number of bytes that can be written to buf
2467 * @param buf where to write the address information
2468 * @return number of bytes written, 0 to signal the
2469 * end of the iteration.
2472 add_validated_address (void *cls,
2473 size_t max, void *buf)
2475 struct AddValidatedAddressContext *avac = cls;
2476 const struct ValidationEntry *ve = avac->ve;
2478 if (GNUNET_YES == avac->done)
2480 avac->done = GNUNET_YES;
2481 return GNUNET_HELLO_add_address (ve->transport_name,
2482 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2492 * Closure for 'check_address_exists'.
2494 struct CheckAddressExistsClosure
2497 * Address to check for.
2502 * Name of the transport.
2509 struct Session *session;
2512 * Set to GNUNET_YES if the address exists.
2525 * Iterator over hash map entries. Checks if the given
2526 * validation entry is for the same address as what is given
2529 * @param cls the 'struct CheckAddressExistsClosure*'
2530 * @param key current key code (ignored)
2531 * @param value value in the hash map ('struct ValidationEntry')
2532 * @return GNUNET_YES if we should continue to
2533 * iterate (mismatch), GNUNET_NO if not (entry matched)
2536 check_address_exists (void *cls,
2537 const GNUNET_HashCode * key,
2540 struct CheckAddressExistsClosure *caec = cls;
2541 struct ValidationEntry *ve = value;
2543 if ( (0 == strcmp (caec->tname,
2544 ve->transport_name)) &&
2545 (caec->addrlen == ve->addrlen) &&
2546 (0 == memcmp (caec->addr,
2550 caec->exists = GNUNET_YES;
2553 if ( (ve->session != NULL) &&
2554 (caec->session == ve->session) )
2556 caec->exists = GNUNET_YES;
2565 * Iterator to free entries in the validation_map.
2567 * @param cls closure (unused)
2568 * @param key current key code
2569 * @param value value in the hash map (validation to abort)
2570 * @return GNUNET_YES (always)
2573 abort_validation (void *cls,
2574 const GNUNET_HashCode * key,
2577 struct ValidationEntry *va = value;
2579 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2580 GNUNET_SCHEDULER_cancel (va->timeout_task);
2581 GNUNET_free (va->transport_name);
2582 if (va->chvc != NULL)
2584 va->chvc->ve_count--;
2585 if (va->chvc->ve_count == 0)
2587 GNUNET_CONTAINER_DLL_remove (chvc_head,
2590 GNUNET_free (va->chvc);
2600 * HELLO validation cleanup task (validation failed).
2602 * @param cls the 'struct ValidationEntry' that failed
2603 * @param tc scheduler context (unused)
2606 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2608 struct ValidationEntry *va = cls;
2609 struct GNUNET_PeerIdentity pid;
2611 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2612 GNUNET_STATISTICS_update (stats,
2613 gettext_noop ("# address validation timeouts"),
2616 GNUNET_CRYPTO_hash (&va->publicKey,
2618 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2620 GNUNET_break (GNUNET_OK ==
2621 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2624 abort_validation (NULL, NULL, va);
2629 neighbour_timeout_task (void *cls,
2630 const struct GNUNET_SCHEDULER_TaskContext *tc)
2632 struct NeighbourList *n = cls;
2635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2636 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2638 GNUNET_STATISTICS_update (stats,
2639 gettext_noop ("# disconnects due to timeout"),
2642 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2643 disconnect_neighbour (n, GNUNET_NO);
2648 * Schedule the job that will cause us to send a PING to the
2649 * foreign address to evaluate its validity and latency.
2651 * @param fal address to PING
2654 schedule_next_ping (struct ForeignAddressList *fal);
2658 * Add the given address to the list of foreign addresses
2659 * available for the given peer (check for duplicates).
2661 * @param cls the respective 'struct NeighbourList' to update
2662 * @param tname name of the transport
2663 * @param expiration expiration time
2664 * @param addr the address
2665 * @param addrlen length of the address
2666 * @return GNUNET_OK (always)
2669 add_to_foreign_address_list (void *cls,
2671 struct GNUNET_TIME_Absolute expiration,
2675 struct NeighbourList *n = cls;
2676 struct ForeignAddressList *fal;
2679 GNUNET_STATISTICS_update (stats,
2680 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2684 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2687 #if DEBUG_TRANSPORT_HELLO
2688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2689 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2690 a2s (tname, addr, addrlen),
2692 GNUNET_i2s (&n->id),
2693 expiration.abs_value);
2695 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2698 GNUNET_STATISTICS_update (stats,
2699 gettext_noop ("# previously validated addresses lacking transport"),
2705 fal->expires = GNUNET_TIME_absolute_max (expiration,
2707 schedule_next_ping (fal);
2713 fal->expires = GNUNET_TIME_absolute_max (expiration,
2718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2719 "Failed to add new address for `%4s'\n",
2720 GNUNET_i2s (&n->id));
2723 if (fal->validated == GNUNET_NO)
2725 fal->validated = GNUNET_YES;
2726 GNUNET_STATISTICS_update (stats,
2727 gettext_noop ("# peer addresses considered valid"),
2731 if (try == GNUNET_YES)
2733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2734 "Have new addresses, will try to trigger transmissions.\n");
2735 try_transmission_to_peer (n);
2742 * Add addresses in validated HELLO "h" to the set of addresses
2743 * we have for this peer.
2745 * @param cls closure ('struct NeighbourList*')
2746 * @param peer id of the peer, NULL for last call
2747 * @param h hello message for the peer (can be NULL)
2748 * @param err_msg NULL if successful, otherwise contains error message
2751 add_hello_for_peer (void *cls,
2752 const struct GNUNET_PeerIdentity *peer,
2753 const struct GNUNET_HELLO_Message *h,
2754 const char *err_msg)
2756 struct NeighbourList *n = cls;
2758 if (err_msg != NULL)
2760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2761 _("Error in communication with PEERINFO service\n"));
2766 GNUNET_STATISTICS_update (stats,
2767 gettext_noop ("# outstanding peerinfo iterate requests"),
2774 return; /* no HELLO available */
2776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2777 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2781 if (GNUNET_YES != n->public_key_valid)
2783 GNUNET_HELLO_get_key (h, &n->publicKey);
2784 n->public_key_valid = GNUNET_YES;
2786 GNUNET_HELLO_iterate_addresses (h,
2788 &add_to_foreign_address_list,
2794 * Create a fresh entry in our neighbour list for the given peer.
2795 * Will try to transmit our current HELLO to the new neighbour.
2796 * Do not call this function directly, use 'setup_peer_check_blacklist.
2798 * @param peer the peer for which we create the entry
2799 * @param do_hello should we schedule transmitting a HELLO
2800 * @return the new neighbour list entry
2802 static struct NeighbourList *
2803 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2806 struct NeighbourList *n;
2807 struct TransportPlugin *tp;
2808 struct ReadyList *rl;
2811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2812 "Setting up state for neighbour `%4s'\n",
2815 GNUNET_assert (our_hello != NULL);
2816 GNUNET_STATISTICS_update (stats,
2817 gettext_noop ("# active neighbours"),
2820 n = GNUNET_malloc (sizeof (struct NeighbourList));
2821 n->next = neighbours;
2825 GNUNET_TIME_relative_to_absolute
2826 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2827 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2828 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2829 MAX_BANDWIDTH_CARRY_S);
2833 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2835 rl = GNUNET_malloc (sizeof (struct ReadyList));
2837 rl->next = n->plugins;
2840 rl->addresses = NULL;
2844 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2846 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2847 &neighbour_timeout_task, n);
2850 GNUNET_STATISTICS_update (stats,
2851 gettext_noop ("# peerinfo new neighbor iterate requests"),
2854 GNUNET_STATISTICS_update (stats,
2855 gettext_noop ("# outstanding peerinfo iterate requests"),
2858 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2859 GNUNET_TIME_UNIT_FOREVER_REL,
2860 &add_hello_for_peer, n);
2862 GNUNET_STATISTICS_update (stats,
2863 gettext_noop ("# HELLO's sent to new neighbors"),
2866 transmit_to_peer (NULL, NULL, 0,
2867 HELLO_ADDRESS_EXPIRATION,
2868 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2876 * Function called after we have checked if communicating
2877 * with a given peer is acceptable.
2879 * @param cls closure
2880 * @param n NULL if communication is not acceptable
2882 typedef void (*SetupContinuation)(void *cls,
2883 struct NeighbourList *n);
2887 * Information kept for each client registered to perform
2893 * This is a linked list.
2895 struct Blacklisters *next;
2898 * This is a linked list.
2900 struct Blacklisters *prev;
2903 * Client responsible for this entry.
2905 struct GNUNET_SERVER_Client *client;
2908 * Blacklist check that we're currently performing.
2910 struct BlacklistCheck *bc;
2916 * Head of DLL of blacklisting clients.
2918 static struct Blacklisters *bl_head;
2921 * Tail of DLL of blacklisting clients.
2923 static struct Blacklisters *bl_tail;
2927 * Context we use when performing a blacklist check.
2929 struct BlacklistCheck
2933 * This is a linked list.
2935 struct BlacklistCheck *next;
2938 * This is a linked list.
2940 struct BlacklistCheck *prev;
2943 * Peer being checked.
2945 struct GNUNET_PeerIdentity peer;
2948 * Option for setup neighbour afterwards.
2953 * Continuation to call with the result.
2955 SetupContinuation cont;
2963 * Current transmission request handle for this client, or NULL if no
2964 * request is pending.
2966 struct GNUNET_CONNECTION_TransmitHandle *th;
2969 * Our current position in the blacklisters list.
2971 struct Blacklisters *bl_pos;
2974 * Current task performing the check.
2976 GNUNET_SCHEDULER_TaskIdentifier task;
2981 * Head of DLL of active blacklisting queries.
2983 static struct BlacklistCheck *bc_head;
2986 * Tail of DLL of active blacklisting queries.
2988 static struct BlacklistCheck *bc_tail;
2992 * Perform next action in the blacklist check.
2994 * @param cls the 'struct BlacklistCheck*'
2998 do_blacklist_check (void *cls,
2999 const struct GNUNET_SCHEDULER_TaskContext *tc);
3002 * Transmit blacklist query to the client.
3004 * @param cls the 'struct BlacklistCheck'
3005 * @param size number of bytes allowed
3006 * @param buf where to copy the message
3007 * @return number of bytes copied to buf
3010 transmit_blacklist_message (void *cls,
3014 struct BlacklistCheck *bc = cls;
3015 struct Blacklisters *bl;
3016 struct BlacklistMessage bm;
3021 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3022 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3027 bm.header.size = htons (sizeof (struct BlacklistMessage));
3028 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3029 bm.is_allowed = htonl (0);
3031 memcpy (buf, &bm, sizeof (bm));
3032 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3038 * Perform next action in the blacklist check.
3040 * @param cls the 'struct BlacklistCheck*'
3044 do_blacklist_check (void *cls,
3045 const struct GNUNET_SCHEDULER_TaskContext *tc)
3047 struct BlacklistCheck *bc = cls;
3048 struct Blacklisters *bl;
3050 bc->task = GNUNET_SCHEDULER_NO_TASK;
3054 bc->cont (bc->cont_cls,
3055 setup_new_neighbour (&bc->peer, bc->do_hello));
3062 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3063 sizeof (struct BlacklistMessage),
3064 GNUNET_TIME_UNIT_FOREVER_REL,
3065 &transmit_blacklist_message,
3072 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3073 * does not yet exist, check the blacklist. If the blacklist says creating
3074 * one is acceptable, create one and call the continuation; otherwise
3075 * call the continuation with NULL.
3077 * @param peer peer to setup or look up a struct NeighbourList for
3078 * @param do_hello should we also schedule sending our HELLO to the peer
3079 * if this is a new record
3080 * @param cont function to call with the 'struct NeigbhbourList*'
3081 * @param cont_cls closure for cont
3084 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3086 SetupContinuation cont,
3089 struct NeighbourList *n;
3090 struct BlacklistCheck *bc;
3092 n = find_neighbour(peer);
3099 if (bl_head == NULL)
3102 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3104 setup_new_neighbour(peer, do_hello);
3107 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3108 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3110 bc->do_hello = do_hello;
3112 bc->cont_cls = cont_cls;
3113 bc->bl_pos = bl_head;
3114 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3120 * Function called with the result of querying a new blacklister about
3121 * it being allowed (or not) to continue to talk to an existing neighbour.
3123 * @param cls the original 'struct NeighbourList'
3124 * @param n NULL if we need to disconnect
3127 confirm_or_drop_neighbour (void *cls,
3128 struct NeighbourList *n)
3130 struct NeighbourList * orig = cls;
3134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3135 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3136 "confirm_or_drop_neighboUr");
3137 disconnect_neighbour (orig, GNUNET_NO);
3143 * Handle a request to start a blacklist.
3145 * @param cls closure (always NULL)
3146 * @param client identification of the client
3147 * @param message the actual message
3150 handle_blacklist_init (void *cls,
3151 struct GNUNET_SERVER_Client *client,
3152 const struct GNUNET_MessageHeader *message)
3154 struct Blacklisters *bl;
3155 struct BlacklistCheck *bc;
3156 struct NeighbourList *n;
3161 if (bl->client == client)
3164 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3169 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3170 bl->client = client;
3171 GNUNET_SERVER_client_keep (client);
3172 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3173 /* confirm that all existing connections are OK! */
3177 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3178 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3180 bc->do_hello = GNUNET_NO;
3181 bc->cont = &confirm_or_drop_neighbour;
3184 if (n == neighbours) /* all would wait for the same client, no need to
3185 create more than just the first task right now */
3186 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3194 * Handle a request to blacklist a peer.
3196 * @param cls closure (always NULL)
3197 * @param client identification of the client
3198 * @param message the actual message
3201 handle_blacklist_reply (void *cls,
3202 struct GNUNET_SERVER_Client *client,
3203 const struct GNUNET_MessageHeader *message)
3205 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3206 struct Blacklisters *bl;
3207 struct BlacklistCheck *bc;
3210 while ( (bl != NULL) &&
3211 (bl->client != client) )
3215 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3220 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3222 bc->cont (bc->cont_cls, NULL);
3223 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3228 bc->bl_pos = bc->bl_pos->next;
3229 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3232 /* check if any other bc's are waiting for this blacklister */
3236 if ( (bc->bl_pos == bl) &&
3237 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3238 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3246 * Send periodic PING messages to a given foreign address.
3248 * @param cls our 'struct PeriodicValidationContext*'
3249 * @param tc task context
3252 send_periodic_ping (void *cls,
3253 const struct GNUNET_SCHEDULER_TaskContext *tc)
3255 struct ForeignAddressList *peer_address = cls;
3256 struct TransportPlugin *tp;
3257 struct ValidationEntry *va;
3258 struct NeighbourList *neighbour;
3259 struct TransportPingMessage ping;
3260 struct CheckAddressExistsClosure caec;
3262 uint16_t hello_size;
3266 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3267 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3269 tp = peer_address->ready_list->plugin;
3270 neighbour = peer_address->ready_list->neighbour;
3271 if (GNUNET_YES != neighbour->public_key_valid)
3273 /* no public key yet, try again later */
3274 schedule_next_ping (peer_address);
3277 caec.addr = peer_address->addr;
3278 caec.addrlen = peer_address->addrlen;
3279 caec.tname = tp->short_name;
3280 caec.session = peer_address->session;
3281 caec.exists = GNUNET_NO;
3282 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3283 &check_address_exists,
3285 if (caec.exists == GNUNET_YES)
3287 /* During validation attempts we will likely trigger the other
3288 peer trying to validate our address which in turn will cause
3289 it to send us its HELLO, so we expect to hit this case rather
3290 frequently. Only print something if we are very verbose. */
3291 #if DEBUG_TRANSPORT > 1
3292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3293 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3294 (peer_address->addr != NULL)
3295 ? a2s (tp->short_name,
3297 peer_address->addrlen)
3300 GNUNET_i2s (&neighbour->id));
3302 schedule_next_ping (peer_address);
3305 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3306 va->transport_name = GNUNET_strdup (tp->short_name);
3307 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3309 va->send_time = GNUNET_TIME_absolute_get();
3310 va->session = peer_address->session;
3311 if (peer_address->addr != NULL)
3313 va->addr = (const void*) &va[1];
3314 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3315 va->addrlen = peer_address->addrlen;
3317 memcpy(&va->publicKey,
3318 &neighbour->publicKey,
3319 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3321 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3322 &timeout_hello_validation,
3324 GNUNET_CONTAINER_multihashmap_put (validation_map,
3325 &neighbour->id.hashPubKey,
3327 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3329 if (peer_address->validated != GNUNET_YES)
3330 hello_size = GNUNET_HELLO_size(our_hello);
3334 tsize = sizeof(struct TransportPingMessage) + hello_size;
3336 if (peer_address->addr != NULL)
3338 slen = strlen (tp->short_name) + 1;
3339 tsize += slen + peer_address->addrlen;
3343 slen = 0; /* make gcc happy */
3345 message_buf = GNUNET_malloc(tsize);
3346 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3347 ping.challenge = htonl(va->challenge);
3348 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3349 if (peer_address->validated != GNUNET_YES)
3351 memcpy(message_buf, our_hello, hello_size);
3354 if (peer_address->addr != NULL)
3356 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3357 peer_address->addrlen +
3359 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3362 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3364 peer_address->addrlen);
3368 ping.header.size = htons(sizeof(struct TransportPingMessage));
3371 memcpy(&message_buf[hello_size],
3373 sizeof(struct TransportPingMessage));
3375 #if DEBUG_TRANSPORT_REVALIDATION
3376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3377 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3378 (peer_address->addr != NULL)
3379 ? a2s (peer_address->plugin->short_name,
3381 peer_address->addrlen)
3384 GNUNET_i2s (&neighbour->id),
3385 "HELLO", hello_size,
3388 if (peer_address->validated != GNUNET_YES)
3389 GNUNET_STATISTICS_update (stats,
3390 gettext_noop ("# PING with HELLO messages sent"),
3394 GNUNET_STATISTICS_update (stats,
3395 gettext_noop ("# PING without HELLO messages sent"),
3398 GNUNET_STATISTICS_update (stats,
3399 gettext_noop ("# PING messages sent for re-validation"),
3402 transmit_to_peer (NULL, peer_address,
3403 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3404 HELLO_VERIFICATION_TIMEOUT,
3406 GNUNET_YES, neighbour);
3407 GNUNET_free(message_buf);
3408 schedule_next_ping (peer_address);
3413 * Schedule the job that will cause us to send a PING to the
3414 * foreign address to evaluate its validity and latency.
3416 * @param fal address to PING
3419 schedule_next_ping (struct ForeignAddressList *fal)
3421 struct GNUNET_TIME_Relative delay;
3423 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3425 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3426 delay.rel_value /= 2; /* do before expiration */
3427 delay = GNUNET_TIME_relative_min (delay,
3428 LATENCY_EVALUATION_MAX_DELAY);
3429 if (GNUNET_YES != fal->estimated)
3431 delay = GNUNET_TIME_UNIT_ZERO;
3432 fal->estimated = GNUNET_YES;
3434 if (GNUNET_YES == fal->connected)
3436 delay = GNUNET_TIME_relative_min (delay,
3437 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3439 /* FIXME: also adjust delay based on how close the last
3440 observed latency is to the latency of the best alternative */
3441 /* bound how fast we can go */
3442 delay = GNUNET_TIME_relative_max (delay,
3443 GNUNET_TIME_UNIT_SECONDS);
3444 /* randomize a bit (to avoid doing all at the same time) */
3445 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3446 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3447 &send_periodic_ping,
3455 * Function that will be called if we receive some payload
3456 * from another peer.
3458 * @param message the payload
3459 * @param n peer who claimed to be the sender
3462 handle_payload_message (const struct GNUNET_MessageHeader *message,
3463 struct NeighbourList *n)
3465 struct InboundMessage *im;
3466 struct TransportClient *cpos;
3469 msize = ntohs (message->size);
3470 if (n->received_pong == GNUNET_NO)
3472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3473 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3474 ntohs (message->type),
3475 ntohs (message->size),
3476 GNUNET_i2s (&n->id));
3477 GNUNET_free_non_null (n->pre_connect_message_buffer);
3478 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3479 memcpy (n->pre_connect_message_buffer, message, msize);
3484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3485 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3486 ntohs (message->type),
3487 ntohs (message->size),
3488 GNUNET_i2s (&n->id));
3490 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3493 n->quota_violation_count++;
3495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3496 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3497 n->in_tracker.available_bytes_per_s__,
3498 n->quota_violation_count);
3500 /* Discount 32k per violation */
3501 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3506 if (n->quota_violation_count > 0)
3508 /* try to add 32k back */
3509 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3511 n->quota_violation_count--;
3514 GNUNET_STATISTICS_update (stats,
3515 gettext_noop ("# payload received from other peers"),
3518 /* transmit message to all clients */
3519 uint32_t ats_count = 2;
3520 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3521 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3524 im = GNUNET_malloc (size);
3525 im->header.size = htons (size);
3526 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3528 im->ats_count = htonl(ats_count);
3529 /* Setting ATS data */
3530 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3531 (&(im->ats))[0].value = htonl (n->distance);
3532 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3533 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3534 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3535 (&(im->ats))[ats_count].value = htonl (0);
3537 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3539 while (cpos != NULL)
3541 transmit_to_client (cpos, &im->header, GNUNET_YES);
3549 * Iterator over hash map entries. Checks if the given validation
3550 * entry is for the same challenge as what is given in the PONG.
3552 * @param cls the 'struct TransportPongMessage*'
3553 * @param key peer identity
3554 * @param value value in the hash map ('struct ValidationEntry')
3555 * @return GNUNET_YES if we should continue to
3556 * iterate (mismatch), GNUNET_NO if not (entry matched)
3559 check_pending_validation (void *cls,
3560 const GNUNET_HashCode * key,
3563 const struct TransportPongMessage *pong = cls;
3564 struct ValidationEntry *ve = value;
3565 struct AddValidatedAddressContext avac;
3566 unsigned int challenge = ntohl(pong->challenge);
3567 struct GNUNET_HELLO_Message *hello;
3568 struct GNUNET_PeerIdentity target;
3569 struct NeighbourList *n;
3570 struct ForeignAddressList *fal;
3571 struct OwnAddressList *oal;
3572 struct TransportPlugin *tp;
3573 struct GNUNET_MessageHeader *prem;
3579 ps = ntohs (pong->header.size);
3580 if (ps < sizeof (struct TransportPongMessage))
3582 GNUNET_break_op (0);
3585 addr = (const char*) &pong[1];
3586 slen = strlen (ve->transport_name) + 1;
3587 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3588 (ve->challenge != challenge) ||
3589 (addr[slen-1] != '\0') ||
3590 (0 != strcmp (addr, ve->transport_name)) ||
3591 (ntohl (pong->purpose.size)
3592 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3594 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3595 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3600 alen = ps - sizeof (struct TransportPongMessage) - slen;
3601 switch (ntohl (pong->purpose.purpose))
3603 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3604 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3605 (0 != memcmp (&addr[slen],
3609 return GNUNET_YES; /* different entry, keep trying! */
3611 if (0 != memcmp (&pong->pid,
3613 sizeof (struct GNUNET_PeerIdentity)))
3615 GNUNET_break_op (0);
3619 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3624 GNUNET_break_op (0);
3629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3630 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3632 a2s (ve->transport_name,
3633 (const struct sockaddr *) ve->addr,
3635 ve->transport_name);
3638 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3639 if (0 != memcmp (&pong->pid,
3641 sizeof (struct GNUNET_PeerIdentity)))
3643 GNUNET_break_op (0);
3646 if (ve->addrlen != 0)
3648 /* must have been for a different validation entry */
3651 tp = find_transport (ve->transport_name);
3657 oal = tp->addresses;
3660 if ( (oal->addrlen == alen) &&
3661 (0 == memcmp (&oal[1],
3669 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3670 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3671 a2s (ve->transport_name,
3677 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3682 GNUNET_break_op (0);
3687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3688 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3690 a2s (ve->transport_name,
3693 ve->transport_name);
3697 GNUNET_break_op (0);
3700 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3702 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3703 _("Received expired signature. Check system time.\n"));
3706 GNUNET_STATISTICS_update (stats,
3707 gettext_noop ("# address validation successes"),
3710 /* create the updated HELLO */
3711 GNUNET_CRYPTO_hash (&ve->publicKey,
3712 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3713 &target.hashPubKey);
3714 if (ve->addr != NULL)
3716 avac.done = GNUNET_NO;
3718 hello = GNUNET_HELLO_create (&ve->publicKey,
3719 &add_validated_address,
3721 GNUNET_PEERINFO_add_peer (peerinfo,
3723 GNUNET_free (hello);
3725 n = find_neighbour (&target);
3728 n->publicKey = ve->publicKey;
3729 n->public_key_valid = GNUNET_YES;
3730 fal = add_peer_address (n,
3735 GNUNET_assert (fal != NULL);
3736 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3737 fal->validated = GNUNET_YES;
3738 mark_address_connected (fal);
3739 GNUNET_STATISTICS_update (stats,
3740 gettext_noop ("# peer addresses considered valid"),
3743 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3744 schedule_next_ping (fal);
3745 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3746 n->latency = fal->latency;
3748 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3750 n->distance = fal->distance;
3751 if (GNUNET_NO == n->received_pong)
3753 n->received_pong = GNUNET_YES;
3755 notify_clients_connect (&target, n->latency, n->distance);
3756 if (NULL != (prem = n->pre_connect_message_buffer))
3758 n->pre_connect_message_buffer = NULL;
3759 handle_payload_message (prem, n);
3763 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3765 GNUNET_SCHEDULER_cancel (n->retry_task);
3766 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3767 try_transmission_to_peer (n);
3771 /* clean up validation entry */
3772 GNUNET_assert (GNUNET_YES ==
3773 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3776 abort_validation (NULL, NULL, ve);
3782 * Function that will be called if we receive a validation
3783 * of an address challenge that we transmitted to another
3784 * peer. Note that the validation should only be considered
3785 * acceptable if the challenge matches AND if the sender
3786 * address is at least a plausible address for this peer
3787 * (otherwise we may be seeing a MiM attack).
3789 * @param cls closure
3790 * @param message the pong message
3791 * @param peer who responded to our challenge
3792 * @param sender_address string describing our sender address (as observed
3793 * by the other peer in binary format)
3794 * @param sender_address_len number of bytes in 'sender_address'
3797 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3798 const struct GNUNET_PeerIdentity *peer,
3799 const char *sender_address,
3800 size_t sender_address_len)
3802 #if DEBUG_TRANSPORT > 1
3803 /* we get tons of these that just get discarded, only log
3804 if we are quite verbose */
3805 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3806 "Receiving `%s' message from `%4s'.\n", "PONG",
3809 GNUNET_STATISTICS_update (stats,
3810 gettext_noop ("# PONG messages received"),
3813 if (GNUNET_SYSERR !=
3814 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3816 &check_pending_validation,
3819 /* This is *expected* to happen a lot since we send
3820 PONGs to *all* known addresses of the sender of
3821 the PING, so most likely we get multiple PONGs
3822 per PING, and all but the first PONG will end up
3823 here. So really we should not print anything here
3824 unless we want to be very, very verbose... */
3825 #if DEBUG_TRANSPORT > 2
3826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3827 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3839 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3841 * @param cls the 'struct ValidationEntry*'
3842 * @param neighbour neighbour to validate, NULL if validation failed
3845 transmit_hello_and_ping (void *cls,
3846 struct NeighbourList *neighbour)
3848 struct ValidationEntry *va = cls;
3849 struct ForeignAddressList *peer_address;
3850 struct TransportPingMessage ping;
3851 uint16_t hello_size;
3854 struct GNUNET_PeerIdentity id;
3857 GNUNET_CRYPTO_hash (&va->publicKey,
3858 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3860 if (neighbour == NULL)
3862 /* FIXME: stats... */
3863 GNUNET_break (GNUNET_OK ==
3864 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3867 abort_validation (NULL, NULL, va);
3870 neighbour->publicKey = va->publicKey;
3871 neighbour->public_key_valid = GNUNET_YES;
3872 peer_address = add_peer_address (neighbour,
3873 va->transport_name, NULL,
3874 (const void*) &va[1],
3876 if (peer_address == NULL)
3878 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3879 "Failed to add peer `%4s' for plugin `%s'\n",
3880 GNUNET_i2s (&neighbour->id),
3881 va->transport_name);
3882 GNUNET_break (GNUNET_OK ==
3883 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3886 abort_validation (NULL, NULL, va);
3889 hello_size = GNUNET_HELLO_size(our_hello);
3890 slen = strlen(va->transport_name) + 1;
3891 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3892 message_buf = GNUNET_malloc(tsize);
3893 ping.challenge = htonl(va->challenge);
3894 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3895 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3896 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3897 memcpy(message_buf, our_hello, hello_size);
3898 memcpy(&message_buf[hello_size],
3900 sizeof(struct TransportPingMessage));
3901 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3904 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3909 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3912 : a2s (va->transport_name,
3913 (const void*) &va[1], va->addrlen),
3915 GNUNET_i2s (&neighbour->id),
3916 "HELLO", hello_size,
3917 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3920 GNUNET_STATISTICS_update (stats,
3921 gettext_noop ("# PING messages sent for initial validation"),
3924 transmit_to_peer (NULL, peer_address,
3925 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3926 HELLO_VERIFICATION_TIMEOUT,
3928 GNUNET_YES, neighbour);
3929 GNUNET_free(message_buf);
3934 * Check if the given address is already being validated; if not,
3935 * append the given address to the list of entries that are being be
3936 * validated and initiate validation.
3938 * @param cls closure ('struct CheckHelloValidatedContext *')
3939 * @param tname name of the transport
3940 * @param expiration expiration time
3941 * @param addr the address
3942 * @param addrlen length of the address
3943 * @return GNUNET_OK (always)
3946 run_validation (void *cls,
3948 struct GNUNET_TIME_Absolute expiration,
3952 struct CheckHelloValidatedContext *chvc = cls;
3953 struct GNUNET_PeerIdentity id;
3954 struct TransportPlugin *tp;
3955 struct ValidationEntry *va;
3956 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3957 struct CheckAddressExistsClosure caec;
3958 struct OwnAddressList *oal;
3960 GNUNET_assert (addr != NULL);
3962 GNUNET_STATISTICS_update (stats,
3963 gettext_noop ("# peer addresses scheduled for validation"),
3966 tp = find_transport (tname);
3969 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3970 GNUNET_ERROR_TYPE_BULK,
3972 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
3974 GNUNET_STATISTICS_update (stats,
3975 gettext_noop ("# peer addresses not validated (plugin not available)"),
3980 /* check if this is one of our own addresses */
3981 oal = tp->addresses;
3984 if ( (oal->addrlen == addrlen) &&
3985 (0 == memcmp (&oal[1],
3989 /* not plausible, this address is equivalent to our own address! */
3990 GNUNET_STATISTICS_update (stats,
3991 gettext_noop ("# peer addresses not validated (loopback)"),
3998 GNUNET_HELLO_get_key (chvc->hello, &pk);
3999 GNUNET_CRYPTO_hash (&pk,
4001 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4004 if (is_blacklisted(&id, tp))
4007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4008 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4016 caec.addrlen = addrlen;
4017 caec.session = NULL;
4019 caec.exists = GNUNET_NO;
4020 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4021 &check_address_exists,
4023 if (caec.exists == GNUNET_YES)
4025 /* During validation attempts we will likely trigger the other
4026 peer trying to validate our address which in turn will cause
4027 it to send us its HELLO, so we expect to hit this case rather
4028 frequently. Only print something if we are very verbose. */
4029 #if DEBUG_TRANSPORT > 1
4030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4031 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4032 a2s (tname, addr, addrlen),
4036 GNUNET_STATISTICS_update (stats,
4037 gettext_noop ("# peer addresses not validated (in progress)"),
4042 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4045 va->transport_name = GNUNET_strdup (tname);
4046 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4048 va->send_time = GNUNET_TIME_absolute_get();
4049 va->addr = (const void*) &va[1];
4050 memcpy (&va[1], addr, addrlen);
4051 va->addrlen = addrlen;
4052 GNUNET_HELLO_get_key (chvc->hello,
4054 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4055 &timeout_hello_validation,
4057 GNUNET_CONTAINER_multihashmap_put (validation_map,
4060 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4061 setup_peer_check_blacklist (&id, GNUNET_NO,
4062 &transmit_hello_and_ping,
4069 * Check if addresses in validated hello "h" overlap with
4070 * those in "chvc->hello" and validate the rest.
4072 * @param cls closure
4073 * @param peer id of the peer, NULL for last call
4074 * @param h hello message for the peer (can be NULL)
4075 * @param err_msg NULL if successful, otherwise contains error message
4078 check_hello_validated (void *cls,
4079 const struct GNUNET_PeerIdentity *peer,
4080 const struct GNUNET_HELLO_Message *h,
4081 const char *err_msg)
4083 struct CheckHelloValidatedContext *chvc = cls;
4084 struct GNUNET_HELLO_Message *plain_hello;
4085 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4086 struct GNUNET_PeerIdentity target;
4087 struct NeighbourList *n;
4089 if (err_msg != NULL)
4091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4092 _("Error in communication with PEERINFO service\n"));
4098 GNUNET_STATISTICS_update (stats,
4099 gettext_noop ("# outstanding peerinfo iterate requests"),
4103 if (GNUNET_NO == chvc->hello_known)
4105 /* notify PEERINFO about the peer now, so that we at least
4106 have the public key if some other component needs it */
4107 GNUNET_HELLO_get_key (chvc->hello, &pk);
4108 GNUNET_CRYPTO_hash (&pk,
4109 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4110 &target.hashPubKey);
4111 plain_hello = GNUNET_HELLO_create (&pk,
4114 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4115 GNUNET_free (plain_hello);
4116 #if DEBUG_TRANSPORT_HELLO
4117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4118 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4120 GNUNET_i2s (&target));
4122 GNUNET_STATISTICS_update (stats,
4123 gettext_noop ("# new HELLOs requiring full validation"),
4126 GNUNET_HELLO_iterate_addresses (chvc->hello,
4133 GNUNET_STATISTICS_update (stats,
4134 gettext_noop ("# duplicate HELLO (peer known)"),
4139 if (chvc->ve_count == 0)
4141 GNUNET_CONTAINER_DLL_remove (chvc_head,
4150 #if DEBUG_TRANSPORT_HELLO
4151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4152 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4156 chvc->hello_known = GNUNET_YES;
4157 n = find_neighbour (peer);
4160 #if DEBUG_TRANSPORT_HELLO
4161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4162 "Calling hello_iterate_addresses for %s!\n",
4165 GNUNET_HELLO_iterate_addresses (h,
4167 &add_to_foreign_address_list,
4169 try_transmission_to_peer (n);
4173 #if DEBUG_TRANSPORT_HELLO
4174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4175 "No existing neighbor record for %s!\n",
4178 GNUNET_STATISTICS_update (stats,
4179 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4183 GNUNET_STATISTICS_update (stats,
4184 gettext_noop ("# HELLO validations (update case)"),
4187 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4189 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4196 * Process HELLO-message.
4198 * @param plugin transport involved, may be NULL
4199 * @param message the actual message
4200 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4203 process_hello (struct TransportPlugin *plugin,
4204 const struct GNUNET_MessageHeader *message)
4207 struct GNUNET_PeerIdentity target;
4208 const struct GNUNET_HELLO_Message *hello;
4209 struct CheckHelloValidatedContext *chvc;
4210 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4211 #if DEBUG_TRANSPORT_HELLO > 2
4214 hsize = ntohs (message->size);
4215 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4216 (hsize < sizeof (struct GNUNET_MessageHeader)))
4219 return GNUNET_SYSERR;
4221 GNUNET_STATISTICS_update (stats,
4222 gettext_noop ("# HELLOs received for validation"),
4226 /* first, check if load is too high */
4227 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4229 GNUNET_STATISTICS_update (stats,
4230 gettext_noop ("# HELLOs ignored due to high load"),
4233 #if DEBUG_TRANSPORT_HELLO
4234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4235 "Ignoring `%s' for `%4s', load too high.\n",
4237 GNUNET_i2s (&target));
4241 hello = (const struct GNUNET_HELLO_Message *) message;
4242 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4244 #if DEBUG_TRANSPORT_HELLO
4245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4246 "Unable to get public key from `%s' for `%4s'!\n",
4248 GNUNET_i2s (&target));
4250 GNUNET_break_op (0);
4251 return GNUNET_SYSERR;
4254 GNUNET_CRYPTO_hash (&publicKey,
4255 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4256 &target.hashPubKey);
4258 #if DEBUG_TRANSPORT_HELLO
4259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4260 "Received `%s' message for `%4s'\n",
4262 GNUNET_i2s (&target));
4265 if (0 == memcmp (&my_identity,
4267 sizeof (struct GNUNET_PeerIdentity)))
4269 GNUNET_STATISTICS_update (stats,
4270 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4276 while (NULL != chvc)
4278 if (GNUNET_HELLO_equals (hello,
4280 GNUNET_TIME_absolute_get ()).abs_value > 0)
4282 #if DEBUG_TRANSPORT_HELLO > 2
4283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4284 "Received duplicate `%s' message for `%4s'; ignored\n",
4286 GNUNET_i2s (&target));
4288 return GNUNET_OK; /* validation already pending */
4290 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4291 GNUNET_break (0 != memcmp (hello, chvc->hello,
4292 GNUNET_HELLO_size(hello)));
4297 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4298 if ((NULL != temp_neighbor))
4300 fprintf(stderr, "Already know peer, ignoring hello\n");
4305 #if DEBUG_TRANSPORT_HELLO > 2
4308 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4310 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4313 GNUNET_i2s (&target),
4315 GNUNET_HELLO_size(hello));
4319 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4321 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4322 memcpy (&chvc[1], hello, hsize);
4323 GNUNET_CONTAINER_DLL_insert (chvc_head,
4326 /* finally, check if HELLO was previously validated
4327 (continuation will then schedule actual validation) */
4328 GNUNET_STATISTICS_update (stats,
4329 gettext_noop ("# peerinfo process hello iterate requests"),
4332 GNUNET_STATISTICS_update (stats,
4333 gettext_noop ("# outstanding peerinfo iterate requests"),
4336 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4338 HELLO_VERIFICATION_TIMEOUT,
4339 &check_hello_validated, chvc);
4345 * The peer specified by the given neighbour has timed-out or a plugin
4346 * has disconnected. We may either need to do nothing (other plugins
4347 * still up), or trigger a full disconnect and clean up. This
4348 * function updates our state and does the necessary notifications.
4349 * Also notifies our clients that the neighbour is now officially
4352 * @param n the neighbour list entry for the peer
4353 * @param check GNUNET_YES to check if ALL addresses for this peer
4354 * are gone, GNUNET_NO to force a disconnect of the peer
4355 * regardless of whether other addresses exist.
4358 disconnect_neighbour (struct NeighbourList *n, int check)
4360 struct ReadyList *rpos;
4361 struct NeighbourList *npos;
4362 struct NeighbourList *nprev;
4363 struct MessageQueue *mq;
4364 struct ForeignAddressList *peer_addresses;
4365 struct ForeignAddressList *peer_pos;
4367 if (GNUNET_YES == check)
4370 while (NULL != rpos)
4372 peer_addresses = rpos->addresses;
4373 while (peer_addresses != NULL)
4375 if (GNUNET_YES == peer_addresses->connected)
4377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4378 "NOT Disconnecting from `%4s', still have live addresses!\n",
4379 GNUNET_i2s (&n->id));
4380 return; /* still connected */
4382 peer_addresses = peer_addresses->next;
4388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4389 "Disconnecting from `%4s'\n",
4390 GNUNET_i2s (&n->id));
4392 /* remove n from neighbours list */
4395 while ((npos != NULL) && (npos != n))
4400 GNUNET_assert (npos != NULL);
4402 neighbours = n->next;
4404 nprev->next = n->next;
4406 /* notify all clients about disconnect */
4407 if (GNUNET_YES == n->received_pong)
4408 notify_clients_disconnect (&n->id);
4410 /* clean up all plugins, cancel connections and pending transmissions */
4411 while (NULL != (rpos = n->plugins))
4413 n->plugins = rpos->next;
4414 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4415 while (rpos->addresses != NULL)
4417 peer_pos = rpos->addresses;
4418 rpos->addresses = peer_pos->next;
4419 if (peer_pos->connected == GNUNET_YES)
4420 GNUNET_STATISTICS_update (stats,
4421 gettext_noop ("# connected addresses"),
4424 if (GNUNET_YES == peer_pos->validated)
4425 GNUNET_STATISTICS_update (stats,
4426 gettext_noop ("# peer addresses considered valid"),
4429 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4431 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4432 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4434 GNUNET_free(peer_pos);
4439 /* free all messages on the queue */
4440 while (NULL != (mq = n->messages_head))
4442 GNUNET_STATISTICS_update (stats,
4443 gettext_noop ("# bytes in message queue for other peers"),
4444 - (int64_t) mq->message_buf_size,
4446 GNUNET_STATISTICS_update (stats,
4447 gettext_noop ("# bytes discarded due to disconnect"),
4448 mq->message_buf_size,
4450 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4453 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4455 sizeof(struct GNUNET_PeerIdentity)));
4458 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4460 GNUNET_SCHEDULER_cancel (n->timeout_task);
4461 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4463 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4465 GNUNET_SCHEDULER_cancel (n->retry_task);
4466 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4468 if (n->piter != NULL)
4470 GNUNET_PEERINFO_iterate_cancel (n->piter);
4471 GNUNET_STATISTICS_update (stats,
4472 gettext_noop ("# outstanding peerinfo iterate requests"),
4477 /* finally, free n itself */
4478 GNUNET_STATISTICS_update (stats,
4479 gettext_noop ("# active neighbours"),
4482 GNUNET_free_non_null (n->pre_connect_message_buffer);
4488 * We have received a PING message from someone. Need to send a PONG message
4489 * in response to the peer by any means necessary.
4492 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4493 const struct GNUNET_PeerIdentity *peer,
4494 struct Session *session,
4495 const char *sender_address,
4496 uint16_t sender_address_len)
4498 struct TransportPlugin *plugin = cls;
4499 struct SessionHeader *session_header = (struct SessionHeader*) session;
4500 struct TransportPingMessage *ping;
4501 struct TransportPongMessage *pong;
4502 struct NeighbourList *n;
4503 struct ReadyList *rl;
4504 struct ForeignAddressList *fal;
4505 struct OwnAddressList *oal;
4510 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4512 GNUNET_break_op (0);
4513 return GNUNET_SYSERR;
4516 ping = (struct TransportPingMessage *) message;
4517 if (0 != memcmp (&ping->target,
4518 plugin->env.my_identity,
4519 sizeof (struct GNUNET_PeerIdentity)))
4521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4522 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4524 (sender_address != NULL)
4525 ? a2s (plugin->short_name,
4526 (const struct sockaddr *)sender_address,
4529 GNUNET_i2s (&ping->target));
4530 return GNUNET_SYSERR;
4533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4534 "Processing `%s' from `%s'\n",
4536 (sender_address != NULL)
4537 ? a2s (plugin->short_name,
4538 (const struct sockaddr *)sender_address,
4542 GNUNET_STATISTICS_update (stats,
4543 gettext_noop ("# PING messages received"),
4546 addr = (const char*) &ping[1];
4547 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4548 slen = strlen (plugin->short_name) + 1;
4551 /* peer wants to confirm that we have an outbound connection to him */
4552 if (session == NULL)
4554 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4555 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4557 return GNUNET_SYSERR;
4559 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4560 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4561 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4562 pong->purpose.size =
4563 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4565 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4566 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4567 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4568 pong->challenge = ping->challenge;
4569 pong->addrlen = htonl(sender_address_len + slen);
4572 sizeof(struct GNUNET_PeerIdentity));
4576 if ((sender_address!=NULL) && (sender_address_len > 0))
4577 memcpy (&((char*)&pong[1])[slen],
4579 sender_address_len);
4580 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4582 /* create / update cached sig */
4584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4585 "Creating PONG signature to indicate active connection.\n");
4587 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4588 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4589 GNUNET_assert (GNUNET_OK ==
4590 GNUNET_CRYPTO_rsa_sign (my_private_key,
4592 &session_header->pong_signature));
4596 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4598 memcpy (&pong->signature,
4599 &session_header->pong_signature,
4600 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4606 /* peer wants to confirm that this is one of our addresses */
4610 plugin->api->check_address (plugin->api->cls,
4614 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4615 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4616 a2s (plugin->short_name,
4621 oal = plugin->addresses;
4624 if ( (oal->addrlen == alen) &&
4631 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4632 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4633 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4634 pong->purpose.size =
4635 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4637 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4638 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4639 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4640 pong->challenge = ping->challenge;
4641 pong->addrlen = htonl(alen + slen);
4644 sizeof(struct GNUNET_PeerIdentity));
4645 memcpy (&pong[1], plugin->short_name, slen);
4646 memcpy (&((char*)&pong[1])[slen], addr, alen);
4647 if ( (oal != NULL) &&
4648 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4650 /* create / update cached sig */
4652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4653 "Creating PONG signature to indicate ownership.\n");
4655 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4656 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4657 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4658 GNUNET_assert (GNUNET_OK ==
4659 GNUNET_CRYPTO_rsa_sign (my_private_key,
4661 &oal->pong_signature));
4662 memcpy (&pong->signature,
4663 &oal->pong_signature,
4664 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4666 else if (oal == NULL)
4668 /* not using cache (typically DV-only) */
4669 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4670 GNUNET_assert (GNUNET_OK ==
4671 GNUNET_CRYPTO_rsa_sign (my_private_key,
4677 /* can used cached version */
4678 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4679 memcpy (&pong->signature,
4680 &oal->pong_signature,
4681 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4684 n = find_neighbour(peer);
4685 GNUNET_assert (n != NULL);
4686 /* first try reliable response transmission */
4690 fal = rl->addresses;
4693 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4696 ntohs (pong->header.size),
4697 TRANSPORT_PONG_PRIORITY,
4698 HELLO_VERIFICATION_TIMEOUT,
4706 GNUNET_STATISTICS_update (stats,
4707 gettext_noop ("# PONGs unicast via reliable transport"),
4717 /* no reliable method found, do multicast */
4718 GNUNET_STATISTICS_update (stats,
4719 gettext_noop ("# PONGs multicast to all available addresses"),
4725 fal = rl->addresses;
4728 transmit_to_peer(NULL, fal,
4729 TRANSPORT_PONG_PRIORITY,
4730 HELLO_VERIFICATION_TIMEOUT,
4732 ntohs(pong->header.size),
4745 * Function called by the plugin for each received message.
4746 * Update data volumes, possibly notify plugins about
4747 * reducing the rate at which they read from the socket
4748 * and generally forward to our receive callback.
4750 * @param cls the "struct TransportPlugin *" we gave to the plugin
4751 * @param peer (claimed) identity of the other peer
4752 * @param message the message, NULL if we only care about
4753 * learning about the delay until we should receive again
4754 * @param ats_data information for automatic transport selection
4755 * @param ats_count number of elements in ats not including 0-terminator
4756 * @param session identifier used for this session (can be NULL)
4757 * @param sender_address binary address of the sender (if observed)
4758 * @param sender_address_len number of bytes in sender_address
4759 * @return how long in ms the plugin should wait until receiving more data
4760 * (plugins that do not support this, can ignore the return value)
4762 static struct GNUNET_TIME_Relative
4763 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4764 const struct GNUNET_MessageHeader *message,
4765 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4767 struct Session *session,
4768 const char *sender_address,
4769 uint16_t sender_address_len)
4771 struct TransportPlugin *plugin = cls;
4772 struct ReadyList *service_context;
4773 struct ForeignAddressList *peer_address;
4775 struct NeighbourList *n;
4776 struct GNUNET_TIME_Relative ret;
4777 if (is_blacklisted (peer, plugin))
4778 return GNUNET_TIME_UNIT_FOREVER_REL;
4782 n = find_neighbour (peer);
4784 n = setup_new_neighbour (peer, GNUNET_YES);
4785 service_context = n->plugins;
4786 while ((service_context != NULL) && (plugin != service_context->plugin))
4787 service_context = service_context->next;
4788 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4789 peer_address = NULL;
4791 for (c=0; c<ats_count; c++)
4793 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4795 distance = ntohl(ats_data[c].value);
4798 /* notify ATS about incoming data */
4799 ats_notify_ats_data(ats, peer, ats_data);
4802 if (message != NULL)
4804 if ( (session != NULL) ||
4805 (sender_address != NULL) )
4806 peer_address = add_peer_address (n,
4810 sender_address_len);
4811 if (peer_address != NULL)
4813 peer_address->distance = distance;
4814 if (GNUNET_YES == peer_address->validated)
4815 mark_address_connected (peer_address);
4816 peer_address->timeout
4818 GNUNET_TIME_relative_to_absolute
4819 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4820 schedule_next_ping (peer_address);
4822 /* update traffic received amount ... */
4823 msize = ntohs (message->size);
4824 GNUNET_STATISTICS_update (stats,
4825 gettext_noop ("# bytes received from other peers"),
4828 n->distance = distance;
4830 GNUNET_TIME_relative_to_absolute
4831 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4832 GNUNET_SCHEDULER_cancel (n->timeout_task);
4834 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4835 &neighbour_timeout_task, n);
4836 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4838 /* dropping message due to frequent inbound volume violations! */
4839 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4840 GNUNET_ERROR_TYPE_BULK,
4842 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4843 n->in_tracker.available_bytes_per_s__,
4844 n->quota_violation_count);
4845 GNUNET_STATISTICS_update (stats,
4846 gettext_noop ("# bandwidth quota violations by other peers"),
4849 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4854 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4855 ntohs (message->type),
4856 ntohs (message->size),
4859 switch (ntohs (message->type))
4861 case GNUNET_MESSAGE_TYPE_HELLO:
4862 GNUNET_STATISTICS_update (stats,
4863 gettext_noop ("# HELLO messages received from other peers"),
4866 process_hello (plugin, message);
4868 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4869 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4871 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4872 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4875 handle_payload_message (message, n);
4879 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4880 if (ret.rel_value > 0)
4882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4883 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4884 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4885 (unsigned int) n->in_tracker.available_bytes_per_s__,
4886 (unsigned long long) ret.rel_value);
4887 GNUNET_STATISTICS_update (stats,
4888 gettext_noop ("# ms throttling suggested"),
4889 (int64_t) ret.rel_value,
4896 * Handle START-message. This is the first message sent to us
4897 * by any client which causes us to add it to our list.
4899 * @param cls closure (always NULL)
4900 * @param client identification of the client
4901 * @param message the actual message
4904 handle_start (void *cls,
4905 struct GNUNET_SERVER_Client *client,
4906 const struct GNUNET_MessageHeader *message)
4908 const struct StartMessage *start;
4909 struct TransportClient *c;
4910 struct ConnectInfoMessage * cim;
4911 struct NeighbourList *n;
4915 start = (const struct StartMessage*) message;
4917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4918 "Received `%s' request from client\n", "START");
4923 if (c->client == client)
4925 /* client already on our list! */
4927 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4932 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4933 (0 != memcmp (&start->self,
4935 sizeof (struct GNUNET_PeerIdentity))) )
4937 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4938 _("Rejecting control connection from peer `%s', which is not me!\n"),
4939 GNUNET_i2s (&start->self));
4940 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4943 c = GNUNET_malloc (sizeof (struct TransportClient));
4947 if (our_hello != NULL)
4950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4951 "Sending our own `%s' to new client\n", "HELLO");
4953 transmit_to_client (c,
4954 (const struct GNUNET_MessageHeader *) our_hello,
4956 /* tell new client about all existing connections */
4958 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
4959 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4963 cim = GNUNET_malloc (size);
4964 cim->header.size = htons (size);
4965 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4966 cim->ats_count = htonl(ats_count);
4967 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4968 (&(cim->ats))[2].value = htonl (0);
4972 if (GNUNET_YES == n->received_pong)
4974 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
4975 (&(cim->ats))[0].value = htonl (n->distance);
4976 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4977 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
4979 transmit_to_client (c, &cim->header, GNUNET_NO);
4985 GNUNET_SERVER_receive_done (client, GNUNET_OK);
4990 * Handle HELLO-message.
4992 * @param cls closure (always NULL)
4993 * @param client identification of the client
4994 * @param message the actual message
4997 handle_hello (void *cls,
4998 struct GNUNET_SERVER_Client *client,
4999 const struct GNUNET_MessageHeader *message)
5003 GNUNET_STATISTICS_update (stats,
5004 gettext_noop ("# HELLOs received from clients"),
5007 ret = process_hello (NULL, message);
5008 GNUNET_SERVER_receive_done (client, ret);
5013 * Closure for 'transmit_client_message'; followed by
5014 * 'msize' bytes of the actual message.
5016 struct TransmitClientMessageContext
5019 * Client on whom's behalf we are sending.
5021 struct GNUNET_SERVER_Client *client;
5024 * Timeout for the transmission.
5026 struct GNUNET_TIME_Absolute timeout;
5034 * Size of the message in bytes.
5041 * Schedule transmission of a message we got from a client to a peer.
5043 * @param cls the 'struct TransmitClientMessageContext*'
5044 * @param n destination, or NULL on error (in that case, drop the message)
5047 transmit_client_message (void *cls,
5048 struct NeighbourList *n)
5050 struct TransmitClientMessageContext *tcmc = cls;
5051 struct TransportClient *tc;
5054 while ((tc != NULL) && (tc->client != tcmc->client))
5059 transmit_to_peer (tc, NULL, tcmc->priority,
5060 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5062 tcmc->msize, GNUNET_NO, n);
5064 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5065 GNUNET_SERVER_client_drop (tcmc->client);
5071 * Handle SEND-message.
5073 * @param cls closure (always NULL)
5074 * @param client identification of the client
5075 * @param message the actual message
5078 handle_send (void *cls,
5079 struct GNUNET_SERVER_Client *client,
5080 const struct GNUNET_MessageHeader *message)
5082 const struct OutboundMessage *obm;
5083 const struct GNUNET_MessageHeader *obmm;
5084 struct TransmitClientMessageContext *tcmc;
5088 size = ntohs (message->size);
5090 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5093 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5096 GNUNET_STATISTICS_update (stats,
5097 gettext_noop ("# payload received for other peers"),
5100 obm = (const struct OutboundMessage *) message;
5101 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5102 msize = size - sizeof (struct OutboundMessage);
5104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5105 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5106 "SEND", GNUNET_i2s (&obm->peer),
5110 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5111 tcmc->client = client;
5112 tcmc->priority = ntohl (obm->priority);
5113 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5114 tcmc->msize = msize;
5115 /* FIXME: this memcpy can be up to 7% of our total runtime */
5116 memcpy (&tcmc[1], obmm, msize);
5117 GNUNET_SERVER_client_keep (client);
5118 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5119 &transmit_client_message,
5125 * Handle request connect message
5127 * @param cls closure (always NULL)
5128 * @param client identification of the client
5129 * @param message the actual message
5132 handle_request_connect (void *cls,
5133 struct GNUNET_SERVER_Client *client,
5134 const struct GNUNET_MessageHeader *message)
5136 const struct TransportRequestConnectMessage *trcm =
5137 (const struct TransportRequestConnectMessage *) message;
5139 GNUNET_STATISTICS_update (stats,
5140 gettext_noop ("# REQUEST CONNECT messages received"),
5143 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5144 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5146 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5150 * Handle SET_QUOTA-message.
5152 * @param cls closure (always NULL)
5153 * @param client identification of the client
5154 * @param message the actual message
5157 handle_set_quota (void *cls,
5158 struct GNUNET_SERVER_Client *client,
5159 const struct GNUNET_MessageHeader *message)
5161 const struct QuotaSetMessage *qsm =
5162 (const struct QuotaSetMessage *) message;
5163 struct NeighbourList *n;
5165 GNUNET_STATISTICS_update (stats,
5166 gettext_noop ("# SET QUOTA messages received"),
5169 n = find_neighbour (&qsm->peer);
5172 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5173 GNUNET_STATISTICS_update (stats,
5174 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5181 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5183 (unsigned int) ntohl (qsm->quota.value__),
5184 (unsigned int) n->in_tracker.available_bytes_per_s__,
5185 GNUNET_i2s (&qsm->peer));
5187 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5189 if (0 == ntohl (qsm->quota.value__))
5191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5192 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5194 disconnect_neighbour (n, GNUNET_NO);
5196 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5201 * Take the given address and append it to the set of results sent back to
5204 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5205 * @param address the resolved name, NULL to indicate the last response
5208 transmit_address_to_client (void *cls, const char *address)
5210 struct GNUNET_SERVER_TransmitContext *tc = cls;
5213 if (NULL == address)
5216 slen = strlen (address) + 1;
5218 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5219 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5220 if (NULL == address)
5221 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5226 * Handle AddressLookup-message.
5228 * @param cls closure (always NULL)
5229 * @param client identification of the client
5230 * @param message the actual message
5233 handle_address_lookup (void *cls,
5234 struct GNUNET_SERVER_Client *client,
5235 const struct GNUNET_MessageHeader *message)
5237 const struct AddressLookupMessage *alum;
5238 struct TransportPlugin *lsPlugin;
5239 const char *nameTransport;
5240 const char *address;
5242 struct GNUNET_SERVER_TransmitContext *tc;
5243 struct GNUNET_TIME_Absolute timeout;
5244 struct GNUNET_TIME_Relative rtimeout;
5247 size = ntohs (message->size);
5248 if (size < sizeof (struct AddressLookupMessage))
5250 GNUNET_break_op (0);
5251 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5254 alum = (const struct AddressLookupMessage *) message;
5255 uint32_t addressLen = ntohl (alum->addrlen);
5256 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5258 GNUNET_break_op (0);
5259 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5262 address = (const char *) &alum[1];
5263 nameTransport = (const char *) &address[addressLen];
5265 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5267 GNUNET_break_op (0);
5268 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5271 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5272 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5273 numeric = ntohl (alum->numeric_only);
5274 lsPlugin = find_transport (nameTransport);
5275 if (NULL == lsPlugin)
5277 tc = GNUNET_SERVER_transmit_context_create (client);
5278 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5279 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5280 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5283 tc = GNUNET_SERVER_transmit_context_create (client);
5284 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5286 address, addressLen,
5289 &transmit_address_to_client, tc);
5294 * Setup the environment for this plugin.
5297 create_environment (struct TransportPlugin *plug)
5299 plug->env.cfg = cfg;
5300 plug->env.my_identity = &my_identity;
5301 plug->env.our_hello = &our_hello;
5302 plug->env.cls = plug;
5303 plug->env.receive = &plugin_env_receive;
5304 plug->env.notify_address = &plugin_env_notify_address;
5305 plug->env.session_end = &plugin_env_session_end;
5306 plug->env.max_connections = max_connect_per_transport;
5307 plug->env.stats = stats;
5312 * Start the specified transport (load the plugin).
5315 start_transport (struct GNUNET_SERVER_Handle *server,
5318 struct TransportPlugin *plug;
5321 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5322 _("Loading `%s' transport plugin\n"), name);
5323 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5324 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5325 create_environment (plug);
5326 plug->short_name = GNUNET_strdup (name);
5327 plug->lib_name = libname;
5328 plug->next = plugins;
5330 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5331 if (plug->api == NULL)
5333 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5334 _("Failed to load transport plugin for `%s'\n"), name);
5335 GNUNET_free (plug->short_name);
5336 plugins = plug->next;
5337 GNUNET_free (libname);
5344 * Called whenever a client is disconnected. Frees our
5345 * resources associated with that client.
5347 * @param cls closure
5348 * @param client identification of the client
5351 client_disconnect_notification (void *cls,
5352 struct GNUNET_SERVER_Client *client)
5354 struct TransportClient *pos;
5355 struct TransportClient *prev;
5356 struct ClientMessageQueueEntry *mqe;
5357 struct Blacklisters *bl;
5358 struct BlacklistCheck *bc;
5363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5364 "Client disconnected, cleaning up.\n");
5366 /* clean up blacklister */
5370 if (bl->client == client)
5375 if (bc->bl_pos == bl)
5377 bc->bl_pos = bl->next;
5380 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5383 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5384 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5390 GNUNET_CONTAINER_DLL_remove (bl_head,
5393 GNUNET_SERVER_client_drop (bl->client);
5399 /* clean up 'normal' clients */
5402 while ((pos != NULL) && (pos->client != client))
5409 while (NULL != (mqe = pos->message_queue_head))
5411 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5412 pos->message_queue_tail,
5414 pos->message_count--;
5418 clients = pos->next;
5420 prev->next = pos->next;
5421 if (GNUNET_YES == pos->tcs_pending)
5426 if (pos->th != NULL)
5428 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5431 GNUNET_break (0 == pos->message_count);
5437 * Function called when the service shuts down. Unloads our plugins
5438 * and cancels pending validations.
5440 * @param cls closure, unused
5441 * @param tc task context (unused)
5444 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5446 struct TransportPlugin *plug;
5447 struct OwnAddressList *al;
5448 struct CheckHelloValidatedContext *chvc;
5450 while (neighbours != NULL)
5452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5453 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5455 disconnect_neighbour (neighbours, GNUNET_NO);
5458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5459 "Transport service is unloading plugins...\n");
5461 while (NULL != (plug = plugins))
5463 plugins = plug->next;
5464 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5466 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5467 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5469 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5470 GNUNET_free (plug->lib_name);
5471 GNUNET_free (plug->short_name);
5472 while (NULL != (al = plug->addresses))
5474 plug->addresses = al->next;
5479 if (my_private_key != NULL)
5480 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5481 GNUNET_free_non_null (our_hello);
5483 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5486 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5487 validation_map = NULL;
5491 /* free 'chvc' data structure */
5492 while (NULL != (chvc = chvc_head))
5494 chvc_head = chvc->next;
5495 if (chvc->piter != NULL)
5497 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5498 GNUNET_STATISTICS_update (stats,
5499 gettext_noop ("# outstanding peerinfo iterate requests"),
5505 GNUNET_assert (chvc->ve_count == 0);
5512 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5515 if (peerinfo != NULL)
5517 GNUNET_PEERINFO_disconnect (peerinfo);
5520 /* Can we assume those are gone by now, or do we need to clean up
5522 GNUNET_break (bl_head == NULL);
5523 GNUNET_break (bc_head == NULL);
5526 void ats_calculate_bandwidth_distribution (struct ATS_info * ats)
5528 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
5529 if (delta.rel_value < ats->min_delta.rel_value)
5532 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
5537 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CALCULATE DISTRIBUTION\n");
5539 ats->last = GNUNET_TIME_absolute_get();
5545 ats_schedule_calculation (void *cls,
5546 const struct GNUNET_SCHEDULER_TaskContext *tc)
5548 struct ATS_info *ats = (struct ATS_info *) cls;
5552 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5553 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
5557 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
5559 ats_calculate_bandwidth_distribution (ats);
5561 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5562 &ats_schedule_calculation, ats);
5566 int ats_map_remove_peer (void *cls,
5567 const GNUNET_HashCode * key,
5571 struct ATS_peer * p = (struct ATS_peer *) value;
5573 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
5582 struct ATS_info * ats_init ()
5584 struct ATS_info * ats;
5586 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
5588 ats = GNUNET_malloc(sizeof (struct ATS_info));
5589 ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
5590 GNUNET_assert(ats->peers!=NULL);
5592 ats->min_delta = ATS_MIN_INTERVAL;
5593 ats->reg_delta = ATS_EXEC_INTERVAL;
5595 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5597 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5598 &schedule_calculation, NULL);
5600 ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
5601 &schedule_calculation, NULL);
5603 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
5609 void ats_shutdown (struct ATS_info * ats)
5612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
5614 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
5615 GNUNET_SCHEDULER_cancel(ats->ats_task);
5616 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5618 GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
5619 GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
5624 void ats_notify_peer_connect (struct ATS_info * ats,
5625 const struct GNUNET_PeerIdentity *peer,
5626 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5630 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
5633 while (ntohl(ats_data[c].type)!=0)
5636 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
5640 /* check if peer is already known */
5641 if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
5643 struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
5644 memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
5645 GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
5648 ats_calculate_bandwidth_distribution(ats);
5651 void ats_notify_peer_disconnect (struct ATS_info * ats,
5652 const struct GNUNET_PeerIdentity *peer)
5655 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
5658 if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
5660 ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
5661 GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
5664 ats_calculate_bandwidth_distribution (ats);
5668 void ats_notify_ats_data (struct ATS_info * ats,
5669 const struct GNUNET_PeerIdentity *peer,
5670 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5673 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
5675 ats_calculate_bandwidth_distribution(ats);
5679 * Initiate transport service.
5681 * @param cls closure
5682 * @param server the initialized server
5683 * @param c configuration to use
5687 struct GNUNET_SERVER_Handle *server,
5688 const struct GNUNET_CONFIGURATION_Handle *c)
5690 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
5691 {&handle_start, NULL,
5692 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
5693 {&handle_hello, NULL,
5694 GNUNET_MESSAGE_TYPE_HELLO, 0},
5695 {&handle_send, NULL,
5696 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
5697 {&handle_request_connect, NULL,
5698 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
5699 {&handle_set_quota, NULL,
5700 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
5701 {&handle_address_lookup, NULL,
5702 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
5704 {&handle_blacklist_init, NULL,
5705 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
5706 {&handle_blacklist_reply, NULL,
5707 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
5713 unsigned long long tneigh;
5717 stats = GNUNET_STATISTICS_create ("transport", cfg);
5718 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
5719 /* parse configuration */
5721 GNUNET_CONFIGURATION_get_value_number (c,
5726 GNUNET_CONFIGURATION_get_value_filename (c,
5728 "HOSTKEY", &keyfile)))
5730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5732 ("Transport service is lacking key configuration settings. Exiting.\n"));
5733 GNUNET_SCHEDULER_shutdown ();
5736 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5739 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5740 validation_map = NULL;
5744 max_connect_per_transport = (uint32_t) tneigh;
5745 peerinfo = GNUNET_PEERINFO_connect (cfg);
5746 if (peerinfo == NULL)
5748 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5749 _("Could not access PEERINFO service. Exiting.\n"));
5750 GNUNET_SCHEDULER_shutdown ();
5753 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5756 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5757 validation_map = NULL;
5758 GNUNET_free (keyfile);
5761 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
5762 GNUNET_free (keyfile);
5763 if (my_private_key == NULL)
5765 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5767 ("Transport service could not access hostkey. Exiting.\n"));
5768 GNUNET_SCHEDULER_shutdown ();
5771 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5774 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5775 validation_map = NULL;
5778 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
5779 GNUNET_CRYPTO_hash (&my_public_key,
5780 sizeof (my_public_key), &my_identity.hashPubKey);
5781 /* setup notification */
5782 GNUNET_SERVER_disconnect_notify (server,
5783 &client_disconnect_notification, NULL);
5784 /* load plugins... */
5787 GNUNET_CONFIGURATION_get_value_string (c,
5788 "TRANSPORT", "PLUGINS", &plugs))
5790 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5791 _("Starting transport plugins `%s'\n"), plugs);
5792 pos = strtok (plugs, " ");
5795 start_transport (server, pos);
5797 pos = strtok (NULL, " ");
5799 GNUNET_free (plugs);
5801 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
5802 &shutdown_task, NULL);
5807 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
5809 /* If we have a blacklist file, read from it */
5810 read_blacklist_file(cfg);
5811 /* process client requests */
5812 GNUNET_SERVER_add_handlers (server, handlers);
5817 * The main function for the transport service.
5819 * @param argc number of arguments from the command line
5820 * @param argv command line arguments
5821 * @return 0 ok, 1 on error
5824 main (int argc, char *const *argv)
5826 a2s (NULL, NULL, 0); /* make compiler happy */
5827 return (GNUNET_OK ==
5828 GNUNET_SERVICE_run (argc,
5831 GNUNET_SERVICE_OPTION_NONE,
5832 &run, NULL)) ? 0 : 1;
5835 /* end of gnunet-service-transport.c */