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"
45 #define DEBUG_BLACKLIST GNUNET_NO
47 #define DEBUG_PING_PONG GNUNET_NO
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
52 * Should we do some additional checks (to validate behavior
55 #define EXTRA_CHECKS GNUNET_YES
58 * How many messages can we have pending for a given client process
59 * before we start to drop incoming messages? We typically should
60 * have only one client and so this would be the primary buffer for
61 * messages, so the number should be chosen rather generously.
63 * The expectation here is that most of the time the queue is large
64 * enough so that a drop is virtually never required. Note that
65 * this value must be about as large as 'TOTAL_MSGS' in the
66 * 'test_transport_api_reliability.c', otherwise that testcase may
69 #define MAX_PENDING (128 * 1024)
72 * Size of the per-transport blacklist hash maps.
74 #define TRANSPORT_BLACKLIST_HT_SIZE 16
77 * How often should we try to reconnect to a peer using a particular
78 * transport plugin before giving up? Note that the plugin may be
79 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
81 #define MAX_CONNECT_RETRY 3
84 * Limit on the number of ready-to-run tasks when validating
85 * HELLOs. If more tasks are ready to run, we will drop
86 * HELLOs instead of validating them.
88 #define MAX_HELLO_LOAD 4
91 * How often must a peer violate bandwidth quotas before we start
92 * to simply drop its messages?
94 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
97 * How long until a HELLO verification attempt should time out?
98 * Must be rather small, otherwise a partially successful HELLO
99 * validation (some addresses working) might not be available
100 * before a client's request for a connection fails for good.
101 * Besides, if a single request to an address takes a long time,
102 * then the peer is unlikely worthwhile anyway.
104 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
107 * How long is a PONG signature valid? We'll recycle a signature until
108 * 1/4 of this time is remaining. PONGs should expire so that if our
109 * external addresses change an adversary cannot replay them indefinitely.
110 * OTOH, we don't want to spend too much time generating PONG signatures,
111 * so they must have some lifetime to reduce our CPU usage.
113 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
116 * Priority to use for PONG messages.
118 #define TRANSPORT_PONG_PRIORITY 4
121 * How often do we re-add (cheaper) plugins to our list of plugins
122 * to try for a given connected peer?
124 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
127 * After how long do we expire an address in a HELLO that we just
128 * validated? This value is also used for our own addresses when we
131 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
135 * How long before an existing address expires should we again try to
136 * validate it? Must be (significantly) smaller than
137 * HELLO_ADDRESS_EXPIRATION.
139 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
142 * Maximum frequency for re-evaluating latencies for all transport addresses.
144 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
147 * Maximum frequency for re-evaluating latencies for connected addresses.
149 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
151 #define VERY_BIG_DOUBLE_VALUE 100000000000LL
154 * List of addresses of other peers
156 struct ForeignAddressList
159 * This is a linked list.
161 struct ForeignAddressList *next;
164 * Which ready list does this entry belong to.
166 struct ReadyList *ready_list;
169 * How long until we auto-expire this address (unless it is
170 * re-confirmed by the transport)?
172 struct GNUNET_TIME_Absolute expires;
175 * Task used to re-validate addresses, updates latencies and
178 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
186 * Session (or NULL if no valid session currently exists or if the
187 * plugin does not use sessions).
189 struct Session *session;
191 struct ATS_ressource_entry * ressources;
194 * What was the last latency observed for this address, plugin and peer?
196 struct GNUNET_TIME_Relative latency;
199 * If we did not successfully transmit a message to the given peer
200 * via this connection during the specified time, we should consider
201 * the connection to be dead. This is used in the case that a TCP
202 * transport simply stalls writing to the stream but does not
203 * formerly get a signal that the other peer died.
205 struct GNUNET_TIME_Absolute timeout;
208 * How often have we tried to connect using this plugin? Used to
209 * discriminate against addresses that do not work well.
210 * FIXME: not yet used, but should be!
212 unsigned int connect_attempts;
215 * DV distance to this peer (1 if no DV is used).
216 * FIXME: need to set this from transport plugins!
226 * Have we ever estimated the latency of this address? Used to
227 * ensure that the first time we add an address, we immediately
233 * Are we currently connected via this address? The first time we
234 * successfully transmit or receive data to a peer via a particular
235 * address, we set this to GNUNET_YES. If we later get an error
236 * (disconnect notification, transmission failure, timeout), we set
237 * it back to GNUNET_NO.
242 * Is this plugin currently busy transmitting to the specific target?
243 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
244 * messages do not count as 'in transmit'.
249 * Has this address been validated yet?
257 * Entry in linked list of network addresses for ourselves. Also
258 * includes a cached signature for 'struct TransportPongMessage's.
260 struct OwnAddressList
263 * This is a linked list.
265 struct OwnAddressList *next;
268 * How long until we actually auto-expire this address (unless it is
269 * re-confirmed by the transport)?
271 struct GNUNET_TIME_Absolute expires;
274 * How long until the current signature expires? (ZERO if the
275 * signature was never created).
277 struct GNUNET_TIME_Absolute pong_sig_expires;
280 * Signature for a 'struct TransportPongMessage' for this address.
282 struct GNUNET_CRYPTO_RsaSignature pong_signature;
293 * Entry in linked list of all of our plugins.
295 struct TransportPlugin
299 * This is a linked list.
301 struct TransportPlugin *next;
304 * API of the transport as returned by the plugin's
305 * initialization function.
307 struct GNUNET_TRANSPORT_PluginFunctions *api;
310 * Short name for the plugin (i.e. "tcp").
315 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
320 * List of our known addresses for this transport.
322 struct OwnAddressList *addresses;
325 * Environment this transport service is using
328 struct GNUNET_TRANSPORT_PluginEnvironment env;
331 * ID of task that is used to clean up expired addresses.
333 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
336 * Set to GNUNET_YES if we need to scrap the existing list of
337 * "addresses" and start fresh when we receive the next address
338 * update from a transport. Set to GNUNET_NO if we should just add
339 * the new address to the list and wait for the commit call.
343 struct ATS_plugin * rc;
346 * Hashmap of blacklisted peers for this particular transport.
348 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
351 struct NeighbourList;
354 * For each neighbour we keep a list of messages
355 * that we still want to transmit to the neighbour.
361 * This is a doubly linked list.
363 struct MessageQueue *next;
366 * This is a doubly linked list.
368 struct MessageQueue *prev;
371 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
372 * stuck together in memory. Allocated at the end of this struct.
374 const char *message_buf;
377 * Size of the message buf
379 size_t message_buf_size;
382 * Client responsible for queueing the message;
383 * used to check that a client has no two messages
384 * pending for the same target. Can be NULL.
386 struct TransportClient *client;
389 * Using which specific address should we send this message?
391 struct ForeignAddressList *specific_address;
394 * Peer ID of the Neighbour this entry belongs to.
396 struct GNUNET_PeerIdentity neighbour_id;
399 * Plugin that we used for the transmission.
400 * NULL until we scheduled a transmission.
402 struct TransportPlugin *plugin;
405 * At what time should we fail?
407 struct GNUNET_TIME_Absolute timeout;
410 * Internal message of the transport system that should not be
411 * included in the usual SEND-SEND_OK transmission confirmation
412 * traffic management scheme. Typically, "internal_msg" will
413 * be set whenever "client" is NULL (but it is not strictly
419 * How important is the message?
421 unsigned int priority;
427 * For a given Neighbour, which plugins are available
428 * to talk to this peer and what are their costs?
433 * This is a linked list.
435 struct ReadyList *next;
438 * Which of our transport plugins does this entry
441 struct TransportPlugin *plugin;
444 * Transport addresses, latency, and readiness for
445 * this particular plugin.
447 struct ForeignAddressList *addresses;
450 * To which neighbour does this ready list belong to?
452 struct NeighbourList *neighbour;
457 * Entry in linked list of all of our current neighbours.
463 * This is a linked list.
465 struct NeighbourList *next;
468 * Which of our transports is connected to this peer
469 * and what is their status?
471 struct ReadyList *plugins;
474 * Head of list of messages we would like to send to this peer;
475 * must contain at most one message per client.
477 struct MessageQueue *messages_head;
480 * Tail of list of messages we would like to send to this peer; must
481 * contain at most one message per client.
483 struct MessageQueue *messages_tail;
486 * Buffer for at most one payload message used when we receive
487 * payload data before our PING-PONG has succeeded. We then
488 * store such messages in this intermediary buffer until the
489 * connection is fully up.
491 struct GNUNET_MessageHeader *pre_connect_message_buffer;
494 * Context for peerinfo iteration.
495 * NULL after we are done processing peerinfo's information.
497 struct GNUNET_PEERINFO_IteratorContext *piter;
500 * Public key for this peer. Valid only if the respective flag is set below.
502 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
505 * Identity of this neighbour.
507 struct GNUNET_PeerIdentity id;
510 * ID of task scheduled to run when this peer is about to
511 * time out (will free resources associated with the peer).
513 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
516 * ID of task scheduled to run when we should retry transmitting
517 * the head of the message queue. Actually triggered when the
518 * transmission is timing out (we trigger instantly when we have
519 * a chance of success).
521 GNUNET_SCHEDULER_TaskIdentifier retry_task;
524 * How long until we should consider this peer dead
525 * (if we don't receive another message in the
528 struct GNUNET_TIME_Absolute peer_timeout;
531 * Tracker for inbound bandwidth.
533 struct GNUNET_BANDWIDTH_Tracker in_tracker;
536 * The latency we have seen for this particular address for
537 * this particular peer. This latency may have been calculated
538 * over multiple transports. This value reflects how long it took
539 * us to receive a response when SENDING via this particular
540 * transport/neighbour/address combination!
542 * FIXME: we need to periodically send PINGs to update this
543 * latency (at least more often than the current "huge" (11h?)
546 struct GNUNET_TIME_Relative latency;
549 * How often has the other peer (recently) violated the
550 * inbound traffic limit? Incremented by 10 per violation,
551 * decremented by 1 per non-violation (for each
554 unsigned int quota_violation_count;
557 * DV distance to this peer (1 if no DV is used).
562 * Have we seen an PONG from this neighbour in the past (and
563 * not had a disconnect since)?
568 * Do we have a valid public key for this neighbour?
570 int public_key_valid;
573 * Performance data for the peer.
575 struct GNUNET_TRANSPORT_ATS_Information *ats;
578 * Identity of the neighbour.
580 struct GNUNET_PeerIdentity peer;
585 * Message used to ask a peer to validate receipt (to check an address
586 * from a HELLO). Followed by the address we are trying to validate,
587 * or an empty address if we are just sending a PING to confirm that a
588 * connection which the receiver (of the PING) initiated is still valid.
590 struct TransportPingMessage
594 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
596 struct GNUNET_MessageHeader header;
599 * Challenge code (to ensure fresh reply).
601 uint32_t challenge GNUNET_PACKED;
604 * Who is the intended recipient?
606 struct GNUNET_PeerIdentity target;
612 * Message used to validate a HELLO. The challenge is included in the
613 * confirmation to make matching of replies to requests possible. The
614 * signature signs our public key, an expiration time and our address.<p>
616 * This message is followed by our transport address that the PING tried
617 * to confirm (if we liked it). The address can be empty (zero bytes)
618 * if the PING had not address either (and we received the request via
619 * a connection that we initiated).
621 struct TransportPongMessage
625 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
627 struct GNUNET_MessageHeader header;
630 * Challenge code from PING (showing freshness). Not part of what
631 * is signed so that we can re-use signatures.
633 uint32_t challenge GNUNET_PACKED;
638 struct GNUNET_CRYPTO_RsaSignature signature;
641 * What are we signing and why? Two possible reason codes can be here:
642 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
643 * plausible address for this peer (pid is set to identity of signer); or
644 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
645 * an address we used to connect to the peer with the given pid.
647 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
650 * When does this signature expire?
652 struct GNUNET_TIME_AbsoluteNBO expiration;
655 * Either the identity of the peer Who signed this message, or the
656 * identity of the peer that we're connected to using the given
657 * address (depending on purpose.type).
659 struct GNUNET_PeerIdentity pid;
662 * Size of address appended to this message (part of what is
663 * being signed, hence not redundant).
671 * Linked list of messages to be transmitted to the client. Each
672 * entry is followed by the actual message.
674 struct ClientMessageQueueEntry
677 * This is a doubly-linked list.
679 struct ClientMessageQueueEntry *next;
682 * This is a doubly-linked list.
684 struct ClientMessageQueueEntry *prev;
689 * Client connected to the transport service.
691 struct TransportClient
695 * This is a linked list.
697 struct TransportClient *next;
700 * Handle to the client.
702 struct GNUNET_SERVER_Client *client;
705 * Linked list of messages yet to be transmitted to
708 struct ClientMessageQueueEntry *message_queue_head;
711 * Tail of linked list of messages yet to be transmitted to the
714 struct ClientMessageQueueEntry *message_queue_tail;
717 * Current transmit request handle.
719 struct GNUNET_CONNECTION_TransmitHandle *th;
722 * Is a call to "transmit_send_continuation" pending? If so, we
723 * must not free this struct (even if the corresponding client
724 * disconnects) and instead only remove it from the linked list and
725 * set the "client" field to NULL.
730 * Length of the list of messages pending for this client.
732 unsigned int message_count;
738 * Context of currently active requests to peerinfo
739 * for validation of HELLOs.
741 struct CheckHelloValidatedContext;
745 * Entry in map of all HELLOs awaiting validation.
747 struct ValidationEntry
751 * NULL if this entry is not part of a larger HELLO validation.
753 struct CheckHelloValidatedContext *chvc;
756 * The address, actually a pointer to the end
757 * of this struct. Do not free!
762 * Name of the transport.
764 char *transport_name;
767 * The public key of the peer.
769 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
772 * ID of task that will clean up this entry if we don't succeed
773 * with the validation first.
775 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
778 * At what time did we send this validation?
780 struct GNUNET_TIME_Absolute send_time;
783 * Session being validated (or NULL for none).
785 struct Session *session;
788 * Challenge number we used.
801 * Context of currently active requests to peerinfo
802 * for validation of HELLOs.
804 struct CheckHelloValidatedContext
808 * This is a doubly-linked list.
810 struct CheckHelloValidatedContext *next;
813 * This is a doubly-linked list.
815 struct CheckHelloValidatedContext *prev;
818 * Hello that we are validating.
820 const struct GNUNET_HELLO_Message *hello;
823 * Context for peerinfo iteration.
824 * NULL after we are done processing peerinfo's information.
826 struct GNUNET_PEERINFO_IteratorContext *piter;
829 * Was a HELLO known for this peer to peerinfo?
834 * Number of validation entries currently referring to this
837 unsigned int ve_count;
840 struct ATS_quality_metric
849 struct ATS_mechanism * prev;
850 struct ATS_mechanism * next;
851 struct ForeignAddressList * addr;
852 struct TransportPlugin * plugin;
853 struct ATS_peer * peer;
856 struct ATS_ressource_cost * rc;
862 struct GNUNET_PeerIdentity peer;
863 struct NeighbourList * n;
864 struct ATS_mechanism * m_head;
865 struct ATS_mechanism * m_tail;
867 /* preference value f */
879 struct ATS_ressource_entry
881 /* index in ressources array */
883 /* depending ATSi parameter to calculcate limits */
892 /* index in ressources array */
894 /* depending ATSi parameter to calculcate limits */
896 /* cfg option to load limits */
903 /* cofficients for the specific plugins */
913 static struct ATS_ressource ressources[] =
915 /* FIXME: the coefficients for the specific plugins */
916 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
917 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
918 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
920 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
921 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
922 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
923 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
926 static int available_ressources = 3;
934 * Time of last execution
936 struct GNUNET_TIME_Absolute last;
938 * Minimum intervall between two executions
940 struct GNUNET_TIME_Relative min_delta;
942 * Regular intervall when execution is triggered
944 struct GNUNET_TIME_Relative exec_intervall;
946 * Maximum execution time per calculation
948 struct GNUNET_TIME_Relative max_exec_duration;
950 * Maximum number of LP iterations per calculation
954 GNUNET_SCHEDULER_TaskIdentifier ats_task;
956 struct ATS_plugin * head;
957 struct ATS_plugin * tail;
964 static struct GNUNET_HELLO_Message *our_hello;
969 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
974 static struct GNUNET_PeerIdentity my_identity;
979 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
984 const struct GNUNET_CONFIGURATION_Handle *cfg;
987 * Linked list of all clients to this service.
989 static struct TransportClient *clients;
992 * All loaded plugins.
994 static struct TransportPlugin *plugins;
997 * Handle to peerinfo service.
999 static struct GNUNET_PEERINFO_Handle *peerinfo;
1002 * All known neighbours and their HELLOs.
1004 static struct NeighbourList *neighbours;
1007 * Number of neighbours we'd like to have.
1009 static uint32_t max_connect_per_transport;
1012 * Head of linked list.
1014 static struct CheckHelloValidatedContext *chvc_head;
1017 * Tail of linked list.
1019 static struct CheckHelloValidatedContext *chvc_tail;
1022 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1023 * of the given peer that we are currently validating).
1025 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1028 * Handle for reporting statistics.
1030 static struct GNUNET_STATISTICS_Handle *stats;
1033 * Handle for ats information
1035 static struct ATS_info *ats;
1038 static struct ATS_quality_metric qm[] =
1040 {1, 1028, "QUALITY_NET_DISTANCE"},
1041 {2, 1034, "QUALITY_NET_DELAY"},
1043 static int available_quality_metrics = 2;
1047 * The peer specified by the given neighbour has timed-out or a plugin
1048 * has disconnected. We may either need to do nothing (other plugins
1049 * still up), or trigger a full disconnect and clean up. This
1050 * function updates our state and do the necessary notifications.
1051 * Also notifies our clients that the neighbour is now officially
1054 * @param n the neighbour list entry for the peer
1055 * @param check should we just check if all plugins
1056 * disconnected or must we ask all plugins to
1059 static void disconnect_neighbour (struct NeighbourList *n, int check);
1062 * Check the ready list for the given neighbour and if a plugin is
1063 * ready for transmission (and if we have a message), do so!
1065 * @param nexi target peer for which to transmit
1067 static void try_transmission_to_peer (struct NeighbourList *n);
1072 void ats_shutdown ( );
1074 void ats_notify_peer_connect (
1075 const struct GNUNET_PeerIdentity *peer,
1076 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1078 void ats_notify_peer_disconnect (
1079 const struct GNUNET_PeerIdentity *peer);
1081 void ats_notify_ats_data (
1082 const struct GNUNET_PeerIdentity *peer,
1083 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1085 struct ForeignAddressList * ats_get_preferred_address (
1086 struct NeighbourList *n);
1089 * Find an entry in the neighbour list for a particular peer.
1091 * @return NULL if not found.
1093 static struct NeighbourList *
1094 find_neighbour (const struct GNUNET_PeerIdentity *key)
1096 struct NeighbourList *head = neighbours;
1098 while ((head != NULL) &&
1099 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1106 * Find an entry in the transport list for a particular transport.
1108 * @return NULL if not found.
1110 static struct TransportPlugin *
1111 find_transport (const char *short_name)
1113 struct TransportPlugin *head = plugins;
1114 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1120 * Is a particular peer blacklisted for a particular transport?
1122 * @param peer the peer to check for
1123 * @param plugin the plugin used to connect to the peer
1125 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1128 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1131 if (plugin->blacklist != NULL)
1133 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137 "Peer `%s:%s' is blacklisted!\n",
1138 plugin->short_name, GNUNET_i2s (peer));
1141 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1151 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1153 struct TransportPlugin *plugin;
1155 plugin = find_transport(transport_name);
1156 if (plugin == NULL) /* Nothing to do */
1158 if (plugin->blacklist == NULL)
1159 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1160 GNUNET_assert(plugin->blacklist != NULL);
1161 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1163 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1168 * Read the blacklist file, containing transport:peer entries.
1169 * Provided the transport is loaded, set up hashmap with these
1170 * entries to blacklist peers by transport.
1174 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1181 struct GNUNET_PeerIdentity pid;
1183 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1184 unsigned int entries_found;
1185 char *transport_name;
1188 GNUNET_CONFIGURATION_get_value_filename (cfg,
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1195 "Option `%s' in section `%s' not specified!\n",
1201 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1202 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1203 | GNUNET_DISK_PERM_USER_WRITE);
1204 if (0 != STAT (fn, &frstat))
1206 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1207 _("Could not read blacklist file `%s'\n"), fn);
1211 if (frstat.st_size == 0)
1214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215 _("Blacklist file `%s' is empty.\n"),
1221 /* FIXME: use mmap */
1222 data = GNUNET_malloc_large (frstat.st_size);
1223 GNUNET_assert(data != NULL);
1224 if (frstat.st_size !=
1225 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1227 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1228 _("Failed to read blacklist from `%s'\n"), fn);
1235 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1237 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1238 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1241 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1244 if (colon_pos >= frstat.st_size)
1246 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1247 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1248 (unsigned long long) colon_pos);
1254 if (isspace( (unsigned char) data[colon_pos]))
1256 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1257 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1258 (unsigned long long) colon_pos);
1260 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1264 tsize = colon_pos - pos;
1265 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1267 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1268 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1269 (unsigned long long) colon_pos);
1278 transport_name = GNUNET_malloc(tsize + 1);
1279 memcpy(transport_name, &data[pos], tsize);
1280 pos = colon_pos + 1;
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283 "Read transport name %s in blacklist file.\n",
1286 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1287 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1289 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1290 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1291 (unsigned long long) pos);
1293 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1295 GNUNET_free_non_null(transport_name);
1298 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1299 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1301 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1302 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1303 (unsigned long long) pos,
1308 if (0 != memcmp (&pid,
1310 sizeof (struct GNUNET_PeerIdentity)))
1313 add_peer_to_blacklist (&pid,
1318 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1319 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1323 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1324 GNUNET_free_non_null(transport_name);
1325 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1328 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1335 * Function called to notify a client about the socket being ready to
1336 * queue more data. "buf" will be NULL and "size" zero if the socket
1337 * was closed for writing in the meantime.
1339 * @param cls closure
1340 * @param size number of bytes available in buf
1341 * @param buf where the callee should write the message
1342 * @return number of bytes written to buf
1345 transmit_to_client_callback (void *cls, size_t size, void *buf)
1347 struct TransportClient *client = cls;
1348 struct ClientMessageQueueEntry *q;
1351 const struct GNUNET_MessageHeader *msg;
1358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359 "Transmission to client failed, closing connection.\n");
1361 /* fatal error with client, free message queue! */
1362 while (NULL != (q = client->message_queue_head))
1364 GNUNET_STATISTICS_update (stats,
1365 gettext_noop ("# bytes discarded (could not transmit to client)"),
1366 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1368 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1369 client->message_queue_tail,
1373 client->message_count = 0;
1378 while (NULL != (q = client->message_queue_head))
1380 msg = (const struct GNUNET_MessageHeader *) &q[1];
1381 msize = ntohs (msg->size);
1382 if (msize + tsize > size)
1385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1386 "Transmitting message of type %u to client.\n",
1389 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1390 client->message_queue_tail,
1392 memcpy (&cbuf[tsize], msg, msize);
1395 client->message_count--;
1399 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1400 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1402 GNUNET_TIME_UNIT_FOREVER_REL,
1403 &transmit_to_client_callback,
1405 GNUNET_assert (client->th != NULL);
1412 * Convert an address to a string.
1414 * @param plugin name of the plugin responsible for the address
1415 * @param addr binary address
1416 * @param addr_len number of bytes in addr
1417 * @return NULL on error, otherwise address string
1420 a2s (const char *plugin,
1424 struct TransportPlugin *p;
1428 p = find_transport (plugin);
1431 return p->api->address_to_string (p->api->cls,
1438 * Mark the given FAL entry as 'connected' (and hence preferred for
1439 * sending); also mark all others for the same peer as 'not connected'
1440 * (since only one can be preferred).
1442 * @param fal address to set to 'connected'
1445 mark_address_connected (struct ForeignAddressList *fal)
1447 struct ForeignAddressList *pos;
1450 GNUNET_assert (GNUNET_YES == fal->validated);
1451 if (fal->connected == GNUNET_YES)
1452 return; /* nothing to do */
1454 pos = fal->ready_list->addresses;
1457 if (GNUNET_YES == pos->connected)
1460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1461 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1462 a2s (pos->ready_list->plugin->short_name,
1466 GNUNET_break (cnt == GNUNET_YES);
1468 pos->connected = GNUNET_NO;
1469 GNUNET_STATISTICS_update (stats,
1470 gettext_noop ("# connected addresses"),
1476 fal->connected = GNUNET_YES;
1477 if (GNUNET_YES == cnt)
1479 GNUNET_STATISTICS_update (stats,
1480 gettext_noop ("# connected addresses"),
1488 * Send the specified message to the specified client. Since multiple
1489 * messages may be pending for the same client at a time, this code
1490 * makes sure that no message is lost.
1492 * @param client client to transmit the message to
1493 * @param msg the message to send
1494 * @param may_drop can this message be dropped if the
1495 * message queue for this client is getting far too large?
1498 transmit_to_client (struct TransportClient *client,
1499 const struct GNUNET_MessageHeader *msg, int may_drop)
1501 struct ClientMessageQueueEntry *q;
1504 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1506 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1508 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1511 client->message_count,
1513 GNUNET_STATISTICS_update (stats,
1514 gettext_noop ("# messages dropped due to slow client"),
1519 msize = ntohs (msg->size);
1520 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1521 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1522 memcpy (&q[1], msg, msize);
1523 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1524 client->message_queue_tail,
1525 client->message_queue_tail,
1527 client->message_count++;
1528 if (client->th == NULL)
1530 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1532 GNUNET_TIME_UNIT_FOREVER_REL,
1533 &transmit_to_client_callback,
1535 GNUNET_assert (client->th != NULL);
1541 * Transmit a 'SEND_OK' notification to the given client for the
1544 * @param client who to notify
1545 * @param n neighbour to notify about, can be NULL (on failure)
1546 * @param target target of the transmission
1547 * @param result status code for the transmission request
1550 transmit_send_ok (struct TransportClient *client,
1551 struct NeighbourList *n,
1552 const struct GNUNET_PeerIdentity *target,
1555 struct SendOkMessage send_ok_msg;
1557 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1558 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1559 send_ok_msg.success = htonl (result);
1561 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1563 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1564 send_ok_msg.peer = *target;
1565 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1570 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1571 * upon "completion" of a send request. This tells the API
1572 * that it is now legal to send another message to the given
1575 * @param cls closure, identifies the entry on the
1576 * message queue that was transmitted and the
1577 * client responsible for queuing the message
1578 * @param target the peer receiving the message
1579 * @param result GNUNET_OK on success, if the transmission
1580 * failed, we should not tell the client to transmit
1584 transmit_send_continuation (void *cls,
1585 const struct GNUNET_PeerIdentity *target,
1588 struct MessageQueue *mq = cls;
1589 struct NeighbourList *n;
1591 GNUNET_STATISTICS_update (stats,
1592 gettext_noop ("# bytes pending with plugins"),
1593 - (int64_t) mq->message_buf_size,
1595 if (result == GNUNET_OK)
1597 GNUNET_STATISTICS_update (stats,
1598 gettext_noop ("# bytes successfully transmitted by plugins"),
1599 mq->message_buf_size,
1604 GNUNET_STATISTICS_update (stats,
1605 gettext_noop ("# bytes with transmission failure by plugins"),
1606 mq->message_buf_size,
1609 if (mq->specific_address != NULL)
1611 if (result == GNUNET_OK)
1613 mq->specific_address->timeout =
1614 GNUNET_TIME_relative_to_absolute
1615 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1616 if (mq->specific_address->validated == GNUNET_YES)
1617 mark_address_connected (mq->specific_address);
1621 if (mq->specific_address->connected != GNUNET_NO)
1624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1625 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1626 a2s (mq->specific_address->ready_list->plugin->short_name,
1627 mq->specific_address->addr,
1628 mq->specific_address->addrlen));
1630 GNUNET_STATISTICS_update (stats,
1631 gettext_noop ("# connected addresses"),
1634 mq->specific_address->connected = GNUNET_NO;
1637 if (! mq->internal_msg)
1638 mq->specific_address->in_transmit = GNUNET_NO;
1640 n = find_neighbour(&mq->neighbour_id);
1641 if (mq->client != NULL)
1642 transmit_send_ok (mq->client, n, target, result);
1645 try_transmission_to_peer (n);
1650 * Find an address in any of the available transports for
1651 * the given neighbour that would be good for message
1652 * transmission. This is essentially the transport selection
1655 * @param neighbour for whom to select an address
1656 * @return selected address, NULL if we have none
1658 struct ForeignAddressList *
1659 find_ready_address(struct NeighbourList *neighbour)
1661 struct ReadyList *head = neighbour->plugins;
1662 struct ForeignAddressList *addresses;
1663 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1664 struct ForeignAddressList *best_address;
1666 /* Hack to prefer unix domain sockets */
1667 struct ForeignAddressList *unix_address = NULL;
1669 best_address = NULL;
1670 while (head != NULL)
1672 addresses = head->addresses;
1673 while (addresses != NULL)
1675 if ( (addresses->timeout.abs_value < now.abs_value) &&
1676 (addresses->connected == GNUNET_YES) )
1679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1680 "Marking long-time inactive connection to `%4s' as down.\n",
1681 GNUNET_i2s (&neighbour->id));
1683 GNUNET_STATISTICS_update (stats,
1684 gettext_noop ("# connected addresses"),
1687 addresses->connected = GNUNET_NO;
1689 addresses = addresses->next;
1692 addresses = head->addresses;
1693 while (addresses != NULL)
1695 #if DEBUG_TRANSPORT > 1
1696 if (addresses->addr != NULL)
1697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1698 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1699 a2s (head->plugin->short_name,
1701 addresses->addrlen),
1702 GNUNET_i2s (&neighbour->id),
1703 addresses->connected,
1704 addresses->in_transmit,
1705 addresses->validated,
1706 addresses->connect_attempts,
1707 (unsigned long long) addresses->timeout.abs_value,
1708 (unsigned int) addresses->distance);
1710 if (0==strcmp(head->plugin->short_name,"unix"))
1712 if ((unix_address == NULL) || ((unix_address != NULL) &&
1713 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1714 unix_address = addresses;
1716 if ( ( (best_address == NULL) ||
1717 (addresses->connected == GNUNET_YES) ||
1718 (best_address->connected == GNUNET_NO) ) &&
1719 (addresses->in_transmit == GNUNET_NO) &&
1720 ( (best_address == NULL) ||
1721 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1722 best_address = addresses;
1723 /* FIXME: also give lower-latency addresses that are not
1724 connected a chance some times... */
1725 addresses = addresses->next;
1727 if (unix_address != NULL)
1731 if (unix_address != NULL)
1733 best_address = unix_address;
1735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1738 if (best_address != NULL)
1742 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1743 "Best address found (`%s') has latency of %llu ms.\n",
1744 (best_address->addrlen > 0)
1745 ? a2s (best_address->ready_list->plugin->short_name,
1747 best_address->addrlen)
1749 best_address->latency.rel_value);
1754 GNUNET_STATISTICS_update (stats,
1755 gettext_noop ("# transmission attempts failed (no address)"),
1760 return best_address;
1766 * We should re-try transmitting to the given peer,
1767 * hopefully we've learned something in the meantime.
1770 retry_transmission_task (void *cls,
1771 const struct GNUNET_SCHEDULER_TaskContext *tc)
1773 struct NeighbourList *n = cls;
1775 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1776 try_transmission_to_peer (n);
1781 * Check the ready list for the given neighbour and if a plugin is
1782 * ready for transmission (and if we have a message), do so!
1784 * @param neighbour target peer for which to transmit
1787 try_transmission_to_peer (struct NeighbourList *n)
1789 struct ReadyList *rl;
1790 struct MessageQueue *mq;
1791 struct GNUNET_TIME_Relative timeout;
1795 if (n->messages_head == NULL)
1798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1799 "Transmission queue for `%4s' is empty\n",
1800 GNUNET_i2s (&neighbour->id));
1802 return; /* nothing to do */
1805 mq = n->messages_head;
1806 force_address = GNUNET_YES;
1807 if (mq->specific_address == NULL)
1810 mq->specific_address = ats_get_preferred_address(n);
1811 GNUNET_STATISTICS_update (stats,
1812 gettext_noop ("# transport selected peer address freely"),
1815 force_address = GNUNET_NO;
1817 if (mq->specific_address == NULL)
1819 GNUNET_STATISTICS_update (stats,
1820 gettext_noop ("# transport failed to selected peer address"),
1823 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1824 if (timeout.rel_value == 0)
1827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1828 "No destination address available to transmit message of size %u to peer `%4s'\n",
1829 mq->message_buf_size,
1830 GNUNET_i2s (&mq->neighbour_id));
1832 GNUNET_STATISTICS_update (stats,
1833 gettext_noop ("# bytes in message queue for other peers"),
1834 - (int64_t) mq->message_buf_size,
1836 GNUNET_STATISTICS_update (stats,
1837 gettext_noop ("# bytes discarded (no destination address available)"),
1838 mq->message_buf_size,
1840 if (mq->client != NULL)
1841 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1842 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1846 return; /* nobody ready */
1848 GNUNET_STATISTICS_update (stats,
1849 gettext_noop ("# message delivery deferred (no address)"),
1852 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1853 GNUNET_SCHEDULER_cancel (n->retry_task);
1854 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1855 &retry_transmission_task,
1858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1859 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1860 mq->message_buf_size,
1861 GNUNET_i2s (&mq->neighbour_id),
1864 /* FIXME: might want to trigger peerinfo lookup here
1865 (unless that's already pending...) */
1868 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1871 if (mq->specific_address->connected == GNUNET_NO)
1872 mq->specific_address->connect_attempts++;
1873 rl = mq->specific_address->ready_list;
1874 mq->plugin = rl->plugin;
1875 if (!mq->internal_msg)
1876 mq->specific_address->in_transmit = GNUNET_YES;
1878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1879 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1880 mq->message_buf_size,
1881 GNUNET_i2s (&neighbour->id),
1882 (mq->specific_address->addr != NULL)
1883 ? a2s (mq->plugin->short_name,
1884 mq->specific_address->addr,
1885 mq->specific_address->addrlen)
1887 rl->plugin->short_name);
1889 GNUNET_STATISTICS_update (stats,
1890 gettext_noop ("# bytes in message queue for other peers"),
1891 - (int64_t) mq->message_buf_size,
1893 GNUNET_STATISTICS_update (stats,
1894 gettext_noop ("# bytes pending with plugins"),
1895 mq->message_buf_size,
1897 ret = rl->plugin->api->send (rl->plugin->api->cls,
1900 mq->message_buf_size,
1902 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1903 mq->specific_address->session,
1904 mq->specific_address->addr,
1905 mq->specific_address->addrlen,
1907 &transmit_send_continuation, mq);
1910 /* failure, but 'send' would not call continuation in this case,
1911 so we need to do it here! */
1912 transmit_send_continuation (mq,
1920 * Send the specified message to the specified peer.
1922 * @param client source of the transmission request (can be NULL)
1923 * @param peer_address ForeignAddressList where we should send this message
1924 * @param priority how important is the message
1925 * @param timeout how long do we have to transmit?
1926 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1927 * @param message_buf_size total size of all messages in message_buf
1928 * @param is_internal is this an internal message; these are pre-pended and
1929 * also do not count for plugins being "ready" to transmit
1930 * @param neighbour handle to the neighbour for transmission
1933 transmit_to_peer (struct TransportClient *client,
1934 struct ForeignAddressList *peer_address,
1935 unsigned int priority,
1936 struct GNUNET_TIME_Relative timeout,
1937 const char *message_buf,
1938 size_t message_buf_size,
1939 int is_internal, struct NeighbourList *neighbour)
1941 struct MessageQueue *mq;
1946 /* check for duplicate submission */
1947 mq = neighbour->messages_head;
1950 if (mq->client == client)
1952 /* client transmitted to same peer twice
1953 before getting SEND_OK! */
1961 GNUNET_STATISTICS_update (stats,
1962 gettext_noop ("# bytes in message queue for other peers"),
1965 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1966 mq->specific_address = peer_address;
1967 mq->client = client;
1968 /* FIXME: this memcpy can be up to 7% of our total runtime! */
1969 memcpy (&mq[1], message_buf, message_buf_size);
1970 mq->message_buf = (const char*) &mq[1];
1971 mq->message_buf_size = message_buf_size;
1972 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1973 mq->internal_msg = is_internal;
1974 mq->priority = priority;
1975 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1977 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1978 neighbour->messages_tail,
1981 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1982 neighbour->messages_tail,
1983 neighbour->messages_tail,
1985 try_transmission_to_peer (neighbour);
1992 struct GeneratorContext
1994 struct TransportPlugin *plug_pos;
1995 struct OwnAddressList *addr_pos;
1996 struct GNUNET_TIME_Absolute expiration;
2004 address_generator (void *cls, size_t max, void *buf)
2006 struct GeneratorContext *gc = cls;
2009 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2011 gc->plug_pos = gc->plug_pos->next;
2012 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2014 if (NULL == gc->plug_pos)
2019 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2022 gc->addr_pos->addrlen, buf, max);
2023 gc->addr_pos = gc->addr_pos->next;
2029 * Construct our HELLO message from all of the addresses of
2030 * all of the transports.
2035 struct GNUNET_HELLO_Message *hello;
2036 struct TransportClient *cpos;
2037 struct NeighbourList *npos;
2038 struct GeneratorContext gc;
2040 gc.plug_pos = plugins;
2041 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2042 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2043 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2046 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2048 GNUNET_STATISTICS_update (stats,
2049 gettext_noop ("# refreshed my HELLO"),
2053 while (cpos != NULL)
2055 transmit_to_client (cpos,
2056 (const struct GNUNET_MessageHeader *) hello,
2061 GNUNET_free_non_null (our_hello);
2063 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2065 while (npos != NULL)
2068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2069 "Transmitting updated `%s' to neighbour `%4s'\n",
2070 "HELLO", GNUNET_i2s (&npos->id));
2072 GNUNET_STATISTICS_update (stats,
2073 gettext_noop ("# transmitted my HELLO to other peers"),
2076 transmit_to_peer (NULL, NULL, 0,
2077 HELLO_ADDRESS_EXPIRATION,
2078 (const char *) our_hello,
2079 GNUNET_HELLO_size(our_hello),
2087 * Task used to clean up expired addresses for a plugin.
2089 * @param cls closure
2093 expire_address_task (void *cls,
2094 const struct GNUNET_SCHEDULER_TaskContext *tc);
2098 * Update the list of addresses for this plugin,
2099 * expiring those that are past their expiration date.
2101 * @param plugin addresses of which plugin should be recomputed?
2102 * @param fresh set to GNUNET_YES if a new address was added
2103 * and we need to regenerate the HELLO even if nobody
2107 update_addresses (struct TransportPlugin *plugin,
2110 static struct GNUNET_TIME_Absolute last_update;
2111 struct GNUNET_TIME_Relative min_remaining;
2112 struct GNUNET_TIME_Relative remaining;
2113 struct GNUNET_TIME_Absolute now;
2114 struct OwnAddressList *pos;
2115 struct OwnAddressList *prev;
2116 struct OwnAddressList *next;
2119 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2120 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2121 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2122 now = GNUNET_TIME_absolute_get ();
2123 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2124 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2126 pos = plugin->addresses;
2130 if (pos->expires.abs_value < now.abs_value)
2132 expired = GNUNET_YES;
2134 plugin->addresses = pos->next;
2136 prev->next = pos->next;
2141 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2142 if (remaining.rel_value < min_remaining.rel_value)
2143 min_remaining = remaining;
2149 if (expired || fresh)
2154 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2155 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2157 plugin->address_update_task
2158 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2159 &expire_address_task, plugin);
2164 * Task used to clean up expired addresses for a plugin.
2166 * @param cls closure
2170 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2172 struct TransportPlugin *plugin = cls;
2174 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2175 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2176 update_addresses (plugin, GNUNET_NO);
2181 * Iterator over hash map entries that NULLs the session of validation
2182 * entries that match the given session.
2184 * @param cls closure (the 'struct Session*' to match against)
2185 * @param key current key code (peer ID, not used)
2186 * @param value value in the hash map ('struct ValidationEntry*')
2187 * @return GNUNET_YES (we should continue to iterate)
2190 remove_session_validations (void *cls,
2191 const GNUNET_HashCode * key,
2194 struct Session *session = cls;
2195 struct ValidationEntry *ve = value;
2197 if (session == ve->session)
2204 * We've been disconnected from the other peer (for some
2205 * connection-oriented transport). Either quickly
2206 * re-establish the connection or signal the disconnect
2209 * Only signal CORE level disconnect if ALL addresses
2210 * for the peer are exhausted.
2212 * @param p overall plugin context
2213 * @param nl neighbour that was disconnected
2216 try_fast_reconnect (struct TransportPlugin *p,
2217 struct NeighbourList *nl)
2219 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2220 /* Note: the idea here is to hide problems with transports (or
2221 switching between plugins) from the core to eliminate the need to
2222 re-negotiate session keys and the like; OTOH, we should tell core
2223 quickly (much faster than timeout) `if a connection was lost and
2224 could not be re-established (i.e. other peer went down or is
2225 unable / refuses to communicate);
2227 So we should consider:
2228 1) ideally: our own willingness / need to connect
2229 2) prior failures to connect to this peer (by plugin)
2230 3) ideally: reasons why other peer terminated (as far as knowable)
2232 Most importantly, it must be POSSIBLE for another peer to terminate
2233 a connection for a while (without us instantly re-establishing it).
2234 Similarly, if another peer is gone we should quickly notify CORE.
2235 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2236 on the other end), we should reconnect in such a way that BOTH CORE
2237 services never even notice.
2238 Furthermore, the same mechanism (or small variation) could be used
2239 to switch to a better-performing plugin (ATS).
2241 Finally, this needs to be tested throughly... */
2244 * GNUNET_NO in the call below makes transport disconnect the peer,
2245 * even if only a single address (out of say, six) went away. This
2246 * function must be careful to ONLY disconnect if the peer is gone,
2247 * not just a specifi address.
2249 * More specifically, half the places it was used had it WRONG.
2252 /* No reconnect, signal disconnect instead! */
2253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2254 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2255 "try_fast_reconnect");
2256 disconnect_neighbour (nl, GNUNET_YES);
2261 * Function that will be called whenever the plugin internally
2262 * cleans up a session pointer and hence the service needs to
2263 * discard all of those sessions as well. Plugins that do not
2264 * use sessions can simply omit calling this function and always
2265 * use NULL wherever a session pointer is needed.
2267 * @param cls closure
2268 * @param peer which peer was the session for
2269 * @param session which session is being destoyed
2272 plugin_env_session_end (void *cls,
2273 const struct GNUNET_PeerIdentity *peer,
2274 struct Session *session)
2276 struct TransportPlugin *p = cls;
2277 struct NeighbourList *nl;
2278 struct ReadyList *rl;
2279 struct ForeignAddressList *pos;
2280 struct ForeignAddressList *prev;
2282 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2283 &remove_session_validations,
2285 nl = find_neighbour (peer);
2287 return; /* was never marked as connected */
2291 if (rl->plugin == p)
2296 return; /* was never marked as connected */
2298 pos = rl->addresses;
2299 while ( (pos != NULL) &&
2300 (pos->session != session) )
2306 return; /* was never marked as connected */
2307 pos->session = NULL;
2308 if (pos->addrlen != 0)
2310 if (nl->received_pong != GNUNET_NO)
2311 try_fast_reconnect (p, nl);
2314 /* was inbound connection, free 'pos' */
2316 rl->addresses = pos->next;
2318 prev->next = pos->next;
2319 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2321 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2322 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2325 if (nl->received_pong == GNUNET_NO)
2326 return; /* nothing to do, never connected... */
2327 /* check if we have any validated addresses left */
2328 pos = rl->addresses;
2333 try_fast_reconnect (p, nl);
2338 /* no valid addresses left, signal disconnect! */
2340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2341 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2342 "plugin_env_session_end");
2343 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2344 * it means there aren't any left for this PLUGIN/PEER combination! So
2345 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2346 * when it isn't necessary. Using GNUNET_YES at least checks to see
2347 * if there are any addresses that work first, so as not to overdo it.
2350 disconnect_neighbour (nl, GNUNET_YES);
2355 * Function that must be called by each plugin to notify the
2356 * transport service about the addresses under which the transport
2357 * provided by the plugin can be reached.
2359 * @param cls closure
2360 * @param name name of the transport that generated the address
2361 * @param addr one of the addresses of the host, NULL for the last address
2362 * the specific address format depends on the transport
2363 * @param addrlen length of the address
2364 * @param expires when should this address automatically expire?
2367 plugin_env_notify_address (void *cls,
2371 struct GNUNET_TIME_Relative expires)
2373 struct TransportPlugin *p = cls;
2374 struct OwnAddressList *al;
2375 struct GNUNET_TIME_Absolute abex;
2377 GNUNET_assert (addr != NULL);
2378 abex = GNUNET_TIME_relative_to_absolute (expires);
2379 GNUNET_assert (p == find_transport (name));
2383 if ( (addrlen == al->addrlen) &&
2384 (0 == memcmp (addr, &al[1], addrlen)) )
2387 update_addresses (p, GNUNET_NO);
2392 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2393 al->next = p->addresses;
2396 al->addrlen = addrlen;
2397 memcpy (&al[1], addr, addrlen);
2398 update_addresses (p, GNUNET_YES);
2403 * Notify all of our clients about a peer connecting.
2406 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2407 struct GNUNET_TIME_Relative latency,
2410 struct ConnectInfoMessage * cim;
2411 struct TransportClient *cpos;
2416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2417 "Notifying clients about connection from `%s'\n",
2420 GNUNET_STATISTICS_update (stats,
2421 gettext_noop ("# peers connected"),
2426 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2427 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2431 cim = GNUNET_malloc (size);
2433 cim->header.size = htons (size);
2434 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2435 cim->ats_count = htonl(2);
2436 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2437 (&(cim->ats))[0].value = htonl (distance);
2438 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2439 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2440 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2441 (&(cim->ats))[2].value = htonl (0);
2442 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2444 /* notify ats about connecting peer */
2445 ats_notify_peer_connect (peer, &(cim->ats));
2448 while (cpos != NULL)
2450 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2459 * Notify all of our clients about a peer disconnecting.
2462 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2464 struct DisconnectInfoMessage dim;
2465 struct TransportClient *cpos;
2468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2469 "Notifying clients about lost connection to `%s'\n",
2472 GNUNET_STATISTICS_update (stats,
2473 gettext_noop ("# peers connected"),
2476 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2477 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2478 dim.reserved = htonl (0);
2479 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2481 /* notify ats about connecting peer */
2482 ats_notify_peer_disconnect (peer);
2485 while (cpos != NULL)
2487 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2494 * Find a ForeignAddressList entry for the given neighbour
2495 * that matches the given address and transport.
2497 * @param neighbour which peer we care about
2498 * @param tname name of the transport plugin
2499 * @param session session to look for, NULL for 'any'; otherwise
2500 * can be used for the service to "learn" this session ID
2502 * @param addr binary address
2503 * @param addrlen length of addr
2504 * @return NULL if no such entry exists
2506 static struct ForeignAddressList *
2507 find_peer_address(struct NeighbourList *neighbour,
2509 struct Session *session,
2513 struct ReadyList *head;
2514 struct ForeignAddressList *pos;
2516 head = neighbour->plugins;
2517 while (head != NULL)
2519 if (0 == strcmp (tname, head->plugin->short_name))
2525 pos = head->addresses;
2526 while ( (pos != NULL) &&
2527 ( (pos->addrlen != addrlen) ||
2528 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2530 if ( (session != NULL) &&
2531 (pos->session == session) )
2535 if ( (session != NULL) && (pos != NULL) )
2536 pos->session = session; /* learn it! */
2542 * Get the peer address struct for the given neighbour and
2543 * address. If it doesn't yet exist, create it.
2545 * @param neighbour which peer we care about
2546 * @param tname name of the transport plugin
2547 * @param session session of the plugin, or NULL for none
2548 * @param addr binary address
2549 * @param addrlen length of addr
2550 * @return NULL if we do not have a transport plugin for 'tname'
2552 static struct ForeignAddressList *
2553 add_peer_address (struct NeighbourList *neighbour,
2555 struct Session *session,
2559 struct ReadyList *head;
2560 struct ForeignAddressList *ret;
2563 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2566 head = neighbour->plugins;
2568 while (head != NULL)
2570 if (0 == strcmp (tname, head->plugin->short_name))
2576 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2577 ret->session = session;
2580 ret->addr = (const char*) &ret[1];
2581 memcpy (&ret[1], addr, addrlen);
2588 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2590 for (c=0; c<available_ressources; c++)
2592 struct ATS_ressource_entry *r = ret->ressources;
2594 r[c].atis_index = ressources[c].atis_index;
2595 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2597 r[c].c = ressources[c].c_unix;
2600 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2602 r[c].c = ressources[c].c_udp;
2605 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2607 r[c].c = ressources[c].c_tcp;
2610 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2612 r[c].c = ressources[c].c_http;
2615 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2617 r[c].c = ressources[c].c_https;
2620 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2622 r[c].c = ressources[c].c_wlan;
2628 r[c].c = ressources[c].c_default;
2629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2630 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2634 ret->addrlen = addrlen;
2635 ret->expires = GNUNET_TIME_relative_to_absolute
2636 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2637 ret->latency = GNUNET_TIME_relative_get_forever();
2639 ret->timeout = GNUNET_TIME_relative_to_absolute
2640 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2641 ret->ready_list = head;
2642 ret->next = head->addresses;
2643 head->addresses = ret;
2649 * Closure for 'add_validated_address'.
2651 struct AddValidatedAddressContext
2654 * Entry that has been validated.
2656 const struct ValidationEntry *ve;
2659 * Flag set after we have added the address so
2660 * that we terminate the iteration next time.
2667 * Callback function used to fill a buffer of max bytes with a list of
2668 * addresses in the format used by HELLOs. Should use
2669 * "GNUNET_HELLO_add_address" as a helper function.
2671 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2672 * @param max maximum number of bytes that can be written to buf
2673 * @param buf where to write the address information
2674 * @return number of bytes written, 0 to signal the
2675 * end of the iteration.
2678 add_validated_address (void *cls,
2679 size_t max, void *buf)
2681 struct AddValidatedAddressContext *avac = cls;
2682 const struct ValidationEntry *ve = avac->ve;
2684 if (GNUNET_YES == avac->done)
2686 avac->done = GNUNET_YES;
2687 return GNUNET_HELLO_add_address (ve->transport_name,
2688 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2698 * Closure for 'check_address_exists'.
2700 struct CheckAddressExistsClosure
2703 * Address to check for.
2708 * Name of the transport.
2715 struct Session *session;
2718 * Set to GNUNET_YES if the address exists.
2731 * Iterator over hash map entries. Checks if the given
2732 * validation entry is for the same address as what is given
2735 * @param cls the 'struct CheckAddressExistsClosure*'
2736 * @param key current key code (ignored)
2737 * @param value value in the hash map ('struct ValidationEntry')
2738 * @return GNUNET_YES if we should continue to
2739 * iterate (mismatch), GNUNET_NO if not (entry matched)
2742 check_address_exists (void *cls,
2743 const GNUNET_HashCode * key,
2746 struct CheckAddressExistsClosure *caec = cls;
2747 struct ValidationEntry *ve = value;
2749 if ( (0 == strcmp (caec->tname,
2750 ve->transport_name)) &&
2751 (caec->addrlen == ve->addrlen) &&
2752 (0 == memcmp (caec->addr,
2756 caec->exists = GNUNET_YES;
2759 if ( (ve->session != NULL) &&
2760 (caec->session == ve->session) )
2762 caec->exists = GNUNET_YES;
2771 * Iterator to free entries in the validation_map.
2773 * @param cls closure (unused)
2774 * @param key current key code
2775 * @param value value in the hash map (validation to abort)
2776 * @return GNUNET_YES (always)
2779 abort_validation (void *cls,
2780 const GNUNET_HashCode * key,
2783 struct ValidationEntry *va = value;
2785 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2786 GNUNET_SCHEDULER_cancel (va->timeout_task);
2787 GNUNET_free (va->transport_name);
2788 if (va->chvc != NULL)
2790 va->chvc->ve_count--;
2791 if (va->chvc->ve_count == 0)
2793 GNUNET_CONTAINER_DLL_remove (chvc_head,
2796 GNUNET_free (va->chvc);
2806 * HELLO validation cleanup task (validation failed).
2808 * @param cls the 'struct ValidationEntry' that failed
2809 * @param tc scheduler context (unused)
2812 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2814 struct ValidationEntry *va = cls;
2815 struct GNUNET_PeerIdentity pid;
2817 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2818 GNUNET_STATISTICS_update (stats,
2819 gettext_noop ("# address validation timeouts"),
2822 GNUNET_CRYPTO_hash (&va->publicKey,
2824 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2826 GNUNET_break (GNUNET_OK ==
2827 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2830 abort_validation (NULL, NULL, va);
2835 neighbour_timeout_task (void *cls,
2836 const struct GNUNET_SCHEDULER_TaskContext *tc)
2838 struct NeighbourList *n = cls;
2841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2842 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2844 GNUNET_STATISTICS_update (stats,
2845 gettext_noop ("# disconnects due to timeout"),
2848 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2849 disconnect_neighbour (n, GNUNET_NO);
2854 * Schedule the job that will cause us to send a PING to the
2855 * foreign address to evaluate its validity and latency.
2857 * @param fal address to PING
2860 schedule_next_ping (struct ForeignAddressList *fal);
2864 * Add the given address to the list of foreign addresses
2865 * available for the given peer (check for duplicates).
2867 * @param cls the respective 'struct NeighbourList' to update
2868 * @param tname name of the transport
2869 * @param expiration expiration time
2870 * @param addr the address
2871 * @param addrlen length of the address
2872 * @return GNUNET_OK (always)
2875 add_to_foreign_address_list (void *cls,
2877 struct GNUNET_TIME_Absolute expiration,
2881 struct NeighbourList *n = cls;
2882 struct ForeignAddressList *fal;
2885 GNUNET_STATISTICS_update (stats,
2886 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2890 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2893 #if DEBUG_TRANSPORT_HELLO
2894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2895 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2896 a2s (tname, addr, addrlen),
2898 GNUNET_i2s (&n->id),
2899 expiration.abs_value);
2901 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2904 GNUNET_STATISTICS_update (stats,
2905 gettext_noop ("# previously validated addresses lacking transport"),
2911 fal->expires = GNUNET_TIME_absolute_max (expiration,
2913 schedule_next_ping (fal);
2919 fal->expires = GNUNET_TIME_absolute_max (expiration,
2924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2925 "Failed to add new address for `%4s'\n",
2926 GNUNET_i2s (&n->id));
2929 if (fal->validated == GNUNET_NO)
2931 fal->validated = GNUNET_YES;
2932 GNUNET_STATISTICS_update (stats,
2933 gettext_noop ("# peer addresses considered valid"),
2937 if (try == GNUNET_YES)
2939 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2940 "Have new addresses, will try to trigger transmissions.\n");
2941 try_transmission_to_peer (n);
2948 * Add addresses in validated HELLO "h" to the set of addresses
2949 * we have for this peer.
2951 * @param cls closure ('struct NeighbourList*')
2952 * @param peer id of the peer, NULL for last call
2953 * @param h hello message for the peer (can be NULL)
2954 * @param err_msg NULL if successful, otherwise contains error message
2957 add_hello_for_peer (void *cls,
2958 const struct GNUNET_PeerIdentity *peer,
2959 const struct GNUNET_HELLO_Message *h,
2960 const char *err_msg)
2962 struct NeighbourList *n = cls;
2964 if (err_msg != NULL)
2966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2967 _("Error in communication with PEERINFO service\n"));
2972 GNUNET_STATISTICS_update (stats,
2973 gettext_noop ("# outstanding peerinfo iterate requests"),
2980 return; /* no HELLO available */
2982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2983 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2987 if (GNUNET_YES != n->public_key_valid)
2989 GNUNET_HELLO_get_key (h, &n->publicKey);
2990 n->public_key_valid = GNUNET_YES;
2992 GNUNET_HELLO_iterate_addresses (h,
2994 &add_to_foreign_address_list,
3000 * Create a fresh entry in our neighbour list for the given peer.
3001 * Will try to transmit our current HELLO to the new neighbour.
3002 * Do not call this function directly, use 'setup_peer_check_blacklist.
3004 * @param peer the peer for which we create the entry
3005 * @param do_hello should we schedule transmitting a HELLO
3006 * @return the new neighbour list entry
3008 static struct NeighbourList *
3009 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3012 struct NeighbourList *n;
3013 struct TransportPlugin *tp;
3014 struct ReadyList *rl;
3017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3018 "Setting up state for neighbour `%4s'\n",
3021 GNUNET_assert (our_hello != NULL);
3022 GNUNET_STATISTICS_update (stats,
3023 gettext_noop ("# active neighbours"),
3026 n = GNUNET_malloc (sizeof (struct NeighbourList));
3027 n->next = neighbours;
3031 GNUNET_TIME_relative_to_absolute
3032 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3033 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3034 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3035 MAX_BANDWIDTH_CARRY_S);
3039 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3041 rl = GNUNET_malloc (sizeof (struct ReadyList));
3043 rl->next = n->plugins;
3046 rl->addresses = NULL;
3050 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3052 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3053 &neighbour_timeout_task, n);
3056 GNUNET_STATISTICS_update (stats,
3057 gettext_noop ("# peerinfo new neighbor iterate requests"),
3060 GNUNET_STATISTICS_update (stats,
3061 gettext_noop ("# outstanding peerinfo iterate requests"),
3064 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3065 GNUNET_TIME_UNIT_FOREVER_REL,
3066 &add_hello_for_peer, n);
3068 GNUNET_STATISTICS_update (stats,
3069 gettext_noop ("# HELLO's sent to new neighbors"),
3072 transmit_to_peer (NULL, NULL, 0,
3073 HELLO_ADDRESS_EXPIRATION,
3074 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3082 * Function called after we have checked if communicating
3083 * with a given peer is acceptable.
3085 * @param cls closure
3086 * @param n NULL if communication is not acceptable
3088 typedef void (*SetupContinuation)(void *cls,
3089 struct NeighbourList *n);
3093 * Information kept for each client registered to perform
3099 * This is a linked list.
3101 struct Blacklisters *next;
3104 * This is a linked list.
3106 struct Blacklisters *prev;
3109 * Client responsible for this entry.
3111 struct GNUNET_SERVER_Client *client;
3114 * Blacklist check that we're currently performing.
3116 struct BlacklistCheck *bc;
3122 * Head of DLL of blacklisting clients.
3124 static struct Blacklisters *bl_head;
3127 * Tail of DLL of blacklisting clients.
3129 static struct Blacklisters *bl_tail;
3133 * Context we use when performing a blacklist check.
3135 struct BlacklistCheck
3139 * This is a linked list.
3141 struct BlacklistCheck *next;
3144 * This is a linked list.
3146 struct BlacklistCheck *prev;
3149 * Peer being checked.
3151 struct GNUNET_PeerIdentity peer;
3154 * Option for setup neighbour afterwards.
3159 * Continuation to call with the result.
3161 SetupContinuation cont;
3169 * Current transmission request handle for this client, or NULL if no
3170 * request is pending.
3172 struct GNUNET_CONNECTION_TransmitHandle *th;
3175 * Our current position in the blacklisters list.
3177 struct Blacklisters *bl_pos;
3180 * Current task performing the check.
3182 GNUNET_SCHEDULER_TaskIdentifier task;
3187 * Head of DLL of active blacklisting queries.
3189 static struct BlacklistCheck *bc_head;
3192 * Tail of DLL of active blacklisting queries.
3194 static struct BlacklistCheck *bc_tail;
3198 * Perform next action in the blacklist check.
3200 * @param cls the 'struct BlacklistCheck*'
3204 do_blacklist_check (void *cls,
3205 const struct GNUNET_SCHEDULER_TaskContext *tc);
3208 * Transmit blacklist query to the client.
3210 * @param cls the 'struct BlacklistCheck'
3211 * @param size number of bytes allowed
3212 * @param buf where to copy the message
3213 * @return number of bytes copied to buf
3216 transmit_blacklist_message (void *cls,
3220 struct BlacklistCheck *bc = cls;
3221 struct Blacklisters *bl;
3222 struct BlacklistMessage bm;
3227 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3228 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3233 bm.header.size = htons (sizeof (struct BlacklistMessage));
3234 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3235 bm.is_allowed = htonl (0);
3237 memcpy (buf, &bm, sizeof (bm));
3238 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3244 * Perform next action in the blacklist check.
3246 * @param cls the 'struct BlacklistCheck*'
3250 do_blacklist_check (void *cls,
3251 const struct GNUNET_SCHEDULER_TaskContext *tc)
3253 struct BlacklistCheck *bc = cls;
3254 struct Blacklisters *bl;
3256 bc->task = GNUNET_SCHEDULER_NO_TASK;
3260 bc->cont (bc->cont_cls,
3261 setup_new_neighbour (&bc->peer, bc->do_hello));
3268 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3269 sizeof (struct BlacklistMessage),
3270 GNUNET_TIME_UNIT_FOREVER_REL,
3271 &transmit_blacklist_message,
3278 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3279 * does not yet exist, check the blacklist. If the blacklist says creating
3280 * one is acceptable, create one and call the continuation; otherwise
3281 * call the continuation with NULL.
3283 * @param peer peer to setup or look up a struct NeighbourList for
3284 * @param do_hello should we also schedule sending our HELLO to the peer
3285 * if this is a new record
3286 * @param cont function to call with the 'struct NeigbhbourList*'
3287 * @param cont_cls closure for cont
3290 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3292 SetupContinuation cont,
3295 struct NeighbourList *n;
3296 struct BlacklistCheck *bc;
3298 n = find_neighbour(peer);
3305 if (bl_head == NULL)
3308 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3310 setup_new_neighbour(peer, do_hello);
3313 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3314 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3316 bc->do_hello = do_hello;
3318 bc->cont_cls = cont_cls;
3319 bc->bl_pos = bl_head;
3320 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3326 * Function called with the result of querying a new blacklister about
3327 * it being allowed (or not) to continue to talk to an existing neighbour.
3329 * @param cls the original 'struct NeighbourList'
3330 * @param n NULL if we need to disconnect
3333 confirm_or_drop_neighbour (void *cls,
3334 struct NeighbourList *n)
3336 struct NeighbourList * orig = cls;
3340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3341 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3342 "confirm_or_drop_neighboUr");
3343 disconnect_neighbour (orig, GNUNET_NO);
3349 * Handle a request to start a blacklist.
3351 * @param cls closure (always NULL)
3352 * @param client identification of the client
3353 * @param message the actual message
3356 handle_blacklist_init (void *cls,
3357 struct GNUNET_SERVER_Client *client,
3358 const struct GNUNET_MessageHeader *message)
3360 struct Blacklisters *bl;
3361 struct BlacklistCheck *bc;
3362 struct NeighbourList *n;
3367 if (bl->client == client)
3370 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3375 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3376 bl->client = client;
3377 GNUNET_SERVER_client_keep (client);
3378 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3379 /* confirm that all existing connections are OK! */
3383 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3384 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3386 bc->do_hello = GNUNET_NO;
3387 bc->cont = &confirm_or_drop_neighbour;
3390 if (n == neighbours) /* all would wait for the same client, no need to
3391 create more than just the first task right now */
3392 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3400 * Handle a request to blacklist a peer.
3402 * @param cls closure (always NULL)
3403 * @param client identification of the client
3404 * @param message the actual message
3407 handle_blacklist_reply (void *cls,
3408 struct GNUNET_SERVER_Client *client,
3409 const struct GNUNET_MessageHeader *message)
3411 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3412 struct Blacklisters *bl;
3413 struct BlacklistCheck *bc;
3416 while ( (bl != NULL) &&
3417 (bl->client != client) )
3421 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3426 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3428 bc->cont (bc->cont_cls, NULL);
3429 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3434 bc->bl_pos = bc->bl_pos->next;
3435 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3438 /* check if any other bc's are waiting for this blacklister */
3442 if ( (bc->bl_pos == bl) &&
3443 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3444 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3452 * Send periodic PING messages to a given foreign address.
3454 * @param cls our 'struct PeriodicValidationContext*'
3455 * @param tc task context
3458 send_periodic_ping (void *cls,
3459 const struct GNUNET_SCHEDULER_TaskContext *tc)
3461 struct ForeignAddressList *peer_address = cls;
3462 struct TransportPlugin *tp;
3463 struct ValidationEntry *va;
3464 struct NeighbourList *neighbour;
3465 struct TransportPingMessage ping;
3466 struct CheckAddressExistsClosure caec;
3468 uint16_t hello_size;
3472 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3473 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3475 tp = peer_address->ready_list->plugin;
3476 neighbour = peer_address->ready_list->neighbour;
3477 if (GNUNET_YES != neighbour->public_key_valid)
3479 /* no public key yet, try again later */
3480 schedule_next_ping (peer_address);
3483 caec.addr = peer_address->addr;
3484 caec.addrlen = peer_address->addrlen;
3485 caec.tname = tp->short_name;
3486 caec.session = peer_address->session;
3487 caec.exists = GNUNET_NO;
3488 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3489 &check_address_exists,
3491 if (caec.exists == GNUNET_YES)
3493 /* During validation attempts we will likely trigger the other
3494 peer trying to validate our address which in turn will cause
3495 it to send us its HELLO, so we expect to hit this case rather
3496 frequently. Only print something if we are very verbose. */
3497 #if DEBUG_TRANSPORT > 1
3498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3499 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3500 (peer_address->addr != NULL)
3501 ? a2s (tp->short_name,
3503 peer_address->addrlen)
3506 GNUNET_i2s (&neighbour->id));
3508 schedule_next_ping (peer_address);
3511 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3512 va->transport_name = GNUNET_strdup (tp->short_name);
3513 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3515 va->send_time = GNUNET_TIME_absolute_get();
3516 va->session = peer_address->session;
3517 if (peer_address->addr != NULL)
3519 va->addr = (const void*) &va[1];
3520 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3521 va->addrlen = peer_address->addrlen;
3523 memcpy(&va->publicKey,
3524 &neighbour->publicKey,
3525 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3527 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3528 &timeout_hello_validation,
3530 GNUNET_CONTAINER_multihashmap_put (validation_map,
3531 &neighbour->id.hashPubKey,
3533 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3535 if (peer_address->validated != GNUNET_YES)
3536 hello_size = GNUNET_HELLO_size(our_hello);
3540 tsize = sizeof(struct TransportPingMessage) + hello_size;
3542 if (peer_address->addr != NULL)
3544 slen = strlen (tp->short_name) + 1;
3545 tsize += slen + peer_address->addrlen;
3549 slen = 0; /* make gcc happy */
3551 message_buf = GNUNET_malloc(tsize);
3552 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3553 ping.challenge = htonl(va->challenge);
3554 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3555 if (peer_address->validated != GNUNET_YES)
3557 memcpy(message_buf, our_hello, hello_size);
3560 if (peer_address->addr != NULL)
3562 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3563 peer_address->addrlen +
3565 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3568 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3570 peer_address->addrlen);
3574 ping.header.size = htons(sizeof(struct TransportPingMessage));
3577 memcpy(&message_buf[hello_size],
3579 sizeof(struct TransportPingMessage));
3581 #if DEBUG_TRANSPORT_REVALIDATION
3582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3583 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3584 (peer_address->addr != NULL)
3585 ? a2s (peer_address->plugin->short_name,
3587 peer_address->addrlen)
3590 GNUNET_i2s (&neighbour->id),
3591 "HELLO", hello_size,
3594 if (peer_address->validated != GNUNET_YES)
3595 GNUNET_STATISTICS_update (stats,
3596 gettext_noop ("# PING with HELLO messages sent"),
3600 GNUNET_STATISTICS_update (stats,
3601 gettext_noop ("# PING without HELLO messages sent"),
3604 GNUNET_STATISTICS_update (stats,
3605 gettext_noop ("# PING messages sent for re-validation"),
3608 transmit_to_peer (NULL, peer_address,
3609 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3610 HELLO_VERIFICATION_TIMEOUT,
3612 GNUNET_YES, neighbour);
3613 GNUNET_free(message_buf);
3614 schedule_next_ping (peer_address);
3619 * Schedule the job that will cause us to send a PING to the
3620 * foreign address to evaluate its validity and latency.
3622 * @param fal address to PING
3625 schedule_next_ping (struct ForeignAddressList *fal)
3627 struct GNUNET_TIME_Relative delay;
3629 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3631 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3632 delay.rel_value /= 2; /* do before expiration */
3633 delay = GNUNET_TIME_relative_min (delay,
3634 LATENCY_EVALUATION_MAX_DELAY);
3635 if (GNUNET_YES != fal->estimated)
3637 delay = GNUNET_TIME_UNIT_ZERO;
3638 fal->estimated = GNUNET_YES;
3640 if (GNUNET_YES == fal->connected)
3642 delay = GNUNET_TIME_relative_min (delay,
3643 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3645 /* FIXME: also adjust delay based on how close the last
3646 observed latency is to the latency of the best alternative */
3647 /* bound how fast we can go */
3648 delay = GNUNET_TIME_relative_max (delay,
3649 GNUNET_TIME_UNIT_SECONDS);
3650 /* randomize a bit (to avoid doing all at the same time) */
3651 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3652 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3653 &send_periodic_ping,
3661 * Function that will be called if we receive some payload
3662 * from another peer.
3664 * @param message the payload
3665 * @param n peer who claimed to be the sender
3668 handle_payload_message (const struct GNUNET_MessageHeader *message,
3669 struct NeighbourList *n)
3671 struct InboundMessage *im;
3672 struct TransportClient *cpos;
3675 msize = ntohs (message->size);
3676 if (n->received_pong == GNUNET_NO)
3678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3679 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3680 ntohs (message->type),
3681 ntohs (message->size),
3682 GNUNET_i2s (&n->id));
3683 GNUNET_free_non_null (n->pre_connect_message_buffer);
3684 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3685 memcpy (n->pre_connect_message_buffer, message, msize);
3690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3691 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3692 ntohs (message->type),
3693 ntohs (message->size),
3694 GNUNET_i2s (&n->id));
3696 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3699 n->quota_violation_count++;
3701 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3702 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3703 n->in_tracker.available_bytes_per_s__,
3704 n->quota_violation_count);
3706 /* Discount 32k per violation */
3707 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3712 if (n->quota_violation_count > 0)
3714 /* try to add 32k back */
3715 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3717 n->quota_violation_count--;
3720 GNUNET_STATISTICS_update (stats,
3721 gettext_noop ("# payload received from other peers"),
3724 /* transmit message to all clients */
3725 uint32_t ats_count = 2;
3726 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3727 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3730 im = GNUNET_malloc (size);
3731 im->header.size = htons (size);
3732 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3734 im->ats_count = htonl(ats_count);
3735 /* Setting ATS data */
3736 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3737 (&(im->ats))[0].value = htonl (n->distance);
3738 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3739 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3740 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3741 (&(im->ats))[ats_count].value = htonl (0);
3743 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3745 while (cpos != NULL)
3747 transmit_to_client (cpos, &im->header, GNUNET_YES);
3755 * Iterator over hash map entries. Checks if the given validation
3756 * entry is for the same challenge as what is given in the PONG.
3758 * @param cls the 'struct TransportPongMessage*'
3759 * @param key peer identity
3760 * @param value value in the hash map ('struct ValidationEntry')
3761 * @return GNUNET_YES if we should continue to
3762 * iterate (mismatch), GNUNET_NO if not (entry matched)
3765 check_pending_validation (void *cls,
3766 const GNUNET_HashCode * key,
3769 const struct TransportPongMessage *pong = cls;
3770 struct ValidationEntry *ve = value;
3771 struct AddValidatedAddressContext avac;
3772 unsigned int challenge = ntohl(pong->challenge);
3773 struct GNUNET_HELLO_Message *hello;
3774 struct GNUNET_PeerIdentity target;
3775 struct NeighbourList *n;
3776 struct ForeignAddressList *fal;
3777 struct OwnAddressList *oal;
3778 struct TransportPlugin *tp;
3779 struct GNUNET_MessageHeader *prem;
3785 ps = ntohs (pong->header.size);
3786 if (ps < sizeof (struct TransportPongMessage))
3788 GNUNET_break_op (0);
3791 addr = (const char*) &pong[1];
3792 slen = strlen (ve->transport_name) + 1;
3793 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3794 (ve->challenge != challenge) ||
3795 (addr[slen-1] != '\0') ||
3796 (0 != strcmp (addr, ve->transport_name)) ||
3797 (ntohl (pong->purpose.size)
3798 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3800 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3801 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3806 alen = ps - sizeof (struct TransportPongMessage) - slen;
3807 switch (ntohl (pong->purpose.purpose))
3809 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3810 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3811 (0 != memcmp (&addr[slen],
3815 return GNUNET_YES; /* different entry, keep trying! */
3817 if (0 != memcmp (&pong->pid,
3819 sizeof (struct GNUNET_PeerIdentity)))
3821 GNUNET_break_op (0);
3825 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3830 GNUNET_break_op (0);
3835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3836 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3838 a2s (ve->transport_name,
3839 (const struct sockaddr *) ve->addr,
3841 ve->transport_name);
3844 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3845 if (0 != memcmp (&pong->pid,
3847 sizeof (struct GNUNET_PeerIdentity)))
3849 GNUNET_break_op (0);
3852 if (ve->addrlen != 0)
3854 /* must have been for a different validation entry */
3857 tp = find_transport (ve->transport_name);
3863 oal = tp->addresses;
3866 if ( (oal->addrlen == alen) &&
3867 (0 == memcmp (&oal[1],
3875 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3876 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3877 a2s (ve->transport_name,
3883 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3888 GNUNET_break_op (0);
3893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3894 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3896 a2s (ve->transport_name,
3899 ve->transport_name);
3903 GNUNET_break_op (0);
3906 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3908 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3909 _("Received expired signature. Check system time.\n"));
3912 GNUNET_STATISTICS_update (stats,
3913 gettext_noop ("# address validation successes"),
3916 /* create the updated HELLO */
3917 GNUNET_CRYPTO_hash (&ve->publicKey,
3918 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3919 &target.hashPubKey);
3920 if (ve->addr != NULL)
3922 avac.done = GNUNET_NO;
3924 hello = GNUNET_HELLO_create (&ve->publicKey,
3925 &add_validated_address,
3927 GNUNET_PEERINFO_add_peer (peerinfo,
3929 GNUNET_free (hello);
3931 n = find_neighbour (&target);
3934 n->publicKey = ve->publicKey;
3935 n->public_key_valid = GNUNET_YES;
3936 fal = add_peer_address (n,
3941 GNUNET_assert (fal != NULL);
3942 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3943 fal->validated = GNUNET_YES;
3944 mark_address_connected (fal);
3945 GNUNET_STATISTICS_update (stats,
3946 gettext_noop ("# peer addresses considered valid"),
3949 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3950 schedule_next_ping (fal);
3951 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3952 n->latency = fal->latency;
3954 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3956 n->distance = fal->distance;
3957 if (GNUNET_NO == n->received_pong)
3959 n->received_pong = GNUNET_YES;
3961 notify_clients_connect (&target, n->latency, n->distance);
3962 if (NULL != (prem = n->pre_connect_message_buffer))
3964 n->pre_connect_message_buffer = NULL;
3965 handle_payload_message (prem, n);
3969 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3971 GNUNET_SCHEDULER_cancel (n->retry_task);
3972 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3973 try_transmission_to_peer (n);
3977 /* clean up validation entry */
3978 GNUNET_assert (GNUNET_YES ==
3979 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3982 abort_validation (NULL, NULL, ve);
3988 * Function that will be called if we receive a validation
3989 * of an address challenge that we transmitted to another
3990 * peer. Note that the validation should only be considered
3991 * acceptable if the challenge matches AND if the sender
3992 * address is at least a plausible address for this peer
3993 * (otherwise we may be seeing a MiM attack).
3995 * @param cls closure
3996 * @param message the pong message
3997 * @param peer who responded to our challenge
3998 * @param sender_address string describing our sender address (as observed
3999 * by the other peer in binary format)
4000 * @param sender_address_len number of bytes in 'sender_address'
4003 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4004 const struct GNUNET_PeerIdentity *peer,
4005 const char *sender_address,
4006 size_t sender_address_len)
4008 #if DEBUG_TRANSPORT > 1
4009 /* we get tons of these that just get discarded, only log
4010 if we are quite verbose */
4011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4012 "Receiving `%s' message from `%4s'.\n", "PONG",
4015 GNUNET_STATISTICS_update (stats,
4016 gettext_noop ("# PONG messages received"),
4019 if (GNUNET_SYSERR !=
4020 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4022 &check_pending_validation,
4025 /* This is *expected* to happen a lot since we send
4026 PONGs to *all* known addresses of the sender of
4027 the PING, so most likely we get multiple PONGs
4028 per PING, and all but the first PONG will end up
4029 here. So really we should not print anything here
4030 unless we want to be very, very verbose... */
4031 #if DEBUG_TRANSPORT > 2
4032 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4033 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4045 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4047 * @param cls the 'struct ValidationEntry*'
4048 * @param neighbour neighbour to validate, NULL if validation failed
4051 transmit_hello_and_ping (void *cls,
4052 struct NeighbourList *neighbour)
4054 struct ValidationEntry *va = cls;
4055 struct ForeignAddressList *peer_address;
4056 struct TransportPingMessage ping;
4057 uint16_t hello_size;
4060 struct GNUNET_PeerIdentity id;
4063 GNUNET_CRYPTO_hash (&va->publicKey,
4064 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4066 if (neighbour == NULL)
4068 /* FIXME: stats... */
4069 GNUNET_break (GNUNET_OK ==
4070 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4073 abort_validation (NULL, NULL, va);
4076 neighbour->publicKey = va->publicKey;
4077 neighbour->public_key_valid = GNUNET_YES;
4078 peer_address = add_peer_address (neighbour,
4079 va->transport_name, NULL,
4080 (const void*) &va[1],
4082 if (peer_address == NULL)
4084 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4085 "Failed to add peer `%4s' for plugin `%s'\n",
4086 GNUNET_i2s (&neighbour->id),
4087 va->transport_name);
4088 GNUNET_break (GNUNET_OK ==
4089 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4092 abort_validation (NULL, NULL, va);
4095 hello_size = GNUNET_HELLO_size(our_hello);
4096 slen = strlen(va->transport_name) + 1;
4097 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4098 message_buf = GNUNET_malloc(tsize);
4099 ping.challenge = htonl(va->challenge);
4100 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4101 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4102 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4103 memcpy(message_buf, our_hello, hello_size);
4104 memcpy(&message_buf[hello_size],
4106 sizeof(struct TransportPingMessage));
4107 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4110 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4115 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4118 : a2s (va->transport_name,
4119 (const void*) &va[1], va->addrlen),
4121 GNUNET_i2s (&neighbour->id),
4122 "HELLO", hello_size,
4123 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4126 GNUNET_STATISTICS_update (stats,
4127 gettext_noop ("# PING messages sent for initial validation"),
4130 transmit_to_peer (NULL, peer_address,
4131 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4132 HELLO_VERIFICATION_TIMEOUT,
4134 GNUNET_YES, neighbour);
4135 GNUNET_free(message_buf);
4140 * Check if the given address is already being validated; if not,
4141 * append the given address to the list of entries that are being be
4142 * validated and initiate validation.
4144 * @param cls closure ('struct CheckHelloValidatedContext *')
4145 * @param tname name of the transport
4146 * @param expiration expiration time
4147 * @param addr the address
4148 * @param addrlen length of the address
4149 * @return GNUNET_OK (always)
4152 run_validation (void *cls,
4154 struct GNUNET_TIME_Absolute expiration,
4158 struct CheckHelloValidatedContext *chvc = cls;
4159 struct GNUNET_PeerIdentity id;
4160 struct TransportPlugin *tp;
4161 struct ValidationEntry *va;
4162 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4163 struct CheckAddressExistsClosure caec;
4164 struct OwnAddressList *oal;
4166 GNUNET_assert (addr != NULL);
4168 GNUNET_STATISTICS_update (stats,
4169 gettext_noop ("# peer addresses scheduled for validation"),
4172 tp = find_transport (tname);
4175 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4176 GNUNET_ERROR_TYPE_BULK,
4178 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4180 GNUNET_STATISTICS_update (stats,
4181 gettext_noop ("# peer addresses not validated (plugin not available)"),
4186 /* check if this is one of our own addresses */
4187 oal = tp->addresses;
4190 if ( (oal->addrlen == addrlen) &&
4191 (0 == memcmp (&oal[1],
4195 /* not plausible, this address is equivalent to our own address! */
4196 GNUNET_STATISTICS_update (stats,
4197 gettext_noop ("# peer addresses not validated (loopback)"),
4204 GNUNET_HELLO_get_key (chvc->hello, &pk);
4205 GNUNET_CRYPTO_hash (&pk,
4207 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4210 if (is_blacklisted(&id, tp))
4213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4214 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4222 caec.addrlen = addrlen;
4223 caec.session = NULL;
4225 caec.exists = GNUNET_NO;
4226 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4227 &check_address_exists,
4229 if (caec.exists == GNUNET_YES)
4231 /* During validation attempts we will likely trigger the other
4232 peer trying to validate our address which in turn will cause
4233 it to send us its HELLO, so we expect to hit this case rather
4234 frequently. Only print something if we are very verbose. */
4235 #if DEBUG_TRANSPORT > 1
4236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4237 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4238 a2s (tname, addr, addrlen),
4242 GNUNET_STATISTICS_update (stats,
4243 gettext_noop ("# peer addresses not validated (in progress)"),
4248 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4251 va->transport_name = GNUNET_strdup (tname);
4252 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4254 va->send_time = GNUNET_TIME_absolute_get();
4255 va->addr = (const void*) &va[1];
4256 memcpy (&va[1], addr, addrlen);
4257 va->addrlen = addrlen;
4258 GNUNET_HELLO_get_key (chvc->hello,
4260 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4261 &timeout_hello_validation,
4263 GNUNET_CONTAINER_multihashmap_put (validation_map,
4266 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4267 setup_peer_check_blacklist (&id, GNUNET_NO,
4268 &transmit_hello_and_ping,
4275 * Check if addresses in validated hello "h" overlap with
4276 * those in "chvc->hello" and validate the rest.
4278 * @param cls closure
4279 * @param peer id of the peer, NULL for last call
4280 * @param h hello message for the peer (can be NULL)
4281 * @param err_msg NULL if successful, otherwise contains error message
4284 check_hello_validated (void *cls,
4285 const struct GNUNET_PeerIdentity *peer,
4286 const struct GNUNET_HELLO_Message *h,
4287 const char *err_msg)
4289 struct CheckHelloValidatedContext *chvc = cls;
4290 struct GNUNET_HELLO_Message *plain_hello;
4291 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4292 struct GNUNET_PeerIdentity target;
4293 struct NeighbourList *n;
4295 if (err_msg != NULL)
4297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4298 _("Error in communication with PEERINFO service\n"));
4304 GNUNET_STATISTICS_update (stats,
4305 gettext_noop ("# outstanding peerinfo iterate requests"),
4309 if (GNUNET_NO == chvc->hello_known)
4311 /* notify PEERINFO about the peer now, so that we at least
4312 have the public key if some other component needs it */
4313 GNUNET_HELLO_get_key (chvc->hello, &pk);
4314 GNUNET_CRYPTO_hash (&pk,
4315 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4316 &target.hashPubKey);
4317 plain_hello = GNUNET_HELLO_create (&pk,
4320 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4321 GNUNET_free (plain_hello);
4322 #if DEBUG_TRANSPORT_HELLO
4323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4324 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4326 GNUNET_i2s (&target));
4328 GNUNET_STATISTICS_update (stats,
4329 gettext_noop ("# new HELLOs requiring full validation"),
4332 GNUNET_HELLO_iterate_addresses (chvc->hello,
4339 GNUNET_STATISTICS_update (stats,
4340 gettext_noop ("# duplicate HELLO (peer known)"),
4345 if (chvc->ve_count == 0)
4347 GNUNET_CONTAINER_DLL_remove (chvc_head,
4356 #if DEBUG_TRANSPORT_HELLO
4357 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4358 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4362 chvc->hello_known = GNUNET_YES;
4363 n = find_neighbour (peer);
4366 #if DEBUG_TRANSPORT_HELLO
4367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4368 "Calling hello_iterate_addresses for %s!\n",
4371 GNUNET_HELLO_iterate_addresses (h,
4373 &add_to_foreign_address_list,
4375 try_transmission_to_peer (n);
4379 #if DEBUG_TRANSPORT_HELLO
4380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4381 "No existing neighbor record for %s!\n",
4384 GNUNET_STATISTICS_update (stats,
4385 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4389 GNUNET_STATISTICS_update (stats,
4390 gettext_noop ("# HELLO validations (update case)"),
4393 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4395 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4402 * Process HELLO-message.
4404 * @param plugin transport involved, may be NULL
4405 * @param message the actual message
4406 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4409 process_hello (struct TransportPlugin *plugin,
4410 const struct GNUNET_MessageHeader *message)
4413 struct GNUNET_PeerIdentity target;
4414 const struct GNUNET_HELLO_Message *hello;
4415 struct CheckHelloValidatedContext *chvc;
4416 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4417 #if DEBUG_TRANSPORT_HELLO > 2
4420 hsize = ntohs (message->size);
4421 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4422 (hsize < sizeof (struct GNUNET_MessageHeader)))
4425 return GNUNET_SYSERR;
4427 GNUNET_STATISTICS_update (stats,
4428 gettext_noop ("# HELLOs received for validation"),
4432 /* first, check if load is too high */
4433 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4435 GNUNET_STATISTICS_update (stats,
4436 gettext_noop ("# HELLOs ignored due to high load"),
4439 #if DEBUG_TRANSPORT_HELLO
4440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4441 "Ignoring `%s' for `%4s', load too high.\n",
4443 GNUNET_i2s (&target));
4447 hello = (const struct GNUNET_HELLO_Message *) message;
4448 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4450 #if DEBUG_TRANSPORT_HELLO
4451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4452 "Unable to get public key from `%s' for `%4s'!\n",
4454 GNUNET_i2s (&target));
4456 GNUNET_break_op (0);
4457 return GNUNET_SYSERR;
4460 GNUNET_CRYPTO_hash (&publicKey,
4461 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4462 &target.hashPubKey);
4464 #if DEBUG_TRANSPORT_HELLO
4465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4466 "Received `%s' message for `%4s'\n",
4468 GNUNET_i2s (&target));
4471 if (0 == memcmp (&my_identity,
4473 sizeof (struct GNUNET_PeerIdentity)))
4475 GNUNET_STATISTICS_update (stats,
4476 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4482 while (NULL != chvc)
4484 if (GNUNET_HELLO_equals (hello,
4486 GNUNET_TIME_absolute_get ()).abs_value > 0)
4488 #if DEBUG_TRANSPORT_HELLO > 2
4489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4490 "Received duplicate `%s' message for `%4s'; ignored\n",
4492 GNUNET_i2s (&target));
4494 return GNUNET_OK; /* validation already pending */
4496 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4497 GNUNET_break (0 != memcmp (hello, chvc->hello,
4498 GNUNET_HELLO_size(hello)));
4503 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4504 if ((NULL != temp_neighbor))
4506 fprintf(stderr, "Already know peer, ignoring hello\n");
4511 #if DEBUG_TRANSPORT_HELLO > 2
4514 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4516 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4519 GNUNET_i2s (&target),
4521 GNUNET_HELLO_size(hello));
4525 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4527 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4528 memcpy (&chvc[1], hello, hsize);
4529 GNUNET_CONTAINER_DLL_insert (chvc_head,
4532 /* finally, check if HELLO was previously validated
4533 (continuation will then schedule actual validation) */
4534 GNUNET_STATISTICS_update (stats,
4535 gettext_noop ("# peerinfo process hello iterate requests"),
4538 GNUNET_STATISTICS_update (stats,
4539 gettext_noop ("# outstanding peerinfo iterate requests"),
4542 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4544 HELLO_VERIFICATION_TIMEOUT,
4545 &check_hello_validated, chvc);
4551 * The peer specified by the given neighbour has timed-out or a plugin
4552 * has disconnected. We may either need to do nothing (other plugins
4553 * still up), or trigger a full disconnect and clean up. This
4554 * function updates our state and does the necessary notifications.
4555 * Also notifies our clients that the neighbour is now officially
4558 * @param n the neighbour list entry for the peer
4559 * @param check GNUNET_YES to check if ALL addresses for this peer
4560 * are gone, GNUNET_NO to force a disconnect of the peer
4561 * regardless of whether other addresses exist.
4564 disconnect_neighbour (struct NeighbourList *n, int check)
4566 struct ReadyList *rpos;
4567 struct NeighbourList *npos;
4568 struct NeighbourList *nprev;
4569 struct MessageQueue *mq;
4570 struct ForeignAddressList *peer_addresses;
4571 struct ForeignAddressList *peer_pos;
4573 if (GNUNET_YES == check)
4576 while (NULL != rpos)
4578 peer_addresses = rpos->addresses;
4579 while (peer_addresses != NULL)
4581 if (GNUNET_YES == peer_addresses->connected)
4583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4584 "NOT Disconnecting from `%4s', still have live addresses!\n",
4585 GNUNET_i2s (&n->id));
4586 return; /* still connected */
4588 peer_addresses = peer_addresses->next;
4594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4595 "Disconnecting from `%4s'\n",
4596 GNUNET_i2s (&n->id));
4598 /* remove n from neighbours list */
4601 while ((npos != NULL) && (npos != n))
4606 GNUNET_assert (npos != NULL);
4608 neighbours = n->next;
4610 nprev->next = n->next;
4612 /* notify all clients about disconnect */
4613 if (GNUNET_YES == n->received_pong)
4614 notify_clients_disconnect (&n->id);
4616 /* clean up all plugins, cancel connections and pending transmissions */
4617 while (NULL != (rpos = n->plugins))
4619 n->plugins = rpos->next;
4620 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4621 while (rpos->addresses != NULL)
4623 peer_pos = rpos->addresses;
4624 rpos->addresses = peer_pos->next;
4625 if (peer_pos->connected == GNUNET_YES)
4626 GNUNET_STATISTICS_update (stats,
4627 gettext_noop ("# connected addresses"),
4630 if (GNUNET_YES == peer_pos->validated)
4631 GNUNET_STATISTICS_update (stats,
4632 gettext_noop ("# peer addresses considered valid"),
4635 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4637 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4638 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4640 GNUNET_free(peer_pos->ressources);
4641 GNUNET_free(peer_pos);
4646 /* free all messages on the queue */
4647 while (NULL != (mq = n->messages_head))
4649 GNUNET_STATISTICS_update (stats,
4650 gettext_noop ("# bytes in message queue for other peers"),
4651 - (int64_t) mq->message_buf_size,
4653 GNUNET_STATISTICS_update (stats,
4654 gettext_noop ("# bytes discarded due to disconnect"),
4655 mq->message_buf_size,
4657 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4660 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4662 sizeof(struct GNUNET_PeerIdentity)));
4665 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4667 GNUNET_SCHEDULER_cancel (n->timeout_task);
4668 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4670 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4672 GNUNET_SCHEDULER_cancel (n->retry_task);
4673 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4675 if (n->piter != NULL)
4677 GNUNET_PEERINFO_iterate_cancel (n->piter);
4678 GNUNET_STATISTICS_update (stats,
4679 gettext_noop ("# outstanding peerinfo iterate requests"),
4684 /* finally, free n itself */
4685 GNUNET_STATISTICS_update (stats,
4686 gettext_noop ("# active neighbours"),
4689 GNUNET_free_non_null (n->pre_connect_message_buffer);
4695 * We have received a PING message from someone. Need to send a PONG message
4696 * in response to the peer by any means necessary.
4699 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4700 const struct GNUNET_PeerIdentity *peer,
4701 struct Session *session,
4702 const char *sender_address,
4703 uint16_t sender_address_len)
4705 struct TransportPlugin *plugin = cls;
4706 struct SessionHeader *session_header = (struct SessionHeader*) session;
4707 struct TransportPingMessage *ping;
4708 struct TransportPongMessage *pong;
4709 struct NeighbourList *n;
4710 struct ReadyList *rl;
4711 struct ForeignAddressList *fal;
4712 struct OwnAddressList *oal;
4717 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4719 GNUNET_break_op (0);
4720 return GNUNET_SYSERR;
4723 ping = (struct TransportPingMessage *) message;
4724 if (0 != memcmp (&ping->target,
4725 plugin->env.my_identity,
4726 sizeof (struct GNUNET_PeerIdentity)))
4728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4729 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4731 (sender_address != NULL)
4732 ? a2s (plugin->short_name,
4733 (const struct sockaddr *)sender_address,
4736 GNUNET_i2s (&ping->target));
4737 return GNUNET_SYSERR;
4740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4741 "Processing `%s' from `%s'\n",
4743 (sender_address != NULL)
4744 ? a2s (plugin->short_name,
4745 (const struct sockaddr *)sender_address,
4749 GNUNET_STATISTICS_update (stats,
4750 gettext_noop ("# PING messages received"),
4753 addr = (const char*) &ping[1];
4754 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4755 slen = strlen (plugin->short_name) + 1;
4758 /* peer wants to confirm that we have an outbound connection to him */
4759 if (session == NULL)
4761 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4762 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4764 return GNUNET_SYSERR;
4766 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4767 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4768 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4769 pong->purpose.size =
4770 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4772 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4773 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4774 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4775 pong->challenge = ping->challenge;
4776 pong->addrlen = htonl(sender_address_len + slen);
4779 sizeof(struct GNUNET_PeerIdentity));
4783 if ((sender_address!=NULL) && (sender_address_len > 0))
4784 memcpy (&((char*)&pong[1])[slen],
4786 sender_address_len);
4787 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4789 /* create / update cached sig */
4791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4792 "Creating PONG signature to indicate active connection.\n");
4794 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4795 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4796 GNUNET_assert (GNUNET_OK ==
4797 GNUNET_CRYPTO_rsa_sign (my_private_key,
4799 &session_header->pong_signature));
4803 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4805 memcpy (&pong->signature,
4806 &session_header->pong_signature,
4807 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4813 /* peer wants to confirm that this is one of our addresses */
4817 plugin->api->check_address (plugin->api->cls,
4821 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4822 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4823 a2s (plugin->short_name,
4828 oal = plugin->addresses;
4831 if ( (oal->addrlen == alen) &&
4838 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4839 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4840 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4841 pong->purpose.size =
4842 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4844 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4845 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4846 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4847 pong->challenge = ping->challenge;
4848 pong->addrlen = htonl(alen + slen);
4851 sizeof(struct GNUNET_PeerIdentity));
4852 memcpy (&pong[1], plugin->short_name, slen);
4853 memcpy (&((char*)&pong[1])[slen], addr, alen);
4854 if ( (oal != NULL) &&
4855 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4857 /* create / update cached sig */
4859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4860 "Creating PONG signature to indicate ownership.\n");
4862 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4863 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4864 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4865 GNUNET_assert (GNUNET_OK ==
4866 GNUNET_CRYPTO_rsa_sign (my_private_key,
4868 &oal->pong_signature));
4869 memcpy (&pong->signature,
4870 &oal->pong_signature,
4871 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4873 else if (oal == NULL)
4875 /* not using cache (typically DV-only) */
4876 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4877 GNUNET_assert (GNUNET_OK ==
4878 GNUNET_CRYPTO_rsa_sign (my_private_key,
4884 /* can used cached version */
4885 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4886 memcpy (&pong->signature,
4887 &oal->pong_signature,
4888 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4891 n = find_neighbour(peer);
4892 GNUNET_assert (n != NULL);
4893 /* first try reliable response transmission */
4897 fal = rl->addresses;
4900 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4903 ntohs (pong->header.size),
4904 TRANSPORT_PONG_PRIORITY,
4905 HELLO_VERIFICATION_TIMEOUT,
4913 GNUNET_STATISTICS_update (stats,
4914 gettext_noop ("# PONGs unicast via reliable transport"),
4924 /* no reliable method found, do multicast */
4925 GNUNET_STATISTICS_update (stats,
4926 gettext_noop ("# PONGs multicast to all available addresses"),
4932 fal = rl->addresses;
4935 transmit_to_peer(NULL, fal,
4936 TRANSPORT_PONG_PRIORITY,
4937 HELLO_VERIFICATION_TIMEOUT,
4939 ntohs(pong->header.size),
4952 * Function called by the plugin for each received message.
4953 * Update data volumes, possibly notify plugins about
4954 * reducing the rate at which they read from the socket
4955 * and generally forward to our receive callback.
4957 * @param cls the "struct TransportPlugin *" we gave to the plugin
4958 * @param peer (claimed) identity of the other peer
4959 * @param message the message, NULL if we only care about
4960 * learning about the delay until we should receive again
4961 * @param ats_data information for automatic transport selection
4962 * @param ats_count number of elements in ats not including 0-terminator
4963 * @param session identifier used for this session (can be NULL)
4964 * @param sender_address binary address of the sender (if observed)
4965 * @param sender_address_len number of bytes in sender_address
4966 * @return how long in ms the plugin should wait until receiving more data
4967 * (plugins that do not support this, can ignore the return value)
4969 static struct GNUNET_TIME_Relative
4970 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4971 const struct GNUNET_MessageHeader *message,
4972 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4974 struct Session *session,
4975 const char *sender_address,
4976 uint16_t sender_address_len)
4978 struct TransportPlugin *plugin = cls;
4979 struct ReadyList *service_context;
4980 struct ForeignAddressList *peer_address;
4982 struct NeighbourList *n;
4983 struct GNUNET_TIME_Relative ret;
4984 if (is_blacklisted (peer, plugin))
4985 return GNUNET_TIME_UNIT_FOREVER_REL;
4989 n = find_neighbour (peer);
4991 n = setup_new_neighbour (peer, GNUNET_YES);
4992 service_context = n->plugins;
4993 while ((service_context != NULL) && (plugin != service_context->plugin))
4994 service_context = service_context->next;
4995 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4996 peer_address = NULL;
4998 for (c=0; c<ats_count; c++)
5000 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5002 distance = ntohl(ats_data[c].value);
5005 /* notify ATS about incoming data */
5006 ats_notify_ats_data(peer, ats_data);
5008 if (message != NULL)
5010 if ( (session != NULL) ||
5011 (sender_address != NULL) )
5012 peer_address = add_peer_address (n,
5016 sender_address_len);
5017 if (peer_address != NULL)
5019 peer_address->distance = distance;
5020 if (GNUNET_YES == peer_address->validated)
5021 mark_address_connected (peer_address);
5022 peer_address->timeout
5024 GNUNET_TIME_relative_to_absolute
5025 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5026 schedule_next_ping (peer_address);
5028 /* update traffic received amount ... */
5029 msize = ntohs (message->size);
5030 GNUNET_STATISTICS_update (stats,
5031 gettext_noop ("# bytes received from other peers"),
5034 n->distance = distance;
5036 GNUNET_TIME_relative_to_absolute
5037 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5038 GNUNET_SCHEDULER_cancel (n->timeout_task);
5040 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5041 &neighbour_timeout_task, n);
5042 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5044 /* dropping message due to frequent inbound volume violations! */
5045 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5046 GNUNET_ERROR_TYPE_BULK,
5048 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5049 n->in_tracker.available_bytes_per_s__,
5050 n->quota_violation_count);
5051 GNUNET_STATISTICS_update (stats,
5052 gettext_noop ("# bandwidth quota violations by other peers"),
5055 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5060 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5061 ntohs (message->type),
5062 ntohs (message->size),
5065 switch (ntohs (message->type))
5067 case GNUNET_MESSAGE_TYPE_HELLO:
5068 GNUNET_STATISTICS_update (stats,
5069 gettext_noop ("# HELLO messages received from other peers"),
5072 process_hello (plugin, message);
5074 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5075 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5077 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5078 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5081 handle_payload_message (message, n);
5085 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5086 if (ret.rel_value > 0)
5088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5089 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5090 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5091 (unsigned int) n->in_tracker.available_bytes_per_s__,
5092 (unsigned long long) ret.rel_value);
5093 GNUNET_STATISTICS_update (stats,
5094 gettext_noop ("# ms throttling suggested"),
5095 (int64_t) ret.rel_value,
5102 * Handle START-message. This is the first message sent to us
5103 * by any client which causes us to add it to our list.
5105 * @param cls closure (always NULL)
5106 * @param client identification of the client
5107 * @param message the actual message
5110 handle_start (void *cls,
5111 struct GNUNET_SERVER_Client *client,
5112 const struct GNUNET_MessageHeader *message)
5114 const struct StartMessage *start;
5115 struct TransportClient *c;
5116 struct ConnectInfoMessage * cim;
5117 struct NeighbourList *n;
5121 start = (const struct StartMessage*) message;
5123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5124 "Received `%s' request from client\n", "START");
5129 if (c->client == client)
5131 /* client already on our list! */
5133 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5138 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5139 (0 != memcmp (&start->self,
5141 sizeof (struct GNUNET_PeerIdentity))) )
5143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5144 _("Rejecting control connection from peer `%s', which is not me!\n"),
5145 GNUNET_i2s (&start->self));
5146 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5149 c = GNUNET_malloc (sizeof (struct TransportClient));
5153 if (our_hello != NULL)
5156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5157 "Sending our own `%s' to new client\n", "HELLO");
5159 transmit_to_client (c,
5160 (const struct GNUNET_MessageHeader *) our_hello,
5162 /* tell new client about all existing connections */
5164 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5165 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5169 cim = GNUNET_malloc (size);
5170 cim->header.size = htons (size);
5171 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5172 cim->ats_count = htonl(ats_count);
5173 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5174 (&(cim->ats))[2].value = htonl (0);
5178 if (GNUNET_YES == n->received_pong)
5180 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5181 (&(cim->ats))[0].value = htonl (n->distance);
5182 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5183 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5185 transmit_to_client (c, &cim->header, GNUNET_NO);
5191 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5196 * Handle HELLO-message.
5198 * @param cls closure (always NULL)
5199 * @param client identification of the client
5200 * @param message the actual message
5203 handle_hello (void *cls,
5204 struct GNUNET_SERVER_Client *client,
5205 const struct GNUNET_MessageHeader *message)
5209 GNUNET_STATISTICS_update (stats,
5210 gettext_noop ("# HELLOs received from clients"),
5213 ret = process_hello (NULL, message);
5214 GNUNET_SERVER_receive_done (client, ret);
5219 * Closure for 'transmit_client_message'; followed by
5220 * 'msize' bytes of the actual message.
5222 struct TransmitClientMessageContext
5225 * Client on whom's behalf we are sending.
5227 struct GNUNET_SERVER_Client *client;
5230 * Timeout for the transmission.
5232 struct GNUNET_TIME_Absolute timeout;
5240 * Size of the message in bytes.
5247 * Schedule transmission of a message we got from a client to a peer.
5249 * @param cls the 'struct TransmitClientMessageContext*'
5250 * @param n destination, or NULL on error (in that case, drop the message)
5253 transmit_client_message (void *cls,
5254 struct NeighbourList *n)
5256 struct TransmitClientMessageContext *tcmc = cls;
5257 struct TransportClient *tc;
5260 while ((tc != NULL) && (tc->client != tcmc->client))
5265 transmit_to_peer (tc, NULL, tcmc->priority,
5266 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5268 tcmc->msize, GNUNET_NO, n);
5270 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5271 GNUNET_SERVER_client_drop (tcmc->client);
5277 * Handle SEND-message.
5279 * @param cls closure (always NULL)
5280 * @param client identification of the client
5281 * @param message the actual message
5284 handle_send (void *cls,
5285 struct GNUNET_SERVER_Client *client,
5286 const struct GNUNET_MessageHeader *message)
5288 const struct OutboundMessage *obm;
5289 const struct GNUNET_MessageHeader *obmm;
5290 struct TransmitClientMessageContext *tcmc;
5294 size = ntohs (message->size);
5296 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5299 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5302 GNUNET_STATISTICS_update (stats,
5303 gettext_noop ("# payload received for other peers"),
5306 obm = (const struct OutboundMessage *) message;
5307 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5308 msize = size - sizeof (struct OutboundMessage);
5310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5311 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5312 "SEND", GNUNET_i2s (&obm->peer),
5316 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5317 tcmc->client = client;
5318 tcmc->priority = ntohl (obm->priority);
5319 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5320 tcmc->msize = msize;
5321 /* FIXME: this memcpy can be up to 7% of our total runtime */
5322 memcpy (&tcmc[1], obmm, msize);
5323 GNUNET_SERVER_client_keep (client);
5324 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5325 &transmit_client_message,
5331 * Handle request connect message
5333 * @param cls closure (always NULL)
5334 * @param client identification of the client
5335 * @param message the actual message
5338 handle_request_connect (void *cls,
5339 struct GNUNET_SERVER_Client *client,
5340 const struct GNUNET_MessageHeader *message)
5342 const struct TransportRequestConnectMessage *trcm =
5343 (const struct TransportRequestConnectMessage *) message;
5345 GNUNET_STATISTICS_update (stats,
5346 gettext_noop ("# REQUEST CONNECT messages received"),
5349 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5350 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5352 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5356 * Handle SET_QUOTA-message.
5358 * @param cls closure (always NULL)
5359 * @param client identification of the client
5360 * @param message the actual message
5363 handle_set_quota (void *cls,
5364 struct GNUNET_SERVER_Client *client,
5365 const struct GNUNET_MessageHeader *message)
5367 const struct QuotaSetMessage *qsm =
5368 (const struct QuotaSetMessage *) message;
5369 struct NeighbourList *n;
5371 GNUNET_STATISTICS_update (stats,
5372 gettext_noop ("# SET QUOTA messages received"),
5375 n = find_neighbour (&qsm->peer);
5378 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5379 GNUNET_STATISTICS_update (stats,
5380 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5387 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5389 (unsigned int) ntohl (qsm->quota.value__),
5390 (unsigned int) n->in_tracker.available_bytes_per_s__,
5391 GNUNET_i2s (&qsm->peer));
5393 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5395 if (0 == ntohl (qsm->quota.value__))
5397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5398 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5400 disconnect_neighbour (n, GNUNET_NO);
5402 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5407 * Take the given address and append it to the set of results sent back to
5410 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5411 * @param address the resolved name, NULL to indicate the last response
5414 transmit_address_to_client (void *cls, const char *address)
5416 struct GNUNET_SERVER_TransmitContext *tc = cls;
5419 if (NULL == address)
5422 slen = strlen (address) + 1;
5424 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5425 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5426 if (NULL == address)
5427 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5432 * Handle AddressLookup-message.
5434 * @param cls closure (always NULL)
5435 * @param client identification of the client
5436 * @param message the actual message
5439 handle_address_lookup (void *cls,
5440 struct GNUNET_SERVER_Client *client,
5441 const struct GNUNET_MessageHeader *message)
5443 const struct AddressLookupMessage *alum;
5444 struct TransportPlugin *lsPlugin;
5445 const char *nameTransport;
5446 const char *address;
5448 struct GNUNET_SERVER_TransmitContext *tc;
5449 struct GNUNET_TIME_Absolute timeout;
5450 struct GNUNET_TIME_Relative rtimeout;
5453 size = ntohs (message->size);
5454 if (size < sizeof (struct AddressLookupMessage))
5456 GNUNET_break_op (0);
5457 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5460 alum = (const struct AddressLookupMessage *) message;
5461 uint32_t addressLen = ntohl (alum->addrlen);
5462 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5464 GNUNET_break_op (0);
5465 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5468 address = (const char *) &alum[1];
5469 nameTransport = (const char *) &address[addressLen];
5471 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5473 GNUNET_break_op (0);
5474 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5477 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5478 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5479 numeric = ntohl (alum->numeric_only);
5480 lsPlugin = find_transport (nameTransport);
5481 if (NULL == lsPlugin)
5483 tc = GNUNET_SERVER_transmit_context_create (client);
5484 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5485 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5486 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5489 tc = GNUNET_SERVER_transmit_context_create (client);
5490 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5492 address, addressLen,
5495 &transmit_address_to_client, tc);
5500 * Setup the environment for this plugin.
5503 create_environment (struct TransportPlugin *plug)
5505 plug->env.cfg = cfg;
5506 plug->env.my_identity = &my_identity;
5507 plug->env.our_hello = &our_hello;
5508 plug->env.cls = plug;
5509 plug->env.receive = &plugin_env_receive;
5510 plug->env.notify_address = &plugin_env_notify_address;
5511 plug->env.session_end = &plugin_env_session_end;
5512 plug->env.max_connections = max_connect_per_transport;
5513 plug->env.stats = stats;
5518 * Start the specified transport (load the plugin).
5521 start_transport (struct GNUNET_SERVER_Handle *server,
5524 struct TransportPlugin *plug;
5527 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5528 _("Loading `%s' transport plugin\n"), name);
5529 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5530 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5531 create_environment (plug);
5532 plug->short_name = GNUNET_strdup (name);
5533 plug->lib_name = libname;
5534 plug->next = plugins;
5536 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5537 if (plug->api == NULL)
5539 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5540 _("Failed to load transport plugin for `%s'\n"), name);
5541 GNUNET_free (plug->short_name);
5542 plugins = plug->next;
5543 GNUNET_free (libname);
5550 * Called whenever a client is disconnected. Frees our
5551 * resources associated with that client.
5553 * @param cls closure
5554 * @param client identification of the client
5557 client_disconnect_notification (void *cls,
5558 struct GNUNET_SERVER_Client *client)
5560 struct TransportClient *pos;
5561 struct TransportClient *prev;
5562 struct ClientMessageQueueEntry *mqe;
5563 struct Blacklisters *bl;
5564 struct BlacklistCheck *bc;
5569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5570 "Client disconnected, cleaning up.\n");
5572 /* clean up blacklister */
5576 if (bl->client == client)
5581 if (bc->bl_pos == bl)
5583 bc->bl_pos = bl->next;
5586 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5589 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5590 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5596 GNUNET_CONTAINER_DLL_remove (bl_head,
5599 GNUNET_SERVER_client_drop (bl->client);
5605 /* clean up 'normal' clients */
5608 while ((pos != NULL) && (pos->client != client))
5615 while (NULL != (mqe = pos->message_queue_head))
5617 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5618 pos->message_queue_tail,
5620 pos->message_count--;
5624 clients = pos->next;
5626 prev->next = pos->next;
5627 if (GNUNET_YES == pos->tcs_pending)
5632 if (pos->th != NULL)
5634 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5637 GNUNET_break (0 == pos->message_count);
5643 * Function called when the service shuts down. Unloads our plugins
5644 * and cancels pending validations.
5646 * @param cls closure, unused
5647 * @param tc task context (unused)
5650 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5652 struct TransportPlugin *plug;
5653 struct OwnAddressList *al;
5654 struct CheckHelloValidatedContext *chvc;
5656 while (neighbours != NULL)
5658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5659 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5661 disconnect_neighbour (neighbours, GNUNET_NO);
5664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5665 "Transport service is unloading plugins...\n");
5667 while (NULL != (plug = plugins))
5669 plugins = plug->next;
5670 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5672 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5673 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5675 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5676 GNUNET_free (plug->lib_name);
5677 GNUNET_free (plug->short_name);
5678 while (NULL != (al = plug->addresses))
5680 plug->addresses = al->next;
5685 if (my_private_key != NULL)
5686 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5687 GNUNET_free_non_null (our_hello);
5689 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5692 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5693 validation_map = NULL;
5697 /* free 'chvc' data structure */
5698 while (NULL != (chvc = chvc_head))
5700 chvc_head = chvc->next;
5701 if (chvc->piter != NULL)
5703 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5704 GNUNET_STATISTICS_update (stats,
5705 gettext_noop ("# outstanding peerinfo iterate requests"),
5711 GNUNET_assert (chvc->ve_count == 0);
5718 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5721 if (peerinfo != NULL)
5723 GNUNET_PEERINFO_disconnect (peerinfo);
5726 /* Can we assume those are gone by now, or do we need to clean up
5728 GNUNET_break (bl_head == NULL);
5729 GNUNET_break (bc_head == NULL);
5734 #define DEBUG_ATS GNUNET_NO
5735 #define VERBOSE_ATS GNUNET_NO
5738 /** solve the bandwidth distribution problem
5739 * @param max_it maximum iterations
5740 * @param max_dur maximum duration in ms
5741 * @param D weight for diversity
5742 * @param U weight for utility
5743 * @param R weight for relativity
5744 * @param v_b_min minimal bandwidth per peer
5745 * @param v_n_min minimum number of connections
5746 * @param res result struct
5747 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
5749 static int ats_solve_problem (int max_it, int max_dur , double D, double U, double R, int v_b_min, int v_n_min, struct ATS_result *res)
5752 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5753 return GNUNET_SYSERR;
5755 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
5765 int c_c_ressources = available_ressources;
5766 int c_q_metrics = available_quality_metrics;
5768 //double M = 10000000000; // ~10 GB
5769 //double M = VERY_BIG_DOUBLE_VALUE;
5771 double Q[c_q_metrics+1];
5772 for (c=1; c<=c_q_metrics; c++)
5777 struct NeighbourList *next = neighbours;
5780 struct ReadyList *r_next = next->plugins;
5781 while (r_next != NULL)
5783 struct ForeignAddressList * a_next = r_next->addresses;
5784 while (a_next != NULL)
5787 a_next = a_next->next;
5789 r_next = r_next->next;
5797 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
5801 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
5802 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
5804 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found mechanisms: %i\n", c_mechs);
5810 peers[c_peers].peer = next->id;
5811 peers[c_peers].m_head = NULL;
5812 peers[c_peers].m_tail = NULL;
5814 peers[c_peers].f = 1.0 / c_mechs;
5816 struct ReadyList *r_next = next->plugins;
5817 while (r_next != NULL)
5819 struct ForeignAddressList * a_next = r_next->addresses;
5820 while (a_next != NULL)
5822 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%i Peer: `%s' plugin `%s' %x:\n", c_mechs, GNUNET_i2s(&next->id), r_next->plugin->short_name, a_next);
5823 mechanisms[c_mechs].addr = a_next;
5824 mechanisms[c_mechs].col_index = c_mechs;
5825 mechanisms[c_mechs].peer = &peers[c_peers];
5826 mechanisms[c_mechs].next = NULL;
5827 mechanisms[c_mechs].plugin = r_next->plugin;
5829 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
5831 a_next = a_next->next;
5833 r_next = r_next->next;
5841 if (v_n_min > c_peers)
5844 /* number of variables == coloumns */
5845 //int c_cols = 2 * c_mechs + 3 + c_q_metrics;
5846 /* number of constraints == rows */
5847 //int c_rows = 2 * c_peers + 2 * c_mechs + c_c_ressources + c_q_metrics + 3;
5849 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms, %i resource entries, %i quality metrics \n", c_peers, c_mechs, c_c_ressources, c_q_metrics);
5851 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources + 1000;
5852 //int size = 1 + 8 *c_mechs +2 + c_mechs + c_peers + (c_q_metrics*c_mechs)+c_q_metrics + c_c_ressources ;
5855 int * ia = GNUNET_malloc (size * sizeof (int));
5856 int * ja = GNUNET_malloc (size * sizeof (int));
5857 double * ar = GNUNET_malloc(size* sizeof (double));
5859 prob = glp_create_prob();
5860 glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
5861 glp_set_obj_dir(prob, GLP_MAX);
5863 /* adding columns */
5865 glp_add_cols(prob, 2 * c_mechs);
5866 /* adding b_t cols */
5867 for (c=1; c <= c_mechs; c++)
5869 GNUNET_asprintf(&name, "b%i",c);
5870 glp_set_col_name(prob, c, name);
5872 glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
5873 glp_set_obj_coef(prob, c, 1);
5876 /* adding n_t cols */
5877 for (c=c_mechs+1; c <= 2*c_mechs; c++)
5879 GNUNET_asprintf(&name, "n%i",(c-c_mechs));
5880 glp_set_col_name(prob, c, name);
5882 glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
5883 glp_set_col_kind(prob, c, GLP_IV);
5884 glp_set_obj_coef(prob, c, 0);
5887 /* feasibility constraints */
5888 /* Constraint 1: one address per peer*/
5889 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 1\n");
5891 glp_add_rows(prob, c_peers);
5892 for (c=1; c<=c_peers; c++)
5894 glp_set_row_bnds(prob, row_index, GLP_FX, 1.0, 1.0);
5896 struct ATS_mechanism *m = peers[c].m_head;
5899 ia[array_index] = row_index;
5900 ja[array_index] = (c_mechs + m->col_index);
5901 ar[array_index] = 1;
5902 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5909 /* Constraint 2: only active mechanism gets bandwidth assigned */
5910 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 2\n");
5911 glp_add_rows(prob, c_mechs);
5912 for (c=1; c<=c_mechs; c++)
5914 /* b_t - n_t * M <= 0 */
5915 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5916 glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
5918 ia[array_index] = row_index;
5919 ja[array_index] = mechanisms[c].col_index;
5920 ar[array_index] = 1;
5921 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5923 ia[array_index] = row_index;
5924 ja[array_index] = c_mechs + mechanisms[c].col_index;
5925 ar[array_index] = -M;
5926 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5931 /* Constraint 3: minimum bandwidth*/
5932 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
5933 glp_add_rows(prob, c_mechs);
5934 for (c=1; c<=c_mechs; c++)
5936 /* b_t - n_t * b_min <= 0 */
5937 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5938 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
5940 ia[array_index] = row_index;
5941 ja[array_index] = mechanisms[c].col_index;
5942 ar[array_index] = 1;
5943 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5945 ia[array_index] = row_index;
5946 ja[array_index] = c_mechs + mechanisms[c].col_index;
5947 ar[array_index] = -v_b_min;
5948 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5953 /* Constraint 4: max ressource capacity */
5954 /* V cr: bt * ct_r <= cr_max
5957 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 4\n");
5958 glp_add_rows(prob, available_ressources);
5959 double ct_max = VERY_BIG_DOUBLE_VALUE;
5960 double ct_min = 0.0;
5962 for (c=0; c<available_ressources; c++)
5964 ct_max = ressources[c].c_max;
5965 ct_min = ressources[c].c_min;
5966 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
5967 glp_set_row_bnds(prob, row_index, GLP_DB, ct_min, ct_max);
5969 for (c2=1; c2<=c_mechs; c2++)
5972 ia[array_index] = row_index;
5973 ja[array_index] = c2;
5974 value = mechanisms[c2].addr->ressources[c].c;
5975 ar[array_index] = value;
5976 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5982 /* Constraint 5: min number of connections*/
5983 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n");
5984 glp_add_rows(prob, 1);
5985 for (c=1; c<=c_mechs; c++)
5987 // b_t - n_t * b_min >= 0
5988 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5989 glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
5991 ia[array_index] = row_index;
5992 ja[array_index] = c_mechs + mechanisms[c].col_index;
5993 ar[array_index] = 1;
5994 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5999 /* optimisation constraints*/
6001 /* adding columns */
6002 glp_add_cols(prob, 3 + c_q_metrics);
6004 glp_set_col_name(prob, (2*c_mechs) + 1, "d");
6005 glp_set_obj_coef(prob, (2*c_mechs) + 1, D);
6006 glp_set_col_bnds(prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6007 glp_set_col_name(prob, (2*c_mechs) + 2, "u");
6008 glp_set_obj_coef(prob, (2*c_mechs) + 2, U);
6009 glp_set_col_bnds(prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6010 glp_set_col_name(prob, (2*c_mechs) + 3, "r");
6011 glp_set_obj_coef(prob, (2*c_mechs) + 3, R);
6012 glp_set_col_bnds(prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6014 for (c=1; c<= c_q_metrics; c++)
6016 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6017 glp_set_col_name(prob, (2*c_mechs) + 3 + c, name);
6018 glp_set_col_bnds(prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6020 glp_set_obj_coef(prob, (2*c_mechs) + 3 + c, Q[c]);
6023 // Constraint 6: optimize for diversity
6024 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 6\n");
6025 glp_add_rows(prob, 1);
6026 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6027 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6028 //glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
6029 for (c=1; c<=c_mechs; c++)
6031 // b_t - n_t * b_min >= 0
6032 ia[array_index] = row_index;
6033 ja[array_index] = c_mechs + mechanisms[c].col_index;
6034 ar[array_index] = 1;
6035 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6038 ia[array_index] = row_index;
6039 ja[array_index] = (2*c_mechs) + 1;
6040 ar[array_index] = -1;
6041 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6046 // Constraint 7: optimize for quality
6048 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 7\n");
6049 glp_add_rows(prob, available_quality_metrics);
6050 for (c=1; c <= c_q_metrics; c++)
6052 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6053 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6055 for (c2=1; c2<=c_mechs; c2++)
6058 ia[array_index] = row_index;
6059 ja[array_index] = c2;
6060 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6062 if (mechanisms[c2].addr->latency.rel_value == -1)
6064 if (mechanisms[c2].addr->latency.rel_value == 0)
6067 value = 100 / (double) mechanisms[c2].addr->latency.rel_value;
6069 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DELAY VALUE %f %llu\n",value, mechanisms[c2].addr->latency.rel_value);
6071 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6073 if (mechanisms[c2].addr->distance == -1)
6075 else if (mechanisms[c2].addr->distance == 0)
6077 else value = (double) 10 / mechanisms[c2].addr->distance;
6078 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DISTANCE VALUE %f %lli\n",value, mechanisms[c2].addr->distance);
6080 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6081 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: %s [%i,%i]=%f \n",array_index, qm[c-1].name, ia[array_index], ja[array_index], ar[array_index]);
6085 ia[array_index] = row_index;
6086 ja[array_index] = (2*c_mechs) + 3 +c;
6087 ar[array_index] = -1;
6088 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6093 // Constraint 8: optimize bandwidth utility
6094 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 8\n");
6095 glp_add_rows(prob, 1);
6096 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6097 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6098 for (c=1; c<=c_mechs; c++)
6100 ia[array_index] = row_index;
6101 ja[array_index] = c;
6102 ar[array_index] = mechanisms[c].peer->f;
6103 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6106 ia[array_index] = row_index;
6107 ja[array_index] = (2*c_mechs) + 2;
6108 ar[array_index] = -1;
6110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6116 // Constraint 9: optimize relativity
6117 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 9\n");
6118 glp_add_rows(prob, c_peers);
6119 for (c=1; c<=c_peers; c++)
6121 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6123 struct ATS_mechanism *m = peers[c].m_head;
6126 ia[array_index] = row_index;
6127 ja[array_index] = m->col_index;
6128 ar[array_index] = 1;
6129 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6133 ia[array_index] = row_index;
6134 ja[array_index] = (2*c_mechs) + 3;
6135 ar[array_index] = -1;
6136 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6141 glp_load_matrix(prob, array_index-1, ia, ja, ar);
6144 glp_init_smcp(&opt_lp);
6146 opt_lp.msg_lev = GLP_MSG_ALL;
6148 opt_lp.msg_lev = GLP_MSG_OFF;
6149 result = glp_simplex(prob, &opt_lp);
6152 glp_init_iocp(&opt_mlp);
6153 /* maximum duration */
6154 opt_mlp.tm_lim = max_dur;
6157 opt_mlp.msg_lev = GLP_MSG_ALL;
6159 opt_mlp.msg_lev = GLP_MSG_OFF;
6161 result = glp_intopt (prob, &opt_mlp);
6162 solution = glp_mip_status (prob);
6169 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",c_peers, c_mechs);
6170 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6171 glp_write_lp (prob, NULL, filename);
6172 GNUNET_free (filename);
6180 case GLP_ESTOP : /* search terminated by application */
6181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Search terminated by application ");
6183 case GLP_EITLIM : /* iteration limit exceeded */
6184 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Iteration limit exceeded ");
6187 case GLP_ETMLIM : /* time limit exceeded */
6188 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Time limit exceeded ");
6190 case GLP_ENOPFS : /* no primal feasible solution */
6191 case GLP_ENODFS : /* no dual feasible solution */
6192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No feasible solution");
6195 case GLP_EBADB : /* invalid basis */
6196 case GLP_ESING : /* singular matrix */
6197 case GLP_ECOND : /* ill-conditioned matrix */
6198 case GLP_EBOUND : /* invalid bounds */
6199 case GLP_EFAIL : /* solver failed */
6200 case GLP_EOBJLL : /* objective lower limit reached */
6201 case GLP_EOBJUL : /* objective upper limit reached */
6202 case GLP_EROOT : /* root LP optimum not provided */
6203 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid Input data: %i\n", result);
6208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem has been solved\n");
6214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is undefined\n");
6217 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer optimal\n");
6220 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n");
6223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MI problem has no integer feasible solution\n");
6231 int error = GNUNET_NO;
6233 struct ATS_mechanism *t = NULL;
6234 for (c=1; c<= (c_peers); c++ )
6237 t = peers[c].m_head;
6240 bw = glp_get_col_prim(prob, t->col_index);
6243 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[%i][%i] `%s' %s %s %f\n", c, t->col_index, GNUNET_h2s(&peers[c].peer.hashPubKey), t->plugin->short_name, glp_get_col_name(prob,t->col_index), bw);
6244 if (check ==GNUNET_YES)
6246 glp_write_sol(prob, "invalid_solution.mlp");
6247 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6248 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6251 if (check ==GNUNET_NO)
6258 for (c=1; c<= c_q_metrics; c++ )
6260 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+3+c), glp_get_col_prim(prob,2*c_mechs+3+c));
6262 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+1), glp_get_col_prim(prob,2*c_mechs+1));
6263 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+2), glp_get_col_prim(prob,2*c_mechs+2));
6264 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+3), glp_get_col_prim(prob,2*c_mechs+3));
6266 res->c_mechs = c_mechs;
6267 res->c_peers = c_peers;
6268 res->solution = solution;
6273 glp_delete_prob(prob);
6279 for (c=0; c<c_mechs; c++)
6281 GNUNET_free_non_null (mechanisms[c].rc);
6284 GNUNET_free(mechanisms);
6291 void ats_calculate_bandwidth_distribution ()
6293 static int glpk = GNUNET_YES;
6294 struct GNUNET_TIME_Absolute start;
6295 struct GNUNET_TIME_Relative duration;
6296 struct ATS_result result;
6299 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6300 if (delta.rel_value < ats->min_delta.rel_value)
6303 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6309 if (INT_MAX < ats->max_exec_duration.rel_value)
6312 dur = (int) ats->max_exec_duration.rel_value;
6314 start = GNUNET_TIME_absolute_get();
6316 if (glpk==GNUNET_YES)
6318 start = GNUNET_TIME_absolute_get();
6319 c_mechs = ats_solve_problem(5000, 5000, 1.0, 1.0, 1.0, 1000, 5, &result);
6320 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6324 if (DEBUG_ATS) {GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);}
6325 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6326 GNUNET_STATISTICS_set (stats, "ATS mechanisms", result.c_mechs, GNUNET_NO);
6327 GNUNET_STATISTICS_set (stats, "ATS peers", result.c_peers, GNUNET_NO);
6328 GNUNET_STATISTICS_set (stats, "ATS solution", result.solution, GNUNET_NO);
6329 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6331 else if (c_mechs == 0)
6333 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6335 else glpk = GNUNET_NO;
6337 ats->last = GNUNET_TIME_absolute_get();
6343 ats_schedule_calculation (void *cls,
6344 const struct GNUNET_SCHEDULER_TaskContext *tc)
6346 struct ATS_info *ats = (struct ATS_info *) cls;
6350 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6351 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6355 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6357 ats_calculate_bandwidth_distribution (ats);
6359 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6360 &ats_schedule_calculation, ats);
6365 ats = GNUNET_malloc(sizeof (struct ATS_info));
6367 ats->min_delta = ATS_MIN_INTERVAL;
6368 ats->exec_intervall = ATS_EXEC_INTERVAL;
6369 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6370 ats->max_iterations = ATS_MAX_ITERATIONS;
6371 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6374 unsigned long long value;
6376 /* loading cost ressources */
6377 for (c=0; c<available_ressources; c++)
6379 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6380 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6382 GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value);
6383 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6384 ressources[c].c_max = value;
6386 GNUNET_free (section);
6387 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6388 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6390 GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value);
6391 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6392 ressources[c].c_min = value;
6394 GNUNET_free (section);
6397 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6401 void ats_shutdown ()
6404 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6406 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6407 GNUNET_SCHEDULER_cancel(ats->ats_task);
6408 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6410 struct ATS_plugin * p;
6411 struct ATS_ressource_cost * rc;
6415 GNUNET_CONTAINER_DLL_remove (ats->head,ats->tail, p);
6419 GNUNET_CONTAINER_DLL_remove (p->head,p->tail, rc);
6423 GNUNET_free(p->short_name);
6432 void ats_notify_peer_connect (
6433 const struct GNUNET_PeerIdentity *peer,
6434 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6438 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6441 while (ntohl(ats_data[c].type)!=0)
6444 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6448 ats_calculate_bandwidth_distribution(ats);
6451 void ats_notify_peer_disconnect (
6452 const struct GNUNET_PeerIdentity *peer)
6455 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6457 ats_calculate_bandwidth_distribution (ats);
6461 void ats_notify_ats_data (
6462 const struct GNUNET_PeerIdentity *peer,
6463 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6466 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6468 ats_calculate_bandwidth_distribution(ats);
6471 struct ForeignAddressList * ats_get_preferred_address (
6472 struct NeighbourList *n)
6475 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6477 struct ReadyList *next = n->plugins;
6478 while (next != NULL)
6481 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6485 return find_ready_address(n);
6489 * Initiate transport service.
6491 * @param cls closure
6492 * @param server the initialized server
6493 * @param c configuration to use
6497 struct GNUNET_SERVER_Handle *server,
6498 const struct GNUNET_CONFIGURATION_Handle *c)
6500 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6501 {&handle_start, NULL,
6502 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6503 {&handle_hello, NULL,
6504 GNUNET_MESSAGE_TYPE_HELLO, 0},
6505 {&handle_send, NULL,
6506 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6507 {&handle_request_connect, NULL,
6508 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6509 {&handle_set_quota, NULL,
6510 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6511 {&handle_address_lookup, NULL,
6512 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6514 {&handle_blacklist_init, NULL,
6515 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6516 {&handle_blacklist_reply, NULL,
6517 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6523 unsigned long long tneigh;
6527 stats = GNUNET_STATISTICS_create ("transport", cfg);
6528 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6529 /* parse configuration */
6531 GNUNET_CONFIGURATION_get_value_number (c,
6536 GNUNET_CONFIGURATION_get_value_filename (c,
6538 "HOSTKEY", &keyfile)))
6540 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6542 ("Transport service is lacking key configuration settings. Exiting.\n"));
6543 GNUNET_SCHEDULER_shutdown ();
6546 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6549 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6550 validation_map = NULL;
6554 max_connect_per_transport = (uint32_t) tneigh;
6555 peerinfo = GNUNET_PEERINFO_connect (cfg);
6556 if (peerinfo == NULL)
6558 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6559 _("Could not access PEERINFO service. Exiting.\n"));
6560 GNUNET_SCHEDULER_shutdown ();
6563 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6566 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6567 validation_map = NULL;
6568 GNUNET_free (keyfile);
6571 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6572 GNUNET_free (keyfile);
6573 if (my_private_key == NULL)
6575 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6577 ("Transport service could not access hostkey. Exiting.\n"));
6578 GNUNET_SCHEDULER_shutdown ();
6581 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6584 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6585 validation_map = NULL;
6588 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6589 GNUNET_CRYPTO_hash (&my_public_key,
6590 sizeof (my_public_key), &my_identity.hashPubKey);
6591 /* setup notification */
6592 GNUNET_SERVER_disconnect_notify (server,
6593 &client_disconnect_notification, NULL);
6594 /* load plugins... */
6597 GNUNET_CONFIGURATION_get_value_string (c,
6598 "TRANSPORT", "PLUGINS", &plugs))
6600 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6601 _("Starting transport plugins `%s'\n"), plugs);
6602 pos = strtok (plugs, " ");
6605 start_transport (server, pos);
6607 pos = strtok (NULL, " ");
6609 GNUNET_free (plugs);
6611 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6612 &shutdown_task, NULL);
6619 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6621 /* If we have a blacklist file, read from it */
6622 read_blacklist_file(cfg);
6623 /* process client requests */
6624 GNUNET_SERVER_add_handlers (server, handlers);
6629 * The main function for the transport service.
6631 * @param argc number of arguments from the command line
6632 * @param argv command line arguments
6633 * @return 0 ok, 1 on error
6636 main (int argc, char *const *argv)
6638 a2s (NULL, NULL, 0); /* make compiler happy */
6639 return (GNUNET_OK ==
6640 GNUNET_SERVICE_run (argc,
6643 GNUNET_SERVICE_OPTION_NONE,
6644 &run, NULL)) ? 0 : 1;
6647 /* end of gnunet-service-transport.c */