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 *n);
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);
950 struct ForeignAddressList * ats_get_preferred_address (struct ATS_info * ats,
951 struct NeighbourList *n);
954 * Find an entry in the neighbour list for a particular peer.
956 * @return NULL if not found.
958 static struct NeighbourList *
959 find_neighbour (const struct GNUNET_PeerIdentity *key)
961 struct NeighbourList *head = neighbours;
963 while ((head != NULL) &&
964 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
971 * Find an entry in the transport list for a particular transport.
973 * @return NULL if not found.
975 static struct TransportPlugin *
976 find_transport (const char *short_name)
978 struct TransportPlugin *head = plugins;
979 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
985 * Is a particular peer blacklisted for a particular transport?
987 * @param peer the peer to check for
988 * @param plugin the plugin used to connect to the peer
990 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
993 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
996 if (plugin->blacklist != NULL)
998 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1002 "Peer `%s:%s' is blacklisted!\n",
1003 plugin->short_name, GNUNET_i2s (peer));
1006 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1016 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1018 struct TransportPlugin *plugin;
1020 plugin = find_transport(transport_name);
1021 if (plugin == NULL) /* Nothing to do */
1023 if (plugin->blacklist == NULL)
1024 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1025 GNUNET_assert(plugin->blacklist != NULL);
1026 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1028 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1033 * Read the blacklist file, containing transport:peer entries.
1034 * Provided the transport is loaded, set up hashmap with these
1035 * entries to blacklist peers by transport.
1039 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1046 struct GNUNET_PeerIdentity pid;
1048 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1049 unsigned int entries_found;
1050 char *transport_name;
1053 GNUNET_CONFIGURATION_get_value_filename (cfg,
1059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1060 "Option `%s' in section `%s' not specified!\n",
1066 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1067 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1068 | GNUNET_DISK_PERM_USER_WRITE);
1069 if (0 != STAT (fn, &frstat))
1071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1072 _("Could not read blacklist file `%s'\n"), fn);
1076 if (frstat.st_size == 0)
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 _("Blacklist file `%s' is empty.\n"),
1086 /* FIXME: use mmap */
1087 data = GNUNET_malloc_large (frstat.st_size);
1088 GNUNET_assert(data != NULL);
1089 if (frstat.st_size !=
1090 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1092 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1093 _("Failed to read blacklist from `%s'\n"), fn);
1100 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1102 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1103 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1106 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1109 if (colon_pos >= frstat.st_size)
1111 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1112 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1113 (unsigned long long) colon_pos);
1119 if (isspace( (unsigned char) data[colon_pos]))
1121 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1122 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1123 (unsigned long long) colon_pos);
1125 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1129 tsize = colon_pos - pos;
1130 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1132 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1133 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1134 (unsigned long long) colon_pos);
1143 transport_name = GNUNET_malloc(tsize + 1);
1144 memcpy(transport_name, &data[pos], tsize);
1145 pos = colon_pos + 1;
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 "Read transport name %s in blacklist file.\n",
1151 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1152 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1154 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1155 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1156 (unsigned long long) pos);
1158 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1160 GNUNET_free_non_null(transport_name);
1163 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1164 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1166 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1167 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1168 (unsigned long long) pos,
1173 if (0 != memcmp (&pid,
1175 sizeof (struct GNUNET_PeerIdentity)))
1178 add_peer_to_blacklist (&pid,
1183 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1184 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1188 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1189 GNUNET_free_non_null(transport_name);
1190 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1193 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1200 * Function called to notify a client about the socket being ready to
1201 * queue more data. "buf" will be NULL and "size" zero if the socket
1202 * was closed for writing in the meantime.
1204 * @param cls closure
1205 * @param size number of bytes available in buf
1206 * @param buf where the callee should write the message
1207 * @return number of bytes written to buf
1210 transmit_to_client_callback (void *cls, size_t size, void *buf)
1212 struct TransportClient *client = cls;
1213 struct ClientMessageQueueEntry *q;
1216 const struct GNUNET_MessageHeader *msg;
1223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1224 "Transmission to client failed, closing connection.\n");
1226 /* fatal error with client, free message queue! */
1227 while (NULL != (q = client->message_queue_head))
1229 GNUNET_STATISTICS_update (stats,
1230 gettext_noop ("# bytes discarded (could not transmit to client)"),
1231 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1233 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1234 client->message_queue_tail,
1238 client->message_count = 0;
1243 while (NULL != (q = client->message_queue_head))
1245 msg = (const struct GNUNET_MessageHeader *) &q[1];
1246 msize = ntohs (msg->size);
1247 if (msize + tsize > size)
1250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1251 "Transmitting message of type %u to client.\n",
1254 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1255 client->message_queue_tail,
1257 memcpy (&cbuf[tsize], msg, msize);
1260 client->message_count--;
1264 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1265 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1267 GNUNET_TIME_UNIT_FOREVER_REL,
1268 &transmit_to_client_callback,
1270 GNUNET_assert (client->th != NULL);
1277 * Convert an address to a string.
1279 * @param plugin name of the plugin responsible for the address
1280 * @param addr binary address
1281 * @param addr_len number of bytes in addr
1282 * @return NULL on error, otherwise address string
1285 a2s (const char *plugin,
1289 struct TransportPlugin *p;
1293 p = find_transport (plugin);
1296 return p->api->address_to_string (p->api->cls,
1303 * Mark the given FAL entry as 'connected' (and hence preferred for
1304 * sending); also mark all others for the same peer as 'not connected'
1305 * (since only one can be preferred).
1307 * @param fal address to set to 'connected'
1310 mark_address_connected (struct ForeignAddressList *fal)
1312 struct ForeignAddressList *pos;
1315 GNUNET_assert (GNUNET_YES == fal->validated);
1316 if (fal->connected == GNUNET_YES)
1317 return; /* nothing to do */
1319 pos = fal->ready_list->addresses;
1322 if (GNUNET_YES == pos->connected)
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1327 a2s (pos->ready_list->plugin->short_name,
1331 GNUNET_break (cnt == GNUNET_YES);
1333 pos->connected = GNUNET_NO;
1334 GNUNET_STATISTICS_update (stats,
1335 gettext_noop ("# connected addresses"),
1341 fal->connected = GNUNET_YES;
1342 if (GNUNET_YES == cnt)
1344 GNUNET_STATISTICS_update (stats,
1345 gettext_noop ("# connected addresses"),
1353 * Send the specified message to the specified client. Since multiple
1354 * messages may be pending for the same client at a time, this code
1355 * makes sure that no message is lost.
1357 * @param client client to transmit the message to
1358 * @param msg the message to send
1359 * @param may_drop can this message be dropped if the
1360 * message queue for this client is getting far too large?
1363 transmit_to_client (struct TransportClient *client,
1364 const struct GNUNET_MessageHeader *msg, int may_drop)
1366 struct ClientMessageQueueEntry *q;
1369 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1371 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1373 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1376 client->message_count,
1378 GNUNET_STATISTICS_update (stats,
1379 gettext_noop ("# messages dropped due to slow client"),
1384 msize = ntohs (msg->size);
1385 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1386 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1387 memcpy (&q[1], msg, msize);
1388 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1389 client->message_queue_tail,
1390 client->message_queue_tail,
1392 client->message_count++;
1393 if (client->th == NULL)
1395 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1397 GNUNET_TIME_UNIT_FOREVER_REL,
1398 &transmit_to_client_callback,
1400 GNUNET_assert (client->th != NULL);
1406 * Transmit a 'SEND_OK' notification to the given client for the
1409 * @param client who to notify
1410 * @param n neighbour to notify about, can be NULL (on failure)
1411 * @param target target of the transmission
1412 * @param result status code for the transmission request
1415 transmit_send_ok (struct TransportClient *client,
1416 struct NeighbourList *n,
1417 const struct GNUNET_PeerIdentity *target,
1420 struct SendOkMessage send_ok_msg;
1422 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1423 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1424 send_ok_msg.success = htonl (result);
1426 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1428 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1429 send_ok_msg.peer = *target;
1430 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1435 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1436 * upon "completion" of a send request. This tells the API
1437 * that it is now legal to send another message to the given
1440 * @param cls closure, identifies the entry on the
1441 * message queue that was transmitted and the
1442 * client responsible for queuing the message
1443 * @param target the peer receiving the message
1444 * @param result GNUNET_OK on success, if the transmission
1445 * failed, we should not tell the client to transmit
1449 transmit_send_continuation (void *cls,
1450 const struct GNUNET_PeerIdentity *target,
1453 struct MessageQueue *mq = cls;
1454 struct NeighbourList *n;
1456 GNUNET_STATISTICS_update (stats,
1457 gettext_noop ("# bytes pending with plugins"),
1458 - (int64_t) mq->message_buf_size,
1460 if (result == GNUNET_OK)
1462 GNUNET_STATISTICS_update (stats,
1463 gettext_noop ("# bytes successfully transmitted by plugins"),
1464 mq->message_buf_size,
1469 GNUNET_STATISTICS_update (stats,
1470 gettext_noop ("# bytes with transmission failure by plugins"),
1471 mq->message_buf_size,
1474 if (mq->specific_address != NULL)
1476 if (result == GNUNET_OK)
1478 mq->specific_address->timeout =
1479 GNUNET_TIME_relative_to_absolute
1480 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1481 if (mq->specific_address->validated == GNUNET_YES)
1482 mark_address_connected (mq->specific_address);
1486 if (mq->specific_address->connected != GNUNET_NO)
1489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1490 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1491 a2s (mq->specific_address->ready_list->plugin->short_name,
1492 mq->specific_address->addr,
1493 mq->specific_address->addrlen));
1495 GNUNET_STATISTICS_update (stats,
1496 gettext_noop ("# connected addresses"),
1499 mq->specific_address->connected = GNUNET_NO;
1502 if (! mq->internal_msg)
1503 mq->specific_address->in_transmit = GNUNET_NO;
1505 n = find_neighbour(&mq->neighbour_id);
1506 if (mq->client != NULL)
1507 transmit_send_ok (mq->client, n, target, result);
1510 try_transmission_to_peer (n);
1515 * Find an address in any of the available transports for
1516 * the given neighbour that would be good for message
1517 * transmission. This is essentially the transport selection
1520 * @param neighbour for whom to select an address
1521 * @return selected address, NULL if we have none
1523 struct ForeignAddressList *
1524 find_ready_address(struct NeighbourList *neighbour)
1526 struct ReadyList *head = neighbour->plugins;
1527 struct ForeignAddressList *addresses;
1528 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1529 struct ForeignAddressList *best_address;
1531 /* Hack to prefer unix domain sockets */
1532 struct ForeignAddressList *unix_address = NULL;
1534 best_address = NULL;
1535 while (head != NULL)
1537 addresses = head->addresses;
1538 while (addresses != NULL)
1540 if ( (addresses->timeout.abs_value < now.abs_value) &&
1541 (addresses->connected == GNUNET_YES) )
1544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1545 "Marking long-time inactive connection to `%4s' as down.\n",
1546 GNUNET_i2s (&neighbour->id));
1548 GNUNET_STATISTICS_update (stats,
1549 gettext_noop ("# connected addresses"),
1552 addresses->connected = GNUNET_NO;
1554 addresses = addresses->next;
1557 addresses = head->addresses;
1558 while (addresses != NULL)
1560 #if DEBUG_TRANSPORT > 1
1561 if (addresses->addr != NULL)
1562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1563 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1564 a2s (head->plugin->short_name,
1566 addresses->addrlen),
1567 GNUNET_i2s (&neighbour->id),
1568 addresses->connected,
1569 addresses->in_transmit,
1570 addresses->validated,
1571 addresses->connect_attempts,
1572 (unsigned long long) addresses->timeout.abs_value,
1573 (unsigned int) addresses->distance);
1575 if (0==strcmp(head->plugin->short_name,"unix"))
1577 if ((unix_address == NULL) || ((unix_address != NULL) &&
1578 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1579 unix_address = addresses;
1581 if ( ( (best_address == NULL) ||
1582 (addresses->connected == GNUNET_YES) ||
1583 (best_address->connected == GNUNET_NO) ) &&
1584 (addresses->in_transmit == GNUNET_NO) &&
1585 ( (best_address == NULL) ||
1586 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1587 best_address = addresses;
1588 /* FIXME: also give lower-latency addresses that are not
1589 connected a chance some times... */
1590 addresses = addresses->next;
1592 if (unix_address != NULL)
1596 if (unix_address != NULL)
1598 best_address = unix_address;
1600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1603 if (best_address != NULL)
1607 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1608 "Best address found (`%s') has latency of %llu ms.\n",
1609 (best_address->addrlen > 0)
1610 ? a2s (best_address->ready_list->plugin->short_name,
1612 best_address->addrlen)
1614 best_address->latency.rel_value);
1619 GNUNET_STATISTICS_update (stats,
1620 gettext_noop ("# transmission attempts failed (no address)"),
1625 return best_address;
1631 * We should re-try transmitting to the given peer,
1632 * hopefully we've learned something in the meantime.
1635 retry_transmission_task (void *cls,
1636 const struct GNUNET_SCHEDULER_TaskContext *tc)
1638 struct NeighbourList *n = cls;
1640 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1641 try_transmission_to_peer (n);
1646 * Check the ready list for the given neighbour and if a plugin is
1647 * ready for transmission (and if we have a message), do so!
1649 * @param neighbour target peer for which to transmit
1652 try_transmission_to_peer (struct NeighbourList *n)
1654 struct ReadyList *rl;
1655 struct MessageQueue *mq;
1656 struct GNUNET_TIME_Relative timeout;
1660 if (n->messages_head == NULL)
1663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1664 "Transmission queue for `%4s' is empty\n",
1665 GNUNET_i2s (&neighbour->id));
1667 return; /* nothing to do */
1670 mq = n->messages_head;
1671 force_address = GNUNET_YES;
1672 if (mq->specific_address == NULL)
1675 mq->specific_address = ats_get_preferred_address(ats, n);
1676 GNUNET_STATISTICS_update (stats,
1677 gettext_noop ("# transport selected peer address freely"),
1680 force_address = GNUNET_NO;
1682 if (mq->specific_address == NULL)
1684 GNUNET_STATISTICS_update (stats,
1685 gettext_noop ("# transport failed to selected peer address"),
1688 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1689 if (timeout.rel_value == 0)
1692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1693 "No destination address available to transmit message of size %u to peer `%4s'\n",
1694 mq->message_buf_size,
1695 GNUNET_i2s (&mq->neighbour_id));
1697 GNUNET_STATISTICS_update (stats,
1698 gettext_noop ("# bytes in message queue for other peers"),
1699 - (int64_t) mq->message_buf_size,
1701 GNUNET_STATISTICS_update (stats,
1702 gettext_noop ("# bytes discarded (no destination address available)"),
1703 mq->message_buf_size,
1705 if (mq->client != NULL)
1706 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1707 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1711 return; /* nobody ready */
1713 GNUNET_STATISTICS_update (stats,
1714 gettext_noop ("# message delivery deferred (no address)"),
1717 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1718 GNUNET_SCHEDULER_cancel (n->retry_task);
1719 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1720 &retry_transmission_task,
1723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1724 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1725 mq->message_buf_size,
1726 GNUNET_i2s (&mq->neighbour_id),
1729 /* FIXME: might want to trigger peerinfo lookup here
1730 (unless that's already pending...) */
1733 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1736 if (mq->specific_address->connected == GNUNET_NO)
1737 mq->specific_address->connect_attempts++;
1738 rl = mq->specific_address->ready_list;
1739 mq->plugin = rl->plugin;
1740 if (!mq->internal_msg)
1741 mq->specific_address->in_transmit = GNUNET_YES;
1743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1744 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1745 mq->message_buf_size,
1746 GNUNET_i2s (&neighbour->id),
1747 (mq->specific_address->addr != NULL)
1748 ? a2s (mq->plugin->short_name,
1749 mq->specific_address->addr,
1750 mq->specific_address->addrlen)
1752 rl->plugin->short_name);
1754 GNUNET_STATISTICS_update (stats,
1755 gettext_noop ("# bytes in message queue for other peers"),
1756 - (int64_t) mq->message_buf_size,
1758 GNUNET_STATISTICS_update (stats,
1759 gettext_noop ("# bytes pending with plugins"),
1760 mq->message_buf_size,
1762 ret = rl->plugin->api->send (rl->plugin->api->cls,
1765 mq->message_buf_size,
1767 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1768 mq->specific_address->session,
1769 mq->specific_address->addr,
1770 mq->specific_address->addrlen,
1772 &transmit_send_continuation, mq);
1775 /* failure, but 'send' would not call continuation in this case,
1776 so we need to do it here! */
1777 transmit_send_continuation (mq,
1785 * Send the specified message to the specified peer.
1787 * @param client source of the transmission request (can be NULL)
1788 * @param peer_address ForeignAddressList where we should send this message
1789 * @param priority how important is the message
1790 * @param timeout how long do we have to transmit?
1791 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1792 * @param message_buf_size total size of all messages in message_buf
1793 * @param is_internal is this an internal message; these are pre-pended and
1794 * also do not count for plugins being "ready" to transmit
1795 * @param neighbour handle to the neighbour for transmission
1798 transmit_to_peer (struct TransportClient *client,
1799 struct ForeignAddressList *peer_address,
1800 unsigned int priority,
1801 struct GNUNET_TIME_Relative timeout,
1802 const char *message_buf,
1803 size_t message_buf_size,
1804 int is_internal, struct NeighbourList *neighbour)
1806 struct MessageQueue *mq;
1811 /* check for duplicate submission */
1812 mq = neighbour->messages_head;
1815 if (mq->client == client)
1817 /* client transmitted to same peer twice
1818 before getting SEND_OK! */
1826 GNUNET_STATISTICS_update (stats,
1827 gettext_noop ("# bytes in message queue for other peers"),
1830 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1831 mq->specific_address = peer_address;
1832 mq->client = client;
1833 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1834 memcpy (&mq[1], message_buf, message_buf_size);
1835 mq->message_buf = (const char*) &mq[1];
1836 mq->message_buf_size = message_buf_size;
1837 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1838 mq->internal_msg = is_internal;
1839 mq->priority = priority;
1840 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1842 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1843 neighbour->messages_tail,
1846 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1847 neighbour->messages_tail,
1848 neighbour->messages_tail,
1850 try_transmission_to_peer (neighbour);
1857 struct GeneratorContext
1859 struct TransportPlugin *plug_pos;
1860 struct OwnAddressList *addr_pos;
1861 struct GNUNET_TIME_Absolute expiration;
1869 address_generator (void *cls, size_t max, void *buf)
1871 struct GeneratorContext *gc = cls;
1874 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1876 gc->plug_pos = gc->plug_pos->next;
1877 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1879 if (NULL == gc->plug_pos)
1884 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1887 gc->addr_pos->addrlen, buf, max);
1888 gc->addr_pos = gc->addr_pos->next;
1894 * Construct our HELLO message from all of the addresses of
1895 * all of the transports.
1900 struct GNUNET_HELLO_Message *hello;
1901 struct TransportClient *cpos;
1902 struct NeighbourList *npos;
1903 struct GeneratorContext gc;
1905 gc.plug_pos = plugins;
1906 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1907 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1908 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1911 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1913 GNUNET_STATISTICS_update (stats,
1914 gettext_noop ("# refreshed my HELLO"),
1918 while (cpos != NULL)
1920 transmit_to_client (cpos,
1921 (const struct GNUNET_MessageHeader *) hello,
1926 GNUNET_free_non_null (our_hello);
1928 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1930 while (npos != NULL)
1933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1934 "Transmitting updated `%s' to neighbour `%4s'\n",
1935 "HELLO", GNUNET_i2s (&npos->id));
1937 GNUNET_STATISTICS_update (stats,
1938 gettext_noop ("# transmitted my HELLO to other peers"),
1941 transmit_to_peer (NULL, NULL, 0,
1942 HELLO_ADDRESS_EXPIRATION,
1943 (const char *) our_hello,
1944 GNUNET_HELLO_size(our_hello),
1952 * Task used to clean up expired addresses for a plugin.
1954 * @param cls closure
1958 expire_address_task (void *cls,
1959 const struct GNUNET_SCHEDULER_TaskContext *tc);
1963 * Update the list of addresses for this plugin,
1964 * expiring those that are past their expiration date.
1966 * @param plugin addresses of which plugin should be recomputed?
1967 * @param fresh set to GNUNET_YES if a new address was added
1968 * and we need to regenerate the HELLO even if nobody
1972 update_addresses (struct TransportPlugin *plugin,
1975 static struct GNUNET_TIME_Absolute last_update;
1976 struct GNUNET_TIME_Relative min_remaining;
1977 struct GNUNET_TIME_Relative remaining;
1978 struct GNUNET_TIME_Absolute now;
1979 struct OwnAddressList *pos;
1980 struct OwnAddressList *prev;
1981 struct OwnAddressList *next;
1984 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1985 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1986 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1987 now = GNUNET_TIME_absolute_get ();
1988 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1989 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
1991 pos = plugin->addresses;
1995 if (pos->expires.abs_value < now.abs_value)
1997 expired = GNUNET_YES;
1999 plugin->addresses = pos->next;
2001 prev->next = pos->next;
2006 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2007 if (remaining.rel_value < min_remaining.rel_value)
2008 min_remaining = remaining;
2014 if (expired || fresh)
2019 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2020 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2022 plugin->address_update_task
2023 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2024 &expire_address_task, plugin);
2029 * Task used to clean up expired addresses for a plugin.
2031 * @param cls closure
2035 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2037 struct TransportPlugin *plugin = cls;
2039 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2040 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2041 update_addresses (plugin, GNUNET_NO);
2046 * Iterator over hash map entries that NULLs the session of validation
2047 * entries that match the given session.
2049 * @param cls closure (the 'struct Session*' to match against)
2050 * @param key current key code (peer ID, not used)
2051 * @param value value in the hash map ('struct ValidationEntry*')
2052 * @return GNUNET_YES (we should continue to iterate)
2055 remove_session_validations (void *cls,
2056 const GNUNET_HashCode * key,
2059 struct Session *session = cls;
2060 struct ValidationEntry *ve = value;
2062 if (session == ve->session)
2069 * We've been disconnected from the other peer (for some
2070 * connection-oriented transport). Either quickly
2071 * re-establish the connection or signal the disconnect
2074 * Only signal CORE level disconnect if ALL addresses
2075 * for the peer are exhausted.
2077 * @param p overall plugin context
2078 * @param nl neighbour that was disconnected
2081 try_fast_reconnect (struct TransportPlugin *p,
2082 struct NeighbourList *nl)
2084 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2085 /* Note: the idea here is to hide problems with transports (or
2086 switching between plugins) from the core to eliminate the need to
2087 re-negotiate session keys and the like; OTOH, we should tell core
2088 quickly (much faster than timeout) `if a connection was lost and
2089 could not be re-established (i.e. other peer went down or is
2090 unable / refuses to communicate);
2092 So we should consider:
2093 1) ideally: our own willingness / need to connect
2094 2) prior failures to connect to this peer (by plugin)
2095 3) ideally: reasons why other peer terminated (as far as knowable)
2097 Most importantly, it must be POSSIBLE for another peer to terminate
2098 a connection for a while (without us instantly re-establishing it).
2099 Similarly, if another peer is gone we should quickly notify CORE.
2100 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2101 on the other end), we should reconnect in such a way that BOTH CORE
2102 services never even notice.
2103 Furthermore, the same mechanism (or small variation) could be used
2104 to switch to a better-performing plugin (ATS).
2106 Finally, this needs to be tested throughly... */
2109 * GNUNET_NO in the call below makes transport disconnect the peer,
2110 * even if only a single address (out of say, six) went away. This
2111 * function must be careful to ONLY disconnect if the peer is gone,
2112 * not just a specifi address.
2114 * More specifically, half the places it was used had it WRONG.
2117 /* No reconnect, signal disconnect instead! */
2118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2119 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2120 "try_fast_reconnect");
2121 disconnect_neighbour (nl, GNUNET_YES);
2126 * Function that will be called whenever the plugin internally
2127 * cleans up a session pointer and hence the service needs to
2128 * discard all of those sessions as well. Plugins that do not
2129 * use sessions can simply omit calling this function and always
2130 * use NULL wherever a session pointer is needed.
2132 * @param cls closure
2133 * @param peer which peer was the session for
2134 * @param session which session is being destoyed
2137 plugin_env_session_end (void *cls,
2138 const struct GNUNET_PeerIdentity *peer,
2139 struct Session *session)
2141 struct TransportPlugin *p = cls;
2142 struct NeighbourList *nl;
2143 struct ReadyList *rl;
2144 struct ForeignAddressList *pos;
2145 struct ForeignAddressList *prev;
2147 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2148 &remove_session_validations,
2150 nl = find_neighbour (peer);
2152 return; /* was never marked as connected */
2156 if (rl->plugin == p)
2161 return; /* was never marked as connected */
2163 pos = rl->addresses;
2164 while ( (pos != NULL) &&
2165 (pos->session != session) )
2171 return; /* was never marked as connected */
2172 pos->session = NULL;
2173 if (pos->addrlen != 0)
2175 if (nl->received_pong != GNUNET_NO)
2176 try_fast_reconnect (p, nl);
2179 /* was inbound connection, free 'pos' */
2181 rl->addresses = pos->next;
2183 prev->next = pos->next;
2184 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2186 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2187 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2190 if (nl->received_pong == GNUNET_NO)
2191 return; /* nothing to do, never connected... */
2192 /* check if we have any validated addresses left */
2193 pos = rl->addresses;
2198 try_fast_reconnect (p, nl);
2203 /* no valid addresses left, signal disconnect! */
2205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2206 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2207 "plugin_env_session_end");
2208 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2209 * it means there aren't any left for this PLUGIN/PEER combination! So
2210 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2211 * when it isn't necessary. Using GNUNET_YES at least checks to see
2212 * if there are any addresses that work first, so as not to overdo it.
2215 disconnect_neighbour (nl, GNUNET_YES);
2220 * Function that must be called by each plugin to notify the
2221 * transport service about the addresses under which the transport
2222 * provided by the plugin can be reached.
2224 * @param cls closure
2225 * @param name name of the transport that generated the address
2226 * @param addr one of the addresses of the host, NULL for the last address
2227 * the specific address format depends on the transport
2228 * @param addrlen length of the address
2229 * @param expires when should this address automatically expire?
2232 plugin_env_notify_address (void *cls,
2236 struct GNUNET_TIME_Relative expires)
2238 struct TransportPlugin *p = cls;
2239 struct OwnAddressList *al;
2240 struct GNUNET_TIME_Absolute abex;
2242 GNUNET_assert (addr != NULL);
2243 abex = GNUNET_TIME_relative_to_absolute (expires);
2244 GNUNET_assert (p == find_transport (name));
2248 if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2251 update_addresses (p, GNUNET_NO);
2257 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2258 al->next = p->addresses;
2261 al->addrlen = addrlen;
2262 memcpy (&al[1], addr, addrlen);
2263 update_addresses (p, GNUNET_YES);
2268 * Notify all of our clients about a peer connecting.
2271 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2272 struct GNUNET_TIME_Relative latency,
2275 struct ConnectInfoMessage * cim;
2276 struct TransportClient *cpos;
2281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2282 "Notifying clients about connection from `%s'\n",
2285 GNUNET_STATISTICS_update (stats,
2286 gettext_noop ("# peers connected"),
2291 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2292 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2296 cim = GNUNET_malloc (size);
2298 cim->header.size = htons (size);
2299 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2300 cim->ats_count = htonl(2);
2301 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2302 (&(cim->ats))[0].value = htonl (distance);
2303 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2304 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2305 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2306 (&(cim->ats))[2].value = htonl (0);
2307 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2309 /* notify ats about connecting peer */
2310 ats_notify_peer_connect(ats, peer, &(cim->ats));
2313 while (cpos != NULL)
2315 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2324 * Notify all of our clients about a peer disconnecting.
2327 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2329 struct DisconnectInfoMessage dim;
2330 struct TransportClient *cpos;
2333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2334 "Notifying clients about lost connection to `%s'\n",
2337 GNUNET_STATISTICS_update (stats,
2338 gettext_noop ("# peers connected"),
2341 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2342 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2343 dim.reserved = htonl (0);
2344 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2346 /* notify ats about connecting peer */
2347 ats_notify_peer_disconnect(ats, peer);
2350 while (cpos != NULL)
2352 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2359 * Find a ForeignAddressList entry for the given neighbour
2360 * that matches the given address and transport.
2362 * @param neighbour which peer we care about
2363 * @param tname name of the transport plugin
2364 * @param session session to look for, NULL for 'any'; otherwise
2365 * can be used for the service to "learn" this session ID
2367 * @param addr binary address
2368 * @param addrlen length of addr
2369 * @return NULL if no such entry exists
2371 static struct ForeignAddressList *
2372 find_peer_address(struct NeighbourList *neighbour,
2374 struct Session *session,
2378 struct ReadyList *head;
2379 struct ForeignAddressList *pos;
2381 head = neighbour->plugins;
2382 while (head != NULL)
2384 if (0 == strcmp (tname, head->plugin->short_name))
2390 pos = head->addresses;
2391 while ( (pos != NULL) &&
2392 ( (pos->addrlen != addrlen) ||
2393 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2395 if ( (session != NULL) &&
2396 (pos->session == session) )
2400 if ( (session != NULL) && (pos != NULL) )
2401 pos->session = session; /* learn it! */
2407 * Get the peer address struct for the given neighbour and
2408 * address. If it doesn't yet exist, create it.
2410 * @param neighbour which peer we care about
2411 * @param tname name of the transport plugin
2412 * @param session session of the plugin, or NULL for none
2413 * @param addr binary address
2414 * @param addrlen length of addr
2415 * @return NULL if we do not have a transport plugin for 'tname'
2417 static struct ForeignAddressList *
2418 add_peer_address (struct NeighbourList *neighbour,
2420 struct Session *session,
2424 struct ReadyList *head;
2425 struct ForeignAddressList *ret;
2427 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2430 head = neighbour->plugins;
2432 while (head != NULL)
2434 if (0 == strcmp (tname, head->plugin->short_name))
2440 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2441 ret->session = session;
2444 ret->addr = (const char*) &ret[1];
2445 memcpy (&ret[1], addr, addrlen);
2451 ret->addrlen = addrlen;
2452 ret->expires = GNUNET_TIME_relative_to_absolute
2453 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2454 ret->latency = GNUNET_TIME_relative_get_forever();
2456 ret->timeout = GNUNET_TIME_relative_to_absolute
2457 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2458 ret->ready_list = head;
2459 ret->next = head->addresses;
2460 head->addresses = ret;
2466 * Closure for 'add_validated_address'.
2468 struct AddValidatedAddressContext
2471 * Entry that has been validated.
2473 const struct ValidationEntry *ve;
2476 * Flag set after we have added the address so
2477 * that we terminate the iteration next time.
2484 * Callback function used to fill a buffer of max bytes with a list of
2485 * addresses in the format used by HELLOs. Should use
2486 * "GNUNET_HELLO_add_address" as a helper function.
2488 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2489 * @param max maximum number of bytes that can be written to buf
2490 * @param buf where to write the address information
2491 * @return number of bytes written, 0 to signal the
2492 * end of the iteration.
2495 add_validated_address (void *cls,
2496 size_t max, void *buf)
2498 struct AddValidatedAddressContext *avac = cls;
2499 const struct ValidationEntry *ve = avac->ve;
2501 if (GNUNET_YES == avac->done)
2503 avac->done = GNUNET_YES;
2504 return GNUNET_HELLO_add_address (ve->transport_name,
2505 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2515 * Closure for 'check_address_exists'.
2517 struct CheckAddressExistsClosure
2520 * Address to check for.
2525 * Name of the transport.
2532 struct Session *session;
2535 * Set to GNUNET_YES if the address exists.
2548 * Iterator over hash map entries. Checks if the given
2549 * validation entry is for the same address as what is given
2552 * @param cls the 'struct CheckAddressExistsClosure*'
2553 * @param key current key code (ignored)
2554 * @param value value in the hash map ('struct ValidationEntry')
2555 * @return GNUNET_YES if we should continue to
2556 * iterate (mismatch), GNUNET_NO if not (entry matched)
2559 check_address_exists (void *cls,
2560 const GNUNET_HashCode * key,
2563 struct CheckAddressExistsClosure *caec = cls;
2564 struct ValidationEntry *ve = value;
2566 if ( (0 == strcmp (caec->tname,
2567 ve->transport_name)) &&
2568 (caec->addrlen == ve->addrlen) &&
2569 (0 == memcmp (caec->addr,
2573 caec->exists = GNUNET_YES;
2576 if ( (ve->session != NULL) &&
2577 (caec->session == ve->session) )
2579 caec->exists = GNUNET_YES;
2588 * Iterator to free entries in the validation_map.
2590 * @param cls closure (unused)
2591 * @param key current key code
2592 * @param value value in the hash map (validation to abort)
2593 * @return GNUNET_YES (always)
2596 abort_validation (void *cls,
2597 const GNUNET_HashCode * key,
2600 struct ValidationEntry *va = value;
2602 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2603 GNUNET_SCHEDULER_cancel (va->timeout_task);
2604 GNUNET_free (va->transport_name);
2605 if (va->chvc != NULL)
2607 va->chvc->ve_count--;
2608 if (va->chvc->ve_count == 0)
2610 GNUNET_CONTAINER_DLL_remove (chvc_head,
2613 GNUNET_free (va->chvc);
2623 * HELLO validation cleanup task (validation failed).
2625 * @param cls the 'struct ValidationEntry' that failed
2626 * @param tc scheduler context (unused)
2629 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2631 struct ValidationEntry *va = cls;
2632 struct GNUNET_PeerIdentity pid;
2634 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2635 GNUNET_STATISTICS_update (stats,
2636 gettext_noop ("# address validation timeouts"),
2639 GNUNET_CRYPTO_hash (&va->publicKey,
2641 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2643 GNUNET_break (GNUNET_OK ==
2644 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2647 abort_validation (NULL, NULL, va);
2652 neighbour_timeout_task (void *cls,
2653 const struct GNUNET_SCHEDULER_TaskContext *tc)
2655 struct NeighbourList *n = cls;
2658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2659 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2661 GNUNET_STATISTICS_update (stats,
2662 gettext_noop ("# disconnects due to timeout"),
2665 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2666 disconnect_neighbour (n, GNUNET_NO);
2671 * Schedule the job that will cause us to send a PING to the
2672 * foreign address to evaluate its validity and latency.
2674 * @param fal address to PING
2677 schedule_next_ping (struct ForeignAddressList *fal);
2681 * Add the given address to the list of foreign addresses
2682 * available for the given peer (check for duplicates).
2684 * @param cls the respective 'struct NeighbourList' to update
2685 * @param tname name of the transport
2686 * @param expiration expiration time
2687 * @param addr the address
2688 * @param addrlen length of the address
2689 * @return GNUNET_OK (always)
2692 add_to_foreign_address_list (void *cls,
2694 struct GNUNET_TIME_Absolute expiration,
2698 struct NeighbourList *n = cls;
2699 struct ForeignAddressList *fal;
2702 GNUNET_STATISTICS_update (stats,
2703 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2707 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2710 #if DEBUG_TRANSPORT_HELLO
2711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2712 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2713 a2s (tname, addr, addrlen),
2715 GNUNET_i2s (&n->id),
2716 expiration.abs_value);
2718 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2721 GNUNET_STATISTICS_update (stats,
2722 gettext_noop ("# previously validated addresses lacking transport"),
2728 fal->expires = GNUNET_TIME_absolute_max (expiration,
2730 schedule_next_ping (fal);
2736 fal->expires = GNUNET_TIME_absolute_max (expiration,
2741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2742 "Failed to add new address for `%4s'\n",
2743 GNUNET_i2s (&n->id));
2746 if (fal->validated == GNUNET_NO)
2748 fal->validated = GNUNET_YES;
2749 GNUNET_STATISTICS_update (stats,
2750 gettext_noop ("# peer addresses considered valid"),
2754 if (try == GNUNET_YES)
2756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2757 "Have new addresses, will try to trigger transmissions.\n");
2758 try_transmission_to_peer (n);
2765 * Add addresses in validated HELLO "h" to the set of addresses
2766 * we have for this peer.
2768 * @param cls closure ('struct NeighbourList*')
2769 * @param peer id of the peer, NULL for last call
2770 * @param h hello message for the peer (can be NULL)
2771 * @param err_msg NULL if successful, otherwise contains error message
2774 add_hello_for_peer (void *cls,
2775 const struct GNUNET_PeerIdentity *peer,
2776 const struct GNUNET_HELLO_Message *h,
2777 const char *err_msg)
2779 struct NeighbourList *n = cls;
2781 if (err_msg != NULL)
2783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2784 _("Error in communication with PEERINFO service\n"));
2789 GNUNET_STATISTICS_update (stats,
2790 gettext_noop ("# outstanding peerinfo iterate requests"),
2797 return; /* no HELLO available */
2799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2800 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2804 if (GNUNET_YES != n->public_key_valid)
2806 GNUNET_HELLO_get_key (h, &n->publicKey);
2807 n->public_key_valid = GNUNET_YES;
2809 GNUNET_HELLO_iterate_addresses (h,
2811 &add_to_foreign_address_list,
2817 * Create a fresh entry in our neighbour list for the given peer.
2818 * Will try to transmit our current HELLO to the new neighbour.
2819 * Do not call this function directly, use 'setup_peer_check_blacklist.
2821 * @param peer the peer for which we create the entry
2822 * @param do_hello should we schedule transmitting a HELLO
2823 * @return the new neighbour list entry
2825 static struct NeighbourList *
2826 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2829 struct NeighbourList *n;
2830 struct TransportPlugin *tp;
2831 struct ReadyList *rl;
2834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2835 "Setting up state for neighbour `%4s'\n",
2838 GNUNET_assert (our_hello != NULL);
2839 GNUNET_STATISTICS_update (stats,
2840 gettext_noop ("# active neighbours"),
2843 n = GNUNET_malloc (sizeof (struct NeighbourList));
2844 n->next = neighbours;
2848 GNUNET_TIME_relative_to_absolute
2849 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2850 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2851 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2852 MAX_BANDWIDTH_CARRY_S);
2856 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2858 rl = GNUNET_malloc (sizeof (struct ReadyList));
2860 rl->next = n->plugins;
2863 rl->addresses = NULL;
2867 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2869 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2870 &neighbour_timeout_task, n);
2873 GNUNET_STATISTICS_update (stats,
2874 gettext_noop ("# peerinfo new neighbor iterate requests"),
2877 GNUNET_STATISTICS_update (stats,
2878 gettext_noop ("# outstanding peerinfo iterate requests"),
2881 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2882 GNUNET_TIME_UNIT_FOREVER_REL,
2883 &add_hello_for_peer, n);
2885 GNUNET_STATISTICS_update (stats,
2886 gettext_noop ("# HELLO's sent to new neighbors"),
2889 transmit_to_peer (NULL, NULL, 0,
2890 HELLO_ADDRESS_EXPIRATION,
2891 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2899 * Function called after we have checked if communicating
2900 * with a given peer is acceptable.
2902 * @param cls closure
2903 * @param n NULL if communication is not acceptable
2905 typedef void (*SetupContinuation)(void *cls,
2906 struct NeighbourList *n);
2910 * Information kept for each client registered to perform
2916 * This is a linked list.
2918 struct Blacklisters *next;
2921 * This is a linked list.
2923 struct Blacklisters *prev;
2926 * Client responsible for this entry.
2928 struct GNUNET_SERVER_Client *client;
2931 * Blacklist check that we're currently performing.
2933 struct BlacklistCheck *bc;
2939 * Head of DLL of blacklisting clients.
2941 static struct Blacklisters *bl_head;
2944 * Tail of DLL of blacklisting clients.
2946 static struct Blacklisters *bl_tail;
2950 * Context we use when performing a blacklist check.
2952 struct BlacklistCheck
2956 * This is a linked list.
2958 struct BlacklistCheck *next;
2961 * This is a linked list.
2963 struct BlacklistCheck *prev;
2966 * Peer being checked.
2968 struct GNUNET_PeerIdentity peer;
2971 * Option for setup neighbour afterwards.
2976 * Continuation to call with the result.
2978 SetupContinuation cont;
2986 * Current transmission request handle for this client, or NULL if no
2987 * request is pending.
2989 struct GNUNET_CONNECTION_TransmitHandle *th;
2992 * Our current position in the blacklisters list.
2994 struct Blacklisters *bl_pos;
2997 * Current task performing the check.
2999 GNUNET_SCHEDULER_TaskIdentifier task;
3004 * Head of DLL of active blacklisting queries.
3006 static struct BlacklistCheck *bc_head;
3009 * Tail of DLL of active blacklisting queries.
3011 static struct BlacklistCheck *bc_tail;
3015 * Perform next action in the blacklist check.
3017 * @param cls the 'struct BlacklistCheck*'
3021 do_blacklist_check (void *cls,
3022 const struct GNUNET_SCHEDULER_TaskContext *tc);
3025 * Transmit blacklist query to the client.
3027 * @param cls the 'struct BlacklistCheck'
3028 * @param size number of bytes allowed
3029 * @param buf where to copy the message
3030 * @return number of bytes copied to buf
3033 transmit_blacklist_message (void *cls,
3037 struct BlacklistCheck *bc = cls;
3038 struct Blacklisters *bl;
3039 struct BlacklistMessage bm;
3044 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3045 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3050 bm.header.size = htons (sizeof (struct BlacklistMessage));
3051 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3052 bm.is_allowed = htonl (0);
3054 memcpy (buf, &bm, sizeof (bm));
3055 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3061 * Perform next action in the blacklist check.
3063 * @param cls the 'struct BlacklistCheck*'
3067 do_blacklist_check (void *cls,
3068 const struct GNUNET_SCHEDULER_TaskContext *tc)
3070 struct BlacklistCheck *bc = cls;
3071 struct Blacklisters *bl;
3073 bc->task = GNUNET_SCHEDULER_NO_TASK;
3077 bc->cont (bc->cont_cls,
3078 setup_new_neighbour (&bc->peer, bc->do_hello));
3085 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3086 sizeof (struct BlacklistMessage),
3087 GNUNET_TIME_UNIT_FOREVER_REL,
3088 &transmit_blacklist_message,
3095 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3096 * does not yet exist, check the blacklist. If the blacklist says creating
3097 * one is acceptable, create one and call the continuation; otherwise
3098 * call the continuation with NULL.
3100 * @param peer peer to setup or look up a struct NeighbourList for
3101 * @param do_hello should we also schedule sending our HELLO to the peer
3102 * if this is a new record
3103 * @param cont function to call with the 'struct NeigbhbourList*'
3104 * @param cont_cls closure for cont
3107 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3109 SetupContinuation cont,
3112 struct NeighbourList *n;
3113 struct BlacklistCheck *bc;
3115 n = find_neighbour(peer);
3122 if (bl_head == NULL)
3125 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3127 setup_new_neighbour(peer, do_hello);
3130 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3131 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3133 bc->do_hello = do_hello;
3135 bc->cont_cls = cont_cls;
3136 bc->bl_pos = bl_head;
3137 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3143 * Function called with the result of querying a new blacklister about
3144 * it being allowed (or not) to continue to talk to an existing neighbour.
3146 * @param cls the original 'struct NeighbourList'
3147 * @param n NULL if we need to disconnect
3150 confirm_or_drop_neighbour (void *cls,
3151 struct NeighbourList *n)
3153 struct NeighbourList * orig = cls;
3157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3158 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3159 "confirm_or_drop_neighboUr");
3160 disconnect_neighbour (orig, GNUNET_NO);
3166 * Handle a request to start a blacklist.
3168 * @param cls closure (always NULL)
3169 * @param client identification of the client
3170 * @param message the actual message
3173 handle_blacklist_init (void *cls,
3174 struct GNUNET_SERVER_Client *client,
3175 const struct GNUNET_MessageHeader *message)
3177 struct Blacklisters *bl;
3178 struct BlacklistCheck *bc;
3179 struct NeighbourList *n;
3184 if (bl->client == client)
3187 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3192 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3193 bl->client = client;
3194 GNUNET_SERVER_client_keep (client);
3195 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3196 /* confirm that all existing connections are OK! */
3200 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3201 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3203 bc->do_hello = GNUNET_NO;
3204 bc->cont = &confirm_or_drop_neighbour;
3207 if (n == neighbours) /* all would wait for the same client, no need to
3208 create more than just the first task right now */
3209 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3217 * Handle a request to blacklist a peer.
3219 * @param cls closure (always NULL)
3220 * @param client identification of the client
3221 * @param message the actual message
3224 handle_blacklist_reply (void *cls,
3225 struct GNUNET_SERVER_Client *client,
3226 const struct GNUNET_MessageHeader *message)
3228 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3229 struct Blacklisters *bl;
3230 struct BlacklistCheck *bc;
3233 while ( (bl != NULL) &&
3234 (bl->client != client) )
3238 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3243 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3245 bc->cont (bc->cont_cls, NULL);
3246 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3251 bc->bl_pos = bc->bl_pos->next;
3252 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3255 /* check if any other bc's are waiting for this blacklister */
3259 if ( (bc->bl_pos == bl) &&
3260 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3261 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3269 * Send periodic PING messages to a given foreign address.
3271 * @param cls our 'struct PeriodicValidationContext*'
3272 * @param tc task context
3275 send_periodic_ping (void *cls,
3276 const struct GNUNET_SCHEDULER_TaskContext *tc)
3278 struct ForeignAddressList *peer_address = cls;
3279 struct TransportPlugin *tp;
3280 struct ValidationEntry *va;
3281 struct NeighbourList *neighbour;
3282 struct TransportPingMessage ping;
3283 struct CheckAddressExistsClosure caec;
3285 uint16_t hello_size;
3289 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3290 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3292 tp = peer_address->ready_list->plugin;
3293 neighbour = peer_address->ready_list->neighbour;
3294 if (GNUNET_YES != neighbour->public_key_valid)
3296 /* no public key yet, try again later */
3297 schedule_next_ping (peer_address);
3300 caec.addr = peer_address->addr;
3301 caec.addrlen = peer_address->addrlen;
3302 caec.tname = tp->short_name;
3303 caec.session = peer_address->session;
3304 caec.exists = GNUNET_NO;
3305 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3306 &check_address_exists,
3308 if (caec.exists == GNUNET_YES)
3310 /* During validation attempts we will likely trigger the other
3311 peer trying to validate our address which in turn will cause
3312 it to send us its HELLO, so we expect to hit this case rather
3313 frequently. Only print something if we are very verbose. */
3314 #if DEBUG_TRANSPORT > 1
3315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3316 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3317 (peer_address->addr != NULL)
3318 ? a2s (tp->short_name,
3320 peer_address->addrlen)
3323 GNUNET_i2s (&neighbour->id));
3325 schedule_next_ping (peer_address);
3328 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3329 va->transport_name = GNUNET_strdup (tp->short_name);
3330 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3332 va->send_time = GNUNET_TIME_absolute_get();
3333 va->session = peer_address->session;
3334 if (peer_address->addr != NULL)
3336 va->addr = (const void*) &va[1];
3337 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3338 va->addrlen = peer_address->addrlen;
3340 memcpy(&va->publicKey,
3341 &neighbour->publicKey,
3342 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3344 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3345 &timeout_hello_validation,
3347 GNUNET_CONTAINER_multihashmap_put (validation_map,
3348 &neighbour->id.hashPubKey,
3350 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3352 if (peer_address->validated != GNUNET_YES)
3353 hello_size = GNUNET_HELLO_size(our_hello);
3357 tsize = sizeof(struct TransportPingMessage) + hello_size;
3359 if (peer_address->addr != NULL)
3361 slen = strlen (tp->short_name) + 1;
3362 tsize += slen + peer_address->addrlen;
3366 slen = 0; /* make gcc happy */
3368 message_buf = GNUNET_malloc(tsize);
3369 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3370 ping.challenge = htonl(va->challenge);
3371 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3372 if (peer_address->validated != GNUNET_YES)
3374 memcpy(message_buf, our_hello, hello_size);
3377 if (peer_address->addr != NULL)
3379 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3380 peer_address->addrlen +
3382 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3385 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3387 peer_address->addrlen);
3391 ping.header.size = htons(sizeof(struct TransportPingMessage));
3394 memcpy(&message_buf[hello_size],
3396 sizeof(struct TransportPingMessage));
3398 #if DEBUG_TRANSPORT_REVALIDATION
3399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3400 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3401 (peer_address->addr != NULL)
3402 ? a2s (peer_address->plugin->short_name,
3404 peer_address->addrlen)
3407 GNUNET_i2s (&neighbour->id),
3408 "HELLO", hello_size,
3411 if (peer_address->validated != GNUNET_YES)
3412 GNUNET_STATISTICS_update (stats,
3413 gettext_noop ("# PING with HELLO messages sent"),
3417 GNUNET_STATISTICS_update (stats,
3418 gettext_noop ("# PING without HELLO messages sent"),
3421 GNUNET_STATISTICS_update (stats,
3422 gettext_noop ("# PING messages sent for re-validation"),
3425 transmit_to_peer (NULL, peer_address,
3426 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3427 HELLO_VERIFICATION_TIMEOUT,
3429 GNUNET_YES, neighbour);
3430 GNUNET_free(message_buf);
3431 schedule_next_ping (peer_address);
3436 * Schedule the job that will cause us to send a PING to the
3437 * foreign address to evaluate its validity and latency.
3439 * @param fal address to PING
3442 schedule_next_ping (struct ForeignAddressList *fal)
3444 struct GNUNET_TIME_Relative delay;
3446 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3448 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3449 delay.rel_value /= 2; /* do before expiration */
3450 delay = GNUNET_TIME_relative_min (delay,
3451 LATENCY_EVALUATION_MAX_DELAY);
3452 if (GNUNET_YES != fal->estimated)
3454 delay = GNUNET_TIME_UNIT_ZERO;
3455 fal->estimated = GNUNET_YES;
3457 if (GNUNET_YES == fal->connected)
3459 delay = GNUNET_TIME_relative_min (delay,
3460 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3462 /* FIXME: also adjust delay based on how close the last
3463 observed latency is to the latency of the best alternative */
3464 /* bound how fast we can go */
3465 delay = GNUNET_TIME_relative_max (delay,
3466 GNUNET_TIME_UNIT_SECONDS);
3467 /* randomize a bit (to avoid doing all at the same time) */
3468 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3469 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3470 &send_periodic_ping,
3478 * Function that will be called if we receive some payload
3479 * from another peer.
3481 * @param message the payload
3482 * @param n peer who claimed to be the sender
3485 handle_payload_message (const struct GNUNET_MessageHeader *message,
3486 struct NeighbourList *n)
3488 struct InboundMessage *im;
3489 struct TransportClient *cpos;
3492 msize = ntohs (message->size);
3493 if (n->received_pong == GNUNET_NO)
3495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3496 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3497 ntohs (message->type),
3498 ntohs (message->size),
3499 GNUNET_i2s (&n->id));
3500 GNUNET_free_non_null (n->pre_connect_message_buffer);
3501 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3502 memcpy (n->pre_connect_message_buffer, message, msize);
3507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3508 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3509 ntohs (message->type),
3510 ntohs (message->size),
3511 GNUNET_i2s (&n->id));
3513 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3516 n->quota_violation_count++;
3518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3519 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3520 n->in_tracker.available_bytes_per_s__,
3521 n->quota_violation_count);
3523 /* Discount 32k per violation */
3524 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3529 if (n->quota_violation_count > 0)
3531 /* try to add 32k back */
3532 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3534 n->quota_violation_count--;
3537 GNUNET_STATISTICS_update (stats,
3538 gettext_noop ("# payload received from other peers"),
3541 /* transmit message to all clients */
3542 uint32_t ats_count = 2;
3543 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3544 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3547 im = GNUNET_malloc (size);
3548 im->header.size = htons (size);
3549 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3551 im->ats_count = htonl(ats_count);
3552 /* Setting ATS data */
3553 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3554 (&(im->ats))[0].value = htonl (n->distance);
3555 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3556 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3557 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3558 (&(im->ats))[ats_count].value = htonl (0);
3560 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3562 while (cpos != NULL)
3564 transmit_to_client (cpos, &im->header, GNUNET_YES);
3572 * Iterator over hash map entries. Checks if the given validation
3573 * entry is for the same challenge as what is given in the PONG.
3575 * @param cls the 'struct TransportPongMessage*'
3576 * @param key peer identity
3577 * @param value value in the hash map ('struct ValidationEntry')
3578 * @return GNUNET_YES if we should continue to
3579 * iterate (mismatch), GNUNET_NO if not (entry matched)
3582 check_pending_validation (void *cls,
3583 const GNUNET_HashCode * key,
3586 const struct TransportPongMessage *pong = cls;
3587 struct ValidationEntry *ve = value;
3588 struct AddValidatedAddressContext avac;
3589 unsigned int challenge = ntohl(pong->challenge);
3590 struct GNUNET_HELLO_Message *hello;
3591 struct GNUNET_PeerIdentity target;
3592 struct NeighbourList *n;
3593 struct ForeignAddressList *fal;
3594 struct OwnAddressList *oal;
3595 struct TransportPlugin *tp;
3596 struct GNUNET_MessageHeader *prem;
3602 ps = ntohs (pong->header.size);
3603 if (ps < sizeof (struct TransportPongMessage))
3605 GNUNET_break_op (0);
3608 addr = (const char*) &pong[1];
3609 slen = strlen (ve->transport_name) + 1;
3610 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3611 (ve->challenge != challenge) ||
3612 (addr[slen-1] != '\0') ||
3613 (0 != strcmp (addr, ve->transport_name)) ||
3614 (ntohl (pong->purpose.size)
3615 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3617 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3618 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3623 alen = ps - sizeof (struct TransportPongMessage) - slen;
3624 switch (ntohl (pong->purpose.purpose))
3626 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3627 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3628 (0 != memcmp (&addr[slen],
3632 return GNUNET_YES; /* different entry, keep trying! */
3634 if (0 != memcmp (&pong->pid,
3636 sizeof (struct GNUNET_PeerIdentity)))
3638 GNUNET_break_op (0);
3642 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3647 GNUNET_break_op (0);
3652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3653 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3655 a2s (ve->transport_name,
3656 (const struct sockaddr *) ve->addr,
3658 ve->transport_name);
3661 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3662 if (0 != memcmp (&pong->pid,
3664 sizeof (struct GNUNET_PeerIdentity)))
3666 GNUNET_break_op (0);
3669 if (ve->addrlen != 0)
3671 /* must have been for a different validation entry */
3674 tp = find_transport (ve->transport_name);
3680 oal = tp->addresses;
3683 if ( (oal->addrlen == alen) &&
3684 (0 == memcmp (&oal[1],
3692 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3693 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3694 a2s (ve->transport_name,
3700 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3705 GNUNET_break_op (0);
3710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3711 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3713 a2s (ve->transport_name,
3716 ve->transport_name);
3720 GNUNET_break_op (0);
3723 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3725 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3726 _("Received expired signature. Check system time.\n"));
3729 GNUNET_STATISTICS_update (stats,
3730 gettext_noop ("# address validation successes"),
3733 /* create the updated HELLO */
3734 GNUNET_CRYPTO_hash (&ve->publicKey,
3735 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3736 &target.hashPubKey);
3737 if (ve->addr != NULL)
3739 avac.done = GNUNET_NO;
3741 hello = GNUNET_HELLO_create (&ve->publicKey,
3742 &add_validated_address,
3744 GNUNET_PEERINFO_add_peer (peerinfo,
3746 GNUNET_free (hello);
3748 n = find_neighbour (&target);
3751 n->publicKey = ve->publicKey;
3752 n->public_key_valid = GNUNET_YES;
3753 fal = add_peer_address (n,
3758 GNUNET_assert (fal != NULL);
3759 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3760 fal->validated = GNUNET_YES;
3761 mark_address_connected (fal);
3762 GNUNET_STATISTICS_update (stats,
3763 gettext_noop ("# peer addresses considered valid"),
3766 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3767 schedule_next_ping (fal);
3768 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3769 n->latency = fal->latency;
3771 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3773 n->distance = fal->distance;
3774 if (GNUNET_NO == n->received_pong)
3776 n->received_pong = GNUNET_YES;
3778 notify_clients_connect (&target, n->latency, n->distance);
3779 if (NULL != (prem = n->pre_connect_message_buffer))
3781 n->pre_connect_message_buffer = NULL;
3782 handle_payload_message (prem, n);
3786 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3788 GNUNET_SCHEDULER_cancel (n->retry_task);
3789 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3790 try_transmission_to_peer (n);
3794 /* clean up validation entry */
3795 GNUNET_assert (GNUNET_YES ==
3796 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3799 abort_validation (NULL, NULL, ve);
3805 * Function that will be called if we receive a validation
3806 * of an address challenge that we transmitted to another
3807 * peer. Note that the validation should only be considered
3808 * acceptable if the challenge matches AND if the sender
3809 * address is at least a plausible address for this peer
3810 * (otherwise we may be seeing a MiM attack).
3812 * @param cls closure
3813 * @param message the pong message
3814 * @param peer who responded to our challenge
3815 * @param sender_address string describing our sender address (as observed
3816 * by the other peer in binary format)
3817 * @param sender_address_len number of bytes in 'sender_address'
3820 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3821 const struct GNUNET_PeerIdentity *peer,
3822 const char *sender_address,
3823 size_t sender_address_len)
3825 #if DEBUG_TRANSPORT > 1
3826 /* we get tons of these that just get discarded, only log
3827 if we are quite verbose */
3828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3829 "Receiving `%s' message from `%4s'.\n", "PONG",
3832 GNUNET_STATISTICS_update (stats,
3833 gettext_noop ("# PONG messages received"),
3836 if (GNUNET_SYSERR !=
3837 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3839 &check_pending_validation,
3842 /* This is *expected* to happen a lot since we send
3843 PONGs to *all* known addresses of the sender of
3844 the PING, so most likely we get multiple PONGs
3845 per PING, and all but the first PONG will end up
3846 here. So really we should not print anything here
3847 unless we want to be very, very verbose... */
3848 #if DEBUG_TRANSPORT > 2
3849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3850 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3862 * Try to validate a neighbour's address by sending him our HELLO and a PING.
3864 * @param cls the 'struct ValidationEntry*'
3865 * @param neighbour neighbour to validate, NULL if validation failed
3868 transmit_hello_and_ping (void *cls,
3869 struct NeighbourList *neighbour)
3871 struct ValidationEntry *va = cls;
3872 struct ForeignAddressList *peer_address;
3873 struct TransportPingMessage ping;
3874 uint16_t hello_size;
3877 struct GNUNET_PeerIdentity id;
3880 GNUNET_CRYPTO_hash (&va->publicKey,
3881 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3883 if (neighbour == NULL)
3885 /* FIXME: stats... */
3886 GNUNET_break (GNUNET_OK ==
3887 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3890 abort_validation (NULL, NULL, va);
3893 neighbour->publicKey = va->publicKey;
3894 neighbour->public_key_valid = GNUNET_YES;
3895 peer_address = add_peer_address (neighbour,
3896 va->transport_name, NULL,
3897 (const void*) &va[1],
3899 if (peer_address == NULL)
3901 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3902 "Failed to add peer `%4s' for plugin `%s'\n",
3903 GNUNET_i2s (&neighbour->id),
3904 va->transport_name);
3905 GNUNET_break (GNUNET_OK ==
3906 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3909 abort_validation (NULL, NULL, va);
3912 hello_size = GNUNET_HELLO_size(our_hello);
3913 slen = strlen(va->transport_name) + 1;
3914 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3915 message_buf = GNUNET_malloc(tsize);
3916 ping.challenge = htonl(va->challenge);
3917 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3918 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3919 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3920 memcpy(message_buf, our_hello, hello_size);
3921 memcpy(&message_buf[hello_size],
3923 sizeof(struct TransportPingMessage));
3924 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3927 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3932 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3935 : a2s (va->transport_name,
3936 (const void*) &va[1], va->addrlen),
3938 GNUNET_i2s (&neighbour->id),
3939 "HELLO", hello_size,
3940 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3943 GNUNET_STATISTICS_update (stats,
3944 gettext_noop ("# PING messages sent for initial validation"),
3947 transmit_to_peer (NULL, peer_address,
3948 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3949 HELLO_VERIFICATION_TIMEOUT,
3951 GNUNET_YES, neighbour);
3952 GNUNET_free(message_buf);
3957 * Check if the given address is already being validated; if not,
3958 * append the given address to the list of entries that are being be
3959 * validated and initiate validation.
3961 * @param cls closure ('struct CheckHelloValidatedContext *')
3962 * @param tname name of the transport
3963 * @param expiration expiration time
3964 * @param addr the address
3965 * @param addrlen length of the address
3966 * @return GNUNET_OK (always)
3969 run_validation (void *cls,
3971 struct GNUNET_TIME_Absolute expiration,
3975 struct CheckHelloValidatedContext *chvc = cls;
3976 struct GNUNET_PeerIdentity id;
3977 struct TransportPlugin *tp;
3978 struct ValidationEntry *va;
3979 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3980 struct CheckAddressExistsClosure caec;
3981 struct OwnAddressList *oal;
3983 GNUNET_assert (addr != NULL);
3985 GNUNET_STATISTICS_update (stats,
3986 gettext_noop ("# peer addresses scheduled for validation"),
3989 tp = find_transport (tname);
3992 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3993 GNUNET_ERROR_TYPE_BULK,
3995 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
3997 GNUNET_STATISTICS_update (stats,
3998 gettext_noop ("# peer addresses not validated (plugin not available)"),
4003 /* check if this is one of our own addresses */
4004 oal = tp->addresses;
4007 if ( (oal->addrlen == addrlen) &&
4008 (0 == memcmp (&oal[1],
4012 /* not plausible, this address is equivalent to our own address! */
4013 GNUNET_STATISTICS_update (stats,
4014 gettext_noop ("# peer addresses not validated (loopback)"),
4021 GNUNET_HELLO_get_key (chvc->hello, &pk);
4022 GNUNET_CRYPTO_hash (&pk,
4024 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4027 if (is_blacklisted(&id, tp))
4030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4031 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4039 caec.addrlen = addrlen;
4040 caec.session = NULL;
4042 caec.exists = GNUNET_NO;
4043 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4044 &check_address_exists,
4046 if (caec.exists == GNUNET_YES)
4048 /* During validation attempts we will likely trigger the other
4049 peer trying to validate our address which in turn will cause
4050 it to send us its HELLO, so we expect to hit this case rather
4051 frequently. Only print something if we are very verbose. */
4052 #if DEBUG_TRANSPORT > 1
4053 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4054 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4055 a2s (tname, addr, addrlen),
4059 GNUNET_STATISTICS_update (stats,
4060 gettext_noop ("# peer addresses not validated (in progress)"),
4065 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4068 va->transport_name = GNUNET_strdup (tname);
4069 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4071 va->send_time = GNUNET_TIME_absolute_get();
4072 va->addr = (const void*) &va[1];
4073 memcpy (&va[1], addr, addrlen);
4074 va->addrlen = addrlen;
4075 GNUNET_HELLO_get_key (chvc->hello,
4077 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4078 &timeout_hello_validation,
4080 GNUNET_CONTAINER_multihashmap_put (validation_map,
4083 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4084 setup_peer_check_blacklist (&id, GNUNET_NO,
4085 &transmit_hello_and_ping,
4092 * Check if addresses in validated hello "h" overlap with
4093 * those in "chvc->hello" and validate the rest.
4095 * @param cls closure
4096 * @param peer id of the peer, NULL for last call
4097 * @param h hello message for the peer (can be NULL)
4098 * @param err_msg NULL if successful, otherwise contains error message
4101 check_hello_validated (void *cls,
4102 const struct GNUNET_PeerIdentity *peer,
4103 const struct GNUNET_HELLO_Message *h,
4104 const char *err_msg)
4106 struct CheckHelloValidatedContext *chvc = cls;
4107 struct GNUNET_HELLO_Message *plain_hello;
4108 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4109 struct GNUNET_PeerIdentity target;
4110 struct NeighbourList *n;
4112 if (err_msg != NULL)
4114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4115 _("Error in communication with PEERINFO service\n"));
4121 GNUNET_STATISTICS_update (stats,
4122 gettext_noop ("# outstanding peerinfo iterate requests"),
4126 if (GNUNET_NO == chvc->hello_known)
4128 /* notify PEERINFO about the peer now, so that we at least
4129 have the public key if some other component needs it */
4130 GNUNET_HELLO_get_key (chvc->hello, &pk);
4131 GNUNET_CRYPTO_hash (&pk,
4132 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4133 &target.hashPubKey);
4134 plain_hello = GNUNET_HELLO_create (&pk,
4137 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4138 GNUNET_free (plain_hello);
4139 #if DEBUG_TRANSPORT_HELLO
4140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4141 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4143 GNUNET_i2s (&target));
4145 GNUNET_STATISTICS_update (stats,
4146 gettext_noop ("# new HELLOs requiring full validation"),
4149 GNUNET_HELLO_iterate_addresses (chvc->hello,
4156 GNUNET_STATISTICS_update (stats,
4157 gettext_noop ("# duplicate HELLO (peer known)"),
4162 if (chvc->ve_count == 0)
4164 GNUNET_CONTAINER_DLL_remove (chvc_head,
4173 #if DEBUG_TRANSPORT_HELLO
4174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4175 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4179 chvc->hello_known = GNUNET_YES;
4180 n = find_neighbour (peer);
4183 #if DEBUG_TRANSPORT_HELLO
4184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4185 "Calling hello_iterate_addresses for %s!\n",
4188 GNUNET_HELLO_iterate_addresses (h,
4190 &add_to_foreign_address_list,
4192 try_transmission_to_peer (n);
4196 #if DEBUG_TRANSPORT_HELLO
4197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4198 "No existing neighbor record for %s!\n",
4201 GNUNET_STATISTICS_update (stats,
4202 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4206 GNUNET_STATISTICS_update (stats,
4207 gettext_noop ("# HELLO validations (update case)"),
4210 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4212 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4219 * Process HELLO-message.
4221 * @param plugin transport involved, may be NULL
4222 * @param message the actual message
4223 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4226 process_hello (struct TransportPlugin *plugin,
4227 const struct GNUNET_MessageHeader *message)
4230 struct GNUNET_PeerIdentity target;
4231 const struct GNUNET_HELLO_Message *hello;
4232 struct CheckHelloValidatedContext *chvc;
4233 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4234 #if DEBUG_TRANSPORT_HELLO > 2
4237 hsize = ntohs (message->size);
4238 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4239 (hsize < sizeof (struct GNUNET_MessageHeader)))
4242 return GNUNET_SYSERR;
4244 GNUNET_STATISTICS_update (stats,
4245 gettext_noop ("# HELLOs received for validation"),
4249 /* first, check if load is too high */
4250 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4252 GNUNET_STATISTICS_update (stats,
4253 gettext_noop ("# HELLOs ignored due to high load"),
4256 #if DEBUG_TRANSPORT_HELLO
4257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4258 "Ignoring `%s' for `%4s', load too high.\n",
4260 GNUNET_i2s (&target));
4264 hello = (const struct GNUNET_HELLO_Message *) message;
4265 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4267 #if DEBUG_TRANSPORT_HELLO
4268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4269 "Unable to get public key from `%s' for `%4s'!\n",
4271 GNUNET_i2s (&target));
4273 GNUNET_break_op (0);
4274 return GNUNET_SYSERR;
4277 GNUNET_CRYPTO_hash (&publicKey,
4278 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4279 &target.hashPubKey);
4281 #if DEBUG_TRANSPORT_HELLO
4282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4283 "Received `%s' message for `%4s'\n",
4285 GNUNET_i2s (&target));
4288 if (0 == memcmp (&my_identity,
4290 sizeof (struct GNUNET_PeerIdentity)))
4292 GNUNET_STATISTICS_update (stats,
4293 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4299 while (NULL != chvc)
4301 if (GNUNET_HELLO_equals (hello,
4303 GNUNET_TIME_absolute_get ()).abs_value > 0)
4305 #if DEBUG_TRANSPORT_HELLO > 2
4306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4307 "Received duplicate `%s' message for `%4s'; ignored\n",
4309 GNUNET_i2s (&target));
4311 return GNUNET_OK; /* validation already pending */
4313 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4314 GNUNET_break (0 != memcmp (hello, chvc->hello,
4315 GNUNET_HELLO_size(hello)));
4320 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4321 if ((NULL != temp_neighbor))
4323 fprintf(stderr, "Already know peer, ignoring hello\n");
4328 #if DEBUG_TRANSPORT_HELLO > 2
4331 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4333 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4336 GNUNET_i2s (&target),
4338 GNUNET_HELLO_size(hello));
4342 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4344 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4345 memcpy (&chvc[1], hello, hsize);
4346 GNUNET_CONTAINER_DLL_insert (chvc_head,
4349 /* finally, check if HELLO was previously validated
4350 (continuation will then schedule actual validation) */
4351 GNUNET_STATISTICS_update (stats,
4352 gettext_noop ("# peerinfo process hello iterate requests"),
4355 GNUNET_STATISTICS_update (stats,
4356 gettext_noop ("# outstanding peerinfo iterate requests"),
4359 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4361 HELLO_VERIFICATION_TIMEOUT,
4362 &check_hello_validated, chvc);
4368 * The peer specified by the given neighbour has timed-out or a plugin
4369 * has disconnected. We may either need to do nothing (other plugins
4370 * still up), or trigger a full disconnect and clean up. This
4371 * function updates our state and does the necessary notifications.
4372 * Also notifies our clients that the neighbour is now officially
4375 * @param n the neighbour list entry for the peer
4376 * @param check GNUNET_YES to check if ALL addresses for this peer
4377 * are gone, GNUNET_NO to force a disconnect of the peer
4378 * regardless of whether other addresses exist.
4381 disconnect_neighbour (struct NeighbourList *n, int check)
4383 struct ReadyList *rpos;
4384 struct NeighbourList *npos;
4385 struct NeighbourList *nprev;
4386 struct MessageQueue *mq;
4387 struct ForeignAddressList *peer_addresses;
4388 struct ForeignAddressList *peer_pos;
4390 if (GNUNET_YES == check)
4393 while (NULL != rpos)
4395 peer_addresses = rpos->addresses;
4396 while (peer_addresses != NULL)
4398 if (GNUNET_YES == peer_addresses->connected)
4400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4401 "NOT Disconnecting from `%4s', still have live addresses!\n",
4402 GNUNET_i2s (&n->id));
4403 return; /* still connected */
4405 peer_addresses = peer_addresses->next;
4411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4412 "Disconnecting from `%4s'\n",
4413 GNUNET_i2s (&n->id));
4415 /* remove n from neighbours list */
4418 while ((npos != NULL) && (npos != n))
4423 GNUNET_assert (npos != NULL);
4425 neighbours = n->next;
4427 nprev->next = n->next;
4429 /* notify all clients about disconnect */
4430 if (GNUNET_YES == n->received_pong)
4431 notify_clients_disconnect (&n->id);
4433 /* clean up all plugins, cancel connections and pending transmissions */
4434 while (NULL != (rpos = n->plugins))
4436 n->plugins = rpos->next;
4437 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4438 while (rpos->addresses != NULL)
4440 peer_pos = rpos->addresses;
4441 rpos->addresses = peer_pos->next;
4442 if (peer_pos->connected == GNUNET_YES)
4443 GNUNET_STATISTICS_update (stats,
4444 gettext_noop ("# connected addresses"),
4447 if (GNUNET_YES == peer_pos->validated)
4448 GNUNET_STATISTICS_update (stats,
4449 gettext_noop ("# peer addresses considered valid"),
4452 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4454 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4455 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4457 GNUNET_free(peer_pos);
4462 /* free all messages on the queue */
4463 while (NULL != (mq = n->messages_head))
4465 GNUNET_STATISTICS_update (stats,
4466 gettext_noop ("# bytes in message queue for other peers"),
4467 - (int64_t) mq->message_buf_size,
4469 GNUNET_STATISTICS_update (stats,
4470 gettext_noop ("# bytes discarded due to disconnect"),
4471 mq->message_buf_size,
4473 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4476 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4478 sizeof(struct GNUNET_PeerIdentity)));
4481 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4483 GNUNET_SCHEDULER_cancel (n->timeout_task);
4484 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4486 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4488 GNUNET_SCHEDULER_cancel (n->retry_task);
4489 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4491 if (n->piter != NULL)
4493 GNUNET_PEERINFO_iterate_cancel (n->piter);
4494 GNUNET_STATISTICS_update (stats,
4495 gettext_noop ("# outstanding peerinfo iterate requests"),
4500 /* finally, free n itself */
4501 GNUNET_STATISTICS_update (stats,
4502 gettext_noop ("# active neighbours"),
4505 GNUNET_free_non_null (n->pre_connect_message_buffer);
4511 * We have received a PING message from someone. Need to send a PONG message
4512 * in response to the peer by any means necessary.
4515 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4516 const struct GNUNET_PeerIdentity *peer,
4517 struct Session *session,
4518 const char *sender_address,
4519 uint16_t sender_address_len)
4521 struct TransportPlugin *plugin = cls;
4522 struct SessionHeader *session_header = (struct SessionHeader*) session;
4523 struct TransportPingMessage *ping;
4524 struct TransportPongMessage *pong;
4525 struct NeighbourList *n;
4526 struct ReadyList *rl;
4527 struct ForeignAddressList *fal;
4528 struct OwnAddressList *oal;
4533 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4535 GNUNET_break_op (0);
4536 return GNUNET_SYSERR;
4539 ping = (struct TransportPingMessage *) message;
4540 if (0 != memcmp (&ping->target,
4541 plugin->env.my_identity,
4542 sizeof (struct GNUNET_PeerIdentity)))
4544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4545 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4547 (sender_address != NULL)
4548 ? a2s (plugin->short_name,
4549 (const struct sockaddr *)sender_address,
4552 GNUNET_i2s (&ping->target));
4553 return GNUNET_SYSERR;
4556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4557 "Processing `%s' from `%s'\n",
4559 (sender_address != NULL)
4560 ? a2s (plugin->short_name,
4561 (const struct sockaddr *)sender_address,
4565 GNUNET_STATISTICS_update (stats,
4566 gettext_noop ("# PING messages received"),
4569 addr = (const char*) &ping[1];
4570 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4571 slen = strlen (plugin->short_name) + 1;
4574 /* peer wants to confirm that we have an outbound connection to him */
4575 if (session == NULL)
4577 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4578 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4580 return GNUNET_SYSERR;
4582 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4583 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4584 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4585 pong->purpose.size =
4586 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4588 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4589 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4590 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4591 pong->challenge = ping->challenge;
4592 pong->addrlen = htonl(sender_address_len + slen);
4595 sizeof(struct GNUNET_PeerIdentity));
4599 if ((sender_address!=NULL) && (sender_address_len > 0))
4600 memcpy (&((char*)&pong[1])[slen],
4602 sender_address_len);
4603 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4605 /* create / update cached sig */
4607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4608 "Creating PONG signature to indicate active connection.\n");
4610 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4611 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4612 GNUNET_assert (GNUNET_OK ==
4613 GNUNET_CRYPTO_rsa_sign (my_private_key,
4615 &session_header->pong_signature));
4619 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4621 memcpy (&pong->signature,
4622 &session_header->pong_signature,
4623 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4629 /* peer wants to confirm that this is one of our addresses */
4633 plugin->api->check_address (plugin->api->cls,
4637 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4638 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4639 a2s (plugin->short_name,
4644 oal = plugin->addresses;
4647 if ( (oal->addrlen == alen) &&
4654 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4655 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4656 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4657 pong->purpose.size =
4658 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4660 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4661 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4662 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4663 pong->challenge = ping->challenge;
4664 pong->addrlen = htonl(alen + slen);
4667 sizeof(struct GNUNET_PeerIdentity));
4668 memcpy (&pong[1], plugin->short_name, slen);
4669 memcpy (&((char*)&pong[1])[slen], addr, alen);
4670 if ( (oal != NULL) &&
4671 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4673 /* create / update cached sig */
4675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4676 "Creating PONG signature to indicate ownership.\n");
4678 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4679 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4680 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4681 GNUNET_assert (GNUNET_OK ==
4682 GNUNET_CRYPTO_rsa_sign (my_private_key,
4684 &oal->pong_signature));
4685 memcpy (&pong->signature,
4686 &oal->pong_signature,
4687 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4689 else if (oal == NULL)
4691 /* not using cache (typically DV-only) */
4692 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4693 GNUNET_assert (GNUNET_OK ==
4694 GNUNET_CRYPTO_rsa_sign (my_private_key,
4700 /* can used cached version */
4701 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4702 memcpy (&pong->signature,
4703 &oal->pong_signature,
4704 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4707 n = find_neighbour(peer);
4708 GNUNET_assert (n != NULL);
4709 /* first try reliable response transmission */
4713 fal = rl->addresses;
4716 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4719 ntohs (pong->header.size),
4720 TRANSPORT_PONG_PRIORITY,
4721 HELLO_VERIFICATION_TIMEOUT,
4729 GNUNET_STATISTICS_update (stats,
4730 gettext_noop ("# PONGs unicast via reliable transport"),
4740 /* no reliable method found, do multicast */
4741 GNUNET_STATISTICS_update (stats,
4742 gettext_noop ("# PONGs multicast to all available addresses"),
4748 fal = rl->addresses;
4751 transmit_to_peer(NULL, fal,
4752 TRANSPORT_PONG_PRIORITY,
4753 HELLO_VERIFICATION_TIMEOUT,
4755 ntohs(pong->header.size),
4768 * Function called by the plugin for each received message.
4769 * Update data volumes, possibly notify plugins about
4770 * reducing the rate at which they read from the socket
4771 * and generally forward to our receive callback.
4773 * @param cls the "struct TransportPlugin *" we gave to the plugin
4774 * @param peer (claimed) identity of the other peer
4775 * @param message the message, NULL if we only care about
4776 * learning about the delay until we should receive again
4777 * @param ats_data information for automatic transport selection
4778 * @param ats_count number of elements in ats not including 0-terminator
4779 * @param session identifier used for this session (can be NULL)
4780 * @param sender_address binary address of the sender (if observed)
4781 * @param sender_address_len number of bytes in sender_address
4782 * @return how long in ms the plugin should wait until receiving more data
4783 * (plugins that do not support this, can ignore the return value)
4785 static struct GNUNET_TIME_Relative
4786 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4787 const struct GNUNET_MessageHeader *message,
4788 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4790 struct Session *session,
4791 const char *sender_address,
4792 uint16_t sender_address_len)
4794 struct TransportPlugin *plugin = cls;
4795 struct ReadyList *service_context;
4796 struct ForeignAddressList *peer_address;
4798 struct NeighbourList *n;
4799 struct GNUNET_TIME_Relative ret;
4800 if (is_blacklisted (peer, plugin))
4801 return GNUNET_TIME_UNIT_FOREVER_REL;
4805 n = find_neighbour (peer);
4807 n = setup_new_neighbour (peer, GNUNET_YES);
4808 service_context = n->plugins;
4809 while ((service_context != NULL) && (plugin != service_context->plugin))
4810 service_context = service_context->next;
4811 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4812 peer_address = NULL;
4814 for (c=0; c<ats_count; c++)
4816 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4818 distance = ntohl(ats_data[c].value);
4821 /* notify ATS about incoming data */
4822 ats_notify_ats_data(ats, peer, ats_data);
4825 if (message != NULL)
4827 if ( (session != NULL) ||
4828 (sender_address != NULL) )
4829 peer_address = add_peer_address (n,
4833 sender_address_len);
4834 if (peer_address != NULL)
4836 peer_address->distance = distance;
4837 if (GNUNET_YES == peer_address->validated)
4838 mark_address_connected (peer_address);
4839 peer_address->timeout
4841 GNUNET_TIME_relative_to_absolute
4842 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4843 schedule_next_ping (peer_address);
4845 /* update traffic received amount ... */
4846 msize = ntohs (message->size);
4847 GNUNET_STATISTICS_update (stats,
4848 gettext_noop ("# bytes received from other peers"),
4851 n->distance = distance;
4853 GNUNET_TIME_relative_to_absolute
4854 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4855 GNUNET_SCHEDULER_cancel (n->timeout_task);
4857 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4858 &neighbour_timeout_task, n);
4859 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4861 /* dropping message due to frequent inbound volume violations! */
4862 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4863 GNUNET_ERROR_TYPE_BULK,
4865 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4866 n->in_tracker.available_bytes_per_s__,
4867 n->quota_violation_count);
4868 GNUNET_STATISTICS_update (stats,
4869 gettext_noop ("# bandwidth quota violations by other peers"),
4872 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4877 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4878 ntohs (message->type),
4879 ntohs (message->size),
4882 switch (ntohs (message->type))
4884 case GNUNET_MESSAGE_TYPE_HELLO:
4885 GNUNET_STATISTICS_update (stats,
4886 gettext_noop ("# HELLO messages received from other peers"),
4889 process_hello (plugin, message);
4891 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4892 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4894 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4895 handle_pong (plugin, message, peer, sender_address, sender_address_len);
4898 handle_payload_message (message, n);
4902 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4903 if (ret.rel_value > 0)
4905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4906 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4907 (unsigned long long) n->in_tracker.consumption_since_last_update__,
4908 (unsigned int) n->in_tracker.available_bytes_per_s__,
4909 (unsigned long long) ret.rel_value);
4910 GNUNET_STATISTICS_update (stats,
4911 gettext_noop ("# ms throttling suggested"),
4912 (int64_t) ret.rel_value,
4919 * Handle START-message. This is the first message sent to us
4920 * by any client which causes us to add it to our list.
4922 * @param cls closure (always NULL)
4923 * @param client identification of the client
4924 * @param message the actual message
4927 handle_start (void *cls,
4928 struct GNUNET_SERVER_Client *client,
4929 const struct GNUNET_MessageHeader *message)
4931 const struct StartMessage *start;
4932 struct TransportClient *c;
4933 struct ConnectInfoMessage * cim;
4934 struct NeighbourList *n;
4938 start = (const struct StartMessage*) message;
4940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4941 "Received `%s' request from client\n", "START");
4946 if (c->client == client)
4948 /* client already on our list! */
4950 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4955 if ( (GNUNET_NO != ntohl (start->do_check)) &&
4956 (0 != memcmp (&start->self,
4958 sizeof (struct GNUNET_PeerIdentity))) )
4960 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4961 _("Rejecting control connection from peer `%s', which is not me!\n"),
4962 GNUNET_i2s (&start->self));
4963 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4966 c = GNUNET_malloc (sizeof (struct TransportClient));
4970 if (our_hello != NULL)
4973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4974 "Sending our own `%s' to new client\n", "HELLO");
4976 transmit_to_client (c,
4977 (const struct GNUNET_MessageHeader *) our_hello,
4979 /* tell new client about all existing connections */
4981 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
4982 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4986 cim = GNUNET_malloc (size);
4987 cim->header.size = htons (size);
4988 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4989 cim->ats_count = htonl(ats_count);
4990 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4991 (&(cim->ats))[2].value = htonl (0);
4995 if (GNUNET_YES == n->received_pong)
4997 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
4998 (&(cim->ats))[0].value = htonl (n->distance);
4999 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5000 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5002 transmit_to_client (c, &cim->header, GNUNET_NO);
5008 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5013 * Handle HELLO-message.
5015 * @param cls closure (always NULL)
5016 * @param client identification of the client
5017 * @param message the actual message
5020 handle_hello (void *cls,
5021 struct GNUNET_SERVER_Client *client,
5022 const struct GNUNET_MessageHeader *message)
5026 GNUNET_STATISTICS_update (stats,
5027 gettext_noop ("# HELLOs received from clients"),
5030 ret = process_hello (NULL, message);
5031 GNUNET_SERVER_receive_done (client, ret);
5036 * Closure for 'transmit_client_message'; followed by
5037 * 'msize' bytes of the actual message.
5039 struct TransmitClientMessageContext
5042 * Client on whom's behalf we are sending.
5044 struct GNUNET_SERVER_Client *client;
5047 * Timeout for the transmission.
5049 struct GNUNET_TIME_Absolute timeout;
5057 * Size of the message in bytes.
5064 * Schedule transmission of a message we got from a client to a peer.
5066 * @param cls the 'struct TransmitClientMessageContext*'
5067 * @param n destination, or NULL on error (in that case, drop the message)
5070 transmit_client_message (void *cls,
5071 struct NeighbourList *n)
5073 struct TransmitClientMessageContext *tcmc = cls;
5074 struct TransportClient *tc;
5077 while ((tc != NULL) && (tc->client != tcmc->client))
5082 transmit_to_peer (tc, NULL, tcmc->priority,
5083 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5085 tcmc->msize, GNUNET_NO, n);
5087 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5088 GNUNET_SERVER_client_drop (tcmc->client);
5094 * Handle SEND-message.
5096 * @param cls closure (always NULL)
5097 * @param client identification of the client
5098 * @param message the actual message
5101 handle_send (void *cls,
5102 struct GNUNET_SERVER_Client *client,
5103 const struct GNUNET_MessageHeader *message)
5105 const struct OutboundMessage *obm;
5106 const struct GNUNET_MessageHeader *obmm;
5107 struct TransmitClientMessageContext *tcmc;
5111 size = ntohs (message->size);
5113 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5116 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5119 GNUNET_STATISTICS_update (stats,
5120 gettext_noop ("# payload received for other peers"),
5123 obm = (const struct OutboundMessage *) message;
5124 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5125 msize = size - sizeof (struct OutboundMessage);
5127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5128 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5129 "SEND", GNUNET_i2s (&obm->peer),
5133 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5134 tcmc->client = client;
5135 tcmc->priority = ntohl (obm->priority);
5136 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5137 tcmc->msize = msize;
5138 /* FIXME: this memcpy can be up to 7% of our total runtime */
5139 memcpy (&tcmc[1], obmm, msize);
5140 GNUNET_SERVER_client_keep (client);
5141 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5142 &transmit_client_message,
5148 * Handle request connect message
5150 * @param cls closure (always NULL)
5151 * @param client identification of the client
5152 * @param message the actual message
5155 handle_request_connect (void *cls,
5156 struct GNUNET_SERVER_Client *client,
5157 const struct GNUNET_MessageHeader *message)
5159 const struct TransportRequestConnectMessage *trcm =
5160 (const struct TransportRequestConnectMessage *) message;
5162 GNUNET_STATISTICS_update (stats,
5163 gettext_noop ("# REQUEST CONNECT messages received"),
5166 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5167 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5169 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5173 * Handle SET_QUOTA-message.
5175 * @param cls closure (always NULL)
5176 * @param client identification of the client
5177 * @param message the actual message
5180 handle_set_quota (void *cls,
5181 struct GNUNET_SERVER_Client *client,
5182 const struct GNUNET_MessageHeader *message)
5184 const struct QuotaSetMessage *qsm =
5185 (const struct QuotaSetMessage *) message;
5186 struct NeighbourList *n;
5188 GNUNET_STATISTICS_update (stats,
5189 gettext_noop ("# SET QUOTA messages received"),
5192 n = find_neighbour (&qsm->peer);
5195 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5196 GNUNET_STATISTICS_update (stats,
5197 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5204 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5206 (unsigned int) ntohl (qsm->quota.value__),
5207 (unsigned int) n->in_tracker.available_bytes_per_s__,
5208 GNUNET_i2s (&qsm->peer));
5210 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5212 if (0 == ntohl (qsm->quota.value__))
5214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5215 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5217 disconnect_neighbour (n, GNUNET_NO);
5219 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5224 * Take the given address and append it to the set of results sent back to
5227 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5228 * @param address the resolved name, NULL to indicate the last response
5231 transmit_address_to_client (void *cls, const char *address)
5233 struct GNUNET_SERVER_TransmitContext *tc = cls;
5236 if (NULL == address)
5239 slen = strlen (address) + 1;
5241 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5242 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5243 if (NULL == address)
5244 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5249 * Handle AddressLookup-message.
5251 * @param cls closure (always NULL)
5252 * @param client identification of the client
5253 * @param message the actual message
5256 handle_address_lookup (void *cls,
5257 struct GNUNET_SERVER_Client *client,
5258 const struct GNUNET_MessageHeader *message)
5260 const struct AddressLookupMessage *alum;
5261 struct TransportPlugin *lsPlugin;
5262 const char *nameTransport;
5263 const char *address;
5265 struct GNUNET_SERVER_TransmitContext *tc;
5266 struct GNUNET_TIME_Absolute timeout;
5267 struct GNUNET_TIME_Relative rtimeout;
5270 size = ntohs (message->size);
5271 if (size < sizeof (struct AddressLookupMessage))
5273 GNUNET_break_op (0);
5274 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5277 alum = (const struct AddressLookupMessage *) message;
5278 uint32_t addressLen = ntohl (alum->addrlen);
5279 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5281 GNUNET_break_op (0);
5282 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5285 address = (const char *) &alum[1];
5286 nameTransport = (const char *) &address[addressLen];
5288 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5290 GNUNET_break_op (0);
5291 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5294 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5295 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5296 numeric = ntohl (alum->numeric_only);
5297 lsPlugin = find_transport (nameTransport);
5298 if (NULL == lsPlugin)
5300 tc = GNUNET_SERVER_transmit_context_create (client);
5301 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5302 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5303 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5306 tc = GNUNET_SERVER_transmit_context_create (client);
5307 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5309 address, addressLen,
5312 &transmit_address_to_client, tc);
5317 * Setup the environment for this plugin.
5320 create_environment (struct TransportPlugin *plug)
5322 plug->env.cfg = cfg;
5323 plug->env.my_identity = &my_identity;
5324 plug->env.our_hello = &our_hello;
5325 plug->env.cls = plug;
5326 plug->env.receive = &plugin_env_receive;
5327 plug->env.notify_address = &plugin_env_notify_address;
5328 plug->env.session_end = &plugin_env_session_end;
5329 plug->env.max_connections = max_connect_per_transport;
5330 plug->env.stats = stats;
5335 * Start the specified transport (load the plugin).
5338 start_transport (struct GNUNET_SERVER_Handle *server,
5341 struct TransportPlugin *plug;
5344 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5345 _("Loading `%s' transport plugin\n"), name);
5346 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5347 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5348 create_environment (plug);
5349 plug->short_name = GNUNET_strdup (name);
5350 plug->lib_name = libname;
5351 plug->next = plugins;
5353 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5354 if (plug->api == NULL)
5356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5357 _("Failed to load transport plugin for `%s'\n"), name);
5358 GNUNET_free (plug->short_name);
5359 plugins = plug->next;
5360 GNUNET_free (libname);
5367 * Called whenever a client is disconnected. Frees our
5368 * resources associated with that client.
5370 * @param cls closure
5371 * @param client identification of the client
5374 client_disconnect_notification (void *cls,
5375 struct GNUNET_SERVER_Client *client)
5377 struct TransportClient *pos;
5378 struct TransportClient *prev;
5379 struct ClientMessageQueueEntry *mqe;
5380 struct Blacklisters *bl;
5381 struct BlacklistCheck *bc;
5386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5387 "Client disconnected, cleaning up.\n");
5389 /* clean up blacklister */
5393 if (bl->client == client)
5398 if (bc->bl_pos == bl)
5400 bc->bl_pos = bl->next;
5403 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5406 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5407 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5413 GNUNET_CONTAINER_DLL_remove (bl_head,
5416 GNUNET_SERVER_client_drop (bl->client);
5422 /* clean up 'normal' clients */
5425 while ((pos != NULL) && (pos->client != client))
5432 while (NULL != (mqe = pos->message_queue_head))
5434 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5435 pos->message_queue_tail,
5437 pos->message_count--;
5441 clients = pos->next;
5443 prev->next = pos->next;
5444 if (GNUNET_YES == pos->tcs_pending)
5449 if (pos->th != NULL)
5451 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5454 GNUNET_break (0 == pos->message_count);
5460 * Function called when the service shuts down. Unloads our plugins
5461 * and cancels pending validations.
5463 * @param cls closure, unused
5464 * @param tc task context (unused)
5467 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5469 struct TransportPlugin *plug;
5470 struct OwnAddressList *al;
5471 struct CheckHelloValidatedContext *chvc;
5473 while (neighbours != NULL)
5475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5476 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5478 disconnect_neighbour (neighbours, GNUNET_NO);
5481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5482 "Transport service is unloading plugins...\n");
5484 while (NULL != (plug = plugins))
5486 plugins = plug->next;
5487 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5489 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5490 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5492 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5493 GNUNET_free (plug->lib_name);
5494 GNUNET_free (plug->short_name);
5495 while (NULL != (al = plug->addresses))
5497 plug->addresses = al->next;
5502 if (my_private_key != NULL)
5503 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5504 GNUNET_free_non_null (our_hello);
5506 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5509 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5510 validation_map = NULL;
5514 /* free 'chvc' data structure */
5515 while (NULL != (chvc = chvc_head))
5517 chvc_head = chvc->next;
5518 if (chvc->piter != NULL)
5520 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5521 GNUNET_STATISTICS_update (stats,
5522 gettext_noop ("# outstanding peerinfo iterate requests"),
5528 GNUNET_assert (chvc->ve_count == 0);
5535 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5538 if (peerinfo != NULL)
5540 GNUNET_PEERINFO_disconnect (peerinfo);
5543 /* Can we assume those are gone by now, or do we need to clean up
5545 GNUNET_break (bl_head == NULL);
5546 GNUNET_break (bc_head == NULL);
5549 void ats_calculate_bandwidth_distribution (struct ATS_info * ats)
5551 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
5552 if (delta.rel_value < ats->min_delta.rel_value)
5555 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
5560 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CALCULATE DISTRIBUTION\n");
5562 ats->last = GNUNET_TIME_absolute_get();
5568 ats_schedule_calculation (void *cls,
5569 const struct GNUNET_SCHEDULER_TaskContext *tc)
5571 struct ATS_info *ats = (struct ATS_info *) cls;
5575 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5576 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
5580 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
5582 ats_calculate_bandwidth_distribution (ats);
5584 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5585 &ats_schedule_calculation, ats);
5589 int ats_map_remove_peer (void *cls,
5590 const GNUNET_HashCode * key,
5594 struct ATS_peer * p = (struct ATS_peer *) value;
5596 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "map_remove_peer_it: `%s'\n", GNUNET_i2s(&p->peer));
5605 struct ATS_info * ats_init ()
5607 struct ATS_info * ats;
5609 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_init\n");
5611 ats = GNUNET_malloc(sizeof (struct ATS_info));
5612 ats->peers = GNUNET_CONTAINER_multihashmap_create(10);
5613 GNUNET_assert(ats->peers!=NULL);
5615 ats->min_delta = ATS_MIN_INTERVAL;
5616 ats->reg_delta = ATS_EXEC_INTERVAL;
5618 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5620 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->reg_delta,
5621 &schedule_calculation, NULL);
5623 ats->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
5624 &schedule_calculation, NULL);
5626 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
5632 void ats_shutdown (struct ATS_info * ats)
5635 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
5637 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
5638 GNUNET_SCHEDULER_cancel(ats->ats_task);
5639 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
5641 GNUNET_CONTAINER_multihashmap_iterate (ats->peers,ats_map_remove_peer,NULL);
5642 GNUNET_CONTAINER_multihashmap_destroy (ats->peers);
5647 void ats_notify_peer_connect (struct ATS_info * ats,
5648 const struct GNUNET_PeerIdentity *peer,
5649 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5653 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
5656 while (ntohl(ats_data[c].type)!=0)
5659 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
5663 /* check if peer is already known */
5664 if (!GNUNET_CONTAINER_multihashmap_contains (ats->peers,&peer->hashPubKey))
5666 struct ATS_peer * p = GNUNET_malloc (sizeof (struct ATS_peer));
5667 memcpy(&p->peer, peer, sizeof (struct GNUNET_PeerIdentity));
5668 GNUNET_CONTAINER_multihashmap_put(ats->peers, &p->peer.hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
5671 ats_calculate_bandwidth_distribution(ats);
5674 void ats_notify_peer_disconnect (struct ATS_info * ats,
5675 const struct GNUNET_PeerIdentity *peer)
5678 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
5681 if (GNUNET_CONTAINER_multihashmap_contains (ats->peers, &peer->hashPubKey))
5683 ats_map_remove_peer(NULL, &peer->hashPubKey, GNUNET_CONTAINER_multihashmap_get (ats->peers, &peer->hashPubKey));
5684 GNUNET_CONTAINER_multihashmap_remove_all (ats->peers, &peer->hashPubKey);
5687 ats_calculate_bandwidth_distribution (ats);
5691 void ats_notify_ats_data (struct ATS_info * ats,
5692 const struct GNUNET_PeerIdentity *peer,
5693 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
5696 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
5698 ats_calculate_bandwidth_distribution(ats);
5701 struct ForeignAddressList * ats_get_preferred_address (struct ATS_info * ats,
5702 struct NeighbourList *n)
5705 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
5707 struct ReadyList *next = n->plugins;
5708 while (next != NULL)
5711 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
5715 return find_ready_address(n);
5719 * Initiate transport service.
5721 * @param cls closure
5722 * @param server the initialized server
5723 * @param c configuration to use
5727 struct GNUNET_SERVER_Handle *server,
5728 const struct GNUNET_CONFIGURATION_Handle *c)
5730 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
5731 {&handle_start, NULL,
5732 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
5733 {&handle_hello, NULL,
5734 GNUNET_MESSAGE_TYPE_HELLO, 0},
5735 {&handle_send, NULL,
5736 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
5737 {&handle_request_connect, NULL,
5738 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
5739 {&handle_set_quota, NULL,
5740 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
5741 {&handle_address_lookup, NULL,
5742 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
5744 {&handle_blacklist_init, NULL,
5745 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
5746 {&handle_blacklist_reply, NULL,
5747 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
5753 unsigned long long tneigh;
5757 stats = GNUNET_STATISTICS_create ("transport", cfg);
5758 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
5759 /* parse configuration */
5761 GNUNET_CONFIGURATION_get_value_number (c,
5766 GNUNET_CONFIGURATION_get_value_filename (c,
5768 "HOSTKEY", &keyfile)))
5770 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5772 ("Transport service is lacking key configuration settings. Exiting.\n"));
5773 GNUNET_SCHEDULER_shutdown ();
5776 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5779 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5780 validation_map = NULL;
5784 max_connect_per_transport = (uint32_t) tneigh;
5785 peerinfo = GNUNET_PEERINFO_connect (cfg);
5786 if (peerinfo == NULL)
5788 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5789 _("Could not access PEERINFO service. Exiting.\n"));
5790 GNUNET_SCHEDULER_shutdown ();
5793 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5796 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5797 validation_map = NULL;
5798 GNUNET_free (keyfile);
5801 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
5802 GNUNET_free (keyfile);
5803 if (my_private_key == NULL)
5805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5807 ("Transport service could not access hostkey. Exiting.\n"));
5808 GNUNET_SCHEDULER_shutdown ();
5811 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5814 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5815 validation_map = NULL;
5818 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
5819 GNUNET_CRYPTO_hash (&my_public_key,
5820 sizeof (my_public_key), &my_identity.hashPubKey);
5821 /* setup notification */
5822 GNUNET_SERVER_disconnect_notify (server,
5823 &client_disconnect_notification, NULL);
5824 /* load plugins... */
5827 GNUNET_CONFIGURATION_get_value_string (c,
5828 "TRANSPORT", "PLUGINS", &plugs))
5830 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5831 _("Starting transport plugins `%s'\n"), plugs);
5832 pos = strtok (plugs, " ");
5835 start_transport (server, pos);
5837 pos = strtok (NULL, " ");
5839 GNUNET_free (plugs);
5841 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
5842 &shutdown_task, NULL);
5847 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
5849 /* If we have a blacklist file, read from it */
5850 read_blacklist_file(cfg);
5851 /* process client requests */
5852 GNUNET_SERVER_add_handlers (server, handlers);
5857 * The main function for the transport service.
5859 * @param argc number of arguments from the command line
5860 * @param argv command line arguments
5861 * @return 0 ok, 1 on error
5864 main (int argc, char *const *argv)
5866 a2s (NULL, NULL, 0); /* make compiler happy */
5867 return (GNUNET_OK ==
5868 GNUNET_SERVICE_run (argc,
5871 GNUNET_SERVICE_OPTION_NONE,
5872 &run, NULL)) ? 0 : 1;
5875 /* end of gnunet-service-transport.c */