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
51 #define DEBUG_ATS GNUNET_NO
53 #define VERBOSE_ATS GNUNET_NO
56 * Should we do some additional checks (to validate behavior
59 #define EXTRA_CHECKS GNUNET_YES
62 * How many messages can we have pending for a given client process
63 * before we start to drop incoming messages? We typically should
64 * have only one client and so this would be the primary buffer for
65 * messages, so the number should be chosen rather generously.
67 * The expectation here is that most of the time the queue is large
68 * enough so that a drop is virtually never required. Note that
69 * this value must be about as large as 'TOTAL_MSGS' in the
70 * 'test_transport_api_reliability.c', otherwise that testcase may
73 #define MAX_PENDING (128 * 1024)
76 * Size of the per-transport blacklist hash maps.
78 #define TRANSPORT_BLACKLIST_HT_SIZE 16
81 * How often should we try to reconnect to a peer using a particular
82 * transport plugin before giving up? Note that the plugin may be
83 * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
85 #define MAX_CONNECT_RETRY 3
88 * Limit on the number of ready-to-run tasks when validating
89 * HELLOs. If more tasks are ready to run, we will drop
90 * HELLOs instead of validating them.
92 #define MAX_HELLO_LOAD 4
95 * How often must a peer violate bandwidth quotas before we start
96 * to simply drop its messages?
98 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
101 * How long until a HELLO verification attempt should time out?
102 * Must be rather small, otherwise a partially successful HELLO
103 * validation (some addresses working) might not be available
104 * before a client's request for a connection fails for good.
105 * Besides, if a single request to an address takes a long time,
106 * then the peer is unlikely worthwhile anyway.
108 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
111 * How long is a PONG signature valid? We'll recycle a signature until
112 * 1/4 of this time is remaining. PONGs should expire so that if our
113 * external addresses change an adversary cannot replay them indefinitely.
114 * OTOH, we don't want to spend too much time generating PONG signatures,
115 * so they must have some lifetime to reduce our CPU usage.
117 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
120 * Priority to use for PONG messages.
122 #define TRANSPORT_PONG_PRIORITY 4
125 * How often do we re-add (cheaper) plugins to our list of plugins
126 * to try for a given connected peer?
128 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
131 * After how long do we expire an address in a HELLO that we just
132 * validated? This value is also used for our own addresses when we
135 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
139 * How long before an existing address expires should we again try to
140 * validate it? Must be (significantly) smaller than
141 * HELLO_ADDRESS_EXPIRATION.
143 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
146 * Maximum frequency for re-evaluating latencies for all transport addresses.
148 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
151 * Maximum frequency for re-evaluating latencies for connected addresses.
153 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
155 #define VERY_BIG_DOUBLE_VALUE 100000000000LL
158 * List of addresses of other peers
160 struct ForeignAddressList
163 * This is a linked list.
165 struct ForeignAddressList *next;
168 * Which ready list does this entry belong to.
170 struct ReadyList *ready_list;
173 * How long until we auto-expire this address (unless it is
174 * re-confirmed by the transport)?
176 struct GNUNET_TIME_Absolute expires;
179 * Task used to re-validate addresses, updates latencies and
182 GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
190 * Session (or NULL if no valid session currently exists or if the
191 * plugin does not use sessions).
193 struct Session *session;
195 struct ATS_ressource_entry * ressources;
197 struct ATS_quality_entry * quality;
200 * What was the last latency observed for this address, plugin and peer?
202 struct GNUNET_TIME_Relative latency;
205 * If we did not successfully transmit a message to the given peer
206 * via this connection during the specified time, we should consider
207 * the connection to be dead. This is used in the case that a TCP
208 * transport simply stalls writing to the stream but does not
209 * formerly get a signal that the other peer died.
211 struct GNUNET_TIME_Absolute timeout;
214 * How often have we tried to connect using this plugin? Used to
215 * discriminate against addresses that do not work well.
216 * FIXME: not yet used, but should be!
218 unsigned int connect_attempts;
221 * DV distance to this peer (1 if no DV is used).
222 * FIXME: need to set this from transport plugins!
232 * Have we ever estimated the latency of this address? Used to
233 * ensure that the first time we add an address, we immediately
239 * Are we currently connected via this address? The first time we
240 * successfully transmit or receive data to a peer via a particular
241 * address, we set this to GNUNET_YES. If we later get an error
242 * (disconnect notification, transmission failure, timeout), we set
243 * it back to GNUNET_NO.
248 * Is this plugin currently busy transmitting to the specific target?
249 * GNUNET_NO if not (initial, default state is GNUNET_NO). Internal
250 * messages do not count as 'in transmit'.
255 * Has this address been validated yet?
263 * Entry in linked list of network addresses for ourselves. Also
264 * includes a cached signature for 'struct TransportPongMessage's.
266 struct OwnAddressList
269 * This is a linked list.
271 struct OwnAddressList *next;
274 * How long until we actually auto-expire this address (unless it is
275 * re-confirmed by the transport)?
277 struct GNUNET_TIME_Absolute expires;
280 * How long until the current signature expires? (ZERO if the
281 * signature was never created).
283 struct GNUNET_TIME_Absolute pong_sig_expires;
286 * Signature for a 'struct TransportPongMessage' for this address.
288 struct GNUNET_CRYPTO_RsaSignature pong_signature;
299 * Entry in linked list of all of our plugins.
301 struct TransportPlugin
305 * This is a linked list.
307 struct TransportPlugin *next;
310 * API of the transport as returned by the plugin's
311 * initialization function.
313 struct GNUNET_TRANSPORT_PluginFunctions *api;
316 * Short name for the plugin (i.e. "tcp").
321 * Name of the library (i.e. "gnunet_plugin_transport_tcp").
326 * List of our known addresses for this transport.
328 struct OwnAddressList *addresses;
331 * Environment this transport service is using
334 struct GNUNET_TRANSPORT_PluginEnvironment env;
337 * ID of task that is used to clean up expired addresses.
339 GNUNET_SCHEDULER_TaskIdentifier address_update_task;
342 * Set to GNUNET_YES if we need to scrap the existing list of
343 * "addresses" and start fresh when we receive the next address
344 * update from a transport. Set to GNUNET_NO if we should just add
345 * the new address to the list and wait for the commit call.
349 struct ATS_plugin * rc;
352 * Hashmap of blacklisted peers for this particular transport.
354 struct GNUNET_CONTAINER_MultiHashMap *blacklist;
357 struct NeighbourList;
360 * For each neighbour we keep a list of messages
361 * that we still want to transmit to the neighbour.
367 * This is a doubly linked list.
369 struct MessageQueue *next;
372 * This is a doubly linked list.
374 struct MessageQueue *prev;
377 * The message(s) we want to transmit, GNUNET_MessageHeader(s)
378 * stuck together in memory. Allocated at the end of this struct.
380 const char *message_buf;
383 * Size of the message buf
385 size_t message_buf_size;
388 * Client responsible for queueing the message;
389 * used to check that a client has no two messages
390 * pending for the same target. Can be NULL.
392 struct TransportClient *client;
395 * Using which specific address should we send this message?
397 struct ForeignAddressList *specific_address;
400 * Peer ID of the Neighbour this entry belongs to.
402 struct GNUNET_PeerIdentity neighbour_id;
405 * Plugin that we used for the transmission.
406 * NULL until we scheduled a transmission.
408 struct TransportPlugin *plugin;
411 * At what time should we fail?
413 struct GNUNET_TIME_Absolute timeout;
416 * Internal message of the transport system that should not be
417 * included in the usual SEND-SEND_OK transmission confirmation
418 * traffic management scheme. Typically, "internal_msg" will
419 * be set whenever "client" is NULL (but it is not strictly
425 * How important is the message?
427 unsigned int priority;
433 * For a given Neighbour, which plugins are available
434 * to talk to this peer and what are their costs?
439 * This is a linked list.
441 struct ReadyList *next;
444 * Which of our transport plugins does this entry
447 struct TransportPlugin *plugin;
450 * Transport addresses, latency, and readiness for
451 * this particular plugin.
453 struct ForeignAddressList *addresses;
456 * To which neighbour does this ready list belong to?
458 struct NeighbourList *neighbour;
463 * Entry in linked list of all of our current neighbours.
469 * This is a linked list.
471 struct NeighbourList *next;
474 * Which of our transports is connected to this peer
475 * and what is their status?
477 struct ReadyList *plugins;
480 * Head of list of messages we would like to send to this peer;
481 * must contain at most one message per client.
483 struct MessageQueue *messages_head;
486 * Tail of list of messages we would like to send to this peer; must
487 * contain at most one message per client.
489 struct MessageQueue *messages_tail;
492 * Buffer for at most one payload message used when we receive
493 * payload data before our PING-PONG has succeeded. We then
494 * store such messages in this intermediary buffer until the
495 * connection is fully up.
497 struct GNUNET_MessageHeader *pre_connect_message_buffer;
500 * Context for peerinfo iteration.
501 * NULL after we are done processing peerinfo's information.
503 struct GNUNET_PEERINFO_IteratorContext *piter;
506 * Public key for this peer. Valid only if the respective flag is set below.
508 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
511 * Identity of this neighbour.
513 struct GNUNET_PeerIdentity id;
516 * ID of task scheduled to run when this peer is about to
517 * time out (will free resources associated with the peer).
519 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
522 * ID of task scheduled to run when we should retry transmitting
523 * the head of the message queue. Actually triggered when the
524 * transmission is timing out (we trigger instantly when we have
525 * a chance of success).
527 GNUNET_SCHEDULER_TaskIdentifier retry_task;
530 * How long until we should consider this peer dead
531 * (if we don't receive another message in the
534 struct GNUNET_TIME_Absolute peer_timeout;
537 * Tracker for inbound bandwidth.
539 struct GNUNET_BANDWIDTH_Tracker in_tracker;
542 * The latency we have seen for this particular address for
543 * this particular peer. This latency may have been calculated
544 * over multiple transports. This value reflects how long it took
545 * us to receive a response when SENDING via this particular
546 * transport/neighbour/address combination!
548 * FIXME: we need to periodically send PINGs to update this
549 * latency (at least more often than the current "huge" (11h?)
552 struct GNUNET_TIME_Relative latency;
555 * How often has the other peer (recently) violated the
556 * inbound traffic limit? Incremented by 10 per violation,
557 * decremented by 1 per non-violation (for each
560 unsigned int quota_violation_count;
563 * DV distance to this peer (1 if no DV is used).
568 * Have we seen an PONG from this neighbour in the past (and
569 * not had a disconnect since)?
574 * Do we have a valid public key for this neighbour?
576 int public_key_valid;
579 * Performance data for the peer.
581 struct GNUNET_TRANSPORT_ATS_Information *ats;
584 * Identity of the neighbour.
586 struct GNUNET_PeerIdentity peer;
591 * Message used to ask a peer to validate receipt (to check an address
592 * from a HELLO). Followed by the address we are trying to validate,
593 * or an empty address if we are just sending a PING to confirm that a
594 * connection which the receiver (of the PING) initiated is still valid.
596 struct TransportPingMessage
600 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
602 struct GNUNET_MessageHeader header;
605 * Challenge code (to ensure fresh reply).
607 uint32_t challenge GNUNET_PACKED;
610 * Who is the intended recipient?
612 struct GNUNET_PeerIdentity target;
618 * Message used to validate a HELLO. The challenge is included in the
619 * confirmation to make matching of replies to requests possible. The
620 * signature signs our public key, an expiration time and our address.<p>
622 * This message is followed by our transport address that the PING tried
623 * to confirm (if we liked it). The address can be empty (zero bytes)
624 * if the PING had not address either (and we received the request via
625 * a connection that we initiated).
627 struct TransportPongMessage
631 * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
633 struct GNUNET_MessageHeader header;
636 * Challenge code from PING (showing freshness). Not part of what
637 * is signed so that we can re-use signatures.
639 uint32_t challenge GNUNET_PACKED;
644 struct GNUNET_CRYPTO_RsaSignature signature;
647 * What are we signing and why? Two possible reason codes can be here:
648 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
649 * plausible address for this peer (pid is set to identity of signer); or
650 * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
651 * an address we used to connect to the peer with the given pid.
653 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
656 * When does this signature expire?
658 struct GNUNET_TIME_AbsoluteNBO expiration;
661 * Either the identity of the peer Who signed this message, or the
662 * identity of the peer that we're connected to using the given
663 * address (depending on purpose.type).
665 struct GNUNET_PeerIdentity pid;
668 * Size of address appended to this message (part of what is
669 * being signed, hence not redundant).
677 * Linked list of messages to be transmitted to the client. Each
678 * entry is followed by the actual message.
680 struct ClientMessageQueueEntry
683 * This is a doubly-linked list.
685 struct ClientMessageQueueEntry *next;
688 * This is a doubly-linked list.
690 struct ClientMessageQueueEntry *prev;
695 * Client connected to the transport service.
697 struct TransportClient
701 * This is a linked list.
703 struct TransportClient *next;
706 * Handle to the client.
708 struct GNUNET_SERVER_Client *client;
711 * Linked list of messages yet to be transmitted to
714 struct ClientMessageQueueEntry *message_queue_head;
717 * Tail of linked list of messages yet to be transmitted to the
720 struct ClientMessageQueueEntry *message_queue_tail;
723 * Current transmit request handle.
725 struct GNUNET_CONNECTION_TransmitHandle *th;
728 * Is a call to "transmit_send_continuation" pending? If so, we
729 * must not free this struct (even if the corresponding client
730 * disconnects) and instead only remove it from the linked list and
731 * set the "client" field to NULL.
736 * Length of the list of messages pending for this client.
738 unsigned int message_count;
744 * Context of currently active requests to peerinfo
745 * for validation of HELLOs.
747 struct CheckHelloValidatedContext;
751 * Entry in map of all HELLOs awaiting validation.
753 struct ValidationEntry
757 * NULL if this entry is not part of a larger HELLO validation.
759 struct CheckHelloValidatedContext *chvc;
762 * The address, actually a pointer to the end
763 * of this struct. Do not free!
768 * Name of the transport.
770 char *transport_name;
773 * The public key of the peer.
775 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
778 * ID of task that will clean up this entry if we don't succeed
779 * with the validation first.
781 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
784 * At what time did we send this validation?
786 struct GNUNET_TIME_Absolute send_time;
789 * Session being validated (or NULL for none).
791 struct Session *session;
794 * Challenge number we used.
807 * Context of currently active requests to peerinfo
808 * for validation of HELLOs.
810 struct CheckHelloValidatedContext
814 * This is a doubly-linked list.
816 struct CheckHelloValidatedContext *next;
819 * This is a doubly-linked list.
821 struct CheckHelloValidatedContext *prev;
824 * Hello that we are validating.
826 const struct GNUNET_HELLO_Message *hello;
829 * Context for peerinfo iteration.
830 * NULL after we are done processing peerinfo's information.
832 struct GNUNET_PEERINFO_IteratorContext *piter;
835 * Was a HELLO known for this peer to peerinfo?
840 * Number of validation entries currently referring to this
843 unsigned int ve_count;
846 struct ATS_quality_metric
855 struct ATS_mechanism * prev;
856 struct ATS_mechanism * next;
857 struct ForeignAddressList * addr;
858 struct TransportPlugin * plugin;
859 struct ATS_peer * peer;
862 struct ATS_ressource_cost * rc;
868 struct GNUNET_PeerIdentity peer;
869 struct NeighbourList * n;
870 struct ATS_mechanism * m_head;
871 struct ATS_mechanism * m_tail;
873 /* preference value f */
885 struct ATS_ressource_entry
887 /* index in ressources array */
889 /* depending ATSi parameter to calculcate limits */
898 /* index in ressources array */
900 /* depending ATSi parameter to calculcate limits */
902 /* cfg option to load limits */
909 /* cofficients for the specific plugins */
919 static struct ATS_ressource ressources[] =
921 /* FIXME: the coefficients for the specific plugins */
922 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
923 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
924 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
926 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
927 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
928 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
929 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
932 static int available_ressources = 3;
940 * Time of last execution
942 struct GNUNET_TIME_Absolute last;
944 * Minimum intervall between two executions
946 struct GNUNET_TIME_Relative min_delta;
948 * Regular intervall when execution is triggered
950 struct GNUNET_TIME_Relative exec_intervall;
952 * Maximum execution time per calculation
954 struct GNUNET_TIME_Relative max_exec_duration;
956 * Maximum number of LP iterations per calculation
963 GNUNET_SCHEDULER_TaskIdentifier ats_task;
965 struct ATS_plugin * head;
966 struct ATS_plugin * tail;
973 static struct GNUNET_HELLO_Message *our_hello;
978 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
983 static struct GNUNET_PeerIdentity my_identity;
988 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
993 const struct GNUNET_CONFIGURATION_Handle *cfg;
996 * Linked list of all clients to this service.
998 static struct TransportClient *clients;
1001 * All loaded plugins.
1003 static struct TransportPlugin *plugins;
1006 * Handle to peerinfo service.
1008 static struct GNUNET_PEERINFO_Handle *peerinfo;
1011 * All known neighbours and their HELLOs.
1013 static struct NeighbourList *neighbours;
1016 * Number of neighbours we'd like to have.
1018 static uint32_t max_connect_per_transport;
1021 * Head of linked list.
1023 static struct CheckHelloValidatedContext *chvc_head;
1026 * Tail of linked list.
1028 static struct CheckHelloValidatedContext *chvc_tail;
1031 * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1032 * of the given peer that we are currently validating).
1034 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1037 * Handle for reporting statistics.
1039 static struct GNUNET_STATISTICS_Handle *stats;
1042 * Handle for ats information
1044 static struct ATS_info *ats;
1046 struct ATS_quality_entry
1054 static struct ATS_quality_metric qm[] =
1056 {1, 1028, "QUALITY_NET_DISTANCE"},
1057 {2, 1034, "QUALITY_NET_DELAY"},
1059 static int available_quality_metrics = 2;
1063 * The peer specified by the given neighbour has timed-out or a plugin
1064 * has disconnected. We may either need to do nothing (other plugins
1065 * still up), or trigger a full disconnect and clean up. This
1066 * function updates our state and do the necessary notifications.
1067 * Also notifies our clients that the neighbour is now officially
1070 * @param n the neighbour list entry for the peer
1071 * @param check should we just check if all plugins
1072 * disconnected or must we ask all plugins to
1075 static void disconnect_neighbour (struct NeighbourList *n, int check);
1078 * Check the ready list for the given neighbour and if a plugin is
1079 * ready for transmission (and if we have a message), do so!
1081 * @param nexi target peer for which to transmit
1083 static void try_transmission_to_peer (struct NeighbourList *n);
1088 void ats_shutdown ( );
1090 void ats_notify_peer_connect (
1091 const struct GNUNET_PeerIdentity *peer,
1092 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1094 void ats_notify_peer_disconnect (
1095 const struct GNUNET_PeerIdentity *peer);
1097 void ats_notify_ats_data (
1098 const struct GNUNET_PeerIdentity *peer,
1099 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1101 struct ForeignAddressList * ats_get_preferred_address (
1102 struct NeighbourList *n);
1105 * Find an entry in the neighbour list for a particular peer.
1107 * @return NULL if not found.
1109 static struct NeighbourList *
1110 find_neighbour (const struct GNUNET_PeerIdentity *key)
1112 struct NeighbourList *head = neighbours;
1114 while ((head != NULL) &&
1115 (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1120 static void update_addr_ats (struct ForeignAddressList *fal, const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
1123 for (c1=0; c1<ats_count; c1++)
1125 for (c2=0; c2<available_quality_metrics; c2++)
1127 if (ntohl(ats_data[c1].type) == qm[c2].atis_index)
1129 fal->quality[c2].values[0] = fal->quality[c2].values[1];
1130 fal->quality[c2].values[1] = fal->quality[c2].values[2];
1131 fal->quality[c2].values[2] = ntohl(ats_data[c1].value);
1137 static void update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
1140 for (c=0; c<available_quality_metrics; c++)
1142 if (ats_index == qm[c].atis_index)
1144 fal->quality[c].values[0] = fal->quality[c].values[1];
1145 fal->quality[c].values[1] = fal->quality[c].values[2];
1146 fal->quality[c].values[2] = value;
1152 * Find an entry in the transport list for a particular transport.
1154 * @return NULL if not found.
1156 static struct TransportPlugin *
1157 find_transport (const char *short_name)
1159 struct TransportPlugin *head = plugins;
1160 while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1166 * Is a particular peer blacklisted for a particular transport?
1168 * @param peer the peer to check for
1169 * @param plugin the plugin used to connect to the peer
1171 * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1174 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1177 if (plugin->blacklist != NULL)
1179 if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183 "Peer `%s:%s' is blacklisted!\n",
1184 plugin->short_name, GNUNET_i2s (peer));
1187 GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1197 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1199 struct TransportPlugin *plugin;
1201 plugin = find_transport(transport_name);
1202 if (plugin == NULL) /* Nothing to do */
1204 if (plugin->blacklist == NULL)
1205 plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1206 GNUNET_assert(plugin->blacklist != NULL);
1207 GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1209 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1214 * Read the blacklist file, containing transport:peer entries.
1215 * Provided the transport is loaded, set up hashmap with these
1216 * entries to blacklist peers by transport.
1220 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1227 struct GNUNET_PeerIdentity pid;
1229 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1230 unsigned int entries_found;
1231 char *transport_name;
1234 GNUNET_CONFIGURATION_get_value_filename (cfg,
1240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1241 "Option `%s' in section `%s' not specified!\n",
1247 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1248 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1249 | GNUNET_DISK_PERM_USER_WRITE);
1250 if (0 != STAT (fn, &frstat))
1252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1253 _("Could not read blacklist file `%s'\n"), fn);
1257 if (frstat.st_size == 0)
1260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1261 _("Blacklist file `%s' is empty.\n"),
1267 /* FIXME: use mmap */
1268 data = GNUNET_malloc_large (frstat.st_size);
1269 GNUNET_assert(data != NULL);
1270 if (frstat.st_size !=
1271 GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1274 _("Failed to read blacklist from `%s'\n"), fn);
1281 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1283 while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1284 (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1287 while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1290 if (colon_pos >= frstat.st_size)
1292 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1293 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1294 (unsigned long long) colon_pos);
1300 if (isspace( (unsigned char) data[colon_pos]))
1302 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1303 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1304 (unsigned long long) colon_pos);
1306 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1310 tsize = colon_pos - pos;
1311 if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1313 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1314 _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1315 (unsigned long long) colon_pos);
1324 transport_name = GNUNET_malloc(tsize + 1);
1325 memcpy(transport_name, &data[pos], tsize);
1326 pos = colon_pos + 1;
1328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1329 "Read transport name %s in blacklist file.\n",
1332 memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1333 if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1335 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1336 _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1337 (unsigned long long) pos);
1339 while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1341 GNUNET_free_non_null(transport_name);
1344 enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1345 if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1347 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1348 _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1349 (unsigned long long) pos,
1354 if (0 != memcmp (&pid,
1356 sizeof (struct GNUNET_PeerIdentity)))
1359 add_peer_to_blacklist (&pid,
1364 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1365 _("Found myself `%s' in blacklist (useless, ignored)\n"),
1369 pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1370 GNUNET_free_non_null(transport_name);
1371 while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1374 GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1381 * Function called to notify a client about the socket being ready to
1382 * queue more data. "buf" will be NULL and "size" zero if the socket
1383 * was closed for writing in the meantime.
1385 * @param cls closure
1386 * @param size number of bytes available in buf
1387 * @param buf where the callee should write the message
1388 * @return number of bytes written to buf
1391 transmit_to_client_callback (void *cls, size_t size, void *buf)
1393 struct TransportClient *client = cls;
1394 struct ClientMessageQueueEntry *q;
1397 const struct GNUNET_MessageHeader *msg;
1404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1405 "Transmission to client failed, closing connection.\n");
1407 /* fatal error with client, free message queue! */
1408 while (NULL != (q = client->message_queue_head))
1410 GNUNET_STATISTICS_update (stats,
1411 gettext_noop ("# bytes discarded (could not transmit to client)"),
1412 ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1414 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1415 client->message_queue_tail,
1419 client->message_count = 0;
1424 while (NULL != (q = client->message_queue_head))
1426 msg = (const struct GNUNET_MessageHeader *) &q[1];
1427 msize = ntohs (msg->size);
1428 if (msize + tsize > size)
1431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1432 "Transmitting message of type %u to client.\n",
1435 GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1436 client->message_queue_tail,
1438 memcpy (&cbuf[tsize], msg, msize);
1441 client->message_count--;
1445 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1446 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1448 GNUNET_TIME_UNIT_FOREVER_REL,
1449 &transmit_to_client_callback,
1451 GNUNET_assert (client->th != NULL);
1458 * Convert an address to a string.
1460 * @param plugin name of the plugin responsible for the address
1461 * @param addr binary address
1462 * @param addr_len number of bytes in addr
1463 * @return NULL on error, otherwise address string
1466 a2s (const char *plugin,
1470 struct TransportPlugin *p;
1474 p = find_transport (plugin);
1477 return p->api->address_to_string (p->api->cls,
1484 * Mark the given FAL entry as 'connected' (and hence preferred for
1485 * sending); also mark all others for the same peer as 'not connected'
1486 * (since only one can be preferred).
1488 * @param fal address to set to 'connected'
1491 mark_address_connected (struct ForeignAddressList *fal)
1493 struct ForeignAddressList *pos;
1496 GNUNET_assert (GNUNET_YES == fal->validated);
1497 if (fal->connected == GNUNET_YES)
1498 return; /* nothing to do */
1500 pos = fal->ready_list->addresses;
1503 if (GNUNET_YES == pos->connected)
1506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1507 "Marking address `%s' as no longer connected (due to connect on other address)\n",
1508 a2s (pos->ready_list->plugin->short_name,
1512 GNUNET_break (cnt == GNUNET_YES);
1514 pos->connected = GNUNET_NO;
1515 GNUNET_STATISTICS_update (stats,
1516 gettext_noop ("# connected addresses"),
1522 fal->connected = GNUNET_YES;
1523 if (GNUNET_YES == cnt)
1525 GNUNET_STATISTICS_update (stats,
1526 gettext_noop ("# connected addresses"),
1534 * Send the specified message to the specified client. Since multiple
1535 * messages may be pending for the same client at a time, this code
1536 * makes sure that no message is lost.
1538 * @param client client to transmit the message to
1539 * @param msg the message to send
1540 * @param may_drop can this message be dropped if the
1541 * message queue for this client is getting far too large?
1544 transmit_to_client (struct TransportClient *client,
1545 const struct GNUNET_MessageHeader *msg, int may_drop)
1547 struct ClientMessageQueueEntry *q;
1550 if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1552 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1554 ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1557 client->message_count,
1559 GNUNET_STATISTICS_update (stats,
1560 gettext_noop ("# messages dropped due to slow client"),
1565 msize = ntohs (msg->size);
1566 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1567 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1568 memcpy (&q[1], msg, msize);
1569 GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1570 client->message_queue_tail,
1571 client->message_queue_tail,
1573 client->message_count++;
1574 if (client->th == NULL)
1576 client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1578 GNUNET_TIME_UNIT_FOREVER_REL,
1579 &transmit_to_client_callback,
1581 GNUNET_assert (client->th != NULL);
1587 * Transmit a 'SEND_OK' notification to the given client for the
1590 * @param client who to notify
1591 * @param n neighbour to notify about, can be NULL (on failure)
1592 * @param target target of the transmission
1593 * @param result status code for the transmission request
1596 transmit_send_ok (struct TransportClient *client,
1597 struct NeighbourList *n,
1598 const struct GNUNET_PeerIdentity *target,
1601 struct SendOkMessage send_ok_msg;
1603 send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1604 send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1605 send_ok_msg.success = htonl (result);
1607 send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1609 send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1610 send_ok_msg.peer = *target;
1611 transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1616 * Function called by the GNUNET_TRANSPORT_TransmitFunction
1617 * upon "completion" of a send request. This tells the API
1618 * that it is now legal to send another message to the given
1621 * @param cls closure, identifies the entry on the
1622 * message queue that was transmitted and the
1623 * client responsible for queuing the message
1624 * @param target the peer receiving the message
1625 * @param result GNUNET_OK on success, if the transmission
1626 * failed, we should not tell the client to transmit
1630 transmit_send_continuation (void *cls,
1631 const struct GNUNET_PeerIdentity *target,
1634 struct MessageQueue *mq = cls;
1635 struct NeighbourList *n;
1637 GNUNET_STATISTICS_update (stats,
1638 gettext_noop ("# bytes pending with plugins"),
1639 - (int64_t) mq->message_buf_size,
1641 if (result == GNUNET_OK)
1643 GNUNET_STATISTICS_update (stats,
1644 gettext_noop ("# bytes successfully transmitted by plugins"),
1645 mq->message_buf_size,
1650 GNUNET_STATISTICS_update (stats,
1651 gettext_noop ("# bytes with transmission failure by plugins"),
1652 mq->message_buf_size,
1655 if (mq->specific_address != NULL)
1657 if (result == GNUNET_OK)
1659 mq->specific_address->timeout =
1660 GNUNET_TIME_relative_to_absolute
1661 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1662 if (mq->specific_address->validated == GNUNET_YES)
1663 mark_address_connected (mq->specific_address);
1667 if (mq->specific_address->connected != GNUNET_NO)
1670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671 "Marking address `%s' as no longer connected (due to transmission problem)\n",
1672 a2s (mq->specific_address->ready_list->plugin->short_name,
1673 mq->specific_address->addr,
1674 mq->specific_address->addrlen));
1676 GNUNET_STATISTICS_update (stats,
1677 gettext_noop ("# connected addresses"),
1680 mq->specific_address->connected = GNUNET_NO;
1683 if (! mq->internal_msg)
1684 mq->specific_address->in_transmit = GNUNET_NO;
1686 n = find_neighbour(&mq->neighbour_id);
1687 if (mq->client != NULL)
1688 transmit_send_ok (mq->client, n, target, result);
1691 try_transmission_to_peer (n);
1696 * Find an address in any of the available transports for
1697 * the given neighbour that would be good for message
1698 * transmission. This is essentially the transport selection
1701 * @param neighbour for whom to select an address
1702 * @return selected address, NULL if we have none
1704 struct ForeignAddressList *
1705 find_ready_address(struct NeighbourList *neighbour)
1707 struct ReadyList *head = neighbour->plugins;
1708 struct ForeignAddressList *addresses;
1709 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1710 struct ForeignAddressList *best_address;
1712 /* Hack to prefer unix domain sockets */
1713 struct ForeignAddressList *unix_address = NULL;
1715 best_address = NULL;
1716 while (head != NULL)
1718 addresses = head->addresses;
1719 while (addresses != NULL)
1721 if ( (addresses->timeout.abs_value < now.abs_value) &&
1722 (addresses->connected == GNUNET_YES) )
1725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 "Marking long-time inactive connection to `%4s' as down.\n",
1727 GNUNET_i2s (&neighbour->id));
1729 GNUNET_STATISTICS_update (stats,
1730 gettext_noop ("# connected addresses"),
1733 addresses->connected = GNUNET_NO;
1735 addresses = addresses->next;
1738 addresses = head->addresses;
1739 while (addresses != NULL)
1741 #if DEBUG_TRANSPORT > 1
1742 if (addresses->addr != NULL)
1743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1744 "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1745 a2s (head->plugin->short_name,
1747 addresses->addrlen),
1748 GNUNET_i2s (&neighbour->id),
1749 addresses->connected,
1750 addresses->in_transmit,
1751 addresses->validated,
1752 addresses->connect_attempts,
1753 (unsigned long long) addresses->timeout.abs_value,
1754 (unsigned int) addresses->distance);
1756 if (0==strcmp(head->plugin->short_name,"unix"))
1758 if ((unix_address == NULL) || ((unix_address != NULL) &&
1759 (addresses->latency.rel_value < unix_address->latency.rel_value)))
1760 unix_address = addresses;
1762 if ( ( (best_address == NULL) ||
1763 (addresses->connected == GNUNET_YES) ||
1764 (best_address->connected == GNUNET_NO) ) &&
1765 (addresses->in_transmit == GNUNET_NO) &&
1766 ( (best_address == NULL) ||
1767 (addresses->latency.rel_value < best_address->latency.rel_value)) )
1768 best_address = addresses;
1769 /* FIXME: also give lower-latency addresses that are not
1770 connected a chance some times... */
1771 addresses = addresses->next;
1773 if (unix_address != NULL)
1777 if (unix_address != NULL)
1779 best_address = unix_address;
1781 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1784 if (best_address != NULL)
1788 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1789 "Best address found (`%s') has latency of %llu ms.\n",
1790 (best_address->addrlen > 0)
1791 ? a2s (best_address->ready_list->plugin->short_name,
1793 best_address->addrlen)
1795 best_address->latency.rel_value);
1800 GNUNET_STATISTICS_update (stats,
1801 gettext_noop ("# transmission attempts failed (no address)"),
1806 return best_address;
1812 * We should re-try transmitting to the given peer,
1813 * hopefully we've learned something in the meantime.
1816 retry_transmission_task (void *cls,
1817 const struct GNUNET_SCHEDULER_TaskContext *tc)
1819 struct NeighbourList *n = cls;
1821 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1822 try_transmission_to_peer (n);
1827 * Check the ready list for the given neighbour and if a plugin is
1828 * ready for transmission (and if we have a message), do so!
1830 * @param neighbour target peer for which to transmit
1833 try_transmission_to_peer (struct NeighbourList *n)
1835 struct ReadyList *rl;
1836 struct MessageQueue *mq;
1837 struct GNUNET_TIME_Relative timeout;
1841 if (n->messages_head == NULL)
1844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1845 "Transmission queue for `%4s' is empty\n",
1846 GNUNET_i2s (&n->id));
1848 return; /* nothing to do */
1851 mq = n->messages_head;
1852 force_address = GNUNET_YES;
1853 if (mq->specific_address == NULL)
1856 mq->specific_address = ats_get_preferred_address(n);
1857 GNUNET_STATISTICS_update (stats,
1858 gettext_noop ("# transport selected peer address freely"),
1861 force_address = GNUNET_NO;
1863 if (mq->specific_address == NULL)
1865 GNUNET_STATISTICS_update (stats,
1866 gettext_noop ("# transport failed to selected peer address"),
1869 timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1870 if (timeout.rel_value == 0)
1873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1874 "No destination address available to transmit message of size %u to peer `%4s'\n",
1875 mq->message_buf_size,
1876 GNUNET_i2s (&mq->neighbour_id));
1878 GNUNET_STATISTICS_update (stats,
1879 gettext_noop ("# bytes in message queue for other peers"),
1880 - (int64_t) mq->message_buf_size,
1882 GNUNET_STATISTICS_update (stats,
1883 gettext_noop ("# bytes discarded (no destination address available)"),
1884 mq->message_buf_size,
1886 if (mq->client != NULL)
1887 transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1888 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1892 return; /* nobody ready */
1894 GNUNET_STATISTICS_update (stats,
1895 gettext_noop ("# message delivery deferred (no address)"),
1898 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1899 GNUNET_SCHEDULER_cancel (n->retry_task);
1900 n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1901 &retry_transmission_task,
1904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1905 "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1906 mq->message_buf_size,
1907 GNUNET_i2s (&mq->neighbour_id),
1910 /* FIXME: might want to trigger peerinfo lookup here
1911 (unless that's already pending...) */
1914 GNUNET_CONTAINER_DLL_remove (n->messages_head,
1917 if (mq->specific_address->connected == GNUNET_NO)
1918 mq->specific_address->connect_attempts++;
1919 rl = mq->specific_address->ready_list;
1920 mq->plugin = rl->plugin;
1921 if (!mq->internal_msg)
1922 mq->specific_address->in_transmit = GNUNET_YES;
1924 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1925 "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1926 mq->message_buf_size,
1927 GNUNET_i2s (&n->id),
1928 (mq->specific_address->addr != NULL)
1929 ? a2s (mq->plugin->short_name,
1930 mq->specific_address->addr,
1931 mq->specific_address->addrlen)
1933 rl->plugin->short_name);
1935 GNUNET_STATISTICS_update (stats,
1936 gettext_noop ("# bytes in message queue for other peers"),
1937 - (int64_t) mq->message_buf_size,
1939 GNUNET_STATISTICS_update (stats,
1940 gettext_noop ("# bytes pending with plugins"),
1941 mq->message_buf_size,
1943 ret = rl->plugin->api->send (rl->plugin->api->cls,
1946 mq->message_buf_size,
1948 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1949 mq->specific_address->session,
1950 mq->specific_address->addr,
1951 mq->specific_address->addrlen,
1953 &transmit_send_continuation, mq);
1956 /* failure, but 'send' would not call continuation in this case,
1957 so we need to do it here! */
1958 transmit_send_continuation (mq,
1966 * Send the specified message to the specified peer.
1968 * @param client source of the transmission request (can be NULL)
1969 * @param peer_address ForeignAddressList where we should send this message
1970 * @param priority how important is the message
1971 * @param timeout how long do we have to transmit?
1972 * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1973 * @param message_buf_size total size of all messages in message_buf
1974 * @param is_internal is this an internal message; these are pre-pended and
1975 * also do not count for plugins being "ready" to transmit
1976 * @param neighbour handle to the neighbour for transmission
1979 transmit_to_peer (struct TransportClient *client,
1980 struct ForeignAddressList *peer_address,
1981 unsigned int priority,
1982 struct GNUNET_TIME_Relative timeout,
1983 const char *message_buf,
1984 size_t message_buf_size,
1985 int is_internal, struct NeighbourList *neighbour)
1987 struct MessageQueue *mq;
1992 /* check for duplicate submission */
1993 mq = neighbour->messages_head;
1996 if (mq->client == client)
1998 /* client transmitted to same peer twice
1999 before getting SEND_OK! */
2007 GNUNET_STATISTICS_update (stats,
2008 gettext_noop ("# bytes in message queue for other peers"),
2011 mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
2012 mq->specific_address = peer_address;
2013 mq->client = client;
2014 /* FIXME: this memcpy can be up to 7% of our total runtime! */
2015 memcpy (&mq[1], message_buf, message_buf_size);
2016 mq->message_buf = (const char*) &mq[1];
2017 mq->message_buf_size = message_buf_size;
2018 memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2019 mq->internal_msg = is_internal;
2020 mq->priority = priority;
2021 mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
2023 GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
2024 neighbour->messages_tail,
2027 GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
2028 neighbour->messages_tail,
2029 neighbour->messages_tail,
2031 try_transmission_to_peer (neighbour);
2038 struct GeneratorContext
2040 struct TransportPlugin *plug_pos;
2041 struct OwnAddressList *addr_pos;
2042 struct GNUNET_TIME_Absolute expiration;
2050 address_generator (void *cls, size_t max, void *buf)
2052 struct GeneratorContext *gc = cls;
2055 while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2057 gc->plug_pos = gc->plug_pos->next;
2058 gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2060 if (NULL == gc->plug_pos)
2065 ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2068 gc->addr_pos->addrlen, buf, max);
2069 gc->addr_pos = gc->addr_pos->next;
2075 * Construct our HELLO message from all of the addresses of
2076 * all of the transports.
2081 struct GNUNET_HELLO_Message *hello;
2082 struct TransportClient *cpos;
2083 struct NeighbourList *npos;
2084 struct GeneratorContext gc;
2086 gc.plug_pos = plugins;
2087 gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2088 gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2089 hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2092 "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2094 GNUNET_STATISTICS_update (stats,
2095 gettext_noop ("# refreshed my HELLO"),
2099 while (cpos != NULL)
2101 transmit_to_client (cpos,
2102 (const struct GNUNET_MessageHeader *) hello,
2107 GNUNET_free_non_null (our_hello);
2109 GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2111 while (npos != NULL)
2114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2115 "Transmitting updated `%s' to neighbour `%4s'\n",
2116 "HELLO", GNUNET_i2s (&npos->id));
2118 GNUNET_STATISTICS_update (stats,
2119 gettext_noop ("# transmitted my HELLO to other peers"),
2122 transmit_to_peer (NULL, NULL, 0,
2123 HELLO_ADDRESS_EXPIRATION,
2124 (const char *) our_hello,
2125 GNUNET_HELLO_size(our_hello),
2133 * Task used to clean up expired addresses for a plugin.
2135 * @param cls closure
2139 expire_address_task (void *cls,
2140 const struct GNUNET_SCHEDULER_TaskContext *tc);
2144 * Update the list of addresses for this plugin,
2145 * expiring those that are past their expiration date.
2147 * @param plugin addresses of which plugin should be recomputed?
2148 * @param fresh set to GNUNET_YES if a new address was added
2149 * and we need to regenerate the HELLO even if nobody
2153 update_addresses (struct TransportPlugin *plugin,
2156 static struct GNUNET_TIME_Absolute last_update;
2157 struct GNUNET_TIME_Relative min_remaining;
2158 struct GNUNET_TIME_Relative remaining;
2159 struct GNUNET_TIME_Absolute now;
2160 struct OwnAddressList *pos;
2161 struct OwnAddressList *prev;
2162 struct OwnAddressList *next;
2165 if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2166 GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2167 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2168 now = GNUNET_TIME_absolute_get ();
2169 min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2170 expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2172 pos = plugin->addresses;
2176 if (pos->expires.abs_value < now.abs_value)
2178 expired = GNUNET_YES;
2180 plugin->addresses = pos->next;
2182 prev->next = pos->next;
2187 remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2188 if (remaining.rel_value < min_remaining.rel_value)
2189 min_remaining = remaining;
2195 if (expired || fresh)
2200 min_remaining = GNUNET_TIME_relative_min (min_remaining,
2201 GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2203 plugin->address_update_task
2204 = GNUNET_SCHEDULER_add_delayed (min_remaining,
2205 &expire_address_task, plugin);
2210 * Task used to clean up expired addresses for a plugin.
2212 * @param cls closure
2216 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2218 struct TransportPlugin *plugin = cls;
2220 plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2221 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2222 update_addresses (plugin, GNUNET_NO);
2227 * Iterator over hash map entries that NULLs the session of validation
2228 * entries that match the given session.
2230 * @param cls closure (the 'struct Session*' to match against)
2231 * @param key current key code (peer ID, not used)
2232 * @param value value in the hash map ('struct ValidationEntry*')
2233 * @return GNUNET_YES (we should continue to iterate)
2236 remove_session_validations (void *cls,
2237 const GNUNET_HashCode * key,
2240 struct Session *session = cls;
2241 struct ValidationEntry *ve = value;
2243 if (session == ve->session)
2250 * We've been disconnected from the other peer (for some
2251 * connection-oriented transport). Either quickly
2252 * re-establish the connection or signal the disconnect
2255 * Only signal CORE level disconnect if ALL addresses
2256 * for the peer are exhausted.
2258 * @param p overall plugin context
2259 * @param nl neighbour that was disconnected
2262 try_fast_reconnect (struct TransportPlugin *p,
2263 struct NeighbourList *nl)
2265 /* FIXME-MW: fast reconnect / transport switching not implemented... */
2266 /* Note: the idea here is to hide problems with transports (or
2267 switching between plugins) from the core to eliminate the need to
2268 re-negotiate session keys and the like; OTOH, we should tell core
2269 quickly (much faster than timeout) `if a connection was lost and
2270 could not be re-established (i.e. other peer went down or is
2271 unable / refuses to communicate);
2273 So we should consider:
2274 1) ideally: our own willingness / need to connect
2275 2) prior failures to connect to this peer (by plugin)
2276 3) ideally: reasons why other peer terminated (as far as knowable)
2278 Most importantly, it must be POSSIBLE for another peer to terminate
2279 a connection for a while (without us instantly re-establishing it).
2280 Similarly, if another peer is gone we should quickly notify CORE.
2281 OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2282 on the other end), we should reconnect in such a way that BOTH CORE
2283 services never even notice.
2284 Furthermore, the same mechanism (or small variation) could be used
2285 to switch to a better-performing plugin (ATS).
2287 Finally, this needs to be tested throughly... */
2290 * GNUNET_NO in the call below makes transport disconnect the peer,
2291 * even if only a single address (out of say, six) went away. This
2292 * function must be careful to ONLY disconnect if the peer is gone,
2293 * not just a specifi address.
2295 * More specifically, half the places it was used had it WRONG.
2298 /* No reconnect, signal disconnect instead! */
2299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2300 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2301 "try_fast_reconnect");
2302 disconnect_neighbour (nl, GNUNET_YES);
2307 * Function that will be called whenever the plugin internally
2308 * cleans up a session pointer and hence the service needs to
2309 * discard all of those sessions as well. Plugins that do not
2310 * use sessions can simply omit calling this function and always
2311 * use NULL wherever a session pointer is needed.
2313 * @param cls closure
2314 * @param peer which peer was the session for
2315 * @param session which session is being destoyed
2318 plugin_env_session_end (void *cls,
2319 const struct GNUNET_PeerIdentity *peer,
2320 struct Session *session)
2322 struct TransportPlugin *p = cls;
2323 struct NeighbourList *nl;
2324 struct ReadyList *rl;
2325 struct ForeignAddressList *pos;
2326 struct ForeignAddressList *prev;
2328 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2329 &remove_session_validations,
2331 nl = find_neighbour (peer);
2333 return; /* was never marked as connected */
2337 if (rl->plugin == p)
2342 return; /* was never marked as connected */
2344 pos = rl->addresses;
2345 while ( (pos != NULL) &&
2346 (pos->session != session) )
2352 return; /* was never marked as connected */
2353 pos->session = NULL;
2354 if (pos->addrlen != 0)
2356 if (nl->received_pong != GNUNET_NO)
2357 try_fast_reconnect (p, nl);
2360 /* was inbound connection, free 'pos' */
2362 rl->addresses = pos->next;
2364 prev->next = pos->next;
2365 if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2367 GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2368 pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2371 if (nl->received_pong == GNUNET_NO)
2372 return; /* nothing to do, never connected... */
2373 /* check if we have any validated addresses left */
2374 pos = rl->addresses;
2379 try_fast_reconnect (p, nl);
2384 /* no valid addresses left, signal disconnect! */
2386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2388 "plugin_env_session_end");
2389 /* FIXME: This doesn't mean there are no addresses left for this PEER,
2390 * it means there aren't any left for this PLUGIN/PEER combination! So
2391 * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2392 * when it isn't necessary. Using GNUNET_YES at least checks to see
2393 * if there are any addresses that work first, so as not to overdo it.
2396 disconnect_neighbour (nl, GNUNET_YES);
2401 * Function that must be called by each plugin to notify the
2402 * transport service about the addresses under which the transport
2403 * provided by the plugin can be reached.
2405 * @param cls closure
2406 * @param name name of the transport that generated the address
2407 * @param addr one of the addresses of the host, NULL for the last address
2408 * the specific address format depends on the transport
2409 * @param addrlen length of the address
2410 * @param expires when should this address automatically expire?
2413 plugin_env_notify_address (void *cls,
2417 struct GNUNET_TIME_Relative expires)
2419 struct TransportPlugin *p = cls;
2420 struct OwnAddressList *al;
2421 struct GNUNET_TIME_Absolute abex;
2423 GNUNET_assert (addr != NULL);
2424 abex = GNUNET_TIME_relative_to_absolute (expires);
2425 GNUNET_assert (p == find_transport (name));
2429 if ( (addrlen == al->addrlen) &&
2430 (0 == memcmp (addr, &al[1], addrlen)) )
2433 update_addresses (p, GNUNET_NO);
2438 al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2439 al->next = p->addresses;
2442 al->addrlen = addrlen;
2443 memcpy (&al[1], addr, addrlen);
2444 update_addresses (p, GNUNET_YES);
2449 * Notify all of our clients about a peer connecting.
2452 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2453 struct GNUNET_TIME_Relative latency,
2456 struct ConnectInfoMessage * cim;
2457 struct TransportClient *cpos;
2462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2463 "Notifying clients about connection from `%s'\n",
2466 GNUNET_STATISTICS_update (stats,
2467 gettext_noop ("# peers connected"),
2472 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2473 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2477 cim = GNUNET_malloc (size);
2479 cim->header.size = htons (size);
2480 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2481 cim->ats_count = htonl(2);
2482 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2483 (&(cim->ats))[0].value = htonl (distance);
2484 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2485 (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2486 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2487 (&(cim->ats))[2].value = htonl (0);
2488 memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2490 /* notify ats about connecting peer */
2491 ats_notify_peer_connect (peer, &(cim->ats));
2494 while (cpos != NULL)
2496 transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2505 * Notify all of our clients about a peer disconnecting.
2508 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2510 struct DisconnectInfoMessage dim;
2511 struct TransportClient *cpos;
2514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2515 "Notifying clients about lost connection to `%s'\n",
2518 GNUNET_STATISTICS_update (stats,
2519 gettext_noop ("# peers connected"),
2522 dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2523 dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2524 dim.reserved = htonl (0);
2525 memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2527 /* notify ats about connecting peer */
2528 ats_notify_peer_disconnect (peer);
2531 while (cpos != NULL)
2533 transmit_to_client (cpos, &dim.header, GNUNET_NO);
2540 * Find a ForeignAddressList entry for the given neighbour
2541 * that matches the given address and transport.
2543 * @param neighbour which peer we care about
2544 * @param tname name of the transport plugin
2545 * @param session session to look for, NULL for 'any'; otherwise
2546 * can be used for the service to "learn" this session ID
2548 * @param addr binary address
2549 * @param addrlen length of addr
2550 * @return NULL if no such entry exists
2552 static struct ForeignAddressList *
2553 find_peer_address(struct NeighbourList *neighbour,
2555 struct Session *session,
2559 struct ReadyList *head;
2560 struct ForeignAddressList *pos;
2562 head = neighbour->plugins;
2563 while (head != NULL)
2565 if (0 == strcmp (tname, head->plugin->short_name))
2571 pos = head->addresses;
2572 while ( (pos != NULL) &&
2573 ( (pos->addrlen != addrlen) ||
2574 (memcmp(pos->addr, addr, addrlen) != 0) ) )
2576 if ( (session != NULL) &&
2577 (pos->session == session) )
2581 if ( (session != NULL) && (pos != NULL) )
2582 pos->session = session; /* learn it! */
2588 * Get the peer address struct for the given neighbour and
2589 * address. If it doesn't yet exist, create it.
2591 * @param neighbour which peer we care about
2592 * @param tname name of the transport plugin
2593 * @param session session of the plugin, or NULL for none
2594 * @param addr binary address
2595 * @param addrlen length of addr
2596 * @return NULL if we do not have a transport plugin for 'tname'
2598 static struct ForeignAddressList *
2599 add_peer_address (struct NeighbourList *neighbour,
2601 struct Session *session,
2605 struct ReadyList *head;
2606 struct ForeignAddressList *ret;
2609 ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2612 head = neighbour->plugins;
2614 while (head != NULL)
2616 if (0 == strcmp (tname, head->plugin->short_name))
2622 ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2623 ret->session = session;
2624 if ((addrlen > 0) && (addr != NULL))
2626 ret->addr = (const char*) &ret[1];
2627 memcpy (&ret[1], addr, addrlen);
2634 ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2636 for (c=0; c<available_ressources; c++)
2638 struct ATS_ressource_entry *r = ret->ressources;
2640 r[c].atis_index = ressources[c].atis_index;
2641 if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2643 r[c].c = ressources[c].c_unix;
2646 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2648 r[c].c = ressources[c].c_udp;
2651 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2653 r[c].c = ressources[c].c_tcp;
2656 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2658 r[c].c = ressources[c].c_http;
2661 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2663 r[c].c = ressources[c].c_https;
2666 else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2668 r[c].c = ressources[c].c_wlan;
2674 r[c].c = ressources[c].c_default;
2675 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2676 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2680 ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2681 ret->addrlen = addrlen;
2682 ret->expires = GNUNET_TIME_relative_to_absolute
2683 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2684 ret->latency = GNUNET_TIME_relative_get_forever();
2686 ret->timeout = GNUNET_TIME_relative_to_absolute
2687 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2688 ret->ready_list = head;
2689 ret->next = head->addresses;
2690 head->addresses = ret;
2696 * Closure for 'add_validated_address'.
2698 struct AddValidatedAddressContext
2701 * Entry that has been validated.
2703 const struct ValidationEntry *ve;
2706 * Flag set after we have added the address so
2707 * that we terminate the iteration next time.
2714 * Callback function used to fill a buffer of max bytes with a list of
2715 * addresses in the format used by HELLOs. Should use
2716 * "GNUNET_HELLO_add_address" as a helper function.
2718 * @param cls the 'struct AddValidatedAddressContext' with the validated address
2719 * @param max maximum number of bytes that can be written to buf
2720 * @param buf where to write the address information
2721 * @return number of bytes written, 0 to signal the
2722 * end of the iteration.
2725 add_validated_address (void *cls,
2726 size_t max, void *buf)
2728 struct AddValidatedAddressContext *avac = cls;
2729 const struct ValidationEntry *ve = avac->ve;
2731 if (GNUNET_YES == avac->done)
2733 avac->done = GNUNET_YES;
2734 return GNUNET_HELLO_add_address (ve->transport_name,
2735 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2745 * Closure for 'check_address_exists'.
2747 struct CheckAddressExistsClosure
2750 * Address to check for.
2755 * Name of the transport.
2762 struct Session *session;
2765 * Set to GNUNET_YES if the address exists.
2778 * Iterator over hash map entries. Checks if the given
2779 * validation entry is for the same address as what is given
2782 * @param cls the 'struct CheckAddressExistsClosure*'
2783 * @param key current key code (ignored)
2784 * @param value value in the hash map ('struct ValidationEntry')
2785 * @return GNUNET_YES if we should continue to
2786 * iterate (mismatch), GNUNET_NO if not (entry matched)
2789 check_address_exists (void *cls,
2790 const GNUNET_HashCode * key,
2793 struct CheckAddressExistsClosure *caec = cls;
2794 struct ValidationEntry *ve = value;
2796 if ( (0 == strcmp (caec->tname,
2797 ve->transport_name)) &&
2798 (caec->addrlen == ve->addrlen) &&
2799 (0 == memcmp (caec->addr,
2803 caec->exists = GNUNET_YES;
2806 if ( (ve->session != NULL) &&
2807 (caec->session == ve->session) )
2809 caec->exists = GNUNET_YES;
2818 * Iterator to free entries in the validation_map.
2820 * @param cls closure (unused)
2821 * @param key current key code
2822 * @param value value in the hash map (validation to abort)
2823 * @return GNUNET_YES (always)
2826 abort_validation (void *cls,
2827 const GNUNET_HashCode * key,
2830 struct ValidationEntry *va = value;
2832 if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2833 GNUNET_SCHEDULER_cancel (va->timeout_task);
2834 GNUNET_free (va->transport_name);
2835 if (va->chvc != NULL)
2837 va->chvc->ve_count--;
2838 if (va->chvc->ve_count == 0)
2840 GNUNET_CONTAINER_DLL_remove (chvc_head,
2843 GNUNET_free (va->chvc);
2853 * HELLO validation cleanup task (validation failed).
2855 * @param cls the 'struct ValidationEntry' that failed
2856 * @param tc scheduler context (unused)
2859 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2861 struct ValidationEntry *va = cls;
2862 struct GNUNET_PeerIdentity pid;
2864 va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2865 GNUNET_STATISTICS_update (stats,
2866 gettext_noop ("# address validation timeouts"),
2869 GNUNET_CRYPTO_hash (&va->publicKey,
2871 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2873 GNUNET_break (GNUNET_OK ==
2874 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2877 abort_validation (NULL, NULL, va);
2882 neighbour_timeout_task (void *cls,
2883 const struct GNUNET_SCHEDULER_TaskContext *tc)
2885 struct NeighbourList *n = cls;
2888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2889 "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2891 GNUNET_STATISTICS_update (stats,
2892 gettext_noop ("# disconnects due to timeout"),
2895 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2896 disconnect_neighbour (n, GNUNET_NO);
2901 * Schedule the job that will cause us to send a PING to the
2902 * foreign address to evaluate its validity and latency.
2904 * @param fal address to PING
2907 schedule_next_ping (struct ForeignAddressList *fal);
2911 * Add the given address to the list of foreign addresses
2912 * available for the given peer (check for duplicates).
2914 * @param cls the respective 'struct NeighbourList' to update
2915 * @param tname name of the transport
2916 * @param expiration expiration time
2917 * @param addr the address
2918 * @param addrlen length of the address
2919 * @return GNUNET_OK (always)
2922 add_to_foreign_address_list (void *cls,
2924 struct GNUNET_TIME_Absolute expiration,
2928 struct NeighbourList *n = cls;
2929 struct ForeignAddressList *fal;
2932 GNUNET_STATISTICS_update (stats,
2933 gettext_noop ("# valid peer addresses returned by PEERINFO"),
2937 fal = find_peer_address (n, tname, NULL, addr, addrlen);
2940 #if DEBUG_TRANSPORT_HELLO
2941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2942 "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2943 a2s (tname, addr, addrlen),
2945 GNUNET_i2s (&n->id),
2946 expiration.abs_value);
2948 fal = add_peer_address (n, tname, NULL, addr, addrlen);
2951 GNUNET_STATISTICS_update (stats,
2952 gettext_noop ("# previously validated addresses lacking transport"),
2958 fal->expires = GNUNET_TIME_absolute_max (expiration,
2960 schedule_next_ping (fal);
2966 fal->expires = GNUNET_TIME_absolute_max (expiration,
2971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2972 "Failed to add new address for `%4s'\n",
2973 GNUNET_i2s (&n->id));
2976 if (fal->validated == GNUNET_NO)
2978 fal->validated = GNUNET_YES;
2979 GNUNET_STATISTICS_update (stats,
2980 gettext_noop ("# peer addresses considered valid"),
2984 if (try == GNUNET_YES)
2986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2987 "Have new addresses, will try to trigger transmissions.\n");
2988 try_transmission_to_peer (n);
2995 * Add addresses in validated HELLO "h" to the set of addresses
2996 * we have for this peer.
2998 * @param cls closure ('struct NeighbourList*')
2999 * @param peer id of the peer, NULL for last call
3000 * @param h hello message for the peer (can be NULL)
3001 * @param err_msg NULL if successful, otherwise contains error message
3004 add_hello_for_peer (void *cls,
3005 const struct GNUNET_PeerIdentity *peer,
3006 const struct GNUNET_HELLO_Message *h,
3007 const char *err_msg)
3009 struct NeighbourList *n = cls;
3011 if (err_msg != NULL)
3013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3014 _("Error in communication with PEERINFO service\n"));
3019 GNUNET_STATISTICS_update (stats,
3020 gettext_noop ("# outstanding peerinfo iterate requests"),
3027 return; /* no HELLO available */
3029 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3030 "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3034 if (GNUNET_YES != n->public_key_valid)
3036 GNUNET_HELLO_get_key (h, &n->publicKey);
3037 n->public_key_valid = GNUNET_YES;
3039 GNUNET_HELLO_iterate_addresses (h,
3041 &add_to_foreign_address_list,
3047 * Create a fresh entry in our neighbour list for the given peer.
3048 * Will try to transmit our current HELLO to the new neighbour.
3049 * Do not call this function directly, use 'setup_peer_check_blacklist.
3051 * @param peer the peer for which we create the entry
3052 * @param do_hello should we schedule transmitting a HELLO
3053 * @return the new neighbour list entry
3055 static struct NeighbourList *
3056 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3059 struct NeighbourList *n;
3060 struct TransportPlugin *tp;
3061 struct ReadyList *rl;
3064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3065 "Setting up state for neighbour `%4s'\n",
3068 GNUNET_assert (our_hello != NULL);
3069 GNUNET_STATISTICS_update (stats,
3070 gettext_noop ("# active neighbours"),
3073 n = GNUNET_malloc (sizeof (struct NeighbourList));
3074 n->next = neighbours;
3078 GNUNET_TIME_relative_to_absolute
3079 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3080 GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3081 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3082 MAX_BANDWIDTH_CARRY_S);
3086 if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3088 rl = GNUNET_malloc (sizeof (struct ReadyList));
3090 rl->next = n->plugins;
3093 rl->addresses = NULL;
3097 n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3099 n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3100 &neighbour_timeout_task, n);
3103 GNUNET_STATISTICS_update (stats,
3104 gettext_noop ("# peerinfo new neighbor iterate requests"),
3107 GNUNET_STATISTICS_update (stats,
3108 gettext_noop ("# outstanding peerinfo iterate requests"),
3111 n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3112 GNUNET_TIME_UNIT_FOREVER_REL,
3113 &add_hello_for_peer, n);
3115 GNUNET_STATISTICS_update (stats,
3116 gettext_noop ("# HELLO's sent to new neighbors"),
3119 transmit_to_peer (NULL, NULL, 0,
3120 HELLO_ADDRESS_EXPIRATION,
3121 (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3129 * Function called after we have checked if communicating
3130 * with a given peer is acceptable.
3132 * @param cls closure
3133 * @param n NULL if communication is not acceptable
3135 typedef void (*SetupContinuation)(void *cls,
3136 struct NeighbourList *n);
3140 * Information kept for each client registered to perform
3146 * This is a linked list.
3148 struct Blacklisters *next;
3151 * This is a linked list.
3153 struct Blacklisters *prev;
3156 * Client responsible for this entry.
3158 struct GNUNET_SERVER_Client *client;
3161 * Blacklist check that we're currently performing.
3163 struct BlacklistCheck *bc;
3169 * Head of DLL of blacklisting clients.
3171 static struct Blacklisters *bl_head;
3174 * Tail of DLL of blacklisting clients.
3176 static struct Blacklisters *bl_tail;
3180 * Context we use when performing a blacklist check.
3182 struct BlacklistCheck
3186 * This is a linked list.
3188 struct BlacklistCheck *next;
3191 * This is a linked list.
3193 struct BlacklistCheck *prev;
3196 * Peer being checked.
3198 struct GNUNET_PeerIdentity peer;
3201 * Option for setup neighbour afterwards.
3206 * Continuation to call with the result.
3208 SetupContinuation cont;
3216 * Current transmission request handle for this client, or NULL if no
3217 * request is pending.
3219 struct GNUNET_CONNECTION_TransmitHandle *th;
3222 * Our current position in the blacklisters list.
3224 struct Blacklisters *bl_pos;
3227 * Current task performing the check.
3229 GNUNET_SCHEDULER_TaskIdentifier task;
3234 * Head of DLL of active blacklisting queries.
3236 static struct BlacklistCheck *bc_head;
3239 * Tail of DLL of active blacklisting queries.
3241 static struct BlacklistCheck *bc_tail;
3245 * Perform next action in the blacklist check.
3247 * @param cls the 'struct BlacklistCheck*'
3251 do_blacklist_check (void *cls,
3252 const struct GNUNET_SCHEDULER_TaskContext *tc);
3255 * Transmit blacklist query to the client.
3257 * @param cls the 'struct BlacklistCheck'
3258 * @param size number of bytes allowed
3259 * @param buf where to copy the message
3260 * @return number of bytes copied to buf
3263 transmit_blacklist_message (void *cls,
3267 struct BlacklistCheck *bc = cls;
3268 struct Blacklisters *bl;
3269 struct BlacklistMessage bm;
3274 GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3275 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3280 bm.header.size = htons (sizeof (struct BlacklistMessage));
3281 bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3282 bm.is_allowed = htonl (0);
3284 memcpy (buf, &bm, sizeof (bm));
3285 GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3291 * Perform next action in the blacklist check.
3293 * @param cls the 'struct BlacklistCheck*'
3297 do_blacklist_check (void *cls,
3298 const struct GNUNET_SCHEDULER_TaskContext *tc)
3300 struct BlacklistCheck *bc = cls;
3301 struct Blacklisters *bl;
3303 bc->task = GNUNET_SCHEDULER_NO_TASK;
3307 bc->cont (bc->cont_cls,
3308 setup_new_neighbour (&bc->peer, bc->do_hello));
3315 bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3316 sizeof (struct BlacklistMessage),
3317 GNUNET_TIME_UNIT_FOREVER_REL,
3318 &transmit_blacklist_message,
3325 * Obtain a 'struct NeighbourList' for the given peer. If such an entry
3326 * does not yet exist, check the blacklist. If the blacklist says creating
3327 * one is acceptable, create one and call the continuation; otherwise
3328 * call the continuation with NULL.
3330 * @param peer peer to setup or look up a struct NeighbourList for
3331 * @param do_hello should we also schedule sending our HELLO to the peer
3332 * if this is a new record
3333 * @param cont function to call with the 'struct NeigbhbourList*'
3334 * @param cont_cls closure for cont
3337 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3339 SetupContinuation cont,
3342 struct NeighbourList *n;
3343 struct BlacklistCheck *bc;
3345 n = find_neighbour(peer);
3352 if (bl_head == NULL)
3355 cont (cont_cls, setup_new_neighbour (peer, do_hello));
3357 setup_new_neighbour(peer, do_hello);
3360 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3361 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3363 bc->do_hello = do_hello;
3365 bc->cont_cls = cont_cls;
3366 bc->bl_pos = bl_head;
3367 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3373 * Function called with the result of querying a new blacklister about
3374 * it being allowed (or not) to continue to talk to an existing neighbour.
3376 * @param cls the original 'struct NeighbourList'
3377 * @param n NULL if we need to disconnect
3380 confirm_or_drop_neighbour (void *cls,
3381 struct NeighbourList *n)
3383 struct NeighbourList * orig = cls;
3387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3388 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3389 "confirm_or_drop_neighboUr");
3390 disconnect_neighbour (orig, GNUNET_NO);
3396 * Handle a request to start a blacklist.
3398 * @param cls closure (always NULL)
3399 * @param client identification of the client
3400 * @param message the actual message
3403 handle_blacklist_init (void *cls,
3404 struct GNUNET_SERVER_Client *client,
3405 const struct GNUNET_MessageHeader *message)
3407 struct Blacklisters *bl;
3408 struct BlacklistCheck *bc;
3409 struct NeighbourList *n;
3414 if (bl->client == client)
3417 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3422 bl = GNUNET_malloc (sizeof (struct Blacklisters));
3423 bl->client = client;
3424 GNUNET_SERVER_client_keep (client);
3425 GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3426 /* confirm that all existing connections are OK! */
3430 bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3431 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3433 bc->do_hello = GNUNET_NO;
3434 bc->cont = &confirm_or_drop_neighbour;
3437 if (n == neighbours) /* all would wait for the same client, no need to
3438 create more than just the first task right now */
3439 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3447 * Handle a request to blacklist a peer.
3449 * @param cls closure (always NULL)
3450 * @param client identification of the client
3451 * @param message the actual message
3454 handle_blacklist_reply (void *cls,
3455 struct GNUNET_SERVER_Client *client,
3456 const struct GNUNET_MessageHeader *message)
3458 const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3459 struct Blacklisters *bl;
3460 struct BlacklistCheck *bc;
3463 while ( (bl != NULL) &&
3464 (bl->client != client) )
3468 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3473 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3475 bc->cont (bc->cont_cls, NULL);
3476 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3481 bc->bl_pos = bc->bl_pos->next;
3482 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3485 /* check if any other bc's are waiting for this blacklister */
3489 if ( (bc->bl_pos == bl) &&
3490 (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3491 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3499 * Send periodic PING messages to a given foreign address.
3501 * @param cls our 'struct PeriodicValidationContext*'
3502 * @param tc task context
3505 send_periodic_ping (void *cls,
3506 const struct GNUNET_SCHEDULER_TaskContext *tc)
3508 struct ForeignAddressList *peer_address = cls;
3509 struct TransportPlugin *tp;
3510 struct ValidationEntry *va;
3511 struct NeighbourList *neighbour;
3512 struct TransportPingMessage ping;
3513 struct CheckAddressExistsClosure caec;
3515 uint16_t hello_size;
3519 peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3520 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3522 tp = peer_address->ready_list->plugin;
3523 neighbour = peer_address->ready_list->neighbour;
3524 if (GNUNET_YES != neighbour->public_key_valid)
3526 /* no public key yet, try again later */
3527 schedule_next_ping (peer_address);
3530 caec.addr = peer_address->addr;
3531 caec.addrlen = peer_address->addrlen;
3532 caec.tname = tp->short_name;
3533 caec.session = peer_address->session;
3534 caec.exists = GNUNET_NO;
3535 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3536 &check_address_exists,
3538 if (caec.exists == GNUNET_YES)
3540 /* During validation attempts we will likely trigger the other
3541 peer trying to validate our address which in turn will cause
3542 it to send us its HELLO, so we expect to hit this case rather
3543 frequently. Only print something if we are very verbose. */
3544 #if DEBUG_TRANSPORT > 1
3545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3546 "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3547 (peer_address->addr != NULL)
3548 ? a2s (tp->short_name,
3550 peer_address->addrlen)
3553 GNUNET_i2s (&neighbour->id));
3555 schedule_next_ping (peer_address);
3558 va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3559 va->transport_name = GNUNET_strdup (tp->short_name);
3560 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3562 va->send_time = GNUNET_TIME_absolute_get();
3563 va->session = peer_address->session;
3564 if (peer_address->addr != NULL)
3566 va->addr = (const void*) &va[1];
3567 memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3568 va->addrlen = peer_address->addrlen;
3570 memcpy(&va->publicKey,
3571 &neighbour->publicKey,
3572 sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3574 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3575 &timeout_hello_validation,
3577 GNUNET_CONTAINER_multihashmap_put (validation_map,
3578 &neighbour->id.hashPubKey,
3580 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3582 if (peer_address->validated != GNUNET_YES)
3583 hello_size = GNUNET_HELLO_size(our_hello);
3587 tsize = sizeof(struct TransportPingMessage) + hello_size;
3589 if (peer_address->addr != NULL)
3591 slen = strlen (tp->short_name) + 1;
3592 tsize += slen + peer_address->addrlen;
3596 slen = 0; /* make gcc happy */
3598 message_buf = GNUNET_malloc(tsize);
3599 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3600 ping.challenge = htonl(va->challenge);
3601 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3602 if (peer_address->validated != GNUNET_YES)
3604 memcpy(message_buf, our_hello, hello_size);
3607 if (peer_address->addr != NULL)
3609 ping.header.size = htons(sizeof(struct TransportPingMessage) +
3610 peer_address->addrlen +
3612 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3615 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3617 peer_address->addrlen);
3621 ping.header.size = htons(sizeof(struct TransportPingMessage));
3624 memcpy(&message_buf[hello_size],
3626 sizeof(struct TransportPingMessage));
3628 #if DEBUG_TRANSPORT_REVALIDATION
3629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3630 "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3631 (peer_address->addr != NULL)
3632 ? a2s (peer_address->plugin->short_name,
3634 peer_address->addrlen)
3637 GNUNET_i2s (&neighbour->id),
3638 "HELLO", hello_size,
3641 if (peer_address->validated != GNUNET_YES)
3642 GNUNET_STATISTICS_update (stats,
3643 gettext_noop ("# PING with HELLO messages sent"),
3647 GNUNET_STATISTICS_update (stats,
3648 gettext_noop ("# PING without HELLO messages sent"),
3651 GNUNET_STATISTICS_update (stats,
3652 gettext_noop ("# PING messages sent for re-validation"),
3655 transmit_to_peer (NULL, peer_address,
3656 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3657 HELLO_VERIFICATION_TIMEOUT,
3659 GNUNET_YES, neighbour);
3660 GNUNET_free(message_buf);
3661 schedule_next_ping (peer_address);
3666 * Schedule the job that will cause us to send a PING to the
3667 * foreign address to evaluate its validity and latency.
3669 * @param fal address to PING
3672 schedule_next_ping (struct ForeignAddressList *fal)
3674 struct GNUNET_TIME_Relative delay;
3676 if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3678 delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3679 delay.rel_value /= 2; /* do before expiration */
3680 delay = GNUNET_TIME_relative_min (delay,
3681 LATENCY_EVALUATION_MAX_DELAY);
3682 if (GNUNET_YES != fal->estimated)
3684 delay = GNUNET_TIME_UNIT_ZERO;
3685 fal->estimated = GNUNET_YES;
3687 if (GNUNET_YES == fal->connected)
3689 delay = GNUNET_TIME_relative_min (delay,
3690 CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3692 /* FIXME: also adjust delay based on how close the last
3693 observed latency is to the latency of the best alternative */
3694 /* bound how fast we can go */
3695 delay = GNUNET_TIME_relative_max (delay,
3696 GNUNET_TIME_UNIT_SECONDS);
3697 /* randomize a bit (to avoid doing all at the same time) */
3698 delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3699 fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3700 &send_periodic_ping,
3708 * Function that will be called if we receive some payload
3709 * from another peer.
3711 * @param message the payload
3712 * @param n peer who claimed to be the sender
3715 handle_payload_message (const struct GNUNET_MessageHeader *message,
3716 struct NeighbourList *n)
3718 struct InboundMessage *im;
3719 struct TransportClient *cpos;
3722 msize = ntohs (message->size);
3723 if (n->received_pong == GNUNET_NO)
3725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3726 "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3727 ntohs (message->type),
3728 ntohs (message->size),
3729 GNUNET_i2s (&n->id));
3730 GNUNET_free_non_null (n->pre_connect_message_buffer);
3731 n->pre_connect_message_buffer = GNUNET_malloc (msize);
3732 memcpy (n->pre_connect_message_buffer, message, msize);
3737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3738 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3739 ntohs (message->type),
3740 ntohs (message->size),
3741 GNUNET_i2s (&n->id));
3743 if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3746 n->quota_violation_count++;
3748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3749 "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3750 n->in_tracker.available_bytes_per_s__,
3751 n->quota_violation_count);
3753 /* Discount 32k per violation */
3754 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3759 if (n->quota_violation_count > 0)
3761 /* try to add 32k back */
3762 GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3764 n->quota_violation_count--;
3767 GNUNET_STATISTICS_update (stats,
3768 gettext_noop ("# payload received from other peers"),
3771 /* transmit message to all clients */
3772 uint32_t ats_count = 2;
3773 size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3774 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3777 im = GNUNET_malloc (size);
3778 im->header.size = htons (size);
3779 im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3781 im->ats_count = htonl(ats_count);
3782 /* Setting ATS data */
3783 (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3784 (&(im->ats))[0].value = htonl (n->distance);
3785 (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3786 (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3787 (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3788 (&(im->ats))[ats_count].value = htonl (0);
3790 memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3792 while (cpos != NULL)
3794 transmit_to_client (cpos, &im->header, GNUNET_YES);
3802 * Iterator over hash map entries. Checks if the given validation
3803 * entry is for the same challenge as what is given in the PONG.
3805 * @param cls the 'struct TransportPongMessage*'
3806 * @param key peer identity
3807 * @param value value in the hash map ('struct ValidationEntry')
3808 * @return GNUNET_YES if we should continue to
3809 * iterate (mismatch), GNUNET_NO if not (entry matched)
3812 check_pending_validation (void *cls,
3813 const GNUNET_HashCode * key,
3816 const struct TransportPongMessage *pong = cls;
3817 struct ValidationEntry *ve = value;
3818 struct AddValidatedAddressContext avac;
3819 unsigned int challenge = ntohl(pong->challenge);
3820 struct GNUNET_HELLO_Message *hello;
3821 struct GNUNET_PeerIdentity target;
3822 struct NeighbourList *n;
3823 struct ForeignAddressList *fal;
3824 struct OwnAddressList *oal;
3825 struct TransportPlugin *tp;
3826 struct GNUNET_MessageHeader *prem;
3832 ps = ntohs (pong->header.size);
3833 if (ps < sizeof (struct TransportPongMessage))
3835 GNUNET_break_op (0);
3838 addr = (const char*) &pong[1];
3839 slen = strlen (ve->transport_name) + 1;
3840 if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3841 (ve->challenge != challenge) ||
3842 (addr[slen-1] != '\0') ||
3843 (0 != strcmp (addr, ve->transport_name)) ||
3844 (ntohl (pong->purpose.size)
3845 != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3847 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3848 sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3853 alen = ps - sizeof (struct TransportPongMessage) - slen;
3854 switch (ntohl (pong->purpose.purpose))
3856 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3857 if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3858 (0 != memcmp (&addr[slen],
3862 return GNUNET_YES; /* different entry, keep trying! */
3864 if (0 != memcmp (&pong->pid,
3866 sizeof (struct GNUNET_PeerIdentity)))
3868 GNUNET_break_op (0);
3872 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3877 GNUNET_break_op (0);
3882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3883 "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3885 a2s (ve->transport_name,
3886 (const struct sockaddr *) ve->addr,
3888 ve->transport_name);
3891 case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3892 if (0 != memcmp (&pong->pid,
3894 sizeof (struct GNUNET_PeerIdentity)))
3896 GNUNET_break_op (0);
3899 if (ve->addrlen != 0)
3901 /* must have been for a different validation entry */
3904 tp = find_transport (ve->transport_name);
3910 oal = tp->addresses;
3913 if ( (oal->addrlen == alen) &&
3914 (0 == memcmp (&oal[1],
3922 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3923 _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3924 a2s (ve->transport_name,
3930 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3935 GNUNET_break_op (0);
3940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3941 "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3943 a2s (ve->transport_name,
3946 ve->transport_name);
3950 GNUNET_break_op (0);
3953 if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3955 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3956 _("Received expired signature. Check system time.\n"));
3959 GNUNET_STATISTICS_update (stats,
3960 gettext_noop ("# address validation successes"),
3963 /* create the updated HELLO */
3964 GNUNET_CRYPTO_hash (&ve->publicKey,
3965 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3966 &target.hashPubKey);
3967 if (ve->addr != NULL)
3969 avac.done = GNUNET_NO;
3971 hello = GNUNET_HELLO_create (&ve->publicKey,
3972 &add_validated_address,
3974 GNUNET_PEERINFO_add_peer (peerinfo,
3976 GNUNET_free (hello);
3978 n = find_neighbour (&target);
3981 n->publicKey = ve->publicKey;
3982 n->public_key_valid = GNUNET_YES;
3983 fal = add_peer_address (n,
3988 GNUNET_assert (fal != NULL);
3989 fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3990 fal->validated = GNUNET_YES;
3991 mark_address_connected (fal);
3992 GNUNET_STATISTICS_update (stats,
3993 gettext_noop ("# peer addresses considered valid"),
3996 fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3997 update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3999 schedule_next_ping (fal);
4000 if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4001 n->latency = fal->latency;
4003 n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4005 n->distance = fal->distance;
4006 if (GNUNET_NO == n->received_pong)
4008 n->received_pong = GNUNET_YES;
4010 notify_clients_connect (&target, n->latency, n->distance);
4011 if (NULL != (prem = n->pre_connect_message_buffer))
4013 n->pre_connect_message_buffer = NULL;
4014 handle_payload_message (prem, n);
4018 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4020 GNUNET_SCHEDULER_cancel (n->retry_task);
4021 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4022 try_transmission_to_peer (n);
4026 /* clean up validation entry */
4027 GNUNET_assert (GNUNET_YES ==
4028 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4031 abort_validation (NULL, NULL, ve);
4037 * Function that will be called if we receive a validation
4038 * of an address challenge that we transmitted to another
4039 * peer. Note that the validation should only be considered
4040 * acceptable if the challenge matches AND if the sender
4041 * address is at least a plausible address for this peer
4042 * (otherwise we may be seeing a MiM attack).
4044 * @param cls closure
4045 * @param message the pong message
4046 * @param peer who responded to our challenge
4047 * @param sender_address string describing our sender address (as observed
4048 * by the other peer in binary format)
4049 * @param sender_address_len number of bytes in 'sender_address'
4052 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4053 const struct GNUNET_PeerIdentity *peer,
4054 const char *sender_address,
4055 size_t sender_address_len)
4057 #if DEBUG_TRANSPORT > 1
4058 /* we get tons of these that just get discarded, only log
4059 if we are quite verbose */
4060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4061 "Receiving `%s' message from `%4s'.\n", "PONG",
4064 GNUNET_STATISTICS_update (stats,
4065 gettext_noop ("# PONG messages received"),
4068 if (GNUNET_SYSERR !=
4069 GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4071 &check_pending_validation,
4074 /* This is *expected* to happen a lot since we send
4075 PONGs to *all* known addresses of the sender of
4076 the PING, so most likely we get multiple PONGs
4077 per PING, and all but the first PONG will end up
4078 here. So really we should not print anything here
4079 unless we want to be very, very verbose... */
4080 #if DEBUG_TRANSPORT > 2
4081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4082 "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4094 * Try to validate a neighbour's address by sending him our HELLO and a PING.
4096 * @param cls the 'struct ValidationEntry*'
4097 * @param neighbour neighbour to validate, NULL if validation failed
4100 transmit_hello_and_ping (void *cls,
4101 struct NeighbourList *neighbour)
4103 struct ValidationEntry *va = cls;
4104 struct ForeignAddressList *peer_address;
4105 struct TransportPingMessage ping;
4106 uint16_t hello_size;
4109 struct GNUNET_PeerIdentity id;
4112 GNUNET_CRYPTO_hash (&va->publicKey,
4113 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4115 if (neighbour == NULL)
4117 /* FIXME: stats... */
4118 GNUNET_break (GNUNET_OK ==
4119 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4122 abort_validation (NULL, NULL, va);
4125 neighbour->publicKey = va->publicKey;
4126 neighbour->public_key_valid = GNUNET_YES;
4127 peer_address = add_peer_address (neighbour,
4128 va->transport_name, NULL,
4129 (const void*) &va[1],
4131 if (peer_address == NULL)
4133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4134 "Failed to add peer `%4s' for plugin `%s'\n",
4135 GNUNET_i2s (&neighbour->id),
4136 va->transport_name);
4137 GNUNET_break (GNUNET_OK ==
4138 GNUNET_CONTAINER_multihashmap_remove (validation_map,
4141 abort_validation (NULL, NULL, va);
4144 hello_size = GNUNET_HELLO_size(our_hello);
4145 slen = strlen(va->transport_name) + 1;
4146 tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4147 message_buf = GNUNET_malloc(tsize);
4148 ping.challenge = htonl(va->challenge);
4149 ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4150 ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4151 memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4152 memcpy(message_buf, our_hello, hello_size);
4153 memcpy(&message_buf[hello_size],
4155 sizeof(struct TransportPingMessage));
4156 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4159 memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4164 "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4167 : a2s (va->transport_name,
4168 (const void*) &va[1], va->addrlen),
4170 GNUNET_i2s (&neighbour->id),
4171 "HELLO", hello_size,
4172 "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4175 GNUNET_STATISTICS_update (stats,
4176 gettext_noop ("# PING messages sent for initial validation"),
4179 transmit_to_peer (NULL, peer_address,
4180 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4181 HELLO_VERIFICATION_TIMEOUT,
4183 GNUNET_YES, neighbour);
4184 GNUNET_free(message_buf);
4189 * Check if the given address is already being validated; if not,
4190 * append the given address to the list of entries that are being be
4191 * validated and initiate validation.
4193 * @param cls closure ('struct CheckHelloValidatedContext *')
4194 * @param tname name of the transport
4195 * @param expiration expiration time
4196 * @param addr the address
4197 * @param addrlen length of the address
4198 * @return GNUNET_OK (always)
4201 run_validation (void *cls,
4203 struct GNUNET_TIME_Absolute expiration,
4207 struct CheckHelloValidatedContext *chvc = cls;
4208 struct GNUNET_PeerIdentity id;
4209 struct TransportPlugin *tp;
4210 struct ValidationEntry *va;
4211 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4212 struct CheckAddressExistsClosure caec;
4213 struct OwnAddressList *oal;
4215 GNUNET_assert (addr != NULL);
4217 GNUNET_STATISTICS_update (stats,
4218 gettext_noop ("# peer addresses scheduled for validation"),
4221 tp = find_transport (tname);
4224 GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4225 GNUNET_ERROR_TYPE_BULK,
4227 ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4229 GNUNET_STATISTICS_update (stats,
4230 gettext_noop ("# peer addresses not validated (plugin not available)"),
4235 /* check if this is one of our own addresses */
4236 oal = tp->addresses;
4239 if ( (oal->addrlen == addrlen) &&
4240 (0 == memcmp (&oal[1],
4244 /* not plausible, this address is equivalent to our own address! */
4245 GNUNET_STATISTICS_update (stats,
4246 gettext_noop ("# peer addresses not validated (loopback)"),
4253 GNUNET_HELLO_get_key (chvc->hello, &pk);
4254 GNUNET_CRYPTO_hash (&pk,
4256 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4259 if (is_blacklisted(&id, tp))
4262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4263 "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4271 caec.addrlen = addrlen;
4272 caec.session = NULL;
4274 caec.exists = GNUNET_NO;
4275 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4276 &check_address_exists,
4278 if (caec.exists == GNUNET_YES)
4280 /* During validation attempts we will likely trigger the other
4281 peer trying to validate our address which in turn will cause
4282 it to send us its HELLO, so we expect to hit this case rather
4283 frequently. Only print something if we are very verbose. */
4284 #if DEBUG_TRANSPORT > 1
4285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4286 "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4287 a2s (tname, addr, addrlen),
4291 GNUNET_STATISTICS_update (stats,
4292 gettext_noop ("# peer addresses not validated (in progress)"),
4297 va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4300 va->transport_name = GNUNET_strdup (tname);
4301 va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4303 va->send_time = GNUNET_TIME_absolute_get();
4304 va->addr = (const void*) &va[1];
4305 memcpy (&va[1], addr, addrlen);
4306 va->addrlen = addrlen;
4307 GNUNET_HELLO_get_key (chvc->hello,
4309 va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4310 &timeout_hello_validation,
4312 GNUNET_CONTAINER_multihashmap_put (validation_map,
4315 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4316 setup_peer_check_blacklist (&id, GNUNET_NO,
4317 &transmit_hello_and_ping,
4324 * Check if addresses in validated hello "h" overlap with
4325 * those in "chvc->hello" and validate the rest.
4327 * @param cls closure
4328 * @param peer id of the peer, NULL for last call
4329 * @param h hello message for the peer (can be NULL)
4330 * @param err_msg NULL if successful, otherwise contains error message
4333 check_hello_validated (void *cls,
4334 const struct GNUNET_PeerIdentity *peer,
4335 const struct GNUNET_HELLO_Message *h,
4336 const char *err_msg)
4338 struct CheckHelloValidatedContext *chvc = cls;
4339 struct GNUNET_HELLO_Message *plain_hello;
4340 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4341 struct GNUNET_PeerIdentity target;
4342 struct NeighbourList *n;
4344 if (err_msg != NULL)
4346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4347 _("Error in communication with PEERINFO service\n"));
4353 GNUNET_STATISTICS_update (stats,
4354 gettext_noop ("# outstanding peerinfo iterate requests"),
4358 if (GNUNET_NO == chvc->hello_known)
4360 /* notify PEERINFO about the peer now, so that we at least
4361 have the public key if some other component needs it */
4362 GNUNET_HELLO_get_key (chvc->hello, &pk);
4363 GNUNET_CRYPTO_hash (&pk,
4364 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4365 &target.hashPubKey);
4366 plain_hello = GNUNET_HELLO_create (&pk,
4369 GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4370 GNUNET_free (plain_hello);
4371 #if DEBUG_TRANSPORT_HELLO
4372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4373 "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4375 GNUNET_i2s (&target));
4377 GNUNET_STATISTICS_update (stats,
4378 gettext_noop ("# new HELLOs requiring full validation"),
4381 GNUNET_HELLO_iterate_addresses (chvc->hello,
4388 GNUNET_STATISTICS_update (stats,
4389 gettext_noop ("# duplicate HELLO (peer known)"),
4394 if (chvc->ve_count == 0)
4396 GNUNET_CONTAINER_DLL_remove (chvc_head,
4405 #if DEBUG_TRANSPORT_HELLO
4406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4407 "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4411 chvc->hello_known = GNUNET_YES;
4412 n = find_neighbour (peer);
4415 #if DEBUG_TRANSPORT_HELLO
4416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4417 "Calling hello_iterate_addresses for %s!\n",
4420 GNUNET_HELLO_iterate_addresses (h,
4422 &add_to_foreign_address_list,
4424 try_transmission_to_peer (n);
4428 #if DEBUG_TRANSPORT_HELLO
4429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4430 "No existing neighbor record for %s!\n",
4433 GNUNET_STATISTICS_update (stats,
4434 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4438 GNUNET_STATISTICS_update (stats,
4439 gettext_noop ("# HELLO validations (update case)"),
4442 GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4444 GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4451 * Process HELLO-message.
4453 * @param plugin transport involved, may be NULL
4454 * @param message the actual message
4455 * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4458 process_hello (struct TransportPlugin *plugin,
4459 const struct GNUNET_MessageHeader *message)
4462 struct GNUNET_PeerIdentity target;
4463 const struct GNUNET_HELLO_Message *hello;
4464 struct CheckHelloValidatedContext *chvc;
4465 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4466 #if DEBUG_TRANSPORT_HELLO > 2
4469 hsize = ntohs (message->size);
4470 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4471 (hsize < sizeof (struct GNUNET_MessageHeader)))
4474 return GNUNET_SYSERR;
4476 GNUNET_STATISTICS_update (stats,
4477 gettext_noop ("# HELLOs received for validation"),
4481 /* first, check if load is too high */
4482 if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4484 GNUNET_STATISTICS_update (stats,
4485 gettext_noop ("# HELLOs ignored due to high load"),
4488 #if DEBUG_TRANSPORT_HELLO
4489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4490 "Ignoring `%s' for `%4s', load too high.\n",
4492 GNUNET_i2s (&target));
4496 hello = (const struct GNUNET_HELLO_Message *) message;
4497 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4499 #if DEBUG_TRANSPORT_HELLO
4500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4501 "Unable to get public key from `%s' for `%4s'!\n",
4503 GNUNET_i2s (&target));
4505 GNUNET_break_op (0);
4506 return GNUNET_SYSERR;
4509 GNUNET_CRYPTO_hash (&publicKey,
4510 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4511 &target.hashPubKey);
4513 #if DEBUG_TRANSPORT_HELLO
4514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4515 "Received `%s' message for `%4s'\n",
4517 GNUNET_i2s (&target));
4520 if (0 == memcmp (&my_identity,
4522 sizeof (struct GNUNET_PeerIdentity)))
4524 GNUNET_STATISTICS_update (stats,
4525 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4531 while (NULL != chvc)
4533 if (GNUNET_HELLO_equals (hello,
4535 GNUNET_TIME_absolute_get ()).abs_value > 0)
4537 #if DEBUG_TRANSPORT_HELLO > 2
4538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4539 "Received duplicate `%s' message for `%4s'; ignored\n",
4541 GNUNET_i2s (&target));
4543 return GNUNET_OK; /* validation already pending */
4545 if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4546 GNUNET_break (0 != memcmp (hello, chvc->hello,
4547 GNUNET_HELLO_size(hello)));
4552 struct NeighbourList *temp_neighbor = find_neighbour(&target);
4553 if ((NULL != temp_neighbor))
4555 fprintf(stderr, "Already know peer, ignoring hello\n");
4560 #if DEBUG_TRANSPORT_HELLO > 2
4563 my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4565 "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4568 GNUNET_i2s (&target),
4570 GNUNET_HELLO_size(hello));
4574 chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4576 chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4577 memcpy (&chvc[1], hello, hsize);
4578 GNUNET_CONTAINER_DLL_insert (chvc_head,
4581 /* finally, check if HELLO was previously validated
4582 (continuation will then schedule actual validation) */
4583 GNUNET_STATISTICS_update (stats,
4584 gettext_noop ("# peerinfo process hello iterate requests"),
4587 GNUNET_STATISTICS_update (stats,
4588 gettext_noop ("# outstanding peerinfo iterate requests"),
4591 chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4593 HELLO_VERIFICATION_TIMEOUT,
4594 &check_hello_validated, chvc);
4600 * The peer specified by the given neighbour has timed-out or a plugin
4601 * has disconnected. We may either need to do nothing (other plugins
4602 * still up), or trigger a full disconnect and clean up. This
4603 * function updates our state and does the necessary notifications.
4604 * Also notifies our clients that the neighbour is now officially
4607 * @param n the neighbour list entry for the peer
4608 * @param check GNUNET_YES to check if ALL addresses for this peer
4609 * are gone, GNUNET_NO to force a disconnect of the peer
4610 * regardless of whether other addresses exist.
4613 disconnect_neighbour (struct NeighbourList *n, int check)
4615 struct ReadyList *rpos;
4616 struct NeighbourList *npos;
4617 struct NeighbourList *nprev;
4618 struct MessageQueue *mq;
4619 struct ForeignAddressList *peer_addresses;
4620 struct ForeignAddressList *peer_pos;
4622 if (GNUNET_YES == check)
4625 while (NULL != rpos)
4627 peer_addresses = rpos->addresses;
4628 while (peer_addresses != NULL)
4630 if (GNUNET_YES == peer_addresses->connected)
4632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4633 "NOT Disconnecting from `%4s', still have live addresses!\n",
4634 GNUNET_i2s (&n->id));
4635 return; /* still connected */
4637 peer_addresses = peer_addresses->next;
4643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4644 "Disconnecting from `%4s'\n",
4645 GNUNET_i2s (&n->id));
4647 /* remove n from neighbours list */
4650 while ((npos != NULL) && (npos != n))
4655 GNUNET_assert (npos != NULL);
4657 neighbours = n->next;
4659 nprev->next = n->next;
4661 /* notify all clients about disconnect */
4662 if (GNUNET_YES == n->received_pong)
4663 notify_clients_disconnect (&n->id);
4665 /* clean up all plugins, cancel connections and pending transmissions */
4666 while (NULL != (rpos = n->plugins))
4668 n->plugins = rpos->next;
4669 rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4670 while (rpos->addresses != NULL)
4672 peer_pos = rpos->addresses;
4673 rpos->addresses = peer_pos->next;
4674 if (peer_pos->connected == GNUNET_YES)
4675 GNUNET_STATISTICS_update (stats,
4676 gettext_noop ("# connected addresses"),
4679 if (GNUNET_YES == peer_pos->validated)
4680 GNUNET_STATISTICS_update (stats,
4681 gettext_noop ("# peer addresses considered valid"),
4684 if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4686 GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4687 peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4689 GNUNET_free(peer_pos->ressources);
4690 GNUNET_free(peer_pos->quality);
4691 GNUNET_free(peer_pos);
4696 /* free all messages on the queue */
4697 while (NULL != (mq = n->messages_head))
4699 GNUNET_STATISTICS_update (stats,
4700 gettext_noop ("# bytes in message queue for other peers"),
4701 - (int64_t) mq->message_buf_size,
4703 GNUNET_STATISTICS_update (stats,
4704 gettext_noop ("# bytes discarded due to disconnect"),
4705 mq->message_buf_size,
4707 GNUNET_CONTAINER_DLL_remove (n->messages_head,
4710 GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4712 sizeof(struct GNUNET_PeerIdentity)));
4715 if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4717 GNUNET_SCHEDULER_cancel (n->timeout_task);
4718 n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4720 if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4722 GNUNET_SCHEDULER_cancel (n->retry_task);
4723 n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4725 if (n->piter != NULL)
4727 GNUNET_PEERINFO_iterate_cancel (n->piter);
4728 GNUNET_STATISTICS_update (stats,
4729 gettext_noop ("# outstanding peerinfo iterate requests"),
4734 /* finally, free n itself */
4735 GNUNET_STATISTICS_update (stats,
4736 gettext_noop ("# active neighbours"),
4739 GNUNET_free_non_null (n->pre_connect_message_buffer);
4745 * We have received a PING message from someone. Need to send a PONG message
4746 * in response to the peer by any means necessary.
4749 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4750 const struct GNUNET_PeerIdentity *peer,
4751 struct Session *session,
4752 const char *sender_address,
4753 uint16_t sender_address_len)
4755 struct TransportPlugin *plugin = cls;
4756 struct SessionHeader *session_header = (struct SessionHeader*) session;
4757 struct TransportPingMessage *ping;
4758 struct TransportPongMessage *pong;
4759 struct NeighbourList *n;
4760 struct ReadyList *rl;
4761 struct ForeignAddressList *fal;
4762 struct OwnAddressList *oal;
4767 if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4769 GNUNET_break_op (0);
4770 return GNUNET_SYSERR;
4773 ping = (struct TransportPingMessage *) message;
4774 if (0 != memcmp (&ping->target,
4775 plugin->env.my_identity,
4776 sizeof (struct GNUNET_PeerIdentity)))
4778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4779 _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4781 (sender_address != NULL)
4782 ? a2s (plugin->short_name,
4783 (const struct sockaddr *)sender_address,
4786 GNUNET_i2s (&ping->target));
4787 return GNUNET_SYSERR;
4790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4791 "Processing `%s' from `%s'\n",
4793 (sender_address != NULL)
4794 ? a2s (plugin->short_name,
4795 (const struct sockaddr *)sender_address,
4799 GNUNET_STATISTICS_update (stats,
4800 gettext_noop ("# PING messages received"),
4803 addr = (const char*) &ping[1];
4804 alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4805 slen = strlen (plugin->short_name) + 1;
4808 /* peer wants to confirm that we have an outbound connection to him */
4809 if (session == NULL)
4811 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4812 _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4814 return GNUNET_SYSERR;
4816 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4817 pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4818 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4819 pong->purpose.size =
4820 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4822 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4823 sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4824 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4825 pong->challenge = ping->challenge;
4826 pong->addrlen = htonl(sender_address_len + slen);
4829 sizeof(struct GNUNET_PeerIdentity));
4833 if ((sender_address!=NULL) && (sender_address_len > 0))
4834 memcpy (&((char*)&pong[1])[slen],
4836 sender_address_len);
4837 if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4839 /* create / update cached sig */
4841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4842 "Creating PONG signature to indicate active connection.\n");
4844 session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4845 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4846 GNUNET_assert (GNUNET_OK ==
4847 GNUNET_CRYPTO_rsa_sign (my_private_key,
4849 &session_header->pong_signature));
4853 pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4855 memcpy (&pong->signature,
4856 &session_header->pong_signature,
4857 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4863 /* peer wants to confirm that this is one of our addresses */
4867 plugin->api->check_address (plugin->api->cls,
4871 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4872 _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4873 a2s (plugin->short_name,
4878 oal = plugin->addresses;
4881 if ( (oal->addrlen == alen) &&
4888 pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4889 pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4890 pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4891 pong->purpose.size =
4892 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4894 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4895 sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4896 pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4897 pong->challenge = ping->challenge;
4898 pong->addrlen = htonl(alen + slen);
4901 sizeof(struct GNUNET_PeerIdentity));
4902 memcpy (&pong[1], plugin->short_name, slen);
4903 memcpy (&((char*)&pong[1])[slen], addr, alen);
4904 if ( (oal != NULL) &&
4905 (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4907 /* create / update cached sig */
4909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4910 "Creating PONG signature to indicate ownership.\n");
4912 oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4913 GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4914 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4915 GNUNET_assert (GNUNET_OK ==
4916 GNUNET_CRYPTO_rsa_sign (my_private_key,
4918 &oal->pong_signature));
4919 memcpy (&pong->signature,
4920 &oal->pong_signature,
4921 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4923 else if (oal == NULL)
4925 /* not using cache (typically DV-only) */
4926 pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4927 GNUNET_assert (GNUNET_OK ==
4928 GNUNET_CRYPTO_rsa_sign (my_private_key,
4934 /* can used cached version */
4935 pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4936 memcpy (&pong->signature,
4937 &oal->pong_signature,
4938 sizeof (struct GNUNET_CRYPTO_RsaSignature));
4941 n = find_neighbour(peer);
4942 GNUNET_assert (n != NULL);
4943 /* first try reliable response transmission */
4947 fal = rl->addresses;
4950 if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4953 ntohs (pong->header.size),
4954 TRANSPORT_PONG_PRIORITY,
4955 HELLO_VERIFICATION_TIMEOUT,
4963 GNUNET_STATISTICS_update (stats,
4964 gettext_noop ("# PONGs unicast via reliable transport"),
4974 /* no reliable method found, do multicast */
4975 GNUNET_STATISTICS_update (stats,
4976 gettext_noop ("# PONGs multicast to all available addresses"),
4982 fal = rl->addresses;
4985 transmit_to_peer(NULL, fal,
4986 TRANSPORT_PONG_PRIORITY,
4987 HELLO_VERIFICATION_TIMEOUT,
4989 ntohs(pong->header.size),
5005 * Function called by the plugin for each received message.
5006 * Update data volumes, possibly notify plugins about
5007 * reducing the rate at which they read from the socket
5008 * and generally forward to our receive callback.
5010 * @param cls the "struct TransportPlugin *" we gave to the plugin
5011 * @param peer (claimed) identity of the other peer
5012 * @param message the message, NULL if we only care about
5013 * learning about the delay until we should receive again
5014 * @param ats_data information for automatic transport selection
5015 * @param ats_count number of elements in ats not including 0-terminator
5016 * @param session identifier used for this session (can be NULL)
5017 * @param sender_address binary address of the sender (if observed)
5018 * @param sender_address_len number of bytes in sender_address
5019 * @return how long in ms the plugin should wait until receiving more data
5020 * (plugins that do not support this, can ignore the return value)
5022 static struct GNUNET_TIME_Relative
5023 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5024 const struct GNUNET_MessageHeader *message,
5025 const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5027 struct Session *session,
5028 const char *sender_address,
5029 uint16_t sender_address_len)
5031 struct TransportPlugin *plugin = cls;
5032 struct ReadyList *service_context;
5033 struct ForeignAddressList *peer_address;
5035 struct NeighbourList *n;
5036 struct GNUNET_TIME_Relative ret;
5037 if (is_blacklisted (peer, plugin))
5038 return GNUNET_TIME_UNIT_FOREVER_REL;
5042 n = find_neighbour (peer);
5044 n = setup_new_neighbour (peer, GNUNET_YES);
5045 service_context = n->plugins;
5046 while ((service_context != NULL) && (plugin != service_context->plugin))
5047 service_context = service_context->next;
5048 GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5049 peer_address = NULL;
5052 for (c=0; c<ats_count; c++)
5054 if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5056 distance = ntohl(ats_data[c].value);
5059 /* notify ATS about incoming data */
5060 //ats_notify_ats_data(peer, ats_data);
5062 if (message != NULL)
5064 if ( (session != NULL) ||
5065 (sender_address != NULL) )
5066 peer_address = add_peer_address (n,
5070 sender_address_len);
5071 if (peer_address != NULL)
5074 update_addr_ats(peer_address, ats_data, ats_count);
5075 update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5077 peer_address->distance = distance;
5078 if (GNUNET_YES == peer_address->validated)
5079 mark_address_connected (peer_address);
5080 peer_address->timeout
5082 GNUNET_TIME_relative_to_absolute
5083 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5084 schedule_next_ping (peer_address);
5086 /* update traffic received amount ... */
5087 msize = ntohs (message->size);
5088 GNUNET_STATISTICS_update (stats,
5089 gettext_noop ("# bytes received from other peers"),
5092 n->distance = distance;
5094 GNUNET_TIME_relative_to_absolute
5095 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5096 GNUNET_SCHEDULER_cancel (n->timeout_task);
5098 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5099 &neighbour_timeout_task, n);
5100 if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5102 /* dropping message due to frequent inbound volume violations! */
5103 GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5104 GNUNET_ERROR_TYPE_BULK,
5106 ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5107 n->in_tracker.available_bytes_per_s__,
5108 n->quota_violation_count);
5109 GNUNET_STATISTICS_update (stats,
5110 gettext_noop ("# bandwidth quota violations by other peers"),
5113 return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5118 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5119 ntohs (message->type),
5120 ntohs (message->size),
5123 switch (ntohs (message->type))
5125 case GNUNET_MESSAGE_TYPE_HELLO:
5126 GNUNET_STATISTICS_update (stats,
5127 gettext_noop ("# HELLO messages received from other peers"),
5130 process_hello (plugin, message);
5132 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5133 handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5135 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5136 handle_pong (plugin, message, peer, sender_address, sender_address_len);
5139 handle_payload_message (message, n);
5143 ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5144 if (ret.rel_value > 0)
5146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5147 "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5148 (unsigned long long) n->in_tracker.consumption_since_last_update__,
5149 (unsigned int) n->in_tracker.available_bytes_per_s__,
5150 (unsigned long long) ret.rel_value);
5151 GNUNET_STATISTICS_update (stats,
5152 gettext_noop ("# ms throttling suggested"),
5153 (int64_t) ret.rel_value,
5160 * Handle START-message. This is the first message sent to us
5161 * by any client which causes us to add it to our list.
5163 * @param cls closure (always NULL)
5164 * @param client identification of the client
5165 * @param message the actual message
5168 handle_start (void *cls,
5169 struct GNUNET_SERVER_Client *client,
5170 const struct GNUNET_MessageHeader *message)
5172 const struct StartMessage *start;
5173 struct TransportClient *c;
5174 struct ConnectInfoMessage * cim;
5175 struct NeighbourList *n;
5179 start = (const struct StartMessage*) message;
5181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5182 "Received `%s' request from client\n", "START");
5187 if (c->client == client)
5189 /* client already on our list! */
5191 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5196 if ( (GNUNET_NO != ntohl (start->do_check)) &&
5197 (0 != memcmp (&start->self,
5199 sizeof (struct GNUNET_PeerIdentity))) )
5201 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5202 _("Rejecting control connection from peer `%s', which is not me!\n"),
5203 GNUNET_i2s (&start->self));
5204 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5207 c = GNUNET_malloc (sizeof (struct TransportClient));
5211 if (our_hello != NULL)
5214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5215 "Sending our own `%s' to new client\n", "HELLO");
5217 transmit_to_client (c,
5218 (const struct GNUNET_MessageHeader *) our_hello,
5220 /* tell new client about all existing connections */
5222 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5223 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5227 cim = GNUNET_malloc (size);
5228 cim->header.size = htons (size);
5229 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5230 cim->ats_count = htonl(ats_count);
5231 (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5232 (&(cim->ats))[2].value = htonl (0);
5236 if (GNUNET_YES == n->received_pong)
5238 (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5239 (&(cim->ats))[0].value = htonl (n->distance);
5240 (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5241 (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5243 transmit_to_client (c, &cim->header, GNUNET_NO);
5249 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5254 * Handle HELLO-message.
5256 * @param cls closure (always NULL)
5257 * @param client identification of the client
5258 * @param message the actual message
5261 handle_hello (void *cls,
5262 struct GNUNET_SERVER_Client *client,
5263 const struct GNUNET_MessageHeader *message)
5267 GNUNET_STATISTICS_update (stats,
5268 gettext_noop ("# HELLOs received from clients"),
5271 ret = process_hello (NULL, message);
5272 GNUNET_SERVER_receive_done (client, ret);
5277 * Closure for 'transmit_client_message'; followed by
5278 * 'msize' bytes of the actual message.
5280 struct TransmitClientMessageContext
5283 * Client on whom's behalf we are sending.
5285 struct GNUNET_SERVER_Client *client;
5288 * Timeout for the transmission.
5290 struct GNUNET_TIME_Absolute timeout;
5298 * Size of the message in bytes.
5305 * Schedule transmission of a message we got from a client to a peer.
5307 * @param cls the 'struct TransmitClientMessageContext*'
5308 * @param n destination, or NULL on error (in that case, drop the message)
5311 transmit_client_message (void *cls,
5312 struct NeighbourList *n)
5314 struct TransmitClientMessageContext *tcmc = cls;
5315 struct TransportClient *tc;
5318 while ((tc != NULL) && (tc->client != tcmc->client))
5323 transmit_to_peer (tc, NULL, tcmc->priority,
5324 GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5326 tcmc->msize, GNUNET_NO, n);
5328 GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5329 GNUNET_SERVER_client_drop (tcmc->client);
5335 * Handle SEND-message.
5337 * @param cls closure (always NULL)
5338 * @param client identification of the client
5339 * @param message the actual message
5342 handle_send (void *cls,
5343 struct GNUNET_SERVER_Client *client,
5344 const struct GNUNET_MessageHeader *message)
5346 const struct OutboundMessage *obm;
5347 const struct GNUNET_MessageHeader *obmm;
5348 struct TransmitClientMessageContext *tcmc;
5352 size = ntohs (message->size);
5354 sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5357 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5360 GNUNET_STATISTICS_update (stats,
5361 gettext_noop ("# payload received for other peers"),
5364 obm = (const struct OutboundMessage *) message;
5365 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5366 msize = size - sizeof (struct OutboundMessage);
5368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5369 "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5370 "SEND", GNUNET_i2s (&obm->peer),
5374 tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5375 tcmc->client = client;
5376 tcmc->priority = ntohl (obm->priority);
5377 tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5378 tcmc->msize = msize;
5379 /* FIXME: this memcpy can be up to 7% of our total runtime */
5380 memcpy (&tcmc[1], obmm, msize);
5381 GNUNET_SERVER_client_keep (client);
5382 setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5383 &transmit_client_message,
5389 * Handle request connect message
5391 * @param cls closure (always NULL)
5392 * @param client identification of the client
5393 * @param message the actual message
5396 handle_request_connect (void *cls,
5397 struct GNUNET_SERVER_Client *client,
5398 const struct GNUNET_MessageHeader *message)
5400 const struct TransportRequestConnectMessage *trcm =
5401 (const struct TransportRequestConnectMessage *) message;
5403 GNUNET_STATISTICS_update (stats,
5404 gettext_noop ("# REQUEST CONNECT messages received"),
5407 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5408 setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5410 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5414 * Handle SET_QUOTA-message.
5416 * @param cls closure (always NULL)
5417 * @param client identification of the client
5418 * @param message the actual message
5421 handle_set_quota (void *cls,
5422 struct GNUNET_SERVER_Client *client,
5423 const struct GNUNET_MessageHeader *message)
5425 const struct QuotaSetMessage *qsm =
5426 (const struct QuotaSetMessage *) message;
5427 struct NeighbourList *n;
5429 GNUNET_STATISTICS_update (stats,
5430 gettext_noop ("# SET QUOTA messages received"),
5433 n = find_neighbour (&qsm->peer);
5436 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5437 GNUNET_STATISTICS_update (stats,
5438 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5445 "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5447 (unsigned int) ntohl (qsm->quota.value__),
5448 (unsigned int) n->in_tracker.available_bytes_per_s__,
5449 GNUNET_i2s (&qsm->peer));
5451 GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5453 if (0 == ntohl (qsm->quota.value__))
5455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5456 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5458 disconnect_neighbour (n, GNUNET_NO);
5460 GNUNET_SERVER_receive_done (client, GNUNET_OK);
5465 * Take the given address and append it to the set of results sent back to
5468 * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5469 * @param address the resolved name, NULL to indicate the last response
5472 transmit_address_to_client (void *cls, const char *address)
5474 struct GNUNET_SERVER_TransmitContext *tc = cls;
5477 if (NULL == address)
5480 slen = strlen (address) + 1;
5482 GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5483 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5484 if (NULL == address)
5485 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5490 * Handle AddressLookup-message.
5492 * @param cls closure (always NULL)
5493 * @param client identification of the client
5494 * @param message the actual message
5497 handle_address_lookup (void *cls,
5498 struct GNUNET_SERVER_Client *client,
5499 const struct GNUNET_MessageHeader *message)
5501 const struct AddressLookupMessage *alum;
5502 struct TransportPlugin *lsPlugin;
5503 const char *nameTransport;
5504 const char *address;
5506 struct GNUNET_SERVER_TransmitContext *tc;
5507 struct GNUNET_TIME_Absolute timeout;
5508 struct GNUNET_TIME_Relative rtimeout;
5511 size = ntohs (message->size);
5512 if (size < sizeof (struct AddressLookupMessage))
5514 GNUNET_break_op (0);
5515 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5518 alum = (const struct AddressLookupMessage *) message;
5519 uint32_t addressLen = ntohl (alum->addrlen);
5520 if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5522 GNUNET_break_op (0);
5523 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5526 address = (const char *) &alum[1];
5527 nameTransport = (const char *) &address[addressLen];
5529 [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5531 GNUNET_break_op (0);
5532 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5535 timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5536 rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5537 numeric = ntohl (alum->numeric_only);
5538 lsPlugin = find_transport (nameTransport);
5539 if (NULL == lsPlugin)
5541 tc = GNUNET_SERVER_transmit_context_create (client);
5542 GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5543 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5544 GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5547 tc = GNUNET_SERVER_transmit_context_create (client);
5548 lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5550 address, addressLen,
5553 &transmit_address_to_client, tc);
5558 * Setup the environment for this plugin.
5561 create_environment (struct TransportPlugin *plug)
5563 plug->env.cfg = cfg;
5564 plug->env.my_identity = &my_identity;
5565 plug->env.our_hello = &our_hello;
5566 plug->env.cls = plug;
5567 plug->env.receive = &plugin_env_receive;
5568 plug->env.notify_address = &plugin_env_notify_address;
5569 plug->env.session_end = &plugin_env_session_end;
5570 plug->env.max_connections = max_connect_per_transport;
5571 plug->env.stats = stats;
5576 * Start the specified transport (load the plugin).
5579 start_transport (struct GNUNET_SERVER_Handle *server,
5582 struct TransportPlugin *plug;
5585 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5586 _("Loading `%s' transport plugin\n"), name);
5587 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5588 plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5589 create_environment (plug);
5590 plug->short_name = GNUNET_strdup (name);
5591 plug->lib_name = libname;
5592 plug->next = plugins;
5594 plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5595 if (plug->api == NULL)
5597 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5598 _("Failed to load transport plugin for `%s'\n"), name);
5599 GNUNET_free (plug->short_name);
5600 plugins = plug->next;
5601 GNUNET_free (libname);
5608 * Called whenever a client is disconnected. Frees our
5609 * resources associated with that client.
5611 * @param cls closure
5612 * @param client identification of the client
5615 client_disconnect_notification (void *cls,
5616 struct GNUNET_SERVER_Client *client)
5618 struct TransportClient *pos;
5619 struct TransportClient *prev;
5620 struct ClientMessageQueueEntry *mqe;
5621 struct Blacklisters *bl;
5622 struct BlacklistCheck *bc;
5627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5628 "Client disconnected, cleaning up.\n");
5630 /* clean up blacklister */
5634 if (bl->client == client)
5639 if (bc->bl_pos == bl)
5641 bc->bl_pos = bl->next;
5644 GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5647 if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5648 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5654 GNUNET_CONTAINER_DLL_remove (bl_head,
5657 GNUNET_SERVER_client_drop (bl->client);
5663 /* clean up 'normal' clients */
5666 while ((pos != NULL) && (pos->client != client))
5673 while (NULL != (mqe = pos->message_queue_head))
5675 GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5676 pos->message_queue_tail,
5678 pos->message_count--;
5682 clients = pos->next;
5684 prev->next = pos->next;
5685 if (GNUNET_YES == pos->tcs_pending)
5690 if (pos->th != NULL)
5692 GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5695 GNUNET_break (0 == pos->message_count);
5701 * Function called when the service shuts down. Unloads our plugins
5702 * and cancels pending validations.
5704 * @param cls closure, unused
5705 * @param tc task context (unused)
5708 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5710 struct TransportPlugin *plug;
5711 struct OwnAddressList *al;
5712 struct CheckHelloValidatedContext *chvc;
5714 while (neighbours != NULL)
5716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5717 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5719 disconnect_neighbour (neighbours, GNUNET_NO);
5722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5723 "Transport service is unloading plugins...\n");
5725 while (NULL != (plug = plugins))
5727 plugins = plug->next;
5728 if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5730 GNUNET_SCHEDULER_cancel (plug->address_update_task);
5731 plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5733 GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5734 GNUNET_free (plug->lib_name);
5735 GNUNET_free (plug->short_name);
5736 while (NULL != (al = plug->addresses))
5738 plug->addresses = al->next;
5743 if (my_private_key != NULL)
5744 GNUNET_CRYPTO_rsa_key_free (my_private_key);
5745 GNUNET_free_non_null (our_hello);
5747 GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5750 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5751 validation_map = NULL;
5755 /* free 'chvc' data structure */
5756 while (NULL != (chvc = chvc_head))
5758 chvc_head = chvc->next;
5759 if (chvc->piter != NULL)
5761 GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5762 GNUNET_STATISTICS_update (stats,
5763 gettext_noop ("# outstanding peerinfo iterate requests"),
5769 GNUNET_assert (chvc->ve_count == 0);
5776 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5779 if (peerinfo != NULL)
5781 GNUNET_PEERINFO_disconnect (peerinfo);
5784 /* Can we assume those are gone by now, or do we need to clean up
5786 GNUNET_break (bl_head == NULL);
5787 GNUNET_break (bc_head == NULL);
5791 static int ats_evaluate_results (int result, int solution, char * problem)
5793 int cont = GNUNET_NO;
5794 int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5796 error_kind = GNUNET_ERROR_TYPE_ERROR;
5800 case GLP_ESTOP : /* search terminated by application */
5801 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5803 case GLP_EITLIM : /* iteration limit exceeded */
5804 GNUNET_log (error_kind, "%s Iteration limit exceeded ", problem);
5807 case GLP_ETMLIM : /* time limit exceeded */
5808 GNUNET_log (error_kind, "%s Time limit exceeded ", problem);
5810 case GLP_ENOPFS : /* no primal feasible solution */
5811 case GLP_ENODFS : /* no dual feasible solution */
5812 GNUNET_log (error_kind, "%s No feasible solution", problem);
5815 case GLP_EBADB : /* invalid basis */
5816 case GLP_ESING : /* singular matrix */
5817 case GLP_ECOND : /* ill-conditioned matrix */
5818 case GLP_EBOUND : /* invalid bounds */
5819 case GLP_EFAIL : /* solver failed */
5820 case GLP_EOBJLL : /* objective lower limit reached */
5821 case GLP_EOBJUL : /* objective upper limit reached */
5822 case GLP_EROOT : /* root LP optimum not provided */
5823 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
5827 GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
5833 GNUNET_log (error_kind, "%s solution is undefined\n", problem);
5836 GNUNET_log (error_kind, "%s solution is optimal\n", problem);
5840 GNUNET_log (error_kind, "%s solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n", problem);
5844 GNUNET_log (error_kind, "%s problem has no integer feasible solution\n", problem);
5854 /** solve the bandwidth distribution problem
5855 * @param max_it maximum iterations
5856 * @param max_dur maximum duration in ms
5857 * @param D weight for diversity
5858 * @param U weight for utility
5859 * @param R weight for relativity
5860 * @param v_b_min minimal bandwidth per peer
5861 * @param v_n_min minimum number of connections
5862 * @param res result struct
5863 * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
5865 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)
5868 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5869 return GNUNET_SYSERR;
5872 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
5884 int c_c_ressources = available_ressources;
5885 int c_q_metrics = available_quality_metrics;
5887 double M = VERY_BIG_DOUBLE_VALUE;
5888 double Q[c_q_metrics+1];
5889 for (c=1; c<=c_q_metrics; c++)
5894 struct NeighbourList *next = neighbours;
5897 struct ReadyList *r_next = next->plugins;
5898 while (r_next != NULL)
5900 struct ForeignAddressList * a_next = r_next->addresses;
5901 while (a_next != NULL)
5904 a_next = a_next->next;
5906 r_next = r_next->next;
5915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
5917 return GNUNET_SYSERR;
5920 struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
5921 struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
5928 peers[c_peers].peer = next->id;
5929 peers[c_peers].m_head = NULL;
5930 peers[c_peers].m_tail = NULL;
5932 peers[c_peers].f = 1.0 / c_mechs;
5934 struct ReadyList *r_next = next->plugins;
5935 while (r_next != NULL)
5937 struct ForeignAddressList * a_next = r_next->addresses;
5938 while (a_next != NULL)
5940 mechanisms[c_mechs].addr = a_next;
5941 mechanisms[c_mechs].col_index = c_mechs;
5942 mechanisms[c_mechs].peer = &peers[c_peers];
5943 mechanisms[c_mechs].next = NULL;
5944 mechanisms[c_mechs].plugin = r_next->plugin;
5946 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
5948 a_next = a_next->next;
5950 r_next = r_next->next;
5958 if (v_n_min > c_peers)
5962 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);
5965 int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
5968 int * ia = GNUNET_malloc (size * sizeof (int));
5969 int * ja = GNUNET_malloc (size * sizeof (int));
5970 double * ar = GNUNET_malloc(size* sizeof (double));
5972 prob = glp_create_prob();
5973 glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
5974 glp_set_obj_dir(prob, GLP_MAX);
5976 /* adding columns */
5978 glp_add_cols(prob, 2 * c_mechs);
5979 /* adding b_t cols */
5980 for (c=1; c <= c_mechs; c++)
5983 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
5984 glp_set_col_name(prob, c, name);
5986 glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
5987 glp_set_obj_coef(prob, c, 1);
5990 /* adding n_t cols */
5991 for (c=c_mechs+1; c <= 2*c_mechs; c++)
5993 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
5994 glp_set_col_name(prob, c, name);
5996 glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
5997 glp_set_col_kind(prob, c, GLP_IV);
5998 glp_set_obj_coef(prob, c, 0);
6001 /* feasibility constraints */
6002 /* Constraint 1: one address per peer*/
6004 glp_add_rows(prob, c_peers);
6005 for (c=1; c<=c_peers; c++)
6007 glp_set_row_bnds(prob, row_index, GLP_FX, 1.0, 1.0);
6009 struct ATS_mechanism *m = peers[c].m_head;
6012 ia[array_index] = row_index;
6013 ja[array_index] = (c_mechs + m->col_index);
6014 ar[array_index] = 1;
6016 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6024 /* Constraint 2: only active mechanism gets bandwidth assigned */
6025 glp_add_rows(prob, c_mechs);
6026 for (c=1; c<=c_mechs; c++)
6028 /* b_t - n_t * M <= 0 */
6030 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6032 glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
6034 ia[array_index] = row_index;
6035 ja[array_index] = mechanisms[c].col_index;
6036 ar[array_index] = 1;
6038 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6041 ia[array_index] = row_index;
6042 ja[array_index] = c_mechs + mechanisms[c].col_index;
6043 ar[array_index] = -M;
6045 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6051 /* Constraint 3: minimum bandwidth*/
6052 glp_add_rows(prob, c_mechs);
6053 for (c=1; c<=c_mechs; c++)
6055 /* b_t - n_t * b_min <= 0 */
6057 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6059 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6061 ia[array_index] = row_index;
6062 ja[array_index] = mechanisms[c].col_index;
6063 ar[array_index] = 1;
6065 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6068 ia[array_index] = row_index;
6069 ja[array_index] = c_mechs + mechanisms[c].col_index;
6070 ar[array_index] = -v_b_min;
6072 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6078 /* Constraint 4: max ressource capacity */
6079 /* V cr: bt * ct_r <= cr_maxsolution
6081 glp_add_rows(prob, available_ressources);
6082 double ct_max = VERY_BIG_DOUBLE_VALUE;
6083 double ct_min = 0.0;
6085 for (c=0; c<available_ressources; c++)
6087 ct_max = ressources[c].c_max;
6088 ct_min = ressources[c].c_min;
6090 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6092 glp_set_row_bnds(prob, row_index, GLP_DB, ct_min, ct_max);
6094 for (c2=1; c2<=c_mechs; c2++)
6097 ia[array_index] = row_index;
6098 ja[array_index] = c2;
6099 value = mechanisms[c2].addr->ressources[c].c;
6100 ar[array_index] = value;
6102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6109 /* Constraint 5: min number of connections*/
6110 glp_add_rows(prob, 1);
6111 for (c=1; c<=c_mechs; c++)
6113 // b_t - n_t * b_min >= 0
6115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6117 glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
6119 ia[array_index] = row_index;
6120 ja[array_index] = c_mechs + mechanisms[c].col_index;
6121 ar[array_index] = 1;
6123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6129 /* optimisation constraints*/
6131 /* adding columns */
6132 glp_add_cols(prob, 3 + c_q_metrics);
6134 glp_set_col_name(prob, (2*c_mechs) + 1, "d");
6135 glp_set_obj_coef(prob, (2*c_mechs) + 1, D);
6136 glp_set_col_bnds(prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6137 glp_set_col_name(prob, (2*c_mechs) + 2, "u");
6138 glp_set_obj_coef(prob, (2*c_mechs) + 2, U);
6139 glp_set_col_bnds(prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6140 glp_set_col_name(prob, (2*c_mechs) + 3, "r");
6141 glp_set_obj_coef(prob, (2*c_mechs) + 3, R);
6142 glp_set_col_bnds(prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6144 for (c=1; c<= c_q_metrics; c++)
6146 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6147 glp_set_col_name(prob, (2*c_mechs) + 3 + c, name);
6148 glp_set_col_bnds(prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6150 glp_set_obj_coef(prob, (2*c_mechs) + 3 + c, Q[c]);
6153 // Constraint 6: optimize for diversity
6154 glp_add_rows(prob, 1);
6156 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6158 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6159 for (c=1; c<=c_mechs; c++)
6161 // b_t - n_t * b_min >= 0
6162 ia[array_index] = row_index;
6163 ja[array_index] = c_mechs + mechanisms[c].col_index;
6164 ar[array_index] = 1;
6166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6170 ia[array_index] = row_index;
6171 ja[array_index] = (2*c_mechs) + 1;
6172 ar[array_index] = -1;
6174 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6180 // Constraint 7: optimize for quality
6181 glp_add_rows(prob, available_quality_metrics);
6182 for (c=1; c <= c_q_metrics; c++)
6185 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6187 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6189 for (c2=1; c2<=c_mechs; c2++)
6192 ia[array_index] = row_index;
6193 ja[array_index] = c2;
6194 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6197 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6198 if (v1 < 1) v0 = 0.1;
6199 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6200 if (v1 < 1) v0 = 0.1;
6201 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6202 if (v1 < 1) v0 = 0.1;
6203 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6205 if (qm[c-1].atis_index == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6208 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6210 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6212 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6214 value = (v0 + 2 * v1 + 3 * v2) / 6.0;
6216 value = (double) 10 / value;
6220 ar[array_index] = (mechanisms[c2].peer->f) * value ;
6222 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]);
6227 ia[array_index] = row_index;
6228 ja[array_index] = (2*c_mechs) + 3 +c;
6229 ar[array_index] = -1;
6231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6237 // Constraint 8: optimize bandwidth utility
6238 glp_add_rows(prob, 1);
6240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6242 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6243 for (c=1; c<=c_mechs; c++)
6245 ia[array_index] = row_index;
6246 ja[array_index] = c;
6247 ar[array_index] = mechanisms[c].peer->f;
6249 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6253 ia[array_index] = row_index;
6254 ja[array_index] = (2*c_mechs) + 2;
6255 ar[array_index] = -1;
6257 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6263 // Constraint 9: optimize relativity
6264 glp_add_rows(prob, c_peers);
6265 for (c=1; c<=c_peers; c++)
6267 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6269 struct ATS_mechanism *m = peers[c].m_head;
6272 ia[array_index] = row_index;
6273 ja[array_index] = m->col_index;
6274 ar[array_index] = 1;
6276 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6281 ia[array_index] = row_index;
6282 ja[array_index] = (2*c_mechs) + 3;
6283 ar[array_index] = -1;
6285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6291 /* Loading the matrix */
6292 glp_load_matrix(prob, array_index-1, ia, ja, ar);
6294 /* Solving simplex */
6296 glp_init_smcp(&opt_lp);
6300 opt_lp.msg_lev = GLP_MSG_ALL;
6302 opt_lp.msg_lev = GLP_MSG_OFF;
6304 result = glp_simplex(prob, &opt_lp);
6305 solution = glp_get_status (prob);
6307 if (GNUNET_YES == ats_evaluate_results(result, solution, "LP"))
6311 glp_init_iocp(&opt_mlp);
6312 /* maximum duration */
6313 opt_mlp.tm_lim = max_dur;
6316 opt_mlp.msg_lev = GLP_MSG_ALL;
6318 opt_mlp.msg_lev = GLP_MSG_OFF;
6320 result = glp_intopt (prob, &opt_mlp);
6321 solution = glp_mip_status (prob);
6322 ats_evaluate_results(result, solution, "MLP");
6325 if ((ats->save_mlp == GNUNET_YES) && (c_peers > 1))
6328 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_llu.mlp",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
6329 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6330 glp_write_lp (prob, NULL, filename);
6331 GNUNET_free (filename);
6333 if ((ats->save_solution == GNUNET_YES) && (c_peers > 1))
6336 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%llu.sol",c_peers, c_mechs, GNUNET_TIME_absolute_get().abs_value);
6337 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6338 glp_print_sol (prob, filename);
6339 GNUNET_free (filename);
6343 int error = GNUNET_NO;
6345 struct ATS_mechanism *t = NULL;
6346 for (c=1; c<= (c_peers); c++ )
6349 t = peers[c].m_head;
6352 bw = glp_get_col_prim(prob, t->col_index);
6356 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);
6358 if (check ==GNUNET_YES)
6360 glp_write_sol(prob, "invalid_solution.mlp");
6361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6362 GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6365 if (check ==GNUNET_NO)
6373 for (c=1; c<= c_q_metrics; c++ )
6376 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));
6379 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));
6380 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));
6381 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));
6383 res->c_mechs = c_mechs;
6384 res->c_peers = c_peers;
6385 res->solution = solution;
6389 glp_delete_prob(prob);
6395 for (c=0; c<c_mechs; c++)
6396 GNUNET_free_non_null (mechanisms[c].rc);
6398 GNUNET_free(mechanisms);
6405 void ats_calculate_bandwidth_distribution ()
6407 struct GNUNET_TIME_Absolute start;
6408 struct GNUNET_TIME_Relative duration;
6409 struct ATS_result result;
6412 struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6413 if (delta.rel_value < ats->min_delta.rel_value)
6416 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6422 if (INT_MAX < ats->max_exec_duration.rel_value)
6425 dur = (int) ats->max_exec_duration.rel_value;
6427 start = GNUNET_TIME_absolute_get();
6428 c_mechs = ats_solve_problem(5000, 5000, 1.0, 1.0, 1.0, 1000, 5, &result);
6429 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6434 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);
6436 GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6437 GNUNET_STATISTICS_set (stats, "ATS mechanisms", result.c_mechs, GNUNET_NO);
6438 GNUNET_STATISTICS_set (stats, "ATS peers", result.c_peers, GNUNET_NO);
6439 GNUNET_STATISTICS_set (stats, "ATS solution", result.solution, GNUNET_NO);
6440 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6443 else if (c_mechs == 0)
6445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6448 ats->last = GNUNET_TIME_absolute_get();
6454 ats_schedule_calculation (void *cls,
6455 const struct GNUNET_SCHEDULER_TaskContext *tc)
6457 struct ATS_info *ats = (struct ATS_info *) cls;
6461 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6462 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6466 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6469 ats_calculate_bandwidth_distribution (ats);
6471 ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6472 &ats_schedule_calculation, ats);
6477 ats = GNUNET_malloc(sizeof (struct ATS_info));
6479 ats->min_delta = ATS_MIN_INTERVAL;
6480 ats->exec_intervall = ATS_EXEC_INTERVAL;
6481 ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6482 ats->max_iterations = ATS_MAX_ITERATIONS;
6483 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6486 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GLPK not installed, ATS not active");
6492 unsigned long long value;
6494 /* loading cost ressources */
6495 for (c=0; c<available_ressources; c++)
6497 GNUNET_asprintf(§ion,"%s_UP",ressources[c].cfg_param);
6498 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6500 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6503 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6505 ressources[c].c_max = value;
6508 GNUNET_free (section);
6509 GNUNET_asprintf(§ion,"%s_DOWN",ressources[c].cfg_param);
6510 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6512 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
6515 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6517 ressources[c].c_min = value;
6520 GNUNET_free (section);
6523 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6524 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
6526 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6527 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
6529 ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6533 void ats_shutdown ()
6536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6538 if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6539 GNUNET_SCHEDULER_cancel(ats->ats_task);
6540 ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6542 struct ATS_plugin * p;
6543 struct ATS_ressource_cost * rc;
6547 GNUNET_CONTAINER_DLL_remove (ats->head,ats->tail, p);
6551 GNUNET_CONTAINER_DLL_remove (p->head,p->tail, rc);
6555 GNUNET_free(p->short_name);
6564 void ats_notify_peer_connect (
6565 const struct GNUNET_PeerIdentity *peer,
6566 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6573 while (ntohl(ats_data[c].type)!=0)
6576 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6580 ats_calculate_bandwidth_distribution(ats);
6583 void ats_notify_peer_disconnect (
6584 const struct GNUNET_PeerIdentity *peer)
6587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6589 ats_calculate_bandwidth_distribution (ats);
6593 void ats_notify_ats_data (
6594 const struct GNUNET_PeerIdentity *peer,
6595 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6598 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6600 ats_calculate_bandwidth_distribution(ats);
6603 struct ForeignAddressList * ats_get_preferred_address (
6604 struct NeighbourList *n)
6607 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6609 struct ReadyList *next = n->plugins;
6610 while (next != NULL)
6613 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6617 return find_ready_address(n);
6621 * Initiate transport service.
6623 * @param cls closure
6624 * @param server the initialized server
6625 * @param c configuration to use
6629 struct GNUNET_SERVER_Handle *server,
6630 const struct GNUNET_CONFIGURATION_Handle *c)
6632 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6633 {&handle_start, NULL,
6634 GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6635 {&handle_hello, NULL,
6636 GNUNET_MESSAGE_TYPE_HELLO, 0},
6637 {&handle_send, NULL,
6638 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6639 {&handle_request_connect, NULL,
6640 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6641 {&handle_set_quota, NULL,
6642 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6643 {&handle_address_lookup, NULL,
6644 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6646 {&handle_blacklist_init, NULL,
6647 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6648 {&handle_blacklist_reply, NULL,
6649 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6655 unsigned long long tneigh;
6659 stats = GNUNET_STATISTICS_create ("transport", cfg);
6660 validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6661 /* parse configuration */
6663 GNUNET_CONFIGURATION_get_value_number (c,
6668 GNUNET_CONFIGURATION_get_value_filename (c,
6670 "HOSTKEY", &keyfile)))
6672 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6674 ("Transport service is lacking key configuration settings. Exiting.\n"));
6675 GNUNET_SCHEDULER_shutdown ();
6678 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6681 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6682 validation_map = NULL;
6686 max_connect_per_transport = (uint32_t) tneigh;
6687 peerinfo = GNUNET_PEERINFO_connect (cfg);
6688 if (peerinfo == NULL)
6690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6691 _("Could not access PEERINFO service. Exiting.\n"));
6692 GNUNET_SCHEDULER_shutdown ();
6695 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6698 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6699 validation_map = NULL;
6700 GNUNET_free (keyfile);
6703 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6704 GNUNET_free (keyfile);
6705 if (my_private_key == NULL)
6707 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6709 ("Transport service could not access hostkey. Exiting.\n"));
6710 GNUNET_SCHEDULER_shutdown ();
6713 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6716 GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6717 validation_map = NULL;
6720 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6721 GNUNET_CRYPTO_hash (&my_public_key,
6722 sizeof (my_public_key), &my_identity.hashPubKey);
6723 /* setup notification */
6724 GNUNET_SERVER_disconnect_notify (server,
6725 &client_disconnect_notification, NULL);
6726 /* load plugins... */
6729 GNUNET_CONFIGURATION_get_value_string (c,
6730 "TRANSPORT", "PLUGINS", &plugs))
6732 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6733 _("Starting transport plugins `%s'\n"), plugs);
6734 pos = strtok (plugs, " ");
6737 start_transport (server, pos);
6739 pos = strtok (NULL, " ");
6741 GNUNET_free (plugs);
6743 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6744 &shutdown_task, NULL);
6751 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6753 /* If we have a blacklist file, read from it */
6754 read_blacklist_file(cfg);
6755 /* process client requests */
6756 GNUNET_SERVER_add_handlers (server, handlers);
6761 * The main function for the transport service.
6763 * @param argc number of arguments from the command line
6764 * @param argv command line arguments
6765 * @return 0 ok, 1 on error
6768 main (int argc, char *const *argv)
6770 a2s (NULL, NULL, 0); /* make compiler happy */
6771 return (GNUNET_OK ==
6772 GNUNET_SERVICE_run (argc,
6775 GNUNET_SERVICE_OPTION_NONE,
6776 &run, NULL)) ? 0 : 1;
6779 /* end of gnunet-service-transport.c */